Sun Aug 15 20:33:30 2010

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

Generated on Sun Aug 15 20:33:30 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7