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