![]() |
Home page |
Mailing list |
Docs
Asterisk developer's documentation :: Codename Pineapple
dial.c
Go to the documentation of this file.
00001 /* 00002 * Asterisk -- An open source telephony toolkit. 00003 * 00004 * Copyright (C) 1999 - 2007, Digium, Inc. 00005 * 00006 * Joshua Colp <jcolp@digium.com> 00007 * 00008 * See http://www.asterisk.org for more information about 00009 * the Asterisk project. Please do not directly contact 00010 * any of the maintainers of this project for assistance; 00011 * the project provides a web site, mailing lists and IRC 00012 * channels for your use. 00013 * 00014 * This program is free software, distributed under the terms of 00015 * the GNU General Public License Version 2. See the LICENSE file 00016 * at the top of the source tree. 00017 */ 00018 00019 /*! \file 00020 * 00021 * \brief Dialing API 00022 * 00023 * \author Joshua Colp <jcolp@digium.com> 00024 */ 00025 00026 #include "asterisk.h" 00027 00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 52331 $") 00029 00030 #include <stdio.h> 00031 #include <stdlib.h> 00032 #include <string.h> 00033 #include <sys/time.h> 00034 #include <signal.h> 00035 #include <errno.h> 00036 #include <unistd.h> 00037 00038 #include "asterisk/logger.h" 00039 #include "asterisk/channel.h" 00040 #include "asterisk/options.h" 00041 #include "asterisk/utils.h" 00042 #include "asterisk/lock.h" 00043 #include "asterisk/linkedlists.h" 00044 #include "asterisk/dial.h" 00045 #include "asterisk/pbx.h" 00046 00047 /*! \brief Main dialing structure. Contains global options, channels being dialed, and more! */ 00048 struct ast_dial { 00049 int num; /*! Current number to give to next dialed channel */ 00050 enum ast_dial_result status; /*! Status of dial */ 00051 void *options[AST_DIAL_OPTION_MAX]; /*! Global options */ 00052 AST_LIST_HEAD_NOLOCK(, ast_dial_channel) channels; /*! Channels being dialed */ 00053 pthread_t thread; /*! Thread (if running in async) */ 00054 }; 00055 00056 /*! \brief Dialing channel structure. Contains per-channel dialing options, asterisk channel, and more! */ 00057 struct ast_dial_channel { 00058 int num; /*! Unique number for dialed channel */ 00059 const char *tech; /*! Technology being dialed */ 00060 const char *device; /*! Device being dialed */ 00061 void *options[AST_DIAL_OPTION_MAX]; /*! Channel specific options */ 00062 int cause; /*! Cause code in case of failure */ 00063 struct ast_channel *owner; /*! Asterisk channel */ 00064 AST_LIST_ENTRY(ast_dial_channel) list; /*! Linked list information */ 00065 }; 00066 00067 /*! \brief Typedef for dial option enable */ 00068 typedef void *(*ast_dial_option_cb_enable)(void *data); 00069 00070 /*! \brief Typedef for dial option disable */ 00071 typedef int (*ast_dial_option_cb_disable)(void *data); 00072 00073 /* Structure for 'ANSWER_EXEC' option */ 00074 struct answer_exec_struct { 00075 char app[AST_MAX_APP]; /* Application name */ 00076 char *args; /* Application arguments */ 00077 }; 00078 00079 /* Enable function for 'ANSWER_EXEC' option */ 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 /* Not giving any data to this option is bad, mmmk? */ 00086 if (ast_strlen_zero(app)) 00087 return NULL; 00088 00089 /* Create new data structure */ 00090 if (!(answer_exec = ast_calloc(1, sizeof(*answer_exec)))) 00091 return NULL; 00092 00093 /* Parse out application and arguments */ 00094 if ((args = strchr(app, '|'))) { 00095 *args++ = '\0'; 00096 answer_exec->args = ast_strdup(args); 00097 } 00098 00099 /* Copy application name */ 00100 ast_copy_string(answer_exec->app, app, sizeof(answer_exec->app)); 00101 00102 return answer_exec; 00103 } 00104 00105 /* Disable function for 'ANSWER_EXEC' option */ 00106 static int answer_exec_disable(void *data) 00107 { 00108 struct answer_exec_struct *answer_exec = data; 00109 00110 /* Make sure we have a value */ 00111 if (!answer_exec) 00112 return -1; 00113 00114 /* If arguments are present, free them too */ 00115 if (answer_exec->args) 00116 free(answer_exec->args); 00117 00118 /* This is simple - just free the structure */ 00119 free(answer_exec); 00120 00121 return 0; 00122 } 00123 00124 /* Application execution function for 'ANSWER_EXEC' option */ 00125 static void answer_exec_run(struct ast_channel *chan, char *app, char *args) 00126 { 00127 struct ast_app *ast_app = pbx_findapp(app); 00128 00129 /* If the application was not found, return immediately */ 00130 if (!ast_app) 00131 return; 00132 00133 /* All is well... execute the application */ 00134 pbx_exec(chan, ast_app, args); 00135 00136 return; 00137 } 00138 00139 /*! \brief Options structure - maps options to respective handlers (enable/disable). This list MUST be perfectly kept in order, or else madness will happen. */ 00140 static const struct ast_option_types { 00141 enum ast_dial_option option; 00142 ast_dial_option_cb_enable enable; 00143 ast_dial_option_cb_disable disable; 00144 } option_types[] = { 00145 { AST_DIAL_OPTION_RINGING, NULL, NULL }, /*! Always indicate ringing to caller */ 00146 { AST_DIAL_OPTION_ANSWER_EXEC, answer_exec_enable, answer_exec_disable }, /*! Execute application upon answer in async mode */ 00147 { AST_DIAL_OPTION_MAX, NULL, NULL }, /*! Terminator of list */ 00148 }; 00149 00150 /* free the buffer if allocated, and set the pointer to the second arg */ 00151 #define S_REPLACE(s, new_val) \ 00152 do { \ 00153 if (s) \ 00154 free(s); \ 00155 s = (new_val); \ 00156 } while (0) 00157 00158 /*! \brief Maximum number of channels we can watch at a time */ 00159 #define AST_MAX_WATCHERS 256 00160 00161 /*! \brief Macro for finding the option structure to use on a dialed channel */ 00162 #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]) 00163 00164 /*! \brief Macro that determines whether a channel is the caller or not */ 00165 #define IS_CALLER(chan, owner) (chan == owner ? 1 : 0) 00166 00167 /*! \brief New dialing structure 00168 * \note Create a dialing structure 00169 * \return Returns a calloc'd ast_dial structure, NULL on failure 00170 */ 00171 struct ast_dial *ast_dial_create(void) 00172 { 00173 struct ast_dial *dial = NULL; 00174 00175 /* Allocate new memory for structure */ 00176 if (!(dial = ast_calloc(1, sizeof(*dial)))) 00177 return NULL; 00178 00179 /* Initialize list of channels */ 00180 AST_LIST_HEAD_INIT_NOLOCK(&dial->channels); 00181 00182 /* Initialize thread to NULL */ 00183 dial->thread = AST_PTHREADT_NULL; 00184 00185 return dial; 00186 } 00187 00188 /*! \brief Append a channel 00189 * \note Appends a channel to a dialing structure 00190 * \return Returns channel reference number on success, -1 on failure 00191 */ 00192 int ast_dial_append(struct ast_dial *dial, const char *tech, const char *device) 00193 { 00194 struct ast_dial_channel *channel = NULL; 00195 00196 /* Make sure we have required arguments */ 00197 if (!dial || !tech || !device) 00198 return -1; 00199 00200 /* Allocate new memory for dialed channel structure */ 00201 if (!(channel = ast_calloc(1, sizeof(*channel)))) 00202 return -1; 00203 00204 /* Record technology and device for when we actually dial */ 00205 channel->tech = tech; 00206 channel->device = device; 00207 00208 /* Grab reference number from dial structure */ 00209 channel->num = ast_atomic_fetchadd_int(&dial->num, +1); 00210 00211 /* Insert into channels list */ 00212 AST_LIST_INSERT_TAIL(&dial->channels, channel, list); 00213 00214 return channel->num; 00215 } 00216 00217 /*! \brief Helper function that does the beginning dialing */ 00218 static int begin_dial(struct ast_dial *dial, struct ast_channel *chan) 00219 { 00220 struct ast_dial_channel *channel = NULL; 00221 int success = 0, res = 0; 00222 00223 /* Iterate through channel list, requesting and calling each one */ 00224 AST_LIST_TRAVERSE(&dial->channels, channel, list) { 00225 char numsubst[AST_MAX_EXTENSION]; 00226 00227 /* Copy device string over */ 00228 ast_copy_string(numsubst, channel->device, sizeof(numsubst)); 00229 00230 /* Request that the channel be created */ 00231 if (!(channel->owner = ast_request(channel->tech, chan->nativeformats, numsubst, &channel->cause))) 00232 continue; 00233 00234 channel->owner->appl = "AppDial2"; 00235 channel->owner->data = "(Outgoing Line)"; 00236 channel->owner->whentohangup = 0; 00237 00238 /* Inherit everything from he who spawned this Dial */ 00239 ast_channel_inherit_variables(chan, channel->owner); 00240 00241 /* Copy over callerid information */ 00242 S_REPLACE(channel->owner->cid.cid_num, ast_strdup(chan->cid.cid_num)); 00243 S_REPLACE(channel->owner->cid.cid_name, ast_strdup(chan->cid.cid_name)); 00244 S_REPLACE(channel->owner->cid.cid_ani, ast_strdup(chan->cid.cid_ani)); 00245 S_REPLACE(channel->owner->cid.cid_rdnis, ast_strdup(chan->cid.cid_rdnis)); 00246 00247 ast_string_field_set(channel->owner, language, chan->language); 00248 ast_string_field_set(channel->owner, accountcode, chan->accountcode); 00249 channel->owner->cdrflags = chan->cdrflags; 00250 if (ast_strlen_zero(channel->owner->musicclass)) 00251 ast_string_field_set(channel->owner, musicclass, chan->musicclass); 00252 00253 channel->owner->cid.cid_pres = chan->cid.cid_pres; 00254 channel->owner->cid.cid_ton = chan->cid.cid_ton; 00255 channel->owner->cid.cid_tns = chan->cid.cid_tns; 00256 channel->owner->adsicpe = chan->adsicpe; 00257 channel->owner->transfercapability = chan->transfercapability; 00258 00259 /* Actually call the device */ 00260 if ((res = ast_call(channel->owner, numsubst, 0))) { 00261 ast_hangup(channel->owner); 00262 channel->owner = NULL; 00263 } else { 00264 success++; 00265 if (option_verbose > 2) 00266 ast_verbose(VERBOSE_PREFIX_3 "Called %s\n", numsubst); 00267 } 00268 } 00269 00270 /* If number of failures matches the number of channels, then this truly failed */ 00271 return success; 00272 } 00273 00274 /*! \brief Helper function that finds the dialed channel based on owner */ 00275 static struct ast_dial_channel *find_relative_dial_channel(struct ast_dial *dial, struct ast_channel *owner) 00276 { 00277 struct ast_dial_channel *channel = NULL; 00278 00279 AST_LIST_TRAVERSE(&dial->channels, channel, list) { 00280 if (channel->owner == owner) 00281 break; 00282 } 00283 00284 return channel; 00285 } 00286 00287 /*! \brief Helper function that handles control frames WITH owner */ 00288 static void handle_frame(struct ast_dial *dial, struct ast_dial_channel *channel, struct ast_frame *fr, struct ast_channel *chan) 00289 { 00290 if (fr->frametype == AST_FRAME_CONTROL) { 00291 switch (fr->subclass) { 00292 case AST_CONTROL_ANSWER: 00293 if (option_verbose > 2) 00294 ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", channel->owner->name, chan->name); 00295 AST_LIST_REMOVE(&dial->channels, channel, list); 00296 AST_LIST_INSERT_HEAD(&dial->channels, channel, list); 00297 dial->status = AST_DIAL_RESULT_ANSWERED; 00298 break; 00299 case AST_CONTROL_BUSY: 00300 if (option_verbose > 2) 00301 ast_verbose(VERBOSE_PREFIX_3 "%s is busy\n", channel->owner->name); 00302 ast_hangup(channel->owner); 00303 channel->owner = NULL; 00304 break; 00305 case AST_CONTROL_CONGESTION: 00306 if (option_verbose > 2) 00307 ast_verbose(VERBOSE_PREFIX_3 "%s is circuit-busy\n", channel->owner->name); 00308 ast_hangup(channel->owner); 00309 channel->owner = NULL; 00310 break; 00311 case AST_CONTROL_RINGING: 00312 if (option_verbose > 2) 00313 ast_verbose(VERBOSE_PREFIX_3 "%s is ringing\n", channel->owner->name); 00314 ast_indicate(chan, AST_CONTROL_RINGING); 00315 break; 00316 case AST_CONTROL_PROGRESS: 00317 if (option_verbose > 2) 00318 ast_verbose (VERBOSE_PREFIX_3 "%s is making progress, passing it to %s\n", channel->owner->name, chan->name); 00319 ast_indicate(chan, AST_CONTROL_PROGRESS); 00320 break; 00321 case AST_CONTROL_VIDUPDATE: 00322 if (option_verbose > 2) 00323 ast_verbose (VERBOSE_PREFIX_3 "%s requested a video update, passing it to %s\n", channel->owner->name, chan->name); 00324 ast_indicate(chan, AST_CONTROL_VIDUPDATE); 00325 break; 00326 case AST_CONTROL_PROCEEDING: 00327 if (option_verbose > 2) 00328 ast_verbose (VERBOSE_PREFIX_3 "%s is proceeding, passing it to %s\n", channel->owner->name, chan->name); 00329 ast_indicate(chan, AST_CONTROL_PROCEEDING); 00330 break; 00331 case AST_CONTROL_HOLD: 00332 if (option_verbose > 2) 00333 ast_verbose(VERBOSE_PREFIX_3 "Call on %s placed on hold\n", chan->name); 00334 ast_indicate(chan, AST_CONTROL_HOLD); 00335 break; 00336 case AST_CONTROL_UNHOLD: 00337 if (option_verbose > 2) 00338 ast_verbose(VERBOSE_PREFIX_3 "Call on %s left from hold\n", chan->name); 00339 ast_indicate(chan, AST_CONTROL_UNHOLD); 00340 break; 00341 case AST_CONTROL_OFFHOOK: 00342 case AST_CONTROL_FLASH: 00343 break; 00344 case -1: 00345 /* Prod the channel */ 00346 ast_indicate(chan, -1); 00347 break; 00348 default: 00349 break; 00350 } 00351 } 00352 00353 return; 00354 } 00355 00356 /*! \brief Helper function that handles control frames WITHOUT owner */ 00357 static void handle_frame_ownerless(struct ast_dial *dial, struct ast_dial_channel *channel, struct ast_frame *fr) 00358 { 00359 /* If we have no owner we can only update the status of the dial structure, so only look at control frames */ 00360 if (fr->frametype != AST_FRAME_CONTROL) 00361 return; 00362 00363 switch (fr->subclass) { 00364 case AST_CONTROL_ANSWER: 00365 if (option_verbose > 2) 00366 ast_verbose( VERBOSE_PREFIX_3 "%s answered\n", channel->owner->name); 00367 AST_LIST_REMOVE(&dial->channels, channel, list); 00368 AST_LIST_INSERT_HEAD(&dial->channels, channel, list); 00369 dial->status = AST_DIAL_RESULT_ANSWERED; 00370 break; 00371 case AST_CONTROL_BUSY: 00372 if (option_verbose > 2) 00373 ast_verbose(VERBOSE_PREFIX_3 "%s is busy\n", channel->owner->name); 00374 ast_hangup(channel->owner); 00375 channel->owner = NULL; 00376 break; 00377 case AST_CONTROL_CONGESTION: 00378 if (option_verbose > 2) 00379 ast_verbose(VERBOSE_PREFIX_3 "%s is circuit-busy\n", channel->owner->name); 00380 ast_hangup(channel->owner); 00381 channel->owner = NULL; 00382 break; 00383 case AST_CONTROL_RINGING: 00384 if (option_verbose > 2) 00385 ast_verbose(VERBOSE_PREFIX_3 "%s is ringing\n", channel->owner->name); 00386 dial->status = AST_DIAL_RESULT_RINGING; 00387 break; 00388 case AST_CONTROL_PROGRESS: 00389 if (option_verbose > 2) 00390 ast_verbose (VERBOSE_PREFIX_3 "%s is making progress\n", channel->owner->name); 00391 dial->status = AST_DIAL_RESULT_PROGRESS; 00392 break; 00393 case AST_CONTROL_PROCEEDING: 00394 if (option_verbose > 2) 00395 ast_verbose (VERBOSE_PREFIX_3 "%s is proceeding\n", channel->owner->name); 00396 dial->status = AST_DIAL_RESULT_PROCEEDING; 00397 break; 00398 default: 00399 break; 00400 } 00401 00402 return; 00403 } 00404 00405 /*! \brief Helper function that basically keeps tabs on dialing attempts */ 00406 static enum ast_dial_result monitor_dial(struct ast_dial *dial, struct ast_channel *chan) 00407 { 00408 int timeout = -1, count = 0; 00409 struct ast_channel *cs[AST_MAX_WATCHERS], *who = NULL; 00410 struct ast_dial_channel *channel = NULL; 00411 struct answer_exec_struct *answer_exec = NULL; 00412 00413 /* Switch dialing status to trying */ 00414 dial->status = AST_DIAL_RESULT_TRYING; 00415 00416 /* If the "always indicate ringing" option is set, change status to ringing and indicate to the owner if present */ 00417 if (dial->options[AST_DIAL_OPTION_RINGING]) { 00418 dial->status = AST_DIAL_RESULT_RINGING; 00419 if (chan) 00420 ast_indicate(chan, AST_CONTROL_RINGING); 00421 } 00422 00423 /* Go into an infinite loop while we are trying */ 00424 while ((dial->status != AST_DIAL_RESULT_UNANSWERED) && (dial->status != AST_DIAL_RESULT_ANSWERED) && (dial->status != AST_DIAL_RESULT_HANGUP) && (dial->status != AST_DIAL_RESULT_TIMEOUT)) { 00425 int pos = 0; 00426 struct ast_frame *fr = NULL; 00427 00428 /* Set up channel structure array */ 00429 pos = count = 0; 00430 if (chan) 00431 cs[pos++] = chan; 00432 00433 /* Add channels we are attempting to dial */ 00434 AST_LIST_TRAVERSE(&dial->channels, channel, list) { 00435 if (channel->owner) { 00436 cs[pos++] = channel->owner; 00437 count++; 00438 } 00439 } 00440 00441 /* If we have no outbound channels in progress, switch status to unanswered and stop */ 00442 if (!count) { 00443 dial->status = AST_DIAL_RESULT_UNANSWERED; 00444 break; 00445 } 00446 00447 /* Just to be safe... */ 00448 if (dial->thread == AST_PTHREADT_STOP) 00449 break; 00450 00451 /* Wait for frames from channels */ 00452 who = ast_waitfor_n(cs, pos, &timeout); 00453 00454 /* Check to see if our thread is being cancelled */ 00455 if (dial->thread == AST_PTHREADT_STOP) 00456 break; 00457 00458 /* If we are not being cancelled and we have no channel, then timeout was tripped */ 00459 if (!who) 00460 continue; 00461 00462 /* Find relative dial channel */ 00463 if (!chan || !IS_CALLER(chan, who)) 00464 channel = find_relative_dial_channel(dial, who); 00465 00466 /* Attempt to read in a frame */ 00467 if (!(fr = ast_read(who))) { 00468 /* If this is the caller then we switch status to hangup and stop */ 00469 if (chan && IS_CALLER(chan, who)) { 00470 dial->status = AST_DIAL_RESULT_HANGUP; 00471 break; 00472 } 00473 ast_hangup(who); 00474 channel->owner = NULL; 00475 continue; 00476 } 00477 00478 /* Process the frame */ 00479 if (chan) 00480 handle_frame(dial, channel, fr, chan); 00481 else 00482 handle_frame_ownerless(dial, channel, fr); 00483 00484 /* Free the received frame and start all over */ 00485 ast_frfree(fr); 00486 } 00487 00488 /* Do post-processing from loop */ 00489 if (dial->status == AST_DIAL_RESULT_ANSWERED) { 00490 /* Hangup everything except that which answered */ 00491 AST_LIST_TRAVERSE(&dial->channels, channel, list) { 00492 if (!channel->owner || channel->owner == who) 00493 continue; 00494 ast_hangup(channel->owner); 00495 channel->owner = NULL; 00496 } 00497 /* If ANSWER_EXEC is enabled as an option, execute application on answered channel */ 00498 if ((channel = find_relative_dial_channel(dial, who)) && (answer_exec = FIND_RELATIVE_OPTION(dial, channel, AST_DIAL_OPTION_ANSWER_EXEC))) 00499 answer_exec_run(who, answer_exec->app, answer_exec->args); 00500 } else if (dial->status == AST_DIAL_RESULT_HANGUP) { 00501 /* Hangup everything */ 00502 AST_LIST_TRAVERSE(&dial->channels, channel, list) { 00503 if (!channel->owner) 00504 continue; 00505 ast_hangup(channel->owner); 00506 channel->owner = NULL; 00507 } 00508 } 00509 00510 return dial->status; 00511 } 00512 00513 /*! \brief Dial async thread function */ 00514 static void *async_dial(void *data) 00515 { 00516 struct ast_dial *dial = data; 00517 00518 /* This is really really simple... we basically pass monitor_dial a NULL owner and it changes it's behavior */ 00519 monitor_dial(dial, NULL); 00520 00521 return NULL; 00522 } 00523 00524 /*! \brief Execute dialing synchronously or asynchronously 00525 * \note Dials channels in a dial structure. 00526 * \return Returns dial result code. (TRYING/INVALID/FAILED/ANSWERED/TIMEOUT/UNANSWERED). 00527 */ 00528 enum ast_dial_result ast_dial_run(struct ast_dial *dial, struct ast_channel *chan, int async) 00529 { 00530 enum ast_dial_result res = AST_DIAL_RESULT_TRYING; 00531 00532 /* Ensure required arguments are passed */ 00533 if (!dial || !chan) 00534 return AST_DIAL_RESULT_INVALID; 00535 00536 /* If there are no channels to dial we can't very well try to dial them */ 00537 if (AST_LIST_EMPTY(&dial->channels)) 00538 return AST_DIAL_RESULT_INVALID; 00539 00540 /* Dial each requested channel */ 00541 if (!begin_dial(dial, chan)) 00542 return AST_DIAL_RESULT_FAILED; 00543 00544 /* If we are running async spawn a thread and send it away... otherwise block here */ 00545 if (async) { 00546 /* Try to create a thread */ 00547 if (ast_pthread_create(&dial->thread, NULL, async_dial, dial)) { 00548 /* Failed to create the thread - hangup all dialed channels and return failed */ 00549 ast_dial_hangup(dial); 00550 res = AST_DIAL_RESULT_FAILED; 00551 } 00552 } else { 00553 res = monitor_dial(dial, chan); 00554 } 00555 00556 return res; 00557 } 00558 00559 /*! \brief Return channel that answered 00560 * \note Returns the Asterisk channel that answered 00561 * \param dial Dialing structure 00562 */ 00563 struct ast_channel *ast_dial_answered(struct ast_dial *dial) 00564 { 00565 if (!dial) 00566 return NULL; 00567 00568 return ((dial->status == AST_DIAL_RESULT_ANSWERED) ? AST_LIST_FIRST(&dial->channels)->owner : NULL); 00569 } 00570 00571 /*! \brief Return status of dial 00572 * \note Returns the status of the dial attempt 00573 * \param dial Dialing structure 00574 */ 00575 enum ast_dial_result ast_dial_status(struct ast_dial *dial) 00576 { 00577 return dial->status; 00578 } 00579 00580 /*! \brief Cancel async thread 00581 * \note Cancel a running async thread 00582 * \param dial Dialing structure 00583 */ 00584 enum ast_dial_result ast_dial_join(struct ast_dial *dial) 00585 { 00586 pthread_t thread; 00587 00588 /* If the dial structure is not running in async, return failed */ 00589 if (dial->thread == AST_PTHREADT_NULL) 00590 return AST_DIAL_RESULT_FAILED; 00591 00592 /* Record thread */ 00593 thread = dial->thread; 00594 00595 /* Stop the thread */ 00596 dial->thread = AST_PTHREADT_STOP; 00597 00598 /* Now we signal it with SIGURG so it will break out of it's waitfor */ 00599 pthread_kill(thread, SIGURG); 00600 00601 /* Finally wait for the thread to exit */ 00602 pthread_join(thread, NULL); 00603 00604 /* Yay thread is all gone */ 00605 dial->thread = AST_PTHREADT_NULL; 00606 00607 return dial->status; 00608 } 00609 00610 /*! \brief Hangup channels 00611 * \note Hangup all active channels 00612 * \param dial Dialing structure 00613 */ 00614 void ast_dial_hangup(struct ast_dial *dial) 00615 { 00616 struct ast_dial_channel *channel = NULL; 00617 00618 if (!dial) 00619 return; 00620 00621 AST_LIST_TRAVERSE(&dial->channels, channel, list) { 00622 if (channel->owner) { 00623 ast_hangup(channel->owner); 00624 channel->owner = NULL; 00625 } 00626 } 00627 00628 return; 00629 } 00630 00631 /*! \brief Destroys a dialing structure 00632 * \note Destroys (free's) the given ast_dial structure 00633 * \param dial Dialing structure to free 00634 * \return Returns 0 on success, -1 on failure 00635 */ 00636 int ast_dial_destroy(struct ast_dial *dial) 00637 { 00638 int i = 0; 00639 struct ast_dial_channel *channel = NULL; 00640 00641 if (!dial) 00642 return -1; 00643 00644 /* Hangup and deallocate all the dialed channels */ 00645 AST_LIST_TRAVERSE(&dial->channels, channel, list) { 00646 /* Disable any enabled options */ 00647 for (i = 0; i < AST_DIAL_OPTION_MAX; i++) { 00648 if (!channel->options[i]) 00649 continue; 00650 if (option_types[i].disable) 00651 option_types[i].disable(channel->options[i]); 00652 channel->options[i] = NULL; 00653 } 00654 /* Hang up channel if need be */ 00655 if (channel->owner) { 00656 ast_hangup(channel->owner); 00657 channel->owner = NULL; 00658 } 00659 /* Free structure */ 00660 free(channel); 00661 } 00662 00663 /* Disable any enabled options globally */ 00664 for (i = 0; i < AST_DIAL_OPTION_MAX; i++) { 00665 if (!dial->options[i]) 00666 continue; 00667 if (option_types[i].disable) 00668 option_types[i].disable(dial->options[i]); 00669 dial->options[i] = NULL; 00670 } 00671 00672 /* Free structure */ 00673 free(dial); 00674 00675 return 0; 00676 } 00677 00678 /*! \brief Enables an option globally 00679 * \param dial Dial structure to enable option on 00680 * \param option Option to enable 00681 * \param data Data to pass to this option (not always needed) 00682 * \return Returns 0 on success, -1 on failure 00683 */ 00684 int ast_dial_option_global_enable(struct ast_dial *dial, enum ast_dial_option option, void *data) 00685 { 00686 /* If the option is already enabled, return failure */ 00687 if (dial->options[option]) 00688 return -1; 00689 00690 /* Execute enable callback if it exists, if not simply make sure the value is set */ 00691 if (option_types[option].enable) 00692 dial->options[option] = option_types[option].enable(data); 00693 else 00694 dial->options[option] = (void*)1; 00695 00696 return 0; 00697 } 00698 00699 /*! \brief Enables an option per channel 00700 * \param dial Dial structure 00701 * \param num Channel number to enable option on 00702 * \param option Option to enable 00703 * \param data Data to pass to this option (not always needed) 00704 * \return Returns 0 on success, -1 on failure 00705 */ 00706 int ast_dial_option_enable(struct ast_dial *dial, int num, enum ast_dial_option option, void *data) 00707 { 00708 struct ast_dial_channel *channel = NULL; 00709 00710 /* Ensure we have required arguments */ 00711 if (!dial || AST_LIST_EMPTY(&dial->channels)) 00712 return -1; 00713 00714 /* Look for channel, we can sort of cheat and predict things - the last channel in the list will probably be what they want */ 00715 if (AST_LIST_LAST(&dial->channels)->num != num) { 00716 AST_LIST_TRAVERSE(&dial->channels, channel, list) { 00717 if (channel->num == num) 00718 break; 00719 } 00720 } else { 00721 channel = AST_LIST_LAST(&dial->channels); 00722 } 00723 00724 /* If none found, return failure */ 00725 if (!channel) 00726 return -1; 00727 00728 /* If the option is already enabled, return failure */ 00729 if (channel->options[option]) 00730 return -1; 00731 00732 /* Execute enable callback if it exists, if not simply make sure the value is set */ 00733 if (option_types[option].enable) 00734 channel->options[option] = option_types[option].enable(data); 00735 else 00736 channel->options[option] = (void*)1; 00737 00738 return 0; 00739 } 00740 00741 /*! \brief Disables an option globally 00742 * \param dial Dial structure to disable option on 00743 * \param option Option to disable 00744 * \return Returns 0 on success, -1 on failure 00745 */ 00746 int ast_dial_option_global_disable(struct ast_dial *dial, enum ast_dial_option option) 00747 { 00748 /* If the option is not enabled, return failure */ 00749 if (!dial->options[option]) 00750 return -1; 00751 00752 /* Execute callback of option to disable if it exists */ 00753 if (option_types[option].disable) 00754 option_types[option].disable(dial->options[option]); 00755 00756 /* Finally disable option on the structure */ 00757 dial->options[option] = NULL; 00758 00759 return 0; 00760 } 00761 00762 /*! \brief Disables an option per channel 00763 * \param dial Dial structure 00764 * \param num Channel number to disable option on 00765 * \param option Option to disable 00766 * \return Returns 0 on success, -1 on failure 00767 */ 00768 int ast_dial_option_disable(struct ast_dial *dial, int num, enum ast_dial_option option) 00769 { 00770 struct ast_dial_channel *channel = NULL; 00771 00772 /* Ensure we have required arguments */ 00773 if (!dial || AST_LIST_EMPTY(&dial->channels)) 00774 return -1; 00775 00776 /* Look for channel, we can sort of cheat and predict things - the last channel in the list will probably be what they want */ 00777 if (AST_LIST_LAST(&dial->channels)->num != num) { 00778 AST_LIST_TRAVERSE(&dial->channels, channel, list) { 00779 if (channel->num == num) 00780 break; 00781 } 00782 } else { 00783 channel = AST_LIST_LAST(&dial->channels); 00784 } 00785 00786 /* If none found, return failure */ 00787 if (!channel) 00788 return -1; 00789 00790 /* If the option is not enabled, return failure */ 00791 if (!channel->options[option]) 00792 return -1; 00793 00794 /* Execute callback of option to disable it if it exists */ 00795 if (option_types[option].disable) 00796 option_types[option].disable(channel->options[option]); 00797 00798 /* Finally disable the option on the structure */ 00799 channel->options[option] = NULL; 00800 00801 return 0; 00802 }