Sat Nov 1 06:28:36 2008

Asterisk developer's documentation


res_features.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Routines implementing call features as call pickup, parking and transfer
00022  *
00023  * \author Mark Spencer <markster@digium.com> 
00024  */
00025 
00026 /*** MODULEINFO
00027         <depend>chan_local</depend>
00028  ***/
00029 
00030 #include "asterisk.h"
00031 
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 153270 $")
00033 
00034 #include <pthread.h>
00035 #include <stdlib.h>
00036 #include <errno.h>
00037 #include <unistd.h>
00038 #include <string.h>
00039 #include <stdlib.h>
00040 #include <stdio.h>
00041 #include <sys/time.h>
00042 #include <sys/signal.h>
00043 #include <netinet/in.h>
00044 
00045 #include "asterisk/lock.h"
00046 #include "asterisk/file.h"
00047 #include "asterisk/logger.h"
00048 #include "asterisk/channel.h"
00049 #include "asterisk/pbx.h"
00050 #include "asterisk/options.h"
00051 #include "asterisk/causes.h"
00052 #include "asterisk/module.h"
00053 #include "asterisk/translate.h"
00054 #include "asterisk/app.h"
00055 #include "asterisk/say.h"
00056 #include "asterisk/features.h"
00057 #include "asterisk/musiconhold.h"
00058 #include "asterisk/config.h"
00059 #include "asterisk/cli.h"
00060 #include "asterisk/manager.h"
00061 #include "asterisk/utils.h"
00062 #include "asterisk/adsi.h"
00063 #include "asterisk/devicestate.h"
00064 #include "asterisk/monitor.h"
00065 #include "asterisk/global_datastores.h"
00066 
00067 #define DEFAULT_PARK_TIME 45000
00068 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
00069 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
00070 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
00071 
00072 #define AST_MAX_WATCHERS 256
00073 
00074 enum {
00075    AST_FEATURE_FLAG_NEEDSDTMF = (1 << 0),
00076    AST_FEATURE_FLAG_ONPEER =    (1 << 1),
00077    AST_FEATURE_FLAG_ONSELF =    (1 << 2),
00078    AST_FEATURE_FLAG_BYCALLEE =  (1 << 3),
00079    AST_FEATURE_FLAG_BYCALLER =  (1 << 4),
00080    AST_FEATURE_FLAG_BYBOTH  =   (3 << 3),
00081 };
00082 
00083 static char *parkedcall = "ParkedCall";
00084 
00085 static int parkaddhints = 0;                               /*!< Add parking hints automatically */
00086 static int parkingtime = DEFAULT_PARK_TIME;                /*!< No more than 45 seconds parked before you do something with them */
00087 static char parking_con[AST_MAX_EXTENSION];                /*!< Context for which parking is made accessible */
00088 static char parking_con_dial[AST_MAX_EXTENSION];           /*!< Context for dialback for parking (KLUDGE) */
00089 static char parking_ext[AST_MAX_EXTENSION];                /*!< Extension you type to park the call */
00090 static char pickup_ext[AST_MAX_EXTENSION];                 /*!< Call pickup extension */
00091 static char parkmohclass[MAX_MUSICCLASS];                  /*!< Music class used for parking */
00092 static int parking_start;                                  /*!< First available extension for parking */
00093 static int parking_stop;                                   /*!< Last available extension for parking */
00094 
00095 static int parkedcalltransfers;                            /*!< Who can REDIRECT after picking up a parked a call */
00096 
00097 static char courtesytone[256];                             /*!< Courtesy tone */
00098 static int parkedplay = 0;                                 /*!< Who to play the courtesy tone to */
00099 static char xfersound[256];                                /*!< Call transfer sound */
00100 static char xferfailsound[256];                            /*!< Call transfer failure sound */
00101 
00102 static int parking_offset;
00103 static int parkfindnext;
00104 
00105 static int adsipark;
00106 
00107 static int transferdigittimeout;
00108 static int featuredigittimeout;
00109 
00110 static int atxfernoanswertimeout;
00111 
00112 static char *registrar = "res_features";        /*!< Registrar for operations */
00113 
00114 /* module and CLI command definitions */
00115 static char *synopsis = "Answer a parked call";
00116 
00117 static char *descrip = "ParkedCall(exten):"
00118 "Used to connect to a parked call.  This application is always\n"
00119 "registered internally and does not need to be explicitly added\n"
00120 "into the dialplan, although you should include the 'parkedcalls'\n"
00121 "context.\n";
00122 
00123 static char *parkcall = PARK_APP_NAME;
00124 
00125 static char *synopsis2 = "Park yourself";
00126 
00127 static char *descrip2 = "Park():"
00128 "Used to park yourself (typically in combination with a supervised\n"
00129 "transfer to know the parking space). This application is always\n"
00130 "registered internally and does not need to be explicitly added\n"
00131 "into the dialplan, although you should include the 'parkedcalls'\n"
00132 "context (or the context specified in features.conf).\n\n"
00133 "If you set the PARKINGEXTEN variable to an extension in your\n"
00134 "parking context, park() will park the call on that extension, unless\n"
00135 "it already exists. In that case, execution will continue at next\n"
00136 "priority.\n" ;
00137 
00138 static struct ast_app *monitor_app = NULL;
00139 static int monitor_ok = 1;
00140 
00141 struct parkeduser {
00142    struct ast_channel *chan;                   /*!< Parking channel */
00143    struct timeval start;                       /*!< Time the parking started */
00144    int parkingnum;                             /*!< Parking lot */
00145    char parkingexten[AST_MAX_EXTENSION];       /*!< If set beforehand, parking extension used for this call */
00146    char context[AST_MAX_CONTEXT];              /*!< Where to go if our parking time expires */
00147    char exten[AST_MAX_EXTENSION];
00148    int priority;
00149    int parkingtime;                            /*!< Maximum length in parking lot before return */
00150    int notquiteyet;
00151    char peername[1024];
00152    unsigned char moh_trys;
00153    struct parkeduser *next;
00154 };
00155 
00156 static struct parkeduser *parkinglot;
00157 
00158 AST_MUTEX_DEFINE_STATIC(parking_lock); /*!< protects all static variables above */
00159 
00160 static pthread_t parking_thread;
00161 
00162 char *ast_parking_ext(void)
00163 {
00164    return parking_ext;
00165 }
00166 
00167 char *ast_pickup_ext(void)
00168 {
00169    return pickup_ext;
00170 }
00171 
00172 struct ast_bridge_thread_obj 
00173 {
00174    struct ast_bridge_config bconfig;
00175    struct ast_channel *chan;
00176    struct ast_channel *peer;
00177 };
00178 
00179 
00180 
00181 /*! \brief store context, priority and extension */
00182 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
00183 {
00184    ast_copy_string(chan->context, context, sizeof(chan->context));
00185    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00186    chan->priority = pri;
00187 }
00188 
00189 static void check_goto_on_transfer(struct ast_channel *chan) 
00190 {
00191    struct ast_channel *xferchan;
00192    const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00193    char *x, *goto_on_transfer;
00194    struct ast_frame *f;
00195 
00196    if (ast_strlen_zero(val))
00197       return;
00198 
00199    goto_on_transfer = ast_strdupa(val);
00200 
00201    if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, chan->name)))
00202       return;
00203 
00204    for (x = goto_on_transfer; x && *x; x++) {
00205       if (*x == '^')
00206          *x = '|';
00207    }
00208    /* Make formats okay */
00209    xferchan->readformat = chan->readformat;
00210    xferchan->writeformat = chan->writeformat;
00211    ast_channel_masquerade(xferchan, chan);
00212    ast_parseable_goto(xferchan, goto_on_transfer);
00213    xferchan->_state = AST_STATE_UP;
00214    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00215    xferchan->_softhangup = 0;
00216    if ((f = ast_read(xferchan))) {
00217       ast_frfree(f);
00218       f = NULL;
00219       ast_pbx_start(xferchan);
00220    } else {
00221       ast_hangup(xferchan);
00222    }
00223 }
00224 
00225 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, const char *language);
00226 
00227 
00228 static void *ast_bridge_call_thread(void *data) 
00229 {
00230    struct ast_bridge_thread_obj *tobj = data;
00231 
00232    tobj->chan->appl = "Transferred Call";
00233    tobj->chan->data = tobj->peer->name;
00234    tobj->peer->appl = "Transferred Call";
00235    tobj->peer->data = tobj->chan->name;
00236 
00237    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00238    ast_hangup(tobj->chan);
00239    ast_hangup(tobj->peer);
00240    bzero(tobj, sizeof(*tobj)); /*! \todo XXX for safety */
00241    free(tobj);
00242    return NULL;
00243 }
00244 
00245 static void ast_bridge_call_thread_launch(void *data) 
00246 {
00247    pthread_t thread;
00248    pthread_attr_t attr;
00249    struct sched_param sched;
00250 
00251    pthread_attr_init(&attr);
00252    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00253    ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00254    pthread_attr_destroy(&attr);
00255    memset(&sched, 0, sizeof(sched));
00256    pthread_setschedparam(thread, SCHED_RR, &sched);
00257 }
00258 
00259 static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
00260 {
00261    int res;
00262    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00263    char tmp[256];
00264    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00265 
00266    snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00267    message[0] = tmp;
00268    res = ast_adsi_load_session(chan, NULL, 0, 1);
00269    if (res == -1)
00270       return res;
00271    return ast_adsi_print(chan, message, justify, 1);
00272 }
00273 
00274 /*! \brief Notify metermaids that we've changed an extension */
00275 static void notify_metermaids(char *exten, char *context)
00276 {
00277    if (option_debug > 3)
00278       ast_log(LOG_DEBUG, "Notification of state change to metermaids %s@%s\n", exten, context);
00279 
00280    /* Send notification to devicestate subsystem */
00281    ast_device_state_changed("park:%s@%s", exten, context);
00282    return;
00283 }
00284 
00285 /*! \brief metermaids callback from devicestate.c */
00286 static int metermaidstate(const char *data)
00287 {
00288    int res = AST_DEVICE_INVALID;
00289    char *context = ast_strdupa(data);
00290    char *exten;
00291 
00292    exten = strsep(&context, "@");
00293    if (!context)
00294       return res;
00295    
00296    if (option_debug > 3)
00297       ast_log(LOG_DEBUG, "Checking state of exten %s in context %s\n", exten, context);
00298 
00299    res = ast_exists_extension(NULL, context, exten, 1, NULL);
00300 
00301    if (!res)
00302       return AST_DEVICE_NOT_INUSE;
00303    else
00304       return AST_DEVICE_INUSE;
00305 }
00306 
00307 static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout, char *orig_chan_name)
00308 {
00309    struct parkeduser *pu, *cur;
00310    int i, x = -1, parking_range, parkingnum_copy;
00311    struct ast_context *con;
00312    const char *parkingexten;
00313    
00314    /* Allocate memory for parking data */
00315    if (!(pu = ast_calloc(1, sizeof(*pu)))) 
00316       return -1;
00317 
00318    /* Lock parking lot */
00319    ast_mutex_lock(&parking_lock);
00320    /* Check for channel variable PARKINGEXTEN */
00321    parkingexten = pbx_builtin_getvar_helper(chan, "PARKINGEXTEN");
00322    if (!ast_strlen_zero(parkingexten)) {
00323       /*!\note The API forces us to specify a numeric parking slot, even
00324        * though the architecture would tend to support non-numeric extensions
00325        * (as are possible with SIP, for example).  Hence, we enforce that
00326        * limitation here.  If extout was not numeric, we could permit
00327        * arbitrary non-numeric extensions.
00328        */
00329       if (sscanf(parkingexten, "%d", &x) != 1 || x < 0) {
00330          ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
00331          ast_mutex_unlock(&parking_lock);
00332          free(pu);
00333          return 1;   /* Continue execution if possible */
00334       }
00335       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
00336 
00337       if (ast_exists_extension(NULL, parking_con, pu->parkingexten, 1, NULL)) {
00338          ast_mutex_unlock(&parking_lock);
00339          free(pu);
00340          ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parking_con);
00341          return 1;   /* Continue execution if possible */
00342       }
00343    } else {
00344       /* Select parking space within range */
00345       parking_range = parking_stop - parking_start+1;
00346       for (i = 0; i < parking_range; i++) {
00347          x = (i + parking_offset) % parking_range + parking_start;
00348          cur = parkinglot;
00349          while(cur) {
00350             if (cur->parkingnum == x) 
00351                break;
00352             cur = cur->next;
00353          }
00354          if (!cur)
00355             break;
00356       }
00357 
00358       if (!(i < parking_range)) {
00359          ast_log(LOG_WARNING, "No more parking spaces\n");
00360          free(pu);
00361          ast_mutex_unlock(&parking_lock);
00362          return -1;
00363       }
00364       /* Set pointer for next parking */
00365       if (parkfindnext) 
00366          parking_offset = x - parking_start + 1;
00367       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", x);
00368    }
00369    
00370    chan->appl = "Parked Call";
00371    chan->data = NULL; 
00372 
00373    pu->chan = chan;
00374    
00375    /* Put the parked channel on hold if we have two different channels */
00376    if (chan != peer) {
00377       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00378          S_OR(parkmohclass, NULL),
00379          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00380    }
00381    
00382    pu->start = ast_tvnow();
00383    pu->parkingnum = x;
00384    pu->parkingtime = (timeout > 0) ? timeout : parkingtime;
00385    if (extout)
00386       *extout = x;
00387 
00388    if (peer) { 
00389       /* This is so ugly that it hurts, but implementing get_base_channel() on local channels
00390          could have ugly side effects.  We could have transferer<->local,1<->local,2<->parking
00391          and we need the callback name to be that of transferer.  Since local,1/2 have the same
00392          name we can be tricky and just grab the bridged channel from the other side of the local
00393       */
00394       if (!strcasecmp(peer->tech->type, "Local")) {
00395          struct ast_channel *tmpchan, *base_peer;
00396          char other_side[AST_CHANNEL_NAME];
00397          char *c;
00398          ast_copy_string(other_side, peer->name, sizeof(other_side));
00399          if ((c = strrchr(other_side, ','))) {
00400             *++c = '1';
00401          }
00402          if ((tmpchan = ast_get_channel_by_name_locked(other_side))) {
00403             if ((base_peer = ast_bridged_channel(tmpchan))) {
00404                ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
00405             }
00406             ast_channel_unlock(tmpchan);
00407          }
00408       } else {
00409          ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
00410       }
00411    }
00412 
00413    /* Remember what had been dialed, so that if the parking
00414       expires, we try to come back to the same place */
00415    ast_copy_string(pu->context, S_OR(chan->macrocontext, chan->context), sizeof(pu->context));
00416    ast_copy_string(pu->exten, S_OR(chan->macroexten, chan->exten), sizeof(pu->exten));
00417    pu->priority = chan->macropriority ? chan->macropriority : chan->priority;
00418    pu->next = parkinglot;
00419    parkinglot = pu;
00420    parkingnum_copy = pu->parkingnum;
00421    /* If parking a channel directly, don't quite yet get parking running on it */
00422    if (peer == chan) 
00423       pu->notquiteyet = 1;
00424 
00425    if (option_verbose > 1) 
00426       ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d@%s. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, parking_con, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
00427 
00428    manager_event(EVENT_FLAG_CALL, "ParkedCall",
00429       "Exten: %s\r\n"
00430       "Channel: %s\r\n"
00431       "From: %s\r\n"
00432       "Timeout: %ld\r\n"
00433       "CallerID: %s\r\n"
00434       "CallerIDName: %s\r\n",
00435       pu->parkingexten, pu->chan->name, peer ? peer->name : "",
00436       (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00437       S_OR(pu->chan->cid.cid_num, "<unknown>"),
00438       S_OR(pu->chan->cid.cid_name, "<unknown>")
00439       );
00440 
00441    if (peer && adsipark && ast_adsi_available(peer)) {
00442       adsi_announce_park(peer, pu->parkingexten);  /* Only supports parking numbers */
00443       ast_adsi_unload_session(peer);
00444    }
00445 
00446    con = ast_context_find(parking_con);
00447    if (!con) 
00448       con = ast_context_create(NULL, parking_con, registrar);
00449    if (!con)   /* Still no context? Bad */
00450       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00451    if (con) {
00452       if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar)) {
00453          notify_metermaids(pu->parkingexten, parking_con);
00454       }
00455    }
00456 
00457    ast_mutex_unlock(&parking_lock);
00458    /* Wake up the (presumably select()ing) thread */
00459    pthread_kill(parking_thread, SIGURG);
00460 
00461    /* Only say number if it's a number and the channel hasn't been masqueraded away */
00462    if (peer && (ast_strlen_zero(orig_chan_name) || !strcasecmp(peer->name, orig_chan_name))) {
00463       /* Make sure we don't start saying digits to the channel being parked */
00464       ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00465       /* Tell the peer channel the number of the parking space */
00466       ast_say_digits(peer, parkingnum_copy, "", peer->language);
00467       ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00468    }
00469 
00470    if (peer == chan) { /* pu->notquiteyet = 1 */
00471       /* Wake up parking thread if we're really done */
00472       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00473          S_OR(parkmohclass, NULL),
00474          !ast_strlen_zero(parkmohclass) ? strlen(parkmohclass) + 1 : 0);
00475       pu->notquiteyet = 0;
00476       pthread_kill(parking_thread, SIGURG);
00477    }
00478    return 0;
00479 }
00480 
00481 /*! \brief Park a call 
00482    \note We put the user in the parking list, then wake up the parking thread to be sure it looks
00483    after these channels too */
00484 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
00485 {
00486    return park_call_full(chan, peer, timeout, extout, NULL);
00487 }
00488 
00489 static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement)
00490 {
00491    struct ast_channel *chan;
00492    struct ast_frame *f;
00493    char *orig_chan_name = NULL;
00494    int park_status;
00495 
00496    /* Make a new, fake channel that we'll use to masquerade in the real one */
00497    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00498       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00499       return -1;
00500    }
00501 
00502    /* Make formats okay */
00503    chan->readformat = rchan->readformat;
00504    chan->writeformat = rchan->writeformat;
00505    ast_channel_masquerade(chan, rchan);
00506 
00507    /* Setup the extensions and such */
00508    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00509 
00510    /* Make the masq execute */
00511    if ((f = ast_read(chan))) {
00512       ast_frfree(f);
00513    }
00514 
00515    if (!play_announcement) {
00516       orig_chan_name = ast_strdupa(chan->name);
00517    }
00518 
00519    park_status = park_call_full(chan, peer, timeout, extout, orig_chan_name);
00520    if (park_status == 1) {
00521       /* would be nice to play: "invalid parking extension" */
00522       ast_hangup(chan);
00523       return -1;
00524    }
00525 
00526    return 0;
00527 }
00528 
00529 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
00530 {
00531    return masq_park_call(rchan, peer, timeout, extout, 0);
00532 }
00533 
00534 static int masq_park_call_announce(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
00535 {
00536    return masq_park_call(rchan, peer, timeout, extout, 1);
00537 }
00538 
00539 #define FEATURE_RETURN_HANGUP                  -1
00540 #define FEATURE_RETURN_SUCCESSBREAK             0
00541 #define FEATURE_RETURN_PBX_KEEPALIVE            AST_PBX_KEEPALIVE
00542 #define FEATURE_RETURN_NO_HANGUP_PEER           AST_PBX_NO_HANGUP_PEER
00543 #define FEATURE_RETURN_NO_HANGUP_PEER_PARKED    AST_PBX_NO_HANGUP_PEER_PARKED
00544 #define FEATURE_RETURN_PASSDIGITS               21
00545 #define FEATURE_RETURN_STOREDIGITS              22
00546 #define FEATURE_RETURN_SUCCESS                  23
00547 #define FEATURE_RETURN_KEEPTRYING               24
00548 
00549 #define FEATURE_SENSE_CHAN (1 << 0)
00550 #define FEATURE_SENSE_PEER (1 << 1)
00551 
00552 /*! \brief
00553  * set caller and callee according to the direction
00554  */
00555 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
00556    struct ast_channel *peer, struct ast_channel *chan, int sense)
00557 {
00558    if (sense == FEATURE_SENSE_PEER) {
00559       *caller = peer;
00560       *callee = chan;
00561    } else {
00562       *callee = peer;
00563       *caller = chan;
00564    }
00565 }
00566 
00567 /*! \brief support routing for one touch call parking */
00568 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00569 {
00570    struct ast_channel *parker;
00571    struct ast_channel *parkee;
00572    int res = 0;
00573    struct ast_module_user *u;
00574 
00575    u = ast_module_user_add(chan);
00576 
00577    set_peers(&parker, &parkee, peer, chan, sense);
00578    /* Setup the exten/priority to be s/1 since we don't know
00579       where this call should return */
00580    strcpy(chan->exten, "s");
00581    chan->priority = 1;
00582    if (chan->_state != AST_STATE_UP)
00583       res = ast_answer(chan);
00584    if (!res)
00585       res = ast_safe_sleep(chan, 1000);
00586 
00587    if (!res) {
00588       if (sense == FEATURE_SENSE_CHAN) {
00589          res = ast_park_call(parkee, parker, 0, NULL);
00590          if (!res) {
00591             if (sense == FEATURE_SENSE_CHAN) {
00592                res = AST_PBX_NO_HANGUP_PEER_PARKED;
00593             } else {
00594                res = AST_PBX_KEEPALIVE;
00595             }
00596          }
00597       }
00598       else if (sense == FEATURE_SENSE_PEER) {
00599          masq_park_call_announce(parkee, parker, 0, NULL);
00600          res = 0; /* PBX should hangup zombie channel */
00601       }
00602    }
00603 
00604    ast_module_user_remove(u);
00605    return res;
00606 
00607 }
00608 
00609 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00610 {
00611    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00612    int x = 0;
00613    size_t len;
00614    struct ast_channel *caller_chan, *callee_chan;
00615 
00616    if (!monitor_ok) {
00617       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00618       return -1;
00619    }
00620 
00621    if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
00622       monitor_ok = 0;
00623       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00624       return -1;
00625    }
00626 
00627    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00628 
00629    if (!ast_strlen_zero(courtesytone)) {
00630       if (ast_autoservice_start(callee_chan))
00631          return -1;
00632       if (ast_stream_and_wait(caller_chan, courtesytone, caller_chan->language, "")) {
00633          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00634          ast_autoservice_stop(callee_chan);
00635          return -1;
00636       }
00637       if (ast_autoservice_stop(callee_chan))
00638          return -1;
00639    }
00640    
00641    if (callee_chan->monitor) {
00642       if (option_verbose > 3)
00643          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
00644       ast_monitor_stop(callee_chan, 1);
00645       return FEATURE_RETURN_SUCCESS;
00646    }
00647 
00648    if (caller_chan && callee_chan) {
00649       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00650       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00651 
00652       if (!touch_format)
00653          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00654 
00655       if (!touch_monitor)
00656          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00657    
00658       if (touch_monitor) {
00659          len = strlen(touch_monitor) + 50;
00660          args = alloca(len);
00661          touch_filename = alloca(len);
00662          snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
00663          snprintf(args, len, "%s|%s|m", (touch_format) ? touch_format : "wav", touch_filename);
00664       } else {
00665          caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
00666          callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
00667          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00668          args = alloca(len);
00669          touch_filename = alloca(len);
00670          snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
00671          snprintf(args, len, "%s|%s|m", S_OR(touch_format, "wav"), touch_filename);
00672       }
00673 
00674       for( x = 0; x < strlen(args); x++) {
00675          if (args[x] == '/')
00676             args[x] = '-';
00677       }
00678       
00679       if (option_verbose > 3)
00680          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
00681 
00682       pbx_exec(callee_chan, monitor_app, args);
00683       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00684       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
00685    
00686       return FEATURE_RETURN_SUCCESS;
00687    }
00688    
00689    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
00690    return -1;
00691 }
00692 
00693 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00694 {
00695    if (option_verbose > 3)
00696       ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00697    return FEATURE_RETURN_HANGUP;
00698 }
00699 
00700 static int finishup(struct ast_channel *chan)
00701 {
00702         ast_indicate(chan, AST_CONTROL_UNHOLD);
00703   
00704         return ast_autoservice_stop(chan);
00705 }
00706 
00707 /*! \brief Find the context for the transfer */
00708 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
00709 {
00710         const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
00711         if (ast_strlen_zero(s))
00712                 s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
00713         if (ast_strlen_zero(s)) /* Use the non-macro context to transfer the call XXX ? */
00714                 s = transferer->macrocontext;
00715         if (ast_strlen_zero(s))
00716                 s = transferer->context;
00717         return s;  
00718 }
00719 
00720 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00721 {
00722    struct ast_channel *transferer;
00723    struct ast_channel *transferee;
00724    const char *transferer_real_context;
00725    char xferto[256];
00726    int res;
00727 
00728    set_peers(&transferer, &transferee, peer, chan, sense);
00729    transferer_real_context = real_ctx(transferer, transferee);
00730    /* Start autoservice on chan while we talk to the originator */
00731    ast_autoservice_start(transferee);
00732    ast_indicate(transferee, AST_CONTROL_HOLD);
00733 
00734    memset(xferto, 0, sizeof(xferto));
00735    
00736    /* Transfer */
00737    res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00738    if (res < 0) {
00739       finishup(transferee);
00740       return -1; /* error ? */
00741    }
00742    if (res > 0)   /* If they've typed a digit already, handle it */
00743       xferto[0] = (char) res;
00744 
00745    ast_stopstream(transferer);
00746    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00747    if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
00748       finishup(transferee);
00749       return res;
00750    }
00751    if (!strcmp(xferto, ast_parking_ext())) {
00752       res = finishup(transferee);
00753       if (res)
00754          res = -1;
00755       else if (!ast_park_call(transferee, transferer, 0, NULL)) { /* success */
00756          /* We return non-zero, but tell the PBX not to hang the channel when
00757             the thread dies -- We have to be careful now though.  We are responsible for 
00758             hanging up the channel, else it will never be hung up! */
00759          return (transferer == peer) ? AST_PBX_KEEPALIVE : AST_PBX_NO_HANGUP_PEER_PARKED;
00760       } else {
00761          ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
00762       }
00763       /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
00764    } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00765       pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
00766       pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
00767       res=finishup(transferee);
00768       if (!transferer->cdr) {
00769          transferer->cdr=ast_cdr_alloc();
00770          if (transferer) {
00771             ast_cdr_init(transferer->cdr, transferer); /* initilize our channel's cdr */
00772             ast_cdr_start(transferer->cdr);
00773          }
00774       }
00775       if (transferer->cdr) {
00776          ast_cdr_setdestchan(transferer->cdr, transferee->name);
00777          ast_cdr_setapp(transferer->cdr, "BLINDTRANSFER","");
00778       }
00779       if (!transferee->pbx) {
00780          /* Doh!  Use our handy async_goto functions */
00781          if (option_verbose > 2) 
00782             ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
00783                         ,transferee->name, xferto, transferer_real_context);
00784          if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
00785             ast_log(LOG_WARNING, "Async goto failed :-(\n");
00786          res = -1;
00787       } else {
00788          /* Set the channel's new extension, since it exists, using transferer context */
00789          set_c_e_p(transferee, transferer_real_context, xferto, 0);
00790       }
00791       check_goto_on_transfer(transferer);
00792       return res;
00793    } else {
00794       if (option_verbose > 2) 
00795          ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
00796    }
00797    if (ast_stream_and_wait(transferer, xferfailsound, transferer->language, AST_DIGIT_ANY) < 0 ) {
00798       finishup(transferee);
00799       return -1;
00800    }
00801    ast_stopstream(transferer);
00802    res = finishup(transferee);
00803    if (res) {
00804       if (option_verbose > 1)
00805          ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
00806       return res;
00807    }
00808    return FEATURE_RETURN_SUCCESS;
00809 }
00810 
00811 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
00812 {
00813    if (ast_channel_make_compatible(c, newchan) < 0) {
00814       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
00815          c->name, newchan->name);
00816       ast_hangup(newchan);
00817       return -1;
00818    }
00819    return 0;
00820 }
00821 
00822 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00823 {
00824    struct ast_channel *transferer;
00825    struct ast_channel *transferee;
00826    const char *transferer_real_context;
00827    char xferto[256] = "";
00828    int res;
00829    int outstate=0;
00830    struct ast_channel *newchan;
00831    struct ast_channel *xferchan;
00832    struct ast_bridge_thread_obj *tobj;
00833    struct ast_bridge_config bconfig;
00834    struct ast_frame *f;
00835    int l;
00836    struct ast_datastore *features_datastore;
00837    struct ast_dial_features *dialfeatures = NULL;
00838 
00839    if (option_debug)
00840       ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
00841    set_peers(&transferer, &transferee, peer, chan, sense);
00842         transferer_real_context = real_ctx(transferer, transferee);
00843    /* Start autoservice on chan while we talk to the originator */
00844    ast_autoservice_start(transferee);
00845    ast_indicate(transferee, AST_CONTROL_HOLD);
00846    
00847    /* Transfer */
00848    res = ast_stream_and_wait(transferer, "pbx-transfer", transferer->language, AST_DIGIT_ANY);
00849    if (res < 0) {
00850       finishup(transferee);
00851       return res;
00852    }
00853    if (res > 0) /* If they've typed a digit already, handle it */
00854       xferto[0] = (char) res;
00855 
00856    /* this is specific of atxfer */
00857    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
00858         if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
00859                 finishup(transferee);
00860                 return res;
00861         }
00862    if (res == 0) {
00863       ast_log(LOG_WARNING, "Did not read data.\n");
00864       finishup(transferee);
00865       if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00866          return -1;
00867       return FEATURE_RETURN_SUCCESS;
00868    }
00869 
00870    /* valid extension, res == 1 */
00871    if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
00872       ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
00873       finishup(transferee);
00874       if (ast_stream_and_wait(transferer, "beeperr", transferer->language, ""))
00875          return -1;
00876       return FEATURE_RETURN_SUCCESS;
00877    }
00878 
00879    l = strlen(xferto);
00880    snprintf(xferto + l, sizeof(xferto) - l, "@%s", transferer_real_context);  /* append context */
00881    newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
00882       xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, transferer->language);
00883 
00884    /* If we are the callee and we are being transferred, after the masquerade
00885    * caller features will really be the original callee features */
00886    ast_channel_lock(transferee);
00887    if ((features_datastore = ast_channel_datastore_find(transferee, &