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

Generated on Mon May 14 04:43:00 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1