Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:00:47 2007

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 }

Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen