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