Mon Jul 14 17:25:00 2008

Asterisk developer's documentation


res_features.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@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  * Copyright (C) 2004, Junghanns.NET GmbH
00015  *
00016  * Klaus-Peter Junghanns <kpj@junghanns.net>
00017  *
00018  * This program is free software, distributed under the terms of
00019  * the GNU General Public License Version 2. See the LICENSE file
00020  * at the top of the source tree.
00021  */
00022 
00023 /*! \file
00024  *
00025  * \brief Routines implementing call features as call pickup, parking and transfer
00026  *
00027  * \author Mark Spencer <markster@digium.com> 
00028  */
00029 
00030 /*** MODULEINFO
00031         <depend>chan_local</depend>
00032  ***/
00033 
00034 #include "asterisk.h"
00035 
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 114542 $")
00037 
00038 #include <pthread.h>
00039 #include <stdlib.h>
00040 #include <errno.h>
00041 #include <unistd.h>
00042 #include <string.h>
00043 #include <stdlib.h>
00044 #include <stdio.h>
00045 #include <sys/time.h>
00046 #include <sys/signal.h>
00047 #include <netinet/in.h>
00048 
00049 #include "asterisk/lock.h"
00050 #include "asterisk/file.h"
00051 #include "asterisk/logger.h"
00052 #include "asterisk/channel.h"
00053 #include "asterisk/pbx.h"
00054 #include "asterisk/options.h"
00055 #include "asterisk/causes.h"
00056 #include "asterisk/module.h"
00057 #include "asterisk/translate.h"
00058 #include "asterisk/app.h"
00059 #include "asterisk/say.h"
00060 #include "asterisk/features.h"
00061 #include "asterisk/musiconhold.h"
00062 #include "asterisk/config.h"
00063 #include "asterisk/cli.h"
00064 #include "asterisk/manager.h"
00065 #include "asterisk/utils.h"
00066 #include "asterisk/adsi.h"
00067 #include "asterisk/devicestate.h"
00068 #include "asterisk/monitor.h"
00069 #include "asterisk/indications.h"
00070 
00071 #define DEFAULT_PARK_TIME 45000
00072 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
00073 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
00074 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
00075 
00076 #define AST_MAX_WATCHERS 256
00077 
00078 enum {
00079    AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
00080    AST_FEATURE_FLAG_ONPEER =    (1 << 1),
00081    AST_FEATURE_FLAG_ONSELF =    (1 << 2),
00082    AST_FEATURE_FLAG_BYCALLEE =  (1 << 3),
00083    AST_FEATURE_FLAG_BYCALLER =  (1 << 4),
00084    AST_FEATURE_FLAG_BYBOTH  =   (3 << 3),
00085 };
00086 
00087 static char *parkedcall = "ParkedCall";
00088 static char *holdedcall = "HoldedCall";
00089 
00090 static int parkaddhints = 0;                               /*!< Add parking hints automatically */
00091 static int parkingtime = DEFAULT_PARK_TIME;                /*!< No more than 45 seconds parked before you do something with them */
00092 static char parking_con[AST_MAX_EXTENSION];                /*!< Context for which parking is made accessible */
00093 static char parking_con_dial[AST_MAX_EXTENSION];           /*!< Context for dialback for parking (KLUDGE) */
00094 static char parking_ext[AST_MAX_EXTENSION];                /*!< Extension you type to park the call */
00095 static char pickup_ext[AST_MAX_EXTENSION];                 /*!< Call pickup extension */
00096 static char parkmohclass[MAX_MUSICCLASS];                  /*!< Music class used for parking */
00097 static int parking_start;                                  /*!< First available extension for parking */
00098 static int parking_stop;                                   /*!< Last available extension for parking */
00099 
00100 static char courtesytone[256];                             /*!< Courtesy tone */
00101 static int parkedplay = 0;                                 /*!< Who to play the courtesy tone to */
00102 static char xfersound[256];                                /*!< Call transfer sound */
00103 static char xferfailsound[256];                            /*!< Call transfer failure sound */
00104 
00105 static int parking_offset;
00106 static int parkfindnext;
00107 
00108 static int adsipark;
00109 
00110 static int transferdigittimeout;
00111 static int featuredigittimeout;
00112 
00113 static int atxfernoanswertimeout;
00114 
00115 static char *registrar = "res_features";        /*!< Registrar for operations */
00116 
00117 /* module and CLI command definitions */
00118 static char *synopsis = "Answer a parked call";
00119 
00120 static char *descrip = "ParkedCall(exten):"
00121 "Used to connect to a parked call.  This application is always\n"
00122 "registered internally and does not need to be explicitly added\n"
00123 "into the dialplan, although you should include the 'parkedcalls'\n"
00124 "context.\n";
00125 
00126 static char *parkcall = "Park";
00127 
00128 static char *synopsis2 = "Park yourself";
00129 
00130 static char *descrip2 = "Park():"
00131 "Used to park yourself (typically in combination with a supervised\n"
00132 "transfer to know the parking space). This application is always\n"
00133 "registered internally and does not need to be explicitly added\n"
00134 "into the dialplan, although you should include the 'parkedcalls'\n"
00135 "context (or the context specified in features.conf).\n\n"
00136 "If you set the PARKINGEXTEN variable to an extension in your\n"
00137 "parking context, park() will park the call on that extension, unless\n"
00138 "it already exists. In that case, execution will continue at next\n"
00139 "priority.\n" ;
00140 
00141 static char *autoanswerlogin = "AutoanswerLogin";
00142 
00143 static char *synopsis3 = "Log in for autoanswer";
00144 
00145 static char *descrip3 = "AutoanswerLogin([context]|exten):"
00146 "Used to login to the autoanswer application for an extension.\n";
00147 
00148 static char *autoanswer = "Autoanswer";
00149 
00150 static char *synopsis4 = "Autoanswer a call";
00151 
00152 static char *descrip4 = "Autoanswer([context]|exten):"
00153 "Used to autoanswer a call for an extension.\n";
00154 
00155 static struct ast_app *monitor_app = NULL;
00156 static int monitor_ok = 1;
00157 
00158 struct parkeduser {
00159    struct ast_channel *chan;                   /*!< Parking channel */
00160    struct timeval start;                       /*!< Time the parking started */
00161    int parkingnum;                             /*!< Parking lot */
00162    char parkingexten[AST_MAX_EXTENSION];       /*!< If set beforehand, parking extension used for this call */
00163    char context[AST_MAX_CONTEXT];              /*!< Where to go if our parking time expires */
00164    char exten[AST_MAX_EXTENSION];
00165    int priority;
00166    int parkingtime;                            /*!< Maximum length in parking lot before return */
00167    int notquiteyet;
00168    char peername[1024];
00169    unsigned char moh_trys;
00170    struct parkeduser *next;
00171 };
00172 
00173 struct holdeduser {
00174    struct ast_channel *chan;
00175    struct timeval start;
00176    int parkingnum;
00177    int cref;
00178    int tei;
00179    /* Where to go if our parking time expires */
00180    char context[AST_MAX_EXTENSION];
00181    char exten[AST_MAX_EXTENSION];
00182    int priority;
00183    int parkingtime;
00184    char uniqueid[AST_MAX_UNIQUEID];
00185    char uniqueidpeer[AST_MAX_UNIQUEID];
00186    struct holdeduser *next;
00187 };
00188 
00189 /* auto answer user */
00190 struct aauser {
00191    struct ast_channel *chan;
00192    struct timeval start;
00193    /* waiting on this extension/context */
00194    char exten[AST_MAX_EXTENSION];
00195    char context[AST_MAX_EXTENSION];
00196    int priority;
00197    int notquiteyet;
00198    struct aauser *next;
00199 };
00200 
00201 
00202 static struct aauser *aalot;
00203 AST_MUTEX_DEFINE_STATIC(autoanswer_lock);
00204 static pthread_t autoanswer_thread;
00205 
00206 static struct parkeduser *parkinglot;
00207 
00208 static struct holdeduser *holdlist;
00209 
00210 AST_MUTEX_DEFINE_STATIC(parking_lock); /*!< protects all static variables above */
00211 
00212 AST_MUTEX_DEFINE_STATIC(holding_lock);
00213 
00214 static pthread_t parking_thread;
00215 
00216 static pthread_t holding_thread;
00217 
00218 char *ast_parking_ext(void)
00219 {
00220    return parking_ext;
00221 }
00222 
00223 char *ast_pickup_ext(void)
00224 {
00225    return pickup_ext;
00226 }
00227 
00228 struct ast_bridge_thread_obj 
00229 {
00230    struct ast_bridge_config bconfig;
00231    struct ast_channel *chan;
00232    struct ast_channel *peer;
00233    unsigned int return_to_pbx:1;
00234 };
00235 
00236 
00237 
00238 /*! \brief store context, priority and extension */
00239 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
00240 {
00241    ast_copy_string(chan->context, context, sizeof(chan->context));
00242    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00243    chan->priority = pri;
00244 }
00245 
00246 static void check_goto_on_transfer(struct ast_channel *chan) 
00247 {
00248    struct ast_channel *xferchan;
00249    const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00250    char *x, *goto_on_transfer;
00251    struct ast_frame *f;
00252 
00253    if (ast_strlen_zero(val))
00254       return;
00255 
00256    goto_on_transfer = ast_strdupa(val);
00257 
00258    if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, chan->name)))
00259       return;
00260 
00261    for (x = goto_on_transfer; x && *x; x++) {
00262       if (*x == '^')
00263          *x = '|';
00264    }
00265    /* Make formats okay */
00266    xferchan->readformat = chan->readformat;
00267    xferchan->writeformat = chan->writeformat;
00268    ast_channel_masquerade(xferchan, chan);
00269    ast_parseable_goto(xferchan, goto_on_transfer);
00270    xferchan->_state = AST_STATE_UP;
00271    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00272    xferchan->_softhangup = 0;
00273    if ((f = ast_read(xferchan))) {
00274       ast_frfree(f);
00275       f = NULL;
00276       ast_pbx_start(xferchan);
00277    } else {
00278       ast_hangup(xferchan);
00279    }
00280 }
00281 
00282 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, const char *language);
00283 
00284 
00285 static void *ast_bridge_call_thread(void *data) 
00286 {
00287    struct ast_bridge_thread_obj *tobj = data;
00288    int res;
00289 
00290    tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00291    tobj->chan->data = tobj->peer->name;
00292    tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00293    tobj->peer->data = tobj->chan->name;
00294 
00295    if (tobj->chan->cdr) {
00296       ast_cdr_reset(tobj->chan->cdr, NULL);
00297       ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
00298    }
00299    if (tobj->peer->cdr) {
00300       ast_cdr_reset(tobj->peer->cdr, NULL);
00301       ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
00302    }
00303 
00304    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00305 
00306    if (tobj->return_to_pbx) {
00307       if (!ast_check_hangup(tobj->peer)) {
00308          ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name);
00309          res = ast_pbx_start(tobj->peer);
00310          if (res != AST_PBX_SUCCESS)
00311             ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name);
00312       } else
00313          ast_hangup(tobj->peer);
00314       if (!ast_check_hangup(tobj->chan)) {
00315          ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name);
00316          res = ast_pbx_start(tobj->chan);
00317          if (res != AST_PBX_SUCCESS)
00318             ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name);
00319       } else
00320          ast_hangup(tobj->chan);
00321    } else {
00322       ast_hangup(tobj->chan);
00323       ast_hangup(tobj->peer);
00324    }
00325 
00326    free(tobj);
00327 
00328    return NULL;
00329 }
00330 
00331 static void ast_bridge_call_thread_launch(void *data) 
00332 {
00333    pthread_t thread;
00334    pthread_attr_t attr;
00335    struct sched_param sched;
00336 
00337    pthread_attr_init(&attr);
00338    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00339    ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00340    pthread_attr_destroy(&attr);
00341    memset(&sched, 0, sizeof(sched));
00342    pthread_setschedparam(thread, SCHED_RR, &sched);
00343 }
00344 
00345 static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
00346 {
00347    int res;
00348    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00349    char tmp[256];
00350    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00351 
00352    snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00353    message[0] = tmp;
00354    res = ast_adsi_load_session(chan, NULL, 0, 1);
00355    if (res == -1)
00356       return res;
00357    return ast_adsi_print(chan, message, justify, 1);
00358 }
00359 
00360 /*! \brief Notify metermaids that we've changed an extension */
00361 static void notify_metermaids(char *exten, char *context)
00362 {
00363    if (option_debug > 3)
00364       ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context);
00365 
00366    /* Send notification to devicestate subsystem */
00367    ast_device_state_changed("park:%s@%s", exten, context);
00368    return;
00369 }
00370 
00371 /*! \brief metermaids callback from devicestate.c */
00372 static int metermaidstate(const char *data)
00373 {
00374    int res = AST_DEVICE_INVALID;
00375    char *context = ast_strdupa(data);
00376    char *exten;
00377 
00378    exten = strsep(&context, "@");
00379    if (!context)
00380       return res;
00381    
00382    if (option_debug > 3)
00383       ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context);
00384 
00385    res = ast_exists_extension(NULL, context, exten, 1, NULL);
00386 
00387    if (!res)
00388       return AST_DEVICE_NOT_INUSE;
00389    else
00390       return AST_DEVICE_INUSE;
00391 }
00392 
00393 static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, char *orig_chan_name)
00394 {
00395    struct parkeduser *pu, *cur;
00396    int i, x = -1, parking_range;
00397    struct ast_context *con;
00398    const char *parkingexten;
00399    
00400    /* Allocate memory for parking data */
00401    if (!(pu = ast_calloc(1, sizeof(*pu)))) 
00402       return -1;
00403 
00404    /* Lock parking lot */
00405    ast_mutex_lock(&parking_lock);
00406    /* Check for channel variable PARKINGEXTEN */
00407    parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
00408    if (!ast_strlen_zero(parkingexten)) {
00409       if (ast_exists_extension(NULL, parking_con, parkingexten, 1, NULL)) {
00410          ast_mutex_unlock(&parking_lock);
00411          free(pu);
00412          ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
00413          return 1;   /* Continue execution if possible */
00414       }
00415       ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten));
00416       x = atoi(parkingexten);
00417    } else {
00418       /* Select parking space within range */
00419       parking_range = parking_stop - parking_start+1;
00420       for (i = 0; i < parking_range; i++) {
00421          x = (i + parking_offset) % parking_range + parking_start;
00422          cur = parkinglot;
00423          while(cur) {
00424             if (cur->parkingnum == x) 
00425                break;
00426             cur = cur->next;
00427          }
00428          if (!cur)
00429             break;
00430       }
00431 
00432       if (!(i < parking_range)) {
00433          ast_log(LOG_WARNING, "No more parking spaces\n");
00434          free(pu);
00435          ast_mutex_unlock(&parking_lock);
00436          return -1;
00437       }
00438       /* Set pointer for next parking */
00439       if (parkfindnext) 
00440          parking_offset = x - parking_start + 1;
00441    }
00442    
00443    chan->appl = "Parked Call";
00444    chan->data = NULL; 
00445 
00446    pu->chan = chan;
00447    
00448    /* Put the parked channel on hold if we have two different channels */
00449    if (chan != peer) {
00450       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00451          S_OR(parkmohclass, NULL),
00452          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00453    }
00454    
00455    pu->start = ast_tvnow();
00456    pu->parkingnum = x;
00457    pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
00458    if (extout)
00459       *extout = x;
00460 
00461    if (peer) 
00462       ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
00463 
00464    /* Remember what had been dialed, so that if the parking
00465       expires, we try to come back to the same place */
00466    ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
00467    ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
00468    pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
00469    pu->next = parkinglot;
00470    parkinglot = pu;
00471 
00472    /* If parking a channel directly, don't quiet yet get parking running on it */
00473    if (peer == chan) 
00474       pu->notquiteyet = 1;
00475    ast_mutex_unlock(&parking_lock);
00476    /* Wake up the (presumably select()ing) thread */
00477    pthread_kill(parking_thread, SIGURG);
00478    if (option_verbose > 1) 
00479       ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parking_con, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
00480 
00481    if (pu->parkingnum != -1)
00482       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
00483    manager_event(EVENT_FLAG_CALL, "ParkedCall",
00484       "Exten: %s\r\n"
00485       "Channel: %s\r\n"
00486       "From: %s\r\n"
00487       "Timeout: %ld\r\n"
00488       "CallerID: %s\r\n"
00489       "CallerIDName: %s\r\n"
00490       "Uniqueid: %s\r\n",
00491       pu->parkingexten, pu->chan->name, peer ? peer->name : "",
00492       (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00493       S_OR(pu->chan->cid.cid_num, "<unknown>"),
00494       S_OR(pu->chan->cid.cid_name, "<unknown>"),
00495       pu->chan->uniqueid
00496       );
00497 
00498    if (peer && adsipark && ast_adsi_available(peer)) {
00499       adsi_announce_park(peer, pu->parkingexten);  /* Only supports parking numbers */
00500       ast_adsi_unload_session(peer);
00501    }
00502 
00503    con = ast_context_find(parking_con);
00504    if (!con) 
00505       con = ast_context_create(NULL, parking_con, registrar);
00506    if (!con)   /* Still no context? Bad */
00507       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00508    /* Tell the peer channel the number of the parking space */
00509    if (peer && ((pu->parkingnum != -1 && ast_strlen_zero(orig_chan_name)) || !strcasecmp(peer->name, orig_chan_name))) { /* Only say number if it's a number and the channel hasn't been masqueraded away */
00510       /* Make sure we don't start saying digits to the channel being parked */
00511       ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00512       ast_say_digits(peer, pu->parkingnum, "", peer->language);
00513       ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00514    }
00515    if (con) {
00516       if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar))
00517          notify_metermaids(pu->parkingexten, parking_con);
00518    }
00519    if (pu->notquiteyet) {
00520       /* Wake up parking thread if we're really done */
00521       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00522          S_OR(parkmohclass, NULL),
00523          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00524       pu->notquiteyet = 0;
00525       pthread_kill(parking_thread, SIGURG);
00526    }
00527    return 0;
00528 }
00529 
00530 /*! \brief Park a call 
00531    \note We put the user in the parking list, then wake up the parking thread to be sure it looks
00532    after these channels too */
00533 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
00534 {
00535    return park_call_full(chan, peer, timeout, extout, NULL);
00536 }
00537 
00538 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
00539 {
00540    struct ast_channel *chan;
00541    struct ast_frame *f;
00542    char *orig_chan_name = NULL;
00543 
00544    /* Make a new, fake channel that we'll use to masquerade in the real one */
00545    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00546       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00547       return -1;
00548    }
00549 
00550    /* Make formats okay */
00551    chan->readformat = rchan->readformat;
00552    chan->writeformat = rchan->writeformat;
00553    ast_channel_masquerade(chan, rchan);
00554 
00555    /* Setup the extensions and such */
00556    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00557 
00558    /* Make the masq execute */
00559    f = ast_read(chan);
00560    if (f)
00561       ast_frfree(f);
00562 
00563    orig_chan_name = ast_strdupa(chan->name);
00564 
00565    park_call_full(chan, peer, timeout, extout, orig_chan_name);
00566 
00567    return 0;
00568 }
00569 
00570 
00571 #define FEATURE_RETURN_HANGUP    -1
00572 #define FEATURE_RETURN_SUCCESSBREAK  0
00573 #define FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE
00574 #define FEATURE_RETURN_NO_HANGUP_PEER  AST_PBX_NO_HANGUP_PEER
00575 #define FEATURE_RETURN_PASSDIGITS    21
00576 #define FEATURE_RETURN_STOREDIGITS   22
00577 #define FEATURE_RETURN_SUCCESS       23
00578 #define FEATURE_RETURN_KEEPTRYING    24
00579 
00580 #define FEATURE_SENSE_CHAN (1 << 0)
00581 #define FEATURE_SENSE_PEER (1 << 1)
00582 
00583 /*! \brief
00584  * set caller and callee according to the direction
00585  */
00586 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
00587    struct ast_channel *peer, struct ast_channel *chan, int sense)
00588 {
00589    if (sense == FEATURE_SENSE_PEER) {
00590       *caller = peer;
00591       *callee = chan;
00592    } else {
00593       *callee = peer;
00594       *caller = chan;
00595    }
00596 }
00597 
00598 /*! \brief support routing for one touch call parking */
00599 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00600 {
00601    struct ast_channel *parker;
00602         struct ast_channel *parkee;
00603    int res = 0;
00604    struct ast_module_user *u;
00605 
00606    u = ast_module_user_add(chan);
00607 
00608    set_peers(&parker, &parkee, peer, chan, sense);
00609    /* Setup the exten/priority to be s/1 since we don't know
00610       where this call should return */
00611    strcpy(chan->exten, "s");
00612    chan->priority = 1;
00613    if (chan->_state != AST_STATE_UP)
00614       res = ast_answer(chan);
00615    if (!res)
00616       res = ast_safe_sleep(chan, 1000);
00617    if (!res)
00618       res = ast_park_call(parkee, parker, 0, NULL);
00619 
00620    ast_module_user_remove(u);
00621 
00622    if (!res) {
00623       if (sense == FEATURE_SENSE_CHAN)
00624          res = AST_PBX_NO_HANGUP_PEER;
00625       else
00626          res = AST_PBX_KEEPALIVE;
00627    }
00628    return res;
00629 
00630 }
00631 
00632 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00633 {
00634    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00635    int x = 0;
00636    size_t len;
00637    struct ast_channel *caller_chan, *callee_chan;
00638 
00639    if (!monitor_ok) {
00640       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00641       return -1;
00642    }
00643 
00644    if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
00645       monitor_ok = 0;
00646       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00647       return -1;
00648    }
00649 
00650    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00651 
00652    if (!ast_strlen_zero(courtesytone)) {
00653       if (ast_autoservice_start(callee_chan))
00654          return -1;
00655       if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) {
00656          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00657          ast_autoservice_stop(callee_chan);
00658          return -1;
00659       }
00660       if (ast_autoservice_stop(callee_chan))
00661          return -1;
00662    }
00663    
00664    if (callee_chan->monitor) {
00665       if (option_verbose > 3)
00666          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
00667       ast_monitor_stop(callee_chan, 1);
00668       return FEATURE_RETURN_SUCCESS;
00669    }
00670 
00671    if (caller_chan && callee_chan) {
00672       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00673       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00674 
00675       if (!touch_format)
00676          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00677 
00678       if (!touch_monitor)
00679          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00680    
00681       if (touch_monitor) {
00682          len = strlen(touch_monitor) + 50;
00683          args = alloca(len);
00684          touch_filename = alloca(len);
00685          snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
00686          snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
00687       } else {
00688          caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00689          callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00690          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00691          args = alloca(len);
00692          touch_filename = alloca(len);
00693          snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
00694          snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
00695       }
00696 
00697       for( x = 0; x < strlen(args); x++) {
00698          if (args[x] == '/')
00699             args[x] = '-';
00700       }
00701       
00702       if (option_verbose > 3)
00703          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
00704 
00705       pbx_exec(callee_chan, monitor_app, args);
00706       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00707       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00708    
00709       return FEATURE_RETURN_SUCCESS;
00710    }
00711    
00712    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
00713    return -1;
00714 }
00715 
00716 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00717 {
00718    if (option_verbose > 3)
00719       ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00720    return FEATURE_RETURN_HANGUP;
00721 }
00722 
00723 static int finishup(struct ast_channel *chan)
00724 {
00725         ast_indicate(chan, AST_CONTROL_UNHOLD);
00726   
00727         return ast_autoservice_stop(chan);
00728 }
00729 
00730 /*! \brief Find the context for the transfer */
00731 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
00732 {
00733         const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
00734         if (ast_strlen_zero(s))
00735                 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
00736         if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
00737                 s = transferer->macrocontext;
00738         if (ast_strlen_zero(s))
00739                 s = transferer->context;
00740         return s;  
00741 }
00742 
00743 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00744 {
00745    struct ast_channel *transferer;
00746    struct ast_channel *transferee;
00747    const char *transferer_real_context;
00748    char xferto[256];
00749    int res;
00750 
00751    set_peers(&transferer, &transferee, peer, chan, sense);
00752    transferer_real_context = real_ctx(transferer, transferee);
00753    /* Start autoservice on chan while we talk to the originator */
00754    ast_autoservice_start(transferee);
00755    ast_indicate(transferee, AST_CONTROL_HOLD);
00756 
00757    memset(xferto, 0, sizeof(xferto));
00758    
00759    /* Transfer */
00760    res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00761    if (res < 0) {
00762       finishup(transferee);
00763       return -1; /* error ? */
00764    }
00765    if (res > 0)   /* If they've typed a digit already, handle it */
00766       xferto[0] = (char) res;
00767 
00768    ast_stopstream(transferer);
00769    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00770    if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
00771       finishup(transferee);
00772       return res;
00773    }
00774    if (!strcmp(xferto, ast_parking_ext())) {
00775       res = finishup(transferee);
00776       if (res)
00777          res = -1;
00778       else if (!ast_park_call(transferee, transferer, 0, NULL)) { /* success */
00779          /* We return non-zero, but tell the PBX not to hang the channel when
00780             the thread dies -- We have to be careful now though.  We are responsible for 
00781             hanging up the channel, else it will never be hung up! */
00782 
00783          return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER;
00784       } else {
00785          ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
00786       }
00787       /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
00788    } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00789       pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", transferee->name);
00790       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
00791       res=finishup(transferee);
00792       if (!transferer->cdr) {
00793          transferer->cdr=ast_cdr_alloc();
00794          if (transferer) {
00795             ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */
00796             ast_cdr_start(transferer->cdr);
00797          }
00798       }
00799       if (transferer->cdr) {
00800          ast_cdr_setdestchan(transferer->cdr, transferee->name);
00801          ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER","");
00802       }
00803       if (!transferee->pbx) {
00804          /* Doh!  Use our handy async_goto functions */
00805          if (option_verbose > 2) 
00806             ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
00807                         ,transferee->name, xferto, transferer_real_context);
00808          if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
00809             ast_log(LOG_WARNING, "Async goto failed :-(\n");
00810          res = -1;
00811       } else {
00812          /* Set the channel's new extension, since it exists, using transferer context */
00813          set_c_e_p(transferee, transferer_real_context, xferto, 0);
00814       }
00815       check_goto_on_transfer(transferer);
00816       return res;
00817    } else {
00818       if (option_verbose > 2) 
00819          ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
00820    }
00821    if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
00822       finishup(transferee);
00823       return -1;
00824    }
00825    ast_stopstream(transferer);
00826    res = finishup(transferee);
00827    if (res) {
00828       if (option_verbose > 1)
00829          ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
00830       return res;
00831    }
00832    return FEATURE_RETURN_SUCCESS;
00833 }
00834 
00835 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
00836 {
00837    if (ast_channel_make_compatible(c, newchan) < 0) {
00838       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
00839          c->name, newchan->name);
00840       ast_hangup(newchan);
00841       return -1;
00842    }
00843    return 0;
00844 }
00845 
00846 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00847 {
00848    struct ast_channel *transferer;
00849    struct ast_channel *transferee;
00850    const char *transferer_real_context;
00851    char xferto[256] = "";
00852    int res;
00853    int outstate=0;
00854    struct ast_channel *newchan;
00855    struct ast_channel *xferchan;
00856    struct ast_bridge_thread_obj *tobj;
00857    struct ast_bridge_config bconfig;
00858    struct ast_frame *f;
00859    int l;
00860 
00861    if (option_debug)
00862       ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
00863    set_peers(&transferer, &transferee, peer, chan, sense);
00864         transferer_real_context = real_ctx(transferer, transferee);
00865    /* Start autoservice on chan while we talk to the originator */
00866    ast_autoservice_start(transferee);
00867    ast_indicate(transferee, AST_CONTROL_HOLD);
00868    
00869    /* Transfer */
00870    res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00871    if (res < 0) {
00872       finishup(transferee);
00873       return res;
00874    }
00875    if (res > 0) /* If they've typed a digit already, handle it */
00876       xferto[0] = (char) res;
00877 
00878    /* this is specific of atxfer */
00879    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00880         if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
00881                 finishup(transferee);
00882                 return res;
00883         }
00884    if (res == 0) {
00885       ast_log(LOG_WARNING, "Did not read data.\n");
00886       finishup(transferee);
00887       if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00888          return -1;
00889       return FEATURE_RETURN_SUCCESS;
00890    }
00891 
00892    /* valid extension, res == 1 */
00893    if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00894       ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
00895       finishup(transferee);
00896       if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00897          return -1;
00898       return FEATURE_RETURN_SUCCESS;
00899    }
00900 
00901    l = strlen(xferto);
00902    snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);   /* append context */
00903    newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
00904       xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, transferer->language);
00905    ast_indicate(transferer, -1);
00906    if (!newchan) {
00907       finishup(transferee);
00908       /* any reason besides user requested cancel and busy triggers the failed sound */
00909       if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
00910             ast_stream_and_wait(transferer, xferfailsound, transferer->language, ""))
00911          return -1;
00912       return FEATURE_RETURN_SUCCESS;
00913    }
00914 
00915    if (check_compat(transferer, newchan)) {
00916       /* we do mean transferee here, NOT transferer */
00917       finishup(transferee);
00918       return -1;
00919    }
00920    memset(&bconfig,0,sizeof(struct ast_bridge_config));
00921    ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
00922    ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
00923    res = ast_bridge_call(transferer, newchan, &bconfig);
00924    if (newchan->_softhangup || !transferer->_softhangup) {
00925       ast_hangup(newchan);
00926       if (ast_stream_and_wait(transferer, xfersound, transferer->language, ""))
00927          ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00928       finishup(transferee);
00929       transferer->_softhangup = 0;
00930       return FEATURE_RETURN_SUCCESS;
00931    }
00932    
00933    if (check_compat(transferee, newchan)) {
00934       finishup(transferee);
00935       return -1;
00936    }
00937 
00938    ast_indicate(transferee, AST_CONTROL_UNHOLD);
00939    
00940    if ((ast_autoservice_stop(transferee) < 0)
00941       || (ast_waitfordigit(transferee, 100) < 0)
00942       || (ast_waitfordigit(newchan, 100) < 0) 
00943       || ast_check_hangup(transferee) 
00944       || ast_check_hangup(newchan)) {
00945       ast_hangup(newchan);
00946       return -1;
00947    }
00948 
00949    xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
00950    if (!xferchan) {
00951       ast_hangup(newchan);
00952       return -1;
00953    }
00954    /* Make formats okay */
00955    xferchan->visible_indication = transferer->visible_indication;
00956    xferchan->readformat = transferee->readformat;
00957    xferchan->writeformat = transferee->writeformat;
00958    ast_channel_masquerade(xferchan, transferee);
00959    ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
00960    xferchan->_state = AST_STATE_UP;
00961    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00962    xferchan->_softhangup = 0;
00963 
00964    if ((f = ast_read(xferchan)))
00965       ast_frfree(f);
00966 
00967    newchan->_state = AST_STATE_UP;
00968    ast_clear_flag(newchan, AST_FLAGS_ALL);   
00969    newchan->_softhangup = 0;
00970 
00971    tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
00972    if (!tobj) {
00973       ast_hangup(xferchan);
00974       ast_hangup(newchan);
00975       return -1;
00976    }
00977    tobj->chan = newchan;
00978    tobj->peer = xferchan;
00979    tobj->bconfig = *config;
00980 
00981    if (ast_stream_and_wait(newchan, xfersound, newchan->language, ""))
00982       ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00983    ast_bridge_call_thread_launch(tobj);
00984    return -1;  /* XXX meaning the channel is bridged ? */
00985 }
00986 
00987 
00988 /* add atxfer and automon as undefined so you can only use em if you configure them */
00989 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
00990 
00991 AST_RWLOCK_DEFINE_STATIC(features_lock);
00992 
00993 static struct ast_call_feature builtin_features[] = 
00994  {
00995    { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00996    { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00997    { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00998    { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00999    { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01000 };
01001 
01002 
01003 static AST_LIST_HEAD_STATIC(feature_list,ast_call_feature);
01004 
01005 /*! \brief register new feature into feature_list*/
01006 void ast_register_feature(struct ast_call_feature *feature)
01007 {
01008    if (!feature) {
01009       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01010          return;
01011    }
01012   
01013    AST_LIST_LOCK(&feature_list);
01014    AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
01015    AST_LIST_UNLOCK(&feature_list);
01016 
01017    if (option_verbose >= 2) 
01018       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
01019 }
01020 
01021 /*! \brief unregister feature from feature_list */
01022 void ast_unregister_feature(struct ast_call_feature *feature)
01023 {
01024    if (!feature)
01025       return;
01026 
01027    AST_LIST_LOCK(&feature_list);
01028    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
01029    AST_LIST_UNLOCK(&feature_list);
01030    free(feature);
01031 }
01032 
01033 /*! \brief Remove all features in the list */
01034 static void ast_unregister_features(void)
01035 {
01036    struct ast_call_feature *feature;
01037 
01038    AST_LIST_LOCK(&feature_list);
01039    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
01040       free(feature);
01041    AST_LIST_UNLOCK(&feature_list);
01042 }
01043 
01044 /*! \brief find a feature by name */
01045 static struct ast_call_feature *find_dynamic_feature(const char *name)
01046 {
01047    struct ast_call_feature *tmp;
01048 
01049    AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01050       if (!strcasecmp(tmp->sname, name))
01051          break;
01052    }
01053 
01054    return tmp;
01055 }
01056 
01057 /*! \brief exec an app by feature */
01058 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
01059 {
01060    struct ast_app *app;
01061    struct ast_call_feature *feature = data;
01062    struct ast_channel *work, *idle;
01063    int res;
01064 
01065    if (!feature) { /* shouldn't ever happen! */
01066       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01067       return -1; 
01068    }
01069 
01070    if (sense == FEATURE_SENSE_CHAN) {
01071       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01072          return FEATURE_RETURN_KEEPTRYING;
01073       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01074          work = chan;
01075          idle = peer;
01076       } else {
01077          work = peer;
01078          idle = chan;
01079       }
01080    } else {
01081       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01082          return FEATURE_RETURN_KEEPTRYING;
01083       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01084          work = peer;
01085          idle = chan;
01086       } else {
01087          work = chan;
01088          idle = peer;
01089       }
01090    }
01091 
01092    if (!(app = pbx_findapp(feature->app))) {
01093       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01094       return -2;
01095    }
01096 
01097    ast_autoservice_start(idle);
01098    
01099    if (!ast_strlen_zero(feature->moh_class))
01100       ast_moh_start(idle, feature->moh_class, NULL);
01101 
01102    res = pbx_exec(work, app, feature->app_args);
01103 
01104    if (!ast_strlen_zero(feature->moh_class))
01105       ast_moh_stop(idle);
01106 
01107    ast_autoservice_stop(idle);
01108 
01109    if (res == AST_PBX_KEEPALIVE)
01110       return FEATURE_RETURN_PBX_KEEPALIVE;
01111    else if (res == AST_PBX_NO_HANGUP_PEER)
01112       return FEATURE_RETURN_NO_HANGUP_PEER;
01113    else if (res)
01114       return FEATURE_RETURN_SUCCESSBREAK;
01115    
01116    return FEATURE_RETURN_SUCCESS;   /*! \todo XXX should probably return res */
01117 }
01118 
01119 static void unmap_features(void)
01120 {
01121    int x;
01122 
01123    ast_rwlock_wrlock(&features_lock);
01124    for (x = 0; x < FEATURES_COUNT; x++)
01125       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01126    ast_rwlock_unlock(&features_lock);
01127 }
01128 
01129 static int remap_feature(const char *name, const char *value)
01130 {
01131    int x, res = -1;
01132 
01133    ast_rwlock_wrlock(&features_lock);
01134    for (x = 0; x < FEATURES_COUNT; x++) {
01135       if (strcasecmp(builtin_features[x].sname, name))
01136          continue;
01137 
01138       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01139       res = 0;
01140       break;
01141    }
01142    ast_rwlock_unlock(&features_lock);
01143 
01144    return res;
01145 }
01146 
01147 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
01148 {
01149    int x;
01150    struct ast_flags features;
01151    int res = FEATURE_RETURN_PASSDIGITS;
01152    struct ast_call_feature *feature;
01153    const char *dynamic_features;
01154    char *tmp, *tok;
01155 
01156    if (sense == FEATURE_SENSE_CHAN) {
01157       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);   
01158       dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01159    } else {
01160       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);   
01161       dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES");
01162    }
01163    if (option_debug > 2)
01164       ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, code=%s, sense=%d, features=%d dynamic=%s\n", chan->name, peer->name, code, sense, features.flags, dynamic_features);
01165 
01166    ast_rwlock_rdlock(&features_lock);
01167    for (x = 0; x < FEATURES_COUNT; x++) {
01168       if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
01169           !ast_strlen_zero(builtin_features[x].exten)) {
01170          /* Feature is up for consideration */
01171          if (!strcmp(builtin_features[x].exten, code)) {
01172             res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
01173             break;
01174          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01175             if (res == FEATURE_RETURN_PASSDIGITS)
01176                res = FEATURE_RETURN_STOREDIGITS;
01177          }
01178       }
01179    }
01180    ast_rwlock_unlock(&features_lock);
01181 
01182    if (ast_strlen_zero(dynamic_features))
01183       return res;
01184 
01185    tmp = ast_strdupa(dynamic_features);
01186 
01187    while ((tok = strsep(&tmp, "#"))) {
01188       AST_LIST_LOCK(&feature_list); 
01189       if (!(feature = find_dynamic_feature(tok))) {
01190          AST_LIST_UNLOCK(&feature_list);
01191          continue;
01192       }
01193          
01194       /* Feature is up for consideration */
01195       if (!strcmp(feature->exten, code)) {
01196          if (option_verbose > 2)
01197             ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
01198          res = feature->operation(chan, peer, config, code, sense, feature);
01199          if (res != FEATURE_RETURN_KEEPTRYING) {
01200             AST_LIST_UNLOCK(&feature_list);
01201             break;
01202          }
01203          res = FEATURE_RETURN_PASSDIGITS;
01204       } else if (!strncmp(feature->exten, code, strlen(code)))
01205          res = FEATURE_RETURN_STOREDIGITS;
01206 
01207       AST_LIST_UNLOCK(&feature_list);
01208    }
01209    
01210    return res;
01211 }
01212 
01213 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
01214 {
01215    int x;
01216    
01217    ast_clear_flag(config, AST_FLAGS_ALL);
01218 
01219    ast_rwlock_rdlock(&features_lock);
01220    for (x = 0; x < FEATURES_COUNT; x++) {
01221       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
01222          continue;
01223 
01224       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01225          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01226 
01227       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01228          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01229    }
01230    ast_rwlock_unlock(&features_lock);
01231    
01232    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01233       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01234 
01235       if (dynamic_features) {
01236          char *tmp = ast_strdupa(dynamic_features);
01237          char *tok;
01238          struct ast_call_feature *feature;
01239 
01240          /* while we have a feature */
01241          while ((tok = strsep(&tmp, "#"))) {
01242             AST_LIST_LOCK(&feature_list);
01243             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01244                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01245                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01246                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01247                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01248             }
01249             AST_LIST_UNLOCK(&feature_list);
01250          }
01251       }
01252    }
01253 }
01254 
01255 /*! \todo XXX Check - this is very similar to the code in channel.c */
01256 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, const char *language)
01257 {
01258    int state = 0;
01259    int cause = 0;
01260    int to;
01261    struct ast_channel *chan;
01262    struct ast_channel *monitor_chans[2];
01263    struct ast_channel *active_channel;
01264    int res = 0, ready = 0;
01265    
01266    if ((chan = ast_request(type, format, data, &cause))) {
01267       ast_set_callerid(chan, cid_num, cid_name, cid_num);
01268       ast_string_field_set(chan, language, language);
01269       ast_channel_inherit_variables(caller, chan); 
01270       pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
01271       if (!chan->cdr) {
01272          chan->cdr=ast_cdr_alloc();
01273          if (chan->cdr) {
01274             ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
01275             ast_cdr_start(chan->cdr);
01276          }
01277       }
01278          
01279       if (!ast_call(chan, data, timeout)) {
01280          struct timeval started;
01281          int x, len = 0;
01282          char *disconnect_code = NULL, *dialed_code = NULL;
01283 
01284          ast_indicate(caller, AST_CONTROL_RINGING);
01285          /* support dialing of the featuremap disconnect code while performing an attended tranfer */
01286          ast_rwlock_rdlock(&features_lock);
01287          for (x = 0; x < FEATURES_COUNT; x++) {
01288             if (strcasecmp(builtin_features[x].sname, "disconnect"))
01289                continue;
01290 
01291             disconnect_code = builtin_features[x].exten;
01292             len = strlen(disconnect_code) + 1;
01293             dialed_code = alloca(len);
01294             memset(dialed_code, 0, len);
01295             break;
01296          }
01297          ast_rwlock_unlock(&features_lock);
01298          x = 0;
01299          started = ast_tvnow();
01300          to = timeout;
01301          while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
01302             struct ast_frame *f = NULL;
01303 
01304             monitor_chans[0] = caller;
01305             monitor_chans[1] = chan;
01306             active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01307 
01308             /* see if the timeout has been violated */
01309             if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01310                state = AST_CONTROL_UNHOLD;
01311                ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01312                break; /*doh! timeout*/
01313             }
01314 
01315             if (!active_channel)
01316                continue;
01317 
01318             if (chan && (chan == active_channel)){
01319                f = ast_read(chan);
01320                if (f == NULL) { /*doh! where'd he go?*/
01321                   state = AST_CONTROL_HANGUP;
01322                   res = 0;
01323                   break;
01324                }
01325                
01326                if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01327                   if (f->subclass == AST_CONTROL_RINGING) {
01328                      state = f->subclass;
01329                      if (option_verbose > 2)
01330                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
01331                      ast_indicate(caller, AST_CONTROL_RINGING);
01332                   } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01333                      state = f->subclass;
01334                      if (option_verbose > 2)
01335                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
01336                      ast_indicate(caller, AST_CONTROL_BUSY);
01337                      ast_frfree(f);
01338                      f = NULL;
01339                      break;
01340                   } else if (f->subclass == AST_CONTROL_ANSWER) {
01341                      /* This is what we are hoping for */
01342                      state = f->subclass;
01343                      ast_frfree(f);
01344                      f = NULL;
01345                      ready=1;
01346                      break;
01347                   } else if (f->subclass != -1) {
01348                      ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01349                   }
01350                   /* else who cares */
01351                }
01352 
01353             } else if (caller && (active_channel == caller)) {
01354                f = ast_read(caller);
01355                if (f == NULL) { /*doh! where'd he go?*/
01356                   if (caller->_softhangup && !chan->_softhangup) {
01357                      /* make this a blind transfer */
01358                      ready = 1;
01359                      break;
01360                   }
01361                   state = AST_CONTROL_HANGUP;
01362                   res = 0;
01363                   break;
01364                }
01365                
01366                if (f->frametype == AST_FRAME_DTMF) {
01367                   dialed_code[x++] = f->subclass;
01368                   dialed_code[x] = '\0';
01369                   if (strlen(dialed_code) == len) {
01370                      x = 0;
01371                   } else if (x && strncmp(dialed_code, disconnect_code, x)) {
01372                      x = 0;
01373                      dialed_code[x] = '\0';
01374                   }
01375                   if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
01376                      /* Caller Canceled the call */
01377                      state = AST_CONTROL_UNHOLD;
01378                      ast_frfree(f);
01379                      f = NULL;
01380                      break;
01381                   }
01382                }
01383             }
01384             if (f)
01385                ast_frfree(f);
01386          } /* end while */
01387       } else
01388          ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
01389    } else {
01390       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01391       switch(cause) {
01392       case AST_CAUSE_BUSY:
01393          state = AST_CONTROL_BUSY;
01394          break;
01395       case AST_CAUSE_CONGESTION:
01396          state = AST_CONTROL_CONGESTION;
01397          break;
01398       }
01399    }
01400    
01401    ast_indicate(caller, -1);
01402    if (chan && ready) {
01403       if (chan->_state == AST_STATE_UP) 
01404          state = AST_CONTROL_ANSWER;
01405       res = 0;
01406    } else if(chan) {
01407       res = -1;
01408       ast_hangup(chan);
01409       chan = NULL;
01410    } else {
01411       res = -1;
01412    }
01413    
01414    if (outstate)
01415       *outstate = state;
01416 
01417    if (chan && res <= 0) {
01418       if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
01419          char tmp[256];
01420          ast_cdr_init(chan->cdr, chan);
01421          snprintf(tmp, 256, "%s/%s", type, (char *)data);
01422          ast_cdr_setapp(chan->cdr,"Dial",tmp);
01423          ast_cdr_update(chan);
01424          ast_cdr_start(chan->cdr);
01425          ast_cdr_end(chan->cdr);
01426          /* If the cause wasn't handled properly */
01427          if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
01428             ast_cdr_failed(chan->cdr);
01429       } else {
01430          ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
01431       }
01432    }
01433    
01434    return chan;
01435 }
01436 
01437 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
01438 {
01439    /* Copy voice back and forth between the two channels.  Give the peer
01440       the ability to transfer calls with '#<extension' syntax. */
01441    struct ast_frame *f;
01442    struct ast_channel *who;
01443    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01444    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01445    int res;
01446    int diff;
01447    int hasfeatures=0;
01448    int hadfeatures=0;
01449    struct ast_option_header *aoh;
01450    struct ast_bridge_config backup_config;
01451    struct ast_cdr *bridge_cdr;
01452 
01453    memset(&backup_config, 0, sizeof(backup_config));
01454 
01455    config->start_time = ast_tvnow();
01456 
01457    if (chan && peer) {
01458       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01459       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01460    } else if (chan)
01461       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01462 
01463    if (monitor_ok) {
01464       const char *monitor_exec;
01465       struct ast_channel *src = NULL;
01466       if (!monitor_app) { 
01467          if (!(monitor_app = pbx_findapp("Monitor")))
01468             monitor_ok=0;
01469       }
01470       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01471          src = chan;
01472       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01473          src = peer;
01474       if (monitor_app && src) {
01475          char *tmp = ast_strdupa(monitor_exec);
01476          pbx_exec(src, monitor_app, tmp);
01477       }
01478    }
01479    
01480    set_config_flags(chan, peer, config);
01481    config->firstpass = 1;
01482 
01483    /* Answer if need be */
01484    if (ast_answer(chan))
01485       return -1;
01486    peer->appl = "Bridged Call";
01487    peer->data = chan->name;
01488 
01489    /* copy the userfield from the B-leg to A-leg if applicable */
01490    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01491       char tmp[256];
01492       if (!ast_strlen_zero(chan->cdr->userfield)) {
01493          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01494          ast_cdr_appenduserfield(chan, tmp);
01495       } else
01496          ast_cdr_setuserfield(chan, peer->cdr->userfield);
01497       /* free the peer's cdr without ast_cdr_free complaining */
01498       free(peer->cdr);
01499       peer->cdr = NULL;
01500    }
01501 
01502    for (;;) {
01503       struct ast_channel *other; /* used later */
01504 
01505       res = ast_channel_bridge(chan, peer, config, &f, &who);
01506 
01507       if (config->feature_timer) {
01508          /* Update time limit for next pass */
01509          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
01510          config->feature_timer -= diff;
01511          if (hasfeatures) {
01512             /* Running on backup config, meaning a feature might be being
01513                activated, but that's no excuse to keep things going 
01514                indefinitely! */
01515             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01516                if (option_debug)
01517                   ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01518                config->feature_timer = 0;
01519                who = chan;
01520                if (f)
01521                   ast_frfree(f);
01522                f = NULL;
01523                res = 0;
01524             } else if (config->feature_timer <= 0) {
01525                /* Not *really* out of time, just out of time for
01526                   digits to come in for features. */
01527                if (option_debug)
01528                   ast_log(LOG_DEBUG, "Timed out for feature!\n");
01529                if (!ast_strlen_zero(peer_featurecode)) {
01530                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01531                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
01532                }
01533                if (!ast_strlen_zero(chan_featurecode)) {
01534                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01535                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
01536                }
01537                if (f)
01538                   ast_frfree(f);
01539                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01540                if (!hasfeatures) {
01541                   /* Restore original (possibly time modified) bridge config */
01542                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01543                   memset(&backup_config, 0, sizeof(backup_config));
01544                }
01545                hadfeatures = hasfeatures;
01546                /* Continue as we were */
01547                continue;
01548             } else if (!f) {
01549                /* The bridge returned without a frame and there is a feature in progress.
01550                 * However, we don't think the feature has quite yet timed out, so just
01551                 * go back into the bridge. */
01552                continue;
01553             }
01554          } else {
01555             if (config->feature_timer <=0) {
01556                /* We ran out of time */
01557                config->feature_timer = 0;
01558                who = chan;
01559                if (f)
01560                   ast_frfree(f);
01561                f = NULL;
01562                res = 0;
01563             }
01564          }
01565       }
01566       if (res < 0) {
01567          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
01568             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01569          return -1;
01570       }
01571       
01572       if (!f || (f->frametype == AST_FRAME_CONTROL &&
01573             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
01574                f->subclass == AST_CONTROL_CONGESTION ) ) ) {
01575          res = -1;
01576          break;
01577       }
01578       /* many things should be sent to the 'other' channel */
01579       other = (who == chan) ? peer : chan;
01580       if (f->frametype == AST_FRAME_CONTROL) {
01581          switch (f->subclass) {
01582          case AST_CONTROL_RINGING:
01583          case AST_CONTROL_FLASH:
01584          case -1:
01585             ast_indicate(other, f->subclass);
01586             break;
01587          case AST_CONTROL_HOLD:
01588          case AST_CONTROL_UNHOLD:
01589             ast_indicate_data(other, f->subclass, f->data, f->datalen);
01590             break;
01591          case AST_CONTROL_OPTION:
01592             aoh = f->data;
01593             /* Forward option Requests */
01594             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
01595                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
01596                   f->datalen - sizeof(struct ast_option_header), 0);
01597             }
01598             break;
01599          }
01600       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
01601          /* eat it */
01602       } else if (f->frametype == AST_FRAME_DTMF) {
01603          char *featurecode;
01604          int sense;
01605 
01606          hadfeatures = hasfeatures;
01607          /* This cannot overrun because the longest feature is one shorter than our buffer */
01608          if (who == chan) {
01609             sense = FEATURE_SENSE_CHAN;
01610             featurecode = chan_featurecode;
01611          } else  {
01612             sense = FEATURE_SENSE_PEER;
01613             featurecode = peer_featurecode;
01614          }
01615          /*! append the event to featurecode. we rely on the string being zero-filled, and
01616           * not overflowing it. 
01617           * \todo XXX how do we guarantee the latter ?
01618           */
01619          featurecode[strlen(featurecode)] = f->subclass;
01620          /* Get rid of the frame before we start doing "stuff" with the channels */
01621          ast_frfree(f);
01622          f = NULL;
01623          config->feature_timer = backup_config.feature_timer;
01624          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01625          switch(res) {
01626          case FEATURE_RETURN_PASSDIGITS:
01627             ast_dtmf_stream(other, who, featurecode, 0);
01628             /* Fall through */
01629          case FEATURE_RETURN_SUCCESS:
01630             memset(featurecode, 0, sizeof(chan_featurecode));
01631             break;
01632          }
01633          if (res >= FEATURE_RETURN_PASSDIGITS) {
01634             res = 0;
01635          } else 
01636             break;
01637          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01638          if (hadfeatures && !hasfeatures) {
01639             /* Restore backup */
01640             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01641             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01642          } else if (hasfeatures) {
01643             if (!hadfeatures) {
01644                /* Backup configuration */
01645                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01646                /* Setup temporary config options */
01647                config->play_warning = 0;
01648                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01649                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01650                config->warning_freq = 0;
01651                config->warning_sound = NULL;
01652                config->end_sound = NULL;
01653                config->start_sound = NULL;
01654                config->firstpass = 0;
01655             }
01656             config->start_time = ast_tvnow();
01657             config->feature_timer = featuredigittimeout;
01658             if (option_debug)
01659                ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01660          }
01661       }
01662       if (f)
01663          ast_frfree(f);
01664 
01665    }
01666 
01667    /* arrange the cdrs */
01668    bridge_cdr = ast_cdr_alloc();
01669    if (bridge_cdr) {
01670       if (chan->cdr && peer->cdr) { /* both of them? merge */
01671          ast_channel_lock(chan);  /* lock the channel before modifing cdrs */
01672          ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the  destination as a base, but, really, it's random */
01673          ast_cdr_start(bridge_cdr); /* now is the time to start */
01674 
01675          /* absorb the channel cdr */
01676          ast_cdr_merge(bridge_cdr, chan->cdr);
01677          if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED)) 
01678             ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01679 
01680          chan->cdr = NULL; /* remove pointer to freed memory before releasing the lock */
01681 
01682          ast_channel_unlock(chan);
01683          
01684          /* absorb the peer cdr */
01685          ast_channel_lock(peer);
01686          ast_cdr_merge(bridge_cdr, peer->cdr);
01687          if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
01688             ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */
01689          
01690          peer->cdr = NULL;
01691          ast_channel_unlock(peer);
01692 
01693          ast_channel_lock(chan);
01694          chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01695          ast_channel_unlock(chan);
01696 
01697       } else if (chan->cdr) {
01698 
01699          ast_channel_lock(chan); /* Lock before modifying CDR */
01700          /* take the cdr from the channel - literally */
01701          ast_cdr_init(bridge_cdr,chan);
01702          /* absorb this data */
01703          ast_cdr_merge(bridge_cdr, chan->cdr);
01704          if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
01705             ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01706          chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01707          ast_channel_unlock(chan);
01708       } else if (peer->cdr) {
01709          ast_channel_lock(peer); /* Lock before modifying CDR */
01710          /* take the cdr from the peer - literally */
01711          ast_cdr_init(bridge_cdr,peer);
01712          /* absorb this data */
01713          ast_cdr_merge(bridge_cdr, peer->cdr);
01714          if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
01715             ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01716          peer->cdr = NULL;
01717          peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01718          ast_channel_unlock(peer);
01719       } else {
01720          ast_channel_lock(chan); /* Lock before modifying CDR */
01721          /* make up a new cdr */
01722          ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */
01723          chan->cdr = bridge_cdr; /*  */
01724          ast_channel_unlock(chan);
01725       }
01726       if (ast_strlen_zero(bridge_cdr->dstchannel)) {
01727          if (strcmp(bridge_cdr->channel, peer->name) != 0)
01728             ast_cdr_setdestchan(bridge_cdr, peer->name);
01729          else
01730             ast_cdr_setdestchan(bridge_cdr, chan->name);
01731       }
01732    }
01733    return res;
01734 }
01735 
01736 static void post_manager_event(const char *s, char *parkingexten, struct ast_channel *chan)
01737 {
01738    manager_event(EVENT_FLAG_CALL, s,
01739       "Exten: %s\r\n"
01740       "Channel: %s\r\n"
01741       "CallerID: %s\r\n"
01742       "CallerIDName: %s\r\n"
01743       "Uniqueid: %s\r\n\r\n",
01744       parkingexten, 
01745       chan->name,
01746       S_OR(chan->cid.cid_num, "<unknown>"),
01747       S_OR(chan->cid.cid_name, "<unknown>"),
01748       chan->uniqueid
01749       );
01750 }
01751 
01752 /*! \brief Take care of parked calls and unpark them if needed */
01753 static void *do_parking_thread(void *ignore)
01754 {
01755    fd_set rfds, efds;   /* results from previous select, to be preserved across loops. */
01756    FD_ZERO(&rfds);
01757    FD_ZERO(&efds);
01758 
01759    for (;;) {
01760       struct parkeduser *pu, *pl, *pt = NULL;
01761       int ms = -1;   /* select timeout, uninitialized */
01762       int max = -1;  /* max fd, none there yet */
01763       fd_set nrfds, nefds; /* args for the next select */
01764       FD_ZERO(&nrfds);
01765       FD_ZERO(&nefds);
01766 
01767       ast_mutex_lock(&parking_lock);
01768       pl = NULL;
01769       pu = parkinglot;
01770       /* navigate the list with prev-cur pointers to support removals */
01771       while (pu) {
01772          struct ast_channel *chan = pu->chan;   /* shorthand */
01773          int tms;        /* timeout for this item */
01774          int x;          /* fd index in channel */
01775          struct ast_context *con;
01776 
01777          if (pu->notquiteyet) { /* Pretend this one isn't here yet */
01778             pl = pu;
01779             pu = pu->next;
01780             continue;
01781          }
01782          tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
01783          if (tms > pu->parkingtime) {
01784             ast_indicate(chan, AST_CONTROL_UNHOLD);
01785             /* Get chan, exten from derived kludge */
01786             if (pu->peername[0]) {
01787                char *peername = ast_strdupa(pu->peername);
01788                char *cp = strrchr(peername, '-');
01789                if (cp) 
01790                   *cp = 0;
01791                con = ast_context_find(parking_con_dial);
01792                if (!con) {
01793                   con = ast_context_create(NULL, parking_con_dial, registrar);
01794                   if (!con)
01795                      ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
01796                }
01797                if (con) {
01798                   char returnexten[AST_MAX_EXTENSION];
01799                   snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername);
01800                   ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
01801                }
01802                set_c_e_p(chan, parking_con_dial, peername, 1);
01803             } else {
01804                /* They've been waiting too long, send them back to where they came.  Theoretically they
01805                   should have their original extensions and such, but we copy to be on the safe side */
01806                set_c_e_p(chan, pu->context, pu->exten, pu->priority);
01807             }
01808 
01809             post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
01810 
01811             if (option_verbose > 1) 
01812                ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", chan->name, pu->parkingnum, chan->context, chan->exten, chan->priority);
01813             /* Start up the PBX, or hang them up */
01814             if (ast_pbx_start(chan))  {
01815                ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
01816                ast_hangup(chan);
01817             }
01818             /* And take them out of the parking lot */
01819             if (pl) 
01820                pl->next = pu->next;
01821             else
01822                parkinglot = pu->next;
01823             pt = pu;
01824             pu = pu->next;
01825             con = ast_context_find(parking_con);
01826             if (con) {
01827                if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
01828                   ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01829                else
01830                   notify_metermaids(pt->parkingexten, parking_con);
01831             } else
01832                ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01833             free(pt);
01834          } else { /* still within parking time, process descriptors */
01835             for (x = 0; x < AST_MAX_FDS; x++) {
01836                struct ast_frame *f;
01837 
01838                if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
01839                   continue;   /* nothing on this descriptor */
01840 
01841                if (FD_ISSET(chan->fds[x], &efds))
01842                   ast_set_flag(chan, AST_FLAG_EXCEPTION);
01843                else
01844                   ast_clear_flag(chan, AST_FLAG_EXCEPTION);
01845                chan->fdno = x;
01846 
01847                /* See if they need servicing */
01848                f = ast_read(chan);
01849                if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass ==  AST_CONTROL_HANGUP)) {
01850                   if (f)
01851                      ast_frfree(f);
01852                   post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
01853 
01854                   /* There's a problem, hang them up*/
01855                   if (option_verbose > 1) 
01856                      ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
01857                   ast_hangup(chan);
01858                   /* And take them out of the parking lot */
01859                   if (pl) 
01860                      pl->next = pu->next;
01861                   else
01862                      parkinglot = pu->next;
01863                   pt = pu;
01864                   pu = pu->next;
01865                   con = ast_context_find(parking_con);
01866                   if (con) {
01867                      if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
01868                         ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01869                   else
01870                      notify_metermaids(pt->parkingexten, parking_con);
01871                   } else
01872                      ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01873                   free(pt);
01874                   break;
01875                } else {
01876                   /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
01877                   ast_frfree(f);
01878                   if (pu->moh_trys < 3 && !chan->generatordata) {
01879                      if (option_debug)
01880                         ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
01881                      ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
01882                         S_OR(parkmohclass, NULL),
01883                         !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
01884                      pu->moh_trys++;
01885                   }
01886                   goto std;   /*! \todo XXX Ick: jumping into an else statement??? XXX */
01887                }
01888 
01889             } /* end for */
01890             if (x >= AST_MAX_FDS) {
01891 std:              for (x=0; x<AST_MAX_FDS; x++) {  /* mark fds for next round */
01892                   if (chan->fds[x] > -1) {
01893                      FD_SET(chan->fds[x], &nrfds);
01894                      FD_SET(chan->fds[x], &nefds);
01895                      if (chan->fds[x] > max)
01896                         max = chan->fds[x];
01897                   }
01898                }
01899                /* Keep track of our shortest wait */
01900                if (tms < ms || ms < 0)
01901                   ms = tms;
01902                pl = pu;
01903                pu = pu->next;
01904             }
01905          }
01906       } /* end while */
01907       ast_mutex_unlock(&parking_lock);
01908       rfds = nrfds;
01909       efds = nefds;
01910       {
01911          struct timeval tv = ast_samp2tv(ms, 1000);
01912          /* Wait for something to happen */
01913          ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
01914       }
01915       pthread_testcancel();
01916    }
01917    return NULL;   /* Never reached */
01918 }
01919 
01920 /*! \brief Park a call */
01921 static int park_call_exec(struct ast_channel *chan, void *data)
01922 {
01923    /* Cache the original channel name in case we get masqueraded in the middle
01924     * of a park--it is still theoretically possible for a transfer to happen before
01925     * we get here, but it is _really_ unlikely */
01926    char *orig_chan_name = ast_strdupa(chan->name);
01927    char orig_exten[AST_MAX_EXTENSION];
01928    int orig_priority = chan->priority;
01929 
01930    /* Data is unused at the moment but could contain a parking
01931       lot context eventually */
01932    int res = 0;
01933    struct ast_module_user *u;
01934 
01935    u = ast_module_user_add(chan);
01936 
01937    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
01938 
01939    /* Setup the exten/priority to be s/1 since we don't know
01940       where this call should return */
01941    strcpy(chan->exten, "s");
01942    chan->priority = 1;
01943    /* Answer if call is not up */
01944    if (chan->_state != AST_STATE_UP)
01945       res = ast_answer(chan);
01946    /* Sleep to allow VoIP streams to settle down */
01947    if (!res)
01948       res = ast_safe_sleep(chan, 1000);
01949    /* Park the call */
01950    if (!res) {
01951       res = park_call_full(chan, chan, 0, NULL, orig_chan_name);
01952       /* Continue on in the dialplan */
01953       if (res == 1) {
01954          ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
01955          chan->priority = orig_priority;
01956          res = 0;
01957       } else if (!res)
01958          res = AST_PBX_KEEPALIVE;
01959    }
01960 
01961    ast_module_user_remove(u);
01962 
01963    return res;
01964 }
01965 
01966 /*! \brief Pickup parked call */
01967 static int park_exec(struct ast_channel *chan, void *data)
01968 {
01969    int res = 0;
01970    struct ast_module_user *u;
01971    struct ast_channel *peer=NULL;
01972    struct parkeduser *pu, *pl=NULL;
01973    struct ast_context *con;
01974 
01975    int park;
01976    struct ast_bridge_config config;
01977 
01978    if (!data) {
01979       ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
01980       return -1;
01981    }
01982    
01983    u = ast_module_user_add(chan);
01984 
01985    park = atoi((char *)data);
01986    ast_mutex_lock(&parking_lock);
01987    pu = parkinglot;
01988    while(pu) {
01989       if (pu->parkingnum == park) {
01990          if (pl)
01991             pl->next = pu->next;
01992          else
01993             parkinglot = pu->next;
01994          break;
01995       }
01996       pl = pu;
01997       pu = pu->next;
01998    }
01999    ast_mutex_unlock(&parking_lock);
02000    if (pu) {
02001       peer = pu->chan;
02002       con = ast_context_find(parking_con);
02003       if (con) {
02004          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
02005             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02006          else
02007             notify_metermaids(pu->parkingexten, parking_con);
02008       } else
02009          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
02010 
02011       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
02012          "Exten: %s\r\n"
02013          "Channel: %s\r\n"
02014          "From: %s\r\n"
02015          "CallerID: %s\r\n"
02016          "CallerIDName: %s\r\n"
02017          "Uniqueid: %s\r\n",
02018          pu->parkingexten, pu->chan->name, chan->name,
02019          S_OR(pu->chan->cid.cid_num, "<unknown>"),
02020          S_OR(pu->chan->cid.cid_name, "<unknown>"),
02021          pu->chan->uniqueid
02022          );
02023 
02024       free(pu);
02025    }
02026    /* JK02: it helps to answer the channel if not already up */
02027    if (chan->_state != AST_STATE_UP)
02028       ast_answer(chan);
02029 
02030    if (peer) {
02031       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
02032       
02033       if (!ast_strlen_zero(courtesytone)) {
02034          int error = 0;
02035          ast_indicate(peer, AST_CONTROL_UNHOLD);
02036          if (parkedplay == 0) {
02037             error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
02038          } else if (parkedplay == 1) {
02039             error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
02040          } else if (parkedplay == 2) {
02041             if (!ast_streamfile(chan, courtesytone, chan->language) &&
02042                   !ast_streamfile(peer, courtesytone, chan->language)) {
02043                /*! \todo XXX we would like to wait on both! */
02044                res = ast_waitstream(chan, "");
02045                if (res >= 0)
02046                   res = ast_waitstream(peer, "");
02047                if (res < 0)
02048                   error = 1;
02049             }
02050                         }
02051          if (error) {
02052             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
02053             ast_hangup(peer);
02054             ast_module_user_remove(u);
02055             return -1;
02056          }
02057       } else
02058          ast_indicate(peer, AST_CONTROL_UNHOLD); 
02059 
02060       res = ast_channel_make_compatible(chan, peer);
02061       if (res < 0) {
02062          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
02063          ast_hangup(peer);
02064          ast_module_user_remove(u);
02065          return -1;
02066       }
02067       /* This runs sorta backwards, since we give the incoming channel control, as if it
02068          were the person called. */
02069       if (option_verbose > 2) 
02070          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
02071 
02072       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
02073       ast_cdr_setdestchan(chan->cdr, peer->name);
02074       memset(&config, 0, sizeof(struct ast_bridge_config));
02075       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02076       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02077       res = ast_bridge_call(chan, peer, &config);
02078 
02079       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
02080       ast_cdr_setdestchan(chan->cdr, peer->name);
02081 
02082       /* Simulate the PBX hanging up */
02083       if (res != AST_PBX_NO_HANGUP_PEER)
02084          ast_hangup(peer);
02085       ast_module_user_remove(u);
02086       return res;
02087    } else {
02088       /*! \todo XXX Play a message XXX */
02089       if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
02090          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
02091       if (option_verbose > 2) 
02092          ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
02093       res = -1;
02094    }
02095 
02096    ast_module_user_remove(u);
02097 
02098    return res;
02099 }
02100 
02101 int ast_hold_call(struct ast_channel *chan, struct ast_channel *peer)
02102 {
02103    /* We put the user in the parking list, then wake up the parking thread to be sure it looks
02104       after these channels too */
02105    struct holdeduser *pu;
02106    pu = malloc(sizeof(struct holdeduser));
02107    if (pu) {
02108       memset(pu, 0, sizeof(pu));
02109       ast_mutex_lock(&holding_lock);
02110       chan->appl = "Holded Call";
02111       chan->data = NULL;
02112 
02113       pu->chan = chan;
02114       strncpy(pu->uniqueid, chan->uniqueid, sizeof(pu->uniqueid));
02115       strncpy(pu->uniqueidpeer, peer->uniqueid, sizeof(pu->uniqueidpeer));
02116       /* Start music on hold */
02117       ast_moh_start(pu->chan, NULL, NULL);
02118       gettimeofday(&pu->start, NULL);
02119       pu->next = holdlist;
02120       holdlist = pu;
02121       ast_mutex_unlock(&holding_lock);
02122       /* Wake up the (presumably select()ing) thread */
02123       pthread_kill(holding_thread, SIGURG);
02124 
02125       manager_event(EVENT_FLAG_CALL, "HoldedCall",
02126                          "Channel1: %s\r\n"
02127                          "Channel2: %s\r\n"
02128                       "Uniqueid1: %s\r\n"
02129                       "Uniqueid2: %s\r\n"
02130                              ,pu->chan->name, peer->name, pu->chan->uniqueid, peer->uniqueid);
02131 
02132    } else {
02133       ast_log(LOG_WARNING, "Out of memory\n");
02134       return -1;
02135    }
02136    return 0;
02137 }
02138 
02139 int ast_masq_hold_call(struct ast_channel *rchan, struct ast_channel *peer)
02140 {
02141    struct ast_channel *chan;
02142    struct ast_frame *f;
02143    /* Make a new, fake channel that we'll use to masquerade in the real one */
02144    chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Onhold/%s",rchan->name);
02145    if (chan) {
02146       /* Let us keep track of the channel name */
02147       ast_string_field_build(chan, name, "Onhold/%s",rchan->name);
02148       /* Make formats okay */
02149       chan->readformat = rchan->readformat;
02150       chan->writeformat = rchan->writeformat;
02151       ast_channel_masquerade(chan, rchan);
02152       /* Setup the extensions and such */
02153       strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
02154       strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
02155       chan->priority = rchan->priority;
02156       /* this might be dirty, but we need to preserve the uniqueid */
02157       ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid);
02158       /* Make the masq execute */
02159       f = ast_read(chan);
02160       if (f)
02161          ast_frfree(f);
02162       ast_hold_call(chan, peer);
02163       return -1;
02164    } else {
02165       ast_log(LOG_WARNING, "Unable to create holded channel\n");
02166       return -1;
02167    }
02168    return 0;
02169 }
02170 
02171 int ast_retrieve_call(struct ast_channel *chan, char *uniqueid)
02172 {
02173    int res=-1, dres=-1;
02174    struct ast_channel *peer=NULL;
02175    struct ast_bridge_config config;
02176 
02177    peer = ast_get_holded_call(uniqueid);
02178 
02179    /* JK02: it helps to answer the channel if not already up */
02180    if (chan->_state != AST_STATE_UP) {
02181       ast_answer(chan);
02182    }
02183 
02184    if (peer) {
02185       ast_mutex_unlock(&peer->lock);
02186       ast_moh_stop(peer);
02187       res = ast_channel_make_compatible(chan, peer);
02188       if (res < 0) {
02189          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
02190          ast_hangup(peer);
02191          return -1;
02192       }
02193       /* This runs sorta backwards, since we give the incoming channel control, as if it
02194          were the person called. */
02195       if (option_verbose > 2)
02196          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to holded call %s\n", chan->name, peer->name);
02197 
02198       memset(&config,0,sizeof(struct ast_bridge_config));
02199       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02200       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02201       config.timelimit = 0;
02202       config.play_warning = 0;
02203       config.warning_freq = 0;
02204       config.warning_sound=NULL;
02205       res = ast_bridge_call(chan,peer,&config);
02206 
02207       /* Simulate the PBX hanging up */
02208       if (res != AST_PBX_NO_HANGUP_PEER)
02209          ast_hangup(peer);
02210       return res;
02211    } else {
02212       /* XXX Play a message XXX */
02213      dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
02214      if (!dres)
02215        dres = ast_waitstream(chan, "");
02216      else {
02217        ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
02218        dres = 0;
02219      }
02220    }
02221    return res;
02222 }
02223 
02224 int ast_retrieve_call_to_death(char *uniqueid)
02225 {
02226    int res=-1;
02227    struct ast_channel *peer=NULL;
02228 
02229    peer = ast_get_holded_call(uniqueid);
02230 
02231    if (peer) {
02232       res=0;
02233       if (option_verbose > 2)
02234          ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name);
02235       ast_mutex_unlock(&peer->lock);
02236       ast_hangup(peer);
02237    } else {
02238       ast_log(LOG_WARNING, "Could not find channel with uniqueid %s to retrieve.\n", uniqueid);
02239    }
02240    return res;
02241 }
02242 
02243 struct ast_channel *ast_get_holded_call(char *uniqueid)
02244 {
02245    int res=-1;
02246    struct ast_channel *peer=NULL;
02247    struct holdeduser *pu, *pl=NULL;
02248 
02249    ast_mutex_lock(&holding_lock);
02250    pu = holdlist;
02251    while(pu) {
02252       if (!strncmp(uniqueid,pu->uniqueid,sizeof(pu->uniqueid))) {
02253          if (pl)
02254             pl->next = pu->next;
02255          else
02256             holdlist = pu->next;
02257          break;
02258       }
02259       pl = pu;
02260       pu = pu->next;
02261    }
02262    ast_mutex_unlock(&holding_lock);
02263    if (pu) {
02264       peer = ast_get_channel_by_uniqueid_locked(pu->uniqueid);
02265       free(pu);
02266       if (peer) {
02267           res=0;
02268           if (option_verbose > 2)
02269          ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name);
02270           ast_moh_stop(peer);
02271           return peer;
02272       } else {
02273           if (option_verbose > 2)
02274          ast_verbose(VERBOSE_PREFIX_3 "Could not find channel with uniqueid %s.\n", uniqueid);
02275           return NULL;
02276       }
02277    } else {
02278       ast_log(LOG_WARNING, "Could not find held channel with uniqueid %s to retrieve.\n", uniqueid);
02279    }
02280    return NULL;
02281 }
02282 
02283 /* this is our autmagically service thread that keeps channels onhold happy */
02284 static void *do_holding_thread(void *ignore)
02285 {
02286    int ms, tms, max;
02287    struct holdeduser *pu, *pl, *pt = NULL;
02288    struct timeval tv;
02289    struct ast_frame *f;
02290    int x;
02291    fd_set rfds, efds;
02292    fd_set nrfds, nefds;
02293    FD_ZERO(&rfds);
02294    FD_ZERO(&efds);
02295    for (;;) {
02296       ms = -1;
02297       max = -1;
02298       ast_mutex_lock(&holding_lock);
02299       pl = NULL;
02300       pu = holdlist;
02301       gettimeofday(&tv, NULL);
02302       FD_ZERO(&nrfds);
02303       FD_ZERO(&nefds);
02304       while(pu) {
02305          tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
02306             for (x=0;x<AST_MAX_FDS;x++) {
02307                if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
02308                   if (FD_ISSET(pu->chan->fds[x], &efds))
02309                      ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
02310                   else
02311                      ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
02312                   pu->chan->fdno = x;
02313                   /* See if they need servicing */
02314                   f = ast_read(pu->chan);
02315                   if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
02316                      /* There's a problem, hang them up*/
02317                      if (option_verbose > 1)
02318                         ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being onhold\n", pu->chan->name);
02319                      ast_hangup(pu->chan);
02320                      /* find the corresponding channel and hang them up too! */
02321                      /* but only if it is not bridged yet! */
02322                      /* And take them out of the parking lot */
02323                      if (pl)
02324                         pl->next = pu->next;
02325                      else
02326                         holdlist = pu->next;
02327                      pt = pu;
02328                      pu = pu->next;
02329                      free(pt);
02330                      break;
02331                   } else {
02332                      /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
02333                      ast_frfree(f);
02334                      goto std;   /* XXX Ick: jumping into an else statement??? XXX */
02335                   }
02336                }
02337             }
02338             if (x >= AST_MAX_FDS) {
02339 std:              for (x=0;x<AST_MAX_FDS;x++) {
02340                   /* Keep this one for next one */
02341                   if (pu->chan->fds[x] > -1) {
02342                      FD_SET(pu->chan->fds[x], &nrfds);
02343                      FD_SET(pu->chan->fds[x], &nefds);
02344                      if (pu->chan->fds[x] > max)
02345                         max = pu->chan->fds[x];
02346                   }
02347                }
02348                /* Keep track of our longest wait */
02349                if ((tms < ms) || (ms < 0))
02350                   ms = tms;
02351                pl = pu;
02352                pu = pu->next;
02353             }
02354       }
02355       ast_mutex_unlock(&holding_lock);
02356       rfds = nrfds;
02357       efds = nefds;
02358       tv.tv_sec = ms / 1000;
02359       tv.tv_usec = (ms % 1000) * 1000;
02360       /* Wait for something to happen */
02361       ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
02362       pthread_testcancel();
02363    }
02364    return NULL;   /* Never reached */
02365 }
02366 
02367 static int retrieve_call_exec(struct ast_channel *chan, void *data) {
02368    int res=0;
02369    struct ast_module_user *u;
02370    char *uniqueid = (char *)data;
02371    u = ast_module_user_add(chan);
02372        res = ast_retrieve_call(chan, uniqueid);
02373    ast_module_user_remove(u);
02374    return res;
02375 }
02376 
02377 static int handle_showfeatures(int fd, int argc, char *argv[])
02378 {
02379    int i;
02380    struct ast_call_feature *feature;
02381    char format[] = "%-25s %-7s %-7s\n";
02382 
02383    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
02384    ast_cli(fd, format, "---------------", "-------", "-------");
02385 
02386    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
02387 
02388    ast_rwlock_rdlock(&features_lock);
02389    for (i = 0; i < FEATURES_COUNT; i++)
02390       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
02391    ast_rwlock_unlock(&features_lock);
02392 
02393    ast_cli(fd, "\n");
02394    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
02395    ast_cli(fd, format, "---------------", "-------", "-------");
02396    if (AST_LIST_EMPTY(&feature_list))
02397       ast_cli(fd, "(none)\n");
02398    else {
02399       AST_LIST_LOCK(&feature_list);
02400       AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
02401          ast_cli(fd, format, feature->sname, "no def", feature->exten); 
02402       AST_LIST_UNLOCK(&feature_list);
02403    }
02404    ast_cli(fd, "\nCall parking\n");
02405    ast_cli(fd, "------------\n");
02406    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
02407    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
02408    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
02409    ast_cli(fd,"\n");
02410    
02411    return RESULT_SUCCESS;
02412 }
02413 
02414 static char mandescr_bridge[] =
02415 "Description: Bridge together two channels already in the PBX\n"
02416 "Variables: ( Headers marked with * are required )\n"
02417 "   *Channel1: Channel to Bridge to Channel2\n"
02418 "   *Channel2: Channel to Bridge to Channel1\n"
02419 "        Tone: (Yes|No) Play courtesy tone to Channel 2\n"
02420 "\n";
02421 
02422 static void do_bridge_masquerade(struct ast_channel *chan, struct ast_channel *tmpchan)
02423 {
02424    ast_moh_stop(chan);
02425    ast_mutex_lock(&chan->lock);
02426    ast_setstate(tmpchan, chan->_state);
02427    tmpchan->readformat = chan->readformat;
02428    tmpchan->writeformat = chan->writeformat;
02429    ast_channel_masquerade(tmpchan, chan);
02430    ast_mutex_lock(&tmpchan->lock);
02431    ast_do_masquerade(tmpchan);
02432    /* when returning from bridge, the channel will continue at the next priority */
02433    ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
02434    ast_mutex_unlock(&tmpchan->lock);
02435    ast_mutex_unlock(&chan->lock);
02436 }
02437 
02438 static int action_bridge(struct mansession *s, const struct message *m)
02439 {
02440    const char *channela = astman_get_header(m, "Channel1");
02441    const char *channelb = astman_get_header(m, "Channel2");
02442    const char *playtone = astman_get_header(m, "Tone");
02443    struct ast_channel *chana = NULL, *chanb = NULL;
02444    struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
02445    struct ast_bridge_thread_obj *tobj = NULL;
02446 
02447    /* make sure valid channels were specified */
02448    if (!ast_strlen_zero(channela) && !ast_strlen_zero(channelb)) {
02449       chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela));
02450       chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb));
02451       if (chana)
02452          ast_mutex_unlock(&chana->lock);
02453       if (chanb)
02454          ast_mutex_unlock(&chanb->lock);
02455 
02456       /* send errors if any of the channels could not be found/locked */
02457       if (!chana) {
02458          char buf[256];
02459          snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
02460          astman_send_error(s, m, buf);
02461          return 0;
02462       }
02463       if (!chanb) {
02464          char buf[256];
02465          snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
02466          astman_send_error(s, m, buf);
02467          return 0;
02468       }
02469    } else {
02470       astman_send_error(s, m, "Missing channel parameter in request");
02471       return 0;
02472    }
02473 
02474    /* Answer the channels if needed */
02475    if (chana->_state != AST_STATE_UP)
02476       ast_answer(chana);
02477    if (chanb->_state != AST_STATE_UP)
02478       ast_answer(chanb);
02479 
02480    /* create the placeholder channels and grab the other channels */
02481    if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
02482       NULL, NULL, 0, "Bridge/%s", chana->name))) {
02483       astman_send_error(s, m, "Unable to create temporary channel!");
02484       return 1;
02485    }
02486 
02487    if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
02488       NULL, NULL, 0, "Bridge/%s", chanb->name))) {
02489       astman_send_error(s, m, "Unable to create temporary channels!");
02490       ast_channel_free(tmpchana);
02491       return 1;
02492    }
02493 
02494    do_bridge_masquerade(chana, tmpchana);
02495    do_bridge_masquerade(chanb, tmpchanb);
02496    
02497    /* make the channels compatible, send error if we fail doing so */
02498    if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
02499       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
02500       astman_send_error(s, m, "Could not make channels compatible for manager bridge");
02501       ast_hangup(tmpchana);
02502       ast_hangup(tmpchanb);
02503       return 1;
02504    }
02505 
02506    /* setup the bridge thread object and start the bridge */
02507    if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
02508       ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
02509       astman_send_error(s, m, "Unable to spawn a new bridge thread");
02510       ast_hangup(tmpchana);
02511       ast_hangup(tmpchanb);
02512       return 1;
02513    }
02514 
02515    tobj->chan = tmpchana;
02516    tobj->peer = tmpchanb;
02517    tobj->return_to_pbx = 1;
02518    
02519    if (ast_true(playtone)) {
02520       if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
02521          if (ast_waitstream(tmpchanb, "") < 0)
02522             ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
02523       }
02524    }
02525 
02526    ast_bridge_call_thread_launch(tobj);
02527 
02528    astman_send_ack(s, m, "Launched bridge thread with success");
02529 
02530    return 0;
02531 }
02532 
02533 static char showfeatures_help[] =
02534 "Usage: feature list\n"
02535 "       Lists currently configured features.\n";
02536 
02537 static int handle_parkedcalls(int fd, int argc, char *argv[])
02538 {
02539    struct parkeduser *cur;
02540    int numparked = 0;
02541 
02542    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
02543       , "Context", "Extension", "Pri", "Timeout");
02544 
02545    ast_mutex_lock(&parking_lock);
02546 
02547    for (cur = parkinglot; cur; cur = cur->next) {
02548       ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
02549          ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
02550          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
02551 
02552       numparked++;
02553    }
02554    ast_mutex_unlock(&parking_lock);
02555    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
02556 
02557 
02558    return RESULT_SUCCESS;
02559 }
02560 
02561 static char showparked_help[] =
02562 "Usage: show parkedcalls\n"
02563 "       Lists currently parked calls.\n";
02564 
02565 static struct ast_cli_entry cli_show_features_deprecated = {
02566    { "show", "features", NULL },
02567    handle_showfeatures, NULL,
02568    NULL };
02569 
02570 static char showautoanswer_help[] =
02571 "Usage: show autoanswer\n"
02572 "       Lists currently logged in autoanswer users.\n";
02573 
02574 
02575 /*! \brief Dump lot status */
02576 static int manager_parking_status( struct mansession *s, const struct message *m)
02577 {
02578    struct parkeduser *cur;
02579    const char *id = astman_get_header(m, "ActionID");
02580    char idText[256] = "";
02581 
02582    if (!ast_strlen_zero(id))
02583       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02584 
02585    astman_send_ack(s, m, "Parked calls will follow");
02586 
02587    ast_mutex_lock(&parking_lock);
02588 
02589    for (cur = parkinglot; cur; cur = cur->next) {
02590       astman_append(s, "Event: ParkedCall\r\n"
02591          "Exten: %d\r\n"
02592          "Channel: %s\r\n"
02593          "From: %s\r\n"
02594          "Timeout: %ld\r\n"
02595          "CallerID: %s\r\n"
02596          "CallerIDName: %s\r\n"
02597          "Uniqueid: %s\r\n\r\n"
02598          "%s"
02599          "\r\n",
02600          cur->parkingnum, cur->chan->name, cur->peername,
02601          (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
02602          S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
02603          S_OR(cur->chan->cid.cid_name, ""), cur->chan->uniqueid,
02604          idText);
02605    }
02606 
02607    astman_append(s,
02608       "Event: ParkedCallsComplete\r\n"
02609       "%s"
02610       "\r\n",idText);
02611 
02612    ast_mutex_unlock(&parking_lock);
02613 
02614    return RESULT_SUCCESS;
02615 }
02616 
02617 static char mandescr_park[] =
02618 "Description: Park a channel.\n"
02619 "Variables: (Names marked with * are required)\n"
02620 "  *Channel: Channel name to park\n"
02621 "  *Channel2: Channel to announce park info to (and return to if timeout)\n"
02622 "  Timeout: Number of milliseconds to wait before callback.\n";  
02623 
02624 static int manager_park(struct mansession *s, const struct message *m)
02625 {
02626    const char *channel = astman_get_header(m, "Channel");
02627    const char *channel2 = astman_get_header(m, "Channel2");
02628    const char *timeout = astman_get_header(m, "Timeout");
02629    char buf[BUFSIZ];
02630    int to = 0;
02631    int res = 0;
02632    int parkExt = 0;
02633    struct ast_channel *ch1, *ch2;
02634 
02635    if (ast_strlen_zero(channel)) {
02636       astman_send_error(s, m, "Channel not specified");
02637       return 0;
02638    }
02639 
02640    if (ast_strlen_zero(channel2)) {
02641       astman_send_error(s, m, "Channel2 not specified");
02642       return 0;
02643    }
02644 
02645    ch1 = ast_get_channel_by_name_locked(channel);
02646    if (!ch1) {
02647       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
02648       astman_send_error(s, m, buf);
02649       return 0;
02650    }
02651 
02652    ch2 = ast_get_channel_by_name_locked(channel2);
02653    if (!ch2) {
02654       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
02655       astman_send_error(s, m, buf);
02656       ast_channel_unlock(ch1);
02657       return 0;
02658    }
02659 
02660    if (!ast_strlen_zero(timeout)) {
02661       sscanf(timeout, "%d", &to);
02662    }
02663 
02664    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
02665    if (!res) {
02666       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
02667       astman_send_ack(s, m, "Park successful");
02668    } else {
02669       astman_send_error(s, m, "Park failure");
02670    }
02671 
02672    ast_channel_unlock(ch1);
02673    ast_channel_unlock(ch2);
02674 
02675    return 0;
02676 }
02677 
02678 static int handle_autoanswer(int fd, int argc, char *argv[])
02679 {
02680    struct aauser *cur;
02681 
02682    ast_cli(fd, "%25s %10s %15s \n", "Channel"
02683       , "Extension", "Context");
02684 
02685    ast_mutex_lock(&autoanswer_lock);
02686 
02687    cur=aalot;
02688    while(cur) {
02689       ast_cli(fd, "%25s %10s %15s\n",cur->chan->name, cur->exten, cur->context);
02690 
02691       cur = cur->next;
02692    }
02693 
02694    ast_mutex_unlock(&autoanswer_lock);
02695 
02696    return RESULT_SUCCESS;
02697 }
02698 
02699 static struct ast_cli_entry cli_features[] = {
02700    { { "feature", "list", NULL },
02701    handle_showfeatures, "Lists configured features",
02702    showfeatures_help, NULL, &cli_show_features_deprecated },
02703 
02704    { { "show", "parkedcalls", NULL },
02705    handle_parkedcalls, "Lists parked calls",
02706    showparked_help },
02707 
02708    { { "show", "autoanswer", NULL },
02709    handle_autoanswer, "Lists autoanswer users",
02710    showautoanswer_help },
02711 };
02712 int ast_masq_autoanswer_login(struct ast_channel *rchan, void *data)
02713 {
02714    struct ast_channel *chan;
02715    struct ast_frame *f;
02716    /* Make a new, fake channel that we'll use to masquerade in the real one */
02717    chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Autoanswer/%s", rchan->name);
02718    if (chan) {
02719       /* Let us keep track of the channel name */
02720       ast_string_field_build(chan, name, "Autoanswer/%s",rchan->name);
02721       /* Make formats okay */
02722       chan->readformat = rchan->readformat;
02723       chan->writeformat = rchan->writeformat;
02724       ast_channel_masquerade(chan, rchan);
02725       /* Setup the extensions and such */
02726       strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
02727       strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
02728       chan->priority = rchan->priority;
02729       /* might be dirty but we want trackable channels */
02730       ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid);
02731       /* Make the masq execute */
02732       f = ast_read(chan);
02733       if (f)
02734          ast_frfree(f);
02735       ast_autoanswer_login(chan, data);
02736    } else {
02737       ast_log(LOG_WARNING, "Unable to create aa channel\n");
02738       return -1;
02739    }
02740    return 0;
02741 }
02742 
02743 static int autoanswer_login_exec(struct ast_channel *chan, void *data)
02744 {
02745    int res=0;
02746    struct ast_module_user *u;
02747 
02748    u = ast_module_user_add(chan);
02749    if (!data) {
02750       ast_log(LOG_WARNING, "AutoanswerLogin requires an argument (extension number)\n");
02751       return -1;
02752    }
02753    res = ast_masq_autoanswer_login(chan, data);
02754    ast_module_user_remove(u);
02755    return res;
02756 }
02757 
02758 int ast_autoanswer_login(struct ast_channel *chan, void *data)
02759 {
02760    /* We put the user in the parking list, then wake up the parking thread to be sure it looks
02761       after these channels too */
02762    struct ast_context *con;
02763    char exten[AST_MAX_EXTENSION];
02764    struct aauser *pu,*pl = NULL;
02765    char *s, *stringp, *aacontext, *aaexten = NULL;
02766 
02767    s = ast_strdupa((void *) data);
02768    stringp=s;
02769    aacontext = strsep(&stringp, "|");
02770    aaexten = strsep(&stringp, "|");
02771    if (!aaexten) {
02772        aaexten = aacontext;
02773        aacontext = NULL;
02774    }
02775    if (!aaexten) {
02776       ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n");
02777       return -1;
02778    } else {
02779       if (!aacontext) {
02780          aacontext = "default";
02781       }
02782    }
02783 
02784    ast_mutex_lock(&autoanswer_lock);
02785    pu = aalot;
02786    while(pu) {
02787       if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){
02788          if (pl)
02789             pl->next = pu->next;
02790          else
02791             aalot = pu->next;
02792          break;
02793       }
02794       pl = pu;
02795       pu = pu->next;
02796    }
02797    ast_mutex_unlock(&autoanswer_lock);
02798    if (pu) {
02799        ast_log(LOG_NOTICE, "Logout old Channel %s for %s@%s.\n",pu->chan->name, pu->exten, pu->context);
02800        manager_event(EVENT_FLAG_CALL, "AutoanswerLogout",
02801                                "Channel: %s\r\n"
02802                                "Uniqueid: %s\r\n"
02803                                "Context: %s\r\n"
02804                                "Exten: %s\r\n"
02805                            ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
02806        ast_hangup(pu->chan);
02807        free(pu);
02808    }
02809    pu = malloc(sizeof(struct aauser));
02810    if (pu) {
02811       memset(pu, 0, sizeof(pu));
02812       ast_mutex_lock(&autoanswer_lock);
02813       chan->appl = "Autoanswer";
02814       chan->data = NULL;
02815 
02816       pu->chan = chan;
02817       if (chan->_state != AST_STATE_UP) {
02818           ast_answer(chan);
02819       }
02820 
02821       /* Start music on hold */
02822       ast_moh_start(pu->chan, NULL, NULL);
02823       gettimeofday(&pu->start, NULL);
02824       strncpy(pu->exten, aaexten, sizeof(pu->exten)-1);
02825       strncpy(pu->context, aacontext, sizeof(pu->exten)-1);
02826       pu->next = aalot;
02827       aalot = pu;
02828       con = ast_context_find(aacontext);
02829       if (!con) {
02830          con = ast_context_create(NULL,aacontext, registrar);
02831          if (!con) {
02832             ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", aacontext);
02833          }
02834       }
02835       if (con) {
02836          snprintf(exten, sizeof(exten), "%s", aaexten);
02837          ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)data), free, registrar);
02838       }
02839 
02840       ast_mutex_unlock(&autoanswer_lock);
02841       /* Wake up the (presumably select()ing) thread */
02842       pthread_kill(autoanswer_thread, SIGURG);
02843       if (option_verbose > 1)
02844          ast_verbose(VERBOSE_PREFIX_2 "Autoanswer login from %s for %s@%s.\n", pu->chan->name, pu->exten, pu->context);
02845          manager_event(EVENT_FLAG_CALL, "AutoanswerLogin",
02846                                 "Channel: %s\r\n"
02847                                 "Uniqueid: %s\r\n"
02848                "Context: %s\r\n"
02849                         "Exten: %s\r\n"
02850                         ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
02851 
02852          return 0;
02853    } else {
02854       ast_log(LOG_WARNING, "Out of memory\n");
02855       return -1;
02856    }
02857    return 0;
02858 }
02859 
02860 static void autoanswer_reregister_extensions(void)
02861 {
02862    struct aauser *cur;
02863    struct ast_context *con;
02864    char exten[AST_MAX_EXTENSION];
02865    char args[AST_MAX_EXTENSION];
02866 
02867    ast_mutex_lock(&autoanswer_lock);
02868 
02869    cur=aalot;
02870    while(cur) {
02871       con = ast_context_find(cur->context);
02872       if (!con) {
02873          con = ast_context_create(NULL,cur->context, registrar);
02874          if (!con) {
02875             ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", cur->context);
02876          }
02877       }
02878       if (con) {
02879          snprintf(exten, sizeof(exten), "%s", cur->exten);
02880          snprintf(args, sizeof(args), "%s|%s", cur->context, cur->exten);
02881          ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)args), free, registrar);
02882       }
02883       cur = cur->next;
02884    }
02885 
02886    ast_mutex_unlock(&autoanswer_lock);
02887 }
02888 static void *do_autoanswer_thread(void *ignore)
02889 {
02890    int ms, tms, max;
02891    struct ast_context *con;
02892    char exten[AST_MAX_EXTENSION];
02893    struct aauser *pu, *pl, *pt = NULL;
02894    struct timeval tv;
02895    struct ast_frame *f;
02896    int x;
02897    fd_set rfds, efds;
02898    fd_set nrfds, nefds;
02899    FD_ZERO(&rfds);
02900    FD_ZERO(&efds);
02901    for (;;) {
02902       ms = -1;
02903       max = -1;
02904       ast_mutex_lock(&autoanswer_lock);
02905       pl = NULL;
02906       pu = aalot;
02907       gettimeofday(&tv, NULL);
02908       FD_ZERO(&nrfds);
02909       FD_ZERO(&nefds);
02910       while(pu) {
02911          tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
02912          for (x=0;x<AST_MAX_FDS;x++) {
02913             if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
02914                if (FD_ISSET(pu->chan->fds[x], &efds))
02915                   ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
02916                else
02917                   ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
02918                pu->chan->fdno = x;
02919                /* See if they need servicing */
02920                f = ast_read(pu->chan);
02921                if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
02922                   /* There's a problem, hang them up*/
02923                   if (option_verbose > 1)
02924                      ast_verbose(VERBOSE_PREFIX_2 "%s logged out of autoanswer app\n", pu->chan->name);
02925                   manager_event(EVENT_FLAG_CALL, "AutoanswerLogout",
02926                                         "Channel: %s\r\n"
02927                                         "Uniqueid: %s\r\n"
02928                                   "Context: %s\r\n"
02929                                   "Exten: %s\r\n"
02930                               ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
02931                   ast_hangup(pu->chan);
02932                   con = ast_context_find(pu->context);
02933                   if (con) {
02934                       snprintf(exten, sizeof(exten), "%s", pu->exten);
02935                       if (ast_context_remove_extension2(con, exten, 1, registrar))
02936                      ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02937                   } else {
02938                      ast_log(LOG_WARNING, "Whoa, no %s context?\n", pu->exten);
02939                   }
02940                   /* And take them out of the parking lot */
02941                   if (pl)
02942                      pl->next = pu->next;
02943                   else
02944                      aalot = pu->next;
02945                   pt = pu;
02946                   pu = pu->next;
02947                   free(pt);
02948                   break;
02949                } else {
02950                   /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
02951                   ast_frfree(f);
02952                   goto std;   /* XXX Ick: jumping into an else statement??? XXX */
02953                }
02954             }
02955          }
02956          if (x >= AST_MAX_FDS) {
02957 std:           for (x=0;x<AST_MAX_FDS;x++) {
02958                /* Keep this one for next one */
02959                if (pu->chan->fds[x] > -1) {
02960                   FD_SET(pu->chan->fds[x], &nrfds);
02961                   FD_SET(pu->chan->fds[x], &nefds);
02962                   if (pu->chan->fds[x] > max)
02963                      max = pu->chan->fds[x];
02964                }
02965             }
02966             /* Keep track of our longest wait */
02967             if ((tms < ms) || (ms < 0))
02968                ms = tms;
02969             pl = pu;
02970             pu = pu->next;
02971          }
02972       }
02973       ast_mutex_unlock(&autoanswer_lock);
02974       rfds = nrfds;
02975       efds = nefds;
02976       tv.tv_sec = ms / 1000;
02977       tv.tv_usec = (ms % 1000) * 1000;
02978       /* Wait for something to happen */
02979       ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
02980       pthread_testcancel();
02981    }
02982    return NULL;   /* Never reached */
02983 }
02984 
02985 static int autoanswer_exec(struct ast_channel *chan, void *data)
02986 {
02987    int res=0;
02988    struct ast_channel *peer=NULL;
02989    struct aauser *pu, *pl=NULL;
02990    struct ast_bridge_config config;
02991    char *s, *stringp, *aacontext, *aaexten = NULL;
02992    char datastring[80];
02993    struct ast_module_user *u;
02994 
02995 
02996    if (!data) {
02997       ast_log(LOG_WARNING, "Autoanswer requires an argument (extension number)\n");
02998       return -1;
02999    }
03000    s = ast_strdupa((void *) data);
03001    stringp=s;
03002    aacontext = strsep(&stringp, "|");
03003    aaexten = strsep(&stringp, "|");
03004    if (!aaexten) {
03005        aaexten = aacontext;
03006        aacontext = NULL;
03007    }
03008    if (!aaexten) {
03009       ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n");
03010       return -1;
03011    } else {
03012       if (!aacontext) {
03013          aacontext = "default";
03014       }
03015    }
03016 
03017    u = ast_module_user_add(chan);
03018    ast_mutex_lock(&autoanswer_lock);
03019    pu = aalot;
03020    while(pu) {
03021       if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){
03022          if (pl)
03023             pl->next = pu->next;
03024          else
03025             aalot = pu->next;
03026          break;
03027       }
03028       pl = pu;
03029       pu = pu->next;
03030    }
03031    ast_mutex_unlock(&autoanswer_lock);
03032    if (pu) {
03033       peer = pu->chan;
03034       free(pu);
03035       pu = NULL;
03036    }
03037    /* JK02: it helps to answer the channel if not already up */
03038    if (chan->_state != AST_STATE_UP) {
03039       ast_answer(chan);
03040    }
03041 
03042    if (peer) {
03043       ast_moh_stop(peer);
03044       /* Play a courtesy beep in the callED channel to prefix the bridge connecting */
03045       if (!ast_strlen_zero(courtesytone)) {
03046          if (!ast_streamfile(peer, courtesytone, peer->language)) {
03047             if (ast_waitstream(peer, "") < 0) {
03048                ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
03049                ast_hangup(peer);
03050                return -1;
03051             }
03052          }
03053       }
03054 
03055       res = ast_channel_make_compatible(chan, peer);
03056       if (res < 0) {
03057          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
03058          ast_hangup(peer);
03059          return -1;
03060       }
03061       /* This runs sorta backwards, since we give the incoming channel control, as if it
03062          were the person called. */
03063       if (option_verbose > 2)
03064          ast_verbose(VERBOSE_PREFIX_3 "Channel %s autoanswered  %s\n", peer->name, chan->name);
03065       manager_event(EVENT_FLAG_CALL, "Autoanswer",
03066                     "Channel: %s\r\n"
03067                     "Uniqueid: %s\r\n"
03068                     "Channel2: %s\r\n"
03069                     "Uniqueid2: %s\r\n"
03070                     "Context: %s\r\n"
03071                     "Exten: %s\r\n"
03072                 ,chan->name, chan->uniqueid, peer->name, peer->uniqueid, aacontext, aaexten);
03073 
03074 
03075       memset(&config,0,sizeof(struct ast_bridge_config));
03076       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
03077       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
03078       config.timelimit = 0;
03079       config.play_warning = 0;
03080       config.warning_freq = 0;
03081       config.warning_sound=NULL;
03082       res = ast_bridge_call(chan,peer,&config);
03083 
03084       if (option_verbose > 2)
03085          ast_verbose(VERBOSE_PREFIX_3 "returning from bridge %s\n", peer->name);
03086          /* relogin */
03087       snprintf(datastring, sizeof(datastring) - 1, "%s|%s", aacontext, aaexten);
03088       ast_autoanswer_login(peer, datastring);
03089       return res;
03090    } else {
03091       if (option_verbose > 2)
03092          ast_verbose(VERBOSE_PREFIX_3 "Nobody logged in for autoanswer %s@%s\n", aaexten, aacontext);
03093       res = -1;
03094    }
03095    ast_module_user_remove(u);
03096    return res;
03097 }
03098 
03099 
03100 int ast_pickup_call(struct ast_channel *chan)
03101 {
03102    struct ast_channel *cur = NULL;
03103    int res = -1;
03104 
03105    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
03106       if (!cur->pbx && 
03107          (cur != chan) &&
03108          (chan->pickupgroup & cur->callgroup) &&
03109          ((cur->_state == AST_STATE_RINGING) ||
03110           (cur->_state == AST_STATE_RING))) {
03111             break;
03112       }
03113       ast_channel_unlock(cur);
03114    }
03115    if (cur) {
03116       if (option_debug)
03117          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
03118       res = ast_answer(chan);
03119       if (res)
03120          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
03121       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
03122       if (res)
03123          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
03124       res = ast_channel_masquerade(cur, chan);
03125       if (res)
03126          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
03127       ast_channel_unlock(cur);
03128    } else   {
03129       if (option_debug)
03130          ast_log(LOG_DEBUG, "No call pickup possible...\n");
03131    }
03132    return res;
03133 }
03134 
03135 /*! \brief Add parking hints for all defined parking lots */
03136 static void park_add_hints(char *context, int start, int stop)
03137 {
03138    int numext;
03139    char device[AST_MAX_EXTENSION];
03140    char exten[10];
03141 
03142    for (numext = start; numext <= stop; numext++) {
03143       snprintf(exten, sizeof(exten), "%d", numext);
03144       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
03145       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
03146    }
03147 }
03148 
03149 
03150 static int load_config(void) 
03151 {
03152    int start = 0, end = 0;
03153    int res;
03154    struct ast_context *con = NULL;
03155    struct ast_config *cfg = NULL;
03156    struct ast_variable *var = NULL;
03157    char old_parking_ext[AST_MAX_EXTENSION];
03158    char old_parking_con[AST_MAX_EXTENSION] = "";
03159 
03160    if (!ast_strlen_zero(parking_con)) {
03161       strcpy(old_parking_ext, parking_ext);
03162       strcpy(old_parking_con, parking_con);
03163    } 
03164 
03165    /* Reset to defaults */
03166    strcpy(parking_con, "parkedcalls");
03167    strcpy(parking_con_dial, "park-dial");
03168    strcpy(parking_ext, "700");
03169    strcpy(pickup_ext, "*8");
03170    strcpy(parkmohclass, "default");
03171    courtesytone[0] = '\0';
03172    strcpy(xfersound, "beep");
03173    strcpy(xferfailsound, "pbx-invalid");
03174    parking_start = 701;
03175    parking_stop = 750;
03176    parkfindnext = 0;
03177    adsipark = 0;
03178    parkaddhints = 0;
03179 
03180    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
03181    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03182    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03183 
03184    cfg = ast_config_load("features.conf");
03185    if (!cfg) {
03186       ast_log(LOG_WARNING,"Could not load features.conf\n");
03187       return AST_MODULE_LOAD_DECLINE;
03188    }
03189    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
03190       if (!strcasecmp(var->name, "parkext")) {
03191          ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
03192       } else if (!strcasecmp(var->name, "context")) {
03193          ast_copy_string(parking_con, var->value, sizeof(parking_con));
03194       } else if (!strcasecmp(var->name, "parkingtime")) {
03195          if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
03196             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
03197             parkingtime = DEFAULT_PARK_TIME;
03198          } else
03199             parkingtime = parkingtime * 1000;
03200       } else if (!strcasecmp(var->name, "parkpos")) {
03201          if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
03202             ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of features.conf\n", var->lineno);
03203          } else {
03204             parking_start = start;
03205             parking_stop = end;
03206          }
03207       } else if (!strcasecmp(var->name, "findslot")) {
03208          parkfindnext = (!strcasecmp(var->value, "next"));
03209       } else if (!strcasecmp(var->name, "parkinghints")) {
03210          parkaddhints = ast_true(var->value);
03211       } else if (!strcasecmp(var->name, "adsipark")) {
03212          adsipark = ast_true(var->value);
03213       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
03214          if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
03215             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
03216             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
03217          } else
03218             transferdigittimeout = transferdigittimeout * 1000;
03219       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
03220          if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
03221             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
03222             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03223          }
03224       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
03225          if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
03226             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
03227             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03228          } else
03229             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
03230       } else if (!strcasecmp(var->name, "courtesytone")) {
03231          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
03232       }  else if (!strcasecmp(var->name, "parkedplay")) {
03233          if (!strcasecmp(var->value, "both"))
03234             parkedplay = 2;
03235          else if (!strcasecmp(var->value, "parked"))
03236             parkedplay = 1;
03237          else
03238             parkedplay = 0;
03239       } else if (!strcasecmp(var->name, "xfersound")) {
03240          ast_copy_string(xfersound, var->value, sizeof(xfersound));
03241       } else if (!strcasecmp(var->name, "xferfailsound")) {
03242          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
03243       } else if (!strcasecmp(var->name, "pickupexten")) {
03244          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
03245       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
03246          ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
03247       }
03248    }
03249 
03250    unmap_features();
03251    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
03252       if (remap_feature(var->name, var->value))
03253          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
03254    }
03255 
03256    /* Map a key combination to an application*/
03257    ast_unregister_features();
03258    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
03259       char *tmp_val = ast_strdupa(var->value);
03260       char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 
03261       struct ast_call_feature *feature;
03262 
03263       /* strsep() sets the argument to NULL if match not found, and it
03264        * is safe to use it with a NULL argument, so we don't check
03265        * between calls.
03266        */
03267       exten = strsep(&tmp_val,",");
03268       activatedby = strsep(&tmp_val,",");
03269       app = strsep(&tmp_val,",");
03270       app_args = strsep(&tmp_val,",");
03271       moh_class = strsep(&tmp_val,",");
03272 
03273       activateon = strsep(&activatedby, "/");   
03274 
03275       /*! \todo XXX var_name or app_args ? */
03276       if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
03277          ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
03278             app, exten, activateon, var->name);
03279          continue;
03280       }
03281 
03282       AST_LIST_LOCK(&feature_list);
03283       if ((feature = find_dynamic_feature(var->name))) {
03284          AST_LIST_UNLOCK(&feature_list);
03285          ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
03286          continue;
03287       }
03288       AST_LIST_UNLOCK(&feature_list);
03289             
03290       if (!(feature = ast_calloc(1, sizeof(*feature))))
03291          continue;               
03292 
03293       ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
03294       ast_copy_string(feature->app, app, FEATURE_APP_LEN);
03295       ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
03296       
03297       if (app_args) 
03298          ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
03299 
03300       if (moh_class)
03301          ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
03302          
03303       ast_copy_string(feature->exten, exten, sizeof(feature->exten));
03304       feature->operation = feature_exec_app;
03305       ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
03306 
03307       /* Allow caller and calle to be specified for backwards compatability */
03308       if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
03309          ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
03310       else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
03311          ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
03312       else {
03313          ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
03314             " must be 'self', or 'peer'\n", var->name);
03315          continue;
03316       }
03317 
03318       if (ast_strlen_zero(activatedby))
03319          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03320       else if (!strcasecmp(activatedby, "caller"))
03321          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
03322       else if (!strcasecmp(activatedby, "callee"))
03323          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
03324       else if (!strcasecmp(activatedby, "both"))
03325          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03326       else {
03327          ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
03328             " must be 'caller', or 'callee', or 'both'\n", var->name);
03329          continue;
03330       }
03331 
03332       ast_register_feature(feature);
03333          
03334       if (option_verbose >= 1)
03335          ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);  
03336    }   
03337    ast_config_destroy(cfg);
03338 
03339    /* Remove the old parking extension */
03340    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
03341       if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
03342             notify_metermaids(old_parking_ext, old_parking_con);
03343       if (option_debug)
03344          ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
03345    }
03346    
03347    if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
03348       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
03349       return -1;
03350    }
03351    res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
03352    if (parkaddhints)
03353       park_add_hints(parking_con, parking_start, parking_stop);
03354    if (!res)
03355       notify_metermaids(ast_parking_ext(), parking_con);
03356    return res;
03357 
03358 }
03359 
03360 static char *app_bridge = "Bridge";
03361 static char *bridge_synopsis = "Bridge two channels";
03362 static char *bridge_descrip =
03363 "Usage: Bridge(channel[|options])\n"
03364 "  Allows the ability to bridge two channels via the dialplan.\n"
03365 "The current channel is bridged to the specified 'channel'.\n"
03366 "The following options are supported:\n"
03367 "   p - Play a courtesy tone to 'channel'.\n"
03368 "BRIDGERESULT dial plan variable will contain SUCCESS, FAILURE, LOOP, NONEXISTENT or INCOMPATIBLE.\n";
03369 
03370 enum {
03371    BRIDGE_OPT_PLAYTONE = (1 << 0),
03372 };
03373 
03374 AST_APP_OPTIONS(bridge_exec_options, BEGIN_OPTIONS
03375    AST_APP_OPTION('p', BRIDGE_OPT_PLAYTONE)
03376 END_OPTIONS );
03377 
03378 static int bridge_exec(struct ast_channel *chan, void *data)
03379 {
03380    struct ast_module_user *u;
03381    struct ast_channel *current_dest_chan, *final_dest_chan;
03382    char *tmp_data  = NULL;
03383    struct ast_flags opts = { 0, };
03384    struct ast_bridge_config bconfig = { { 0, }, };
03385 
03386    AST_DECLARE_APP_ARGS(args,
03387       AST_APP_ARG(dest_chan);
03388       AST_APP_ARG(options);
03389    );
03390    
03391    if (ast_strlen_zero(data)) {
03392       ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
03393       return -1;
03394    }
03395    
03396    u = ast_module_user_add(chan);
03397 
03398    tmp_data = ast_strdupa(data);
03399    AST_STANDARD_APP_ARGS(args, tmp_data);
03400    if (!ast_strlen_zero(args.options))
03401       ast_app_parse_options(bridge_exec_options, &opts, NULL, args.options);
03402 
03403    /* avoid bridge with ourselves */
03404    if (!strncmp(chan->name, args.dest_chan, 
03405       strlen(chan->name) < strlen(args.dest_chan) ? 
03406       strlen(chan->name) : strlen(args.dest_chan))) {
03407       ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
03408       manager_event(EVENT_FLAG_CALL, "BridgeExec",
03409                "Response: Failed\r\n"
03410                "Reason: Unable to bridge channel to itself\r\n"
03411                "Channel1: %s\r\n"
03412                "Channel2: %s\r\n",
03413                chan->name, args.dest_chan);
03414       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
03415       ast_module_user_remove(u);
03416       return 0;
03417    }
03418 
03419    /* make sure we have a valid end point */
03420    if (!(current_dest_chan = ast_get_channel_by_name_prefix_locked(args.dest_chan, 
03421       strlen(args.dest_chan)))) {
03422       ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we "
03423          "cannot get its lock\n", args.dest_chan);
03424       manager_event(EVENT_FLAG_CALL, "BridgeExec",
03425                "Response: Failed\r\n"
03426                "Reason: Cannot grab end point\r\n"
03427                "Channel1: %s\r\n"
03428                "Channel2: %s\r\n", chan->name, args.dest_chan);
03429       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
03430       ast_module_user_remove(u);
03431       return 0;
03432    }
03433    ast_mutex_unlock(&current_dest_chan->lock);
03434 
03435    /* answer the channel if needed */
03436    if (current_dest_chan->_state != AST_STATE_UP)
03437       ast_answer(current_dest_chan);
03438 
03439    /* try to allocate a place holder where current_dest_chan will be placed */
03440    if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
03441       NULL, NULL, 0, "Bridge/%s", current_dest_chan->name))) {
03442       ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
03443       manager_event(EVENT_FLAG_CALL, "BridgeExec",
03444                "Response: Failed\r\n"
03445                "Reason: cannot create placeholder\r\n"
03446                "Channel1: %s\r\n"
03447                "Channel2: %s\r\n", chan->name, args.dest_chan);
03448    }
03449    do_bridge_masquerade(current_dest_chan, final_dest_chan);
03450 
03451    /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */
03452    /* try to make compatible, send error if we fail */
03453    if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
03454       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
03455       manager_event(EVENT_FLAG_CALL, "BridgeExec",
03456                "Response: Failed\r\n"
03457                "Reason: Could not make channels compatible for bridge\r\n"
03458                "Channel1: %s\r\n"
03459                "Channel2: %s\r\n", chan->name, final_dest_chan->name);
03460       ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */
03461       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
03462       ast_module_user_remove(u);
03463       return 0;
03464    }
03465 
03466    /* Report that the bridge will be successfull */
03467    manager_event(EVENT_FLAG_CALL, "BridgeExec",
03468             "Response: Success\r\n"
03469             "Channel1: %s\r\n"
03470             "Channel2: %s\r\n", chan->name, final_dest_chan->name);
03471 
03472    /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */  
03473    if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
03474       if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
03475          if (ast_waitstream(final_dest_chan, "") < 0)
03476             ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
03477       }
03478    }
03479    
03480    /* do the bridge */
03481    ast_bridge_call(chan, final_dest_chan, &bconfig);
03482 
03483    /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */
03484    pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
03485    if (!ast_check_hangup(final_dest_chan)) {
03486       if (option_debug) {
03487          ast_log(LOG_DEBUG, "starting new PBX in %s,%s,%d for chan %s\n", 
03488          final_dest_chan->context, final_dest_chan->exten, 
03489          final_dest_chan->priority, final_dest_chan->name);
03490       }
03491 
03492       if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) {
03493          ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
03494          ast_hangup(final_dest_chan);
03495       } else if (option_debug)
03496          ast_log(LOG_DEBUG, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
03497    } else {
03498       if (option_debug)
03499          ast_log(LOG_DEBUG, "hangup chan %s since the other endpoint has hung up\n", final_dest_chan->name);
03500       ast_hangup(final_dest_chan);
03501    }
03502 
03503    ast_module_user_remove(u);
03504 
03505    return 0;
03506 }
03507 
03508 static int reload(void)
03509 {
03510    autoanswer_reregister_extensions();
03511    return load_config();
03512 }
03513 
03514 static int load_module(void)
03515 {
03516    int res;
03517    
03518    ast_register_application(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip); 
03519 
03520    memset(parking_ext, 0, sizeof(parking_ext));
03521    memset(parking_con, 0, sizeof(parking_con));
03522 
03523    if ((res = load_config()))
03524       return res;
03525    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03526    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
03527    ast_pthread_create(&holding_thread, NULL, do_holding_thread, NULL);
03528    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
03529    if (!res)
03530       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
03531    if (!res) {
03532       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
03533       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
03534          "Park a channel", mandescr_park); 
03535       ast_manager_register2("Bridge", EVENT_FLAG_COMMAND, action_bridge, "Bridge two channels already in the PBX", mandescr_bridge);
03536    }
03537 
03538    res |= ast_register_application(holdedcall, retrieve_call_exec, synopsis, descrip);
03539    ast_pthread_create(&autoanswer_thread, NULL, do_autoanswer_thread, NULL);
03540    if (!res)
03541       res |= ast_register_application(autoanswerlogin, autoanswer_login_exec, synopsis3, descrip3);
03542    if (!res)
03543       res |= ast_register_application(autoanswer, autoanswer_exec, synopsis4, descrip4);
03544 
03545    res |= ast_devstate_prov_add("Park", metermaidstate);
03546 
03547    return res;
03548 }
03549 
03550 
03551 static int unload_module(void)
03552 {
03553    ast_module_user_hangup_all();
03554 
03555    ast_manager_unregister("ParkedCalls");
03556    ast_manager_unregister("Bridge");
03557    ast_manager_unregister("Park");
03558    ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03559    ast_unregister_application(parkcall);
03560    ast_unregister_application(app_bridge);
03561    ast_unregister_application(autoanswer);
03562    ast_unregister_application(autoanswerlogin);
03563    ast_unregister_application(holdedcall);
03564    ast_devstate_prov_del("Park");
03565    return ast_unregister_application(parkedcall);
03566 }
03567 
03568 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Call Features Resource",
03569       .load = load_module,
03570       .unload = unload_module,
03571       .reload = reload,
03572           );

Generated on Mon Jul 14 17:25:00 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1