Thu Apr 8 01:20:58 2010

Asterisk developer's documentation


features.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2008, 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 #include "asterisk.h"
00027 
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 247654 $")
00029 
00030 #include "asterisk/_private.h"
00031 
00032 #include <pthread.h>
00033 #include <sys/time.h>
00034 #include <sys/signal.h>
00035 #include <netinet/in.h>
00036 
00037 #include "asterisk/lock.h"
00038 #include "asterisk/file.h"
00039 #include "asterisk/channel.h"
00040 #include "asterisk/pbx.h"
00041 #include "asterisk/causes.h"
00042 #include "asterisk/module.h"
00043 #include "asterisk/translate.h"
00044 #include "asterisk/app.h"
00045 #include "asterisk/say.h"
00046 #include "asterisk/features.h"
00047 #include "asterisk/musiconhold.h"
00048 #include "asterisk/config.h"
00049 #include "asterisk/cli.h"
00050 #include "asterisk/manager.h"
00051 #include "asterisk/utils.h"
00052 #include "asterisk/adsi.h"
00053 #include "asterisk/devicestate.h"
00054 #include "asterisk/monitor.h"
00055 #include "asterisk/audiohook.h"
00056 #include "asterisk/global_datastores.h"
00057 #include "asterisk/astobj2.h"
00058 
00059 #define DEFAULT_PARK_TIME 45000
00060 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
00061 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 1000
00062 #define DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER 15000
00063 #define DEFAULT_PARKINGLOT "default"         /*!< Default parking lot */
00064 #define DEFAULT_ATXFER_DROP_CALL 0
00065 #define DEFAULT_ATXFER_LOOP_DELAY 10000
00066 #define DEFAULT_ATXFER_CALLBACK_RETRIES 2
00067 
00068 #define AST_MAX_WATCHERS 256
00069 #define MAX_DIAL_FEATURE_OPTIONS 30
00070 
00071 struct feature_group_exten {
00072    AST_LIST_ENTRY(feature_group_exten) entry;
00073    AST_DECLARE_STRING_FIELDS(
00074       AST_STRING_FIELD(exten);
00075    );
00076    struct ast_call_feature *feature;
00077 };
00078 
00079 struct feature_group {
00080    AST_LIST_ENTRY(feature_group) entry;
00081    AST_DECLARE_STRING_FIELDS(
00082       AST_STRING_FIELD(gname);
00083    );
00084    AST_LIST_HEAD_NOLOCK(, feature_group_exten) features;
00085 };
00086 
00087 static AST_RWLIST_HEAD_STATIC(feature_groups, feature_group);
00088 
00089 static char *parkedcall = "ParkedCall";
00090 
00091 static char pickup_ext[AST_MAX_EXTENSION];                 /*!< Call pickup extension */
00092 
00093 /*! \brief Description of one parked call, added to a list while active, then removed.
00094    The list belongs to a parkinglot 
00095 */
00096 struct parkeduser {
00097    struct ast_channel *chan;                   /*!< Parking channel */
00098    struct timeval start;                       /*!< Time the parking started */
00099    int parkingnum;                             /*!< Parking lot */
00100    char parkingexten[AST_MAX_EXTENSION];       /*!< If set beforehand, parking extension used for this call */
00101    char context[AST_MAX_CONTEXT];              /*!< Where to go if our parking time expires */
00102    char exten[AST_MAX_EXTENSION];
00103    int priority;
00104    int parkingtime;                            /*!< Maximum length in parking lot before return */
00105    unsigned int notquiteyet:1;
00106    unsigned int options_specified:1;
00107    char peername[1024];
00108    unsigned char moh_trys;
00109    struct ast_parkinglot *parkinglot;
00110    AST_LIST_ENTRY(parkeduser) list;
00111 };
00112 
00113 /*! \brief Structure for parking lots which are put in a container. */
00114 struct ast_parkinglot {
00115    char name[AST_MAX_CONTEXT];
00116    char parking_con[AST_MAX_EXTENSION];      /*!< Context for which parking is made accessible */
00117    char parking_con_dial[AST_MAX_EXTENSION]; /*!< Context for dialback for parking (KLUDGE) */
00118    int parking_start;            /*!< First available extension for parking */
00119    int parking_stop;          /*!< Last available extension for parking */
00120    int parking_offset;
00121    int parkfindnext;
00122    int parkingtime;           /*!< Default parking time */
00123    char mohclass[MAX_MUSICCLASS];                  /*!< Music class used for parking */
00124    int parkaddhints;                               /*!< Add parking hints automatically */
00125    int parkedcalltransfers;                        /*!< Enable DTMF based transfers on bridge when picking up parked calls */
00126    int parkedcallreparking;                        /*!< Enable DTMF based parking on bridge when picking up parked calls */
00127    int parkedcallhangup;                           /*!< Enable DTMF based hangup on a bridge when pickup up parked calls */
00128    int parkedcallrecording;                        /*!< Enable DTMF based recording on a bridge when picking up parked calls */
00129    AST_LIST_HEAD(parkinglot_parklist, parkeduser) parkings; /*!< List of active parkings in this parkinglot */
00130 };
00131 
00132 /*! \brief The list of parking lots configured. Always at least one  - the default parking lot */
00133 static struct ao2_container *parkinglots;
00134  
00135 struct ast_parkinglot *default_parkinglot;
00136 char parking_ext[AST_MAX_EXTENSION];            /*!< Extension you type to park the call */
00137 
00138 static char courtesytone[256];                             /*!< Courtesy tone */
00139 static int parkedplay = 0;                                 /*!< Who to play the courtesy tone to */
00140 static char xfersound[256];                                /*!< Call transfer sound */
00141 static char xferfailsound[256];                            /*!< Call transfer failure sound */
00142 
00143 static int adsipark;
00144 
00145 static int transferdigittimeout;
00146 static int featuredigittimeout;
00147 static int comebacktoorigin = 1;
00148 
00149 static int atxfernoanswertimeout;
00150 static unsigned int atxferdropcall;
00151 static unsigned int atxferloopdelay;
00152 static unsigned int atxfercallbackretries;
00153 
00154 static char *registrar = "features";         /*!< Registrar for operations */
00155 
00156 /* module and CLI command definitions */
00157 static char *synopsis = "Answer a parked call";
00158 
00159 static char *descrip = "ParkedCall(exten): "
00160 "Used to connect to a parked call.  This application is always\n"
00161 "registered internally and does not need to be explicitly added\n"
00162 "into the dialplan, although you should include the 'parkedcalls'\n"
00163 "context.  If no extension is provided, then the first available\n"
00164 "parked call will be acquired.\n";
00165 
00166 static char *parkcall = PARK_APP_NAME;
00167 
00168 static char *synopsis2 = "Park yourself";
00169 
00170 static char *descrip2 = 
00171 "   Park([timeout,[return_context,[return_exten,[return_priority,[options]]]]]):"
00172 "Used to park yourself (typically in combination with a supervised\n"
00173 "transfer to know the parking space). This application is always\n"
00174 "registered internally and does not need to be explicitly added\n"
00175 "into the dialplan, although you should include the 'parkedcalls'\n"
00176 "context (or the context specified in features.conf).\n\n"
00177 "If you set the PARKINGEXTEN variable to an extension in your\n"
00178 "parking context, Park() will park the call on that extension, unless\n"
00179 "it already exists. In that case, execution will continue at next\n"
00180 "priority.\n"
00181 "   This application can accept arguments as well.\n"
00182 " timeout - A custom parking timeout for this parked call.\n"
00183 " return_context - The context to return the call to after it times out.\n"
00184 " return_exten - The extension to return the call to after it times out.\n"
00185 " return_priority - The priority to return the call to after it times out.\n"
00186 " options - A list of options for this parked call.  Valid options are:\n"
00187 "    'r' - Send ringing instead of MOH to the parked call.\n"
00188 "    'R' - Randomize the selection of a parking space.\n"
00189 "    's' - Silence announcement of the parking space number.\n"
00190 "";
00191 
00192 static struct ast_app *monitor_app = NULL;
00193 static int monitor_ok = 1;
00194 
00195 static struct ast_app *mixmonitor_app = NULL;
00196 static int mixmonitor_ok = 1;
00197 
00198 static struct ast_app *stopmixmonitor_app = NULL;
00199 static int stopmixmonitor_ok = 1;
00200 
00201 static pthread_t parking_thread;
00202 struct ast_dial_features {
00203    struct ast_flags features_caller;
00204    struct ast_flags features_callee;
00205    int is_caller;
00206 };
00207 
00208 static void *dial_features_duplicate(void *data)
00209 {
00210    struct ast_dial_features *df = data, *df_copy;
00211  
00212    if (!(df_copy = ast_calloc(1, sizeof(*df)))) {
00213       return NULL;
00214    }
00215  
00216    memcpy(df_copy, df, sizeof(*df));
00217  
00218    return df_copy;
00219  }
00220  
00221  static void dial_features_destroy(void *data)
00222  {
00223    struct ast_dial_features *df = data;
00224    if (df) {
00225       ast_free(df);
00226    }
00227  }
00228  
00229  const struct ast_datastore_info dial_features_info = {
00230    .type = "dial-features",
00231    .destroy = dial_features_destroy,
00232    .duplicate = dial_features_duplicate,
00233  };
00234  
00235 /* Forward declarations */
00236 static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot);
00237 static void parkinglot_unref(struct ast_parkinglot *parkinglot);
00238 static void parkinglot_destroy(void *obj);
00239 int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *fs, int *max);
00240 struct ast_parkinglot *find_parkinglot(const char *name);
00241 
00242 
00243 const char *ast_parking_ext(void)
00244 {
00245    return parking_ext;
00246 }
00247 
00248 const char *ast_pickup_ext(void)
00249 {
00250    return pickup_ext;
00251 }
00252 
00253 struct ast_bridge_thread_obj 
00254 {
00255    struct ast_bridge_config bconfig;
00256    struct ast_channel *chan;
00257    struct ast_channel *peer;
00258    unsigned int return_to_pbx:1;
00259 };
00260 
00261 static int parkinglot_hash_cb(const void *obj, const int flags)
00262 {
00263    const struct ast_parkinglot *parkinglot = obj;
00264 
00265    return ast_str_case_hash(parkinglot->name);
00266 }
00267 
00268 static int parkinglot_cmp_cb(void *obj, void *arg, int flags)
00269 {
00270    struct ast_parkinglot *parkinglot = obj, *parkinglot2 = arg;
00271 
00272    return !strcasecmp(parkinglot->name, parkinglot2->name) ? CMP_MATCH | CMP_STOP : 0;
00273 }
00274 
00275 /*!
00276  * \brief store context, extension and priority 
00277  * \param chan, context, ext, pri
00278 */
00279 static void set_c_e_p(struct ast_channel *chan, const char *context, const char *ext, int pri)
00280 {
00281    ast_copy_string(chan->context, context, sizeof(chan->context));
00282    ast_copy_string(chan->exten, ext, sizeof(chan->exten));
00283    chan->priority = pri;
00284 }
00285 
00286 /*!
00287  * \brief Check goto on transfer
00288  * \param chan
00289  *
00290  * Check if channel has 'GOTO_ON_BLINDXFR' set, if not exit.
00291  * When found make sure the types are compatible. Check if channel is valid
00292  * if so start the new channel else hangup the call. 
00293 */
00294 static void check_goto_on_transfer(struct ast_channel *chan) 
00295 {
00296    struct ast_channel *xferchan;
00297    const char *val = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00298    char *x, *goto_on_transfer;
00299    struct ast_frame *f;
00300 
00301    if (ast_strlen_zero(val))
00302       return;
00303 
00304    goto_on_transfer = ast_strdupa(val);
00305 
00306    if (!(xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "%s", chan->name)))
00307       return;
00308 
00309    for (x = goto_on_transfer; x && *x; x++) {
00310       if (*x == '^')
00311          *x = '|';
00312    }
00313    /* Make formats okay */
00314    xferchan->readformat = chan->readformat;
00315    xferchan->writeformat = chan->writeformat;
00316    ast_channel_masquerade(xferchan, chan);
00317    ast_parseable_goto(xferchan, goto_on_transfer);
00318    xferchan->_state = AST_STATE_UP;
00319    ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00320    xferchan->_softhangup = 0;
00321    if ((f = ast_read(xferchan))) {
00322       ast_frfree(f);
00323       f = NULL;
00324       ast_pbx_start(xferchan);
00325    } else {
00326       ast_hangup(xferchan);
00327    }
00328 }
00329 
00330 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, struct ast_channel *transferee, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, int igncallerstate, const char *language);
00331 
00332 /*!
00333  * \brief bridge the call 
00334  * \param data thread bridge.
00335  *
00336  * Set Last Data for respective channels, reset cdr for channels
00337  * bridge call, check if we're going back to dialplan
00338  * if not hangup both legs of the call
00339 */
00340 static void *ast_bridge_call_thread(void *data)
00341 {
00342    struct ast_bridge_thread_obj *tobj = data;
00343    int res;
00344 
00345    tobj->chan->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00346    tobj->chan->data = tobj->peer->name;
00347    tobj->peer->appl = !tobj->return_to_pbx ? "Transferred Call" : "ManagerBridge";
00348    tobj->peer->data = tobj->chan->name;
00349 
00350    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00351 
00352    if (tobj->return_to_pbx) {
00353       if (!ast_check_hangup(tobj->peer)) {
00354          ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", tobj->peer->name);
00355          res = ast_pbx_start(tobj->peer);
00356          if (res != AST_PBX_SUCCESS)
00357             ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", tobj->peer->name);
00358       } else
00359          ast_hangup(tobj->peer);
00360       if (!ast_check_hangup(tobj->chan)) {
00361          ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", tobj->chan->name);
00362          res = ast_pbx_start(tobj->chan);
00363          if (res != AST_PBX_SUCCESS)
00364             ast_log(LOG_WARNING, "FAILED continuing PBX on chan %s\n", tobj->chan->name);
00365       } else
00366          ast_hangup(tobj->chan);
00367    } else {
00368       ast_hangup(tobj->chan);
00369       ast_hangup(tobj->peer);
00370    }
00371 
00372    ast_free(tobj);
00373 
00374    return NULL;
00375 }
00376 
00377 /*!
00378  * \brief create thread for the parked call
00379  * \param data
00380  *
00381  * Create thread and attributes, call ast_bridge_call_thread
00382 */
00383 static void ast_bridge_call_thread_launch(void *data) 
00384 {
00385    pthread_t thread;
00386    pthread_attr_t attr;
00387    struct sched_param sched;
00388 
00389    pthread_attr_init(&attr);
00390    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00391    ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00392    pthread_attr_destroy(&attr);
00393    memset(&sched, 0, sizeof(sched));
00394    pthread_setschedparam(thread, SCHED_RR, &sched);
00395 }
00396 
00397 /*!
00398  * \brief Announce call parking by ADSI
00399  * \param chan .
00400  * \param parkingexten .
00401  * Create message to show for ADSI, display message.
00402  * \retval 0 on success.
00403  * \retval -1 on failure.
00404 */
00405 static int adsi_announce_park(struct ast_channel *chan, char *parkingexten)
00406 {
00407    int res;
00408    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00409    char tmp[256];
00410    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00411 
00412    snprintf(tmp, sizeof(tmp), "Parked on %s", parkingexten);
00413    message[0] = tmp;
00414    res = ast_adsi_load_session(chan, NULL, 0, 1);
00415    if (res == -1)
00416       return res;
00417    return ast_adsi_print(chan, message, justify, 1);
00418 }
00419 
00420 /*! \brief Find parking lot name from channel */
00421 static const char *findparkinglotname(struct ast_channel *chan)
00422 {
00423    const char *temp, *parkinglot = NULL;
00424 
00425    /* Check if the channel has a parking lot */
00426    if (!ast_strlen_zero(chan->parkinglot))
00427       parkinglot = chan->parkinglot;
00428 
00429    /* Channel variables override everything */
00430 
00431    if ((temp  = pbx_builtin_getvar_helper(chan, "PARKINGLOT")))
00432       return temp;
00433 
00434    return parkinglot;
00435 }
00436 
00437 /*! \brief Notify metermaids that we've changed an extension */
00438 static void notify_metermaids(const char *exten, char *context, enum ast_device_state state)
00439 {
00440    ast_debug(4, "Notification of state change to metermaids %s@%s\n to state '%s'", 
00441       exten, context, devstate2str(state));
00442 
00443    ast_devstate_changed(state, "park:%s@%s", exten, context);
00444 }
00445 
00446 /*! \brief metermaids callback from devicestate.c */
00447 static enum ast_device_state metermaidstate(const char *data)
00448 {
00449    char *context;
00450    char *exten;
00451 
00452    context = ast_strdupa(data);
00453 
00454    exten = strsep(&context, "@");
00455    if (!context)
00456       return AST_DEVICE_INVALID;
00457    
00458    ast_debug(4, "Checking state of exten %s in context %s\n", exten, context);
00459 
00460    if (!ast_exists_extension(NULL, context, exten, 1, NULL))
00461       return AST_DEVICE_NOT_INUSE;
00462 
00463    return AST_DEVICE_INUSE;
00464 }
00465 
00466 /*! Options to pass to ast_park_call_full */
00467 enum ast_park_call_options {
00468    /*! Provide ringing to the parked caller instead of music on hold */
00469    AST_PARK_OPT_RINGING =   (1 << 0),
00470    /*! Randomly choose a parking spot for the caller instead of choosing
00471     *  the first one that is available. */
00472    AST_PARK_OPT_RANDOMIZE = (1 << 1),
00473    /*! Do not announce the parking number */
00474    AST_PARK_OPT_SILENCE = (1 << 2),
00475 };
00476 
00477 struct ast_park_call_args {
00478    /*! How long to wait in the parking lot before the call gets sent back
00479     *  to the specified return extension (or a best guess at where it came
00480     *  from if not explicitly specified). */
00481    int timeout;
00482    /*! An output parameter to store the parking space where the parked caller
00483     *  was placed. */
00484    int *extout;
00485    const char *orig_chan_name;
00486    const char *return_con;
00487    const char *return_ext;
00488    int return_pri;
00489    uint32_t flags;
00490    /*! Parked user that has already obtained a parking space */
00491    struct parkeduser *pu;
00492 };
00493 
00494 static struct parkeduser *park_space_reserve(struct ast_channel *chan,
00495  struct ast_channel *peer, struct ast_park_call_args *args)
00496 {
00497    struct parkeduser *pu;
00498    int i, parking_space = -1, parking_range;
00499    const char *parkinglotname = NULL;
00500    const char *parkingexten;
00501    struct ast_parkinglot *parkinglot = NULL;
00502    
00503    if (peer)
00504       parkinglotname = findparkinglotname(peer);
00505 
00506    if (parkinglotname) {
00507       if (option_debug)
00508          ast_log(LOG_DEBUG, "Found chanvar Parkinglot: %s\n", parkinglotname);
00509       parkinglot = find_parkinglot(parkinglotname);   
00510    }
00511    if (!parkinglot) {
00512       parkinglot = parkinglot_addref(default_parkinglot);
00513    }
00514 
00515    if (option_debug)
00516       ast_log(LOG_DEBUG, "Parkinglot: %s\n", parkinglot->name);
00517 
00518    /* Allocate memory for parking data */
00519    if (!(pu = ast_calloc(1, sizeof(*pu)))) {
00520       parkinglot_unref(parkinglot);
00521       return NULL;
00522    }
00523 
00524    /* Lock parking list */
00525    AST_LIST_LOCK(&parkinglot->parkings);
00526    /* Check for channel variable PARKINGEXTEN */
00527    ast_channel_lock(chan);
00528    parkingexten = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "PARKINGEXTEN"), ""));
00529    ast_channel_unlock(chan);
00530    if (!ast_strlen_zero(parkingexten)) {
00531       /*!\note The API forces us to specify a numeric parking slot, even
00532        * though the architecture would tend to support non-numeric extensions
00533        * (as are possible with SIP, for example).  Hence, we enforce that
00534        * limitation here.  If extout was not numeric, we could permit
00535        * arbitrary non-numeric extensions.
00536        */
00537         if (sscanf(parkingexten, "%30d", &parking_space) != 1 || parking_space < 0) {
00538          AST_LIST_UNLOCK(&parkinglot->parkings);
00539          parkinglot_unref(parkinglot);
00540             free(pu);
00541             ast_log(LOG_WARNING, "PARKINGEXTEN does not indicate a valid parking slot: '%s'.\n", parkingexten);
00542             return NULL;
00543         }
00544         snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
00545 
00546       if (ast_exists_extension(NULL, parkinglot->parking_con, pu->parkingexten, 1, NULL)) {
00547          ast_log(LOG_WARNING, "Requested parking extension already exists: %s@%s\n", parkingexten, parkinglot->parking_con);
00548          AST_LIST_UNLOCK(&parkinglot->parkings);
00549          parkinglot_unref(parkinglot);
00550          ast_free(pu);
00551          return NULL;
00552       }
00553    } else {
00554       int start;
00555       struct parkeduser *cur = NULL;
00556 
00557       /* Select parking space within range */
00558       parking_range = parkinglot->parking_stop - parkinglot->parking_start + 1;
00559 
00560       if (ast_test_flag(args, AST_PARK_OPT_RANDOMIZE)) {
00561          start = ast_random() % (parkinglot->parking_stop - parkinglot->parking_start + 1);
00562       } else {
00563          start = parkinglot->parking_start;
00564       }
00565 
00566       for (i = start; 1; i++) {
00567          if (i == parkinglot->parking_stop + 1) {
00568             i = parkinglot->parking_start - 1;
00569             break;
00570          }
00571 
00572          AST_LIST_TRAVERSE(&parkinglot->parkings, cur, list) {
00573             if (cur->parkingnum == i) {
00574                break;
00575             }
00576          }
00577          if (!cur) {
00578             parking_space = i;
00579             break;
00580          }
00581       }
00582 
00583       if (i == start - 1 && cur) {
00584          ast_log(LOG_WARNING, "No more parking spaces\n");
00585          ast_free(pu);
00586          AST_LIST_UNLOCK(&parkinglot->parkings);
00587          parkinglot_unref(parkinglot);
00588          return NULL;
00589       }
00590       /* Set pointer for next parking */
00591       if (parkinglot->parkfindnext) 
00592          parkinglot->parking_offset = parking_space - parkinglot->parking_start + 1;
00593       snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", parking_space);
00594    }
00595 
00596    pu->notquiteyet = 1;
00597    pu->parkingnum = parking_space;
00598    pu->parkinglot = parkinglot_addref(parkinglot);
00599    AST_LIST_INSERT_TAIL(&parkinglot->parkings, pu, list);
00600    parkinglot_unref(parkinglot);
00601 
00602    return pu;
00603 }
00604 
00605 /* Park a call */
00606 static int ast_park_call_full(struct ast_channel *chan, struct ast_channel *peer, struct ast_park_call_args *args)
00607 {
00608    struct ast_context *con;
00609    int parkingnum_copy;
00610    struct parkeduser *pu = args->pu;
00611    const char *event_from;
00612 
00613    if (pu == NULL)
00614       pu = park_space_reserve(chan, peer, args);
00615    if (pu == NULL)
00616       return 1; /* Continue execution if possible */
00617 
00618    snprintf(pu->parkingexten, sizeof(pu->parkingexten), "%d", pu->parkingnum);
00619    
00620    chan->appl = "Parked Call";
00621    chan->data = NULL; 
00622 
00623    pu->chan = chan;
00624    
00625    /* Put the parked channel on hold if we have two different channels */
00626    if (chan != peer) {
00627       if (ast_test_flag(args, AST_PARK_OPT_RINGING)) {
00628          ast_indicate(pu->chan, AST_CONTROL_RINGING);
00629       } else {
00630          ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00631             S_OR(pu->parkinglot->mohclass, NULL),
00632             !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0);
00633       }
00634    }
00635    
00636    pu->start = ast_tvnow();
00637    pu->parkingtime = (args->timeout > 0) ? args->timeout : pu->parkinglot->parkingtime;
00638    parkingnum_copy = pu->parkingnum;
00639    if (args->extout)
00640       *(args->extout) = pu->parkingnum;
00641 
00642    if (peer) { 
00643       /* This is so ugly that it hurts, but implementing get_base_channel() on local channels
00644          could have ugly side effects.  We could have transferer<->local,1<->local,2<->parking
00645          and we need the callback name to be that of transferer.  Since local,1/2 have the same
00646          name we can be tricky and just grab the bridged channel from the other side of the local
00647       */
00648       if (!strcasecmp(peer->tech->type, "Local")) {
00649          struct ast_channel *tmpchan, *base_peer;
00650          char other_side[AST_CHANNEL_NAME];
00651          char *c;
00652          ast_copy_string(other_side, S_OR(args->orig_chan_name, peer->name), sizeof(other_side));
00653          if ((c = strrchr(other_side, ';'))) {
00654             *++c = '1';
00655          }
00656          if ((tmpchan = ast_get_channel_by_name_locked(other_side))) {
00657             if ((base_peer = ast_bridged_channel(tmpchan))) {
00658                ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
00659             }
00660             ast_channel_unlock(tmpchan);
00661          }
00662       } else {
00663          ast_copy_string(pu->peername, S_OR(args->orig_chan_name, peer->name), sizeof(pu->peername));
00664       }
00665    }
00666 
00667    /* Remember what had been dialed, so that if the parking
00668       expires, we try to come back to the same place */
00669 
00670    pu->options_specified = (!ast_strlen_zero(args->return_con) || !ast_strlen_zero(args->return_ext) || args->return_pri);
00671 
00672    /* If extension has options specified, they override all other possibilities
00673    such as the returntoorigin flag and transferred context. Information on
00674    extension options is lost here, so we set a flag */
00675 
00676    ast_copy_string(pu->context, 
00677       S_OR(args->return_con, S_OR(chan->macrocontext, chan->context)), 
00678       sizeof(pu->context));
00679    ast_copy_string(pu->exten, 
00680       S_OR(args->return_ext, S_OR(chan->macroexten, chan->exten)), 
00681       sizeof(pu->exten));
00682    pu->priority = args->return_pri ? args->return_pri : 
00683       (chan->macropriority ? chan->macropriority : chan->priority);
00684 
00685    /* If parking a channel directly, don't quiet yet get parking running on it.
00686     * All parking lot entries are put into the parking lot with notquiteyet on. */
00687    if (peer != chan) 
00688       pu->notquiteyet = 0;
00689 
00690    /* Wake up the (presumably select()ing) thread */
00691    pthread_kill(parking_thread, SIGURG);
00692    ast_verb(2, "Parked %s on %d (lot %s). Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
00693 
00694    if (peer) {
00695       event_from = peer->name;
00696    } else {
00697       event_from = pbx_builtin_getvar_helper(chan, "BLINDTRANSFER");
00698    }
00699 
00700    manager_event(EVENT_FLAG_CALL, "ParkedCall",
00701       "Exten: %s\r\n"
00702       "Channel: %s\r\n"
00703       "Parkinglot: %s\r\n"
00704       "From: %s\r\n"
00705       "Timeout: %ld\r\n"
00706       "CallerIDNum: %s\r\n"
00707       "CallerIDName: %s\r\n"
00708       "Uniqueid: %s\r\n",
00709       pu->parkingexten, pu->chan->name, pu->parkinglot->name, event_from ? event_from : "",
00710       (long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL),
00711       S_OR(pu->chan->cid.cid_num, "<unknown>"),
00712       S_OR(pu->chan->cid.cid_name, "<unknown>"),
00713       pu->chan->uniqueid
00714       );
00715 
00716    if (peer && adsipark && ast_adsi_available(peer)) {
00717       adsi_announce_park(peer, pu->parkingexten);  /* Only supports parking numbers */
00718       ast_adsi_unload_session(peer);
00719    }
00720 
00721    con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con, registrar);
00722    if (!con)   /* Still no context? Bad */
00723       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con);
00724    if (con) {
00725       if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, ast_strdup(pu->parkingexten), ast_free_ptr, registrar))
00726          notify_metermaids(pu->parkingexten, pu->parkinglot->parking_con, AST_DEVICE_INUSE);
00727    }
00728 
00729    AST_LIST_UNLOCK(&pu->parkinglot->parkings);
00730 
00731    /* Only say number if it's a number and the channel hasn't been masqueraded away */
00732    if (peer && !ast_test_flag(args, AST_PARK_OPT_SILENCE) && (ast_strlen_zero(args->orig_chan_name) || !strcasecmp(peer->name, args->orig_chan_name))) {
00733       /* If a channel is masqueraded into peer while playing back the parking slot number do not continue playing it back. This is the case if an attended transfer occurs. */
00734       ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00735       /* Tell the peer channel the number of the parking space */
00736       ast_say_digits(peer, pu->parkingnum, "", peer->language);
00737       ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
00738    }
00739    if (peer == chan) { /* pu->notquiteyet = 1 */
00740       /* Wake up parking thread if we're really done */
00741       ast_indicate_data(pu->chan, AST_CONTROL_HOLD, 
00742          S_OR(pu->parkinglot->mohclass, NULL),
00743          !ast_strlen_zero(pu->parkinglot->mohclass) ? strlen(pu->parkinglot->mohclass) + 1 : 0);
00744       pu->notquiteyet = 0;
00745       pthread_kill(parking_thread, SIGURG);
00746    }
00747    return 0;
00748 }
00749 
00750 /*! \brief Park a call */
00751 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
00752 {
00753    struct ast_park_call_args args = {
00754       .timeout = timeout,
00755       .extout = extout,
00756    };
00757 
00758    return ast_park_call_full(chan, peer, &args);
00759 }
00760 
00761 static int masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout, int play_announcement, struct ast_park_call_args *args)
00762 {
00763    struct ast_channel *chan;
00764    struct ast_frame *f;
00765    int park_status;
00766    struct ast_park_call_args park_args = {0,};
00767 
00768    if (!args) {
00769       args = &park_args;
00770       args->timeout = timeout;
00771       args->extout = extout;
00772    }
00773 
00774    if ((args->pu = park_space_reserve(rchan, peer, args)) == NULL) {
00775       if (peer)
00776          ast_stream_and_wait(peer, "beeperr", "");
00777       return AST_FEATURE_RETURN_PARKFAILED;
00778    }
00779 
00780    /* Make a new, fake channel that we'll use to masquerade in the real one */
00781    if (!(chan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, rchan->accountcode, rchan->exten, rchan->context, rchan->amaflags, "Parked/%s",rchan->name))) {
00782       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00783       return -1;
00784    }
00785 
00786    /* Make formats okay */
00787    chan->readformat = rchan->readformat;
00788    chan->writeformat = rchan->writeformat;
00789    ast_channel_masquerade(chan, rchan);
00790 
00791    /* Setup the extensions and such */
00792    set_c_e_p(chan, rchan->context, rchan->exten, rchan->priority);
00793 
00794    /* Setup the macro extension and such */
00795    ast_copy_string(chan->macrocontext,rchan->macrocontext,sizeof(chan->macrocontext));
00796    ast_copy_string(chan->macroexten,rchan->macroexten,sizeof(chan->macroexten));
00797    chan->macropriority = rchan->macropriority;
00798 
00799    /* Make the masq execute */
00800    if ((f = ast_read(chan)))
00801       ast_frfree(f);
00802 
00803    if (peer == rchan) {
00804       peer = chan;
00805    }
00806 
00807    if (peer && (!play_announcement && args == &park_args)) {
00808       args->orig_chan_name = ast_strdupa(peer->name);
00809    }
00810 
00811    park_status = ast_park_call_full(chan, peer, args);
00812    if (park_status == 1) {
00813    /* would be nice to play "invalid parking extension" */
00814       ast_hangup(chan);
00815       return -1;
00816    }
00817 
00818    return 0;
00819 }
00820 
00821 /* Park call via masquraded channel */
00822 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
00823 {
00824    return masq_park_call(rchan, peer, timeout, extout, 0, NULL);
00825 }
00826 
00827 static int masq_park_call_announce_args(struct ast_channel *rchan, struct ast_channel *peer, struct ast_park_call_args *args)
00828 {
00829    return masq_park_call(rchan, peer, 0, NULL, 1, args);
00830 }
00831 
00832 static int masq_park_call_announce(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
00833 {
00834    return masq_park_call(rchan, peer, timeout, extout, 1, NULL);
00835 }
00836 
00837 /*! 
00838  * \brief set caller and callee according to the direction 
00839  * \param caller, callee, peer, chan, sense
00840  *
00841  * Detect who triggered feature and set callee/caller variables accordingly
00842 */
00843 static void set_peers(struct ast_channel **caller, struct ast_channel **callee,
00844    struct ast_channel *peer, struct ast_channel *chan, int sense)
00845 {
00846    if (sense == FEATURE_SENSE_PEER) {
00847       *caller = peer;
00848       *callee = chan;
00849    } else {
00850       *callee = peer;
00851       *caller = chan;
00852    }
00853 }
00854 
00855 /*! 
00856  * \brief support routing for one touch call parking
00857  * \param chan channel parking call
00858  * \param peer channel to be parked
00859  * \param config unsed
00860  * \param code unused
00861  * \param sense feature options
00862  *
00863  * \param data
00864  * Setup channel, set return exten,priority to 's,1'
00865  * answer chan, sleep chan, park call
00866 */
00867 static int builtin_parkcall(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00868 {
00869    struct ast_channel *parker;
00870    struct ast_channel *parkee;
00871    int res = 0;
00872 
00873    set_peers(&parker, &parkee, peer, chan, sense);
00874    /* we used to set chan's exten and priority to "s" and 1
00875       here, but this generates (in some cases) an invalid
00876       extension, and if "s" exists, could errantly
00877       cause execution of extensions you don't expect. It
00878       makes more sense to let nature take its course
00879       when chan finishes, and let the pbx do its thing
00880       and hang up when the park is over.
00881    */
00882    if (chan->_state != AST_STATE_UP)
00883       res = ast_answer(chan);
00884    if (!res)
00885       res = ast_safe_sleep(chan, 1000);
00886 
00887    if (!res) { /* one direction used to call park_call.... */
00888       res = masq_park_call_announce(parkee, parker, 0, NULL);
00889       /* PBX should hangup zombie channel if a masquerade actually occurred (res=0) */
00890    }
00891 
00892    return res;
00893 }
00894 
00895 /*! \brief Play message to both caller and callee in bridged call, plays synchronously, autoservicing the
00896    other channel during the message, so please don't use this for very long messages
00897  */
00898 static int play_message_in_bridged_call(struct ast_channel *caller_chan, struct ast_channel *callee_chan, const char *audiofile)
00899 {
00900    /* First play for caller, put other channel on auto service */
00901    if (ast_autoservice_start(callee_chan))
00902       return -1;
00903    if (ast_stream_and_wait(caller_chan, audiofile, "")) {
00904       ast_log(LOG_WARNING, "Failed to play automon message!\n");
00905       ast_autoservice_stop(callee_chan);
00906       return -1;
00907    }
00908    if (ast_autoservice_stop(callee_chan))
00909       return -1;
00910    /* Then play for callee, put other channel on auto service */
00911    if (ast_autoservice_start(caller_chan))
00912       return -1;
00913    if (ast_stream_and_wait(callee_chan, audiofile, "")) {
00914       ast_log(LOG_WARNING, "Failed to play automon message !\n");
00915       ast_autoservice_stop(caller_chan);
00916       return -1;
00917    }
00918    if (ast_autoservice_stop(caller_chan))
00919       return -1;
00920    return(0);
00921 }
00922 
00923 /*!
00924  * \brief Monitor a channel by DTMF
00925  * \param chan channel requesting monitor
00926  * \param peer channel to be monitored
00927  * \param config
00928  * \param code
00929  * \param sense feature options
00930  *
00931  * \param data
00932  * Check monitor app enabled, setup channels, both caller/callee chans not null
00933  * get TOUCH_MONITOR variable for filename if exists, exec monitor app.
00934  * \retval AST_FEATURE_RETURN_SUCCESS on success.
00935  * \retval -1 on error.
00936 */
00937 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
00938 {
00939    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
00940    int x = 0;
00941    size_t len;
00942    struct ast_channel *caller_chan, *callee_chan;
00943    const char *automon_message_start = NULL;
00944    const char *automon_message_stop = NULL;
00945 
00946    if (!monitor_ok) {
00947       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00948       return -1;
00949    }
00950 
00951    if (!monitor_app && !(monitor_app = pbx_findapp("Monitor"))) {
00952       monitor_ok = 0;
00953       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00954       return -1;
00955    }
00956 
00957    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
00958    if (caller_chan) {   /* Find extra messages */
00959       automon_message_start = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_START");
00960       automon_message_stop = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_MESSAGE_STOP");
00961    }
00962 
00963    if (!ast_strlen_zero(courtesytone)) {  /* Play courtesy tone if configured */
00964       if(play_message_in_bridged_call(caller_chan, callee_chan, courtesytone) == -1) {
00965          return -1;
00966       }
00967    }
00968    
00969    if (callee_chan->monitor) {
00970       ast_verb(4, "User hit '%s' to stop recording call.\n", code);
00971       if (!ast_strlen_zero(automon_message_stop)) {
00972          play_message_in_bridged_call(caller_chan, callee_chan, automon_message_stop);
00973       }
00974       callee_chan->monitor->stop(callee_chan, 1);
00975       return AST_FEATURE_RETURN_SUCCESS;
00976    }
00977 
00978    if (caller_chan && callee_chan) {
00979       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00980       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00981       const char *touch_monitor_prefix = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_PREFIX");
00982 
00983       if (!touch_format)
00984          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00985 
00986       if (!touch_monitor)
00987          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00988    
00989       if (!touch_monitor_prefix)
00990          touch_monitor_prefix = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_PREFIX");
00991    
00992       if (touch_monitor) {
00993          len = strlen(touch_monitor) + 50;
00994          args = alloca(len);
00995          touch_filename = alloca(len);
00996          snprintf(touch_filename, len, "%s-%ld-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), touch_monitor);
00997          snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
00998       } else {
00999          caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
01000          callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
01001          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
01002          args = alloca(len);
01003          touch_filename = alloca(len);
01004          snprintf(touch_filename, len, "%s-%ld-%s-%s", S_OR(touch_monitor_prefix, "auto"), (long)time(NULL), caller_chan_id, callee_chan_id);
01005          snprintf(args, len, "%s,%s,m", S_OR(touch_format, "wav"), touch_filename);
01006       }
01007 
01008       for(x = 0; x < strlen(args); x++) {
01009          if (args[x] == '/')
01010             args[x] = '-';
01011       }
01012       
01013       ast_verb(4, "User hit '%s' to record call. filename: %s\n", code, args);
01014 
01015       pbx_exec(callee_chan, monitor_app, args);
01016       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
01017       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MONITOR_OUTPUT", touch_filename);
01018 
01019       if (!ast_strlen_zero(automon_message_start)) {  /* Play start message for both channels */
01020          play_message_in_bridged_call(caller_chan, callee_chan, automon_message_start);
01021       }
01022    
01023       return AST_FEATURE_RETURN_SUCCESS;
01024    }
01025    
01026    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
01027    return -1;
01028 }
01029 
01030 static int builtin_automixmonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
01031 {
01032    char *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_filename = NULL;
01033    int x = 0;
01034    size_t len;
01035    struct ast_channel *caller_chan, *callee_chan;
01036    const char *mixmonitor_spy_type = "MixMonitor";
01037    int count = 0;
01038 
01039    if (!mixmonitor_ok) {
01040       ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
01041       return -1;
01042    }
01043 
01044    if (!(mixmonitor_app = pbx_findapp("MixMonitor"))) {
01045       mixmonitor_ok = 0;
01046       ast_log(LOG_ERROR,"Cannot record the call. The mixmonitor application is disabled.\n");
01047       return -1;
01048    }
01049 
01050    set_peers(&caller_chan, &callee_chan, peer, chan, sense);
01051 
01052    if (!ast_strlen_zero(courtesytone)) {
01053       if (ast_autoservice_start(callee_chan))
01054          return -1;
01055       if (ast_stream_and_wait(caller_chan, courtesytone, "")) {
01056          ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01057          ast_autoservice_stop(callee_chan);
01058          return -1;
01059       }
01060       if (ast_autoservice_stop(callee_chan))
01061          return -1;
01062    }
01063 
01064    ast_channel_lock(callee_chan);
01065    count = ast_channel_audiohook_count_by_source(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
01066    ast_channel_unlock(callee_chan);
01067 
01068    /* This means a mixmonitor is attached to the channel, running or not is unknown. */
01069    if (count > 0) {
01070       
01071       ast_verb(3, "User hit '%s' to stop recording call.\n", code);
01072 
01073       /* Make sure they are running */
01074       ast_channel_lock(callee_chan);
01075       count = ast_channel_audiohook_count_by_source_running(callee_chan, mixmonitor_spy_type, AST_AUDIOHOOK_TYPE_SPY);
01076       ast_channel_unlock(callee_chan);
01077       if (count > 0) {
01078          if (!stopmixmonitor_ok) {
01079             ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
01080             return -1;
01081          }
01082          if (!(stopmixmonitor_app = pbx_findapp("StopMixMonitor"))) {
01083             stopmixmonitor_ok = 0;
01084             ast_log(LOG_ERROR,"Cannot stop recording the call. The stopmixmonitor application is disabled.\n");
01085             return -1;
01086          } else {
01087             pbx_exec(callee_chan, stopmixmonitor_app, "");
01088             return AST_FEATURE_RETURN_SUCCESS;
01089          }
01090       }
01091       
01092       ast_log(LOG_WARNING,"Stopped MixMonitors are attached to the channel.\n"); 
01093    }        
01094 
01095    if (caller_chan && callee_chan) {
01096       const char *touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR_FORMAT");
01097       const char *touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MIXMONITOR");
01098 
01099       if (!touch_format)
01100          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR_FORMAT");
01101 
01102       if (!touch_monitor)
01103          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MIXMONITOR");
01104 
01105       if (touch_monitor) {
01106          len = strlen(touch_monitor) + 50;
01107          args = alloca(len);
01108          touch_filename = alloca(len);
01109          snprintf(touch_filename, len, "auto-%ld-%s", (long)time(NULL), touch_monitor);
01110          snprintf(args, len, "%s.%s,b", touch_filename, (touch_format) ? touch_format : "wav");
01111       } else {
01112          caller_chan_id = ast_strdupa(S_OR(caller_chan->cid.cid_num, caller_chan->name));
01113          callee_chan_id = ast_strdupa(S_OR(callee_chan->cid.cid_num, callee_chan->name));
01114          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
01115          args = alloca(len);
01116          touch_filename = alloca(len);
01117          snprintf(touch_filename, len, "auto-%ld-%s-%s", (long)time(NULL), caller_chan_id, callee_chan_id);
01118          snprintf(args, len, "%s.%s,b", touch_filename, S_OR(touch_format, "wav"));
01119       }
01120 
01121       for( x = 0; x < strlen(args); x++) {
01122          if (args[x] == '/')
01123             args[x] = '-';
01124       }
01125 
01126       ast_verb(3, "User hit '%s' to record call. filename: %s\n", code, touch_filename);
01127 
01128       pbx_exec(callee_chan, mixmonitor_app, args);
01129       pbx_builtin_setvar_helper(callee_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
01130       pbx_builtin_setvar_helper(caller_chan, "TOUCH_MIXMONITOR_OUTPUT", touch_filename);
01131       return AST_FEATURE_RETURN_SUCCESS;
01132    
01133    }
01134 
01135    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");
01136    return -1;
01137 
01138 }
01139 
01140 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
01141 {
01142    ast_verb(4, "User hit '%s' to disconnect call.\n", code);
01143    return AST_FEATURE_RETURN_HANGUP;
01144 }
01145 
01146 static int finishup(struct ast_channel *chan)
01147 {
01148    ast_indicate(chan, AST_CONTROL_UNHOLD);
01149 
01150    return ast_autoservice_stop(chan);
01151 }
01152 
01153 /*!
01154  * \brief Find the context for the transfer
01155  * \param transferer
01156  * \param transferee
01157  * 
01158  * Grab the TRANSFER_CONTEXT, if fails try grabbing macrocontext.
01159  * \return a context string
01160 */
01161 static const char *real_ctx(struct ast_channel *transferer, struct ast_channel *transferee)
01162 {
01163    const char *s = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT");
01164    if (ast_strlen_zero(s)) {
01165       s = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT");
01166    }
01167    if (ast_strlen_zero(s)) { /* Use the non-macro context to transfer the call XXX ? */
01168       s = transferer->macrocontext;
01169    }
01170    if (ast_strlen_zero(s)) {
01171       s = transferer->context;
01172    }
01173    return s;  
01174 }
01175 
01176 /*!
01177  * \brief Blind transfer user to another extension
01178  * \param chan channel to be transfered
01179  * \param peer channel initiated blind transfer
01180  * \param config
01181  * \param code
01182  * \param data
01183  * \param sense  feature options
01184  * 
01185  * Place chan on hold, check if transferred to parkinglot extension,
01186  * otherwise check extension exists and transfer caller.
01187  * \retval AST_FEATURE_RETURN_SUCCESS.
01188  * \retval -1 on failure.
01189 */
01190 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
01191 {
01192    struct ast_channel *transferer;
01193    struct ast_channel *transferee;
01194    const char *transferer_real_context;
01195    char xferto[256];
01196    int res, parkstatus = 0;
01197 
01198    set_peers(&transferer, &transferee, peer, chan, sense);
01199    transferer_real_context = real_ctx(transferer, transferee);
01200    /* Start autoservice on chan while we talk to the originator */
01201    ast_autoservice_start(transferee);
01202    ast_indicate(transferee, AST_CONTROL_HOLD);
01203 
01204    memset(xferto, 0, sizeof(xferto));
01205 
01206    /* Transfer */
01207    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
01208    if (res < 0) {
01209       finishup(transferee);
01210       return -1; /* error ? */
01211    }
01212    if (res > 0)   /* If they've typed a digit already, handle it */
01213       xferto[0] = (char) res;
01214 
01215    ast_stopstream(transferer);
01216    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
01217    if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
01218       finishup(transferee);
01219       return res;
01220    }
01221    if (!strcmp(xferto, ast_parking_ext())) {
01222       res = finishup(transferee);
01223       if (res)
01224          res = -1;
01225       else if (!(parkstatus = masq_park_call_announce(transferee, transferer, 0, NULL))) {   /* success */
01226          /* We return non-zero, but tell the PBX not to hang the channel when
01227             the thread dies -- We have to be careful now though.  We are responsible for 
01228             hanging up the channel, else it will never be hung up! */
01229 
01230          return 0;
01231       } else {
01232          ast_log(LOG_WARNING, "Unable to park call %s, parkstatus = %d\n", transferee->name, parkstatus);
01233       }
01234       /*! \todo XXX Maybe we should have another message here instead of invalid extension XXX */
01235    } else if (ast_exists_extension(transferee, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
01236       pbx_builtin_setvar_helper(transferer, "BLINDTRANSFER", transferee->name);
01237       pbx_builtin_setvar_helper(transferee, "BLINDTRANSFER", transferer->name);
01238       res=finishup(transferee);
01239       if (!transferer->cdr) { /* this code should never get called (in a perfect world) */
01240          transferer->cdr=ast_cdr_alloc();
01241          if (transferer->cdr) {
01242             ast_cdr_init(transferer->cdr, transferer); /* initialize our channel's cdr */
01243             ast_cdr_start(transferer->cdr);
01244          }
01245       }
01246       if (transferer->cdr) {
01247          struct ast_cdr *swap = transferer->cdr;
01248          ast_log(LOG_DEBUG,"transferer=%s; transferee=%s; lastapp=%s; lastdata=%s; chan=%s; dstchan=%s\n",
01249                transferer->name, transferee->name, transferer->cdr->lastapp, transferer->cdr->lastdata, 
01250                transferer->cdr->channel, transferer->cdr->dstchannel);
01251          ast_log(LOG_DEBUG,"TRANSFEREE; lastapp=%s; lastdata=%s, chan=%s; dstchan=%s\n",
01252                transferee->cdr->lastapp, transferee->cdr->lastdata, transferee->cdr->channel, transferee->cdr->dstchannel);
01253          ast_log(LOG_DEBUG,"transferer_real_context=%s; xferto=%s\n", transferer_real_context, xferto);
01254          /* swap cdrs-- it will save us some time & work */
01255          transferer->cdr = transferee->cdr;
01256          transferee->cdr = swap;
01257       }
01258       if (!transferee->pbx) {
01259          /* Doh!  Use our handy async_goto functions */
01260          ast_verb(3, "Transferring %s to '%s' (context %s) priority 1\n"
01261                         ,transferee->name, xferto, transferer_real_context);
01262          if (ast_async_goto(transferee, transferer_real_context, xferto, 1))
01263             ast_log(LOG_WARNING, "Async goto failed :-(\n");
01264       } else {
01265          /* Set the channel's new extension, since it exists, using transferer context */
01266          ast_set_flag(transferee, AST_FLAG_BRIDGE_HANGUP_DONT); /* don't let the after-bridge code run the h-exten */
01267          ast_log(LOG_DEBUG,"ABOUT TO AST_ASYNC_GOTO, have a pbx... set HANGUP_DONT on chan=%s\n", transferee->name);
01268          set_c_e_p(transferee, transferer_real_context, xferto, 0);
01269       }
01270       check_goto_on_transfer(transferer);
01271       return res;
01272    } else {
01273       ast_verb(3, "Unable to find extension '%s' in context '%s'\n", xferto, transferer_real_context);
01274    }
01275    if (parkstatus != AST_FEATURE_RETURN_PARKFAILED && ast_stream_and_wait(transferer, xferfailsound, AST_DIGIT_ANY) < 0) {
01276       finishup(transferee);
01277       return -1;
01278    }
01279    ast_stopstream(transferer);
01280    res = finishup(transferee);
01281    if (res) {
01282       ast_verb(2, "Hungup during autoservice stop on '%s'\n", transferee->name);
01283       return res;
01284    }
01285    return AST_FEATURE_RETURN_SUCCESS;
01286 }
01287 
01288 /*!
01289  * \brief make channels compatible
01290  * \param c
01291  * \param newchan
01292  * \retval 0 on success.
01293  * \retval -1 on failure.
01294 */
01295 static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
01296 {
01297    if (ast_channel_make_compatible(c, newchan) < 0) {
01298       ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
01299          c->name, newchan->name);
01300       ast_hangup(newchan);
01301       return -1;
01302    }
01303    return 0;
01304 }
01305 
01306 /*!
01307  * \brief Attended transfer
01308  * \param chan transfered user
01309  * \param peer person transfering call
01310  * \param config
01311  * \param code
01312  * \param sense feature options
01313  * 
01314  * \param data
01315  * Get extension to transfer to, if you cannot generate channel (or find extension) 
01316  * return to host channel. After called channel answered wait for hangup of transferer,
01317  * bridge call between transfer peer (taking them off hold) to attended transfer channel.
01318  *
01319  * \return -1 on failure
01320 */
01321 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
01322 {
01323    struct ast_channel *transferer;
01324    struct ast_channel *transferee;
01325    const char *transferer_real_context;
01326    char xferto[256] = "";
01327    int res;
01328    int outstate=0;
01329    struct ast_channel *newchan;
01330    struct ast_channel *xferchan;
01331    struct ast_bridge_thread_obj *tobj;
01332    struct ast_bridge_config bconfig;
01333    struct ast_frame *f;
01334    int l;
01335    struct ast_datastore *features_datastore;
01336    struct ast_dial_features *dialfeatures = NULL;
01337 
01338    ast_debug(1, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
01339    set_peers(&transferer, &transferee, peer, chan, sense);
01340    transferer_real_context = real_ctx(transferer, transferee);
01341    /* Start autoservice on chan while we talk to the originator */
01342    ast_autoservice_start(transferee);
01343    ast_indicate(transferee, AST_CONTROL_HOLD);
01344    
01345    /* Transfer */
01346    res = ast_stream_and_wait(transferer, "pbx-transfer", AST_DIGIT_ANY);
01347    if (res < 0) {
01348       finishup(transferee);
01349       return res;
01350    }
01351    if (res > 0) /* If they've typed a digit already, handle it */
01352       xferto[0] = (char) res;
01353 
01354    /* this is specific of atxfer */
01355    res = ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout);
01356    if (res < 0) {  /* hangup, would be 0 for invalid and 1 for valid */
01357       finishup(transferee);
01358       return res;
01359    }
01360    if (res == 0) {
01361       ast_log(LOG_WARNING, "Did not read data.\n");
01362       finishup(transferee);
01363       if (ast_stream_and_wait(transferer, "beeperr", ""))
01364          return -1;
01365       return AST_FEATURE_RETURN_SUCCESS;
01366    }
01367 
01368    /* valid extension, res == 1 */
01369    if (!ast_exists_extension(transferer, transferer_real_context, xferto, 1, transferer->cid.cid_num)) {
01370       ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
01371       finishup(transferee);
01372       if (ast_stream_and_wait(transferer, "beeperr", ""))
01373          return -1;
01374       return AST_FEATURE_RETURN_SUCCESS;
01375    }
01376 
01377    /* If we are attended transfering to parking, just use builtin_parkcall instead of trying to track all of
01378     * the different variables for handling this properly with a builtin_atxfer */
01379    if (!strcmp(xferto, ast_parking_ext())) {
01380       finishup(transferee);
01381       return builtin_parkcall(chan, peer, config, code, sense, data);
01382    }
01383 
01384    l = strlen(xferto);
01385    snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context);   /* append context */
01386 
01387    /* If we are performing an attended transfer and we have two channels involved then
01388       copy sound file information to play upon attended transfer completion */
01389    if (transferee) {
01390       const char *chan1_attended_sound = pbx_builtin_getvar_helper(transferer, "ATTENDED_TRANSFER_COMPLETE_SOUND");
01391       const char *chan2_attended_sound = pbx_builtin_getvar_helper(transferee, "ATTENDED_TRANSFER_COMPLETE_SOUND");
01392 
01393       if (!ast_strlen_zero(chan1_attended_sound)) {
01394          pbx_builtin_setvar_helper(transferer, "BRIDGE_PLAY_SOUND", chan1_attended_sound);
01395       }
01396       if (!ast_strlen_zero(chan2_attended_sound)) {
01397          pbx_builtin_setvar_helper(transferee, "BRIDGE_PLAY_SOUND", chan2_attended_sound);
01398       }
01399    }
01400 
01401    newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
01402       xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language);
01403 
01404    if (!ast_check_hangup(transferer)) {
01405       /* Transferer is up - old behaviour */
01406       ast_indicate(transferer, -1);
01407       if (!newchan) {
01408          finishup(transferee);
01409          /* any reason besides user requested cancel and busy triggers the failed sound */
01410          if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
01411             ast_stream_and_wait(transferer, xferfailsound, ""))
01412             return -1;
01413          if (ast_stream_and_wait(transferer, xfersound, ""))
01414             ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01415          return AST_FEATURE_RETURN_SUCCESS;
01416       }
01417 
01418       if (check_compat(transferer, newchan)) {
01419          /* we do mean transferee here, NOT transferer */
01420          finishup(transferee);
01421          return -1;
01422       }
01423       memset(&bconfig,0,sizeof(struct ast_bridge_config));
01424       ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
01425       ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
01426       res = ast_bridge_call(transferer, newchan, &bconfig);
01427       if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
01428          ast_hangup(newchan);
01429          if (ast_stream_and_wait(transferer, xfersound, ""))
01430             ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01431          finishup(transferee);
01432          transferer->_softhangup = 0;
01433          return AST_FEATURE_RETURN_SUCCESS;
01434       }
01435       if (check_compat(transferee, newchan)) {
01436          finishup(transferee);
01437          return -1;
01438       }
01439       ast_indicate(transferee, AST_CONTROL_UNHOLD);
01440 
01441       if ((ast_autoservice_stop(transferee) < 0)
01442        || (ast_waitfordigit(transferee, 100) < 0)
01443        || (ast_waitfordigit(newchan, 100) < 0)
01444        || ast_check_hangup(transferee)
01445        || ast_check_hangup(newchan)) {
01446          ast_hangup(newchan);
01447          return -1;
01448       }
01449       xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
01450       if (!xferchan) {
01451          ast_hangup(newchan);
01452          return -1;
01453       }
01454       /* Make formats okay */
01455       xferchan->visible_indication = transferer->visible_indication;
01456       xferchan->readformat = transferee->readformat;
01457       xferchan->writeformat = transferee->writeformat;
01458       ast_channel_masquerade(xferchan, transferee);
01459       ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
01460       xferchan->_state = AST_STATE_UP;
01461       ast_clear_flag(xferchan, AST_FLAGS_ALL);
01462       xferchan->_softhangup = 0;
01463       if ((f = ast_read(xferchan)))
01464          ast_frfree(f);
01465       newchan->_state = AST_STATE_UP;
01466       ast_clear_flag(newchan, AST_FLAGS_ALL);
01467       newchan->_softhangup = 0;
01468       if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
01469          ast_hangup(xferchan);
01470          ast_hangup(newchan);
01471          return -1;
01472       }
01473 
01474       ast_channel_lock(newchan);
01475       if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
01476             dialfeatures = features_datastore->data;
01477       }
01478       ast_channel_unlock(newchan);
01479 
01480       if (dialfeatures) {
01481          /* newchan should always be the callee and shows up as callee in dialfeatures, but for some reason
01482             I don't currently understand, the abilities of newchan seem to be stored on the caller side */
01483          ast_copy_flags(&(config->features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
01484          dialfeatures = NULL;
01485       }
01486 
01487       ast_channel_lock(xferchan);
01488       if ((features_datastore = ast_channel_datastore_find(xferchan, &dial_features_info, NULL))) {
01489          dialfeatures = features_datastore->data;
01490       }
01491       ast_channel_unlock(xferchan);
01492     
01493       if (dialfeatures) {
01494          ast_copy_flags(&(config->features_caller), &(dialfeatures->features_caller), AST_FLAGS_ALL);
01495       }
01496     
01497       tobj->chan = newchan;
01498       tobj->peer = xferchan;
01499       tobj->bconfig = *config;
01500 
01501       if (tobj->bconfig.end_bridge_callback_data_fixup) {
01502          tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
01503       }
01504 
01505       if (ast_stream_and_wait(newchan, xfersound, ""))
01506          ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01507       ast_bridge_call_thread_launch(tobj);
01508       return -1;      /* XXX meaning the channel is bridged ? */
01509    } else if (!ast_check_hangup(transferee)) {
01510       /* act as blind transfer */
01511       if (ast_autoservice_stop(transferee) < 0) {
01512          ast_hangup(newchan);
01513          return -1;
01514       }
01515 
01516       if (!newchan) {
01517          unsigned int tries = 0;
01518          char *transferer_tech, *transferer_name = ast_strdupa(transferer->name);
01519 
01520          transferer_tech = strsep(&transferer_name, "/");
01521          transferer_name = strsep(&transferer_name, "-");
01522 
01523          if (ast_strlen_zero(transferer_name) || ast_strlen_zero(transferer_tech)) {
01524             ast_log(LOG_WARNING, "Transferer has invalid channel name: '%s'\n", transferer->name);
01525             if (ast_stream_and_wait(transferee, "beeperr", ""))
01526                return -1;
01527             return AST_FEATURE_RETURN_SUCCESS;
01528          }
01529 
01530          ast_log(LOG_NOTICE, "We're trying to call %s/%s\n", transferer_tech, transferer_name);
01531          newchan = ast_feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats),
01532             transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language);
01533          while (!newchan && !atxferdropcall && tries < atxfercallbackretries) {
01534             /* Trying to transfer again */
01535             ast_autoservice_start(transferee);
01536             ast_indicate(transferee, AST_CONTROL_HOLD);
01537 
01538             newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
01539                xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1, transferer->language);
01540             if (ast_autoservice_stop(transferee) < 0) {
01541                if (newchan)
01542                   ast_hangup(newchan);
01543                return -1;
01544             }
01545             if (!newchan) {
01546                /* Transfer failed, sleeping */
01547                ast_debug(1, "Sleeping for %d ms before callback.\n", atxferloopdelay);
01548                ast_safe_sleep(transferee, atxferloopdelay);
01549                ast_debug(1, "Trying to callback...\n");
01550                newchan = ast_feature_request_and_dial(transferee, NULL, transferer_tech, ast_best_codec(transferee->nativeformats),
01551                   transferer_name, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0, transferer->language);
01552             }
01553             tries++;
01554          }
01555       }
01556       if (!newchan)
01557          return -1;
01558 
01559       /* newchan is up, we should prepare transferee and bridge them */
01560       if (check_compat(transferee, newchan)) {
01561          finishup(transferee);
01562          return -1;
01563       }
01564       ast_indicate(transferee, AST_CONTROL_UNHOLD);
01565 
01566       if ((ast_waitfordigit(transferee, 100) < 0)
01567          || (ast_waitfordigit(newchan, 100) < 0)
01568          || ast_check_hangup(transferee)
01569          || ast_check_hangup(newchan)) {
01570          ast_hangup(newchan);
01571          return -1;
01572       }
01573 
01574       xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
01575       if (!xferchan) {
01576          ast_hangup(newchan);
01577          return -1;
01578       }
01579       /* Make formats okay */
01580       xferchan->visible_indication = transferer->visible_indication;
01581       xferchan->readformat = transferee->readformat;
01582       xferchan->writeformat = transferee->writeformat;
01583       ast_channel_masquerade(xferchan, transferee);
01584       ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
01585       xferchan->_state = AST_STATE_UP;
01586       ast_clear_flag(xferchan, AST_FLAGS_ALL);
01587       xferchan->_softhangup = 0;
01588       if ((f = ast_read(xferchan)))
01589          ast_frfree(f);
01590       newchan->_state = AST_STATE_UP;
01591       ast_clear_flag(newchan, AST_FLAGS_ALL);
01592       newchan->_softhangup = 0;
01593       if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
01594          ast_hangup(xferchan);
01595          ast_hangup(newchan);
01596          return -1;
01597       }
01598       tobj->chan = newchan;
01599       tobj->peer = xferchan;
01600       tobj->bconfig = *config;
01601 
01602       if (tobj->bconfig.end_bridge_callback_data_fixup) {
01603          tobj->bconfig.end_bridge_callback_data_fixup(&tobj->bconfig, tobj->peer, tobj->chan);
01604       }
01605 
01606       if (ast_stream_and_wait(newchan, xfersound, ""))
01607          ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
01608       ast_bridge_call_thread_launch(tobj);
01609       return -1;      /* XXX meaning the channel is bridged ? */
01610    } else {
01611       /* Transferee hung up */
01612       finishup(transferee);
01613       return -1;
01614    }
01615 }
01616 
01617 /* add atxfer and automon as undefined so you can only use em if you configure them */
01618 #define FEATURES_COUNT ARRAY_LEN(builtin_features)
01619 
01620 AST_RWLOCK_DEFINE_STATIC(features_lock);
01621 
01622 static struct ast_call_feature builtin_features[] = 
01623 {
01624    { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01625    { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01626    { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01627    { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01628    { AST_FEATURE_PARKCALL, "Park Call", "parkcall", "", "", builtin_parkcall, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01629    { AST_FEATURE_AUTOMIXMON, "One Touch MixMonitor", "automixmon", "", "", builtin_automixmonitor, AST_FEATURE_FLAG_NEEDSDTMF, "" },
01630 };
01631 
01632 
01633 static AST_RWLIST_HEAD_STATIC(feature_list, ast_call_feature);
01634 
01635 /*! \brief register new feature into feature_list*/
01636 void ast_register_feature(struct ast_call_feature *feature)
01637 {
01638    if (!feature) {
01639       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
01640       return;
01641    }
01642   
01643    AST_RWLIST_WRLOCK(&feature_list);
01644    AST_RWLIST_INSERT_HEAD(&feature_list,feature,feature_entry);
01645    AST_RWLIST_UNLOCK(&feature_list);
01646 
01647    ast_verb(2, "Registered Feature '%s'\n",feature->sname);
01648 }
01649 
01650 /*! 
01651  * \brief Add new feature group
01652  * \param fgname feature group name.
01653  *
01654  * Add new feature group to the feature group list insert at head of list.
01655  * \note This function MUST be called while feature_groups is locked.
01656 */
01657 static struct feature_group* register_group(const char *fgname)
01658 {
01659    struct feature_group *fg;
01660 
01661    if (!fgname) {
01662       ast_log(LOG_NOTICE, "You didn't pass a new group name!\n");
01663       return NULL;
01664    }
01665 
01666    if (!(fg = ast_calloc(1, sizeof(*fg))))
01667       return NULL;
01668 
01669    if (ast_string_field_init(fg, 128)) {
01670       ast_free(fg);
01671       return NULL;
01672    }
01673 
01674    ast_string_field_set(fg, gname, fgname);
01675 
01676    AST_LIST_INSERT_HEAD(&feature_groups, fg, entry);
01677 
01678    ast_verb(2, "Registered group '%s'\n", fg->gname);
01679 
01680    return fg;
01681 }
01682 
01683 /*! 
01684  * \brief Add feature to group
01685  * \param fg feature group
01686  * \param exten
01687  * \param feature feature to add.
01688  *
01689  * Check fg and feature specified, add feature to list
01690  * \note This function MUST be called while feature_groups is locked. 
01691 */
01692 static void register_group_feature(struct feature_group *fg, const char *exten, struct ast_call_feature *feature) 
01693 {
01694    struct feature_group_exten *fge;
01695 
01696    if (!fg) {
01697       ast_log(LOG_NOTICE, "You didn't pass a group!\n");
01698       return;
01699    }
01700 
01701    if (!feature) {
01702       ast_log(LOG_NOTICE, "You didn't pass a feature!\n");
01703       return;
01704    }
01705 
01706    if (!(fge = ast_calloc(1, sizeof(*fge))))
01707       return;
01708 
01709    if (ast_string_field_init(fge, 128)) {
01710       ast_free(fge);
01711       return;
01712    }
01713 
01714    ast_string_field_set(fge, exten, S_OR(exten, feature->exten));
01715 
01716    fge->feature = feature;
01717 
01718    AST_LIST_INSERT_HEAD(&fg->features, fge, entry);      
01719 
01720    ast_verb(2, "Registered feature '%s' for group '%s' at exten '%s'\n",
01721                feature->sname, fg->gname, exten);
01722 }
01723 
01724 void ast_unregister_feature(struct ast_call_feature *feature)
01725 {
01726    if (!feature) {
01727       return;
01728    }
01729 
01730    AST_RWLIST_WRLOCK(&feature_list);
01731    AST_RWLIST_REMOVE(&feature_list, feature, feature_entry);
01732    AST_RWLIST_UNLOCK(&feature_list);
01733 
01734    ast_free(feature);
01735 }
01736 
01737 /*! \brief Remove all features in the list */
01738 static void ast_unregister_features(void)
01739 {
01740    struct ast_call_feature *feature;
01741 
01742    AST_RWLIST_WRLOCK(&feature_list);
01743    while ((feature = AST_RWLIST_REMOVE_HEAD(&feature_list, feature_entry))) {
01744       ast_free(feature);
01745    }
01746    AST_RWLIST_UNLOCK(&feature_list);
01747 }
01748 
01749 /*! \brief find a call feature by name */
01750 static struct ast_call_feature *find_dynamic_feature(const char *name)
01751 {
01752    struct ast_call_feature *tmp;
01753 
01754    AST_RWLIST_TRAVERSE(&feature_list, tmp, feature_entry) {
01755       if (!strcasecmp(tmp->sname, name)) {
01756          break;
01757       }
01758    }
01759 
01760    return tmp;
01761 }
01762 
01763 /*! \brief Remove all feature groups in the list */
01764 static void ast_unregister_groups(void)
01765 {
01766    struct feature_group *fg;
01767    struct feature_group_exten *fge;
01768 
01769    AST_RWLIST_WRLOCK(&feature_groups);
01770    while ((fg = AST_LIST_REMOVE_HEAD(&feature_groups, entry))) {
01771       while ((fge = AST_LIST_REMOVE_HEAD(&fg->features, entry))) {
01772          ast_string_field_free_memory(fge);
01773          ast_free(fge);
01774       }
01775 
01776       ast_string_field_free_memory(fg);
01777       ast_free(fg);
01778    }
01779    AST_RWLIST_UNLOCK(&feature_groups);
01780 }
01781 
01782 /*! 
01783  * \brief Find a group by name 
01784  * \param name feature name
01785  * \retval feature group on success.
01786  * \retval NULL on failure.
01787 */
01788 static struct feature_group *find_group(const char *name) {
01789    struct feature_group *fg = NULL;
01790 
01791    AST_LIST_TRAVERSE(&feature_groups, fg, entry) {
01792       if (!strcasecmp(fg->gname, name))
01793          break;
01794    }
01795 
01796    return fg;
01797 }
01798 
01799 void ast_rdlock_call_features(void)
01800 {
01801    ast_rwlock_rdlock(&features_lock);
01802 }
01803 
01804 void ast_unlock_call_features(void)
01805 {
01806    ast_rwlock_unlock(&features_lock);
01807 }
01808 
01809 struct ast_call_feature *ast_find_call_feature(const char *name)
01810 {
01811    int x;
01812    for (x = 0; x < FEATURES_COUNT; x++) {
01813       if (!strcasecmp(name, builtin_features[x].sname))
01814          return &builtin_features[x];
01815    }
01816    return NULL;
01817 }
01818 
01819 /*!
01820  * \brief exec an app by feature 
01821  * \param chan,peer,config,code,sense,data
01822  *
01823  * Find a feature, determine which channel activated
01824  * \retval AST_FEATURE_RETURN_NO_HANGUP_PEER
01825  * \retval -1 error.
01826  * \retval -2 when an application cannot be found.
01827 */
01828 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense, void *data)
01829 {
01830    struct ast_app *app;
01831    struct ast_call_feature *feature = data;
01832    struct ast_channel *work, *idle;
01833    int res;
01834 
01835    if (!feature) { /* shouldn't ever happen! */
01836       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
01837       return -1; 
01838    }
01839 
01840    if (sense == FEATURE_SENSE_CHAN) {
01841       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
01842          return AST_FEATURE_RETURN_KEEPTRYING;
01843       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01844          work = chan;
01845          idle = peer;
01846       } else {
01847          work = peer;
01848          idle = chan;
01849       }
01850    } else {
01851       if (!ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
01852          return AST_FEATURE_RETURN_KEEPTRYING;
01853       if (ast_test_flag(feature, AST_FEATURE_FLAG_ONSELF)) {
01854          work = peer;
01855          idle = chan;
01856       } else {
01857          work = chan;
01858          idle = peer;
01859       }
01860    }
01861 
01862    if (!(app = pbx_findapp(feature->app))) {
01863       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
01864       return -2;
01865    }
01866 
01867    ast_autoservice_start(idle);
01868    
01869    if (!ast_strlen_zero(feature->moh_class))
01870       ast_moh_start(idle, feature->moh_class, NULL);
01871 
01872    res = pbx_exec(work, app, feature->app_args);
01873 
01874    if (!ast_strlen_zero(feature->moh_class))
01875       ast_moh_stop(idle);
01876 
01877    ast_autoservice_stop(idle);
01878 
01879    if (res) {
01880       return AST_FEATURE_RETURN_SUCCESSBREAK;
01881    }
01882    return AST_FEATURE_RETURN_SUCCESS;  /*! \todo XXX should probably return res */
01883 }
01884 
01885 static void unmap_features(void)
01886 {
01887    int x;
01888 
01889    ast_rwlock_wrlock(&features_lock);
01890    for (x = 0; x < FEATURES_COUNT; x++)
01891       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
01892    ast_rwlock_unlock(&features_lock);
01893 }
01894 
01895 static int remap_feature(const char *name, const char *value)
01896 {
01897    int x, res = -1;
01898 
01899    ast_rwlock_wrlock(&features_lock);
01900    for (x = 0; x < FEATURES_COUNT; x++) {
01901       if (strcasecmp(builtin_features[x].sname, name))
01902          continue;
01903 
01904       ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
01905       res = 0;
01906       break;
01907    }
01908    ast_rwlock_unlock(&features_lock);
01909 
01910    return res;
01911 }
01912 
01913 /*!
01914  * \brief Helper function for feature_interpret and ast_feature_detect
01915  * \param chan,peer,config,code,sense,dynamic_features char buf,feature flags,operation,feature
01916  *
01917  * Lock features list, browse for code, unlock list
01918  * If a feature is found and the operation variable is set, that feature's
01919  * operation is executed.  The first feature found is copied to the feature parameter.
01920  * \retval res on success.
01921  * \retval -1 on failure.
01922 */
01923 static int feature_interpret_helper(struct ast_channel *chan, struct ast_channel *peer,
01924    struct ast_bridge_config *config, char *code, int sense, char *dynamic_features_buf,
01925    struct ast_flags *features, int operation, struct ast_call_feature *feature)
01926 {
01927    int x;
01928    struct feature_group *fg = NULL;
01929    struct feature_group_exten *fge;
01930    struct ast_call_feature *tmpfeature;
01931    char *tmp, *tok;
01932    int res = AST_FEATURE_RETURN_PASSDIGITS;
01933    int feature_detected = 0;
01934 
01935    if (!(peer && chan && config) && operation) {
01936       return -1; /* can not run feature operation */
01937    }
01938 
01939    ast_rwlock_rdlock(&features_lock);
01940    for (x = 0; x < FEATURES_COUNT; x++) {
01941       if ((ast_test_flag(features, builtin_features[x].feature_mask)) &&
01942           !ast_strlen_zero(builtin_features[x].exten)) {
01943          /* Feature is up for consideration */
01944          if (!strcmp(builtin_features[x].exten, code)) {
01945             ast_debug(3, "Feature detected: fname=%s sname=%s exten=%s\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
01946             if (operation) {
01947                res = builtin_features[x].operation(chan, peer, config, code, sense, NULL);
01948             }
01949             memcpy(feature, &builtin_features[x], sizeof(feature));
01950             feature_detected = 1;
01951             break;
01952          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01953             if (res == AST_FEATURE_RETURN_PASSDIGITS)
01954                res = AST_FEATURE_RETURN_STOREDIGITS;
01955          }
01956       }
01957    }
01958    ast_rwlock_unlock(&features_lock);
01959 
01960    if (ast_strlen_zero(dynamic_features_buf) || feature_detected) {
01961       return res;
01962    }
01963 
01964    tmp = dynamic_features_buf;
01965 
01966    while ((tok = strsep(&tmp, "#"))) {
01967       AST_RWLIST_RDLOCK(&feature_groups);
01968 
01969       fg = find_group(tok);
01970 
01971       if (fg) {
01972          AST_LIST_TRAVERSE(&fg->features, fge, entry) {
01973             if (strcasecmp(fge->exten, code))
01974                continue;
01975             if (operation) {
01976                res = fge->feature->operation(chan, peer, config, code, sense, fge->feature);
01977             }
01978             memcpy(feature, fge->feature, sizeof(feature));
01979             if (res != AST_FEATURE_RETURN_KEEPTRYING) {
01980                AST_RWLIST_UNLOCK(&feature_groups);
01981                break;
01982             }
01983             res = AST_FEATURE_RETURN_PASSDIGITS;
01984          }
01985          if (fge)
01986             break;
01987       }
01988 
01989       AST_RWLIST_UNLOCK(&feature_groups);
01990 
01991       AST_RWLIST_RDLOCK(&feature_list);
01992 
01993       if (!(tmpfeature = find_dynamic_feature(tok))) {
01994          AST_RWLIST_UNLOCK(&feature_list);
01995          continue;
01996       }
01997 
01998       /* Feature is up for consideration */
01999       if (!strcmp(tmpfeature->exten, code)) {
02000          ast_verb(3, " Feature Found: %s exten: %s\n",tmpfeature->sname, tok);
02001          if (operation) {
02002             res = tmpfeature->operation(chan, peer, config, code, sense, tmpfeature);
02003          }
02004          memcpy(feature, tmpfeature, sizeof(feature));
02005          if (res != AST_FEATURE_RETURN_KEEPTRYING) {
02006             AST_RWLIST_UNLOCK(&feature_list);
02007             break;
02008          }
02009          res = AST_FEATURE_RETURN_PASSDIGITS;
02010       } else if (!strncmp(tmpfeature->exten, code, strlen(code)))
02011          res = AST_FEATURE_RETURN_STOREDIGITS;
02012 
02013       AST_RWLIST_UNLOCK(&feature_list);
02014    }
02015 
02016    return res;
02017 }
02018 
02019 /*!
02020  * \brief Check the dynamic features
02021  * \param chan,peer,config,code,sense
02022  *
02023  * \retval res on success.
02024  * \retval -1 on failure.
02025 */
02026 
02027 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense) {
02028 
02029    char dynamic_features_buf[128];
02030    const char *peer_dynamic_features, *chan_dynamic_features;
02031    struct ast_flags features;
02032    struct ast_call_feature feature;
02033    if (sense == FEATURE_SENSE_CHAN) {
02034       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);
02035    }
02036    else {
02037       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);
02038    }
02039 
02040    ast_channel_lock(peer);
02041    peer_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(peer, "DYNAMIC_FEATURES"),""));
02042    ast_channel_unlock(peer);
02043 
02044    ast_channel_lock(chan);
02045    chan_dynamic_features = ast_strdupa(S_OR(pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES"),""));
02046    ast_channel_unlock(chan);
02047 
02048    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,""));
02049 
02050    ast_debug(3, "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);
02051 
02052    return feature_interpret_helper(chan, peer, config, code, sense, dynamic_features_buf, &features, 1, &feature);
02053 }
02054 
02055 
02056 int ast_feature_detect(struct ast_channel *chan, struct ast_flags *features, char *code, struct ast_call_feature *feature) {
02057 
02058    return feature_interpret_helper(chan, NULL, NULL, code, 0, NULL, features, 0, feature);
02059 }
02060 
02061 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
02062 {
02063    int x;
02064    
02065    ast_clear_flag(config, AST_FLAGS_ALL);
02066 
02067    ast_rwlock_rdlock(&features_lock);
02068    for (x = 0; x < FEATURES_COUNT; x++) {
02069       if (!ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF))
02070          continue;
02071 
02072       if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
02073          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
02074 
02075       if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
02076          ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
02077    }
02078    ast_rwlock_unlock(&features_lock);
02079    
02080    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
02081       const char *dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
02082 
02083       if (dynamic_features) {
02084          char *tmp = ast_strdupa(dynamic_features);
02085          char *tok;
02086          struct ast_call_feature *feature;
02087 
02088          /* while we have a feature */
02089          while ((tok = strsep(&tmp, "#"))) {
02090             AST_RWLIST_RDLOCK(&feature_list);
02091             if ((feature = find_dynamic_feature(tok)) && ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
02092                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLER))
02093                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
02094                if (ast_test_flag(feature, AST_FEATURE_FLAG_BYCALLEE))
02095                   ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
02096             }
02097             AST_RWLIST_UNLOCK(&feature_list);
02098          }
02099       }
02100    }
02101 }
02102 
02103 /*! 
02104  * \brief Get feature and dial
02105  * \param caller,transferee,type,format,data,timeout,outstate,cid_num,cid_name,igncallerstate
02106  *
02107  * Request channel, set channel variables, initiate call,check if they want to disconnect
02108  * go into loop, check if timeout has elapsed, check if person to be transfered hung up,
02109  * check for answer break loop, set cdr return channel.
02110  *
02111  * \todo XXX Check - this is very similar to the code in channel.c 
02112  * \return always a channel
02113 */
02114 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, struct ast_channel *transferee, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, int igncallerstate, const char *language)
02115 {
02116    int state = 0;
02117    int cause = 0;
02118    int to;
02119    struct ast_channel *chan;
02120    struct ast_channel *monitor_chans[2];
02121    struct ast_channel *active_channel;
02122    int res = 0, ready = 0;
02123 
02124    if ((chan = ast_request(type, format, data, &cause))) {
02125       ast_set_callerid(chan, cid_num, cid_name, cid_num);
02126       ast_string_field_set(chan, language, language);
02127       ast_channel_inherit_variables(caller, chan); 
02128       pbx_builtin_setvar_helper(chan, "TRANSFERERNAME", caller->name);
02129          
02130       if (!ast_call(chan, data, timeout)) {
02131          struct timeval started;
02132          int x, len = 0;
02133          char *disconnect_code = NULL, *dialed_code = NULL;
02134 
02135          ast_indicate(caller, AST_CONTROL_RINGING);
02136          /* support dialing of the featuremap disconnect code while performing an attended tranfer */
02137          ast_rwlock_rdlock(&features_lock);
02138          for (x = 0; x < FEATURES_COUNT; x++) {
02139             if (strcasecmp(builtin_features[x].sname, "disconnect"))
02140                continue;
02141 
02142             disconnect_code = builtin_features[x].exten;
02143             len = strlen(disconnect_code) + 1;
02144             dialed_code = alloca(len);
02145             memset(dialed_code, 0, len);
02146             break;
02147          }
02148          ast_rwlock_unlock(&features_lock);
02149          x = 0;
02150          started = ast_tvnow();
02151          to = timeout;
02152 
02153          ast_poll_channel_add(caller, chan);
02154 
02155          while (!((transferee && ast_check_hangup(transferee)) && (!igncallerstate && ast_check_hangup(caller))) && timeout && (chan->_state != AST_STATE_UP)) {
02156             struct ast_frame *f = NULL;
02157 
02158             monitor_chans[0] = caller;
02159             monitor_chans[1] = chan;
02160             active_channel = ast_waitfor_n(monitor_chans, 2, &to);
02161 
02162             /* see if the timeout has been violated */
02163             if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
02164                state = AST_CONTROL_UNHOLD;
02165                ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
02166                break; /*doh! timeout*/
02167             }
02168 
02169             if (!active_channel)
02170                continue;
02171 
02172             if (chan && (chan == active_channel)) {
02173                if (!ast_strlen_zero(chan->call_forward)) {
02174                   if (!(chan = ast_call_forward(caller, chan, &to, format, NULL, outstate))) {
02175                      return NULL;
02176                   }
02177                   continue;
02178                }
02179                f = ast_read(chan);
02180                if (f == NULL) { /*doh! where'd he go?*/
02181                   state = AST_CONTROL_HANGUP;
02182                   res = 0;
02183                   break;
02184                }
02185                
02186                if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
02187                   if (f->subclass == AST_CONTROL_RINGING) {
02188                      state = f->subclass;
02189                      ast_verb(3, "%s is ringing\n", chan->name);
02190                      ast_indicate(caller, AST_CONTROL_RINGING);
02191                   } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
02192                      state = f->subclass;
02193                      ast_verb(3, "%s is busy\n", chan->name);
02194                      ast_indicate(caller, AST_CONTROL_BUSY);
02195                      ast_frfree(f);
02196                      f = NULL;
02197                      break;
02198                   } else if (f->subclass == AST_CONTROL_ANSWER) {
02199                      /* This is what we are hoping for */
02200                      state = f->subclass;
02201                      ast_frfree(f);
02202                      f = NULL;
02203                      ready=1;
02204                      break;
02205                   } else if (f->subclass != -1 && f->subclass != AST_CONTROL_PROGRESS) {
02206                      ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
02207                   }
02208                   /* else who cares */
02209                } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
02210                   ast_write(caller, f);
02211                }
02212 
02213             } else if (caller && (active_channel == caller)) {
02214                f = ast_read(caller);
02215                if (f == NULL) { /*doh! where'd he go?*/
02216                   if (!igncallerstate) {
02217                      if (ast_check_hangup(caller) && !ast_check_hangup(chan)) {
02218                         /* make this a blind transfer */
02219                         ready = 1;
02220                         break;
02221                      }
02222                      state = AST_CONTROL_HANGUP;
02223                      res = 0;
02224                      break;
02225                   }
02226                } else {
02227                
02228                   if (f->frametype == AST_FRAME_DTMF) {
02229                      dialed_code[x++] = f->subclass;
02230                      dialed_code[x] = '\0';
02231                      if (strlen(dialed_code) == len) {
02232                         x = 0;
02233                      } else if (x && strncmp(dialed_code, disconnect_code, x)) {
02234                         x = 0;
02235                         dialed_code[x] = '\0';
02236                      }
02237                      if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
02238                         /* Caller Canceled the call */
02239                         state = AST_CONTROL_UNHOLD;
02240                         ast_frfree(f);
02241                         f = NULL;
02242                         break;
02243                      }
02244                   }
02245                }
02246             } else if (f->frametype == AST_FRAME_VOICE || f->frametype == AST_FRAME_VIDEO) {
02247                ast_write(chan, f);
02248             }
02249             if (f)
02250                ast_frfree(f);
02251          } /* end while */
02252 
02253          ast_poll_channel_del(caller, chan);
02254 
02255       } else
02256          ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
02257    } else {
02258       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
02259       switch(cause) {
02260       case AST_CAUSE_BUSY:
02261          state = AST_CONTROL_BUSY;
02262          break;
02263       case AST_CAUSE_CONGESTION:
02264          state = AST_CONTROL_CONGESTION;
02265          break;
02266       }
02267    }
02268    
02269    ast_indicate(caller, -1);
02270    if (chan && ready) {
02271       if (chan->_state == AST_STATE_UP) 
02272          state = AST_CONTROL_ANSWER;
02273       res = 0;
02274    } else if(chan) {
02275       res = -1;
02276       ast_hangup(chan);
02277       chan = NULL;
02278    } else {
02279       res = -1;
02280    }
02281    
02282    if (outstate)
02283       *outstate = state;
02284 
02285    return chan;
02286 }
02287 
02288 /*!
02289  * \brief return the first unlocked cdr in a possible chain
02290 */
02291 static struct ast_cdr *pick_unlocked_cdr(struct ast_cdr *cdr)
02292 {
02293    struct ast_cdr *cdr_orig = cdr;
02294    while (cdr) {
02295       if (!ast_test_flag(cdr,AST_CDR_FLAG_LOCKED))
02296          return cdr;
02297       cdr = cdr->next;
02298    }
02299    return cdr_orig; /* everybody LOCKED or some other weirdness, like a NULL */
02300 }
02301 
02302 static void set_bridge_features_on_config(struct ast_bridge_config *config, const char *features)
02303 {
02304    const char *feature;
02305 
02306    if (ast_strlen_zero(features)) {
02307       return;
02308    }
02309 
02310    for (feature = features; *feature; feature++) {
02311       switch (*feature) {
02312       case 'T' :
02313       case 't' :
02314          ast_set_flag(&(config->features_caller), AST_FEATURE_REDIRECT);
02315          break;
02316       case 'K' :
02317       case 'k' :
02318          ast_set_flag(&(config->features_caller), AST_FEATURE_PARKCALL);
02319          break;
02320       case 'H' :
02321       case 'h' :
02322          ast_set_flag(&(config->features_caller), AST_FEATURE_DISCONNECT);
02323          break;
02324       case 'W' :
02325       case 'w' :
02326          ast_set_flag(&(config->features_caller), AST_FEATURE_AUTOMON);
02327          break;
02328       default :
02329          ast_log(LOG_WARNING, "Skipping unknown feature code '%c'\n", *feature);
02330       }
02331    }
02332 }
02333 
02334 static void add_features_datastores(struct ast_channel *caller, struct ast_channel *callee, struct ast_bridge_config *config)
02335 {
02336    struct ast_datastore *ds_callee_features = NULL, *ds_caller_features = NULL;
02337    struct ast_dial_features *callee_features = NULL, *caller_features = NULL;
02338 
02339    ast_channel_lock(caller);
02340    ds_caller_features = ast_channel_datastore_find(caller, &dial_features_info, NULL);
02341    ast_channel_unlock(caller);
02342    if (!ds_caller_features) {
02343       if (!(ds_caller_features = ast_datastore_alloc(&dial_features_info, NULL))) {
02344          ast_log(LOG_WARNING, "Unable to create channel datastore for caller features. Aborting!\n");
02345          return;
02346       }
02347       if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
02348          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
02349          ast_datastore_free(ds_caller_features);
02350          return;
02351       }
02352       ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
02353       caller_features->is_caller = 1;
02354       ast_copy_flags(&(caller_features->features_callee), &(config->features_callee), AST_FLAGS_ALL);
02355       ast_copy_flags(&(caller_features->features_caller), &(config->features_caller), AST_FLAGS_ALL);
02356       ds_caller_features->data = caller_features;
02357       ast_channel_lock(caller);
02358       ast_channel_datastore_add(caller, ds_caller_features);
02359       ast_channel_unlock(caller);
02360    } else {
02361       /* If we don't return here, then when we do a builtin_atxfer we will copy the disconnect
02362        * flags over from the atxfer to the caller */
02363       return;
02364    }
02365 
02366    ast_channel_lock(callee);
02367    ds_callee_features = ast_channel_datastore_find(callee, &dial_features_info, NULL);
02368    ast_channel_unlock(callee);
02369    if (!ds_callee_features) {
02370       if (!(ds_callee_features = ast_datastore_alloc(&dial_features_info, NULL))) {
02371          ast_log(LOG_WARNING, "Unable to create channel datastore for callee features. Aborting!\n");
02372          return;
02373       }
02374       if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
02375          ast_log(LOG_WARNING, "Unable to allocate memory for callee feature flags. Aborting!\n");
02376          ast_datastore_free(ds_callee_features);
02377          return;
02378       }
02379       ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
02380       callee_features->is_caller = 0;
02381       ast_copy_flags(&(callee_features->features_callee), &(config->features_caller), AST_FLAGS_ALL);
02382       ast_copy_flags(&(callee_features->features_caller), &(config->features_callee), AST_FLAGS_ALL);
02383       ds_callee_features->data = callee_features;
02384       ast_channel_lock(callee);
02385       ast_channel_datastore_add(callee, ds_callee_features);
02386       ast_channel_unlock(callee);
02387    }
02388 
02389    return;
02390 }
02391 
02392 /*!
02393  * \brief bridge the call and set CDR
02394  * \param chan,peer,config
02395  * 
02396  * Set start time, check for two channels,check if monitor on
02397  * check for feature activation, create new CDR
02398  * \retval res on success.
02399  * \retval -1 on failure to bridge.
02400 */
02401 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
02402 {
02403    /* Copy voice back and forth between the two channels.  Give the peer
02404       the ability to transfer calls with '#<extension' syntax. */
02405    struct ast_frame *f;
02406    struct ast_channel *who;
02407    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
02408    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
02409    char orig_channame[AST_MAX_EXTENSION];
02410    char orig_peername[AST_MAX_EXTENSION];
02411    int res;
02412    int diff;
02413    int hasfeatures=0;
02414    int hadfeatures=0;
02415    int autoloopflag;
02416    struct ast_option_header *aoh;
02417    struct ast_bridge_config backup_config;
02418    struct ast_cdr *bridge_cdr = NULL;
02419    struct ast_cdr *orig_peer_cdr = NULL;
02420    struct ast_cdr *chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
02421    struct ast_cdr *peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
02422    struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
02423    struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
02424 
02425    memset(&backup_config, 0, sizeof(backup_config));
02426 
02427    config->start_time = ast_tvnow();
02428 
02429    if (chan && peer) {
02430       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
02431       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
02432    } else if (chan) {
02433       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
02434    }
02435 
02436    set_bridge_features_on_config(config, pbx_builtin_getvar_helper(chan, "BRIDGE_FEATURES"));
02437    add_features_datastores(chan, peer, config);
02438 
02439    /* This is an interesting case.  One example is if a ringing channel gets redirected to
02440     * an extension that picks up a parked call.  This will make sure that the call taken
02441     * out of parking gets told that the channel it just got bridged to is still ringing. */
02442    if (chan->_state == AST_STATE_RINGING && peer->visible_indication != AST_CONTROL_RINGING) {
02443       ast_indicate(peer, AST_CONTROL_RINGING);
02444    }
02445 
02446    if (monitor_ok) {
02447       const char *monitor_exec;
02448       struct ast_channel *src = NULL;
02449       if (!monitor_app) { 
02450          if (!(monitor_app = pbx_findapp("Monitor")))
02451             monitor_ok=0;
02452       }
02453       if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
02454          src = chan;
02455       else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
02456          src = peer;
02457       if (monitor_app && src) {
02458          char *tmp = ast_strdupa(monitor_exec);
02459          pbx_exec(src, monitor_app, tmp);
02460       }
02461    }
02462 
02463    set_config_flags(chan, peer, config);
02464    config->firstpass = 1;
02465 
02466    /* Answer if need be */
02467    if (chan->_state != AST_STATE_UP) {
02468       if (ast_raw_answer(chan, 1)) {
02469          return -1;
02470       }
02471    }
02472 
02473    ast_copy_string(orig_channame,chan->name,sizeof(orig_channame));
02474    ast_copy_string(orig_peername,peer->name,sizeof(orig_peername));
02475    orig_peer_cdr = peer_cdr;
02476    
02477    if (!chan_cdr || (chan_cdr && !ast_test_flag(chan_cdr, AST_CDR_FLAG_POST_DISABLED))) {
02478       
02479       if (chan_cdr) {
02480          ast_set_flag(chan_cdr, AST_CDR_FLAG_MAIN);
02481          ast_cdr_update(chan);
02482          bridge_cdr = ast_cdr_dup(chan_cdr);
02483          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
02484          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
02485          if (peer_cdr && !ast_strlen_zero(peer_cdr->userfield)) {
02486             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
02487          }
02488          if (peer_cdr && ast_strlen_zero(peer->accountcode)) {
02489             ast_cdr_setaccount(peer, chan->accountcode);
02490          }
02491 
02492       } else {
02493          /* better yet, in a xfer situation, find out why the chan cdr got zapped (pun unintentional) */
02494          bridge_cdr = ast_cdr_alloc(); /* this should be really, really rare/impossible? */
02495          ast_copy_string(bridge_cdr->channel, chan->name, sizeof(bridge_cdr->channel));
02496          ast_copy_string(bridge_cdr->dstchannel, peer->name, sizeof(bridge_cdr->dstchannel));
02497          ast_copy_string(bridge_cdr->uniqueid, chan->uniqueid, sizeof(bridge_cdr->uniqueid));
02498          ast_copy_string(bridge_cdr->lastapp, S_OR(chan->appl, ""), sizeof(bridge_cdr->lastapp));
02499          ast_copy_string(bridge_cdr->lastdata, S_OR(chan->data, ""), sizeof(bridge_cdr->lastdata));
02500          ast_cdr_setcid(bridge_cdr, chan);
02501          bridge_cdr->disposition = (chan->_state == AST_STATE_UP) ?  AST_CDR_ANSWERED : AST_CDR_NULL;
02502          bridge_cdr->amaflags = chan->amaflags ? chan->amaflags :  ast_default_amaflags;
02503          ast_copy_string(bridge_cdr->accountcode, chan->accountcode, sizeof(bridge_cdr->accountcode));
02504          /* Destination information */
02505          ast_copy_string(bridge_cdr->dst, chan->exten, sizeof(bridge_cdr->dst));
02506          ast_copy_string(bridge_cdr->dcontext, chan->context, sizeof(bridge_cdr->dcontext));
02507          if (peer_cdr) {
02508             bridge_cdr->start = peer_cdr->start;
02509             ast_copy_string(bridge_cdr->userfield, peer_cdr->userfield, sizeof(bridge_cdr->userfield));
02510          } else {
02511             ast_cdr_start(bridge_cdr);
02512          }
02513       }
02514       ast_debug(4,"bridge answer set, chan answer set\n");
02515       /* peer_cdr->answer will be set when a macro runs on the peer;
02516          in that case, the bridge answer will be delayed while the
02517          macro plays on the peer channel. The peer answered the call
02518          before the macro started playing. To the phone system,
02519          this is billable time for the call, even tho the caller
02520          hears nothing but ringing while the macro does its thing. */
02521 
02522       /* Another case where the peer cdr's time will be set, is when
02523          A self-parks by pickup up phone and dialing 700, then B
02524          picks up A by dialing its parking slot; there may be more 
02525          practical paths that get the same result, tho... in which
02526          case you get the previous answer time from the Park... which
02527          is before the bridge's start time, so I added in the 
02528          tvcmp check to the if below */
02529 
02530       if (peer_cdr && !ast_tvzero(peer_cdr->answer) && ast_tvcmp(peer_cdr->answer, bridge_cdr->start) >= 0) {
02531          bridge_cdr->answer = peer_cdr->answer;
02532          bridge_cdr->disposition = peer_cdr->disposition;
02533          if (chan_cdr) {
02534             chan_cdr->answer = peer_cdr->answer;
02535             chan_cdr->disposition = peer_cdr->disposition;
02536          }
02537       } else {
02538          ast_cdr_answer(bridge_cdr);
02539          if (chan_cdr) {
02540             ast_cdr_answer(chan_cdr); /* for the sake of cli status checks */
02541          }
02542       }
02543       if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT) && (chan_cdr || peer_cdr)) {
02544          if (chan_cdr) {
02545             ast_set_flag(chan_cdr, AST_CDR_FLAG_BRIDGED);
02546          }
02547          if (peer_cdr) {
02548             ast_set_flag(peer_cdr, AST_CDR_FLAG_BRIDGED);
02549          }
02550       }
02551    }
02552    for (;;) {
02553       struct ast_channel *other; /* used later */
02554    
02555       res = ast_channel_bridge(chan, peer, config, &f, &who);
02556       
02557       /* When frame is not set, we are probably involved in a situation
02558          where we've timed out.
02559          When frame is set, we'll come this code twice; once for DTMF_BEGIN
02560          and also for DTMF_END. If we flow into the following 'if' for both, then 
02561          our wait times are cut in half, as both will subtract from the
02562          feature_timer. Not good!
02563       */
02564       if (config->feature_timer && (!f || f->frametype == AST_FRAME_DTMF_END)) {
02565          /* Update time limit for next pass */
02566          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
02567          if (res == AST_BRIDGE_RETRY) {
02568             /* The feature fully timed out but has not been updated. Skip
02569              * the potential round error from the diff calculation and
02570              * explicitly set to expired. */
02571             config->feature_timer = -1;
02572          } else {
02573             config->feature_timer -= diff;
02574          }
02575 
02576          if (hasfeatures) {
02577             /* Running on backup config, meaning a feature might be being
02578                activated, but that's no excuse to keep things going 
02579                indefinitely! */
02580             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
02581                ast_debug(1, "Timed out, realtime this time!\n");
02582                config->feature_timer = 0;
02583                who = chan;
02584                if (f)
02585                   ast_frfree(f);
02586                f = NULL;
02587                res = 0;
02588             } else if (config->feature_timer <= 0) {
02589                /* Not *really* out of time, just out of time for
02590                   digits to come in for features. */
02591                ast_debug(1, "Timed out for feature!\n");
02592                if (!ast_strlen_zero(peer_featurecode)) {
02593                   ast_dtmf_stream(chan, peer, peer_featurecode, 0, 0);
02594                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
02595                }
02596                if (!ast_strlen_zero(chan_featurecode)) {
02597                   ast_dtmf_stream(peer, chan, chan_featurecode, 0, 0);
02598                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
02599                }
02600                if (f)
02601                   ast_frfree(f);
02602                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02603                if (!hasfeatures) {
02604                   /* Restore original (possibly time modified) bridge config */
02605                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
02606                   memset(&backup_config, 0, sizeof(backup_config));
02607                }
02608                hadfeatures = hasfeatures;
02609                /* Continue as we were */
02610                continue;
02611             } else if (!f) {
02612                /* The bridge returned without a frame and there is a feature in progress.
02613                 * However, we don't think the feature has quite yet timed out, so just
02614                 * go back into the bridge. */
02615                continue;
02616             }
02617          } else {
02618             if (config->feature_timer <=0) {
02619                /* We ran out of time */
02620                config->feature_timer = 0;
02621                who = chan;
02622                if (f)
02623                   ast_frfree(f);
02624                f = NULL;
02625                res = 0;
02626             }
02627          }
02628       }
02629       if (res < 0) {
02630          if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_test_flag(peer, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan) && !ast_check_hangup(peer))
02631             ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
02632          goto before_you_go;
02633       }
02634       
02635       if (!f || (f->frametype == AST_FRAME_CONTROL &&
02636             (f->subclass == AST_CONTROL_HANGUP || f->subclass == AST_CONTROL_BUSY || 
02637                f->subclass == AST_CONTROL_CONGESTION))) {
02638          res = -1;
02639          break;
02640       }
02641       /* many things should be sent to the 'other' channel */
02642       other = (who == chan) ? peer : chan;
02643       if (f->frametype == AST_FRAME_CONTROL) {
02644          switch (f->subclass) {
02645          case AST_CONTROL_RINGING:
02646          case AST_CONTROL_FLASH:
02647          case -1:
02648             ast_indicate(other, f->subclass);
02649             break;
02650          case AST_CONTROL_HOLD:
02651          case AST_CONTROL_UNHOLD:
02652             ast_indicate_data(other, f->subclass, f->data.ptr, f->datalen);
02653             break;
02654          case AST_CONTROL_OPTION:
02655             aoh = f->data.ptr;
02656             /* Forward option Requests */
02657             if (aoh && aoh->flag == AST_OPTION_FLAG_REQUEST) {
02658                ast_channel_setoption(other, ntohs(aoh->option), aoh->data, 
02659                   f->datalen - sizeof(struct ast_option_header), 0);
02660             }
02661             break;
02662          }
02663       } else if (f->frametype == AST_FRAME_DTMF_BEGIN) {
02664          /* eat it */
02665       } else if (f->frametype == AST_FRAME_DTMF) {
02666          char *featurecode;
02667          int sense;
02668 
02669          hadfeatures = hasfeatures;
02670          /* This cannot overrun because the longest feature is one shorter than our buffer */
02671          if (who == chan) {
02672             sense = FEATURE_SENSE_CHAN;
02673             featurecode = chan_featurecode;
02674          } else  {
02675             sense = FEATURE_SENSE_PEER;
02676             featurecode = peer_featurecode;
02677          }
02678          /*! append the event to featurecode. we rely on the string being zero-filled, and
02679           * not overflowing it. 
02680           * \todo XXX how do we guarantee the latter ?
02681           */
02682          featurecode[strlen(featurecode)] = f->subclass;
02683          /* Get rid of the frame before we start doing "stuff" with the channels */
02684          ast_frfree(f);
02685          f = NULL;
02686          config->feature_timer = backup_config.feature_timer;
02687          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
02688          switch(res) {
02689          case AST_FEATURE_RETURN_PASSDIGITS:
02690             ast_dtmf_stream(other, who, featurecode, 0, 0);
02691             /* Fall through */
02692          case AST_FEATURE_RETURN_SUCCESS:
02693             memset(featurecode, 0, sizeof(chan_featurecode));
02694             break;
02695          }
02696          if (res >= AST_FEATURE_RETURN_PASSDIGITS) {
02697             res = 0;
02698          } else 
02699             break;
02700          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
02701          if (hadfeatures && !hasfeatures) {
02702             /* Restore backup */
02703             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
02704             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
02705          } else if (hasfeatures) {
02706             if (!hadfeatures) {
02707                /* Backup configuration */
02708                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
02709                /* Setup temporary config options */
02710                config->play_warning = 0;
02711                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
02712                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
02713                config->warning_freq = 0;
02714                config->warning_sound = NULL;
02715                config->end_sound = NULL;
02716                config->start_sound = NULL;
02717                config->firstpass = 0;
02718             }
02719             config->start_time = ast_tvnow();
02720             config->feature_timer = featuredigittimeout;
02721             ast_debug(1, "Set time limit to %ld\n", config->feature_timer);
02722          }
02723       }
02724       if (f)
02725          ast_frfree(f);
02726 
02727    }
02728    before_you_go:
02729 
02730    if (ast_test_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT)) {
02731       ast_clear_flag(chan,AST_FLAG_BRIDGE_HANGUP_DONT); /* its job is done */
02732       if (bridge_cdr) {
02733          ast_cdr_discard(bridge_cdr);
02734          /* QUESTION: should we copy bridge_cdr fields to the peer before we throw it away? */
02735       }
02736       return res; /* if we shouldn't do the h-exten, we shouldn't do the bridge cdr, either! */
02737    }
02738 
02739    if (config->end_bridge_callback) {
02740       config->end_bridge_callback(config->end_bridge_callback_data);
02741    }
02742 
02743    /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation 
02744     * if it were, then chan belongs to a different thread now, and might have been hung up long
02745      * ago.
02746     */
02747    if (!ast_test_flag(&(config->features_caller),AST_FEATURE_NO_H_EXTEN) &&
02748       ast_exists_extension(chan, chan->context, "h", 1, chan->cid.cid_num)) {
02749       struct ast_cdr *swapper = NULL;
02750       char savelastapp[AST_MAX_EXTENSION];
02751       char savelastdata[AST_MAX_EXTENSION];
02752       char save_exten[AST_MAX_EXTENSION];
02753       int  save_prio;
02754       int  found = 0;   /* set if we find at least one match */
02755       int  spawn_error = 0;
02756       
02757       autoloopflag = ast_test_flag(chan, AST_FLAG_IN_AUTOLOOP);
02758       ast_set_flag(chan, AST_FLAG_IN_AUTOLOOP);
02759       if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
02760          ast_cdr_end(bridge_cdr);
02761       }
02762       /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge
02763          dialplan code operate on it */
02764       ast_channel_lock(chan);
02765       if (bridge_cdr) {
02766          swapper = chan->cdr;
02767          ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
02768          ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
02769          chan->cdr = bridge_cdr;
02770       }
02771       ast_copy_string(save_exten, chan->exten, sizeof(save_exten));
02772       save_prio = chan->priority;
02773       ast_copy_string(chan->exten, "h", sizeof(chan->exten));
02774       chan->priority = 1;
02775       ast_channel_unlock(chan);
02776       while ((spawn_error = ast_spawn_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num, &found, 1)) == 0) {
02777          chan->priority++;
02778       }
02779       if (spawn_error && (!ast_exists_extension(chan, chan->context, chan->exten, chan->priority, chan->cid.cid_num) || ast_check_hangup(chan))) {
02780          /* if the extension doesn't exist or a hangup occurred, this isn't really a spawn error */
02781          spawn_error = 0;
02782       }
02783       if (found && spawn_error) {
02784          /* Something bad happened, or a hangup has been requested. */
02785          ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
02786          ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", chan->context, chan->exten, chan->priority, chan->name);
02787       }
02788       /* swap it back */
02789       ast_channel_lock(chan);
02790       ast_copy_string(chan->exten, save_exten, sizeof(chan->exten));
02791       chan->priority = save_prio;
02792       if (bridge_cdr) {
02793          if (chan->cdr == bridge_cdr) {
02794             chan->cdr = swapper;
02795          } else {
02796             bridge_cdr = NULL;
02797          }
02798       }
02799       if (!spawn_error) {
02800          ast_set_flag(chan, AST_FLAG_BRIDGE_HANGUP_RUN);
02801       }
02802       ast_channel_unlock(chan);
02803       /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
02804       if (bridge_cdr) {
02805          ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
02806          ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
02807       }
02808       ast_set2_flag(chan, autoloopflag, AST_FLAG_IN_AUTOLOOP);
02809    }
02810    
02811    /* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
02812    new_chan_cdr = pick_unlocked_cdr(chan->cdr); /* the proper chan cdr, if there are forked cdrs */
02813    if (bridge_cdr && new_chan_cdr && ast_test_flag(new_chan_cdr, AST_CDR_FLAG_POST_DISABLED))
02814       ast_set_flag(bridge_cdr, AST_CDR_FLAG_POST_DISABLED);
02815 
02816    /* we can post the bridge CDR at this point */
02817    if (bridge_cdr) {
02818       ast_cdr_end(bridge_cdr);
02819       ast_cdr_detach(bridge_cdr);
02820    }
02821    
02822    /* do a specialized reset on the beginning channel
02823       CDR's, if they still exist, so as not to mess up
02824       issues in future bridges;
02825       
02826       Here are the rules of the game:
02827       1. The chan and peer channel pointers will not change
02828          during the life of the bridge.
02829       2. But, in transfers, the channel names will change.
02830          between the time the bridge is started, and the
02831          time the channel ends. 
02832          Usually, when a channel changes names, it will
02833          also change CDR pointers.
02834       3. Usually, only one of the two channels (chan or peer)
02835          will change names.
02836       4. Usually, if a channel changes names during a bridge,
02837          it is because of a transfer. Usually, in these situations,
02838          it is normal to see 2 bridges running simultaneously, and
02839          it is not unusual to see the two channels that change
02840          swapped between bridges.
02841       5. After a bridge occurs, we have 2 or 3 channels' CDRs
02842          to attend to; if the chan or peer changed names,
02843          we have the before and after attached CDR's.
02844    */
02845    
02846    if (new_chan_cdr) {
02847       struct ast_channel *chan_ptr = NULL;
02848  
02849       if (strcasecmp(orig_channame, chan->name) != 0) { 
02850          /* old channel */
02851          chan_ptr = ast_get_channel_by_name_locked(orig_channame);
02852          if (chan_ptr) {
02853             if (!ast_bridged_channel(chan_ptr)) {
02854                struct ast_cdr *cur;
02855                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02856                   if (cur == chan_cdr) {
02857                      break;
02858                   }
02859                }
02860                if (cur)
02861                   ast_cdr_specialized_reset(chan_cdr,0);
02862             }
02863             ast_channel_unlock(chan_ptr);
02864          }
02865          /* new channel */
02866          ast_cdr_specialized_reset(new_chan_cdr,0);
02867       } else {
02868          ast_cdr_specialized_reset(chan_cdr,0); /* nothing changed, reset the chan_cdr  */
02869       }
02870    }
02871    
02872    {
02873       struct ast_channel *chan_ptr = NULL;
02874       new_peer_cdr = pick_unlocked_cdr(peer->cdr); /* the proper chan cdr, if there are forked cdrs */
02875       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))
02876          ast_set_flag(new_peer_cdr, AST_CDR_FLAG_POST_DISABLED); /* DISABLED is viral-- it will propagate across a bridge */
02877       if (strcasecmp(orig_peername, peer->name) != 0) { 
02878          /* old channel */
02879          chan_ptr = ast_get_channel_by_name_locked(orig_peername);
02880          if (chan_ptr) {
02881             if (!ast_bridged_channel(chan_ptr)) {
02882                struct ast_cdr *cur;
02883                for (cur = chan_ptr->cdr; cur; cur = cur->next) {
02884                   if (cur == peer_cdr) {
02885                      break;
02886                   }
02887                }
02888                if (cur)
02889                   ast_cdr_specialized_reset(peer_cdr,0);
02890             }
02891             ast_channel_unlock(chan_ptr);
02892          }
02893          /* new channel */
02894          ast_cdr_specialized_reset(new_peer_cdr,0);
02895       } else {
02896          ast_cdr_specialized_reset(peer_cdr,0); /* nothing changed, reset the peer_cdr  */
02897       }
02898    }
02899    
02900    return res;
02901 }
02902 
02903 /*! \brief Output parking event to manager */
02904 static void post_manager_event(const char *s, struct parkeduser *pu)
02905 {
02906    manager_event(EVENT_FLAG_CALL, s,
02907       "Exten: %s\r\n"
02908       "Channel: %s\r\n"
02909       "Parkinglot: %s\r\n"
02910       "CallerIDNum: %s\r\n"
02911       "CallerIDName: %s\r\n"
02912       "UniqueID: %s\r\n\r\n",
02913       pu->parkingexten, 
02914       pu->chan->name,
02915       pu->parkinglot->name,
02916       S_OR(pu->chan->cid.cid_num, "<unknown>"),
02917       S_OR(pu->chan->cid.cid_name, "<unknown>"),
02918       pu->chan->uniqueid
02919       );
02920 }
02921 
02922 static char *callback_dialoptions(struct ast_flags *features_callee, struct ast_flags *features_caller, char *options, size_t len)
02923 {
02924    int i = 0;
02925    enum {
02926       OPT_CALLEE_REDIRECT   = 't',
02927       OPT_CALLER_REDIRECT   = 'T',
02928       OPT_CALLEE_AUTOMON    = 'w',
02929       OPT_CALLER_AUTOMON    = 'W',
02930       OPT_CALLEE_DISCONNECT = 'h',
02931       OPT_CALLER_DISCONNECT = 'H',
02932       OPT_CALLEE_PARKCALL   = 'k',
02933       OPT_CALLER_PARKCALL   = 'K',
02934    };
02935 
02936    memset(options, 0, len);
02937    if (ast_test_flag(features_caller, AST_FEATURE_REDIRECT) && i < len) {
02938       options[i++] = OPT_CALLER_REDIRECT;
02939    }
02940    if (ast_test_flag(features_caller, AST_FEATURE_AUTOMON) && i < len) {
02941       options[i++] = OPT_CALLER_AUTOMON;
02942    }
02943    if (ast_test_flag(features_caller, AST_FEATURE_DISCONNECT) && i < len) {
02944       options[i++] = OPT_CALLER_DISCONNECT;
02945    }
02946    if (ast_test_flag(features_caller, AST_FEATURE_PARKCALL) && i < len) {
02947       options[i++] = OPT_CALLER_PARKCALL;
02948    }
02949 
02950    if (ast_test_flag(features_callee, AST_FEATURE_REDIRECT) && i < len) {
02951       options[i++] = OPT_CALLEE_REDIRECT;
02952    }
02953    if (ast_test_flag(features_callee, AST_FEATURE_AUTOMON) && i < len) {
02954       options[i++] = OPT_CALLEE_AUTOMON;
02955    }
02956    if (ast_test_flag(features_callee, AST_FEATURE_DISCONNECT) && i < len) {
02957       options[i++] = OPT_CALLEE_DISCONNECT;
02958    }
02959    if (ast_test_flag(features_callee, AST_FEATURE_PARKCALL) && i < len) {
02960       options[i++] = OPT_CALLEE_PARKCALL;
02961    }
02962 
02963    return options;
02964 }
02965 
02966 /*! \brief Run management on parkinglots, called once per parkinglot */
02967 int manage_parkinglot(struct ast_parkinglot *curlot, fd_set *rfds, fd_set *efds, fd_set *nrfds, fd_set *nefds, int *ms, int *max)
02968 {
02969 
02970    struct parkeduser *pu;
02971    int res = 0;
02972    char parkingslot[AST_MAX_EXTENSION];
02973 
02974    /* Lock parking list */
02975    AST_LIST_LOCK(&curlot->parkings);
02976    AST_LIST_TRAVERSE_SAFE_BEGIN(&curlot->parkings, pu, list) {
02977       struct ast_channel *chan = pu->chan;   /* shorthand */
02978       int tms;        /* timeout for this item */
02979       int x;          /* fd index in channel */
02980       struct ast_context *con;
02981 
02982       if (pu->notquiteyet) { /* Pretend this one isn't here yet */
02983          continue;
02984       }
02985       tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
02986       if (tms > pu->parkingtime) {
02987          /* Stop music on hold */
02988          ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
02989          /* Get chan, exten from derived kludge */
02990          if (pu->peername[0]) {
02991             char *peername = ast_strdupa(pu->peername);
02992             char *cp = strrchr(peername, '-');
02993             char peername_flat[AST_MAX_EXTENSION]; /* using something like DAHDI/52 for an extension name is NOT a good idea */
02994             int i;
02995 
02996             if (cp) 
02997                *cp = 0;
02998             ast_copy_string(peername_flat,peername,sizeof(peername_flat));
02999             for(i=0; peername_flat[i] && i < AST_MAX_EXTENSION; i++) {
03000                if (peername_flat[i] == '/') 
03001                   peername_flat[i]= '0';
03002             }
03003             con = ast_context_find_or_create(NULL, NULL, pu->parkinglot->parking_con_dial, registrar);
03004             if (!con) {
03005                ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", pu->parkinglot->parking_con_dial);
03006             }
03007             if (con) {
03008                char returnexten[AST_MAX_EXTENSION];
03009                struct ast_datastore *features_datastore;
03010                struct ast_dial_features *dialfeatures = NULL;
03011 
03012                ast_channel_lock(chan);
03013 
03014                if ((features_datastore = ast_channel_datastore_find(chan, &dial_features_info, NULL)))
03015                   dialfeatures = features_datastore->data;
03016 
03017                ast_channel_unlock(chan);
03018 
03019                if (!strncmp(peername, "Parked/", 7)) {
03020                   peername += 7;
03021                }
03022 
03023                if (dialfeatures) {
03024                   char buf[MAX_DIAL_FEATURE_OPTIONS] = {0,};
03025                   snprintf(returnexten, sizeof(returnexten), "%s,30,%s", peername, callback_dialoptions(&(dialfeatures->features_callee), &(dialfeatures->features_caller), buf, sizeof(buf)));
03026                } else { /* Existing default */
03027                   ast_log(LOG_WARNING, "Dialfeatures not found on %s, using default!\n", chan->name);
03028                   snprintf(returnexten, sizeof(returnexten), "%s,30,t", peername);
03029                }
03030 
03031                ast_add_extension2(con, 1, peername_flat, 1, NULL, NULL, "Dial", ast_strdup(returnexten), ast_free_ptr, registrar);
03032             }
03033             if (pu->options_specified == 1) {
03034                /* Park() was called with overriding return arguments, respect those arguments */
03035                set_c_e_p(chan, pu->context, pu->exten, pu->priority);
03036             } else {
03037                if (comebacktoorigin) {
03038                   set_c_e_p(chan, pu->parkinglot->parking_con_dial, peername_flat, 1);
03039                } else {
03040                   ast_log(LOG_WARNING, "now going to parkedcallstimeout,s,1 | ps is %d\n",pu->parkingnum);
03041                   snprintf(parkingslot, sizeof(parkingslot), "%d", pu->parkingnum);
03042                   pbx_builtin_setvar_helper(chan, "PARKINGSLOT", parkingslot);
03043                   set_c_e_p(chan, "parkedcallstimeout", peername_flat, 1);
03044                }
03045             }
03046          } else {
03047             /* They've been waiting too long, send them back to where they came.  Theoretically they
03048                should have their original extensions and such, but we copy to be on the safe side */
03049             set_c_e_p(chan, pu->context, pu->exten, pu->priority);
03050          }
03051          post_manager_event("ParkedCallTimeOut", pu);
03052 
03053          ast_verb(2, "Timeout for %s parked on %d (%s). Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->parkinglot->name, pu->chan->context, pu->chan->exten, pu->chan->priority);
03054          /* Start up the PBX, or hang them up */
03055          if (ast_pbx_start(chan))  {
03056             ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
03057             ast_hangup(chan);
03058          }
03059          /* And take them out of the parking lot */
03060          con = ast_context_find(pu->parkinglot->parking_con);
03061          if (con) {
03062             if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
03063                ast_log(LOG_WARNING, "Whoa, failed to remove the parking extension!\n");
03064             else
03065                notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE);
03066          } else
03067             ast_log(LOG_WARNING, "Whoa, no parking context?\n");
03068          AST_LIST_REMOVE_CURRENT(list);
03069          free(pu);
03070       } else { /* still within parking time, process descriptors */
03071          for (x = 0; x < AST_MAX_FDS; x++) {
03072             struct ast_frame *f;
03073 
03074             if ((chan->fds[x] == -1) || (!FD_ISSET(chan->fds[x], rfds) && !FD_ISSET(pu->chan->fds[x], efds))) 
03075                continue;
03076             
03077             if (FD_ISSET(chan->fds[x], efds))
03078                ast_set_flag(chan, AST_FLAG_EXCEPTION);
03079             else
03080                ast_clear_flag(chan, AST_FLAG_EXCEPTION);
03081             chan->fdno = x;
03082 
03083             /* See if they need servicing */
03084             f = ast_read(pu->chan);
03085             /* Hangup? */
03086             if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
03087                if (f)
03088                   ast_frfree(f);
03089                post_manager_event("ParkedCallGiveUp", pu);
03090 
03091                /* There's a problem, hang them up*/
03092                ast_verb(2, "%s got tired of being parked\n", chan->name);
03093                ast_hangup(chan);
03094                /* And take them out of the parking lot */
03095                con = ast_context_find(curlot->parking_con);
03096                if (con) {
03097                   if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
03098                      ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
03099                   else
03100                      notify_metermaids(pu->parkingexten, curlot->parking_con, AST_DEVICE_NOT_INUSE);
03101                } else
03102                   ast_log(LOG_WARNING, "Whoa, no parking context for parking lot %s?\n", curlot->name);
03103                AST_LIST_REMOVE_CURRENT(list);
03104                free(pu);
03105                break;
03106             } else {
03107                /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
03108                ast_frfree(f);
03109                if (pu->moh_trys < 3 && !chan->generatordata) {
03110                   ast_debug(1, "MOH on parked call stopped by outside source.  Restarting on channel %s.\n", chan->name);
03111                   ast_indicate_data(chan, AST_CONTROL_HOLD, 
03112                      S_OR(curlot->mohclass, NULL),
03113                      (!ast_strlen_zero(curlot->mohclass) ? strlen(curlot->mohclass) + 1 : 0));
03114                   pu->moh_trys++;
03115                }
03116                goto std;   /* XXX Ick: jumping into an else statement??? XXX */
03117             }
03118          } /* End for */
03119          if (x >= AST_MAX_FDS) {
03120 std:           for (x=0; x<AST_MAX_FDS; x++) {  /* mark fds for next round */
03121                if (chan->fds[x] > -1) {
03122                   FD_SET(chan->fds[x], nrfds);
03123                   FD_SET(chan->fds[x], nefds);
03124                   if (chan->fds[x] > *max)
03125                      *max = chan->fds[x];
03126                }
03127             }
03128             /* Keep track of our shortest wait */
03129             if (tms < *ms || *ms < 0)
03130                *ms = tms;
03131          }
03132       }
03133    }
03134    AST_LIST_TRAVERSE_SAFE_END;
03135    AST_LIST_UNLOCK(&curlot->parkings);
03136    return res;
03137 }
03138 
03139 /*! 
03140  * \brief Take care of parked calls and unpark them if needed 
03141  * \param ignore unused var.
03142  * 
03143  * Start inf loop, lock parking lot, check if any parked channels have gone above timeout
03144  * if so, remove channel from parking lot and return it to the extension that parked it.
03145  * Check if parked channel decided to hangup, wait until next FD via select().
03146 */
03147 static void *do_parking_thread(void *ignore)
03148 {
03149    fd_set rfds, efds;   /* results from previous select, to be preserved across loops. */
03150    fd_set nrfds, nefds; /* args for the next select */
03151    FD_ZERO(&rfds);
03152    FD_ZERO(&efds);
03153 
03154    for (;;) {
03155       int res = 0;
03156       int ms = -1;   /* select timeout, uninitialized */
03157       int max = -1;  /* max fd, none there yet */
03158       struct ao2_iterator iter;
03159       struct ast_parkinglot *curlot;
03160       FD_ZERO(&nrfds);
03161       FD_ZERO(&nefds);
03162       iter = ao2_iterator_init(parkinglots, 0);
03163 
03164       while ((curlot = ao2_iterator_next(&iter))) {
03165          res = manage_parkinglot(curlot, &rfds, &efds, &nrfds, &nefds, &ms, &max);
03166          ao2_ref(curlot, -1);
03167       }
03168 
03169       rfds = nrfds;
03170       efds = nefds;
03171       {
03172          struct timeval wait = ast_samp2tv(ms, 1000);
03173          /* Wait for something to happen */
03174          ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &wait : NULL);
03175       }
03176       pthread_testcancel();
03177    }
03178    return NULL;   /* Never reached */
03179 }
03180 
03181 /*! \brief Find parkinglot by name */
03182 struct ast_parkinglot *find_parkinglot(const char *name)
03183 {
03184    struct ast_parkinglot *parkinglot = NULL;
03185    struct ast_parkinglot tmp_parkinglot;
03186    
03187    if (ast_strlen_zero(name))
03188       return NULL;
03189 
03190    ast_copy_string(tmp_parkinglot.name, name, sizeof(tmp_parkinglot.name));
03191 
03192    parkinglot = ao2_find(parkinglots, &tmp_parkinglot, OBJ_POINTER);
03193 
03194    if (parkinglot && option_debug)
03195       ast_log(LOG_DEBUG, "Found Parkinglot: %s\n", parkinglot->name);
03196 
03197    return parkinglot;
03198 }
03199 
03200 AST_APP_OPTIONS(park_call_options, BEGIN_OPTIONS
03201    AST_APP_OPTION('r', AST_PARK_OPT_RINGING),
03202    AST_APP_OPTION('R', AST_PARK_OPT_RANDOMIZE),
03203    AST_APP_OPTION('s', AST_PARK_OPT_SILENCE),
03204 END_OPTIONS );
03205 
03206 /*! \brief Park a call */
03207 static int park_call_exec(struct ast_channel *chan, void *data)
03208 {
03209    /* Cache the original channel name in case we get masqueraded in the middle
03210     * of a park--it is still theoretically possible for a transfer to happen before
03211     * we get here, but it is _really_ unlikely */
03212    char *orig_chan_name = ast_strdupa(chan->name);
03213    char orig_exten[AST_MAX_EXTENSION];
03214    int orig_priority = chan->priority;
03215 
03216    /* Data is unused at the moment but could contain a parking
03217       lot context eventually */
03218    int res = 0;
03219 
03220    char *parse = NULL;
03221    AST_DECLARE_APP_ARGS(app_args,
03222       AST_APP_ARG(timeout);
03223       AST_APP_ARG(return_con);
03224       AST_APP_ARG(return_ext);
03225       AST_APP_ARG(return_pri);
03226       AST_APP_ARG(options);
03227    );
03228 
03229    parse = ast_strdupa(data);
03230    AST_STANDARD_APP_ARGS(app_args, parse);
03231 
03232    ast_copy_string(orig_exten, chan->exten, sizeof(orig_exten));
03233 
03234    /* Setup the exten/priority to be s/1 since we don't know
03235       where this call should return */
03236    strcpy(chan->exten, "s");
03237    chan->priority = 1;
03238 
03239    /* Answer if call is not up */
03240    if (chan->_state != AST_STATE_UP)
03241       res = ast_answer(chan);
03242 
03243    /* Sleep to allow VoIP streams to settle down */
03244    if (!res)
03245       res = ast_safe_sleep(chan, 1000);
03246 
03247    /* Park the call */
03248    if (!res) {
03249       struct ast_park_call_args args = {
03250          .orig_chan_name = orig_chan_name,
03251       };
03252       struct ast_flags flags = { 0 };
03253 
03254       if (parse) {
03255          if (!ast_strlen_zero(app_args.timeout)) {
03256             if (sscanf(app_args.timeout, "%30d", &args.timeout) != 1) {
03257                ast_log(LOG_WARNING, "Invalid timeout '%s' provided\n", app_args.timeout);
03258                args.timeout = 0;
03259             }
03260          }
03261          if (!ast_strlen_zero(app_args.return_con)) {
03262             args.return_con = app_args.return_con;
03263          }
03264          if (!ast_strlen_zero(app_args.return_ext)) {
03265             args.return_ext = app_args.return_ext;
03266          }
03267          if (!ast_strlen_zero(app_args.return_pri)) {
03268             if (sscanf(app_args.return_pri, "%30d", &args.return_pri) != 1) {
03269                ast_log(LOG_WARNING, "Invalid priority '%s' specified\n", app_args.return_pri);
03270                args.return_pri = 0;
03271             }
03272          }
03273       }
03274 
03275       ast_app_parse_options(park_call_options, &flags, NULL, app_args.options);
03276       args.flags = flags.flags;
03277 
03278       res = masq_park_call_announce_args(chan, chan, &args);
03279       /* Continue on in the dialplan */
03280       if (res == 1) {
03281          ast_copy_string(chan->exten, orig_exten, sizeof(chan->exten));
03282          chan->priority = orig_priority;
03283          res = 0;
03284       } else if (!res) {
03285          res = 1;
03286       }
03287    }
03288 
03289    return res;
03290 }
03291 
03292 /*! \brief Pickup parked call */
03293 static int park_exec_full(struct ast_channel *chan, void *data, struct ast_parkinglot *parkinglot)
03294 {
03295    int res = 0;
03296    struct ast_channel *peer=NULL;
03297    struct parkeduser *pu;
03298    struct ast_context *con;
03299    int park = 0;
03300    struct ast_bridge_config config;
03301 
03302    if (data)
03303       park = atoi((char *)data);
03304 
03305    parkinglot = find_parkinglot(findparkinglotname(chan));  
03306    if (!parkinglot)
03307       parkinglot = default_parkinglot;
03308 
03309    AST_LIST_LOCK(&parkinglot->parkings);
03310    AST_LIST_TRAVERSE_SAFE_BEGIN(&parkinglot->parkings, pu, list) {
03311       if (!data || pu->parkingnum == park) {
03312          if (pu->chan->pbx) { /* do not allow call to be picked up until the PBX thread is finished */
03313             AST_LIST_UNLOCK(&parkinglot->parkings);
03314             return -1;
03315          }
03316          AST_LIST_REMOVE_CURRENT(list);
03317          break;
03318       }
03319    }
03320    AST_LIST_TRAVERSE_SAFE_END;
03321    AST_LIST_UNLOCK(&parkinglot->parkings);
03322 
03323    if (pu) {
03324       peer = pu->chan;
03325       con = ast_context_find(parkinglot->parking_con);
03326       if (con) {
03327          if (ast_context_remove_extension2(con, pu->parkingexten, 1, NULL, 0))
03328             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
03329          else
03330             notify_metermaids(pu->parkingexten, parkinglot->parking_con, AST_DEVICE_NOT_INUSE);
03331       } else
03332          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
03333 
03334       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
03335          "Exten: %s\r\n"
03336          "Channel: %s\r\n"
03337          "From: %s\r\n"
03338          "CallerIDNum: %s\r\n"
03339          "CallerIDName: %s\r\n",
03340          pu->parkingexten, pu->chan->name, chan->name,
03341          S_OR(pu->chan->cid.cid_num, "<unknown>"),
03342          S_OR(pu->chan->cid.cid_name, "<unknown>")
03343          );
03344 
03345       ast_free(pu);
03346    }
03347    /* JK02: it helps to answer the channel if not already up */
03348    if (chan->_state != AST_STATE_UP)
03349       ast_answer(chan);
03350 
03351    //XXX Why do we unlock here ?
03352    // uncomment it for now, till my setup with debug_threads and detect_deadlocks starts to complain
03353    //ASTOBJ_UNLOCK(parkinglot);
03354 
03355    if (peer) {
03356       struct ast_datastore *features_datastore;
03357       struct ast_dial_features *dialfeatures = NULL;
03358 
03359       /* Play a courtesy to the source(s) configured to prefix the bridge connecting */
03360 
03361       if (!ast_strlen_zero(courtesytone)) {
03362          int error = 0;
03363          ast_indicate(peer, AST_CONTROL_UNHOLD);
03364          if (parkedplay == 0) {
03365             error = ast_stream_and_wait(chan, courtesytone, "");
03366          } else if (parkedplay == 1) {
03367             error = ast_stream_and_wait(peer, courtesytone, "");
03368          } else if (parkedplay == 2) {
03369             if (!ast_streamfile(chan, courtesytone, chan->language) &&
03370                   !ast_streamfile(peer, courtesytone, chan->language)) {
03371                /*! \todo XXX we would like to wait on both! */
03372                res = ast_waitstream(chan, "");
03373                if (res >= 0)
03374                   res = ast_waitstream(peer, "");
03375                if (res < 0)
03376                   error = 1;
03377             }
03378          }
03379          if (error) {
03380             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
03381             ast_hangup(peer);
03382             return -1;
03383          }
03384       } else
03385          ast_indicate(peer, AST_CONTROL_UNHOLD);
03386 
03387       res = ast_channel_make_compatible(chan, peer);
03388       if (res < 0) {
03389          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
03390          ast_hangup(peer);
03391          return -1;
03392       }
03393       /* This runs sorta backwards, since we give the incoming channel control, as if it
03394          were the person called. */
03395       ast_verb(3, "Channel %s connected to parked call %d\n", chan->name, park);
03396 
03397       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
03398       ast_cdr_setdestchan(chan->cdr, peer->name);
03399       memset(&config, 0, sizeof(struct ast_bridge_config));
03400 
03401       /* Get datastore for peer and apply it's features to the callee side of the bridge config */
03402       ast_channel_lock(peer);
03403       if ((features_datastore = ast_channel_datastore_find(peer, &dial_features_info, NULL))) {
03404          dialfeatures = features_datastore->data;
03405       }
03406       ast_channel_unlock(peer);
03407 
03408       /* When the datastores for both caller and callee are created, both the callee and caller channels
03409        * use the features_caller flag variable to represent themselves. With that said, the config.features_callee
03410        * flags should be copied from the datastore's caller feature flags regardless if peer was a callee
03411        * or caller. */
03412       if (dialfeatures) {
03413          ast_copy_flags(&(config.features_callee), &(dialfeatures->features_caller), AST_FLAGS_ALL);
03414       }
03415 
03416       if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
03417          ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
03418       }
03419       if ((parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcalltransfers == AST_FEATURE_FLAG_BYBOTH)) {
03420          ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
03421       }
03422       if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
03423          ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
03424       }
03425       if ((parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallreparking == AST_FEATURE_FLAG_BYBOTH)) {
03426          ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
03427       }
03428       if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
03429          ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
03430       }
03431       if ((parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallhangup == AST_FEATURE_FLAG_BYBOTH)) {
03432          ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
03433       }
03434       if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLEE) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
03435          ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
03436       }
03437       if ((parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYCALLER) || (parkinglot->parkedcallrecording == AST_FEATURE_FLAG_BYBOTH)) {
03438          ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
03439       }
03440 
03441       res = ast_bridge_call(chan, peer, &config);
03442 
03443       pbx_builtin_setvar_helper(chan, "PARKEDCHANNEL", peer->name);
03444       ast_cdr_setdestchan(chan->cdr, peer->name);
03445 
03446       /* Simulate the PBX hanging up */
03447       ast_hangup(peer);
03448       return -1;
03449    } else {
03450       /*! \todo XXX Play a message XXX */
03451       if (ast_stream_and_wait(chan, "pbx-invalidpark", ""))
03452          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
03453       ast_verb(3, "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
03454       res = -1;
03455    }
03456 
03457    return -1;
03458 }
03459 
03460 static int park_exec(struct ast_channel *chan, void *data) 
03461 {
03462    return park_exec_full(chan, data, default_parkinglot);
03463 }
03464 
03465 /*! \brief Unreference parkinglot object. If no more references,
03466    then go ahead and delete it */
03467 static void parkinglot_unref(struct ast_parkinglot *parkinglot) 
03468 {
03469    int refcount = ao2_ref(parkinglot, -1);
03470    if (option_debug > 2)
03471       ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount - 1);
03472 }
03473 
03474 static struct ast_parkinglot *parkinglot_addref(struct ast_parkinglot *parkinglot)
03475 {
03476    int refcount = ao2_ref(parkinglot, +1);
03477    if (option_debug > 2)
03478       ast_log(LOG_DEBUG, "Multiparking: %s refcount now %d\n", parkinglot->name, refcount + 1);
03479    return parkinglot;
03480 }
03481 
03482 /*! \brief Allocate parking lot structure */
03483 static struct ast_parkinglot *create_parkinglot(char *name)
03484 {
03485    struct ast_parkinglot *newlot = (struct ast_parkinglot *) NULL;
03486 
03487    if (!name)
03488       return NULL;
03489 
03490    newlot = ao2_alloc(sizeof(*newlot), parkinglot_destroy);
03491    if (!newlot)
03492       return NULL;
03493    
03494    ast_copy_string(newlot->name, name, sizeof(newlot->name));
03495    AST_LIST_HEAD_INIT(&newlot->parkings);
03496 
03497    return newlot;
03498 }
03499 
03500 /*! \brief Destroy a parking lot */
03501 static void parkinglot_destroy(void *obj)
03502 {
03503    struct ast_parkinglot *ruin = obj;
03504    struct ast_context *con;
03505    con = ast_context_find(ruin->parking_con);
03506    if (con)
03507       ast_context_destroy(con, registrar);
03508    ao2_unlink(parkinglots, ruin);
03509 }
03510 
03511 /*! \brief Build parkinglot from configuration and chain it in */
03512 static struct ast_parkinglot *build_parkinglot(char *name, struct ast_variable *var)
03513 {
03514    struct ast_parkinglot *parkinglot;
03515    struct ast_context *con = NULL;
03516 
03517    struct ast_variable *confvar = var;
03518    int error = 0;
03519    int start = 0, end = 0;
03520    int oldparkinglot = 0;
03521 
03522    parkinglot = find_parkinglot(name);
03523    if (parkinglot)
03524       oldparkinglot = 1;
03525    else
03526       parkinglot = create_parkinglot(name);
03527 
03528    if (!parkinglot)
03529       return NULL;
03530 
03531    ao2_lock(parkinglot);
03532 
03533    if (option_debug)
03534       ast_log(LOG_DEBUG, "Building parking lot %s\n", name);
03535    
03536    /* Do some config stuff */
03537    while(confvar) {
03538       if (!strcasecmp(confvar->name, "context")) {
03539          ast_copy_string(parkinglot->parking_con, confvar->value, sizeof(parkinglot->parking_con));
03540       } else if (!strcasecmp(confvar->name, "parkingtime")) {
03541          if ((sscanf(confvar->value, "%30d", &parkinglot->parkingtime) != 1) || (parkinglot->parkingtime < 1)) {
03542             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", confvar->value);
03543             parkinglot->parkingtime = DEFAULT_PARK_TIME;
03544          } else
03545             parkinglot->parkingtime = parkinglot->parkingtime * 1000;
03546       } else if (!strcasecmp(confvar->name, "parkpos")) {
03547          if (sscanf(confvar->value, "%30d-%30d", &start, &end) != 2) {
03548             ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of parking.conf\n", confvar->lineno);
03549             error = 1;
03550          } else {
03551             parkinglot->parking_start = start;
03552             parkinglot->parking_stop = end;
03553          }
03554       } else if (!strcasecmp(confvar->name, "findslot")) {
03555          parkinglot->parkfindnext = (!strcasecmp(confvar->value, "next"));
03556       }
03557       confvar = confvar->next;
03558    }
03559    /* make sure parkingtime is set if not specified */
03560    if (parkinglot->parkingtime == 0) {
03561       parkinglot->parkingtime = DEFAULT_PARK_TIME;
03562    }
03563 
03564    if (!var) { /* Default parking lot */
03565       ast_copy_string(parkinglot->parking_con, "parkedcalls", sizeof(parkinglot->parking_con));
03566       ast_copy_string(parkinglot->parking_con_dial, "park-dial", sizeof(parkinglot->parking_con_dial));
03567       ast_copy_string(parkinglot->mohclass, "default", sizeof(parkinglot->mohclass));
03568    }
03569 
03570    /* Check for errors */
03571    if (ast_strlen_zero(parkinglot->parking_con)) {
03572       ast_log(LOG_WARNING, "Parking lot %s lacks context\n", name);
03573       error = 1;
03574    }
03575 
03576    /* Create context */
03577    if (!error && !(con = ast_context_find_or_create(NULL, NULL, parkinglot->parking_con, registrar))) {
03578       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parkinglot->parking_con);
03579       error = 1;
03580    }
03581 
03582    /* Add a parking extension into the context */
03583    if (!error && !oldparkinglot) {
03584       if (!ast_strlen_zero(ast_parking_ext())) {
03585          if (ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), ast_free_ptr, registrar) == -1)
03586             error = 1;
03587       }
03588    }
03589 
03590    ao2_unlock(parkinglot);
03591 
03592    if (error) {
03593       ast_log(LOG_WARNING, "Parking %s not open for business. Configuration error.\n", name);
03594       parkinglot_destroy(parkinglot);
03595       return NULL;
03596    }
03597    if (option_debug)
03598       ast_log(LOG_DEBUG, "Parking %s now open for business. (start exten %d end %d)\n", name, start, end);
03599 
03600 
03601    /* Move it into the list, if it wasn't already there */
03602    if (!oldparkinglot) {
03603       ao2_link(parkinglots, parkinglot);
03604    }
03605    parkinglot_unref(parkinglot);
03606 
03607    return parkinglot;
03608 }
03609 
03610 
03611 /*! 
03612  * \brief Add parking hints for all defined parking lots 
03613  * \param context
03614  * \param start starting parkinglot number
03615  * \param stop ending parkinglot number
03616 */
03617 static void park_add_hints(char *context, int start, int stop)
03618 {
03619    int numext;
03620    char device[AST_MAX_EXTENSION];
03621    char exten[10];
03622 
03623    for (numext = start; numext <= stop; numext++) {
03624       snprintf(exten, sizeof(exten), "%d", numext);
03625       snprintf(device, sizeof(device), "park:%s@%s", exten, context);
03626       ast_add_extension(context, 1, exten, PRIORITY_HINT, NULL, NULL, device, NULL, NULL, registrar);
03627    }
03628 }
03629 
03630 static int load_config(void) 
03631 {
03632    int start = 0, end = 0;
03633    int res;
03634    int i;
03635    struct ast_context *con = NULL;
03636    struct ast_config *cfg = NULL;
03637    struct ast_variable *var = NULL;
03638    struct feature_group *fg = NULL;
03639    struct ast_flags config_flags = { 0 };
03640    char old_parking_ext[AST_MAX_EXTENSION];
03641    char old_parking_con[AST_MAX_EXTENSION] = "";
03642    char *ctg; 
03643    static const char *categories[] = { 
03644       /* Categories in features.conf that are not
03645        * to be parsed as group categories
03646        */
03647       "general",
03648       "featuremap",
03649       "applicationmap"
03650    };
03651 
03652    if (default_parkinglot) {
03653       strcpy(old_parking_con, default_parkinglot->parking_con);
03654       strcpy(old_parking_ext, parking_ext);
03655    } else {
03656       default_parkinglot = build_parkinglot(DEFAULT_PARKINGLOT, NULL);
03657       if (default_parkinglot) {
03658          ao2_lock(default_parkinglot);
03659          default_parkinglot->parking_start = 701;
03660          default_parkinglot->parking_stop = 750;
03661          default_parkinglot->parking_offset = 0;
03662          default_parkinglot->parkfindnext = 0;
03663          default_parkinglot->parkingtime = DEFAULT_PARK_TIME;
03664          ao2_unlock(default_parkinglot);
03665       }
03666    }
03667    if (default_parkinglot) {
03668       if (option_debug)
03669          ast_log(LOG_DEBUG, "Configuration of default parkinglot done.\n");
03670    } else {
03671       ast_log(LOG_ERROR, "Configuration of default parkinglot failed.\n");
03672       return -1;
03673    }
03674    
03675 
03676    /* Reset to defaults */
03677    strcpy(parking_ext, "700");
03678    strcpy(pickup_ext, "*8");
03679    courtesytone[0] = '\0';
03680    strcpy(xfersound, "beep");
03681    strcpy(xferfailsound, "pbx-invalid");
03682    adsipark = 0;
03683    comebacktoorigin = 1;
03684 
03685    default_parkinglot->parkaddhints = 0;
03686    default_parkinglot->parkedcalltransfers = 0;
03687    default_parkinglot->parkedcallreparking = 0;
03688    default_parkinglot->parkedcallrecording = 0;
03689    default_parkinglot->parkedcallhangup = 0;
03690 
03691    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
03692    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03693    atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03694    atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
03695    atxferdropcall = DEFAULT_ATXFER_DROP_CALL;
03696    atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
03697 
03698    cfg = ast_config_load2("features.conf", "features", config_flags);
03699    if (!cfg) {
03700       ast_log(LOG_WARNING,"Could not load features.conf\n");
03701       return 0;
03702    }
03703    for (var = ast_variable_browse(cfg, "general"); var; var = var->next) {
03704       if (!strcasecmp(var->name, "parkext")) {
03705          ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
03706       } else if (!strcasecmp(var->name, "context")) {
03707          ast_copy_string(default_parkinglot->parking_con, var->value, sizeof(default_parkinglot->parking_con));
03708       } else if (!strcasecmp(var->name, "parkingtime")) {
03709          if ((sscanf(var->value, "%30d", &default_parkinglot->parkingtime) != 1) || (default_parkinglot->parkingtime < 1)) {
03710             ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
03711             default_parkinglot->parkingtime = DEFAULT_PARK_TIME;
03712          } else
03713             default_parkinglot->parkingtime = default_parkinglot->parkingtime * 1000;
03714       } else if (!strcasecmp(var->name, "parkpos")) {
03715          if (sscanf(var->value, "%30d-%30d", &start, &end) != 2) {
03716             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);
03717          } else if (default_parkinglot) {
03718             default_parkinglot->parking_start = start;
03719             default_parkinglot->parking_stop = end;
03720          } else {
03721             ast_log(LOG_WARNING, "No default parking lot!\n");
03722          }
03723       } else if (!strcasecmp(var->name, "findslot")) {
03724          default_parkinglot->parkfindnext = (!strcasecmp(var->value, "next"));
03725       } else if (!strcasecmp(var->name, "parkinghints")) {
03726          default_parkinglot->parkaddhints = ast_true(var->value);
03727       } else if (!strcasecmp(var->name, "parkedcalltransfers")) {
03728          if (!strcasecmp(var->value, "both"))
03729             default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYBOTH;
03730          else if (!strcasecmp(var->value, "caller"))
03731             default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLER;
03732          else if (!strcasecmp(var->value, "callee"))
03733             default_parkinglot->parkedcalltransfers = AST_FEATURE_FLAG_BYCALLEE;
03734       } else if (!strcasecmp(var->name, "parkedcallreparking")) {
03735          if (!strcasecmp(var->value, "both"))
03736             default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYBOTH;
03737          else if (!strcasecmp(var->value, "caller"))
03738             default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLER;
03739          else if (!strcasecmp(var->value, "callee"))
03740             default_parkinglot->parkedcallreparking = AST_FEATURE_FLAG_BYCALLEE;
03741       } else if (!strcasecmp(var->name, "parkedcallhangup")) {
03742          if (!strcasecmp(var->value, "both"))
03743             default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYBOTH;
03744          else if (!strcasecmp(var->value, "caller"))
03745             default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLER;
03746          else if (!strcasecmp(var->value, "callee"))
03747             default_parkinglot->parkedcallhangup = AST_FEATURE_FLAG_BYCALLEE;
03748       } else if (!strcasecmp(var->name, "parkedcallrecording")) {
03749          if (!strcasecmp(var->value, "both"))
03750             default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYBOTH;
03751          else if (!strcasecmp(var->value, "caller"))
03752             default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLER;
03753          else if (!strcasecmp(var->value, "callee"))
03754             default_parkinglot->parkedcallrecording = AST_FEATURE_FLAG_BYCALLEE;
03755       } else if (!strcasecmp(var->name, "adsipark")) {
03756          adsipark = ast_true(var->value);
03757       } else if (!strcasecmp(var->name, "transferdigittimeout")) {
03758          if ((sscanf(var->value, "%30d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
03759             ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
03760             transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
03761          } else
03762             transferdigittimeout = transferdigittimeout * 1000;
03763       } else if (!strcasecmp(var->name, "featuredigittimeout")) {
03764          if ((sscanf(var->value, "%30d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
03765             ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
03766             featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
03767          }
03768       } else if (!strcasecmp(var->name, "atxfernoanswertimeout")) {
03769          if ((sscanf(var->value, "%30d", &atxfernoanswertimeout) != 1) || (atxfernoanswertimeout < 1)) {
03770             ast_log(LOG_WARNING, "%s is not a valid atxfernoanswertimeout\n", var->value);
03771             atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
03772          } else
03773             atxfernoanswertimeout = atxfernoanswertimeout * 1000;
03774       } else if (!strcasecmp(var->name, "atxferloopdelay")) {
03775          if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) {
03776             ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
03777             atxferloopdelay = DEFAULT_ATXFER_LOOP_DELAY;
03778          } else 
03779             atxferloopdelay *= 1000;
03780       } else if (!strcasecmp(var->name, "atxferdropcall")) {
03781          atxferdropcall = ast_true(var->value);
03782       } else if (!strcasecmp(var->name, "atxfercallbackretries")) {
03783          if ((sscanf(var->value, "%30u", &atxferloopdelay) != 1)) {
03784             ast_log(LOG_WARNING, "%s is not a valid atxfercallbackretries\n", var->value);
03785             atxfercallbackretries = DEFAULT_ATXFER_CALLBACK_RETRIES;
03786          }
03787       } else if (!strcasecmp(var->name, "courtesytone")) {
03788          ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
03789       }  else if (!strcasecmp(var->name, "parkedplay")) {
03790          if (!strcasecmp(var->value, "both"))
03791             parkedplay = 2;
03792          else if (!strcasecmp(var->value, "parked"))
03793             parkedplay = 1;
03794          else
03795             parkedplay = 0;
03796       } else if (!strcasecmp(var->name, "xfersound")) {
03797          ast_copy_string(xfersound, var->value, sizeof(xfersound));
03798       } else if (!strcasecmp(var->name, "xferfailsound")) {
03799          ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
03800       } else if (!strcasecmp(var->name, "pickupexten")) {
03801          ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
03802       } else if (!strcasecmp(var->name, "comebacktoorigin")) {
03803          comebacktoorigin = ast_true(var->value);
03804       } else if (!strcasecmp(var->name, "parkedmusicclass")) {
03805          ast_copy_string(default_parkinglot->mohclass, var->value, sizeof(default_parkinglot->mohclass));
03806       }
03807    }
03808 
03809    unmap_features();
03810    for (var = ast_variable_browse(cfg, "featuremap"); var; var = var->next) {
03811       if (remap_feature(var->name, var->value))
03812          ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
03813    }
03814 
03815    /* Map a key combination to an application*/
03816    ast_unregister_features();
03817    for (var = ast_variable_browse(cfg, "applicationmap"); var; var = var->next) {
03818       char *tmp_val = ast_strdupa(var->value);
03819       char *exten, *activateon, *activatedby, *app, *app_args, *moh_class; 
03820       struct ast_call_feature *feature;
03821 
03822       /* strsep() sets the argument to NULL if match not found, and it
03823        * is safe to use it with a NULL argument, so we don't check
03824        * between calls.
03825        */
03826       exten = strsep(&tmp_val,",");
03827       activatedby = strsep(&tmp_val,",");
03828       app = strsep(&tmp_val,",");
03829       app_args = strsep(&tmp_val,",");
03830       moh_class = strsep(&tmp_val,",");
03831 
03832       activateon = strsep(&activatedby, "/");   
03833 
03834       /*! \todo XXX var_name or app_args ? */
03835       if (ast_strlen_zero(app) || ast_strlen_zero(exten) || ast_strlen_zero(activateon) || ast_strlen_zero(var->name)) {
03836          ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",
03837             app, exten, activateon, var->name);
03838          continue;
03839       }
03840 
03841       AST_RWLIST_RDLOCK(&feature_list);
03842       if ((feature = find_dynamic_feature(var->name))) {
03843          AST_RWLIST_UNLOCK(&feature_list);
03844          ast_log(LOG_WARNING, "Dynamic Feature '%s' specified more than once!\n", var->name);
03845          continue;
03846       }
03847       AST_RWLIST_UNLOCK(&feature_list);
03848             
03849       if (!(feature = ast_calloc(1, sizeof(*feature))))
03850          continue;               
03851 
03852       ast_copy_string(feature->sname, var->name, FEATURE_SNAME_LEN);
03853       ast_copy_string(feature->app, app, FEATURE_APP_LEN);
03854       ast_copy_string(feature->exten, exten, FEATURE_EXTEN_LEN);
03855       
03856       if (app_args) 
03857          ast_copy_string(feature->app_args, app_args, FEATURE_APP_ARGS_LEN);
03858 
03859       if (moh_class)
03860          ast_copy_string(feature->moh_class, moh_class, FEATURE_MOH_LEN);
03861          
03862       ast_copy_string(feature->exten, exten, sizeof(feature->exten));
03863       feature->operation = feature_exec_app;
03864       ast_set_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF);
03865 
03866       /* Allow caller and calle to be specified for backwards compatability */
03867       if (!strcasecmp(activateon, "self") || !strcasecmp(activateon, "caller"))
03868          ast_set_flag(feature, AST_FEATURE_FLAG_ONSELF);
03869       else if (!strcasecmp(activateon, "peer") || !strcasecmp(activateon, "callee"))
03870          ast_set_flag(feature, AST_FEATURE_FLAG_ONPEER);
03871       else {
03872          ast_log(LOG_NOTICE, "Invalid 'ActivateOn' specification for feature '%s',"
03873             " must be 'self', or 'peer'\n", var->name);
03874          continue;
03875       }
03876 
03877       if (ast_strlen_zero(activatedby))
03878          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03879       else if (!strcasecmp(activatedby, "caller"))
03880          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLER);
03881       else if (!strcasecmp(activatedby, "callee"))
03882          ast_set_flag(feature, AST_FEATURE_FLAG_BYCALLEE);
03883       else if (!strcasecmp(activatedby, "both"))
03884          ast_set_flag(feature, AST_FEATURE_FLAG_BYBOTH);
03885       else {
03886          ast_log(LOG_NOTICE, "Invalid 'ActivatedBy' specification for feature '%s',"
03887             " must be 'caller', or 'callee', or 'both'\n", var->name);
03888          continue;
03889       }
03890 
03891       ast_register_feature(feature);
03892          
03893       ast_verb(2, "Mapping Feature '%s' to app '%s(%s)' with code '%s'\n", var->name, app, app_args, exten);
03894    }
03895 
03896    ast_unregister_groups();
03897    AST_RWLIST_WRLOCK(&feature_groups);
03898 
03899    ctg = NULL;
03900    while ((ctg = ast_category_browse(cfg, ctg))) {
03901       /* Is this a parkinglot definition ? */
03902       if (!strncasecmp(ctg, "parkinglot_", strlen("parkinglot_"))) {
03903          ast_debug(2, "Found configuration section %s, assume parking context\n", ctg);
03904          if(!build_parkinglot(ctg, ast_variable_browse(cfg, ctg)))
03905             ast_log(LOG_ERROR, "Could not build parking lot %s. Configuration error.\n", ctg);
03906          else
03907             ast_debug(1, "Configured parking context %s\n", ctg);
03908          continue;   
03909       }
03910       /* No, check if it's a group */
03911       for (i = 0; i < ARRAY_LEN(categories); i++) {
03912          if (!strcasecmp(categories[i], ctg))
03913             break;
03914       }
03915 
03916       if (i < ARRAY_LEN(categories)) 
03917          continue;
03918 
03919       if (!(fg = register_group(ctg)))
03920          continue;
03921 
03922       for (var = ast_variable_browse(cfg, ctg); var; var = var->next) {
03923          struct ast_call_feature *feature;
03924 
03925          AST_RWLIST_RDLOCK(&feature_list);
03926          if (!(feature = find_dynamic_feature(var->name)) && 
03927              !(feature = ast_find_call_feature(var->name))) {
03928             AST_RWLIST_UNLOCK(&feature_list);
03929             ast_log(LOG_WARNING, "Feature '%s' was not found.\n", var->name);
03930             continue;
03931          }
03932          AST_RWLIST_UNLOCK(&feature_list);
03933 
03934          register_group_feature(fg, var->value, feature);
03935       }
03936    }
03937 
03938    AST_RWLIST_UNLOCK(&feature_groups);
03939 
03940    ast_config_destroy(cfg);
03941 
03942    /* Remove the old parking extension */
03943    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
03944       if(ast_context_remove_extension2(con, old_parking_ext, 1, registrar, 0))
03945             notify_metermaids(old_parking_ext, old_parking_con, AST_DEVICE_NOT_INUSE);
03946       ast_debug(1, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
03947    }
03948    
03949    if (!(con = ast_context_find_or_create(NULL, NULL, default_parkinglot->parking_con, registrar))) {
03950       ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", default_parkinglot->parking_con);
03951       return -1;
03952    }
03953    res = ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, NULL, NULL, registrar);
03954    if (default_parkinglot->parkaddhints)
03955       park_add_hints(default_parkinglot->parking_con, default_parkinglot->parking_start, default_parkinglot->parking_stop);
03956    if (!res)
03957       notify_metermaids(ast_parking_ext(), default_parkinglot->parking_con, AST_DEVICE_INUSE);
03958    return res;
03959 
03960 }
03961 
03962 /*!
03963  * \brief CLI command to list configured features
03964  * \param e
03965  * \param cmd
03966  * \param a
03967  *
03968  * \retval CLI_SUCCESS on success.
03969  * \retval NULL when tab completion is used.
03970  */
03971 static char *handle_feature_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03972 {
03973    int i;
03974    struct ast_call_feature *feature;
03975    struct ao2_iterator iter;
03976    struct ast_parkinglot *curlot;
03977 #define HFS_FORMAT "%-25s %-7s %-7s\n"
03978 
03979    switch (cmd) {
03980    
03981    case CLI_INIT:
03982       e->command = "features show";
03983       e->usage =
03984          "Usage: features show\n"
03985          "       Lists configured features\n";
03986       return NULL;
03987    case CLI_GENERATE:
03988       return NULL;
03989    }
03990 
03991    ast_cli(a->fd, HFS_FORMAT, "Builtin Feature", "Default", "Current");
03992    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
03993 
03994    ast_cli(a->fd, HFS_FORMAT, "Pickup", "*8", ast_pickup_ext());          /* default hardcoded above, so we'll hardcode it here */
03995 
03996    ast_rwlock_rdlock(&features_lock);
03997    for (i = 0; i < FEATURES_COUNT; i++)
03998       ast_cli(a->fd, HFS_FORMAT, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
03999    ast_rwlock_unlock(&features_lock);
04000 
04001    ast_cli(a->fd, "\n");
04002    ast_cli(a->fd, HFS_FORMAT, "Dynamic Feature", "Default", "Current");
04003    ast_cli(a->fd, HFS_FORMAT, "---------------", "-------", "-------");
04004    if (AST_RWLIST_EMPTY(&feature_list)) {
04005       ast_cli(a->fd, "(none)\n");
04006    } else {
04007       AST_RWLIST_RDLOCK(&feature_list);
04008       AST_RWLIST_TRAVERSE(&feature_list, feature, feature_entry) {
04009          ast_cli(a->fd, HFS_FORMAT, feature->sname, "no def", feature->exten);
04010       }
04011       AST_RWLIST_UNLOCK(&feature_list);
04012    }
04013 
04014    // loop through all the parking lots
04015    iter = ao2_iterator_init(parkinglots, 0);
04016 
04017    while ((curlot = ao2_iterator_next(&iter))) {
04018       ast_cli(a->fd, "\nCall parking (Parking lot: %s)\n", curlot->name);
04019       ast_cli(a->fd, "------------\n");
04020       ast_cli(a->fd,"%-22s:      %s\n", "Parking extension", parking_ext);
04021       ast_cli(a->fd,"%-22s:      %s\n", "Parking context", curlot->parking_con);
04022       ast_cli(a->fd,"%-22s:      %d-%d\n", "Parked call extensions", curlot->parking_start, curlot->parking_stop);
04023       ast_cli(a->fd,"\n");
04024       ao2_ref(curlot, -1);
04025    }
04026 
04027 
04028    return CLI_SUCCESS;
04029 }
04030 
04031 int ast_features_reload(void)
04032 {
04033    int res;
04034    /* Release parking lot list */
04035    //ASTOBJ_CONTAINER_MARKALL(&parkinglots);
04036    // TODO: I don't think any marking is necessary
04037 
04038    /* Reload configuration */
04039    res = load_config();
04040    
04041    //ASTOBJ_CONTAINER_PRUNE_MARKED(&parkinglots, parkinglot_destroy);
04042    return res;
04043 }
04044 
04045 static char *handle_features_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04046 {
04047    switch (cmd) { 
04048    case CLI_INIT:
04049       e->command = "features reload";
04050       e->usage =
04051          "Usage: features reload\n"
04052          "       Reloads configured call features from features.conf\n";
04053       return NULL;
04054    case CLI_GENERATE:
04055       return NULL;
04056    }
04057    ast_features_reload();
04058 
04059    return CLI_SUCCESS;
04060 }
04061 
04062 static char mandescr_bridge[] =
04063 "Description: Bridge together two channels already in the PBX\n"
04064 "Variables: ( Headers marked with * are required )\n"
04065 "   *Channel1: Channel to Bridge to Channel2\n"
04066 "   *Channel2: Channel to Bridge to Channel1\n"
04067 "        Tone: (Yes|No) Play courtesy tone to Channel 2\n"
04068 "\n";
04069 
04070 /*!
04071  * \brief Actual bridge
04072  * \param chan
04073  * \param tmpchan
04074  * 
04075  * Stop hold music, lock both channels, masq channels,
04076  * after bridge return channel to next priority.
04077 */
04078 static void do_bridge_masquerade(struct ast_channel *chan, struct ast_channel *tmpchan)
04079 {
04080    ast_moh_stop(chan);
04081    ast_channel_lock(chan);
04082    ast_setstate(tmpchan, chan->_state);
04083    tmpchan->readformat = chan->readformat;
04084    tmpchan->writeformat = chan->writeformat;
04085    ast_channel_masquerade(tmpchan, chan);
04086    ast_channel_lock(tmpchan);
04087    ast_do_masquerade(tmpchan);
04088    /* when returning from bridge, the channel will continue at the next priority */
04089    ast_explicit_goto(tmpchan, chan->context, chan->exten, chan->priority + 1);
04090    ast_channel_unlock(tmpchan);
04091    ast_channel_unlock(chan);
04092 }
04093 
04094 /*!
04095  * \brief Bridge channels together
04096  * \param s
04097  * \param m
04098  * 
04099  * Make sure valid channels were specified, 
04100  * send errors if any of the channels could not be found/locked, answer channels if needed,
04101  * create the placeholder channels and grab the other channels 
04102  * make the channels compatible, send error if we fail doing so 
04103  * setup the bridge thread object and start the bridge.
04104  * 
04105  * \retval 0 on success or on incorrect use.
04106  * \retval 1 on failure to bridge channels.
04107 */
04108 static int action_bridge(struct mansession *s, const struct message *m)
04109 {
04110    const char *channela = astman_get_header(m, "Channel1");
04111    const char *channelb = astman_get_header(m, "Channel2");
04112    const char *playtone = astman_get_header(m, "Tone");
04113    struct ast_channel *chana = NULL, *chanb = NULL;
04114    struct ast_channel *tmpchana = NULL, *tmpchanb = NULL;
04115    struct ast_bridge_thread_obj *tobj = NULL;
04116 
04117    /* make sure valid channels were specified */
04118    if (ast_strlen_zero(channela) || ast_strlen_zero(channelb)) {
04119       astman_send_error(s, m, "Missing channel parameter in request");
04120       return 0;
04121    }
04122 
04123    /* The same code must be executed for chana and chanb.  To avoid a
04124     * theoretical deadlock, this code is separated so both chana and chanb will
04125     * not hold locks at the same time. */
04126 
04127    /* Start with chana */
04128    chana = ast_get_channel_by_name_prefix_locked(channela, strlen(channela));
04129 
04130    /* send errors if any of the channels could not be found/locked */
04131    if (!chana) {
04132       char buf[256];
04133       snprintf(buf, sizeof(buf), "Channel1 does not exists: %s", channela);
04134       astman_send_error(s, m, buf);
04135       return 0;
04136    }
04137 
04138    /* Answer the channels if needed */
04139    if (chana->_state != AST_STATE_UP)
04140       ast_answer(chana);
04141 
04142    /* create the placeholder channels and grab the other channels */
04143    if (!(tmpchana = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
04144       NULL, NULL, 0, "Bridge/%s", chana->name))) {
04145       astman_send_error(s, m, "Unable to create temporary channel!");
04146       ast_channel_unlock(chana);
04147       return 1;
04148    }
04149 
04150    do_bridge_masquerade(chana, tmpchana);
04151    ast_channel_unlock(chana);
04152    chana = NULL;
04153 
04154    /* now do chanb */
04155    chanb = ast_get_channel_by_name_prefix_locked(channelb, strlen(channelb));
04156    /* send errors if any of the channels could not be found/locked */
04157    if (!chanb) {
04158       char buf[256];
04159       snprintf(buf, sizeof(buf), "Channel2 does not exists: %s", channelb);
04160       ast_hangup(tmpchana);
04161       astman_send_error(s, m, buf);
04162       return 0;
04163    }
04164 
04165    /* Answer the channels if needed */
04166    if (chanb->_state != AST_STATE_UP)
04167       ast_answer(chanb);
04168 
04169    /* create the placeholder channels and grab the other channels */
04170    if (!(tmpchanb = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
04171       NULL, NULL, 0, "Bridge/%s", chanb->name))) {
04172       astman_send_error(s, m, "Unable to create temporary channels!");
04173       ast_hangup(tmpchana);
04174       ast_channel_unlock(chanb);
04175       return 1;
04176    }
04177    do_bridge_masquerade(chanb, tmpchanb);
04178    ast_channel_unlock(chanb);
04179    chanb = NULL;
04180 
04181    /* make the channels compatible, send error if we fail doing so */
04182    if (ast_channel_make_compatible(tmpchana, tmpchanb)) {
04183       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for manager bridge\n", tmpchana->name, tmpchanb->name);
04184       astman_send_error(s, m, "Could not make channels compatible for manager bridge");
04185       ast_hangup(tmpchana);
04186       ast_hangup(tmpchanb);
04187       return 1;
04188    }
04189 
04190    /* setup the bridge thread object and start the bridge */
04191    if (!(tobj = ast_calloc(1, sizeof(*tobj)))) {
04192       ast_log(LOG_WARNING, "Unable to spawn a new bridge thread on %s and %s: %s\n", tmpchana->name, tmpchanb->name, strerror(errno));
04193       astman_send_error(s, m, "Unable to spawn a new bridge thread");
04194       ast_hangup(tmpchana);
04195       ast_hangup(tmpchanb);
04196       return 1;
04197    }
04198 
04199    tobj->chan = tmpchana;
04200    tobj->peer = tmpchanb;
04201    tobj->return_to_pbx = 1;
04202 
04203    if (ast_true(playtone)) {
04204       if (!ast_strlen_zero(xfersound) && !ast_streamfile(tmpchanb, xfersound, tmpchanb->language)) {
04205          if (ast_waitstream(tmpchanb, "") < 0)
04206             ast_log(LOG_WARNING, "Failed to play a courtesy tone on chan %s\n", tmpchanb->name);
04207       }
04208    }
04209 
04210    ast_bridge_call_thread_launch(tobj);
04211 
04212    astman_send_ack(s, m, "Launched bridge thread with success");
04213 
04214    return 0;
04215 }
04216 
04217 /*!
04218  * \brief CLI command to list parked calls
04219  * \param e 
04220  * \param cmd
04221  * \param a
04222  *  
04223  * Check right usage, lock parking lot, display parked calls, unlock parking lot list.
04224  * \retval CLI_SUCCESS on success.
04225  * \retval CLI_SHOWUSAGE on incorrect number of arguments.
04226  * \retval NULL when tab completion is used.
04227 */
04228 static char *handle_parkedcalls(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04229 {
04230    struct parkeduser *cur;
04231    int numparked = 0;
04232    struct ao2_iterator iter;
04233    struct ast_parkinglot *curlot;
04234 
04235    switch (cmd) {
04236    case CLI_INIT:
04237       e->command = "parkedcalls show";
04238       e->usage =
04239          "Usage: parkedcalls show\n"
04240          "       List currently parked calls\n";
04241       return NULL;
04242    case CLI_GENERATE:
04243       return NULL;
04244    }
04245 
04246    if (a->argc > e->args)
04247       return CLI_SHOWUSAGE;
04248 
04249    ast_cli(a->fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
04250       , "Context", "Extension", "Pri", "Timeout");
04251 
04252    iter = ao2_iterator_init(parkinglots, 0);
04253    while ((curlot = ao2_iterator_next(&iter))) {
04254       int lotparked = 0;
04255       ast_cli(a->fd, "*** Parking lot: %s\n", curlot->name);
04256 
04257       AST_LIST_LOCK(&curlot->parkings);
04258       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
04259          ast_cli(a->fd, "%-10.10s %25s (%-15s %-12s %-4d) %6lds\n"
04260             ,cur->parkingexten, cur->chan->name, cur->context, cur->exten
04261             ,cur->priority,
04262             (long)(cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL)) );
04263          numparked++;
04264          numparked += lotparked;
04265       }
04266       AST_LIST_UNLOCK(&curlot->parkings);
04267       if (lotparked)
04268          ast_cli(a->fd, "   %d parked call%s in parking lot %s\n", lotparked, ESS(lotparked), curlot->name);
04269 
04270       ao2_ref(curlot, -1);
04271    }
04272 
04273    ast_cli(a->fd, "---\n%d parked call%s in total.\n", numparked, ESS(numparked));
04274 
04275    return CLI_SUCCESS;
04276 }
04277 
04278 static struct ast_cli_entry cli_features[] = {
04279    AST_CLI_DEFINE(handle_feature_show, "Lists configured features"),
04280    AST_CLI_DEFINE(handle_features_reload, "Reloads configured features"),
04281    AST_CLI_DEFINE(handle_parkedcalls, "List currently parked calls"),
04282 };
04283 
04284 /*! 
04285  * \brief Dump parking lot status
04286  * \param s
04287  * \param m
04288  * 
04289  * Lock parking lot, iterate list and append parked calls status, unlock parking lot.
04290  * \return Always RESULT_SUCCESS 
04291 */
04292 static int manager_parking_status(struct mansession *s, const struct message *m)
04293 {
04294    struct parkeduser *cur;
04295    const char *id = astman_get_header(m, "ActionID");
04296    char idText[256] = "";
04297    struct ao2_iterator iter;
04298    struct ast_parkinglot *curlot;
04299 
04300    if (!ast_strlen_zero(id))
04301       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
04302 
04303    astman_send_ack(s, m, "Parked calls will follow");
04304 
04305    iter = ao2_iterator_init(parkinglots, 0);
04306    while ((curlot = ao2_iterator_next(&iter))) {
04307 
04308       AST_LIST_LOCK(&curlot->parkings);
04309       AST_LIST_TRAVERSE(&curlot->parkings, cur, list) {
04310          astman_append(s, "Event: ParkedCall\r\n"
04311             "Exten: %d\r\n"
04312             "Channel: %s\r\n"
04313             "From: %s\r\n"
04314             "Timeout: %ld\r\n"
04315             "CallerIDNum: %s\r\n"
04316             "CallerIDName: %s\r\n"
04317             "%s"
04318             "\r\n",
04319             cur->parkingnum, cur->chan->name, cur->peername,
04320             (long) cur->start.tv_sec + (long) (cur->parkingtime / 1000) - (long) time(NULL),
04321             S_OR(cur->chan->cid.cid_num, ""),   /* XXX in other places it is <unknown> */
04322             S_OR(cur->chan->cid.cid_name, ""),
04323             idText);
04324       }
04325       AST_LIST_UNLOCK(&curlot->parkings);
04326       ao2_ref(curlot, -1);
04327    }
04328 
04329    astman_append(s,
04330       "Event: ParkedCallsComplete\r\n"
04331       "%s"
04332       "\r\n",idText);
04333 
04334 
04335    return RESULT_SUCCESS;
04336 }
04337 
04338 static char mandescr_park[] =
04339 "Description: Park a channel.\n"
04340 "Variables: (Names marked with * are required)\n"
04341 "  *Channel: Channel name to park\n"
04342 "  *Channel2: Channel to announce park info to (and return to if timeout)\n"
04343 "  Timeout: Number of milliseconds to wait before callback.\n";  
04344 
04345 /*!
04346  * \brief Create manager event for parked calls
04347  * \param s
04348  * \param m
04349  *
04350  * Get channels involved in park, create event.
04351  * \return Always 0
04352 */
04353 static int manager_park(struct mansession *s, const struct message *m)
04354 {
04355    const char *channel = astman_get_header(m, "Channel");
04356    const char *channel2 = astman_get_header(m, "Channel2");
04357    const char *timeout = astman_get_header(m, "Timeout");
04358    char buf[BUFSIZ];
04359    int to = 0;
04360    int res = 0;
04361    int parkExt = 0;
04362    struct ast_channel *ch1, *ch2;
04363 
04364    if (ast_strlen_zero(channel)) {
04365       astman_send_error(s, m, "Channel not specified");
04366       return 0;
04367    }
04368 
04369    if (ast_strlen_zero(channel2)) {
04370       astman_send_error(s, m, "Channel2 not specified");
04371       return 0;
04372    }
04373 
04374    ch1 = ast_get_channel_by_name_locked(channel);
04375    if (!ch1) {
04376       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel);
04377       astman_send_error(s, m, buf);
04378       return 0;
04379    }
04380 
04381    ch2 = ast_get_channel_by_name_locked(channel2);
04382    if (!ch2) {
04383       snprintf(buf, sizeof(buf), "Channel does not exist: %s", channel2);
04384       astman_send_error(s, m, buf);
04385       ast_channel_unlock(ch1);
04386       return 0;
04387    }
04388 
04389    if (!ast_strlen_zero(timeout)) {
04390       sscanf(timeout, "%30d", &to);
04391    }
04392 
04393    res = ast_masq_park_call(ch1, ch2, to, &parkExt);
04394    if (!res) {
04395       ast_softhangup(ch2, AST_SOFTHANGUP_EXPLICIT);
04396       astman_send_ack(s, m, "Park successful");
04397    } else {
04398       astman_send_error(s, m, "Park failure");
04399    }
04400 
04401    ast_channel_unlock(ch1);
04402    ast_channel_unlock(ch2);
04403 
04404    return 0;
04405 }
04406 
04407 /*!
04408  * \brief Pickup a call
04409  * \param chan channel that initiated pickup.
04410  *
04411  * Walk list of channels, checking it is not itself, channel is pbx one,
04412  * check that the callgroup for both channels are the same and the channel is ringing.
04413  * Answer calling channel, flag channel as answered on queue, masq channels together.
04414 */
04415 int ast_pickup_call(struct ast_channel *chan)
04416 {
04417    struct ast_channel *cur = NULL;
04418    int res = -1;
04419 
04420    while ((cur = ast_channel_walk_locked(cur)) != NULL) {
04421       if (!cur->pbx && 
04422          (cur != chan) &&
04423          (chan->pickupgroup & cur->callgroup) &&
04424          ((cur->_state == AST_STATE_RINGING) ||
04425           (cur->_state == AST_STATE_RING))) {
04426             break;
04427       }
04428       ast_channel_unlock(cur);
04429    }
04430    if (cur) {
04431       ast_debug(1, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
04432       res = ast_answer(chan);
04433       if (res)
04434          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
04435       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
04436       if (res)
04437          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
04438       res = ast_channel_masquerade(cur, chan);
04439       if (res)
04440          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
04441       ast_channel_unlock(cur);
04442    } else   {
04443       ast_debug(1, "No call pickup possible...\n");
04444    }
04445    return res;
04446 }
04447 
04448 static char *app_bridge = "Bridge";
04449 static char *bridge_synopsis = "Bridge two channels";
04450 static char *bridge_descrip =
04451 "Usage: Bridge(channel[,options])\n"
04452 "  Allows the ability to bridge two channels via the dialplan.\n"
04453 "The current channel is bridged to the specified 'channel'.\n"
04454 "  Options:\n"
04455 "    p - Play a courtesy tone to 'channel'.\n"
04456 "This application sets the following channel variable upon completion:\n"
04457 " BRIDGERESULT    The result of the bridge attempt as a text string, one of\n"
04458 "           SUCCESS | FAILURE | LOOP | NONEXISTENT | INCOMPATIBLE\n";
04459 
04460 enum {
04461    BRIDGE_OPT_PLAYTONE = (1 << 0),
04462 };
04463 
04464 AST_APP_OPTIONS(bridge_exec_options, BEGIN_OPTIONS
04465    AST_APP_OPTION('p', BRIDGE_OPT_PLAYTONE)
04466 END_OPTIONS );
04467 
04468 /*!
04469  * \brief Bridge channels
04470  * \param chan
04471  * \param data channel to bridge with.
04472  * 
04473  * Split data, check we aren't bridging with ourself, check valid channel,
04474  * answer call if not already, check compatible channels, setup bridge config
04475  * now bridge call, if transfered party hangs up return to PBX extension.
04476 */
04477 static int bridge_exec(struct ast_channel *chan, void *data)
04478 {
04479    struct ast_channel *current_dest_chan, *final_dest_chan;
04480    char *tmp_data  = NULL;
04481    struct ast_flags opts = { 0, };
04482    struct ast_bridge_config bconfig = { { 0, }, };
04483 
04484    AST_DECLARE_APP_ARGS(args,
04485       AST_APP_ARG(dest_chan);
04486       AST_APP_ARG(options);
04487    );
04488    
04489    if (ast_strlen_zero(data)) {
04490       ast_log(LOG_WARNING, "Bridge require at least 1 argument specifying the other end of the bridge\n");
04491       return -1;
04492    }
04493 
04494    tmp_data = ast_strdupa(data);
04495    AST_STANDARD_APP_ARGS(args, tmp_data);
04496    if (!ast_strlen_zero(args.options))
04497       ast_app_parse_options(bridge_exec_options, &opts, NULL, args.options);
04498 
04499    /* avoid bridge with ourselves */
04500    if (!strcmp(chan->name, args.dest_chan)) {
04501       ast_log(LOG_WARNING, "Unable to bridge channel %s with itself\n", chan->name);
04502       manager_event(EVENT_FLAG_CALL, "BridgeExec",
04503                "Response: Failed\r\n"
04504                "Reason: Unable to bridge channel to itself\r\n"
04505                "Channel1: %s\r\n"
04506                "Channel2: %s\r\n",
04507                chan->name, args.dest_chan);
04508       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "LOOP");
04509       return 0;
04510    }
04511 
04512    /* make sure we have a valid end point */
04513    if (!(current_dest_chan = ast_get_channel_by_name_prefix_locked(args.dest_chan, 
04514       strlen(args.dest_chan)))) {
04515       ast_log(LOG_WARNING, "Bridge failed because channel %s does not exists or we "
04516          "cannot get its lock\n", args.dest_chan);
04517       manager_event(EVENT_FLAG_CALL, "BridgeExec",
04518                "Response: Failed\r\n"
04519                "Reason: Cannot grab end point\r\n"
04520                "Channel1: %s\r\n"
04521                "Channel2: %s\r\n", chan->name, args.dest_chan);
04522       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "NONEXISTENT");
04523       return 0;
04524    }
04525 
04526    /* answer the channel if needed */
04527    if (current_dest_chan->_state != AST_STATE_UP)
04528       ast_answer(current_dest_chan);
04529 
04530    /* try to allocate a place holder where current_dest_chan will be placed */
04531    if (!(final_dest_chan = ast_channel_alloc(0, AST_STATE_DOWN, NULL, NULL, NULL, 
04532       NULL, NULL, 0, "Bridge/%s", current_dest_chan->name))) {
04533       ast_log(LOG_WARNING, "Cannot create placeholder channel for chan %s\n", args.dest_chan);
04534       manager_event(EVENT_FLAG_CALL, "BridgeExec",
04535                "Response: Failed\r\n"
04536                "Reason: cannot create placeholder\r\n"
04537                "Channel1: %s\r\n"
04538                "Channel2: %s\r\n", chan->name, args.dest_chan);
04539    }
04540    do_bridge_masquerade(current_dest_chan, final_dest_chan);
04541 
04542    ast_channel_unlock(current_dest_chan);
04543 
04544    /* now current_dest_chan is a ZOMBIE and with softhangup set to 1 and final_dest_chan is our end point */
04545    /* try to make compatible, send error if we fail */
04546    if (ast_channel_make_compatible(chan, final_dest_chan) < 0) {
04547       ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, final_dest_chan->name);
04548       manager_event(EVENT_FLAG_CALL, "BridgeExec",
04549                "Response: Failed\r\n"
04550                "Reason: Could not make channels compatible for bridge\r\n"
04551                "Channel1: %s\r\n"
04552                "Channel2: %s\r\n", chan->name, final_dest_chan->name);
04553       ast_hangup(final_dest_chan); /* may be we should return this channel to the PBX? */
04554       pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
04555       return 0;
04556    }
04557 
04558    /* Report that the bridge will be successfull */
04559    manager_event(EVENT_FLAG_CALL, "BridgeExec",
04560             "Response: Success\r\n"
04561             "Channel1: %s\r\n"
04562             "Channel2: %s\r\n", chan->name, final_dest_chan->name);
04563 
04564    /* we have 2 valid channels to bridge, now it is just a matter of setting up the bridge config and starting the bridge */  
04565    if (ast_test_flag(&opts, BRIDGE_OPT_PLAYTONE) && !ast_strlen_zero(xfersound)) {
04566       if (!ast_streamfile(final_dest_chan, xfersound, final_dest_chan->language)) {
04567          if (ast_waitstream(final_dest_chan, "") < 0)
04568             ast_log(LOG_WARNING, "Failed to play courtesy tone on %s\n", final_dest_chan->name);
04569       }
04570    }
04571    
04572    /* do the bridge */
04573    ast_bridge_call(chan, final_dest_chan, &bconfig);
04574 
04575    /* the bridge has ended, set BRIDGERESULT to SUCCESS. If the other channel has not been hung up, return it to the PBX */
04576    pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "SUCCESS");
04577    if (!ast_check_hangup(final_dest_chan)) {
04578       ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n", 
04579          final_dest_chan->context, final_dest_chan->exten, 
04580          final_dest_chan->priority, final_dest_chan->name);
04581 
04582       if (ast_pbx_start(final_dest_chan) != AST_PBX_SUCCESS) {
04583          ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", final_dest_chan->name);
04584          ast_hangup(final_dest_chan);
04585       } else
04586          ast_debug(1, "SUCCESS continuing PBX on chan %s\n", final_dest_chan->name);
04587    } else {
04588       ast_debug(1, "hangup chan %s since the other endpoint has hung up\n", final_dest_chan->name);
04589       ast_hangup(final_dest_chan);
04590    }
04591 
04592    return 0;
04593 }
04594 
04595 int ast_features_init(void)
04596 {
04597    int res;
04598 
04599    ast_register_application2(app_bridge, bridge_exec, bridge_synopsis, bridge_descrip, NULL);
04600 
04601    parkinglots = ao2_container_alloc(7, parkinglot_hash_cb, parkinglot_cmp_cb);
04602 
04603    if ((res = load_config()))
04604       return res;
04605    ast_cli_register_multiple(cli_features, sizeof(cli_features) / sizeof(struct ast_cli_entry));
04606    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
04607    res = ast_register_application2(parkedcall, park_exec, synopsis, descrip, NULL);
04608    if (!res)
04609       res = ast_register_application2(parkcall, park_call_exec, synopsis2, descrip2, NULL);
04610    if (!res) {
04611       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls");
04612       ast_manager_register2("Park", EVENT_FLAG_CALL, manager_park, "Park a channel", mandescr_park); 
04613       ast_manager_register2("Bridge", EVENT_FLAG_CALL, action_bridge, "Bridge two channels already in the PBX", mandescr_bridge);
04614    }
04615 
04616    res |= ast_devstate_prov_add("Park", metermaidstate);
04617 
04618    return res;
04619 }

Generated on 8 Apr 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1