Tue Nov 4 13:20:21 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  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Routines implementing call features as call pickup, parking and transfer
00022  *
00023  * \author Mark Spencer <markster@digium.com> 
00024  */
00025 
00026 /*** MODULEINFO
00027         <depend>chan_local</depend>
00028  ***/
00029 
00030 #include "asterisk.h"
00031 
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 114542 $")
00033 
00034 #include <pthread.h>
00035 #include <stdlib.h>
00036 #include <errno.h>
00037 #include <unistd.h>
00038 #include <string.h>
00039 #include <stdlib.h>
00040 #include <stdio.h>
00041 #include <sys/time.h>
00042 #include <sys/signal.h>
00043 #include <netinet/in.h>
00044 
00045 #include "asterisk/lock.h"
00046 #include "asterisk/file.h"
00047 #include "asterisk/logger.h"
00048 #include "asterisk/channel.h"
00049 #include "asterisk/pbx.h"
00050 #include "asterisk/options.h"
00051 #include "asterisk/causes.h"
00052 #include "asterisk/module.h"
00053 #include "asterisk/translate.h"
00054 #include "asterisk/app.h"
00055 #include "asterisk/say.h"
00056 #include "asterisk/features.h"
00057 #include "asterisk/musiconhold.h"
00058 #include "asterisk/config.h"
00059 #include "asterisk/cli.h"
00060 #include "asterisk/manager.h"
00061 #include "asterisk/utils.h"
00062 #include "asterisk/adsi.h"
00063 #include "asterisk/devicestate.h"
00064 #include "asterisk/monitor.h"
00065 
00066 #define DEFAULT_PARK_TIME 45000
00067 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
00068 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
00069 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
00070 
00071 #define AST_MAX_WATCHERS 256
00072 
00073 enum {
00074    AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
00075    AST_FEATURE_FLAG_ONPEER =    (1 << 1),
00076    AST_FEATURE_FLAG_ONSELF =    (1 << 2),
00077    AST_FEATURE_FLAG_BYCALLEE =  (1 << 3),
00078    AST_FEATURE_FLAG_BYCALLER =  (1 << 4),
00079    AST_FEATURE_FLAG_BYBOTH  =   (3 << 3),
00080 };
00081 
00082 static char *parkedcall = "ParkedCall";
00083 
00084 static int parkaddhints = 0;                               /*!< Add parking hints automatically */
00085 static int parkingtime = DEFAULT_PARK_TIME;                /*!< No more than 45 seconds parked before you do something with them */
00086 static char parking_con[AST_MAX_EXTENSION];                /*!< Context for which parking is made accessible */
00087 static char parking_con_dial[AST_MAX_EXTENSION];           /*!< Context for dialback for parking (KLUDGE) */
00088 static char parking_ext[AST_MAX_EXTENSION];                /*!< Extension you type to park the call */
00089 static char pickup_ext[AST_MAX_EXTENSION];                 /*!< Call pickup extension */
00090 static char parkmohclass[MAX_MUSICCLASS];                  /*!< Music class used for parking */
00091 static int parking_start;                                  /*!< First available extension for parking */
00092 static int parking_stop;                                   /*!< Last available extension for parking */
00093 
00094 static char courtesytone[256];                             /*!< Courtesy tone */
00095 static int parkedplay = 0;                                 /*!< Who to play the courtesy tone to */
00096 static char xfersound[256];                                /*!< Call transfer sound */
00097 static char xferfailsound[256];                            /*!< Call transfer failure sound */
00098 
00099 static int parking_offset;
00100 static int parkfindnext;
00101 
00102 static int adsipark;
00103 
00104 static int transferdigittimeout;
00105 static int featuredigittimeout;
00106 
00107 static int atxfernoanswertimeout;
00108 
00109 static char *registrar = "res_features";        /*!< Registrar for operations */
00110 
00111 /* module and CLI command definitions */
00112 static char *synopsis = "Answer a parked call";
00113 
00114 static char *descrip = "ParkedCall(exten):"
00115 "Used to connect to a parked call.  This application is always\n"
00116 "registered internally and does not need to be explicitly added\n"
00117 "into the dialplan, although you should include the 'parkedcalls'\n"
00118 "context.\n";
00119 
00120 static char *parkcall = "Park";
00121 
00122 static char *synopsis2 = "Park yourself";
00123 
00124 static char *descrip2 = "Park():"
00125 "Used to park yourself (typically in combination with a supervised\n"
00126 "transfer to know the parking space). This application is always\n"
00127 "registered internally and does not need to be explicitly added\n"
00128 "into the dialplan, although you should include the 'parkedcalls'\n"
00129 "context (or the context specified in features.conf).\n\n"
00130 "If you set the PARKINGEXTEN variable to an extension in your\n"
00131 "parking context, park() will park the call on that extension, unless\n"
00132 "it already exists. In that case, execution will continue at next\n"
00133 "priority.\n" ;
00134 
00135 static struct ast_app *monitor_app = NULL;
00136 static int monitor_ok = 1;
00137 
00138 struct parkeduser {
00139    struct ast_channel *chan;                   /*!< Parking channel */
00140    struct timeval start;                       /*!< Time the parking started */
00141    int parkingnum;                             /*!< Parking lot */
00142    char parkingexten[AST_MAX_EXTENSION];       /*!< If set beforehand, parking extension used for this call */
00143    char context[AST_MAX_CONTEXT];              /*!< Where to go if our parking time expires */
00144    char exten[AST_MAX_EXTENSION];
00145    int priority;
00146    int parkingtime;                            /*!< Maximum length in parking lot before return */
00147    int notquiteyet;
00148    char peername[1024];
00149    unsigned char moh_trys;
00150    struct parkeduser *next;
00151 };
00152 
00153 static struct parkeduser *parkinglot;
00154 
00155 AST_MUTEX_DEFINE_STATIC(parking_lock); /*!< protects all static variables above */
00156 
00157 static pthread_t parking_thread;
00158 
00159 char *ast_parking_ext(void)
00160 {
00161    return parking_ext;
00162 }
00163 
00164 char *ast_pickup_ext(void)
00165 {
00166    return pickup_ext;
00167 }
00168 
00169 struct ast_bridge_thread_obj 
00170 {
00171    struct ast_bridge_config bconfig;
00172    struct ast_channel *chan;
00173    struct ast_channel *peer;
00174 };
00175 
00176 
00177 
00178 /*! \brief store context, priority and extension */
00179 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
00180 {
00181    ast_copy_string(chan->context, context, sizeof(chan->context));
00182    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00183    chan->priority = pri;
00184 }
00185 
00186 static void check_goto_on_transfer(struct ast_channel *chan) 
00187 {
00188    struct ast_channel *xferchan;
00189    const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00190    char *x, *goto_on_transfer;
00191    struct ast_frame *f;
00192 
00193    if (ast_strlen_zero(val))
00194       return;
00195 
00196    goto_on_transfer = ast_strdupa(val);
00197 
00198    if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, chan->name)))
00199       return;
00200 
00201    for (x = goto_on_transfer; x && *x; x++) {
00202       if (*x == '^')
00203          *x = '|';
00204    }
00205    /* Make formats okay */
00206    xferchan->readformat = chan->readformat;
00207    xferchan->writeformat = chan->writeformat;
00208    ast_channel_masquerade(xferchan, chan);
00209    ast_parseable_goto(xferchan, goto_on_transfer);
00210    xferchan->_state = AST_STATE_UP;
00211    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00212    xferchan->_softhangup = 0;
00213    if ((f = ast_read(xferchan))) {
00214       ast_frfree(f);
00215       f = NULL;
00216       ast_pbx_start(xferchan);
00217    } else {
00218       ast_hangup(xferchan);
00219    }
00220 }
00221 
00222 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);
00223 
00224 
00225 static void *ast_bridge_call_thread(void *data) 
00226 {
00227    struct ast_bridge_thread_obj *tobj = data;
00228 
00229    tobj->chan->appl = "Transferred Call";
00230    tobj->chan->data = tobj->peer->name;
00231    tobj->peer->appl = "Transferred Call";
00232    tobj->peer->data = tobj->chan->name;
00233    if (tobj->chan->cdr) {
00234       ast_cdr_reset(tobj->chan->cdr, NULL);
00235       ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
00236    }
00237    if (tobj->peer->cdr) {
00238       ast_cdr_reset(tobj->peer->cdr, NULL);
00239       ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
00240    }
00241 
00242    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00243    ast_hangup(tobj->chan);
00244    ast_hangup(tobj->peer);
00245    bzero(tobj, sizeof(*tobj)); /*! \todo XXX for safety */
00246    free(tobj);
00247    return NULL;
00248 }
00249 
00250 static void ast_bridge_call_thread_launch(void *data) 
00251 {
00252    pthread_t thread;
00253    pthread_attr_t attr;
00254    struct sched_param sched;
00255 
00256    pthread_attr_init(&attr);
00257    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00258    ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00259    pthread_attr_destroy(&attr);
00260    memset(&sched, 0, sizeof(sched));
00261    pthread_setschedparam(thread, SCHED_RR, &sched);
00262 }
00263 
00264 static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
00265 {
00266    int res;
00267    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00268    char tmp[256];
00269    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00270 
00271    snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00272    message[0] = tmp;
00273    res = ast_adsi_load_session(chan, NULL, 0, 1);
00274    if (res == -1)
00275       return res;
00276    return ast_adsi_print(chan, message, justify, 1);
00277 }
00278 
00279 /*! \brief Notify metermaids that we've changed an extension */
00280 static void notify_metermaids(char *exten, char *context)
00281 {
00282    if (option_debug > 3)
00283       ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context);
00284 
00285    /* Send notification to devicestate subsystem */
00286    ast_device_state_changed("park:%s@%s", exten, context);
00287    return;
00288 }
00289 
00290 /*! \brief metermaids callback from devicestate.c */
00291 static int metermaidstate(const char *data)
00292 {
00293    int res = AST_DEVICE_INVALID;
00294    char *context = ast_strdupa(data);
00295    char *exten;
00296 
00297    exten = strsep(&context, "@");
00298    if (!context)
00299       return res;
00300    
00301    if (option_debug > 3)
00302       ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context);
00303 
00304    res = ast_exists_extension(NULL, context, exten, 1, NULL);
00305 
00306    if (!res)
00307       return AST_DEVICE_NOT_INUSE;
00308    else
00309       return AST_DEVICE_INUSE;
00310 }
00311 
00312 static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, char *orig_chan_name)
00313 {
00314    struct parkeduser *pu, *cur;
00315    int i, x = -1, parking_range;
00316    struct ast_context *con;
00317    const char *parkingexten;
00318    
00319    /* Allocate memory for parking data */
00320    if (!(pu = ast_calloc(1, sizeof(*pu)))) 
00321       return -1;
00322 
00323    /* Lock parking lot */
00324    ast_mutex_lock(&parking_lock);
00325    /* Check for channel variable PARKINGEXTEN */
00326    parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
00327    if (!ast_strlen_zero(parkingexten)) {
00328       if (ast_exists_extension(NULL, parking_con, parkingexten, 1, NULL)) {
00329          ast_mutex_unlock(&parking_lock);
00330          free(pu);
00331          ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
00332          return 1;   /* Continue execution if possible */
00333       }
00334       ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten));
00335       x = atoi(parkingexten);
00336    } else {
00337       /* Select parking space within range */
00338       parking_range = parking_stop - parking_start+1;
00339       for (i = 0; i < parking_range; i++) {
00340          x = (i + parking_offset) % parking_range + parking_start;
00341          cur = parkinglot;
00342          while(cur) {
00343             if (cur->parkingnum == x) 
00344                break;
00345             cur = cur->next;
00346          }
00347          if (!cur)
00348             break;
00349       }
00350 
00351       if (!(i < parking_range)) {
00352          ast_log(LOG_WARNING, "No more parking spaces\n");
00353          free(pu);
00354          ast_mutex_unlock(&parking_lock);
00355          return -1;
00356       }
00357       /* Set pointer for next parking */
00358       if (parkfindnext) 
00359          parking_offset = x - parking_start + 1;
00360    }
00361    
00362    chan->appl = "Parked Call";
00363    chan->data = NULL; 
00364 
00365    pu->chan = chan;
00366    
00367    /* Put the parked channel on hold if we have two different channels */
00368    if (chan != peer) {
00369       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00370          S_OR(parkmohclass, NULL),
00371          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00372    }
00373    
00374    pu->start = ast_tvnow();
00375    pu->parkingnum = x;
00376    pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
00377    if (extout)
00378       *extout = x;
00379 
00380    if (peer) 
00381       ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
00382 
00383    /* Remember what had been dialed, so that if the parking
00384       expires, we try to come back to the same place */
00385    ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
00386    ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
00387    pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
00388    pu->next = parkinglot;
00389    parkinglot = pu;
00390 
00391    /* If parking a channel directly, don't quiet yet get parking running on it */
00392    if (peer == chan) 
00393       pu->notquiteyet = 1;
00394    ast_mutex_unlock(&parking_lock);
00395    /* Wake up the (presumably select()ing) thread */
00396    pthread_kill(parking_thread, SIGURG);
00397    if (option_verbose > 1) 
00398       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));
00399 
00400    if (pu->parkingnum != -1)
00401       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
00402    manager_event(EVENT_FLAG_CALL, "ParkedCall",
00403       "Exten: %s\r\n"
00404       "Channel: %s\r\n"
00405       "From: %s\r\n"
00406       "Timeout: %ld\r\n"
00407       "CallerID: %s\r\n"
00408       "CallerIDName: %s\r\n",
00409       pu->parkingexten, pu->chan->name, peer ? peer->name : "",
00410       (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00411       S_OR(pu->chan->cid.cid_num, "<unknown>"),
00412       S_OR(pu->chan->cid.cid_name, "<unknown>")
00413       );
00414 
00415    if (peer && adsipark && ast_adsi_available(peer)) {
00416       adsi_announce_park(peer, pu->parkingexten);  /* Only supports parking numbers */
00417       ast_adsi_unload_session(peer);
00418    }
00419 
00420    con = ast_context_find(parking_con);
00421    if (!con) 
00422       con = ast_context_create(NULL, parking_con, registrar);
00423    if (!con)   /* Still no context? Bad */
00424       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00425    /* Tell the peer channel the number of the parking space */
00426    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 */
00427       /* Make sure we don't start saying digits to the channel being parked */
00428       ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00429       ast_say_digits(peer, pu->parkingnum, "", peer->language);
00430       ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00431    }
00432    if (con) {
00433       if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar))
00434          notify_metermaids(pu->parkingexten, parking_con);
00435    }
00436    if (pu->notquiteyet) {
00437       /* Wake up parking thread if we're really done */
00438       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00439          S_OR(parkmohclass, NULL),
00440          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00441       pu->notquiteyet = 0;
00442       pthread_kill(parking_thread, SIGURG);
00443    }
00444    return 0;
00445 }
00446 
00447 /*! \brief Park a call 
00448    \note We put the user in the parking list, then wake up the parking thread to be sure it looks
00449    after these channels too */
00450 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
00451 {
00452    return park_call_full(chan, peer, timeout, extout, NULL);
00453 }
00454 
00455 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
00456 {
00457    struct ast_channel *chan;
00458    struct ast_frame *f;
00459    char *orig_chan_name = NULL;
00460 
00461    /* Make a new, fake channel that we'll use to masquerade in the real one */
00462    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00463       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00464       return -1;
00465    }
00466 
00467    /* Make formats okay */
00468    chan->readformat = rchan->readformat;
00469    chan->writeformat = rchan->writeformat;
00470    ast_channel_masquerade(chan, rchan);
00471 
00472    /* Setup the extensions and such */
00473    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00474 
00475    /* Make the masq execute */
00476    f = ast_read(chan);
00477    if (f)
00478       ast_frfree(f);
00479 
00480    orig_chan_name = ast_strdupa(chan->name);
00481 
00482    park_call_full(chan, peer, timeout, extout, orig_chan_name);
00483 
00484    return 0;
00485 }
00486 
00487 
00488 #define FEATURE_RETURN_HANGUP    -1
00489 #define FEATURE_RETURN_SUCCESSBREAK  0
00490 #define FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE
00491 #define FEATURE_RETURN_NO_HANGUP_PEER  AST_PBX_NO_HANGUP_PEER
00492 #define FEATURE_RETURN_PASSDIGITS    21
00493 #define FEATURE_RETURN_STOREDIGITS   22
00494 #define FEATURE_RETURN_SUCCESS       23
00495 #define FEATURE_RETURN_KEEPTRYING    24
00496 
00497 #define FEATURE_SENSE_CHAN (1 << 0)
00498 #define FEATURE_SENSE_PEER (1 << 1)
00499 
00500 /*! \brief
00501  * set caller and callee according to the direction
00502  */
00503 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
00504    struct ast_channel *peer, struct ast_channel *chan, int sense)
00505 {
00506    if (sense == FEATURE_SENSE_PEER) {
00507       *caller = peer;
00508       *callee = chan;
00509    } else {
00510       *callee = peer;
00511       *caller = chan;
00512    }
00513 }
00514 
00515 /*! \brief support routing for one touch call parking */
00516 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00517 {
00518    struct ast_channel *parker;
00519         struct ast_channel *parkee;
00520    int res = 0;
00521    struct ast_module_user *u;
00522 
00523    u = ast_module_user_add(chan);
00524 
00525    set_peers(&parker, &parkee, peer, chan, sense);
00526    /* Setup the exten/priority to be s/1 since we don't know
00527       where this call should return */
00528    strcpy(chan->exten, "s");
00529    chan->priority = 1;
00530    if (chan->_state != AST_STATE_UP)
00531       res = ast_answer(chan);
00532    if (!res)
00533       res = ast_safe_sleep(chan, 1000);
00534    if (!res)
00535       res = ast_park_call(parkee, parker, 0, NULL);
00536 
00537    ast_module_user_remove(u);
00538 
00539    if (!res) {
00540       if (sense == FEATURE_SENSE_CHAN)
00541          res = AST_PBX_NO_HANGUP_PEER;
00542       else
00543          res = AST_PBX_KEEPALIVE;
00544    }
00545    return res;
00546 
00547 }
00548 
00549 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00550 {
00551    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00552    int x = 0;
00553    size_t len;
00554    struct ast_channel *caller_chan, *callee_chan;
00555 
00556    if (!monitor_ok) {
00557       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00558       return -1;
00559    }
00560 
00561    if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
00562       monitor_ok = 0;
00563       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00564       return -1;
00565    }
00566 
00567    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00568 
00569    if (!ast_strlen_zero(courtesytone)) {
00570       if (ast_autoservice_start(callee_chan))
00571          return -1;
00572       if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) {
00573          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00574          ast_autoservice_stop(callee_chan);
00575          return -1;
00576       }
00577       if (ast_autoservice_stop(callee_chan))
00578          return -1;
00579    }
00580    
00581    if (callee_chan->monitor) {
00582       if (option_verbose > 3)
00583          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
00584       ast_monitor_stop(callee_chan, 1);
00585       return FEATURE_RETURN_SUCCESS;
00586    }
00587 
00588    if (caller_chan && callee_chan) {
00589       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00590       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00591 
00592       if (!touch_format)
00593          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00594 
00595       if (!touch_monitor)
00596          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00597    
00598       if (touch_monitor) {
00599          len = strlen(touch_monitor) + 50;
00600          args = alloca(len);
00601          touch_filename = alloca(len);
00602          snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
00603          snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
00604       } else {
00605          caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00606          callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00607          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00608          args = alloca(len);
00609          touch_filename = alloca(len);
00610          snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
00611          snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
00612       }
00613 
00614       for( x = 0; x < strlen(args); x++) {
00615          if (args[x] == '/')
00616             args[x] = '-';
00617       }
00618       
00619       if (option_verbose > 3)
00620          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
00621 
00622       pbx_exec(callee_chan, monitor_app, args);
00623       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00624       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00625    
00626       return FEATURE_RETURN_SUCCESS;
00627    }
00628    
00629    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
00630    return -1;
00631 }
00632 
00633 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00634 {
00635    if (option_verbose > 3)
00636       ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00637    return FEATURE_RETURN_HANGUP;
00638 }
00639 
00640 static int finishup(struct ast_channel *chan)
00641 {
00642         ast_indicate(chan, AST_CONTROL_UNHOLD);
00643   
00644         return ast_autoservice_stop(chan);
00645 }
00646 
00647 /*! \brief Find the context for the transfer */
00648 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
00649 {
00650         const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
00651         if (ast_strlen_zero(s))
00652                 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
00653         if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
00654                 s = transferer->macrocontext;
00655         if (ast_strlen_zero(s))
00656                 s = transferer->context;
00657         return s;  
00658 }
00659 
00660 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00661 {
00662    struct ast_channel *transferer;
00663    struct ast_channel *transferee;
00664    const char *transferer_real_context;
00665    char xferto[256];
00666    int res;
00667 
00668    set_peers(&transferer, &transferee, peer, chan, sense);
00669    transferer_real_context = real_ctx(transferer, transferee);
00670    /* Start autoservice on chan while we talk to the originator */
00671    ast_autoservice_start(transferee);
00672    ast_indicate(transferee, AST_CONTROL_HOLD);
00673 
00674    memset(xferto, 0, sizeof(xferto));
00675    
00676    /* Transfer */
00677    res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00678    if (res < 0) {
00679       finishup(transferee);
00680       return -1; /* error ? */
00681    }
00682    if (res > 0)   /* If they've typed a digit already, handle it */
00683       xferto[0] = (char) res;
00684 
00685    ast_stopstream(transferer);
00686    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00687    if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
00688       finishup(transferee);
00689       return res;
00690    }
00691    if (!strcmp(xferto, ast_parking_ext())) {
00692       res = finishup(transferee);
00693       if (res)
00694          res = -1;
00695       else if (!ast_park_call(transferee, transferer, 0, NULL)) { /* success */
00696          /* We return non-zero, but tell the PBX not to hang the channel when
00697             the thread dies -- We have to be careful now though.  We are responsible for 
00698             hanging up the channel, else it will never be hung up! */
00699 
00700          return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER;
00701       } else {
00702          ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
00703       }
00704       /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
00705    } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00706       pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", transferee->name);
00707       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
00708       res=finishup(transferee);
00709       if (!transferer->cdr) {
00710          transferer->cdr=ast_cdr_alloc();
00711          if (transferer) {
00712             ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */
00713             ast_cdr_start(transferer->cdr);
00714          }
00715       }
00716       if (transferer->cdr) {
00717          ast_cdr_setdestchan(transferer->cdr, transferee->name);
00718          ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER","");
00719       }
00720       if (!transferee->pbx) {
00721          /* Doh!  Use our handy async_goto functions */
00722          if (option_verbose > 2) 
00723             ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
00724                         ,transferee->name, xferto, transferer_real_context);
00725          if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
00726             ast_log(LOG_WARNING, "Async goto failed :-(\n");
00727          res = -1;
00728       } else {
00729          /* Set the channel's new extension, since it exists, using transferer context */
00730          set_c_e_p(transferee, transferer_real_context, xferto, 0);
00731       }
00732       check_goto_on_transfer(transferer);
00733       return res;
00734    } else {
00735       if (option_verbose > 2) 
00736          ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
00737    }
00738    if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
00739       finishup(transferee);
00740       return -1;
00741    }
00742    ast_stopstream(transferer);
00743    res = finishup(transferee);
00744    if (res) {
00745       if (option_verbose > 1)
00746          ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
00747       return res;
00748    }
00749    return FEATURE_RETURN_SUCCESS;
00750 }
00751 
00752 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
00753 {
00754    if (ast_channel_make_compatible(c, newchan) < 0) {
00755       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
00756          c->name, newchan->name);
00757       ast_hangup(newchan);
00758       return -1;
00759    }
00760    return 0;
00761 }
00762 
00763 /*!
00764  * \brief Attended transfer implementation
00765  * \param chan transfered user
00766  * \param peer person transfering call
00767  * \param config
00768  * \param sense feature options
00769  * 
00770  * \param toExt
00771  * \param toCont
00772  * This is the actual implementation of attended transfer, it can be activated as a regular feature or through the AMI.
00773  * "toExt" is the extension to transfer to (default: ask for it on the transferer channel)
00774  * "toCont" is the context to transfer to (default: the one in which the transferer is)
00775  *
00776  * \return -1 on failure
00777 */
00778 static int do_atxfer(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config,int sense,const char *toExt,const char *toCont)
00779 {
00780    struct ast_channel *transferer;
00781    struct ast_channel *transferee;
00782    const char *transferer_real_context;
00783    const char *transfer_context;
00784    char xferto[256] = "";
00785    int res;
00786    int outstate=0;
00787    struct ast_channel *newchan;
00788    struct ast_channel *xferchan;
00789    struct ast_bridge_thread_obj *tobj;
00790    struct ast_bridge_config bconfig;
00791    struct ast_frame *f;
00792    int l;
00793 
00794    if (option_debug)
00795       ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
00796    set_peers(&transferer, &transferee, peer, chan, sense);
00797    transferer_real_context = real_ctx(transferer, transferee);
00798    transfer_context = S_OR(toCont, transferer_real_context);
00799 
00800    /* Start autoservice on chan while we talk to the originator */
00801    ast_autoservice_start(transferee);
00802    ast_indicate(transferee, AST_CONTROL_HOLD);
00803 
00804    if (!ast_strlen_zero(toExt)) {
00805       ast_copy_string(xferto, toExt, sizeof(xferto));
00806    } else {
00807       /* Ask for extension to transfer to on the transferer channel */
00808       res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00809       if (res < 0) {
00810          finishup(transferee);
00811          return res;
00812       }
00813       if (res > 0) /* If they've typed a digit already, handle it */
00814          xferto[0] = (char) res;
00815 
00816       /* this is specific of atxfer */
00817       res = ast_app_dtget(transferer, transfer_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00818       if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
00819          finishup(transferee);
00820          return res;
00821       }
00822       if (res == 0) {
00823          ast_log(LOG_WARNING, "Did not read data.\n");
00824          finishup(transferee);
00825          if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00826             return -1;
00827          return FEATURE_RETURN_SUCCESS;
00828       }
00829    }
00830 
00831    /* valid extension, res == 1 */
00832    if (!ast_exists_extension(transferer, transfer_context, xferto, 1, transferer->cid.cid_num)) {
00833       ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transfer_context);
00834       finishup(transferee);
00835       if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00836          return -1;
00837       return FEATURE_RETURN_SUCCESS;
00838    }
00839 
00840    l = strlen(xferto);
00841    snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transfer_context); /* append context */
00842    newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
00843       xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, transferer->language);
00844    ast_indicate(transferer, -1);
00845    if (!newchan) {
00846       finishup(transferee);
00847       /* any reason besides user requested cancel and busy triggers the failed sound */
00848       if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
00849             ast_stream_and_wait(transferer, xferfailsound, transferer->language, ""))
00850          return -1;
00851       return FEATURE_RETURN_SUCCESS;
00852    }
00853 
00854    if (check_compat(transferer, newchan)) {
00855       /* we do mean transferee here, NOT transferer */
00856       finishup(transferee);
00857       return -1;
00858    }
00859    memset(&bconfig,0,sizeof(struct ast_bridge_config));
00860    ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
00861    ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
00862    res = ast_bridge_call(transferer, newchan, &bconfig);
00863    if (newchan->_softhangup || !transferer->_softhangup) {
00864       ast_hangup(newchan);
00865       if (ast_stream_and_wait(transferer, xfersound, transferer->language, ""))
00866          ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00867       finishup(transferee);
00868       transferer->_softhangup = 0;
00869       return FEATURE_RETURN_SUCCESS;
00870    }
00871    
00872    if (check_compat(transferee, newchan)) {
00873       finishup(transferee);
00874       return -1;
00875    }
00876 
00877    ast_indicate(transferee, AST_CONTROL_UNHOLD);
00878    
00879    if ((ast_autoservice_stop(transferee) < 0)
00880       || (ast_waitfordigit(transferee, 100) < 0)
00881       || (ast_waitfordigit(newchan, 100) < 0) 
00882       || ast_check_hangup(transferee) 
00883       || ast_check_hangup(newchan)) {
00884       ast_hangup(newchan);
00885       return -1;
00886    }
00887 
00888    xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
00889    if (!xferchan) {
00890       ast_hangup(newchan);
00891       return -1;
00892    }
00893    /* Make formats okay */
00894    xferchan->visible_indication = transferer->visible_indication;
00895    xferchan->readformat = transferee->readformat;
00896    xferchan->writeformat = transferee->writeformat;
00897    ast_channel_masquerade(xferchan, transferee);
00898    ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
00899    xferchan->_state = AST_STATE_UP;
00900    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00901    xferchan->_softhangup = 0;
00902 
00903    if ((f = ast_read(xferchan)))
00904       ast_frfree(f);
00905 
00906    newchan->_state = AST_STATE_UP;
00907    ast_clear_flag(newchan, AST_FLAGS_ALL);   
00908    newchan->_softhangup = 0;
00909 
00910    tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
00911    if (!tobj) {
00912       ast_hangup(xferchan);
00913       ast_hangup(newchan);
00914       return -1;
00915    }
00916    tobj->chan = newchan;
00917    tobj->peer = xferchan;
00918    tobj->bconfig = *config;
00919 
00920    if (ast_stream_and_wait(newchan, xfersound, newchan->language, ""))
00921       ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00922    ast_bridge_call_thread_launch(tobj);
00923    return -1;  /* XXX meaning the channel is bridged ? */
00924 }
00925 
00926 
00927 /*!
00928  * \brief Attended transfer ()
00929  * \param chan
00930  * \param peer
00931  * \param config
00932  * \param code
00933  * \param sense
00934  * \param data
00935  * Get extension to transfer to, if you cannot generate channel (or find extension)
00936  * return to host channel. After called channel answered wait for hangup of transferer,
00937  * bridge call between transfer peer (taking them off hold) to attended transfer channel.
00938  * \return -1 means what failure/success both?
00939 */
00940 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00941 {
00942    return do_atxfer(chan, peer, config, sense, NULL, NULL);
00943 }
00944 
00945 /* add atxfer and automon as undefined so you can only use em if you configure them */
00946 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
00947 
00948 AST_RWLOCK_DEFINE_STATIC(features_lock);
00949 
00950 static struct ast_call_feature builtin_features[] = 
00951  {
00952    { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00953    { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00954    { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00955    { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00956    { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00957 };
00958 
00959 
00960 static AST_LIST_HEAD_STATIC(feature_list,ast_call_feature);
00961 
00962 /*! \brief register new feature into feature_list*/
00963 void ast_register_feature(struct ast_call_feature *feature)
00964 {
00965    if (!feature) {
00966       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00967          return;
00968    }
00969   
00970    AST_LIST_LOCK(&feature_list);
00971    AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00972    AST_LIST_UNLOCK(&feature_list);
00973 
00974    if (option_verbose >= 2) 
00975       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00976 }
00977 
00978 /*! \brief unregister feature from feature_list */
00979 void ast_unregister_feature(struct ast_call_feature *feature)
00980 {
00981    if (!feature)
00982       return;
00983 
00984    AST_LIST_LOCK(&feature_list);
00985    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00986    AST_LIST_UNLOCK(&feature_list);
00987    free(feature);
00988 }
00989 
00990 /*! \brief Remove all features in the list */
00991 static void ast_unregister_features(void)
00992 {
00993    struct ast_call_feature *feature;
00994 
00995    AST_LIST_LOCK(&feature_list);
00996    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
00997       free(feature);
00998    AST_LIST_UNLOCK(&feature_list);
00999 }
01000 
01001 /*! \brief find a feature by name */
01002 static struct ast_call_feature *find_dynamic_feature(const char *name)
01003 {
01004    struct ast_call_feature *tmp;
01005 
01006    AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01007       if (!strcasecmp(tmp->sname, name))
01008          break;
01009    }
01010 
01011    return tmp;
01012 }
01013 
01014 /*! \brief exec an app by feature */
01015 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
01016 {
01017    struct ast_app *app;
01018    struct ast_call_feature *feature = data;
01019    struct ast_channel *work, *idle;
01020    int res;
01021 
01022    if (!feature) { /* shouldn't ever happen! */
01023       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01024       return -1; 
01025    }
01026 
01027    if (sense == FEATURE_SENSE_CHAN) {
01028       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01029          return FEATURE_RETURN_KEEPTRYING;
01030       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01031          work = chan;
01032          idle = peer;
01033       } else {
01034          work = peer;
01035          idle = chan;
01036       }
01037    } else {
01038       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01039          return FEATURE_RETURN_KEEPTRYING;
01040       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01041          work = peer;
01042          idle = chan;
01043       } else {
01044          work = chan;
01045          idle = peer;
01046       }
01047    }
01048 
01049    if (!(app = pbx_findapp(feature->app))) {
01050       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01051       return -2;
01052    }
01053 
01054    ast_autoservice_start(idle);
01055    
01056    if (!ast_strlen_zero(feature->moh_class))
01057       ast_moh_start(idle, feature->moh_class, NULL);
01058 
01059    res = pbx_exec(work, app, feature->app_args);
01060 
01061    if (!ast_strlen_zero(feature->moh_class))
01062       ast_moh_stop(idle);
01063 
01064    ast_autoservice_stop(idle);
01065 
01066    if (res == AST_PBX_KEEPALIVE)
01067       return FEATURE_RETURN_PBX_KEEPALIVE;
01068    else if (res == AST_PBX_NO_HANGUP_PEER)
01069       return FEATURE_RETURN_NO_HANGUP_PEER;
01070    else if (res)
01071       return FEATURE_RETURN_SUCCESSBREAK;
01072    
01073    return FEATURE_RETURN_SUCCESS;   /*! \todo XXX should probably return res */
01074 }
01075 
01076 static void unmap_features(void)
01077 {
01078    int x;
01079 
01080    ast_rwlock_wrlock(&features_lock);
01081    for (x = 0; x < FEATURES_COUNT; x++)
01082       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01083    ast_rwlock_unlock(&features_lock);
01084 }
01085 
01086 static int remap_feature(const char *name, const char *value)
01087 {
01088    int x, res = -1;
01089 
01090    ast_rwlock_wrlock(&features_lock);
01091    for (x = 0; x < FEATURES_COUNT; x++) {
01092       if (strcasecmp(builtin_features[x].sname, name))
01093          continue;
01094 
01095       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01096       res = 0;
01097       break;
01098    }
01099    ast_rwlock_unlock(&features_lock);
01100 
01101    return res;
01102 }
01103 
01104 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
01105 {
01106    int x;
01107    struct ast_flags features;
01108    int res = FEATURE_RETURN_PASSDIGITS;
01109    struct ast_call_feature *feature;
01110    const char *dynamic_features;
01111    char *tmp, *tok;
01112 
01113    if (sense == FEATURE_SENSE_CHAN) {
01114       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);   
01115       dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01116    } else {
01117       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);   
01118       dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES");
01119    }
01120    if (option_debug > 2)
01121       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);
01122 
01123    ast_rwlock_rdlock(&features_lock);
01124    for (x = 0; x < FEATURES_COUNT; x++) {
01125       if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
01126           !ast_strlen_zero(builtin_features[x].exten)) {
01127          /* Feature is up for consideration */
01128          if (!strcmp(builtin_features[x].exten, code)) {
01129             res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
01130             break;
01131          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01132             if (res == FEATURE_RETURN_PASSDIGITS)
01133                res = FEATURE_RETURN_STOREDIGITS;
01134          }
01135       }
01136    }
01137    ast_rwlock_unlock(&features_lock);
01138 
01139    if (ast_strlen_zero(dynamic_features))
01140       return res;
01141 
01142    tmp = ast_strdupa(dynamic_features);
01143 
01144    while ((tok = strsep(&tmp, "#"))) {
01145       AST_LIST_LOCK(&feature_list); 
01146       if (!(feature = find_dynamic_feature(tok))) {
01147          AST_LIST_UNLOCK(&feature_list);
01148          continue;
01149       }
01150          
01151       /* Feature is up for consideration */
01152       if (!strcmp(feature->exten, code)) {
01153          if (option_verbose > 2)
01154             ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
01155          res = feature->operation(chan, peer, config, code, sense, feature);
01156          if (res != FEATURE_RETURN_KEEPTRYING) {
01157             AST_LIST_UNLOCK(&feature_list);
01158             break;
01159          }
01160          res = FEATURE_RETURN_PASSDIGITS;
01161       } else if (!strncmp(feature->exten, code, strlen(code)))
01162          res = FEATURE_RETURN_STOREDIGITS;
01163 
01164       AST_LIST_UNLOCK(&feature_list);
01165    }
01166    
01167    return res;
01168 }
01169 
01170 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
01171 {
01172    int x;
01173    
01174    ast_clear_flag(config, AST_FLAGS_ALL);
01175 
01176    ast_rwlock_rdlock(&features_lock);
01177    for (x = 0; x < FEATURES_COUNT; x++) {
01178       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
01179          continue;
01180 
01181       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01182          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01183 
01184       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01185          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01186    }
01187    ast_rwlock_unlock(&features_lock);
01188    
01189    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01190       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01191 
01192       if (dynamic_features) {
01193          char *tmp = ast_strdupa(dynamic_features);
01194          char *tok;
01195          struct ast_call_feature *feature;
01196 
01197          /* while we have a feature */
01198          while ((tok = strsep(&tmp, "#"))) {
01199             AST_LIST_LOCK(&feature_list);
01200             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01201                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01202                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01203                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01204                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01205             }
01206             AST_LIST_UNLOCK(&feature_list);
01207          }
01208       }
01209    }
01210 }
01211 
01212 /*! \todo XXX Check - this is very similar to the code in channel.c */
01213 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)
01214 {
01215    int state = 0;
01216    int cause = 0;
01217    int to;
01218    struct ast_channel *chan;
01219    struct ast_channel *monitor_chans[2];
01220    struct ast_channel *active_channel;
01221    int res = 0, ready = 0;
01222    
01223    if ((chan = ast_request(type, format, data, &cause))) {
01224       ast_set_callerid(chan, cid_num, cid_name, cid_num);
01225       ast_string_field_set(chan, language, language);
01226       ast_channel_inherit_variables(caller, chan); 
01227       pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
01228       if (!chan->cdr) {
01229          chan->cdr=ast_cdr_alloc();
01230          if (chan->cdr) {
01231             ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
01232             ast_cdr_start(chan->cdr);
01233          }
01234       }
01235          
01236       if (!ast_call(chan, data, timeout)) {
01237          struct timeval started;
01238          int x, len = 0;
01239          char *disconnect_code = NULL, *dialed_code = NULL;
01240 
01241          ast_indicate(caller, AST_CONTROL_RINGING);
01242          /* support dialing of the featuremap disconnect code while performing an attended tranfer */
01243          ast_rwlock_rdlock(&features_lock);
01244          for (x = 0; x < FEATURES_COUNT; x++) {
01245             if (strcasecmp(builtin_features[x].sname, "disconnect"))
01246                continue;
01247 
01248             disconnect_code = builtin_features[x].exten;
01249             len = strlen(disconnect_code) + 1;
01250             dialed_code = alloca(len);
01251             memset(dialed_code, 0, len);
01252             break;
01253          }
01254          ast_rwlock_unlock(&features_lock);
01255          x = 0;
01256          started = ast_tvnow();
01257          to = timeout;
01258          while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
01259             struct ast_frame *f = NULL;
01260 
01261             monitor_chans[0] = caller;
01262             monitor_chans[1] = chan;
01263             active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01264 
01265             /* see if the timeout has been violated */
01266             if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01267                state = AST_CONTROL_UNHOLD;
01268                ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01269                break; /*doh! timeout*/
01270             }
01271 
01272             if (!active_channel)
01273                continue;
01274 
01275             if (chan && (chan == active_channel)){
01276                f = ast_read(chan);
01277                if (f == NULL) { /*doh! where'd he go?*/
01278                   state = AST_CONTROL_HANGUP;
01279                   res = 0;
01280                   break;
01281                }
01282                
01283                if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01284                   if (f->subclass == AST_CONTROL_RINGING) {
01285                      state = f->subclass;
01286                      if (option_verbose > 2)
01287                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
01288                      ast_indicate(caller, AST_CONTROL_RINGING);
01289                   } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01290                      state = f->subclass;
01291                      if (option_verbose > 2)
01292                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
01293                      ast_indicate(caller, AST_CONTROL_BUSY);
01294                      ast_frfree(f);
01295                      f = NULL;
01296                      break;
01297                   } else if (f->subclass == AST_CONTROL_ANSWER) {
01298                      /* This is what we are hoping for */
01299                      state = f->subclass;
01300                      ast_frfree(f);
01301                      f = NULL;
01302                      ready=1;
01303                      break;
01304                   } else if (f->subclass != -1) {
01305                      ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01306                   }
01307                   /* else who cares */
01308                }
01309 
01310             } else if (caller && (active_channel == caller)) {
01311                f = ast_read(caller);
01312                if (f == NULL) { /*doh! where'd he go?*/
01313                   if (caller->_softhangup && !chan->_softhangup) {
01314                      /* make this a blind transfer */
01315                      ready = 1;
01316                      break;
01317                   }
01318                   state = AST_CONTROL_HANGUP;
01319                   res = 0;
01320                   break;
01321                }
01322                
01323                if (f->frametype == AST_FRAME_DTMF) {
01324                   dialed_code[x++] = f->subclass;
01325                   dialed_code[x] = '\0';
01326                   if (strlen(dialed_code) == len) {
01327                      x = 0;
01328                   } else if (x && strncmp(dialed_code, disconnect_code, x)) {
01329                      x = 0;
01330                      dialed_code[x] = '\0';
01331                   }
01332                   if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
01333                      /* Caller Canceled the call */
01334                      state = AST_CONTROL_UNHOLD;
01335                      ast_frfree(f);
01336                      f = NULL;
01337                      break;
01338                   }
01339                }
01340             }
01341             if (f)
01342                ast_frfree(f);
01343          } /* end while */
01344       } else
01345          ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
01346    } else {
01347       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01348       switch(cause) {
01349       case AST_CAUSE_BUSY:
01350          state = AST_CONTROL_BUSY;
01351          break;
01352       case AST_CAUSE_CONGESTION:
01353          state = AST_CONTROL_CONGESTION;
01354          break;
01355       }
01356    }
01357    
01358    ast_indicate(caller, -1);
01359    if (chan && ready) {
01360       if (chan->_state == AST_STATE_UP) 
01361          state = AST_CONTROL_ANSWER;
01362       res = 0;
01363    } else if(chan) {
01364       res = -1;
01365       ast_hangup(chan);
01366       chan = NULL;
01367    } else {
01368       res = -1;
01369    }
01370    
01371    if (outstate)
01372       *outstate = state;
01373 
01374    if (chan && res <= 0) {
01375       if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
01376          char tmp[256];
01377          ast_cdr_init(chan->cdr, chan);
01378          snprintf(tmp, 256, "%s/%s", type, (char *)data);
01379          ast_cdr_setapp(chan->cdr,"Dial",tmp);
01380          ast_cdr_update(chan);
01381          ast_cdr_start(chan->cdr);
01382          ast_cdr_end(chan->cdr);
01383          /* If the cause wasn't handled properly */
01384          if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
01385             ast_cdr_failed(chan->cdr);
01386       } else {
01387          ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
01388       }
01389    }
01390    
01391    return chan;
01392 }
01393 
01394 static void cmd_atxfer(struct ast_channel *a, struct ast_channel *b, struct ast_bridge_config *conf, struct ast_channel *who, char *xferto)
01395 {
01396    int sense = (a == who) ? FEATURE_SENSE_CHAN : FEATURE_SENSE_PEER;
01397    char *context = strchr(xferto, '@');;
01398    if (context)
01399       *context++ = '\0';
01400    do_atxfer(a, b, conf, sense, xferto, context);
01401 }
01402 
01403 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
01404 {
01405    /* Copy voice back and forth between the two channels.  Give the peer
01406       the ability to transfer calls with '#<extension' syntax. */
01407    struct ast_frame *f;
01408    struct ast_channel *who;
01409    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01410    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01411    int res;
01412    int diff;
01413    int hasfeatures=0;
01414    int hadfeatures=0;
01415    struct ast_option_header *aoh;
01416    struct ast_bridge_config backup_config;
01417    struct ast_cdr *bridge_cdr;
01418 
01419    memset(&backup_config, 0, sizeof(backup_config));
01420 
01421    config->start_time = ast_tvnow();
01422 
01423    if (chan && peer) {
01424       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01425       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01426    } else if (chan)
01427       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01428 
01429    if (monitor_ok) {
01430       const char *monitor_exec;
01431       struct ast_channel *src = NULL;
01432       if (!monitor_app) { 
01433          if (!(monitor_app = pbx_findapp("Monitor")))
01434             monitor_ok=0;
01435       }
01436       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01437          src = chan;
01438       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01439          src = peer;
01440       if (monitor_app && src) {
01441          char *tmp = ast_strdupa(monitor_exec);
01442          pbx_exec(src, monitor_app, tmp);
01443       }
01444    }
01445    
01446    set_config_flags(chan, peer, config);
01447    config->firstpass = 1;
01448 
01449    /* Answer if need be */
01450    if (ast_answer(chan))
01451       return -1;
01452    peer->appl = "Bridged Call";
01453    peer->data = chan->name;
01454 
01455    /* copy the userfield from the B-leg to A-leg if applicable */
01456    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01457       char tmp[256];
01458       if (!ast_strlen_zero(chan->cdr->userfield)) {
01459          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01460          ast_cdr_appenduserfield(chan, tmp);
01461       } else
01462          ast_cdr_setuserfield(chan, peer->cdr->userfield);
01463       /* free the peer's cdr without ast_cdr_free complaining */
01464       free(peer->cdr);
01465       peer->cdr = NULL;
01466    }
01467 
01468    for (;;) {
01469       struct ast_channel *other; /* used later */
01470 
01471       res = ast_channel_bridge(chan, peer, config, &f, &who);
01472 
01473       if (config->feature_timer) {
01474          /* Update time limit for next pass */
01475          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
01476          config->feature_timer -= diff;
01477          if (hasfeatures) {
01478             /* Running on backup config, meaning a feature might be being
01479                activated, but that's no excuse to keep things going 
01480                indefinitely! */
01481             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01482                if (option_debug)
01483                   ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01484                config->feature_timer = 0;
01485                who = chan;
01486                if (f)
01487                   ast_frfree(f);
01488                f = NULL;
01489                res = 0;
01490             } else if (config->feature_timer <= 0) {
01491                /* Not *really* out of time, just out of time for
01492                   digits to come in for features. */
01493                if (option_debug)
01494                   ast_log(LOG_DEBUG, "Timed out for feature!\n");
01495                if (!ast_strlen_zero(peer_featurecode)) {
01496                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01497                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
01498                }
01499                if (!ast_strlen_zero(chan_featurecode)) {
01500                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01501                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
01502                }
01503                if (f)
01504                   ast_frfree(f);
01505                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01506                if (!hasfeatures) {
01507                   /* Restore original (possibly time modified) bridge config */
01508                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01509                   memset(&backup_config, 0, sizeof(backup_config));
01510                }
01511                hadfeatures = hasfeatures;
01512                /* Continue as we were */
01513                continue;
01514             } else if (!f) {
01515                /* The bridge returned without a frame and there is a feature in progress.
01516                 * However, we don't think the feature has quite yet timed out, so just
01517                 * go back into the bridge. */
01518                continue;
01519             }
01520          } else {
01521             if (config->feature_timer <=0) {
01522                /* We ran out of time */
01523                config->feature_timer = 0;
01524                who = chan;
01525                if (f)
01526                   ast_frfree(f);
01527                f = NULL;
01528                res = 0;
01529             }
01530          }
01531       }
01532       if (res < 0) {
01533          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
01534             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01535          return -1;
01536       }
01537       
01538       if (!f || (f->frametype == AST_FRAME_CONTROL &&
01539             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
01540                f->subclass == AST_CONTROL_CONGESTION ) ) ) {
01541          res = -1;
01542          break;
01543       }
01544       /* many things should be sent to the 'other' channel */
01545       other = (who == chan) ? peer : chan;
01546       if (f->frametype == AST_FRAME_CONTROL) {
01547          switch (f->subclass) {
01548          case AST_CONTROL_RINGING:
01549          case AST_CONTROL_FLASH:
01550          case -1:
01551             ast_indicate(other, f->subclass);
01552             break;
01553          case AST_CONTROL_HOLD:
01554          case AST_CONTROL_UNHOLD:
01555             ast_indicate_data(other, f->subclass, f->data, f->datalen);
01556             break;
01557          case AST_CONTROL_OPTION:
01558             aoh = f->data;
01559             /* Forward option Requests */
01560             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
01561                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
01562                   f->datalen - sizeof(struct ast_option_header), 0);
01563             }
01564             break;
01565          case AST_CONTROL_ATXFERCMD:
01566             cmd_atxfer(chan, peer, config, who, f->data);
01567             break;
01568          }
01569       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
01570          /* eat it */
01571       } else if (f->frametype == AST_FRAME_DTMF) {
01572          char *featurecode;
01573          int sense;
01574 
01575          hadfeatures = hasfeatures;
01576          /* This cannot overrun because the longest feature is one shorter than our buffer */
01577          if (who == chan) {
01578             sense = FEATURE_SENSE_CHAN;
01579             featurecode = chan_featurecode;
01580          } else  {
01581             sense = FEATURE_SENSE_PEER;
01582             featurecode = peer_featurecode;
01583          }
01584          /*! append the event to featurecode. we rely on the string being zero-filled, and
01585           * not overflowing it. 
01586           * \todo XXX how do we guarantee the latter ?
01587           */
01588          featurecode[strlen(featurecode)] = f->subclass;
01589          /* Get rid of the frame before we start doing "stuff" with the channels */
01590          ast_frfree(f);
01591          f = NULL;
01592          config->feature_timer = backup_config.feature_timer;
01593          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01594          switch(res) {
01595          case FEATURE_RETURN_PASSDIGITS:
01596             ast_dtmf_stream(other, who, featurecode, 0);
01597             /* Fall through */
01598          case FEATURE_RETURN_SUCCESS:
01599             memset(featurecode, 0, sizeof(chan_featurecode));
01600             break;
01601          }
01602          if (res >= FEATURE_RETURN_PASSDIGITS) {
01603             res = 0;
01604          } else 
01605             break;
01606          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01607          if (hadfeatures && !hasfeatures) {
01608             /* Restore backup */
01609             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01610             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01611          } else if (hasfeatures) {
01612             if (!hadfeatures) {
01613                /* Backup configuration */
01614                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01615                /* Setup temporary config options */
01616                config->play_warning = 0;
01617                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01618                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01619                config->warning_freq = 0;
01620                config->warning_sound = NULL;
01621                config->end_sound = NULL;
01622                config->start_sound = NULL;
01623                config->firstpass = 0;
01624             }
01625             config->start_time = ast_tvnow();
01626             config->feature_timer = featuredigittimeout;
01627             if (option_debug)
01628                ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01629          }
01630       }
01631       if (f)
01632          ast_frfree(f);
01633 
01634    }
01635 
01636    /* arrange the cdrs */
01637    bridge_cdr = ast_cdr_alloc();
01638    if (bridge_cdr) {
01639       if (chan->cdr && peer->cdr) { /* both of them? merge */
01640          ast_channel_lock(chan);  /* lock the channel before modifing cdrs */
01641          ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the  destination as a base, but, really, it's random */
01642          ast_cdr_start(bridge_cdr); /* now is the time to start */
01643 
01644          /* absorb the channel cdr */
01645          ast_cdr_merge(bridge_cdr, chan->cdr);
01646          if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED)) 
01647             ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01648 
01649          chan->cdr = NULL; /* remove pointer to freed memory before releasing the lock */
01650 
01651          ast_channel_unlock(chan);
01652          
01653          /* absorb the peer cdr */
01654          ast_channel_lock(peer);
01655          ast_cdr_merge(bridge_cdr, peer->cdr);
01656          if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
01657             ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */
01658          
01659          peer->cdr = NULL;
01660          ast_channel_unlock(peer);
01661 
01662          ast_channel_lock(chan);
01663          chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01664          ast_channel_unlock(chan);
01665 
01666       } else if (chan->cdr) {
01667 
01668          ast_channel_lock(chan); /* Lock before modifying CDR */
01669          /* take the cdr from the channel - literally */
01670          ast_cdr_init(bridge_cdr,chan);
01671          /* absorb this data */
01672          ast_cdr_merge(bridge_cdr, chan->cdr);
01673          if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
01674             ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01675          chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01676          ast_channel_unlock(chan);
01677       } else if (peer->cdr) {
01678          ast_channel_lock(peer); /* Lock before modifying CDR */
01679          /* take the cdr from the peer - literally */
01680          ast_cdr_init(bridge_cdr,peer);
01681          /* absorb this data */
01682          ast_cdr_merge(bridge_cdr, peer->cdr);
01683          if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
01684             ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01685          peer->cdr = NULL;
01686          peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01687          ast_channel_unlock(peer);
01688       } else {
01689          ast_channel_lock(chan); /* Lock before modifying CDR */
01690          /* make up a new cdr */
01691          ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */
01692          chan->cdr = bridge_cdr; /*  */
01693          ast_channel_unlock(chan);
01694       }
01695       if (ast_strlen_zero(bridge_cdr->dstchannel)) {
01696          if (strcmp(bridge_cdr->channel, peer->name) != 0)
01697             ast_cdr_setdestchan(bridge_cdr, peer->name);
01698          else
01699             ast_cdr_setdestchan(bridge_cdr, chan->name);
01700       }
01701    }
01702    return res;
01703 }
01704 
01705 static void post_manager_event(const char *s, char *parkingexten, struct ast_channel *chan)
01706 {
01707    manager_event(EVENT_FLAG_CALL, s,
01708       "Exten: %s\r\n"
01709       "Channel: %s\r\n"
01710       "CallerID: %s\r\n"
01711       "CallerIDName: %s\r\n\r\n",
01712       parkingexten, 
01713       chan->name,
01714       S_OR(chan->cid.cid_num, "<unknown>"),
01715       S_OR(chan->cid.cid_name, "<unknown>")
01716       );
01717 }
01718 
01719 /*! \brief Take care of parked calls and unpark them if needed */
01720 static void *do_parking_thread(void *ignore)
01721 {
01722    fd_set rfds, efds;   /* results from previous select, to be preserved across loops. */
01723    FD_ZERO(&rfds);
01724    FD_ZERO(&efds);
01725 
01726    for (;;) {
01727       struct parkeduser *pu, *pl, *pt = NULL;
01728       int ms = -1;   /* select timeout, uninitialized */
01729       int max = -1;  /* max fd, none there yet */
01730       fd_set nrfds, nefds; /* args for the next select */
01731       FD_ZERO(&nrfds);
01732       FD_ZERO(&nefds);
01733 
01734       ast_mutex_lock(&parking_lock);
01735       pl = NULL;
01736       pu = parkinglot;
01737       /* navigate the list with prev-cur pointers to support removals */
01738       while (pu) {
01739          struct ast_channel *chan = pu->chan;   /* shorthand */
01740          int tms;        /* timeout for this item */
01741          int x;          /* fd index in channel */
01742          struct ast_context *con;
01743 
01744          if (pu->notquiteyet) { /* Pretend this one isn't here yet */
01745             pl = pu;
01746             pu = pu->next;
01747             continue;
01748          }
01749          tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
01750          if (tms > pu->parkingtime) {
01751             ast_indicate(chan, AST_CONTROL_UNHOLD);
01752             /* Get chan, exten from derived kludge */
01753             if (pu->peername[0]) {
01754                char *peername = ast_strdupa(pu->peername);
01755                char *cp = strrchr(peername, '-');
01756                if (cp) 
01757                   *cp = 0;
01758                con = ast_context_find(parking_con_dial);
01759                if (!con) {
01760                   con = ast_context_create(NULL, parking_con_dial, registrar);
01761                   if (!con)
01762                      ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
01763                }
01764                if (con) {
01765                   char returnexten[AST_MAX_EXTENSION];
01766                   snprintf(returnexten, sizeof(returnexten), "%s|30|t", peername);
01767                   ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
01768                }
01769                set_c_e_p(chan, parking_con_dial, peername, 1);
01770             } else {
01771                /* They've been waiting too long, send them back to where they came.  Theoretically they
01772                   should have their original extensions and such, but we copy to be on the safe side */
01773                set_c_e_p(chan, pu->context, pu->exten, pu->priority);
01774             }
01775 
01776             post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
01777 
01778             if (option_verbose > 1) 
01779                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);
01780             /* Start up the PBX, or hang them up */
01781             if (ast_pbx_start(chan))  {
01782                ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
01783                ast_hangup(chan);
01784             }
01785             /* And take them out of the parking lot */
01786             if (pl) 
01787                pl->next = pu->next;
01788             else
01789                parkinglot = pu->next;
01790             pt = pu;
01791             pu = pu->next;
01792             con = ast_context_find(parking_con);
01793             if (con) {
01794                if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
01795                   ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01796                else
01797                   notify_metermaids(pt->parkingexten, parking_con);
01798             } else
01799                ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01800             free(pt);
01801          } else { /* still within parking time, process descriptors */
01802             for (x = 0; x < AST_MAX_FDS; x++) {
01803                struct ast_frame *f;
01804 
01805                if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
01806                   continue;   /* nothing on this descriptor */
01807 
01808                if (FD_ISSET(chan->fds[x], &efds))
01809                   ast_set_flag(chan, AST_FLAG_EXCEPTION);
01810                else
01811                   ast_clear_flag(chan, AST_FLAG_EXCEPTION);
01812                chan->fdno = x;
01813 
01814                /* See if they need servicing */
01815                f = ast_read(chan);
01816                if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass ==  AST_CONTROL_HANGUP)) {
01817                   if (f)
01818                      ast_frfree(f);
01819                   post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
01820 
01821                   /* There's a problem, hang them up*/
01822                   if (option_verbose > 1) 
01823                      ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
01824                   ast_hangup(chan);
01825                   /* And take them out of the parking lot */
01826                   if (pl) 
01827                      pl->next = pu->next;
01828                   else
01829                      parkinglot = pu->next;
01830                   pt = pu;
01831                   pu = pu->next;
01832                   con = ast_context_find(parking_con);
01833                   if (con) {
01834                      if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
01835                         ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01836                   else
01837                      notify_metermaids(pt->parkingexten, parking_con);
01838                   } else
01839                      ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01840                   free(pt);
01841                   break;
01842                } else {
01843                   /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
01844                   ast_frfree(f);
01845                   if (pu->moh_trys < 3 && !chan->generatordata) {
01846                      if (option_debug)
01847                         ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
01848                      ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
01849                         S_OR(parkmohclass, NULL),
01850                         !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
01851                      pu->moh_trys++;
01852                   }
01853                   goto std;   /*! \todo XXX Ick: jumping into an else statement??? XXX */
01854                }
01855 
01856             } /* end for */
01857             if (x >= AST_MAX_FDS) {
01858 std:              for (x=0; x<AST_MAX_FDS; x++) {  /* mark fds for next round */
01859                   if (chan->fds[x] > -1) {
01860                      FD_SET(chan->fds[x], &nrfds);
01861                      FD_SET(chan->fds[x], &nefds);
01862                      if (chan->fds[x] > max)
01863                         max = chan->fds[x];
01864                   }
01865                }
01866                /* Keep track of our shortest wait */
01867                if (tms < ms || ms < 0)
01868                   ms = tms;
01869                pl = pu;
01870                pu = pu->next;
01871             }
01872          }
01873       } /* end while */
01874       ast_mutex_unlock(&parking_lock);
01875       rfds = nrfds;
01876       efds = nefds;
01877       {
01878          struct timeval tv = ast_samp2tv(ms, 1000);
01879          /* Wait for something to happen */
01880          ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
01881       }
01882       pthread_testcancel();
01883    }
01884    return NULL;   /* Never reached */
01885 }
01886 
01887 /*! \brief Park a call */
01888 static int park_call_exec(struct ast_channel *chan, void *data)
01889 {
01890    /* Cache the original channel name in case we get masqueraded in the middle
01891     * of a park--it is still theoretically possible for a transfer to happen before
01892     * we get here, but it is _really_ unlikely */
01893    char *orig_chan_name = ast_strdupa(chan->name);
01894    char orig_exten[AST_MAX_EXTENSION];
01895    int orig_priority = chan->priority;
01896 
01897    /* Data is unused at the moment but could contain a parking
01898       lot context eventually */
01899    int res = 0;
01900    struct ast_module_user *u;
01901 
01902    u = ast_module_user_add(chan);
01903 
01904    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
01905 
01906    /* Setup the exten/priority to be s/1 since we don't know
01907       where this call should return */
01908    strcpy(chan->exten, "s");
01909    chan->priority = 1;
01910    /* Answer if call is not up */
01911    if (chan->_state != AST_STATE_UP)
01912       res = ast_answer(chan);
01913    /* Sleep to allow VoIP streams to settle down */
01914    if (!res)
01915       res = ast_safe_sleep(chan, 1000);
01916    /* Park the call */
01917    if (!res) {
01918       res = park_call_full(chan, chan, 0, NULL, orig_chan_name);
01919       /* Continue on in the dialplan */
01920       if (res == 1) {
01921          ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
01922          chan->priority = orig_priority;
01923          res = 0;
01924       } else if (!res)
01925          res = AST_PBX_KEEPALIVE;
01926    }
01927 
01928    ast_module_user_remove(u);
01929 
01930    return res;
01931 }
01932 
01933 /*! \brief Pickup parked call */
01934 static int park_exec(struct ast_channel *chan, void *data)
01935 {
01936    int res = 0;
01937    struct ast_module_user *u;
01938    struct ast_channel *peer=NULL;
01939    struct parkeduser *pu, *pl=NULL;
01940    struct ast_context *con;
01941 
01942    int park;
01943    struct ast_bridge_config config;
01944 
01945    if (!data) {
01946       ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
01947       return -1;
01948    }
01949    
01950    u = ast_module_user_add(chan);
01951 
01952    park = atoi((char *)data);
01953    ast_mutex_lock(&parking_lock);
01954    pu = parkinglot;
01955    while(pu) {
01956       if (pu->parkingnum == park) {
01957          if (pl)
01958             pl->next = pu->next;
01959          else
01960             parkinglot = pu->next;
01961          break;
01962       }
01963       pl = pu;
01964       pu = pu->next;
01965    }
01966    ast_mutex_unlock(&parking_lock);
01967    if (pu) {
01968       peer = pu->chan;
01969       con = ast_context_find(parking_con);
01970       if (con) {
01971          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
01972             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01973          else
01974             notify_metermaids(pu->parkingexten, parking_con);
01975       } else
01976          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01977 
01978       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
01979          "Exten: %s\r\n"
01980          "Channel: %s\r\n"
01981          "From: %s\r\n"
01982          "CallerID: %s\r\n"
01983          "CallerIDName: %s\r\n",
01984          pu->parkingexten, pu->chan->name, chan->name,
01985          S_OR(pu->chan->cid.cid_num, "<unknown>"),
01986          S_OR(pu->chan->cid.cid_name, "<unknown>")
01987          );
01988 
01989       free(pu);
01990    }
01991    /* JK02: it helps to answer the channel if not already up */
01992    if (chan->_state != AST_STATE_UP)
01993       ast_answer(chan);
01994 
01995    if (peer) {
01996       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
01997       
01998       if (!ast_strlen_zero(courtesytone)) {
01999          int error = 0;
02000          ast_indicate(peer, AST_CONTROL_UNHOLD);
02001          if (parkedplay == 0) {
02002             error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
02003          } else if (parkedplay == 1) {
02004             error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
02005          } else if (parkedplay == 2) {
02006             if (!ast_streamfile(chan, courtesytone, chan->language) &&
02007                   !ast_streamfile(peer, courtesytone, chan->language)) {
02008                /*! \todo XXX we would like to wait on both! */
02009                res = ast_waitstream(chan, "");
02010                if (res >= 0)
02011                   res = ast_waitstream(peer, "");
02012                if (res < 0)
02013                   error = 1;
02014             }
02015                         }
02016          if (error) {
02017             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
02018             ast_hangup(peer);
02019             ast_module_user_remove(u);
02020             return -1;
02021          }
02022       } else
02023          ast_indicate(peer, AST_CONTROL_UNHOLD); 
02024 
02025       res = ast_channel_make_compatible(chan, peer);
02026       if (res < 0) {
02027          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
02028          ast_hangup(peer);
02029          ast_module_user_remove(u);
02030          return -1;
02031       }
02032       /* This runs sorta backwards, since we give the incoming channel control, as if it
02033          were the person called. */
02034       if (option_verbose > 2) 
02035          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
02036 
02037       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
02038       ast_cdr_setdestchan(chan->cdr, peer->name);
02039       memset(&config, 0, sizeof(struct ast_bridge_config));
02040       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02041       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02042       res = ast_bridge_call(chan, peer, &config);
02043 
02044       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
02045       ast_cdr_setdestchan(chan->cdr, peer->name);
02046 
02047       /* Simulate the PBX hanging up */
02048       if (res != AST_PBX_NO_HANGUP_PEER)
02049          ast_hangup(peer);
02050       ast_module_user_remove(u);
02051       return res;
02052    } else {
02053       /*! \todo XXX Play a message XXX */
02054       if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
02055          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
02056       if (option_verbose > 2) 
02057          ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
02058       res = -1;
02059    }
02060 
02061    ast_module_user_remove(u);
02062 
02063    return res;
02064 }
02065 
02066 static int handle_showfeatures(int fd, int argc, char *argv[])
02067 {
02068    int i;
02069    struct ast_call_feature *feature;
02070    char format[] = "%-25s %-7s %-7s\n";
02071 
02072    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
02073    ast_cli(fd, format, "---------------", "-------", "-------");
02074 
02075    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
02076 
02077    ast_rwlock_rdlock(&features_lock);
02078    for (i = 0; i < FEATURES_COUNT; i++)
02079       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
02080    ast_rwlock_unlock(&features_lock);
02081 
02082    ast_cli(fd, "\n");
02083    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
02084    ast_cli(fd, format, "---------------", "-------", "-------");
02085    if (AST_LIST_EMPTY(&feature_list))
02086       ast_cli(fd, "(none)\n");
02087    else {
02088       AST_LIST_LOCK(&feature_list);
02089       AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
02090          ast_cli(fd, format, feature->sname, "no def", feature->exten); 
02091       AST_LIST_UNLOCK(&feature_list);
02092    }
02093    ast_cli(fd, "\nCall parking\n");
02094    ast_cli(fd, "------------\n");
02095    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
02096    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
02097    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
02098    ast_cli(fd,"\n");
02099    
02100    return RESULT_SUCCESS;
02101 }
02102 
02103 static char showfeatures_help[] =
02104 "Usage: feature list\n"
02105 "       Lists currently configured features.\n";
02106 
02107 static int handle_parkedcalls(int fd, int argc, char *argv[])
02108 {
02109    struct parkeduser *cur;
02110    int numparked = 0;
02111 
02112    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
02113       , "Context", "Extension", "Pri", "Timeout");
02114 
02115    ast_mutex_lock(&parking_lock);
02116 
02117    for (cur = parkinglot; cur; cur = cur->next) {
02118       ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
02119          ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
02120          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
02121 
02122       numparked++;
02123    }
02124    ast_mutex_unlock(&parking_lock);
02125    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
02126 
02127 
02128    return RESULT_SUCCESS;
02129 }
02130 
02131 static char showparked_help[] =
02132 "Usage: show parkedcalls\n"
02133 "       Lists currently parked calls.\n";
02134 
02135 static struct ast_cli_entry cli_show_features_deprecated = {
02136    { "show", "features", NULL },
02137    handle_showfeatures, NULL,
02138    NULL };
02139 
02140 static struct ast_cli_entry cli_features[] = {
02141    { { "feature", "show", NULL },
02142    handle_showfeatures, "Lists configured features",
02143    showfeatures_help, NULL, &cli_show_features_deprecated },
02144 
02145    { { "show", "parkedcalls", NULL },
02146    handle_parkedcalls, "Lists parked calls",
02147    showparked_help },
02148 };
02149 
02150 /*! \brief Dump lot status */
02151 static int manager_parking_status( struct mansession *s, const struct message *m)
02152 {
02153    struct parkeduser *cur;
02154    const char *id = astman_get_header(m, "ActionID");
02155    char idText[256] = "";
02156 
02157    if (!ast_strlen_zero(id))
02158       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02159 
02160    astman_send_ack(s, m, "Parked calls will follow");
02161 
02162    ast_mutex_lock(&parking_lock);
02163 
02164    for (cur = parkinglot; cur; cur = cur->next) {
02165       astman_append(s, "Event: ParkedCall\r\n"
02166          "Exten: %d\r\n"
02167          "Channel: %s\r\n"
02168          "From: %s\r\n"
02169          "Timeout: %ld\r\n"
02170          "CallerID: %s\r\n"
02171          "CallerIDName: %s\r\n"
02172          "%s"
02173          "\r\n",
02174          cur->parkingnum, cur->chan->name, cur->peername,
02175          (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
02176          S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
02177          S_OR(cur->chan->cid.cid_name, ""),
02178          idText);
02179    }
02180 
02181    astman_append(s,
02182       "Event: ParkedCallsComplete\r\n"
02183       "%s"
02184       "\r\n",idText);
02185 
02186    ast_mutex_unlock(&parking_lock);
02187 
02188    return RESULT_SUCCESS;
02189 }
02190 
02191 static char mandescr_park[] =
02192 "Description: Park a channel.\n"
02193 "Variables: (Names marked with * are required)\n"
02194 "  *Channel: Channel name to park\n"
02195 "  *Channel2: Channel to announce park info to (and return to if timeout)\n"
02196 "  Timeout: Number of milliseconds to wait before callback.\n";  
02197 
02198 static int manager_park(struct mansession *s, const struct message *m)
02199 {
02200    const char *channel = astman_get_header(m, "Channel");
02201    const char *channel2 = astman_get_header(m, "Channel2");
02202    const char *timeout = astman_get_header(m, "Timeout");
02203    char buf[BUFSIZ];
02204    int to = 0;
02205    int res = 0;
02206    int parkExt = 0;
02207    struct ast_channel *ch1, *ch2;
02208 
02209    if (ast_strlen_zero(channel)) {
02210       astman_send_error(s, m, "Channel not specified");
02211       return 0;
02212    }
02213 
02214    if (ast_strlen_zero(channel2)) {
02215       astman_send_error(s, m, "Channel2 not specified");
02216       return 0;
02217    }
02218 
02219    ch1 = ast_get_channel_by_name_locked(channel);
02220    if (!ch1) {
02221       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
02222       astman_send_error(s, m, buf);
02223       return 0;
02224    }
02225 
02226    ch2 = ast_get_channel_by_name_locked(channel2);
02227    if (!ch2) {
02228       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
02229       astman_send_error(s, m, buf);
02230       ast_channel_unlock(ch1);
02231       return 0;
02232    }
02233 
02234    if (!ast_strlen_zero(timeout)) {
02235       sscanf(timeout, "%d", &to);
02236    }
02237 
02238    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
02239    if (!res) {
02240       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
02241       astman_send_ack(s, m, "Park successful");
02242    } else {
02243       astman_send_error(s, m, "Park failure");
02244    }
02245 
02246    ast_channel_unlock(ch1);
02247    ast_channel_unlock(ch2);
02248 
02249    return 0;
02250 }
02251 
02252 
02253 int ast_pickup_call(struct ast_channel *chan)
02254 {
02255    struct ast_channel *cur = NULL;
02256    int res = -1;
02257 
02258    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02259       if (!cur->pbx && 
02260          (cur != chan) &&
02261          (chan->pickupgroup & cur->callgroup) &&
02262          ((cur->_state == AST_STATE_RINGING) ||
02263           (cur->_state == AST_STATE_RING))) {
02264             break;
02265       }
02266       ast_channel_unlock(cur);
02267    }
02268    if (cur) {
02269       if (option_debug)
02270          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02271       res = ast_answer(chan);
02272       if (res)
02273          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02274       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02275       if (res)
02276          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02277       res = ast_channel_masquerade(cur, chan);
02278       if (res)
02279          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02280       ast_channel_unlock(cur);
02281    } else   {
02282       if (option_debug)
02283          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02284    }
02285    return res;
02286 }
02287 
02288 /*! \brief Add parking hints for all defined parking lots */
02289 static void park_add_hints(char *context, int start, int stop)
02290 {
02291    int numext;
02292    char device[AST_MAX_EXTENSION];
02293    char exten[10];
02294 
02295    for (numext = start; numext <= stop; numext++) {
02296       snprintf(exten, sizeof(exten), "%d", numext);
02297       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
02298       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
02299    }
02300 }
02301 
02302 
02303 static int load_config(void) 
02304 {
02305    int start = 0, end = 0;
02306    int res;
02307    struct ast_context *con = NULL;
02308    struct ast_config *cfg = NULL;
02309    struct ast_variable *var = NULL;
02310    char old_parking_ext[AST_MAX_EXTENSION];
02311    char old_parking_con[AST_MAX_EXTENSION] = "";
02312 
02313    if (!ast_strlen_zero(parking_con)) {
02314       strcpy(old_parking_ext, parking_ext);
02315       strcpy(old_parking_con, parking_con);
02316    } 
02317 
02318    /* Reset to defaults */
02319    strcpy(parking_con, "parkedcalls");
02320    strcpy(parking_con_dial, "park-dial");
02321    strcpy(parking_ext, "700");
02322    strcpy(pickup_ext, "*8");
02323    strcpy(parkmohclass, "default");
02324    courtesytone[0] = '\0';
02325    strcpy(xfersound, "beep");
02326    strcpy(xferfailsound, "pbx-invalid");
02327    parking_start = 701;
02328    parking_stop = 750;
02329    parkfindnext = 0;
02330    adsipark = 0;
02331    parkaddhints = 0;
02332 
02333    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02334    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02335    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02336 
02337    cfg = ast_config_load("features.conf");
02338    if (!cfg) {
02339       ast_log(LOG_WARNING,"Could not load features.conf\n");
02340       return AST_MODULE_LOAD_DECLINE;
02341    }
02342    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
02343       if (!strcasecmp(var->name, "parkext")) {
02344          ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
02345       } else if (!strcasecmp(var->name, "context")) {
02346          ast_copy_string(parking_con, var->value, sizeof(parking_con));
02347       } else if (!strcasecmp(var->name, "parkingtime")) {
02348          if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
02349             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
02350             parkingtime = DEFAULT_PARK_TIME;
02351          } else
02352             parkingtime = parkingtime * 1000;
02353       } else if (!strcasecmp(var->name, "parkpos")) {
02354          if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
02355             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);
02356          } else {
02357             parking_start = start;
02358             parking_stop = end;
02359          }
02360       } else if (!strcasecmp(var->name, "findslot")) {
02361          parkfindnext = (!strcasecmp(var->value, "next"));
02362       } else if (!strcasecmp(var->name, "parkinghints")) {
02363          parkaddhints = ast_true(var->value);
02364       } else if (!strcasecmp(var->name, "adsipark")) {
02365          adsipark = ast_true(var->value);
02366       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
02367          if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
02368             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
02369             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02370          } else
02371             transferdigittimeout = transferdigittimeout * 1000;
02372       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
02373          if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
02374             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
02375             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02376          }
02377       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
02378          if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
02379             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
02380             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
02381          } else
02382             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
02383       } else if (!strcasecmp(var->name, "courtesytone")) {
02384          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
02385       }  else if (!strcasecmp(var->name, "parkedplay")) {
02386          if (!strcasecmp(var->value, "both"))
02387             parkedplay = 2;
02388          else if (!strcasecmp(var->value, "parked"))
02389             parkedplay = 1;
02390          else
02391             parkedplay = 0;
02392       } else if (!strcasecmp(var->name, "xfersound")) {
02393          ast_copy_string(xfersound, var->value, sizeof(xfersound));
02394       } else if (!strcasecmp(var->name, "xferfailsound")) {
02395          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
02396       } else if (!strcasecmp(var->name, "pickupexten")) {
02397          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
02398       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
02399          ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
02400       }
02401    }
02402 
02403    unmap_features();
02404    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
02405       if (remap_feature(var->name, var->value))
02406          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
02407    }
02408 
02409    /* Map a key combination to an application*/
02410    ast_unregister_features();
02411    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
02412       char *tmp_val = ast_strdupa(var->value);
02413       char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 
02414       struct ast_call_feature *feature;
02415 
02416       /* strsep() sets the argument to NULL if match not found, and it
02417        * is safe to use it with a NULL argument, so we don't check
02418        * between calls.
02419        */
02420       exten = strsep(&tmp_val,",");
02421       activatedby = strsep(&tmp_val,",");
02422       app = strsep(&tmp_val,",");
02423       app_args = strsep(&tmp_val,",");
02424       moh_class = strsep(&tmp_val,",");
02425 
02426       activateon = strsep(&activatedby, "/");   
02427 
02428       /*! \todo XXX var_name or app_args ? */
02429       if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
02430          ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
02431             app, exten, activateon, var->name);
02432          continue;
02433       }
02434 
02435       AST_LIST_LOCK(&feature_list);
02436       if ((feature = find_dynamic_feature(var->name))) {
02437          AST_LIST_UNLOCK(&feature_list);
02438          ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
02439          continue;
02440       }
02441       AST_LIST_UNLOCK(&feature_list);
02442             
02443       if (!(feature = ast_calloc(1, sizeof(*feature))))
02444          continue;               
02445 
02446       ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
02447       ast_copy_string(feature->app, app, FEATURE_APP_LEN);
02448       ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
02449       
02450       if (app_args) 
02451          ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
02452 
02453       if (moh_class)
02454          ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
02455          
02456       ast_copy_string(feature->exten, exten, sizeof(feature->exten));
02457       feature->operation = feature_exec_app;
02458       ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
02459 
02460       /* Allow caller and calle to be specified for backwards compatability */
02461       if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
02462          ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
02463       else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
02464          ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
02465       else {
02466          ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
02467             " must be 'self', or 'peer'\n", var->name);
02468          continue;
02469       }
02470 
02471       if (ast_strlen_zero(activatedby))
02472          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
02473       else if (!strcasecmp(activatedby, "caller"))
02474          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
02475       else if (!strcasecmp(activatedby, "callee"))
02476          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
02477       else if (!strcasecmp(activatedby, "both"))
02478          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
02479       else {
02480          ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
02481             " must be 'caller', or 'callee', or 'both'\n", var->name);
02482          continue;
02483       }
02484 
02485       ast_register_feature(feature);
02486          
02487       if (option_verbose >= 1)
02488          ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);  
02489    }   
02490    ast_config_destroy(cfg);
02491 
02492    /* Remove the old parking extension */
02493    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
02494       if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
02495             notify_metermaids(old_parking_ext, old_parking_con);
02496       if (option_debug)
02497          ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
02498    }
02499    
02500    if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
02501       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
02502       return -1;
02503    }
02504    res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
02505    if (parkaddhints)
02506       park_add_hints(parking_con, parking_start, parking_stop);
02507    if (!res)
02508       notify_metermaids(ast_parking_ext(), parking_con);
02509    return res;
02510 
02511 }
02512 
02513 static int reload(void)
02514 {
02515    return load_config();
02516 }
02517 
02518 static int load_module(void)
02519 {
02520    int res;
02521    
02522    memset(parking_ext, 0, sizeof(parking_ext));
02523    memset(parking_con, 0, sizeof(parking_con));
02524 
02525    if ((res = load_config()))
02526       return res;
02527    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
02528    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
02529    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
02530    if (!res)
02531       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
02532    if (!res) {
02533       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
02534       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
02535          "Park a channel", mandescr_park); 
02536    }
02537 
02538    res |= ast_devstate_prov_add("Park", metermaidstate);
02539 
02540    return res;
02541 }
02542 
02543 
02544 static int unload_module(void)
02545 {
02546    ast_module_user_hangup_all();
02547 
02548    ast_manager_unregister("ParkedCalls");
02549    ast_manager_unregister("Park");
02550    ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
02551    ast_unregister_application(parkcall);
02552    ast_devstate_prov_del("Park");
02553    return ast_unregister_application(parkedcall);
02554 }
02555 
02556 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Call Features Resource",
02557       .load = load_module,
02558       .unload = unload_module,
02559       .reload = reload,
02560           );

Generated on Tue Nov 4 13:20:21 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7