Wed Mar 4 19:58:13 2009

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

Generated on Wed Mar 4 19:58:13 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7