Fri Aug 24 02:22:17 2007

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

Generated on Fri Aug 24 02:22:17 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1