Sat Apr 12 07:12:27 2008

Asterisk developer's documentation


res_features.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * Copyright (C) 2004, Junghanns.NET GmbH
00015  *
00016  * Klaus-Peter Junghanns <kpj@junghanns.net>
00017  *
00018  * This program is free software, distributed under the terms of
00019  * the GNU General Public License Version 2. See the LICENSE file
00020  * at the top of the source tree.
00021  */
00022 
00023 /*! \file
00024  *
00025  * \brief Routines implementing call features as call pickup, parking and transfer
00026  *
00027  * \author Mark Spencer <markster@digium.com> 
00028  */
00029 
00030 #include "asterisk.h"
00031 
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 94793 $")
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/indications.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 static char *holdedcall = "HoldedCall";
00085 
00086 static int parkaddhints = 0;                               /*!< Add parking hints automatically */
00087 static int parkingtime = DEFAULT_PARK_TIME;                /*!< No more than 45 seconds parked before you do something with them */
00088 static char parking_con[AST_MAX_EXTENSION];                /*!< Context for which parking is made accessible */
00089 static char parking_con_dial[AST_MAX_EXTENSION];           /*!< Context for dialback for parking (KLUDGE) */
00090 static char parking_ext[AST_MAX_EXTENSION];                /*!< Extension you type to park the call */
00091 static char pickup_ext[AST_MAX_EXTENSION];                 /*!< Call pickup extension */
00092 static char parkmohclass[MAX_MUSICCLASS];                  /*!< Music class used for parking */
00093 static int parking_start;                                  /*!< First available extension for parking */
00094 static int parking_stop;                                   /*!< Last available extension for parking */
00095 
00096 static char courtesytone[256];                             /*!< Courtesy tone */
00097 static int parkedplay = 0;                                 /*!< Who to play the courtesy tone to */
00098 static char xfersound[256];                                /*!< Call transfer sound */
00099 static char xferfailsound[256];                            /*!< Call transfer failure sound */
00100 
00101 static int parking_offset;
00102 static int parkfindnext;
00103 
00104 static int adsipark;
00105 
00106 static int transferdigittimeout;
00107 static int featuredigittimeout;
00108 
00109 static int atxfernoanswertimeout;
00110 
00111 static char *registrar = "res_features";        /*!< Registrar for operations */
00112 
00113 /* module and CLI command definitions */
00114 static char *synopsis = "Answer a parked call";
00115 
00116 static char *descrip = "ParkedCall(exten):"
00117 "Used to connect to a parked call.  This application is always\n"
00118 "registered internally and does not need to be explicitly added\n"
00119 "into the dialplan, although you should include the 'parkedcalls'\n"
00120 "context.\n";
00121 
00122 static char *parkcall = "Park";
00123 
00124 static char *synopsis2 = "Park yourself";
00125 
00126 static char *descrip2 = "Park():"
00127 "Used to park yourself (typically in combination with a supervised\n"
00128 "transfer to know the parking space). This application is always\n"
00129 "registered internally and does not need to be explicitly added\n"
00130 "into the dialplan, although you should include the 'parkedcalls'\n"
00131 "context (or the context specified in features.conf).\n\n"
00132 "If you set the PARKINGEXTEN variable to an extension in your\n"
00133 "parking context, park() will park the call on that extension, unless\n"
00134 "it already exists. In that case, execution will continue at next\n"
00135 "priority.\n" ;
00136 
00137 static char *autoanswerlogin = "AutoanswerLogin";
00138 
00139 static char *synopsis3 = "Log in for autoanswer";
00140 
00141 static char *descrip3 = "AutoanswerLogin([context]|exten):"
00142 "Used to login to the autoanswer application for an extension.\n";
00143 
00144 static char *autoanswer = "Autoanswer";
00145 
00146 static char *synopsis4 = "Autoanswer a call";
00147 
00148 static char *descrip4 = "Autoanswer([context]|exten):"
00149 "Used to autoanswer a call for an extension.\n";
00150 
00151 static struct ast_app *monitor_app = NULL;
00152 static int monitor_ok = 1;
00153 
00154 struct parkeduser {
00155    struct ast_channel *chan;                   /*!< Parking channel */
00156    struct timeval start;                       /*!< Time the parking started */
00157    int parkingnum;                             /*!< Parking lot */
00158    char parkingexten[AST_MAX_EXTENSION];       /*!< If set beforehand, parking extension used for this call */
00159    char context[AST_MAX_CONTEXT];              /*!< Where to go if our parking time expires */
00160    char exten[AST_MAX_EXTENSION];
00161    int priority;
00162    int parkingtime;                            /*!< Maximum length in parking lot before return */
00163    int notquiteyet;
00164    char peername[1024];
00165    unsigned char moh_trys;
00166    struct parkeduser *next;
00167 };
00168 
00169 struct holdeduser {
00170    struct ast_channel *chan;
00171    struct timeval start;
00172    int parkingnum;
00173    int cref;
00174    int tei;
00175    /* Where to go if our parking time expires */
00176    char context[AST_MAX_EXTENSION];
00177    char exten[AST_MAX_EXTENSION];
00178    int priority;
00179    int parkingtime;
00180    char uniqueid[AST_MAX_UNIQUEID];
00181    char uniqueidpeer[AST_MAX_UNIQUEID];
00182    struct holdeduser *next;
00183 };
00184 
00185 /* auto answer user */
00186 struct aauser {
00187    struct ast_channel *chan;
00188    struct timeval start;
00189    /* waiting on this extension/context */
00190    char exten[AST_MAX_EXTENSION];
00191    char context[AST_MAX_EXTENSION];
00192    int priority;
00193    int notquiteyet;
00194    struct aauser *next;
00195 };
00196 
00197  
00198 static struct aauser *aalot;
00199 AST_MUTEX_DEFINE_STATIC(autoanswer_lock);
00200 static pthread_t autoanswer_thread;
00201 
00202 static struct parkeduser *parkinglot;
00203 
00204 static struct holdeduser *holdlist;
00205 
00206 AST_MUTEX_DEFINE_STATIC(parking_lock); /*!< protects all static variables above */
00207 
00208 AST_MUTEX_DEFINE_STATIC(holding_lock);
00209 
00210 static pthread_t parking_thread;
00211 
00212 static pthread_t holding_thread;
00213 
00214 char *ast_parking_ext(void)
00215 {
00216    return parking_ext;
00217 }
00218 
00219 char *ast_pickup_ext(void)
00220 {
00221    return pickup_ext;
00222 }
00223 
00224 struct ast_bridge_thread_obj 
00225 {
00226    struct ast_bridge_config bconfig;
00227    struct ast_channel *chan;
00228    struct ast_channel *peer;
00229 };
00230 
00231 
00232 
00233 /*! \brief store context, priority and extension */
00234 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
00235 {
00236    ast_copy_string(chan->context, context, sizeof(chan->context));
00237    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00238    chan->priority = pri;
00239 }
00240 
00241 static void check_goto_on_transfer(struct ast_channel *chan) 
00242 {
00243    struct ast_channel *xferchan;
00244    const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00245    char *x, *goto_on_transfer;
00246    struct ast_frame *f;
00247 
00248    if (ast_strlen_zero(val))
00249       return;
00250 
00251    goto_on_transfer = ast_strdupa(val);
00252 
00253    if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, chan->name)))
00254       return;
00255 
00256    for (x = goto_on_transfer; x && *x; x++) {
00257       if (*x == '^')
00258          *x = '|';
00259    }
00260    /* Make formats okay */
00261    xferchan->readformat = chan->readformat;
00262    xferchan->writeformat = chan->writeformat;
00263    ast_channel_masquerade(xferchan, chan);
00264    ast_parseable_goto(xferchan, goto_on_transfer);
00265    xferchan->_state = AST_STATE_UP;
00266    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00267    xferchan->_softhangup = 0;
00268    if ((f = ast_read(xferchan))) {
00269       ast_frfree(f);
00270       f = NULL;
00271       ast_pbx_start(xferchan);
00272    } else {
00273       ast_hangup(xferchan);
00274    }
00275 }
00276 
00277 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);
00278 
00279 
00280 static void *ast_bridge_call_thread(void *data) 
00281 {
00282    struct ast_bridge_thread_obj *tobj = data;
00283 
00284    tobj->chan->appl = "Transferred Call";
00285    tobj->chan->data = tobj->peer->name;
00286    tobj->peer->appl = "Transferred Call";
00287    tobj->peer->data = tobj->chan->name;
00288    if (tobj->chan->cdr) {
00289       ast_cdr_reset(tobj->chan->cdr, NULL);
00290       ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
00291    }
00292    if (tobj->peer->cdr) {
00293       ast_cdr_reset(tobj->peer->cdr, NULL);
00294       ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
00295    }
00296 
00297    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00298    ast_hangup(tobj->chan);
00299    ast_hangup(tobj->peer);
00300    bzero(tobj, sizeof(*tobj)); /*! \todo XXX for safety */
00301    free(tobj);
00302    return NULL;
00303 }
00304 
00305 static void ast_bridge_call_thread_launch(void *data) 
00306 {
00307    pthread_t thread;
00308    pthread_attr_t attr;
00309    struct sched_param sched;
00310 
00311    pthread_attr_init(&attr);
00312    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00313    ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00314    pthread_attr_destroy(&attr);
00315    memset(&sched, 0, sizeof(sched));
00316    pthread_setschedparam(thread, SCHED_RR, &sched);
00317 }
00318 
00319 static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
00320 {
00321    int res;
00322    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00323    char tmp[256];
00324    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00325 
00326    snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00327    message[0] = tmp;
00328    res = ast_adsi_load_session(chan, NULL, 0, 1);
00329    if (res == -1)
00330       return res;
00331    return ast_adsi_print(chan, message, justify, 1);
00332 }
00333 
00334 /*! \brief Notify metermaids that we've changed an extension */
00335 static void notify_metermaids(char *exten, char *context)
00336 {
00337    if (option_debug > 3)
00338       ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context);
00339 
00340    /* Send notification to devicestate subsystem */
00341    ast_device_state_changed("park:%s@%s", exten, context);
00342    return;
00343 }
00344 
00345 /*! \brief metermaids callback from devicestate.c */
00346 static int metermaidstate(const char *data)
00347 {
00348    int res = AST_DEVICE_INVALID;
00349    char *context = ast_strdupa(data);
00350    char *exten;
00351 
00352    exten = strsep(&context, "@");
00353    if (!context)
00354       return res;
00355    
00356    if (option_debug > 3)
00357       ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context);
00358 
00359    res = ast_exists_extension(NULL, context, exten, 1, NULL);
00360 
00361    if (!res)
00362       return AST_DEVICE_NOT_INUSE;
00363    else
00364       return AST_DEVICE_INUSE;
00365 }
00366 
00367 static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, char *orig_chan_name)
00368 {
00369    struct parkeduser *pu, *cur;
00370    int i, x = -1, parking_range;
00371    struct ast_context *con;
00372    const char *parkingexten;
00373    
00374    /* Allocate memory for parking data */
00375    if (!(pu = ast_calloc(1, sizeof(*pu)))) 
00376       return -1;
00377 
00378    /* Lock parking lot */
00379    ast_mutex_lock(&parking_lock);
00380    /* Check for channel variable PARKINGEXTEN */
00381    parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
00382    if (!ast_strlen_zero(parkingexten)) {
00383       if (ast_exists_extension(NULL, parking_con, parkingexten, 1, NULL)) {
00384          ast_mutex_unlock(&parking_lock);
00385          free(pu);
00386          ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
00387          return 0;   /* Continue execution if possible */
00388       }
00389       ast_copy_string(pu->parkingexten, parkingexten, sizeof(pu->parkingexten));
00390       x = atoi(parkingexten);
00391    } else {
00392       /* Select parking space within range */
00393       parking_range = parking_stop - parking_start+1;
00394       for (i = 0; i < parking_range; i++) {
00395          x = (i + parking_offset) % parking_range + parking_start;
00396          cur = parkinglot;
00397          while(cur) {
00398             if (cur->parkingnum == x) 
00399                break;
00400             cur = cur->next;
00401          }
00402          if (!cur)
00403             break;
00404       }
00405 
00406       if (!(i < parking_range)) {
00407          ast_log(LOG_WARNING, "No more parking spaces\n");
00408          free(pu);
00409          ast_mutex_unlock(&parking_lock);
00410          return -1;
00411       }
00412       /* Set pointer for next parking */
00413       if (parkfindnext) 
00414          parking_offset = x - parking_start + 1;
00415    }
00416    
00417    chan->appl = "Parked Call";
00418    chan->data = NULL; 
00419 
00420    pu->chan = chan;
00421    
00422    /* Put the parked channel on hold if we have two different channels */
00423    if (chan != peer) {
00424       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00425          S_OR(parkmohclass, NULL),
00426          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00427    }
00428    
00429    pu->start = ast_tvnow();
00430    pu->parkingnum = x;
00431    pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
00432    if (extout)
00433       *extout = x;
00434 
00435    if (peer) 
00436       ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
00437 
00438    /* Remember what had been dialed, so that if the parking
00439       expires, we try to come back to the same place */
00440    ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
00441    ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
00442    pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
00443    pu->next = parkinglot;
00444    parkinglot = pu;
00445 
00446    /* If parking a channel directly, don't quiet yet get parking running on it */
00447    if (peer == chan) 
00448       pu->notquiteyet = 1;
00449    ast_mutex_unlock(&parking_lock);
00450    /* Wake up the (presumably select()ing) thread */
00451    pthread_kill(parking_thread, SIGURG);
00452    if (option_verbose > 1) 
00453       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));
00454 
00455    if (pu->parkingnum != -1)
00456       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
00457    manager_event(EVENT_FLAG_CALL, "ParkedCall",
00458       "Exten: %s\r\n"
00459       "Channel: %s\r\n"
00460       "From: %s\r\n"
00461       "Timeout: %ld\r\n"
00462       "CallerID: %s\r\n"
00463       "CallerIDName: %s\r\n"
00464       "Uniqueid: %s\r\n",
00465       pu->parkingexten, pu->chan->name, peer ? peer->name : "",
00466       (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00467       S_OR(pu->chan->cid.cid_num, "<unknown>"),
00468       S_OR(pu->chan->cid.cid_name, "<unknown>"),
00469       pu->chan->uniqueid
00470       );
00471 
00472    if (peer && adsipark && ast_adsi_available(peer)) {
00473       adsi_announce_park(peer, pu->parkingexten);  /* Only supports parking numbers */
00474       ast_adsi_unload_session(peer);
00475    }
00476 
00477    con = ast_context_find(parking_con);
00478    if (!con) 
00479       con = ast_context_create(NULL, parking_con, registrar);
00480    if (!con)   /* Still no context? Bad */
00481       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00482    /* Tell the peer channel the number of the parking space */
00483    if (peer && ((pu->parkingnum != -1 && ast_strlen_zero(orig_chan_name)) || !strcasecmp(peer->name, orig_chan_name))) { /* Only say number if it's a number and the channel hasn't been masqueraded away */
00484       /* Make sure we don't start saying digits to the channel being parked */
00485       ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00486       ast_say_digits(peer, pu->parkingnum, "", peer->language);
00487       ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00488    }
00489    if (con) {
00490       if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar))
00491          notify_metermaids(pu->parkingexten, parking_con);
00492    }
00493    if (pu->notquiteyet) {
00494       /* Wake up parking thread if we're really done */
00495       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00496          S_OR(parkmohclass, NULL),
00497          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00498       pu->notquiteyet = 0;
00499       pthread_kill(parking_thread, SIGURG);
00500    }
00501    return 0;
00502 }
00503 
00504 /*! \brief Park a call 
00505    \note We put the user in the parking list, then wake up the parking thread to be sure it looks
00506    after these channels too */
00507 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
00508 {
00509    return park_call_full(chan, peer, timeout, extout, NULL);
00510 }
00511 
00512 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
00513 {
00514    struct ast_channel *chan;
00515    struct ast_frame *f;
00516 
00517    /* Make a new, fake channel that we'll use to masquerade in the real one */
00518    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00519       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00520       return -1;
00521    }
00522 
00523    /* Make formats okay */
00524    chan->readformat = rchan->readformat;
00525    chan->writeformat = rchan->writeformat;
00526    ast_channel_masquerade(chan, rchan);
00527 
00528    /* Setup the extensions and such */
00529    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00530 
00531    /* Make the masq execute */
00532    f = ast_read(chan);
00533    if (f)
00534       ast_frfree(f);
00535 
00536    ast_park_call(chan, peer, timeout, extout);
00537    return 0;
00538 }
00539 
00540 
00541 #define FEATURE_RETURN_HANGUP    -1
00542 #define FEATURE_RETURN_SUCCESSBREAK  0
00543 #define FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE
00544 #define FEATURE_RETURN_NO_HANGUP_PEER  AST_PBX_NO_HANGUP_PEER
00545 #define FEATURE_RETURN_PASSDIGITS    21
00546 #define FEATURE_RETURN_STOREDIGITS   22
00547 #define FEATURE_RETURN_SUCCESS       23
00548 #define FEATURE_RETURN_KEEPTRYING    24
00549 
00550 #define FEATURE_SENSE_CHAN (1 << 0)
00551 #define FEATURE_SENSE_PEER (1 << 1)
00552 
00553 /*! \brief
00554  * set caller and callee according to the direction
00555  */
00556 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
00557    struct ast_channel *peer, struct ast_channel *chan, int sense)
00558 {
00559    if (sense == FEATURE_SENSE_PEER) {
00560       *caller = peer;
00561       *callee = chan;
00562    } else {
00563       *callee = peer;
00564       *caller = chan;
00565    }
00566 }
00567 
00568 /*! \brief support routing for one touch call parking */
00569 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00570 {
00571    struct ast_channel *parker;
00572         struct ast_channel *parkee;
00573    int res = 0;
00574    struct ast_module_user *u;
00575 
00576    u = ast_module_user_add(chan);
00577 
00578    set_peers(&parker, &parkee, peer, chan, sense);
00579    /* Setup the exten/priority to be s/1 since we don't know
00580       where this call should return */
00581    strcpy(chan->exten, "s");
00582    chan->priority = 1;
00583    if (chan->_state != AST_STATE_UP)
00584       res = ast_answer(chan);
00585    if (!res)
00586       res = ast_safe_sleep(chan, 1000);
00587    if (!res)
00588       res = ast_park_call(parkee, parker, 0, NULL);
00589 
00590    ast_module_user_remove(u);
00591 
00592    if (!res) {
00593       if (sense == FEATURE_SENSE_CHAN)
00594          res = AST_PBX_NO_HANGUP_PEER;
00595       else
00596          res = AST_PBX_KEEPALIVE;
00597    }
00598    return res;
00599 
00600 }
00601 
00602 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00603 {
00604    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00605    int x = 0;
00606    size_t len;
00607    struct ast_channel *caller_chan, *callee_chan;
00608 
00609    if (!monitor_ok) {
00610       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00611       return -1;
00612    }
00613 
00614    if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
00615       monitor_ok = 0;
00616       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00617       return -1;
00618    }
00619 
00620    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00621 
00622    if (!ast_strlen_zero(courtesytone)) {
00623       if (ast_autoservice_start(callee_chan))
00624          return -1;
00625       if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) {
00626          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00627          ast_autoservice_stop(callee_chan);
00628          return -1;
00629       }
00630       if (ast_autoservice_stop(callee_chan))
00631          return -1;
00632    }
00633    
00634    if (callee_chan->monitor) {
00635       if (option_verbose > 3)
00636          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
00637       ast_monitor_stop(callee_chan, 1);
00638       return FEATURE_RETURN_SUCCESS;
00639    }
00640 
00641    if (caller_chan && callee_chan) {
00642       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00643       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00644 
00645       if (!touch_format)
00646          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00647 
00648       if (!touch_monitor)
00649          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00650    
00651       if (touch_monitor) {
00652          len = strlen(touch_monitor) + 50;
00653          args = alloca(len);
00654          touch_filename = alloca(len);
00655          snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
00656          snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
00657       } else {
00658          caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00659          callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00660          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00661          args = alloca(len);
00662          touch_filename = alloca(len);
00663          snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
00664          snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
00665       }
00666 
00667       for( x = 0; x < strlen(args); x++) {
00668          if (args[x] == '/')
00669             args[x] = '-';
00670       }
00671       
00672       if (option_verbose > 3)
00673          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
00674 
00675       pbx_exec(callee_chan, monitor_app, args);
00676       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00677       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00678    
00679       return FEATURE_RETURN_SUCCESS;
00680    }
00681    
00682    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
00683    return -1;
00684 }
00685 
00686 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00687 {
00688    if (option_verbose > 3)
00689       ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00690    return FEATURE_RETURN_HANGUP;
00691 }
00692 
00693 static int finishup(struct ast_channel *chan)
00694 {
00695         ast_indicate(chan, AST_CONTROL_UNHOLD);
00696   
00697         return ast_autoservice_stop(chan);
00698 }
00699 
00700 /*! \brief Find the context for the transfer */
00701 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
00702 {
00703         const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
00704         if (ast_strlen_zero(s))
00705                 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
00706         if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
00707                 s = transferer->macrocontext;
00708         if (ast_strlen_zero(s))
00709                 s = transferer->context;
00710         return s;  
00711 }
00712 
00713 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00714 {
00715    struct ast_channel *transferer;
00716    struct ast_channel *transferee;
00717    const char *transferer_real_context;
00718    char xferto[256];
00719    int res;
00720 
00721    set_peers(&transferer, &transferee, peer, chan, sense);
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 (!ast_park_call(transferee, transferer, 0, NULL)) { /* 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 
00753          return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER;
00754       } else {
00755          ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
00756       }
00757       /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
00758    } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00759       pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", transferee->name);
00760       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
00761       res=finishup(transferee);
00762       if (!transferer->cdr) {
00763          transferer->cdr=ast_cdr_alloc();
00764          if (transferer) {
00765             ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */
00766             ast_cdr_start(transferer->cdr);
00767          }
00768       }
00769       if (transferer->cdr) {
00770          ast_cdr_setdestchan(transferer->cdr, transferee->name);
00771          ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER","");
00772       }
00773       if (!transferee->pbx) {
00774          /* Doh!  Use our handy async_goto functions */
00775          if (option_verbose > 2) 
00776             ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
00777                         ,transferee->name, xferto, transferer_real_context);
00778          if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
00779             ast_log(LOG_WARNING, "Async goto failed :-(\n");
00780          res = -1;
00781       } else {
00782          /* Set the channel's new extension, since it exists, using transferer context */
00783          set_c_e_p(transferee, transferer_real_context, xferto, 0);
00784       }
00785       check_goto_on_transfer(transferer);
00786       return res;
00787    } else {
00788       if (option_verbose > 2) 
00789          ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
00790    }
00791    if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
00792       finishup(transferee);
00793       return -1;
00794    }
00795    ast_stopstream(transferer);
00796    res = finishup(transferee);
00797    if (res) {
00798       if (option_verbose > 1)
00799          ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
00800       return res;
00801    }
00802    return FEATURE_RETURN_SUCCESS;
00803 }
00804 
00805 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
00806 {
00807    if (ast_channel_make_compatible(c, newchan) < 0) {
00808       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
00809          c->name, newchan->name);
00810       ast_hangup(newchan);
00811       return -1;
00812    }
00813    return 0;
00814 }
00815 
00816 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00817 {
00818    struct ast_channel *transferer;
00819    struct ast_channel *transferee;
00820    const char *transferer_real_context;
00821    char xferto[256] = "";
00822    int res;
00823    int outstate=0;
00824    struct ast_channel *newchan;
00825    struct ast_channel *xferchan;
00826    struct ast_bridge_thread_obj *tobj;
00827    struct ast_bridge_config bconfig;
00828    struct ast_frame *f;
00829    int l;
00830 
00831    if (option_debug)
00832       ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
00833    set_peers(&transferer, &transferee, peer, chan, sense);
00834         transferer_real_context = real_ctx(transferer, transferee);
00835    /* Start autoservice on chan while we talk to the originator */
00836    ast_autoservice_start(transferee);
00837    ast_indicate(transferee, AST_CONTROL_HOLD);
00838    
00839    /* Transfer */
00840    res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00841    if (res < 0) {
00842       finishup(transferee);
00843       return res;
00844    }
00845    if (res > 0) /* If they've typed a digit already, handle it */
00846       xferto[0] = (char) res;
00847 
00848    /* this is specific of atxfer */
00849    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00850         if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
00851                 finishup(transferee);
00852                 return res;
00853         }
00854    if (res == 0) {
00855       ast_log(LOG_WARNING, "Did not read data.\n");
00856       finishup(transferee);
00857       if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00858          return -1;
00859       return FEATURE_RETURN_SUCCESS;
00860    }
00861 
00862    /* valid extension, res == 1 */
00863    if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00864       ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
00865       finishup(transferee);
00866       if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00867          return -1;
00868       return FEATURE_RETURN_SUCCESS;
00869    }
00870 
00871    l = strlen(xferto);
00872    snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);   /* append context */
00873    newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
00874       xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name);
00875    ast_indicate(transferer, -1);
00876    if (!newchan) {
00877       finishup(transferee);
00878       /* any reason besides user requested cancel and busy triggers the failed sound */
00879       if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
00880             ast_stream_and_wait(transferer, xferfailsound, transferer->language, ""))
00881          return -1;
00882       return FEATURE_RETURN_SUCCESS;
00883    }
00884 
00885    if (check_compat(transferer, newchan)) {
00886       /* we do mean transferee here, NOT transferer */
00887       finishup(transferee);
00888       return -1;
00889    }
00890    memset(&bconfig,0,sizeof(struct ast_bridge_config));
00891    ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
00892    ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
00893    res = ast_bridge_call(transferer, newchan, &bconfig);
00894    if (newchan->_softhangup || !transferer->_softhangup) {
00895       ast_hangup(newchan);
00896       if (ast_stream_and_wait(transferer, xfersound, transferer->language, ""))
00897          ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00898       finishup(transferee);
00899       transferer->_softhangup = 0;
00900       return FEATURE_RETURN_SUCCESS;
00901    }
00902    
00903    if (check_compat(transferee, newchan)) {
00904       finishup(transferee);
00905       return -1;
00906    }
00907 
00908    ast_indicate(transferee, AST_CONTROL_UNHOLD);
00909    
00910    if ((ast_autoservice_stop(transferee) < 0)
00911       || (ast_waitfordigit(transferee, 100) < 0)
00912       || (ast_waitfordigit(newchan, 100) < 0) 
00913       || ast_check_hangup(transferee) 
00914       || ast_check_hangup(newchan)) {
00915       ast_hangup(newchan);
00916       return -1;
00917    }
00918 
00919    xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
00920    if (!xferchan) {
00921       ast_hangup(newchan);
00922       return -1;
00923    }
00924    /* Make formats okay */
00925    xferchan->readformat = transferee->readformat;
00926    xferchan->writeformat = transferee->writeformat;
00927    ast_channel_masquerade(xferchan, transferee);
00928    ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
00929    xferchan->_state = AST_STATE_UP;
00930    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00931    xferchan->_softhangup = 0;
00932 
00933    if ((f = ast_read(xferchan)))
00934       ast_frfree(f);
00935 
00936    newchan->_state = AST_STATE_UP;
00937    ast_clear_flag(newchan, AST_FLAGS_ALL);   
00938    newchan->_softhangup = 0;
00939 
00940    tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
00941    if (!tobj) {
00942       ast_hangup(xferchan);
00943       ast_hangup(newchan);
00944       return -1;
00945    }
00946    tobj->chan = xferchan;
00947    tobj->peer = newchan;
00948    tobj->bconfig = *config;
00949 
00950    if (ast_stream_and_wait(newchan, xfersound, newchan->language, ""))
00951       ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00952    ast_bridge_call_thread_launch(tobj);
00953    return -1;  /* XXX meaning the channel is bridged ? */
00954 }
00955 
00956 
00957 /* add atxfer and automon as undefined so you can only use em if you configure them */
00958 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
00959 
00960 AST_RWLOCK_DEFINE_STATIC(features_lock);
00961 
00962 static struct ast_call_feature builtin_features[] = 
00963  {
00964    { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00965    { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00966    { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00967    { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00968    { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
00969 };
00970 
00971 
00972 static AST_LIST_HEAD_STATIC(feature_list,ast_call_feature);
00973 
00974 /*! \brief register new feature into feature_list*/
00975 void ast_register_feature(struct ast_call_feature *feature)
00976 {
00977    if (!feature) {
00978       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00979          return;
00980    }
00981   
00982    AST_LIST_LOCK(&feature_list);
00983    AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00984    AST_LIST_UNLOCK(&feature_list);
00985 
00986    if (option_verbose >= 2) 
00987       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00988 }
00989 
00990 /*! \brief unregister feature from feature_list */
00991 void ast_unregister_feature(struct ast_call_feature *feature)
00992 {
00993    if (!feature)
00994       return;
00995 
00996    AST_LIST_LOCK(&feature_list);
00997    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00998    AST_LIST_UNLOCK(&feature_list);
00999    free(feature);
01000 }
01001 
01002 /*! \brief Remove all features in the list */
01003 static void ast_unregister_features(void)
01004 {
01005    struct ast_call_feature *feature;
01006 
01007    AST_LIST_LOCK(&feature_list);
01008    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
01009       free(feature);
01010    AST_LIST_UNLOCK(&feature_list);
01011 }
01012 
01013 /*! \brief find a feature by name */
01014 static struct ast_call_feature *find_dynamic_feature(const char *name)
01015 {
01016    struct ast_call_feature *tmp;
01017 
01018    AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01019       if (!strcasecmp(tmp->sname, name))
01020          break;
01021    }
01022 
01023    return tmp;
01024 }
01025 
01026 /*! \brief exec an app by feature */
01027 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
01028 {
01029    struct ast_app *app;
01030    struct ast_call_feature *feature = data;
01031    struct ast_channel *work, *idle;
01032    int res;
01033 
01034    if (!feature) { /* shouldn't ever happen! */
01035       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01036       return -1; 
01037    }
01038 
01039    if (sense == FEATURE_SENSE_CHAN) {
01040       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01041          return FEATURE_RETURN_KEEPTRYING;
01042       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01043          work = chan;
01044          idle = peer;
01045       } else {
01046          work = peer;
01047          idle = chan;
01048       }
01049    } else {
01050       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01051          return FEATURE_RETURN_KEEPTRYING;
01052       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01053          work = peer;
01054          idle = chan;
01055       } else {
01056          work = chan;
01057          idle = peer;
01058       }
01059    }
01060 
01061    if (!(app = pbx_findapp(feature->app))) {
01062       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01063       return -2;
01064    }
01065 
01066    ast_autoservice_start(idle);
01067    
01068    if (!ast_strlen_zero(feature->moh_class))
01069       ast_moh_start(idle, feature->moh_class, NULL);
01070 
01071    res = pbx_exec(work, app, feature->app_args);
01072 
01073    if (!ast_strlen_zero(feature->moh_class))
01074       ast_moh_stop(idle);
01075 
01076    ast_autoservice_stop(idle);
01077 
01078    if (res == AST_PBX_KEEPALIVE)
01079       return FEATURE_RETURN_PBX_KEEPALIVE;
01080    else if (res == AST_PBX_NO_HANGUP_PEER)
01081       return FEATURE_RETURN_NO_HANGUP_PEER;
01082    else if (res)
01083       return FEATURE_RETURN_SUCCESSBREAK;
01084    
01085    return FEATURE_RETURN_SUCCESS;   /*! \todo XXX should probably return res */
01086 }
01087 
01088 static void unmap_features(void)
01089 {
01090    int x;
01091 
01092    ast_rwlock_wrlock(&features_lock);
01093    for (x = 0; x < FEATURES_COUNT; x++)
01094       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01095    ast_rwlock_unlock(&features_lock);
01096 }
01097 
01098 static int remap_feature(const char *name, const char *value)
01099 {
01100    int x, res = -1;
01101 
01102    ast_rwlock_wrlock(&features_lock);
01103    for (x = 0; x < FEATURES_COUNT; x++) {
01104       if (strcasecmp(builtin_features[x].sname, name))
01105          continue;
01106 
01107       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01108       res = 0;
01109       break;
01110    }
01111    ast_rwlock_unlock(&features_lock);
01112 
01113    return res;
01114 }
01115 
01116 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
01117 {
01118    int x;
01119    struct ast_flags features;
01120    int res = FEATURE_RETURN_PASSDIGITS;
01121    struct ast_call_feature *feature;
01122    const char *dynamic_features;
01123    char *tmp, *tok;
01124 
01125    if (sense == FEATURE_SENSE_CHAN) {
01126       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);   
01127       dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01128    } else {
01129       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);   
01130       dynamic_features = pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES");
01131    }
01132    if (option_debug > 2)
01133       ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d dynamic=%s\n", chan->name, peer->name, sense, features.flags, dynamic_features);
01134 
01135    ast_rwlock_rdlock(&features_lock);
01136    for (x = 0; x < FEATURES_COUNT; x++) {
01137       if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
01138           !ast_strlen_zero(builtin_features[x].exten)) {
01139          /* Feature is up for consideration */
01140          if (!strcmp(builtin_features[x].exten, code)) {
01141             res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
01142             break;
01143          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01144             if (res == FEATURE_RETURN_PASSDIGITS)
01145                res = FEATURE_RETURN_STOREDIGITS;
01146          }
01147       }
01148    }
01149    ast_rwlock_unlock(&features_lock);
01150 
01151    if (ast_strlen_zero(dynamic_features))
01152       return res;
01153 
01154    tmp = ast_strdupa(dynamic_features);
01155 
01156    while ((tok = strsep(&tmp, "#"))) {
01157       AST_LIST_LOCK(&feature_list); 
01158       if (!(feature = find_dynamic_feature(tok))) {
01159          AST_LIST_UNLOCK(&feature_list);
01160          continue;
01161       }
01162          
01163       /* Feature is up for consideration */
01164       if (!strcmp(feature->exten, code)) {
01165          if (option_verbose > 2)
01166             ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
01167          res = feature->operation(chan, peer, config, code, sense, feature);
01168          if (res != FEATURE_RETURN_KEEPTRYING) {
01169             AST_LIST_UNLOCK(&feature_list);
01170             break;
01171          }
01172          res = FEATURE_RETURN_PASSDIGITS;
01173       } else if (!strncmp(feature->exten, code, strlen(code)))
01174          res = FEATURE_RETURN_STOREDIGITS;
01175 
01176       AST_LIST_UNLOCK(&feature_list);
01177    }
01178    
01179    return res;
01180 }
01181 
01182 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
01183 {
01184    int x;
01185    
01186    ast_clear_flag(config, AST_FLAGS_ALL);
01187 
01188    ast_rwlock_rdlock(&features_lock);
01189    for (x = 0; x < FEATURES_COUNT; x++) {
01190       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
01191          continue;
01192 
01193       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01194          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01195 
01196       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01197          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01198    }
01199    ast_rwlock_unlock(&features_lock);
01200    
01201    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01202       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01203 
01204       if (dynamic_features) {
01205          char *tmp = ast_strdupa(dynamic_features);
01206          char *tok;
01207          struct ast_call_feature *feature;
01208 
01209          /* while we have a feature */
01210          while ((tok = strsep(&tmp, "#"))) {
01211             AST_LIST_LOCK(&feature_list);
01212             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01213                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01214                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01215                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01216                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01217             }
01218             AST_LIST_UNLOCK(&feature_list);
01219          }
01220       }
01221    }
01222 }
01223 
01224 /*! \todo XXX Check - this is very similar to the code in channel.c */
01225 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)
01226 {
01227    int state = 0;
01228    int cause = 0;
01229    int to;
01230    struct ast_channel *chan;
01231    struct ast_channel *monitor_chans[2];
01232    struct ast_channel *active_channel;
01233    int res = 0, ready = 0;
01234    
01235    if ((chan = ast_request(type, format, data, &cause))) {
01236       ast_set_callerid(chan, cid_num, cid_name, cid_num);
01237       ast_channel_inherit_variables(caller, chan); 
01238       pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
01239       if (!chan->cdr) {
01240          chan->cdr=ast_cdr_alloc();
01241          if (chan->cdr) {
01242             ast_cdr_init(chan->cdr, chan); /* initilize our channel's cdr */
01243             ast_cdr_start(chan->cdr);
01244          }
01245       }
01246          
01247       if (!ast_call(chan, data, timeout)) {
01248          struct timeval started;
01249          int x, len = 0;
01250          char *disconnect_code = NULL, *dialed_code = NULL;
01251 
01252          ast_indicate(caller, AST_CONTROL_RINGING);
01253          /* support dialing of the featuremap disconnect code while performing an attended tranfer */
01254          ast_rwlock_rdlock(&features_lock);
01255          for (x = 0; x < FEATURES_COUNT; x++) {
01256             if (strcasecmp(builtin_features[x].sname, "disconnect"))
01257                continue;
01258 
01259             disconnect_code = builtin_features[x].exten;
01260             len = strlen(disconnect_code) + 1;
01261             dialed_code = alloca(len);
01262             memset(dialed_code, 0, len);
01263             break;
01264          }
01265          ast_rwlock_unlock(&features_lock);
01266          x = 0;
01267          started = ast_tvnow();
01268          to = timeout;
01269          while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
01270             struct ast_frame *f = NULL;
01271 
01272             monitor_chans[0] = caller;
01273             monitor_chans[1] = chan;
01274             active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01275 
01276             /* see if the timeout has been violated */
01277             if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01278                state = AST_CONTROL_UNHOLD;
01279                ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01280                break; /*doh! timeout*/
01281             }
01282 
01283             if (!active_channel)
01284                continue;
01285 
01286             if (chan && (chan == active_channel)){
01287                f = ast_read(chan);
01288                if (f == NULL) { /*doh! where'd he go?*/
01289                   state = AST_CONTROL_HANGUP;
01290                   res = 0;
01291                   break;
01292                }
01293                
01294                if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01295                   if (f->subclass == AST_CONTROL_RINGING) {
01296                      state = f->subclass;
01297                      if (option_verbose > 2)
01298                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
01299                      ast_indicate(caller, AST_CONTROL_RINGING);
01300                   } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01301                      state = f->subclass;
01302                      if (option_verbose > 2)
01303                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
01304                      ast_indicate(caller, AST_CONTROL_BUSY);
01305                      ast_frfree(f);
01306                      f = NULL;
01307                      break;
01308                   } else if (f->subclass == AST_CONTROL_ANSWER) {
01309                      /* This is what we are hoping for */
01310                      state = f->subclass;
01311                      ast_frfree(f);
01312                      f = NULL;
01313                      ready=1;
01314                      break;
01315                   } else if (f->subclass != -1) {
01316                      ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01317                   }
01318                   /* else who cares */
01319                }
01320 
01321             } else if (caller && (active_channel == caller)) {
01322                f = ast_read(caller);
01323                if (f == NULL) { /*doh! where'd he go?*/
01324                   if (caller->_softhangup && !chan->_softhangup) {
01325                      /* make this a blind transfer */
01326                      ready = 1;
01327                      break;
01328                   }
01329                   state = AST_CONTROL_HANGUP;
01330                   res = 0;
01331                   break;
01332                }
01333                
01334                if (f->frametype == AST_FRAME_DTMF) {
01335                   dialed_code[x++] = f->subclass;
01336                   dialed_code[x] = '\0';
01337                   if (strlen(dialed_code) == len) {
01338                      x = 0;
01339                   } else if (x && strncmp(dialed_code, disconnect_code, x)) {
01340                      x = 0;
01341                      dialed_code[x] = '\0';
01342                   }
01343                   if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
01344                      /* Caller Canceled the call */
01345                      state = AST_CONTROL_UNHOLD;
01346                      ast_frfree(f);
01347                      f = NULL;
01348                      break;
01349                   }
01350                }
01351             }
01352             if (f)
01353                ast_frfree(f);
01354          } /* end while */
01355       } else
01356          ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
01357    } else {
01358       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01359       switch(cause) {
01360       case AST_CAUSE_BUSY:
01361          state = AST_CONTROL_BUSY;
01362          break;
01363       case AST_CAUSE_CONGESTION:
01364          state = AST_CONTROL_CONGESTION;
01365          break;
01366       }
01367    }
01368    
01369    ast_indicate(caller, -1);
01370    if (chan && ready) {
01371       if (chan->_state == AST_STATE_UP) 
01372          state = AST_CONTROL_ANSWER;
01373       res = 0;
01374    } else if(chan) {
01375       res = -1;
01376       ast_hangup(chan);
01377       chan = NULL;
01378    } else {
01379       res = -1;
01380    }
01381    
01382    if (outstate)
01383       *outstate = state;
01384 
01385    if (chan && res <= 0) {
01386       if (chan->cdr || (chan->cdr = ast_cdr_alloc())) {
01387          char tmp[256];
01388          ast_cdr_init(chan->cdr, chan);
01389          snprintf(tmp, 256, "%s/%s", type, (char *)data);
01390          ast_cdr_setapp(chan->cdr,"Dial",tmp);
01391          ast_cdr_update(chan);
01392          ast_cdr_start(chan->cdr);
01393          ast_cdr_end(chan->cdr);
01394          /* If the cause wasn't handled properly */
01395          if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
01396             ast_cdr_failed(chan->cdr);
01397       } else {
01398          ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
01399       }
01400    }
01401    
01402    return chan;
01403 }
01404 
01405 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
01406 {
01407    /* Copy voice back and forth between the two channels.  Give the peer
01408       the ability to transfer calls with '#<extension' syntax. */
01409    struct ast_frame *f;
01410    struct ast_channel *who;
01411    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01412    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01413    int res;
01414    int diff;
01415    int hasfeatures=0;
01416    int hadfeatures=0;
01417    struct ast_option_header *aoh;
01418    struct ast_bridge_config backup_config;
01419    struct ast_cdr *bridge_cdr;
01420 
01421    memset(&backup_config, 0, sizeof(backup_config));
01422 
01423    config->start_time = ast_tvnow();
01424 
01425    if (chan && peer) {
01426       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01427       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01428    } else if (chan)
01429       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01430 
01431    if (monitor_ok) {
01432       const char *monitor_exec;
01433       struct ast_channel *src = NULL;
01434       if (!monitor_app) { 
01435          if (!(monitor_app = pbx_findapp("Monitor")))
01436             monitor_ok=0;
01437       }
01438       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01439          src = chan;
01440       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01441          src = peer;
01442       if (monitor_app && src) {
01443          char *tmp = ast_strdupa(monitor_exec);
01444          pbx_exec(src, monitor_app, tmp);
01445       }
01446    }
01447    
01448    set_config_flags(chan, peer, config);
01449    config->firstpass = 1;
01450 
01451    /* Answer if need be */
01452    if (ast_answer(chan))
01453       return -1;
01454    peer->appl = "Bridged Call";
01455    peer->data = chan->name;
01456 
01457    /* copy the userfield from the B-leg to A-leg if applicable */
01458    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01459       char tmp[256];
01460       if (!ast_strlen_zero(chan->cdr->userfield)) {
01461          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01462          ast_cdr_appenduserfield(chan, tmp);
01463       } else
01464          ast_cdr_setuserfield(chan, peer->cdr->userfield);
01465       /* free the peer's cdr without ast_cdr_free complaining */
01466       free(peer->cdr);
01467       peer->cdr = NULL;
01468    }
01469 
01470    for (;;) {
01471       struct ast_channel *other; /* used later */
01472 
01473       res = ast_channel_bridge(chan, peer, config, &f, &who);
01474 
01475       if (config->feature_timer) {
01476          /* Update time limit for next pass */
01477          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
01478          config->feature_timer -= diff;
01479          if (hasfeatures) {
01480             /* Running on backup config, meaning a feature might be being
01481                activated, but that's no excuse to keep things going 
01482                indefinitely! */
01483             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01484                if (option_debug)
01485                   ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01486                config->feature_timer = 0;
01487                who = chan;
01488                if (f)
01489                   ast_frfree(f);
01490                f = NULL;
01491                res = 0;
01492             } else if (config->feature_timer <= 0) {
01493                /* Not *really* out of time, just out of time for
01494                   digits to come in for features. */
01495                if (option_debug)
01496                   ast_log(LOG_DEBUG, "Timed out for feature!\n");
01497                if (!ast_strlen_zero(peer_featurecode)) {
01498                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01499                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
01500                }
01501                if (!ast_strlen_zero(chan_featurecode)) {
01502                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01503                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
01504                }
01505                if (f)
01506                   ast_frfree(f);
01507                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01508                if (!hasfeatures) {
01509                   /* Restore original (possibly time modified) bridge config */
01510                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01511                   memset(&backup_config, 0, sizeof(backup_config));
01512                }
01513                hadfeatures = hasfeatures;
01514                /* Continue as we were */
01515                continue;
01516             } else if (!f) {
01517                /* The bridge returned without a frame and there is a feature in progress.
01518                 * However, we don't think the feature has quite yet timed out, so just
01519                 * go back into the bridge. */
01520                continue;
01521             }
01522          } else {
01523             if (config->feature_timer <=0) {
01524                /* We ran out of time */
01525                config->feature_timer = 0;
01526                who = chan;
01527                if (f)
01528                   ast_frfree(f);
01529                f = NULL;
01530                res = 0;
01531             }
01532          }
01533       }
01534       if (res < 0) {
01535          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
01536             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01537          return -1;
01538       }
01539       
01540       if (!f || (f->frametype == AST_FRAME_CONTROL &&
01541             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
01542                f->subclass == AST_CONTROL_CONGESTION ) ) ) {
01543          res = -1;
01544          break;
01545       }
01546       /* many things should be sent to the 'other' channel */
01547       other = (who == chan) ? peer : chan;
01548       if (f->frametype == AST_FRAME_CONTROL) {
01549          switch (f->subclass) {
01550          case AST_CONTROL_RINGING:
01551          case AST_CONTROL_FLASH:
01552          case -1:
01553             ast_indicate(other, f->subclass);
01554             break;
01555          case AST_CONTROL_HOLD:
01556          case AST_CONTROL_UNHOLD:
01557             ast_indicate_data(other, f->subclass, f->data, f->datalen);
01558             break;
01559          case AST_CONTROL_OPTION:
01560             aoh = f->data;
01561             /* Forward option Requests */
01562             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
01563                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
01564                   f->datalen - sizeof(struct ast_option_header), 0);
01565             }
01566             break;
01567          }
01568       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
01569          /* eat it */
01570       } else if (f->frametype == AST_FRAME_DTMF) {
01571          char *featurecode;
01572          int sense;
01573 
01574          hadfeatures = hasfeatures;
01575          /* This cannot overrun because the longest feature is one shorter than our buffer */
01576          if (who == chan) {
01577             sense = FEATURE_SENSE_CHAN;
01578             featurecode = chan_featurecode;
01579          } else  {
01580             sense = FEATURE_SENSE_PEER;
01581             featurecode = peer_featurecode;
01582          }
01583          /*! append the event to featurecode. we rely on the string being zero-filled, and
01584           * not overflowing it. 
01585           * \todo XXX how do we guarantee the latter ?
01586           */
01587          featurecode[strlen(featurecode)] = f->subclass;
01588          /* Get rid of the frame before we start doing "stuff" with the channels */
01589          ast_frfree(f);
01590          f = NULL;
01591          config->feature_timer = backup_config.feature_timer;
01592          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01593          switch(res) {
01594          case FEATURE_RETURN_PASSDIGITS:
01595             ast_dtmf_stream(other, who, featurecode, 0);
01596             /* Fall through */
01597          case FEATURE_RETURN_SUCCESS:
01598             memset(featurecode, 0, sizeof(chan_featurecode));
01599             break;
01600          }
01601          if (res >= FEATURE_RETURN_PASSDIGITS) {
01602             res = 0;
01603          } else 
01604             break;
01605          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01606          if (hadfeatures && !hasfeatures) {
01607             /* Restore backup */
01608             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01609             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01610          } else if (hasfeatures) {
01611             if (!hadfeatures) {
01612                /* Backup configuration */
01613                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01614                /* Setup temporary config options */
01615                config->play_warning = 0;
01616                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01617                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01618                config->warning_freq = 0;
01619                config->warning_sound = NULL;
01620                config->end_sound = NULL;
01621                config->start_sound = NULL;
01622                config->firstpass = 0;
01623             }
01624             config->start_time = ast_tvnow();
01625             config->feature_timer = featuredigittimeout;
01626             if (option_debug)
01627                ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01628          }
01629       }
01630       if (f)
01631          ast_frfree(f);
01632 
01633    }
01634 
01635    /* arrange the cdrs */
01636    bridge_cdr = ast_cdr_alloc();
01637    if (bridge_cdr) {
01638       if (chan->cdr && peer->cdr) { /* both of them? merge */
01639          ast_cdr_init(bridge_cdr,chan); /* seems more logicaller to use the  destination as a base, but, really, it's random */
01640          ast_cdr_start(bridge_cdr); /* now is the time to start */
01641 
01642          /* absorb the channel cdr */
01643          ast_cdr_merge(bridge_cdr, chan->cdr);
01644          if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
01645             ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01646          
01647          /* absorb the peer cdr */
01648          ast_cdr_merge(bridge_cdr, peer->cdr);
01649          if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
01650             ast_cdr_discard(peer->cdr); /* if locked cdrs are in peer, they are taken over in the merge */
01651          
01652          peer->cdr = NULL;
01653          chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01654       } else if (chan->cdr) {
01655          /* take the cdr from the channel - literally */
01656          ast_cdr_init(bridge_cdr,chan);
01657          /* absorb this data */
01658          ast_cdr_merge(bridge_cdr, chan->cdr);
01659          if (!ast_test_flag(chan->cdr, AST_CDR_FLAG_LOCKED))
01660             ast_cdr_discard(chan->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01661          chan->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01662       } else if (peer->cdr) {
01663          /* take the cdr from the peer - literally */
01664          ast_cdr_init(bridge_cdr,peer);
01665          /* absorb this data */
01666          ast_cdr_merge(bridge_cdr, peer->cdr);
01667          if (!ast_test_flag(peer->cdr, AST_CDR_FLAG_LOCKED))
01668             ast_cdr_discard(peer->cdr); /* if locked cdrs are in chan, they are taken over in the merge */
01669          peer->cdr = NULL;
01670          peer->cdr = bridge_cdr; /* make this available to the rest of the world via the chan while the call is in progress */
01671       } else {
01672          /* make up a new cdr */
01673          ast_cdr_init(bridge_cdr,chan); /* eh, just pick one of them */
01674          chan->cdr = bridge_cdr; /*  */
01675       }
01676       if (ast_strlen_zero(bridge_cdr->dstchannel)) {
01677          if (strcmp(bridge_cdr->channel, peer->name) != 0)
01678             ast_cdr_setdestchan(bridge_cdr, peer->name);
01679          else
01680             ast_cdr_setdestchan(bridge_cdr, chan->name);
01681       }
01682    }
01683    return res;
01684 }
01685 
01686 static void post_manager_event(const char *s, char *parkingexten, struct ast_channel *chan)
01687 {
01688    manager_event(EVENT_FLAG_CALL, s,
01689       "Exten: %s\r\n"
01690       "Channel: %s\r\n"
01691       "CallerID: %s\r\n"
01692       "CallerIDName: %s\r\n"
01693       "Uniqueid: %s\r\n\r\n",
01694       parkingexten, 
01695       chan->name,
01696       S_OR(chan->cid.cid_num, "<unknown>"),
01697       S_OR(chan->cid.cid_name, "<unknown>"),
01698       chan->uniqueid
01699       );
01700 }
01701 
01702 /*! \brief Take care of parked calls and unpark them if needed */
01703 static void *do_parking_thread(void *ignore)
01704 {
01705    fd_set rfds, efds;   /* results from previous select, to be preserved across loops. */
01706    FD_ZERO(&rfds);
01707    FD_ZERO(&efds);
01708 
01709    for (;;) {
01710       struct parkeduser *pu, *pl, *pt = NULL;
01711       int ms = -1;   /* select timeout, uninitialized */
01712       int max = -1;  /* max fd, none there yet */
01713       fd_set nrfds, nefds; /* args for the next select */
01714       FD_ZERO(&nrfds);
01715       FD_ZERO(&nefds);
01716 
01717       ast_mutex_lock(&parking_lock);
01718       pl = NULL;
01719       pu = parkinglot;
01720       /* navigate the list with prev-cur pointers to support removals */
01721       while (pu) {
01722          struct ast_channel *chan = pu->chan;   /* shorthand */
01723          int tms;        /* timeout for this item */
01724          int x;          /* fd index in channel */
01725          struct ast_context *con;
01726 
01727          if (pu->notquiteyet) { /* Pretend this one isn't here yet */
01728             pl = pu;
01729             pu = pu->next;
01730             continue;
01731          }
01732          tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
01733          if (tms > pu->parkingtime) {
01734             ast_indicate(chan, AST_CONTROL_UNHOLD);
01735             /* Get chan, exten from derived kludge */
01736             if (pu->peername[0]) {
01737                char *peername = ast_strdupa(pu->peername);
01738                char *cp = strrchr(peername, '-');
01739                if (cp) 
01740                   *cp = 0;
01741                con = ast_context_find(parking_con_dial);
01742                if (!con) {
01743                   con = ast_context_create(NULL, parking_con_dial, registrar);
01744                   if (!con)
01745                      ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
01746                }
01747                if (con) {
01748                   char returnexten[AST_MAX_EXTENSION];
01749                   snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
01750                   ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), ast_free, registrar);
01751                }
01752                set_c_e_p(chan, parking_con_dial, peername, 1);
01753             } else {
01754                /* They've been waiting too long, send them back to where they came.  Theoretically they
01755                   should have their original extensions and such, but we copy to be on the safe side */
01756                set_c_e_p(chan, pu->context, pu->exten, pu->priority);
01757             }
01758 
01759             post_manager_event("ParkedCallTimeOut", pu->parkingexten, chan);
01760 
01761             if (option_verbose > 1) 
01762                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);
01763             /* Start up the PBX, or hang them up */
01764             if (ast_pbx_start(chan))  {
01765                ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", chan->name);
01766                ast_hangup(chan);
01767             }
01768             /* And take them out of the parking lot */
01769             if (pl) 
01770                pl->next = pu->next;
01771             else
01772                parkinglot = pu->next;
01773             pt = pu;
01774             pu = pu->next;
01775             con = ast_context_find(parking_con);
01776             if (con) {
01777                if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
01778                   ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01779                else
01780                   notify_metermaids(pt->parkingexten, parking_con);
01781             } else
01782                ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01783             free(pt);
01784          } else { /* still within parking time, process descriptors */
01785             for (x = 0; x < AST_MAX_FDS; x++) {
01786                struct ast_frame *f;
01787 
01788                if (chan->fds[x] == -1 || (!FD_ISSET(chan->fds[x], &rfds) && !FD_ISSET(chan->fds[x], &efds)))
01789                   continue;   /* nothing on this descriptor */
01790 
01791                if (FD_ISSET(chan->fds[x], &efds))
01792                   ast_set_flag(chan, AST_FLAG_EXCEPTION);
01793                else
01794                   ast_clear_flag(chan, AST_FLAG_EXCEPTION);
01795                chan->fdno = x;
01796 
01797                /* See if they need servicing */
01798                f = ast_read(chan);
01799                if (!f || (f->frametype == AST_FRAME_CONTROL && f->subclass ==  AST_CONTROL_HANGUP)) {
01800                   if (f)
01801                      ast_frfree(f);
01802                   post_manager_event("ParkedCallGiveUp", pu->parkingexten, chan);
01803 
01804                   /* There's a problem, hang them up*/
01805                   if (option_verbose > 1) 
01806                      ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", chan->name);
01807                   ast_hangup(chan);
01808                   /* And take them out of the parking lot */
01809                   if (pl) 
01810                      pl->next = pu->next;
01811                   else
01812                      parkinglot = pu->next;
01813                   pt = pu;
01814                   pu = pu->next;
01815                   con = ast_context_find(parking_con);
01816                   if (con) {
01817                      if (ast_context_remove_extension2(con, pt->parkingexten, 1, NULL))
01818                         ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01819                   else
01820                      notify_metermaids(pt->parkingexten, parking_con);
01821                   } else
01822                      ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01823                   free(pt);
01824                   break;
01825                } else {
01826                   /*! \todo XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
01827                   ast_frfree(f);
01828                   if (pu->moh_trys < 3 && !chan->generatordata) {
01829                      if (option_debug)
01830                         ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
01831                      ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
01832                         S_OR(parkmohclass, NULL),
01833                         !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
01834                      pu->moh_trys++;
01835                   }
01836                   goto std;   /*! \todo XXX Ick: jumping into an else statement??? XXX */
01837                }
01838 
01839             } /* end for */
01840             if (x >= AST_MAX_FDS) {
01841 std:              for (x=0; x<AST_MAX_FDS; x++) {  /* mark fds for next round */
01842                   if (chan->fds[x] > -1) {
01843                      FD_SET(chan->fds[x], &nrfds);
01844                      FD_SET(chan->fds[x], &nefds);
01845                      if (chan->fds[x] > max)
01846                         max = chan->fds[x];
01847                   }
01848                }
01849                /* Keep track of our shortest wait */
01850                if (tms < ms || ms < 0)
01851                   ms = tms;
01852                pl = pu;
01853                pu = pu->next;
01854             }
01855          }
01856       } /* end while */
01857       ast_mutex_unlock(&parking_lock);
01858       rfds = nrfds;
01859       efds = nefds;
01860       {
01861          struct timeval tv = ast_samp2tv(ms, 1000);
01862          /* Wait for something to happen */
01863          ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
01864       }
01865       pthread_testcancel();
01866    }
01867    return NULL;   /* Never reached */
01868 }
01869 
01870 /*! \brief Park a call */
01871 static int park_call_exec(struct ast_channel *chan, void *data)
01872 {
01873    /* Cache the original channel name in case we get masqueraded in the middle
01874     * of a park--it is still theoretically possible for a transfer to happen before
01875     * we get here, but it is _really_ unlikely */
01876    char *orig_chan_name = ast_strdupa(chan->name);
01877    /* Data is unused at the moment but could contain a parking
01878       lot context eventually */
01879    int res = 0;
01880    struct ast_module_user *u;
01881 
01882    u = ast_module_user_add(chan);
01883 
01884    /* Setup the exten/priority to be s/1 since we don't know
01885       where this call should return */
01886    strcpy(chan->exten, "s");
01887    chan->priority = 1;
01888    /* Answer if call is not up */
01889    if (chan->_state != AST_STATE_UP)
01890       res = ast_answer(chan);
01891    /* Sleep to allow VoIP streams to settle down */
01892    if (!res)
01893       res = ast_safe_sleep(chan, 1000);
01894    /* Park the call */
01895    if (!res)
01896       res = park_call_full(chan, NULL, 0, NULL, orig_chan_name);
01897 
01898    ast_module_user_remove(u);
01899 
01900    return !res ? AST_PBX_KEEPALIVE : res;
01901 }
01902 
01903 /*! \brief Pickup parked call */
01904 static int park_exec(struct ast_channel *chan, void *data)
01905 {
01906    int res = 0;
01907    struct ast_module_user *u;
01908    struct ast_channel *peer=NULL;
01909    struct parkeduser *pu, *pl=NULL;
01910    struct ast_context *con;
01911 
01912    int park;
01913    struct ast_bridge_config config;
01914 
01915    if (!data) {
01916       ast_log(LOG_WARNING, "Parkedcall requires an argument (extension number)\n");
01917       return -1;
01918    }
01919    
01920    u = ast_module_user_add(chan);
01921 
01922    park = atoi((char *)data);
01923    ast_mutex_lock(&parking_lock);
01924    pu = parkinglot;
01925    while(pu) {
01926       if (pu->parkingnum == park) {
01927          if (pl)
01928             pl->next = pu->next;
01929          else
01930             parkinglot = pu->next;
01931          break;
01932       }
01933       pl = pu;
01934       pu = pu->next;
01935    }
01936    ast_mutex_unlock(&parking_lock);
01937    if (pu) {
01938       peer = pu->chan;
01939       con = ast_context_find(parking_con);
01940       if (con) {
01941          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL))
01942             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01943          else
01944             notify_metermaids(pu->parkingexten, parking_con);
01945       } else
01946          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01947 
01948       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
01949          "Exten: %s\r\n"
01950          "Channel: %s\r\n"
01951          "From: %s\r\n"
01952          "CallerID: %s\r\n"
01953          "CallerIDName: %s\r\n"
01954          "Uniqueid: %s\r\n",
01955          pu->parkingexten, pu->chan->name, chan->name,
01956          S_OR(pu->chan->cid.cid_num, "<unknown>"),
01957          S_OR(pu->chan->cid.cid_name, "<unknown>"),
01958          pu->chan->uniqueid
01959          );
01960 
01961       free(pu);
01962    }
01963    /* JK02: it helps to answer the channel if not already up */
01964    if (chan->_state != AST_STATE_UP)
01965       ast_answer(chan);
01966 
01967    if (peer) {
01968       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
01969       
01970       if (!ast_strlen_zero(courtesytone)) {
01971          int error = 0;
01972          ast_indicate(peer, AST_CONTROL_UNHOLD);
01973          if (parkedplay == 0) {
01974             error = ast_stream_and_wait(chan, courtesytone, chan->language, "");
01975          } else if (parkedplay == 1) {
01976             error = ast_stream_and_wait(peer, courtesytone, chan->language, "");
01977          } else if (parkedplay == 2) {
01978             if (!ast_streamfile(chan, courtesytone, chan->language) &&
01979                   !ast_streamfile(peer, courtesytone, chan->language)) {
01980                /*! \todo XXX we would like to wait on both! */
01981                res = ast_waitstream(chan, "");
01982                if (res >= 0)
01983                   res = ast_waitstream(peer, "");
01984                if (res < 0)
01985                   error = 1;
01986             }
01987                         }
01988          if (error) {
01989             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01990             ast_hangup(peer);
01991             ast_module_user_remove(u);
01992             return -1;
01993          }
01994       } else
01995          ast_indicate(peer, AST_CONTROL_UNHOLD); 
01996 
01997       res = ast_channel_make_compatible(chan, peer);
01998       if (res < 0) {
01999          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
02000          ast_hangup(peer);
02001          ast_module_user_remove(u);
02002          return -1;
02003       }
02004       /* This runs sorta backwards, since we give the incoming channel control, as if it
02005          were the person called. */
02006       if (option_verbose > 2) 
02007          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
02008 
02009       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
02010       ast_cdr_setdestchan(chan->cdr, peer->name);
02011       memset(&config, 0, sizeof(struct ast_bridge_config));
02012       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02013       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02014       res = ast_bridge_call(chan, peer, &config);
02015 
02016       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
02017       ast_cdr_setdestchan(chan->cdr, peer->name);
02018 
02019       /* Simulate the PBX hanging up */
02020       if (res != AST_PBX_NO_HANGUP_PEER)
02021          ast_hangup(peer);
02022       ast_module_user_remove(u);
02023       return res;
02024    } else {
02025       /*! \todo XXX Play a message XXX */
02026       if (ast_stream_and_wait(chan, "pbx-invalidpark", chan->language, ""))
02027          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
02028       if (option_verbose > 2) 
02029          ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
02030       res = -1;
02031    }
02032 
02033    ast_module_user_remove(u);
02034 
02035    return res;
02036 }
02037 
02038 int ast_hold_call(struct ast_channel *chan, struct ast_channel *peer)
02039 {
02040    /* We put the user in the parking list, then wake up the parking thread to be sure it looks
02041       after these channels too */
02042    struct holdeduser *pu;
02043    pu = malloc(sizeof(struct holdeduser));
02044    if (pu) {
02045       memset(pu, 0, sizeof(pu));
02046       ast_mutex_lock(&holding_lock);
02047       chan->appl = "Holded Call";
02048       chan->data = NULL; 
02049 
02050       pu->chan = chan;
02051       strncpy(pu->uniqueid, chan->uniqueid, sizeof(pu->uniqueid));
02052       strncpy(pu->uniqueidpeer, peer->uniqueid, sizeof(pu->uniqueidpeer));
02053       /* Start music on hold */
02054       ast_moh_start(pu->chan, NULL, NULL);
02055       gettimeofday(&pu->start, NULL);
02056       pu->next = holdlist;
02057       holdlist = pu;
02058       ast_mutex_unlock(&holding_lock);
02059       /* Wake up the (presumably select()ing) thread */
02060       pthread_kill(holding_thread, SIGURG);
02061 
02062       manager_event(EVENT_FLAG_CALL, "HoldedCall",
02063                          "Channel1: %s\r\n"
02064                          "Channel2: %s\r\n"
02065                       "Uniqueid1: %s\r\n"
02066                       "Uniqueid2: %s\r\n"
02067                              ,pu->chan->name, peer->name, pu->chan->uniqueid, peer->uniqueid);
02068 
02069    } else {
02070       ast_log(LOG_WARNING, "Out of memory\n");
02071       return -1;
02072    }
02073    return 0;
02074 }
02075 
02076 int ast_masq_hold_call(struct ast_channel *rchan, struct ast_channel *peer)
02077 {
02078    struct ast_channel *chan;
02079    struct ast_frame *f;
02080    /* Make a new, fake channel that we'll use to masquerade in the real one */
02081    chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Onhold/%s",rchan->name);
02082    if (chan) {
02083       /* Let us keep track of the channel name */
02084       ast_string_field_build(chan, name, "Onhold/%s",rchan->name);
02085       /* Make formats okay */
02086       chan->readformat = rchan->readformat;
02087       chan->writeformat = rchan->writeformat;
02088       ast_channel_masquerade(chan, rchan);
02089       /* Setup the extensions and such */
02090       strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
02091       strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
02092       chan->priority = rchan->priority;
02093       /* this might be dirty, but we need to preserve the uniqueid */
02094       ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid);
02095       /* Make the masq execute */
02096       f = ast_read(chan);
02097       if (f)
02098          ast_frfree(f);
02099       ast_hold_call(chan, peer);
02100       return -1;
02101    } else {
02102       ast_log(LOG_WARNING, "Unable to create holded channel\n");
02103       return -1;
02104    }
02105    return 0;
02106 }
02107 
02108 int ast_retrieve_call(struct ast_channel *chan, char *uniqueid)
02109 {
02110    int res=-1, dres=-1;
02111    struct ast_channel *peer=NULL;
02112    struct ast_bridge_config config;
02113 
02114    peer = ast_get_holded_call(uniqueid);
02115 
02116    /* JK02: it helps to answer the channel if not already up */
02117    if (chan->_state != AST_STATE_UP) {
02118       ast_answer(chan);
02119    }
02120 
02121    if (peer) {
02122       ast_mutex_unlock(&peer->lock);
02123       ast_moh_stop(peer);
02124       res = ast_channel_make_compatible(chan, peer);
02125       if (res < 0) {
02126          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
02127          ast_hangup(peer);
02128          return -1;
02129       }
02130       /* This runs sorta backwards, since we give the incoming channel control, as if it
02131          were the person called. */
02132       if (option_verbose > 2) 
02133          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to holded call %s\n", chan->name, peer->name);
02134 
02135       memset(&config,0,sizeof(struct ast_bridge_config));
02136       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02137       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02138       config.timelimit = 0;
02139       config.play_warning = 0;
02140       config.warning_freq = 0;
02141       config.warning_sound=NULL;
02142       res = ast_bridge_call(chan,peer,&config);
02143 
02144       /* Simulate the PBX hanging up */
02145       if (res != AST_PBX_NO_HANGUP_PEER)
02146          ast_hangup(peer);
02147       return res;
02148    } else {
02149       /* XXX Play a message XXX */
02150      dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
02151      if (!dres)
02152        dres = ast_waitstream(chan, "");
02153      else {
02154        ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
02155        dres = 0;
02156      }
02157    }
02158    return res;
02159 }
02160 
02161 int ast_retrieve_call_to_death(char *uniqueid)
02162 {
02163    int res=-1;
02164    struct ast_channel *peer=NULL;
02165 
02166    peer = ast_get_holded_call(uniqueid);
02167 
02168    if (peer) {
02169       res=0;
02170       if (option_verbose > 2) 
02171          ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name);
02172       ast_mutex_unlock(&peer->lock);
02173       ast_hangup(peer);
02174    } else {
02175       ast_log(LOG_WARNING, "Could not find channel with uniqueid %s to retrieve.\n", uniqueid);
02176    }
02177    return res;
02178 }
02179 
02180 struct ast_channel *ast_get_holded_call(char *uniqueid)
02181 {
02182    int res=-1;
02183    struct ast_channel *peer=NULL;
02184    struct holdeduser *pu, *pl=NULL;
02185 
02186    ast_mutex_lock(&holding_lock);
02187    pu = holdlist;
02188    while(pu) {
02189       if (!strncmp(uniqueid,pu->uniqueid,sizeof(pu->uniqueid))) {
02190          if (pl)
02191             pl->next = pu->next;
02192          else
02193             holdlist = pu->next; 
02194          break;
02195       }
02196       pl = pu;
02197       pu = pu->next;
02198    }
02199    ast_mutex_unlock(&holding_lock);
02200    if (pu) {
02201       peer = ast_get_channel_by_uniqueid_locked(pu->uniqueid);
02202       free(pu);
02203       if (peer) {
02204           res=0;
02205           if (option_verbose > 2) 
02206          ast_verbose(VERBOSE_PREFIX_3 "Channel %s removed from hold.\n", peer->name);
02207           ast_moh_stop(peer);
02208           return peer;
02209       } else {
02210           if (option_verbose > 2) 
02211          ast_verbose(VERBOSE_PREFIX_3 "Could not find channel with uniqueid %s.\n", uniqueid);
02212           return NULL;
02213       }
02214    } else {
02215       ast_log(LOG_WARNING, "Could not find held channel with uniqueid %s to retrieve.\n", uniqueid);
02216    }
02217    return NULL;
02218 }
02219 
02220 /* this is our autmagically service thread that keeps channels onhold happy */
02221 static void *do_holding_thread(void *ignore)
02222 {
02223    int ms, tms, max;
02224    struct holdeduser *pu, *pl, *pt = NULL;
02225    struct timeval tv;
02226    struct ast_frame *f;
02227    int x;
02228    fd_set rfds, efds;
02229    fd_set nrfds, nefds;
02230    FD_ZERO(&rfds);
02231    FD_ZERO(&efds);
02232    for (;;) {
02233       ms = -1;
02234       max = -1;
02235       ast_mutex_lock(&holding_lock);
02236       pl = NULL;
02237       pu = holdlist;
02238       gettimeofday(&tv, NULL);
02239       FD_ZERO(&nrfds);
02240       FD_ZERO(&nefds);
02241       while(pu) {
02242          tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
02243             for (x=0;x<AST_MAX_FDS;x++) {
02244                if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
02245                   if (FD_ISSET(pu->chan->fds[x], &efds))
02246                      ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
02247                   else
02248                      ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
02249                   pu->chan->fdno = x;
02250                   /* See if they need servicing */
02251                   f = ast_read(pu->chan);
02252                   if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
02253                      /* There's a problem, hang them up*/
02254                      if (option_verbose > 1) 
02255                         ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being onhold\n", pu->chan->name);
02256                      ast_hangup(pu->chan);
02257                      /* find the corresponding channel and hang them up too! */
02258                      /* but only if it is not bridged yet! */
02259                      /* And take them out of the parking lot */
02260                      if (pl) 
02261                         pl->next = pu->next;
02262                      else
02263                         holdlist = pu->next;
02264                      pt = pu;
02265                      pu = pu->next;
02266                      free(pt);
02267                      break;
02268                   } else {
02269                      /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
02270                      ast_frfree(f);
02271                      goto std;   /* XXX Ick: jumping into an else statement??? XXX */
02272                   }
02273                }
02274             }
02275             if (x >= AST_MAX_FDS) {
02276 std:              for (x=0;x<AST_MAX_FDS;x++) {
02277                   /* Keep this one for next one */
02278                   if (pu->chan->fds[x] > -1) {
02279                      FD_SET(pu->chan->fds[x], &nrfds);
02280                      FD_SET(pu->chan->fds[x], &nefds);
02281                      if (pu->chan->fds[x] > max)
02282                         max = pu->chan->fds[x];
02283                   }
02284                }
02285                /* Keep track of our longest wait */
02286                if ((tms < ms) || (ms < 0))
02287                   ms = tms;
02288                pl = pu;
02289                pu = pu->next;
02290             }
02291       }
02292       ast_mutex_unlock(&holding_lock);
02293       rfds = nrfds;
02294       efds = nefds;
02295       tv.tv_sec = ms / 1000;
02296       tv.tv_usec = (ms % 1000) * 1000;
02297       /* Wait for something to happen */
02298       ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
02299       pthread_testcancel();
02300    }
02301    return NULL;   /* Never reached */
02302 }
02303 
02304 static int retrieve_call_exec(struct ast_channel *chan, void *data) {
02305    int res=0;
02306    struct ast_module_user *u;
02307    char *uniqueid = (char *)data;
02308    u = ast_module_user_add(chan);
02309        res = ast_retrieve_call(chan, uniqueid);
02310    ast_module_user_remove(u);
02311    return res;
02312 }
02313 
02314 static int handle_showfeatures(int fd, int argc, char *argv[])
02315 {
02316    int i;
02317    struct ast_call_feature *feature;
02318    char format[] = "%-25s %-7s %-7s\n";
02319 
02320    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
02321    ast_cli(fd, format, "---------------", "-------", "-------");
02322 
02323    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
02324 
02325    ast_rwlock_rdlock(&features_lock);
02326    for (i = 0; i < FEATURES_COUNT; i++)
02327       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
02328    ast_rwlock_unlock(&features_lock);
02329 
02330    ast_cli(fd, "\n");
02331    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
02332    ast_cli(fd, format, "---------------", "-------", "-------");
02333    if (AST_LIST_EMPTY(&feature_list))
02334       ast_cli(fd, "(none)\n");
02335    else {
02336       AST_LIST_LOCK(&feature_list);
02337       AST_LIST_TRAVERSE(&feature_list, feature, feature_entry)
02338          ast_cli(fd, format, feature->sname, "no def", feature->exten); 
02339       AST_LIST_UNLOCK(&feature_list);
02340    }
02341    ast_cli(fd, "\nCall parking\n");
02342    ast_cli(fd, "------------\n");
02343    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
02344    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
02345    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
02346    ast_cli(fd,"\n");
02347    
02348    return RESULT_SUCCESS;
02349 }
02350 
02351 static char showfeatures_help[] =
02352 "Usage: feature list\n"
02353 "       Lists currently configured features.\n";
02354 
02355 static int handle_parkedcalls(int fd, int argc, char *argv[])
02356 {
02357    struct parkeduser *cur;
02358    int numparked = 0;
02359 
02360    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
02361       , "Context", "Extension", "Pri", "Timeout");
02362 
02363    ast_mutex_lock(&parking_lock);
02364 
02365    for (cur = parkinglot; cur; cur = cur->next) {
02366       ast_cli(fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
02367          ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
02368          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
02369 
02370       numparked++;
02371    }
02372    ast_mutex_unlock(&parking_lock);
02373    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
02374 
02375 
02376    return RESULT_SUCCESS;
02377 }
02378 
02379 static char showparked_help[] =
02380 "Usage: show parkedcalls\n"
02381 "       Lists currently parked calls.\n";
02382 
02383 static struct ast_cli_entry cli_show_features_deprecated = {
02384    { "show", "features", NULL },
02385    handle_showfeatures, NULL,
02386    NULL };
02387 
02388 static char showautoanswer_help[] =
02389 "Usage: show autoanswer\n"
02390 "       Lists currently logged in autoanswer users.\n";
02391 
02392 
02393 /*! \brief Dump lot status */
02394 static int manager_parking_status( struct mansession *s, const struct message *m)
02395 {
02396    struct parkeduser *cur;
02397    const char *id = astman_get_header(m, "ActionID");
02398    char idText[256] = "";
02399 
02400    if (!ast_strlen_zero(id))
02401       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
02402 
02403    astman_send_ack(s, m, "Parked calls will follow");
02404 
02405    ast_mutex_lock(&parking_lock);
02406 
02407    for (cur = parkinglot; cur; cur = cur->next) {
02408       astman_append(s, "Event: ParkedCall\r\n"
02409          "Exten: %d\r\n"
02410          "Channel: %s\r\n"
02411          "From: %s\r\n"
02412          "Timeout: %ld\r\n"
02413          "CallerID: %s\r\n"
02414          "CallerIDName: %s\r\n"
02415          "Unqiueid: %s\r\n\r\n"
02416          "%s"
02417          "\r\n",
02418          cur->parkingnum, cur->chan->name, cur->peername,
02419          (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
02420          S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
02421          S_OR(cur->chan->cid.cid_name, ""), cur->chan->uniqueid,
02422          idText);
02423    }
02424 
02425    astman_append(s,
02426       "Event: ParkedCallsComplete\r\n"
02427       "%s"
02428       "\r\n",idText);
02429 
02430    ast_mutex_unlock(&parking_lock);
02431 
02432    return RESULT_SUCCESS;
02433 }
02434 
02435 static char mandescr_park[] =
02436 "Description: Park a channel.\n"
02437 "Variables: (Names marked with * are required)\n"
02438 "  *Channel: Channel name to park\n"
02439 "  *Channel2: Channel to announce park info to (and return to if timeout)\n"
02440 "  Timeout: Number of milliseconds to wait before callback.\n";  
02441 
02442 static int manager_park(struct mansession *s, const struct message *m)
02443 {
02444    const char *channel = astman_get_header(m, "Channel");
02445    const char *channel2 = astman_get_header(m, "Channel2");
02446    const char *timeout = astman_get_header(m, "Timeout");
02447    char buf[BUFSIZ];
02448    int to = 0;
02449    int res = 0;
02450    int parkExt = 0;
02451    struct ast_channel *ch1, *ch2;
02452 
02453    if (ast_strlen_zero(channel)) {
02454       astman_send_error(s, m, "Channel not specified");
02455       return 0;
02456    }
02457 
02458    if (ast_strlen_zero(channel2)) {
02459       astman_send_error(s, m, "Channel2 not specified");
02460       return 0;
02461    }
02462 
02463    ch1 = ast_get_channel_by_name_locked(channel);
02464    if (!ch1) {
02465       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
02466       astman_send_error(s, m, buf);
02467       return 0;
02468    }
02469 
02470    ch2 = ast_get_channel_by_name_locked(channel2);
02471    if (!ch2) {
02472       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
02473       astman_send_error(s, m, buf);
02474       ast_channel_unlock(ch1);
02475       return 0;
02476    }
02477 
02478    if (!ast_strlen_zero(timeout)) {
02479       sscanf(timeout, "%d", &to);
02480    }
02481 
02482    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
02483    if (!res) {
02484       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
02485       astman_send_ack(s, m, "Park successful");
02486    } else {
02487       astman_send_error(s, m, "Park failure");
02488    }
02489 
02490    ast_channel_unlock(ch1);
02491    ast_channel_unlock(ch2);
02492 
02493    return 0;
02494 }
02495 
02496 static int handle_autoanswer(int fd, int argc, char *argv[])
02497 {
02498    struct aauser *cur;
02499 
02500    ast_cli(fd, "%25s %10s %15s \n", "Channel"
02501       , "Extension", "Context");
02502 
02503    ast_mutex_lock(&autoanswer_lock);
02504 
02505    cur=aalot;
02506    while(cur) {
02507       ast_cli(fd, "%25s %10s %15s\n",cur->chan->name, cur->exten, cur->context);
02508 
02509       cur = cur->next;
02510    }
02511 
02512    ast_mutex_unlock(&autoanswer_lock);
02513 
02514    return RESULT_SUCCESS;
02515 }
02516 
02517 static struct ast_cli_entry cli_features[] = {
02518    { { "feature", "list", NULL },
02519    handle_showfeatures, "Lists configured features",
02520    showfeatures_help, NULL, &cli_show_features_deprecated },
02521 
02522    { { "show", "parkedcalls", NULL },
02523    handle_parkedcalls, "Lists parked calls",
02524    showparked_help },
02525 
02526    { { "show", "autoanswer", NULL },
02527    handle_autoanswer, "Lists autoanswer users",
02528    showautoanswer_help },
02529 };
02530 int ast_masq_autoanswer_login(struct ast_channel *rchan, void *data)
02531 {
02532    struct ast_channel *chan;
02533    struct ast_frame *f;
02534    /* Make a new, fake channel that we'll use to masquerade in the real one */
02535    chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Autoanswer/%s", rchan->name);
02536    if (chan) {
02537       /* Let us keep track of the channel name */
02538       ast_string_field_build(chan, name, "Autoanswer/%s",rchan->name);
02539       /* Make formats okay */
02540       chan->readformat = rchan->readformat;
02541       chan->writeformat = rchan->writeformat;
02542       ast_channel_masquerade(chan, rchan);
02543       /* Setup the extensions and such */
02544       strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
02545       strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
02546       chan->priority = rchan->priority;
02547       /* might be dirty but we want trackable channels */
02548       ast_string_field_build(chan, uniqueid, "%s",rchan->uniqueid);
02549       /* Make the masq execute */
02550       f = ast_read(chan);
02551       if (f)
02552          ast_frfree(f);
02553       ast_autoanswer_login(chan, data);
02554    } else {
02555       ast_log(LOG_WARNING, "Unable to create aa channel\n");
02556       return -1;
02557    }
02558    return 0;
02559 }
02560 
02561 static int autoanswer_login_exec(struct ast_channel *chan, void *data)
02562 {
02563    int res=0;
02564    struct ast_module_user *u;
02565 
02566    u = ast_module_user_add(chan);
02567    if (!data) {
02568       ast_log(LOG_WARNING, "AutoanswerLogin requires an argument (extension number)\n");
02569       return -1;
02570    }
02571    res = ast_masq_autoanswer_login(chan, data);
02572    ast_module_user_remove(u);
02573    return res; 
02574 }
02575 
02576 int ast_autoanswer_login(struct ast_channel *chan, void *data)
02577 {
02578    /* We put the user in the parking list, then wake up the parking thread to be sure it looks
02579       after these channels too */
02580    struct ast_context *con;
02581    char exten[AST_MAX_EXTENSION];
02582    struct aauser *pu,*pl = NULL;
02583    char *s, *stringp, *aacontext, *aaexten = NULL;
02584 
02585    s = ast_strdupa((void *) data);
02586    stringp=s;
02587    aacontext = strsep(&stringp, "|");
02588    aaexten = strsep(&stringp, "|");
02589    if (!aaexten) {
02590        aaexten = aacontext;
02591        aacontext = NULL;
02592    }
02593    if (!aaexten) {
02594       ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n");
02595       return -1;
02596    } else {
02597       if (!aacontext) {
02598          aacontext = "default";
02599       }
02600    }
02601 
02602    ast_mutex_lock(&autoanswer_lock);
02603    pu = aalot;
02604    while(pu) {
02605       if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){
02606          if (pl)
02607             pl->next = pu->next;
02608          else
02609             aalot = pu->next;
02610          break;
02611       }
02612       pl = pu;
02613       pu = pu->next;
02614    }
02615    ast_mutex_unlock(&autoanswer_lock);
02616    if (pu) {
02617        ast_log(LOG_NOTICE, "Logout old Channel %s for %s@%s.\n",pu->chan->name, pu->exten, pu->context);
02618        manager_event(EVENT_FLAG_CALL, "AutoanswerLogout",
02619                                "Channel: %s\r\n"
02620                                "Uniqueid: %s\r\n"
02621                                "Context: %s\r\n"
02622                                "Exten: %s\r\n"
02623                            ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
02624        ast_hangup(pu->chan);
02625        free(pu);
02626    }
02627    pu = malloc(sizeof(struct aauser));
02628    if (pu) {
02629       memset(pu, 0, sizeof(pu));
02630       ast_mutex_lock(&autoanswer_lock);
02631       chan->appl = "Autoanswer";
02632       chan->data = NULL; 
02633 
02634       pu->chan = chan;
02635       if (chan->_state != AST_STATE_UP) {
02636           ast_answer(chan);
02637       }
02638 
02639       /* Start music on hold */
02640       ast_moh_start(pu->chan, NULL, NULL);
02641       gettimeofday(&pu->start, NULL);
02642       strncpy(pu->exten, aaexten, sizeof(pu->exten)-1);
02643       strncpy(pu->context, aacontext, sizeof(pu->exten)-1);
02644       pu->next = aalot;
02645       aalot = pu;
02646       con = ast_context_find(aacontext);
02647       if (!con) {
02648          con = ast_context_create(NULL,aacontext, registrar);
02649          if (!con) {
02650             ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", aacontext);
02651          }
02652       }
02653       if (con) {
02654          snprintf(exten, sizeof(exten), "%s", aaexten);
02655          ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)data), free, registrar);
02656       }
02657 
02658       ast_mutex_unlock(&autoanswer_lock);
02659       /* Wake up the (presumably select()ing) thread */
02660       pthread_kill(autoanswer_thread, SIGURG);
02661       if (option_verbose > 1) 
02662          ast_verbose(VERBOSE_PREFIX_2 "Autoanswer login from %s for %s@%s.\n", pu->chan->name, pu->exten, pu->context);
02663          manager_event(EVENT_FLAG_CALL, "AutoanswerLogin",
02664                                 "Channel: %s\r\n"
02665                                 "Uniqueid: %s\r\n"
02666                "Context: %s\r\n"
02667                         "Exten: %s\r\n"
02668                         ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
02669 
02670          return 0;
02671    } else {
02672       ast_log(LOG_WARNING, "Out of memory\n");
02673       return -1;
02674    }
02675    return 0;
02676 }
02677 
02678 static void autoanswer_reregister_extensions(void)
02679 {
02680    struct aauser *cur;
02681    struct ast_context *con;
02682    char exten[AST_MAX_EXTENSION];
02683    char args[AST_MAX_EXTENSION];
02684 
02685    ast_mutex_lock(&autoanswer_lock);
02686 
02687    cur=aalot;
02688    while(cur) {
02689       con = ast_context_find(cur->context);
02690       if (!con) {
02691          con = ast_context_create(NULL,cur->context, registrar);
02692          if (!con) {
02693             ast_log(LOG_ERROR, "Context '%s' does not exist and unable to create\n", cur->context);
02694          }
02695       }
02696       if (con) {
02697          snprintf(exten, sizeof(exten), "%s", cur->exten);
02698          snprintf(args, sizeof(args), "%s|%s", cur->context, cur->exten);
02699          ast_add_extension2(con, 1, exten, 1, NULL, NULL, autoanswer, strdup((char *)args), free, registrar);
02700       }
02701       cur = cur->next;
02702    }
02703 
02704    ast_mutex_unlock(&autoanswer_lock);
02705 }
02706 static void *do_autoanswer_thread(void *ignore)
02707 {
02708    int ms, tms, max;
02709    struct ast_context *con;
02710    char exten[AST_MAX_EXTENSION];
02711    struct aauser *pu, *pl, *pt = NULL;
02712    struct timeval tv;
02713    struct ast_frame *f;
02714    int x;
02715    fd_set rfds, efds;
02716    fd_set nrfds, nefds;
02717    FD_ZERO(&rfds);
02718    FD_ZERO(&efds);
02719    for (;;) {
02720       ms = -1;
02721       max = -1;
02722       ast_mutex_lock(&autoanswer_lock);
02723       pl = NULL;
02724       pu = aalot;
02725       gettimeofday(&tv, NULL);
02726       FD_ZERO(&nrfds);
02727       FD_ZERO(&nefds);
02728       while(pu) {
02729          tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
02730          for (x=0;x<AST_MAX_FDS;x++) {
02731             if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
02732                if (FD_ISSET(pu->chan->fds[x], &efds))
02733                   ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
02734                else
02735                   ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
02736                pu->chan->fdno = x;
02737                /* See if they need servicing */
02738                f = ast_read(pu->chan);
02739                if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
02740                   /* There's a problem, hang them up*/
02741                   if (option_verbose > 1) 
02742                      ast_verbose(VERBOSE_PREFIX_2 "%s logged out of autoanswer app\n", pu->chan->name);
02743                   manager_event(EVENT_FLAG_CALL, "AutoanswerLogout",
02744                                         "Channel: %s\r\n"
02745                                         "Uniqueid: %s\r\n"
02746                                   "Context: %s\r\n"
02747                                   "Exten: %s\r\n"
02748                               ,pu->chan->name, pu->chan->uniqueid, pu->context, pu->exten);
02749                   ast_hangup(pu->chan);
02750                   con = ast_context_find(pu->context);
02751                   if (con) {
02752                       snprintf(exten, sizeof(exten), "%s", pu->exten);
02753                       if (ast_context_remove_extension2(con, exten, 1, registrar))
02754                      ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
02755                   } else {
02756                      ast_log(LOG_WARNING, "Whoa, no %s context?\n", pu->exten);
02757                   }
02758                   /* And take them out of the parking lot */
02759                   if (pl) 
02760                      pl->next = pu->next;
02761                   else
02762                      aalot = pu->next;
02763                   pt = pu;
02764                   pu = pu->next;
02765                   free(pt);
02766                   break;
02767                } else {
02768                   /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
02769                   ast_frfree(f);
02770                   goto std;   /* XXX Ick: jumping into an else statement??? XXX */
02771                }
02772             }
02773          }
02774          if (x >= AST_MAX_FDS) {
02775 std:           for (x=0;x<AST_MAX_FDS;x++) {
02776                /* Keep this one for next one */
02777                if (pu->chan->fds[x] > -1) {
02778                   FD_SET(pu->chan->fds[x], &nrfds);
02779                   FD_SET(pu->chan->fds[x], &nefds);
02780                   if (pu->chan->fds[x] > max)
02781                      max = pu->chan->fds[x];
02782                }
02783             }
02784             /* Keep track of our longest wait */
02785             if ((tms < ms) || (ms < 0))
02786                ms = tms;
02787             pl = pu;
02788             pu = pu->next;
02789          }
02790       }
02791       ast_mutex_unlock(&autoanswer_lock);
02792       rfds = nrfds;
02793       efds = nefds;
02794       tv.tv_sec = ms / 1000;
02795       tv.tv_usec = (ms % 1000) * 1000;
02796       /* Wait for something to happen */
02797       ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
02798       pthread_testcancel();
02799    }
02800    return NULL;   /* Never reached */
02801 }
02802 
02803 static int autoanswer_exec(struct ast_channel *chan, void *data)
02804 {
02805    int res=0;
02806    struct ast_channel *peer=NULL;
02807    struct aauser *pu, *pl=NULL;
02808    struct ast_bridge_config config;
02809    char *s, *stringp, *aacontext, *aaexten = NULL;
02810    char datastring[80];
02811    struct ast_module_user *u;
02812 
02813 
02814    if (!data) {
02815       ast_log(LOG_WARNING, "Autoanswer requires an argument (extension number)\n");
02816       return -1;
02817    }
02818    s = ast_strdupa((void *) data);
02819    stringp=s;
02820    aacontext = strsep(&stringp, "|");
02821    aaexten = strsep(&stringp, "|");
02822    if (!aaexten) {
02823        aaexten = aacontext;
02824        aacontext = NULL;
02825    }
02826    if (!aaexten) {
02827       ast_log(LOG_WARNING, "AutoanswerLogin requires at least an extension!\n");
02828       return -1;
02829    } else {
02830       if (!aacontext) {
02831          aacontext = "default";
02832       }
02833    }
02834 
02835    u = ast_module_user_add(chan);
02836    ast_mutex_lock(&autoanswer_lock);
02837    pu = aalot;
02838    while(pu) {
02839       if ((!strncasecmp(pu->exten, aaexten, sizeof(pu->exten)-1)) && (!strncasecmp(pu->context, aacontext, sizeof(pu->context)-1))){
02840          if (pl)
02841             pl->next = pu->next;
02842          else
02843             aalot = pu->next;
02844          break;
02845       }
02846       pl = pu;
02847       pu = pu->next;
02848    }
02849    ast_mutex_unlock(&autoanswer_lock);
02850    if (pu) {
02851       peer = pu->chan;
02852       free(pu);
02853       pu = NULL;
02854    }
02855    /* JK02: it helps to answer the channel if not already up */
02856    if (chan->_state != AST_STATE_UP) {
02857       ast_answer(chan);
02858    }
02859 
02860    if (peer) {
02861       ast_moh_stop(peer);
02862       /* Play a courtesy beep in the callED channel to prefix the bridge connecting */ 
02863       if (!ast_strlen_zero(courtesytone)) {
02864          if (!ast_streamfile(peer, courtesytone, peer->language)) {
02865             if (ast_waitstream(peer, "") < 0) {
02866                ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
02867                ast_hangup(peer);
02868                return -1;
02869             }
02870          }
02871       }
02872  
02873       res = ast_channel_make_compatible(chan, peer);
02874       if (res < 0) {
02875          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
02876          ast_hangup(peer);
02877          return -1;
02878       }
02879       /* This runs sorta backwards, since we give the incoming channel control, as if it
02880          were the person called. */
02881       if (option_verbose > 2) 
02882          ast_verbose(VERBOSE_PREFIX_3 "Channel %s autoanswered  %s\n", peer->name, chan->name);
02883       manager_event(EVENT_FLAG_CALL, "Autoanswer",
02884                     "Channel: %s\r\n"
02885                     "Uniqueid: %s\r\n"
02886                     "Channel2: %s\r\n"
02887                     "Uniqueid2: %s\r\n"
02888                     "Context: %s\r\n"
02889                     "Exten: %s\r\n"
02890                 ,chan->name, chan->uniqueid, peer->name, peer->uniqueid, aacontext, aaexten);
02891 
02892 
02893       memset(&config,0,sizeof(struct ast_bridge_config));
02894       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
02895       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
02896       config.timelimit = 0;
02897       config.play_warning = 0;
02898       config.warning_freq = 0;
02899       config.warning_sound=NULL;
02900       res = ast_bridge_call(chan,peer,&config);
02901 
02902       if (option_verbose > 2) 
02903          ast_verbose(VERBOSE_PREFIX_3 "returning from bridge %s\n", peer->name);
02904          /* relogin */
02905       snprintf(datastring, sizeof(datastring) - 1, "%s|%s", aacontext, aaexten);
02906       ast_autoanswer_login(peer, datastring);
02907       return res;
02908    } else {
02909       if (option_verbose > 2) 
02910          ast_verbose(VERBOSE_PREFIX_3 "Nobody logged in for autoanswer %s@%s\n", aaexten, aacontext);
02911       res = -1;
02912    }
02913    ast_module_user_remove(u);
02914    return res;
02915 }
02916 
02917 
02918 int ast_pickup_call(struct ast_channel *chan)
02919 {
02920    struct ast_channel *cur = NULL;
02921    int res = -1;
02922 
02923    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
02924       if (!cur->pbx && 
02925          (cur != chan) &&
02926          (chan->pickupgroup & cur->callgroup) &&
02927          ((cur->_state == AST_STATE_RINGING) ||
02928           (cur->_state == AST_STATE_RING))) {
02929             break;
02930       }
02931       ast_channel_unlock(cur);
02932    }
02933    if (cur) {
02934       if (option_debug)
02935          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
02936       res = ast_answer(chan);
02937       if (res)
02938          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
02939       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
02940       if (res)
02941          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
02942       res = ast_channel_masquerade(cur, chan);
02943       if (res)
02944          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
02945       ast_channel_unlock(cur);
02946    } else   {
02947       if (option_debug)
02948          ast_log(LOG_DEBUG, "No call pickup possible...\n");
02949    }
02950    return res;
02951 }
02952 
02953 /*! \brief Add parking hints for all defined parking lots */
02954 static void park_add_hints(char *context, int start, int stop)
02955 {
02956    int numext;
02957    char device[AST_MAX_EXTENSION];
02958    char exten[10];
02959 
02960    for (numext = start; numext <= stop; numext++) {
02961       snprintf(exten, sizeof(exten), "%d", numext);
02962       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
02963       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
02964    }
02965 }
02966 
02967 
02968 static int load_config(void) 
02969 {
02970    int start = 0, end = 0;
02971    int res;
02972    struct ast_context *con = NULL;
02973    struct ast_config *cfg = NULL;
02974    struct ast_variable *var = NULL;
02975    char old_parking_ext[AST_MAX_EXTENSION];
02976    char old_parking_con[AST_MAX_EXTENSION] = "";
02977 
02978    if (!ast_strlen_zero(parking_con)) {
02979       strcpy(old_parking_ext, parking_ext);
02980       strcpy(old_parking_con, parking_con);
02981    } 
02982 
02983    /* Reset to defaults */
02984    strcpy(parking_con, "parkedcalls");
02985    strcpy(parking_con_dial, "park-dial");
02986    strcpy(parking_ext, "700");
02987    strcpy(pickup_ext, "*8");
02988    strcpy(parkmohclass, "default");
02989    courtesytone[0] = '\0';
02990    strcpy(xfersound, "beep");
02991    strcpy(xferfailsound, "pbx-invalid");
02992    parking_start = 701;
02993    parking_stop = 750;
02994    parkfindnext = 0;
02995    adsipark = 0;
02996    parkaddhints = 0;
02997 
02998    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02999    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03000    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03001 
03002    cfg = ast_config_load("features.conf");
03003    if (!cfg) {
03004       ast_log(LOG_WARNING,"Could not load features.conf\n");
03005       return AST_MODULE_LOAD_DECLINE;
03006    }
03007    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
03008       if (!strcasecmp(var->name, "parkext")) {
03009          ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
03010       } else if (!strcasecmp(var->name, "context")) {
03011          ast_copy_string(parking_con, var->value, sizeof(parking_con));
03012       } else if (!strcasecmp(var->name, "parkingtime")) {
03013          if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
03014             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
03015             parkingtime = DEFAULT_PARK_TIME;
03016          } else
03017             parkingtime = parkingtime * 1000;
03018       } else if (!strcasecmp(var->name, "parkpos")) {
03019          if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
03020             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);
03021          } else {
03022             parking_start = start;
03023             parking_stop = end;
03024          }
03025       } else if (!strcasecmp(var->name, "findslot")) {
03026          parkfindnext = (!strcasecmp(var->value, "next"));
03027       } else if (!strcasecmp(var->name, "parkinghints")) {
03028          parkaddhints = ast_true(var->value);
03029       } else if (!strcasecmp(var->name, "adsipark")) {
03030          adsipark = ast_true(var->value);
03031       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
03032          if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
03033             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
03034             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
03035          } else
03036             transferdigittimeout = transferdigittimeout * 1000;
03037       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
03038          if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
03039             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
03040             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03041          }
03042       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
03043          if ((sscanf(var->value, "%d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
03044             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
03045             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03046          } else
03047             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
03048       } else if (!strcasecmp(var->name, "courtesytone")) {
03049          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
03050       }  else if (!strcasecmp(var->name, "parkedplay")) {
03051          if (!strcasecmp(var->value, "both"))
03052             parkedplay = 2;
03053          else if (!strcasecmp(var->value, "parked"))
03054             parkedplay = 1;
03055          else
03056             parkedplay = 0;
03057       } else if (!strcasecmp(var->name, "xfersound")) {
03058          ast_copy_string(xfersound, var->value, sizeof(xfersound));
03059       } else if (!strcasecmp(var->name, "xferfailsound")) {
03060          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
03061       } else if (!strcasecmp(var->name, "pickupexten")) {
03062          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
03063       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
03064          ast_copy_string(parkmohclass, var->value, sizeof(parkmohclass));
03065       }
03066    }
03067 
03068    unmap_features();
03069    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
03070       if (remap_feature(var->name, var->value))
03071          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
03072    }
03073 
03074    /* Map a key combination to an application*/
03075    ast_unregister_features();
03076    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
03077       char *tmp_val = ast_strdupa(var->value);
03078       char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 
03079       struct ast_call_feature *feature;
03080 
03081       /* strsep() sets the argument to NULL if match not found, and it
03082        * is safe to use it with a NULL argument, so we don't check
03083        * between calls.
03084        */
03085       exten = strsep(&tmp_val,",");
03086       activatedby = strsep(&tmp_val,",");
03087       app = strsep(&tmp_val,",");
03088       app_args = strsep(&tmp_val,",");
03089       moh_class = strsep(&tmp_val,",");
03090 
03091       activateon = strsep(&activatedby, "/");   
03092 
03093       /*! \todo XXX var_name or app_args ? */
03094       if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
03095          ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
03096             app, exten, activateon, var->name);
03097          continue;
03098       }
03099 
03100       AST_LIST_LOCK(&feature_list);
03101       if ((feature = find_dynamic_feature(var->name))) {
03102          AST_LIST_UNLOCK(&feature_list);
03103          ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
03104          continue;
03105       }
03106       AST_LIST_UNLOCK(&feature_list);
03107             
03108       if (!(feature = ast_calloc(1, sizeof(*feature))))
03109          continue;               
03110 
03111       ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
03112       ast_copy_string(feature->app, app, FEATURE_APP_LEN);
03113       ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
03114       
03115       if (app_args) 
03116          ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
03117 
03118       if (moh_class)
03119          ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
03120          
03121       ast_copy_string(feature->exten, exten, sizeof(feature->exten));
03122       feature->operation = feature_exec_app;
03123       ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
03124 
03125       /* Allow caller and calle to be specified for backwards compatability */
03126       if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
03127          ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
03128       else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
03129          ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
03130       else {
03131          ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
03132             " must be 'self', or 'peer'\n", var->name);
03133          continue;
03134       }
03135 
03136       if (ast_strlen_zero(activatedby))
03137          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03138       else if (!strcasecmp(activatedby, "caller"))
03139          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
03140       else if (!strcasecmp(activatedby, "callee"))
03141          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
03142       else if (!strcasecmp(activatedby, "both"))
03143          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03144       else {
03145          ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
03146             " must be 'caller', or 'callee', or 'both'\n", var->name);
03147          continue;
03148       }
03149 
03150       ast_register_feature(feature);
03151          
03152       if (option_verbose >= 1)
03153          ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);  
03154    }   
03155    ast_config_destroy(cfg);
03156 
03157    /* Remove the old parking extension */
03158    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
03159       if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar))
03160             notify_metermaids(old_parking_ext, old_parking_con);
03161       if (option_debug)
03162          ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
03163    }
03164    
03165    if (!(con = ast_context_find(parking_con)) && !(con = ast_context_create(NULL, parking_con, registrar))) {
03166       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
03167       return -1;
03168    }
03169    res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
03170    if (parkaddhints)
03171       park_add_hints(parking_con, parking_start, parking_stop);
03172    if (!res)
03173       notify_metermaids(ast_parking_ext(), parking_con);
03174    return res;
03175 
03176 }
03177 
03178 static int reload(void)
03179 {
03180    autoanswer_reregister_extensions();
03181    return load_config();
03182 }
03183 
03184 static int load_module(void)
03185 {
03186    int res;
03187    
03188    memset(parking_ext, 0, sizeof(parking_ext));
03189    memset(parking_con, 0, sizeof(parking_con));
03190 
03191    if ((res = load_config()))
03192       return res;
03193    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03194    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
03195    ast_pthread_create(&holding_thread, NULL, do_holding_thread, NULL);
03196    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
03197    if (!res)
03198       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
03199    if (!res) {
03200       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
03201       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park,
03202          "Park a channel", mandescr_park); 
03203    }
03204 
03205    res |= ast_register_application(holdedcall, retrieve_call_exec, synopsis, descrip);
03206    ast_pthread_create(&autoanswer_thread, NULL, do_autoanswer_thread, NULL);
03207    if (!res)
03208       res |= ast_register_application(autoanswerlogin, autoanswer_login_exec, synopsis3, descrip3);
03209    if (!res)
03210       res |= ast_register_application(autoanswer, autoanswer_exec, synopsis4, descrip4);
03211 
03212    res |= ast_devstate_prov_add("Park", metermaidstate);
03213 
03214    return res;
03215 }
03216 
03217 
03218 static int unload_module(void)
03219 {
03220    ast_module_user_hangup_all();
03221 
03222    ast_manager_unregister("ParkedCalls");
03223    ast_manager_unregister("Park");
03224    ast_cli_unregister_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
03225    ast_unregister_application(parkcall);
03226    ast_unregister_application(autoanswer);
03227    ast_unregister_application(autoanswerlogin);
03228    ast_unregister_application(holdedcall);
03229    ast_devstate_prov_del("Park");
03230    return ast_unregister_application(parkedcall);
03231 }
03232 
03233 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Call Features Resource",
03234       .load = load_module,
03235       .unload = unload_module,
03236       .reload = reload,
03237           );

Generated on Sat Apr 12 07:12:27 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.5