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