00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 108961 $")
00029
00030 #include <stdio.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033 #include <sys/time.h>
00034 #include <signal.h>
00035 #include <errno.h>
00036 #include <unistd.h>
00037
00038 #include "asterisk/logger.h"
00039 #include "asterisk/channel.h"
00040 #include "asterisk/options.h"
00041 #include "asterisk/utils.h"
00042 #include "asterisk/lock.h"
00043 #include "asterisk/linkedlists.h"
00044 #include "asterisk/dial.h"
00045 #include "asterisk/pbx.h"
00046
00047
00048 struct ast_dial {
00049 int num;
00050 enum ast_dial_result state;
00051 void *options[AST_DIAL_OPTION_MAX];
00052 ast_dial_state_callback state_callback;
00053 AST_LIST_HEAD(, ast_dial_channel) channels;
00054 pthread_t thread;
00055 ast_mutex_t lock;
00056 };
00057
00058
00059 struct ast_dial_channel {
00060 int num;
00061 const char *tech;
00062 const char *device;
00063 void *options[AST_DIAL_OPTION_MAX];
00064 int cause;
00065 int is_running_app:1;
00066 struct ast_channel *owner;
00067 AST_LIST_ENTRY(ast_dial_channel) list;
00068 };
00069
00070
00071 typedef void *(*ast_dial_option_cb_enable)(void *data);
00072
00073
00074 typedef int (*ast_dial_option_cb_disable)(void *data);
00075
00076
00077 struct answer_exec_struct {
00078 char app[AST_MAX_APP];
00079 char *args;
00080 };
00081
00082
00083 static void *answer_exec_enable(void *data)
00084 {
00085 struct answer_exec_struct *answer_exec = NULL;
00086 char *app = ast_strdupa((char*)data), *args = NULL;
00087
00088
00089 if (ast_strlen_zero(app))
00090 return NULL;
00091
00092
00093 if (!(answer_exec = ast_calloc(1, sizeof(*answer_exec))))
00094 return NULL;
00095
00096
00097 if ((args = strchr(app, '|'))) {
00098 *args++ = '\0';
00099 answer_exec->args = ast_strdup(args);
00100 }
00101
00102
00103 ast_copy_string(answer_exec->app, app, sizeof(answer_exec->app));
00104
00105 return answer_exec;
00106 }
00107
00108
00109 static int answer_exec_disable(void *data)
00110 {
00111 struct answer_exec_struct *answer_exec = data;
00112
00113
00114 if (!answer_exec)
00115 return -1;
00116
00117
00118 if (answer_exec->args)
00119 free(answer_exec->args);
00120
00121
00122 free(answer_exec);
00123
00124 return 0;
00125 }
00126
00127
00128 static void answer_exec_run(struct ast_dial *dial, struct ast_dial_channel *dial_channel, char *app, char *args)
00129 {
00130 struct ast_channel *chan = dial_channel->owner;
00131 struct ast_app *ast_app = pbx_findapp(app);
00132
00133
00134 if (!ast_app)
00135 return;
00136
00137
00138 pbx_exec(chan, ast_app, args);
00139
00140
00141 ast_mutex_lock(&dial->lock);
00142 if (dial->thread != AST_PTHREADT_STOP) {
00143 ast_hangup(chan);
00144 dial_channel->owner = NULL;
00145 }
00146 ast_mutex_unlock(&dial->lock);
00147
00148 return;
00149 }
00150
00151
00152 static const struct ast_option_types {
00153 enum ast_dial_option option;
00154 ast_dial_option_cb_enable enable;
00155 ast_dial_option_cb_disable disable;
00156 } option_types[] = {
00157 { AST_DIAL_OPTION_RINGING, NULL, NULL },
00158 { AST_DIAL_OPTION_ANSWER_EXEC, answer_exec_enable, answer_exec_disable },
00159 { AST_DIAL_OPTION_MAX, NULL, NULL },
00160 };
00161
00162
00163 #define S_REPLACE(s, new_val) \
00164 do { \
00165 if (s) \
00166 free(s); \
00167 s = (new_val); \
00168 } while (0)
00169
00170
00171 #define AST_MAX_WATCHERS 256
00172
00173
00174 #define FIND_RELATIVE_OPTION(dial, dial_channel, ast_dial_option) (dial_channel->options[ast_dial_option] ? dial_channel->options[ast_dial_option] : dial->options[ast_dial_option])
00175
00176
00177 #define IS_CALLER(chan, owner) (chan == owner ? 1 : 0)
00178
00179
00180
00181
00182
00183 struct ast_dial *ast_dial_create(void)
00184 {
00185 struct ast_dial *dial = NULL;
00186
00187
00188 if (!(dial = ast_calloc(1, sizeof(*dial))))
00189 return NULL;
00190
00191
00192 AST_LIST_HEAD_INIT(&dial->channels);
00193
00194
00195 dial->thread = AST_PTHREADT_NULL;
00196
00197
00198 ast_mutex_init(&dial->lock);
00199
00200 return dial;
00201 }
00202
00203
00204
00205
00206
00207 int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device)
00208 {
00209 struct ast_dial_channel *channel = NULL;
00210
00211
00212 if (!dial || !tech || !device)
00213 return -1;
00214
00215
00216 if (!(channel = ast_calloc(1, sizeof(*channel))))
00217 return -1;
00218
00219
00220 channel->tech = tech;
00221 channel->device = device;
00222
00223
00224 channel->num = ast_atomic_fetchadd_int(&dial->num, +1);
00225
00226
00227 AST_LIST_INSERT_TAIL(&dial->channels, channel, list);
00228
00229 return channel->num;
00230 }
00231
00232
00233 static int begin_dial(struct ast_dial *dial, struct ast_channel *chan)
00234 {
00235 struct ast_dial_channel *channel = NULL;
00236 int success = 0, res = 0;
00237
00238
00239 AST_LIST_LOCK(&dial->channels);
00240 AST_LIST_TRAVERSE(&dial->channels, channel, list) {
00241 char numsubst[AST_MAX_EXTENSION];
00242
00243
00244 ast_copy_string(numsubst, channel->device, sizeof(numsubst));
00245
00246
00247 if (!(channel->owner = ast_request(channel->tech,
00248 chan ? chan->nativeformats : AST_FORMAT_AUDIO_MASK, numsubst, &channel->cause))) {
00249 continue;
00250 }
00251
00252 channel->owner->appl = "AppDial2";
00253 channel->owner->data = "(Outgoing Line)";
00254 channel->owner->whentohangup = 0;
00255
00256
00257 if (chan) {
00258 ast_channel_inherit_variables(chan, channel->owner);
00259
00260
00261 S_REPLACE(channel->owner->cid.cid_num, ast_strdup(chan->cid.cid_num));
00262 S_REPLACE(channel->owner->cid.cid_name, ast_strdup(chan->cid.cid_name));
00263 S_REPLACE(channel->owner->cid.cid_ani, ast_strdup(chan->cid.cid_ani));
00264 S_REPLACE(channel->owner->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis));
00265
00266 ast_string_field_set(channel->owner, language, chan->language);
00267 ast_string_field_set(channel->owner, accountcode, chan->accountcode);
00268 channel->owner->cdrflags = chan->cdrflags;
00269 if (ast_strlen_zero(channel->owner->musicclass))
00270 ast_string_field_set(channel->owner, musicclass, chan->musicclass);
00271
00272 channel->owner->cid.cid_pres = chan->cid.cid_pres;
00273 channel->owner->cid.cid_ton = chan->cid.cid_ton;
00274 channel->owner->cid.cid_tns = chan->cid.cid_tns;
00275 channel->owner->adsicpe = chan->adsicpe;
00276 channel->owner->transfercapability = chan->transfercapability;
00277 }
00278
00279
00280 if ((res = ast_call(channel->owner, numsubst, 0))) {
00281 ast_hangup(channel->owner);
00282 channel->owner = NULL;
00283 } else {
00284 success++;
00285 if (option_verbose > 2)
00286 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst);
00287 }
00288 }
00289 AST_LIST_UNLOCK(&dial->channels);
00290
00291
00292 return success;
00293 }
00294
00295
00296 static struct ast_dial_channel *find_relative_dial_channel(struct ast_dial *dial, struct ast_channel *owner)
00297 {
00298 struct ast_dial_channel *channel = NULL;
00299
00300 AST_LIST_LOCK(&dial->channels);
00301 AST_LIST_TRAVERSE(&dial->channels, channel, list) {
00302 if (channel->owner == owner)
00303 break;
00304 }
00305 AST_LIST_UNLOCK(&dial->channels);
00306
00307 return channel;
00308 }
00309
00310 static void set_state(struct ast_dial *dial, enum ast_dial_result state)
00311 {
00312 dial->state = state;
00313
00314 if (dial->state_callback)
00315 dial->state_callback(dial);
00316 }
00317
00318
00319 static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel, struct ast_frame *fr, struct ast_channel *chan)
00320 {
00321 if (fr->frametype == AST_FRAME_CONTROL) {
00322 switch (fr->subclass) {
00323 case AST_CONTROL_ANSWER:
00324 if (option_verbose > 2)
00325 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", channel->owner->name, chan->name);
00326 AST_LIST_LOCK(&dial->channels);
00327 AST_LIST_REMOVE(&dial->channels, channel, list);
00328 AST_LIST_INSERT_HEAD(&dial->channels, channel, list);
00329 AST_LIST_UNLOCK(&dial->channels);
00330 set_state(dial, AST_DIAL_RESULT_ANSWERED);
00331 break;
00332 case AST_CONTROL_BUSY:
00333 if (option_verbose > 2)
00334 ast_verbose(VERBOSE_PREFIX_3 "%s is busy\n", channel->owner->name);
00335 ast_hangup(channel->owner);
00336 channel->owner = NULL;
00337 break;
00338 case AST_CONTROL_CONGESTION:
00339 if (option_verbose > 2)
00340 ast_verbose(VERBOSE_PREFIX_3 "%s is circuit-busy\n", channel->owner->name);
00341 ast_hangup(channel->owner);
00342 channel->owner = NULL;
00343 break;
00344 case AST_CONTROL_RINGING:
00345 if (option_verbose > 2)
00346 ast_verbose(VERBOSE_PREFIX_3 "%s is ringing\n", channel->owner->name);
00347 ast_indicate(chan, AST_CONTROL_RINGING);
00348 set_state(dial, AST_DIAL_RESULT_RINGING);
00349 break;
00350 case AST_CONTROL_PROGRESS:
00351 if (option_verbose > 2)
00352 ast_verbose (VERBOSE_PREFIX_3 "%s is making progress, passing it to %s\n", channel->owner->name, chan->name);
00353 ast_indicate(chan, AST_CONTROL_PROGRESS);
00354 set_state(dial, AST_DIAL_RESULT_PROGRESS);
00355 break;
00356 case AST_CONTROL_VIDUPDATE:
00357 if (option_verbose > 2)
00358 ast_verbose (VERBOSE_PREFIX_3 "%s requested a video update, passing it to %s\n", channel->owner->name, chan->name);
00359 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
00360 break;
00361 case AST_CONTROL_SRCUPDATE:
00362 if (option_verbose > 2)
00363 ast_verbose (VERBOSE_PREFIX_3 "%s requested a source update, passing it to %s\n", channel->owner->name, chan->name);
00364 ast_indicate(chan, AST_CONTROL_SRCUPDATE);
00365 break;
00366 case AST_CONTROL_PROCEEDING:
00367 if (option_verbose > 2)
00368 ast_verbose (VERBOSE_PREFIX_3 "%s is proceeding, passing it to %s\n", channel->owner->name, chan->name);
00369 ast_indicate(chan, AST_CONTROL_PROCEEDING);
00370 set_state(dial, AST_DIAL_RESULT_PROCEEDING);
00371 break;
00372 case AST_CONTROL_HOLD:
00373 if (option_verbose > 2)
00374 ast_verbose(VERBOSE_PREFIX_3 "Call on %s placed on hold\n", chan->name);
00375 ast_indicate(chan, AST_CONTROL_HOLD);
00376 break;
00377 case AST_CONTROL_UNHOLD:
00378 if (option_verbose > 2)
00379 ast_verbose(VERBOSE_PREFIX_3 "Call on %s left from hold\n", chan->name);
00380 ast_indicate(chan, AST_CONTROL_UNHOLD);
00381 break;
00382 case AST_CONTROL_OFFHOOK:
00383 case AST_CONTROL_FLASH:
00384 break;
00385 case -1:
00386
00387 ast_indicate(chan, -1);
00388 break;
00389 default:
00390 break;
00391 }
00392 }
00393
00394 return;
00395 }
00396
00397
00398 static void handle_frame_ownerless(struct ast_dial *dial, struct ast_dial_channel *channel, struct ast_frame *fr)
00399 {
00400
00401 if (fr->frametype != AST_FRAME_CONTROL)
00402 return;
00403
00404 switch (fr->subclass) {
00405 case AST_CONTROL_ANSWER:
00406 if (option_verbose > 2)
00407 ast_verbose( VERBOSE_PREFIX_3 "%s answered\n", channel->owner->name);
00408 AST_LIST_LOCK(&dial->channels);
00409 AST_LIST_REMOVE(&dial->channels, channel, list);
00410 AST_LIST_INSERT_HEAD(&dial->channels, channel, list);
00411 AST_LIST_UNLOCK(&dial->channels);
00412 set_state(dial, AST_DIAL_RESULT_ANSWERED);
00413 break;
00414 case AST_CONTROL_BUSY:
00415 if (option_verbose > 2)
00416 ast_verbose(VERBOSE_PREFIX_3 "%s is busy\n", channel->owner->name);
00417 ast_hangup(channel->owner);
00418 channel->owner = NULL;
00419 break;
00420 case AST_CONTROL_CONGESTION:
00421 if (option_verbose > 2)
00422 ast_verbose(VERBOSE_PREFIX_3 "%s is circuit-busy\n", channel->owner->name);
00423 ast_hangup(channel->owner);
00424 channel->owner = NULL;
00425 break;
00426 case AST_CONTROL_RINGING:
00427 if (option_verbose > 2)
00428 ast_verbose(VERBOSE_PREFIX_3 "%s is ringing\n", channel->owner->name);
00429 set_state(dial, AST_DIAL_RESULT_RINGING);
00430 break;
00431 case AST_CONTROL_PROGRESS:
00432 if (option_verbose > 2)
00433 ast_verbose (VERBOSE_PREFIX_3 "%s is making progress\n", channel->owner->name);
00434 set_state(dial, AST_DIAL_RESULT_PROGRESS);
00435 break;
00436 case AST_CONTROL_PROCEEDING:
00437 if (option_verbose > 2)
00438 ast_verbose (VERBOSE_PREFIX_3 "%s is proceeding\n", channel->owner->name);
00439 set_state(dial, AST_DIAL_RESULT_PROCEEDING);
00440 break;
00441 default:
00442 break;
00443 }
00444
00445 return;
00446 }
00447
00448
00449 static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_channel *chan)
00450 {
00451 int timeout = -1, count = 0;
00452 struct ast_channel *cs[AST_MAX_WATCHERS], *who = NULL;
00453 struct ast_dial_channel *channel = NULL;
00454 struct answer_exec_struct *answer_exec = NULL;
00455
00456 set_state(dial, AST_DIAL_RESULT_TRYING);
00457
00458
00459 if (dial->options[AST_DIAL_OPTION_RINGING]) {
00460 set_state(dial, AST_DIAL_RESULT_RINGING);
00461 if (chan)
00462 ast_indicate(chan, AST_CONTROL_RINGING);
00463 }
00464
00465
00466 while ((dial->state != AST_DIAL_RESULT_UNANSWERED) && (dial->state != AST_DIAL_RESULT_ANSWERED) && (dial->state != AST_DIAL_RESULT_HANGUP) && (dial->state != AST_DIAL_RESULT_TIMEOUT)) {
00467 int pos = 0;
00468 struct ast_frame *fr = NULL;
00469
00470
00471 pos = count = 0;
00472 if (chan)
00473 cs[pos++] = chan;
00474
00475
00476 AST_LIST_LOCK(&dial->channels);
00477 AST_LIST_TRAVERSE(&dial->channels, channel, list) {
00478 if (channel->owner) {
00479 cs[pos++] = channel->owner;
00480 count++;
00481 }
00482 }
00483 AST_LIST_UNLOCK(&dial->channels);
00484
00485
00486 if (!count) {
00487 set_state(dial, AST_DIAL_RESULT_UNANSWERED);
00488 break;
00489 }
00490
00491
00492 if (dial->thread == AST_PTHREADT_STOP)
00493 break;
00494
00495
00496 who = ast_waitfor_n(cs, pos, &timeout);
00497
00498
00499 if (dial->thread == AST_PTHREADT_STOP)
00500 break;
00501
00502
00503 if (!who)
00504 continue;
00505
00506
00507 if (!chan || !IS_CALLER(chan, who))
00508 channel = find_relative_dial_channel(dial, who);
00509
00510
00511 if (!(fr = ast_read(who))) {
00512
00513 if (chan && IS_CALLER(chan, who)) {
00514 set_state(dial, AST_DIAL_RESULT_HANGUP);
00515 break;
00516 }
00517 ast_hangup(who);
00518 channel->owner = NULL;
00519 continue;
00520 }
00521
00522
00523 if (chan)
00524 handle_frame(dial, channel, fr, chan);
00525 else
00526 handle_frame_ownerless(dial, channel, fr);
00527
00528
00529 ast_frfree(fr);
00530 }
00531
00532
00533 if (dial->state == AST_DIAL_RESULT_ANSWERED) {
00534
00535 AST_LIST_LOCK(&dial->channels);
00536 AST_LIST_TRAVERSE(&dial->channels, channel, list) {
00537 if (!channel->owner || channel->owner == who)
00538 continue;
00539 ast_hangup(channel->owner);
00540 channel->owner = NULL;
00541 }
00542 AST_LIST_UNLOCK(&dial->channels);
00543
00544 if ((channel = find_relative_dial_channel(dial, who)) && (answer_exec = FIND_RELATIVE_OPTION(dial, channel, AST_DIAL_OPTION_ANSWER_EXEC))) {
00545 channel->is_running_app = 1;
00546 answer_exec_run(dial, channel, answer_exec->app, answer_exec->args);
00547 channel->is_running_app = 0;
00548 }
00549 } else if (dial->state == AST_DIAL_RESULT_HANGUP) {
00550
00551 AST_LIST_LOCK(&dial->channels);
00552 AST_LIST_TRAVERSE(&dial->channels, channel, list) {
00553 if (!channel->owner)
00554 continue;
00555 ast_hangup(channel->owner);
00556 channel->owner = NULL;
00557 }
00558 AST_LIST_UNLOCK(&dial->channels);
00559 }
00560
00561 return dial->state;
00562 }
00563
00564
00565 static void *async_dial(void *data)
00566 {
00567 struct ast_dial *dial = data;
00568
00569
00570 monitor_dial(dial, NULL);
00571
00572 return NULL;
00573 }
00574
00575
00576
00577
00578
00579 enum ast_dial_result ast_dial_run(struct ast_dial *dial, struct ast_channel *chan, int async)
00580 {
00581 enum ast_dial_result res = AST_DIAL_RESULT_TRYING;
00582
00583
00584 if (!dial || (!chan && !async)) {
00585 ast_log(LOG_DEBUG, "invalid #1\n");
00586 return AST_DIAL_RESULT_INVALID;
00587 }
00588
00589
00590 if (AST_LIST_EMPTY(&dial->channels)) {
00591 ast_log(LOG_DEBUG, "invalid #2\n");
00592 return AST_DIAL_RESULT_INVALID;
00593 }
00594
00595
00596 if (!begin_dial(dial, chan))
00597 return AST_DIAL_RESULT_FAILED;
00598
00599
00600 if (async) {
00601 dial->state = AST_DIAL_RESULT_TRYING;
00602
00603 if (ast_pthread_create(&dial->thread, NULL, async_dial, dial)) {
00604
00605 ast_dial_hangup(dial);
00606 res = AST_DIAL_RESULT_FAILED;
00607 }
00608 } else {
00609 res = monitor_dial(dial, chan);
00610 }
00611
00612 return res;
00613 }
00614
00615
00616
00617
00618
00619 struct ast_channel *ast_dial_answered(struct ast_dial *dial)
00620 {
00621 if (!dial)
00622 return NULL;
00623
00624 return ((dial->state == AST_DIAL_RESULT_ANSWERED) ? AST_LIST_FIRST(&dial->channels)->owner : NULL);
00625 }
00626
00627
00628
00629
00630
00631 enum ast_dial_result ast_dial_state(struct ast_dial *dial)
00632 {
00633 return dial->state;
00634 }
00635
00636
00637
00638
00639
00640 enum ast_dial_result ast_dial_join(struct ast_dial *dial)
00641 {
00642 pthread_t thread;
00643
00644
00645 if (dial->thread == AST_PTHREADT_NULL)
00646 return AST_DIAL_RESULT_FAILED;
00647
00648
00649 thread = dial->thread;
00650
00651
00652 ast_mutex_lock(&dial->lock);
00653
00654
00655 dial->thread = AST_PTHREADT_STOP;
00656
00657
00658 AST_LIST_LOCK(&dial->channels);
00659 if (AST_LIST_FIRST(&dial->channels)->is_running_app) {
00660 struct ast_channel *chan = AST_LIST_FIRST(&dial->channels)->owner;
00661 if (chan) {
00662 ast_channel_lock(chan);
00663 ast_softhangup(chan, AST_SOFTHANGUP_EXPLICIT);
00664 ast_channel_unlock(chan);
00665 }
00666 } else {
00667
00668 pthread_kill(thread, SIGURG);
00669 }
00670 AST_LIST_UNLOCK(&dial->channels);
00671
00672
00673 ast_mutex_unlock(&dial->lock);
00674
00675
00676 pthread_join(thread, NULL);
00677
00678
00679 dial->thread = AST_PTHREADT_NULL;
00680
00681 return dial->state;
00682 }
00683
00684
00685
00686
00687
00688 void ast_dial_hangup(struct ast_dial *dial)
00689 {
00690 struct ast_dial_channel *channel = NULL;
00691
00692 if (!dial)
00693 return;
00694
00695 AST_LIST_LOCK(&dial->channels);
00696 AST_LIST_TRAVERSE(&dial->channels, channel, list) {
00697 if (channel->owner) {
00698 ast_hangup(channel->owner);
00699 channel->owner = NULL;
00700 }
00701 }
00702 AST_LIST_UNLOCK(&dial->channels);
00703
00704 return;
00705 }
00706
00707
00708
00709
00710
00711
00712 int ast_dial_destroy(struct ast_dial *dial)
00713 {
00714 int i = 0;
00715 struct ast_dial_channel *channel = NULL;
00716
00717 if (!dial)
00718 return -1;
00719
00720
00721 AST_LIST_LOCK(&dial->channels);
00722 AST_LIST_TRAVERSE_SAFE_BEGIN(&dial->channels, channel, list) {
00723
00724 for (i = 0; i < AST_DIAL_OPTION_MAX; i++) {
00725 if (!channel->options[i])
00726 continue;
00727 if (option_types[i].disable)
00728 option_types[i].disable(channel->options[i]);
00729 channel->options[i] = NULL;
00730 }
00731
00732 if (channel->owner) {
00733 ast_hangup(channel->owner);
00734 channel->owner = NULL;
00735 }
00736
00737 AST_LIST_REMOVE_CURRENT(&dial->channels, list);
00738 free(channel);
00739 }
00740 AST_LIST_TRAVERSE_SAFE_END;
00741 AST_LIST_UNLOCK(&dial->channels);
00742
00743
00744 for (i = 0; i < AST_DIAL_OPTION_MAX; i++) {
00745 if (!dial->options[i])
00746 continue;
00747 if (option_types[i].disable)
00748 option_types[i].disable(dial->options[i]);
00749 dial->options[i] = NULL;
00750 }
00751
00752
00753 ast_mutex_destroy(&dial->lock);
00754
00755
00756 free(dial);
00757
00758 return 0;
00759 }
00760
00761
00762
00763
00764
00765
00766
00767 int ast_dial_option_global_enable(struct ast_dial *dial, enum ast_dial_option option, void *data)
00768 {
00769
00770 if (dial->options[option])
00771 return -1;
00772
00773
00774 if (option_types[option].enable)
00775 dial->options[option] = option_types[option].enable(data);
00776 else
00777 dial->options[option] = (void*)1;
00778
00779 return 0;
00780 }
00781
00782
00783
00784
00785
00786
00787
00788
00789 int ast_dial_option_enable(struct ast_dial *dial, int num, enum ast_dial_option option, void *data)
00790 {
00791 struct ast_dial_channel *channel = NULL;
00792
00793
00794 if (!dial || AST_LIST_EMPTY(&dial->channels))
00795 return -1;
00796
00797
00798 AST_LIST_LOCK(&dial->channels);
00799 if (AST_LIST_LAST(&dial->channels)->num != num) {
00800 AST_LIST_TRAVERSE(&dial->channels, channel, list) {
00801 if (channel->num == num)
00802 break;
00803 }
00804 } else {
00805 channel = AST_LIST_LAST(&dial->channels);
00806 }
00807 AST_LIST_UNLOCK(&dial->channels);
00808
00809
00810 if (!channel)
00811 return -1;
00812
00813
00814 if (channel->options[option])
00815 return -1;
00816
00817
00818 if (option_types[option].enable)
00819 channel->options[option] = option_types[option].enable(data);
00820 else
00821 channel->options[option] = (void*)1;
00822
00823 return 0;
00824 }
00825
00826
00827
00828
00829
00830
00831 int ast_dial_option_global_disable(struct ast_dial *dial, enum ast_dial_option option)
00832 {
00833
00834 if (!dial->options[option])
00835 return -1;
00836
00837
00838 if (option_types[option].disable)
00839 option_types[option].disable(dial->options[option]);
00840
00841
00842 dial->options[option] = NULL;
00843
00844 return 0;
00845 }
00846
00847
00848
00849
00850
00851
00852
00853 int ast_dial_option_disable(struct ast_dial *dial, int num, enum ast_dial_option option)
00854 {
00855 struct ast_dial_channel *channel = NULL;
00856
00857
00858 if (!dial || AST_LIST_EMPTY(&dial->channels))
00859 return -1;
00860
00861
00862 AST_LIST_LOCK(&dial->channels);
00863 if (AST_LIST_LAST(&dial->channels)->num != num) {
00864 AST_LIST_TRAVERSE(&dial->channels, channel, list) {
00865 if (channel->num == num)
00866 break;
00867 }
00868 } else {
00869 channel = AST_LIST_LAST(&dial->channels);
00870 }
00871 AST_LIST_UNLOCK(&dial->channels);
00872
00873
00874 if (!channel)
00875 return -1;
00876
00877
00878 if (!channel->options[option])
00879 return -1;
00880
00881
00882 if (option_types[option].disable)
00883 option_types[option].disable(channel->options[option]);
00884
00885
00886 channel->options[option] = NULL;
00887
00888 return 0;
00889 }
00890
00891 void ast_dial_set_state_callback(struct ast_dial *dial, ast_dial_state_callback callback)
00892 {
00893 dial->state_callback = callback;
00894 }