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