Mon Nov 24 15:34:20 2008

Asterisk developer's documentation


res_features.c

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

Generated on Mon Nov 24 15:34:20 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7