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