Sat Mar 24 22:55:18 2007

Asterisk developer's documentation


res_features.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief Routines implementing call parking
00022  * 
00023  */
00024 
00025 #include <pthread.h>
00026 #include <stdlib.h>
00027 #include <errno.h>
00028 #include <unistd.h>
00029 #include <string.h>
00030 #include <stdlib.h>
00031 #include <stdio.h>
00032 #include <sys/time.h>
00033 #include <sys/signal.h>
00034 #include <netinet/in.h>
00035 
00036 #include "asterisk.h"
00037 
00038 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 38686 $")
00039 
00040 #include "asterisk/lock.h"
00041 #include "asterisk/file.h"
00042 #include "asterisk/logger.h"
00043 #include "asterisk/channel.h"
00044 #include "asterisk/pbx.h"
00045 #include "asterisk/options.h"
00046 #include "asterisk/causes.h"
00047 #include "asterisk/module.h"
00048 #include "asterisk/translate.h"
00049 #include "asterisk/app.h"
00050 #include "asterisk/say.h"
00051 #include "asterisk/features.h"
00052 #include "asterisk/musiconhold.h"
00053 #include "asterisk/config.h"
00054 #include "asterisk/cli.h"
00055 #include "asterisk/manager.h"
00056 #include "asterisk/utils.h"
00057 #include "asterisk/adsi.h"
00058 #include "asterisk/monitor.h"
00059 
00060 #ifdef __AST_DEBUG_MALLOC
00061 static void FREE(void *ptr)
00062 {
00063    free(ptr);
00064 }
00065 #else
00066 #define FREE free
00067 #endif
00068 
00069 #define DEFAULT_PARK_TIME 45000
00070 #define DEFAULT_TRANSFER_DIGIT_TIMEOUT 3000
00071 #define DEFAULT_FEATURE_DIGIT_TIMEOUT 500
00072 
00073 #define AST_MAX_WATCHERS 256
00074 
00075 static char *parkedcall = "ParkedCall";
00076 
00077 /* No more than 45 seconds parked before you do something with them */
00078 static int parkingtime = DEFAULT_PARK_TIME;
00079 
00080 /* Context for which parking is made accessible */
00081 static char parking_con[AST_MAX_EXTENSION];
00082 
00083 /* Context for dialback for parking (KLUDGE) */
00084 static char parking_con_dial[AST_MAX_EXTENSION];
00085 
00086 /* Extension you type to park the call */
00087 static char parking_ext[AST_MAX_EXTENSION];
00088 
00089 static char pickup_ext[AST_MAX_EXTENSION];
00090 
00091 /* Default sounds */
00092 static char courtesytone[256];
00093 static char xfersound[256];
00094 static char xferfailsound[256];
00095 
00096 /* First available extension for parking */
00097 static int parking_start;
00098 
00099 /* Last available extension for parking */
00100 static int parking_stop;
00101 
00102 static int parking_offset;
00103 
00104 static int parkfindnext;
00105 
00106 static int adsipark;
00107 
00108 static int transferdigittimeout;
00109 static int featuredigittimeout;
00110 
00111 /* Default courtesy tone played when party joins conference */
00112 
00113 /* Registrar for operations */
00114 static char *registrar = "res_features";
00115 
00116 static char *synopsis = "Answer a parked call";
00117 
00118 static char *descrip = "ParkedCall(exten):"
00119 "Used to connect to a parked call.  This application is always\n"
00120 "registered internally and does not need to be explicitly added\n"
00121 "into the dialplan, although you should include the 'parkedcalls'\n"
00122 "context.\n";
00123 
00124 static char *parkcall = "Park";
00125 
00126 static char *synopsis2 = "Park yourself";
00127 
00128 static char *descrip2 = "Park():"
00129 "Used to park yourself (typically in combination with a supervised\n"
00130 "transfer to know the parking space). This application is always\n"
00131 "registered internally and does not need to be explicitly added\n"
00132 "into the dialplan, although you should include the 'parkedcalls'\n"
00133 "context.\n";
00134 
00135 static struct ast_app *monitor_app=NULL;
00136 static int monitor_ok=1;
00137 
00138 struct parkeduser {
00139    struct ast_channel *chan;
00140    struct timeval start;
00141    int parkingnum;
00142    /* Where to go if our parking time expires */
00143    char context[AST_MAX_CONTEXT];
00144    char exten[AST_MAX_EXTENSION];
00145    int priority;
00146    int parkingtime;
00147    int notquiteyet;
00148    char peername[1024];
00149    unsigned char moh_trys;
00150    struct parkeduser *next;
00151 };
00152 
00153 static struct parkeduser *parkinglot;
00154 
00155 AST_MUTEX_DEFINE_STATIC(parking_lock);
00156 
00157 static pthread_t parking_thread;
00158 
00159 STANDARD_LOCAL_USER;
00160 
00161 LOCAL_USER_DECL;
00162 
00163 char *ast_parking_ext(void)
00164 {
00165    return parking_ext;
00166 }
00167 
00168 char *ast_pickup_ext(void)
00169 {
00170    return pickup_ext;
00171 }
00172 
00173 struct ast_bridge_thread_obj 
00174 {
00175    struct ast_bridge_config bconfig;
00176    struct ast_channel *chan;
00177    struct ast_channel *peer;
00178 };
00179 
00180 static void check_goto_on_transfer(struct ast_channel *chan) 
00181 {
00182    struct ast_channel *xferchan;
00183    char *goto_on_transfer;
00184 
00185    goto_on_transfer = pbx_builtin_getvar_helper(chan, "GOTO_ON_BLINDXFR");
00186 
00187    if (!ast_strlen_zero(goto_on_transfer) && (xferchan = ast_channel_alloc(0))) {
00188       char *x;
00189       struct ast_frame *f;
00190       
00191       for (x = goto_on_transfer; x && *x; x++)
00192          if (*x == '^')
00193             *x = '|';
00194 
00195       strcpy(xferchan->name, chan->name);
00196       /* Make formats okay */
00197       xferchan->readformat = chan->readformat;
00198       xferchan->writeformat = chan->writeformat;
00199       ast_channel_masquerade(xferchan, chan);
00200       ast_parseable_goto(xferchan, goto_on_transfer);
00201       xferchan->_state = AST_STATE_UP;
00202       ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00203       xferchan->_softhangup = 0;
00204       if ((f = ast_read(xferchan))) {
00205          ast_frfree(f);
00206          f = NULL;
00207          ast_pbx_start(xferchan);
00208       } else {
00209          ast_hangup(xferchan);
00210       }
00211    }
00212 }
00213 
00214 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name);
00215 
00216 
00217 static void *ast_bridge_call_thread(void *data) 
00218 {
00219    struct ast_bridge_thread_obj *tobj = data;
00220 
00221    tobj->chan->appl = "Transferred Call";
00222    tobj->chan->data = tobj->peer->name;
00223    tobj->peer->appl = "Transferred Call";
00224    tobj->peer->data = tobj->chan->name;
00225    if (tobj->chan->cdr) {
00226       ast_cdr_reset(tobj->chan->cdr, NULL);
00227       ast_cdr_setdestchan(tobj->chan->cdr, tobj->peer->name);
00228    }
00229    if (tobj->peer->cdr) {
00230       ast_cdr_reset(tobj->peer->cdr, NULL);
00231       ast_cdr_setdestchan(tobj->peer->cdr, tobj->chan->name);
00232    }
00233 
00234    ast_bridge_call(tobj->peer, tobj->chan, &tobj->bconfig);
00235    ast_hangup(tobj->chan);
00236    ast_hangup(tobj->peer);
00237    tobj->chan = tobj->peer = NULL;
00238    free(tobj);
00239    tobj=NULL;
00240    return NULL;
00241 }
00242 
00243 static void ast_bridge_call_thread_launch(void *data) 
00244 {
00245    pthread_t thread;
00246    pthread_attr_t attr;
00247    struct sched_param sched;
00248 
00249    pthread_attr_init(&attr);
00250    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
00251    ast_pthread_create(&thread, &attr,ast_bridge_call_thread, data);
00252    pthread_attr_destroy(&attr);
00253    memset(&sched, 0, sizeof(sched));
00254    pthread_setschedparam(thread, SCHED_RR, &sched);
00255 }
00256 
00257 
00258 
00259 static int adsi_announce_park(struct ast_channel *chan, int parkingnum)
00260 {
00261    int res;
00262    int justify[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT};
00263    char tmp[256];
00264    char *message[5] = {NULL, NULL, NULL, NULL, NULL};
00265 
00266    snprintf(tmp, sizeof(tmp), "Parked on %d", parkingnum);
00267    message[0] = tmp;
00268    res = adsi_load_session(chan, NULL, 0, 1);
00269    if (res == -1) {
00270       return res;
00271    }
00272    return adsi_print(chan, message, justify, 1);
00273 }
00274 
00275 /*--- ast_park_call: Park a call */
00276 /* We put the user in the parking list, then wake up the parking thread to be sure it looks
00277       after these channels too */
00278 int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
00279 {
00280    struct parkeduser *pu, *cur;
00281    int i,x,parking_range;
00282    char exten[AST_MAX_EXTENSION];
00283    struct ast_context *con;
00284 
00285    pu = malloc(sizeof(struct parkeduser));
00286    if (!pu) {
00287       ast_log(LOG_WARNING, "Out of memory\n");
00288       return -1;
00289    }
00290    memset(pu, 0, sizeof(struct parkeduser));
00291    ast_mutex_lock(&parking_lock);
00292    parking_range = parking_stop - parking_start+1;
00293    for (i = 0; i < parking_range; i++) {
00294       x = (i + parking_offset) % parking_range + parking_start;
00295       cur = parkinglot;
00296       while(cur) {
00297          if (cur->parkingnum == x) 
00298             break;
00299          cur = cur->next;
00300       }
00301       if (!cur)
00302          break;
00303    }
00304 
00305    if (!(i < parking_range)) {
00306       ast_log(LOG_WARNING, "No more parking spaces\n");
00307       free(pu);
00308       ast_mutex_unlock(&parking_lock);
00309       return -1;
00310    }
00311    if (parkfindnext) 
00312       parking_offset = x - parking_start + 1;
00313    chan->appl = "Parked Call";
00314    chan->data = NULL; 
00315 
00316    pu->chan = chan;
00317    /* Start music on hold */
00318    if (chan != peer) {
00319       ast_indicate(pu->chan, AST_CONTROL_HOLD);
00320       ast_moh_start(pu->chan, NULL);
00321    }
00322    pu->start = ast_tvnow();
00323    pu->parkingnum = x;
00324    if (timeout > 0)
00325       pu->parkingtime = timeout;
00326    else
00327       pu->parkingtime = parkingtime;
00328    if (extout)
00329       *extout = x;
00330    if (peer) 
00331       ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
00332 
00333    /* Remember what had been dialed, so that if the parking
00334       expires, we try to come back to the same place */
00335    if (!ast_strlen_zero(chan->macrocontext))
00336       ast_copy_string(pu->context, chan->macrocontext, sizeof(pu->context));
00337    else
00338       ast_copy_string(pu->context, chan->context, sizeof(pu->context));
00339    if (!ast_strlen_zero(chan->macroexten))
00340       ast_copy_string(pu->exten, chan->macroexten, sizeof(pu->exten));
00341    else
00342       ast_copy_string(pu->exten, chan->exten, sizeof(pu->exten));
00343    if (chan->macropriority)
00344       pu->priority = chan->macropriority;
00345    else
00346       pu->priority = chan->priority;
00347    pu->next = parkinglot;
00348    parkinglot = pu;
00349    /* If parking a channel directly, don't quiet yet get parking running on it */
00350    if (peer == chan) 
00351       pu->notquiteyet = 1;
00352    ast_mutex_unlock(&parking_lock);
00353    /* Wake up the (presumably select()ing) thread */
00354    pthread_kill(parking_thread, SIGURG);
00355    if (option_verbose > 1) 
00356       ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d. Will timeout back to extension [%s] %s, %d in %d seconds\n", pu->chan->name, pu->parkingnum, pu->context, pu->exten, pu->priority, (pu->parkingtime/1000));
00357 
00358    manager_event(EVENT_FLAG_CALL, "ParkedCall",
00359       "Exten: %d\r\n"
00360       "Channel: %s\r\n"
00361       "From: %s\r\n"
00362       "Timeout: %ld\r\n"
00363       "CallerID: %s\r\n"
00364       "CallerIDName: %s\r\n"
00365       ,pu->parkingnum, pu->chan->name, peer ? peer->name : ""
00366       ,(long)pu->start.tv_sec + (long)(pu->parkingtime/1000) - (long)time(NULL)
00367       ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
00368       ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
00369       );
00370 
00371    if (peer) {
00372       if (adsipark && adsi_available(peer)) {
00373          adsi_announce_park(peer, pu->parkingnum);
00374       }
00375       if (adsipark && adsi_available(peer)) {
00376          adsi_unload_session(peer);
00377       }
00378    }
00379    con = ast_context_find(parking_con);
00380    if (!con) {
00381       con = ast_context_create(NULL, parking_con, registrar);
00382       if (!con) {
00383          ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
00384       }
00385    }
00386    if (con) {
00387       snprintf(exten, sizeof(exten), "%d", x);
00388       ast_add_extension2(con, 1, exten, 1, NULL, NULL, parkedcall, strdup(exten), FREE, registrar);
00389    }
00390    if (peer) 
00391       ast_say_digits(peer, pu->parkingnum, "", peer->language);
00392    if (pu->notquiteyet) {
00393       /* Wake up parking thread if we're really done */
00394       ast_moh_start(pu->chan, NULL);
00395       pu->notquiteyet = 0;
00396       pthread_kill(parking_thread, SIGURG);
00397    }
00398    return 0;
00399 }
00400 
00401 int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
00402 {
00403    struct ast_channel *chan;
00404    struct ast_frame *f;
00405 
00406    /* Make a new, fake channel that we'll use to masquerade in the real one */
00407    chan = ast_channel_alloc(0);
00408    if (chan) {
00409       /* Let us keep track of the channel name */
00410       snprintf(chan->name, sizeof (chan->name), "Parked/%s",rchan->name);
00411 
00412       /* Make formats okay */
00413       chan->readformat = rchan->readformat;
00414       chan->writeformat = rchan->writeformat;
00415       ast_channel_masquerade(chan, rchan);
00416 
00417       /* Setup the extensions and such */
00418       ast_copy_string(chan->context, rchan->context, sizeof(chan->context));
00419       ast_copy_string(chan->exten, rchan->exten, sizeof(chan->exten));
00420       chan->priority = rchan->priority;
00421 
00422       /* Make the masq execute */
00423       f = ast_read(chan);
00424       if (f)
00425          ast_frfree(f);
00426       ast_park_call(chan, peer, timeout, extout);
00427    } else {
00428       ast_log(LOG_WARNING, "Unable to create parked channel\n");
00429       return -1;
00430    }
00431    return 0;
00432 }
00433 
00434 
00435 #define FEATURE_RETURN_HANGUP    -1
00436 #define FEATURE_RETURN_SUCCESSBREAK  0
00437 #define FEATURE_RETURN_PBX_KEEPALIVE   AST_PBX_KEEPALIVE
00438 #define FEATURE_RETURN_NO_HANGUP_PEER  AST_PBX_NO_HANGUP_PEER
00439 #define FEATURE_RETURN_PASSDIGITS    21
00440 #define FEATURE_RETURN_STOREDIGITS   22
00441 #define FEATURE_RETURN_SUCCESS       23
00442 
00443 #define FEATURE_SENSE_CHAN (1 << 0)
00444 #define FEATURE_SENSE_PEER (1 << 1)
00445 
00446 
00447 static int builtin_automonitor(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
00448 {
00449    char *touch_monitor = NULL, *caller_chan_id = NULL, *callee_chan_id = NULL, *args = NULL, *touch_format = NULL;
00450    int x = 0;
00451    size_t len;
00452    struct ast_channel *caller_chan = NULL, *callee_chan = NULL;
00453 
00454 
00455    if(sense == 2) {
00456       caller_chan = peer;
00457       callee_chan = chan;
00458    } else {
00459       callee_chan = peer;
00460       caller_chan = chan;
00461    }
00462    
00463    if (!monitor_ok) {
00464       ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00465       return -1;
00466    }
00467 
00468    if (!monitor_app) { 
00469       if (!(monitor_app = pbx_findapp("Monitor"))) {
00470          monitor_ok=0;
00471          ast_log(LOG_ERROR,"Cannot record the call. The monitor application is disabled.\n");
00472          return -1;
00473       }
00474    }
00475    if (!ast_strlen_zero(courtesytone)) {
00476       if (ast_autoservice_start(callee_chan))
00477          return -1;
00478       if (!ast_streamfile(caller_chan, courtesytone, caller_chan->language)) {
00479          if (ast_waitstream(caller_chan, "") < 0) {
00480             ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
00481             ast_autoservice_stop(callee_chan);
00482             return -1;
00483          }
00484       }
00485       if (ast_autoservice_stop(callee_chan))
00486          return -1;
00487    }
00488    
00489    if (callee_chan->monitor) {
00490       if (option_verbose > 3)
00491          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
00492       ast_monitor_stop(callee_chan, 1);
00493       return FEATURE_RETURN_SUCCESS;
00494    }
00495 
00496    if (caller_chan && callee_chan) {
00497       touch_format = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR_FORMAT");
00498       if (!touch_format)
00499          touch_format = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR_FORMAT");
00500 
00501       touch_monitor = pbx_builtin_getvar_helper(caller_chan, "TOUCH_MONITOR");
00502       if (!touch_monitor)
00503          touch_monitor = pbx_builtin_getvar_helper(callee_chan, "TOUCH_MONITOR");
00504       
00505       if (touch_monitor) {
00506          len = strlen(touch_monitor) + 50;
00507          args = alloca(len);
00508          snprintf(args, len, "%s|auto-%ld-%s|m", (touch_format) ? touch_format : "wav", time(NULL), touch_monitor);
00509       } else {
00510          caller_chan_id = ast_strdupa(caller_chan->cid.cid_num ? caller_chan->cid.cid_num : caller_chan->name);
00511          callee_chan_id = ast_strdupa(callee_chan->cid.cid_num ? callee_chan->cid.cid_num : callee_chan->name);
00512          len = strlen(caller_chan_id) + strlen(callee_chan_id) + 50;
00513          args = alloca(len);
00514          snprintf(args, len, "%s|auto-%ld-%s-%s|m", (touch_format) ? touch_format : "wav", time(NULL), caller_chan_id, callee_chan_id);
00515       }
00516 
00517       for( x = 0; x < strlen(args); x++)
00518          if (args[x] == '/')
00519             args[x] = '-';
00520       
00521       if (option_verbose > 3)
00522          ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to record call. filename: %s\n", code, args);
00523 
00524       pbx_exec(callee_chan, monitor_app, args, 1);
00525       
00526       return FEATURE_RETURN_SUCCESS;
00527    }
00528    
00529    ast_log(LOG_NOTICE,"Cannot record the call. One or both channels have gone away.\n");  
00530    return -1;
00531 }
00532 
00533 static int builtin_disconnect(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
00534 {
00535    if (option_verbose > 3)
00536       ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to disconnect call.\n", code);
00537    return FEATURE_RETURN_HANGUP;
00538 }
00539 
00540 static int builtin_blindtransfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
00541 {
00542    struct ast_channel *transferer;
00543    struct ast_channel *transferee;
00544    char *transferer_real_context;
00545    char newext[256];
00546    int res;
00547 
00548    if (sense == FEATURE_SENSE_PEER) {
00549       transferer = peer;
00550       transferee = chan;
00551    } else {
00552       transferer = chan;
00553       transferee = peer;
00554    }
00555    if (!(transferer_real_context = pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
00556       !(transferer_real_context = pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
00557       /* Use the non-macro context to transfer the call */
00558       if (!ast_strlen_zero(transferer->macrocontext))
00559          transferer_real_context = transferer->macrocontext;
00560       else
00561          transferer_real_context = transferer->context;
00562    }
00563    /* Start autoservice on chan while we talk
00564       to the originator */
00565    ast_indicate(transferee, AST_CONTROL_HOLD);
00566    ast_autoservice_start(transferee);
00567    ast_moh_start(transferee, NULL);
00568 
00569    memset(newext, 0, sizeof(newext));
00570    
00571    /* Transfer */
00572    if ((res=ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
00573       ast_moh_stop(transferee);
00574       ast_autoservice_stop(transferee);
00575       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00576       return res;
00577    }
00578    if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
00579       ast_moh_stop(transferee);
00580       ast_autoservice_stop(transferee);
00581       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00582       return res;
00583    } else if (res > 0) {
00584       /* If they've typed a digit already, handle it */
00585       newext[0] = (char) res;
00586    }
00587 
00588    ast_stopstream(transferer);
00589    res = ast_app_dtget(transferer, transferer_real_context, newext, sizeof(newext), 100, transferdigittimeout);
00590    if (res < 0) {
00591       ast_moh_stop(transferee);
00592       ast_autoservice_stop(transferee);
00593       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00594       return res;
00595    }
00596    if (!strcmp(newext, ast_parking_ext())) {
00597       ast_moh_stop(transferee);
00598 
00599       res = ast_autoservice_stop(transferee);
00600       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00601       if (res)
00602          res = -1;
00603       else if (!ast_park_call(transferee, transferer, 0, NULL)) {
00604          /* We return non-zero, but tell the PBX not to hang the channel when
00605             the thread dies -- We have to be careful now though.  We are responsible for 
00606             hanging up the channel, else it will never be hung up! */
00607 
00608          if (transferer == peer)
00609             res = AST_PBX_KEEPALIVE;
00610          else
00611             res = AST_PBX_NO_HANGUP_PEER;
00612          return res;
00613       } else {
00614          ast_log(LOG_WARNING, "Unable to park call %s\n", transferee->name);
00615       }
00616       /* XXX Maybe we should have another message here instead of invalid extension XXX */
00617    } else if (ast_exists_extension(transferee, transferer_real_context, newext, 1, transferer->cid.cid_num)) {
00618       pbx_builtin_setvar_helper(peer, "BLINDTRANSFER", chan->name);
00619       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", peer->name);
00620       ast_moh_stop(transferee);
00621       res=ast_autoservice_stop(transferee);
00622       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00623       if (!transferee->pbx) {
00624          /* Doh!  Use our handy async_goto functions */
00625          if (option_verbose > 2) 
00626             ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n"
00627                         ,transferee->name, newext, transferer_real_context);
00628          if (ast_async_goto(transferee, transferer_real_context, newext, 1))
00629             ast_log(LOG_WARNING, "Async goto failed :-(\n");
00630          res = -1;
00631       } else {
00632          /* Set the channel's new extension, since it exists, using transferer context */
00633          ast_copy_string(transferee->exten, newext, sizeof(transferee->exten));
00634          ast_copy_string(transferee->context, transferer_real_context, sizeof(transferee->context));
00635          transferee->priority = 0;
00636       }
00637       check_goto_on_transfer(transferer);
00638       return res;
00639    } else {
00640       if (option_verbose > 2) 
00641          ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context '%s'\n", newext, transferer_real_context);
00642    }
00643    if (!ast_strlen_zero(xferfailsound))
00644       res = ast_streamfile(transferer, xferfailsound, transferer->language);
00645    else
00646       res = 0;
00647    if (res) {
00648       ast_moh_stop(transferee);
00649       ast_autoservice_stop(transferee);
00650       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00651       return res;
00652    }
00653    res = ast_waitstream(transferer, AST_DIGIT_ANY);
00654    ast_stopstream(transferer);
00655    ast_moh_stop(transferee);
00656    res = ast_autoservice_stop(transferee);
00657    ast_indicate(transferee, AST_CONTROL_UNHOLD);
00658    if (res) {
00659       if (option_verbose > 1)
00660          ast_verbose(VERBOSE_PREFIX_2 "Hungup during autoservice stop on '%s'\n", transferee->name);
00661       return res;
00662    }
00663    return FEATURE_RETURN_SUCCESS;
00664 }
00665 
00666 static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
00667 {
00668    struct ast_channel *transferer;
00669    struct ast_channel *transferee;
00670    struct ast_channel *newchan, *xferchan=NULL;
00671    int outstate=0;
00672    struct ast_bridge_config bconfig;
00673    char *transferer_real_context;
00674    char xferto[256],dialstr[265];
00675    char *cid_num;
00676    char *cid_name;
00677    int res;
00678    struct ast_frame *f = NULL;
00679    struct ast_bridge_thread_obj *tobj;
00680 
00681    ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) XXX\n", chan->name, peer->name, sense);
00682    if (sense == FEATURE_SENSE_PEER) {
00683       transferer = peer;
00684       transferee = chan;
00685    } else {
00686       transferer = chan;
00687       transferee = peer;
00688    }
00689    if (!(transferer_real_context=pbx_builtin_getvar_helper(transferee, "TRANSFER_CONTEXT")) &&
00690       !(transferer_real_context=pbx_builtin_getvar_helper(transferer, "TRANSFER_CONTEXT"))) {
00691       /* Use the non-macro context to transfer the call */
00692       if (!ast_strlen_zero(transferer->macrocontext))
00693          transferer_real_context = transferer->macrocontext;
00694       else
00695          transferer_real_context = transferer->context;
00696    }
00697    /* Start autoservice on chan while we talk
00698       to the originator */
00699    ast_indicate(transferee, AST_CONTROL_HOLD);
00700    ast_autoservice_start(transferee);
00701    ast_moh_start(transferee, NULL);
00702    memset(xferto, 0, sizeof(xferto));
00703    /* Transfer */
00704    if ((res = ast_streamfile(transferer, "pbx-transfer", transferer->language))) {
00705       ast_moh_stop(transferee);
00706       ast_autoservice_stop(transferee);
00707       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00708       return res;
00709    }
00710    if ((res=ast_waitstream(transferer, AST_DIGIT_ANY)) < 0) {
00711       ast_moh_stop(transferee);
00712       ast_autoservice_stop(transferee);
00713       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00714       return res;
00715    } else if(res > 0) {
00716       /* If they've typed a digit already, handle it */
00717       xferto[0] = (char) res;
00718    }
00719    if ((ast_app_dtget(transferer, transferer_real_context, xferto, sizeof(xferto), 100, transferdigittimeout))) {
00720       cid_num = transferer->cid.cid_num;
00721       cid_name = transferer->cid.cid_name;
00722       if (ast_exists_extension(transferer, transferer_real_context,xferto, 1, cid_num)) {
00723          snprintf(dialstr, sizeof(dialstr), "%s@%s/n", xferto, transferer_real_context);
00724          newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats), dialstr, 15000, &outstate, cid_num, cid_name);
00725          ast_indicate(transferer, -1);
00726          if (newchan) {
00727             res = ast_channel_make_compatible(transferer, newchan);
00728             if (res < 0) {
00729                ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferer->name, newchan->name);
00730                ast_hangup(newchan);
00731                return -1;
00732             }
00733             memset(&bconfig,0,sizeof(struct ast_bridge_config));
00734             ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
00735             ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
00736             res = ast_bridge_call(transferer,newchan,&bconfig);
00737             if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) {
00738                ast_hangup(newchan);
00739                if (f) {
00740                   ast_frfree(f);
00741                   f = NULL;
00742                }
00743                if (!ast_strlen_zero(xfersound) && !ast_streamfile(transferer, xfersound, transferer->language)) {
00744                   if (ast_waitstream(transferer, "") < 0) {
00745                      ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00746                   }
00747                }
00748                ast_moh_stop(transferee);
00749                ast_autoservice_stop(transferee);
00750                ast_indicate(transferee, AST_CONTROL_UNHOLD);
00751                transferer->_softhangup = 0;
00752                return FEATURE_RETURN_SUCCESS;
00753             }
00754             
00755             res = ast_channel_make_compatible(transferee, newchan);
00756             if (res < 0) {
00757                ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", transferee->name, newchan->name);
00758                ast_hangup(newchan);
00759                return -1;
00760             }
00761             
00762             
00763             ast_moh_stop(transferee);
00764             
00765             if ((ast_autoservice_stop(transferee) < 0)
00766                || (ast_waitfordigit(transferee, 100) < 0)
00767                || (ast_waitfordigit(newchan, 100) < 0) 
00768                || ast_check_hangup(transferee) 
00769                || ast_check_hangup(newchan)) {
00770                ast_hangup(newchan);
00771                res = -1;
00772                return -1;
00773             }
00774 
00775             if ((xferchan = ast_channel_alloc(0))) {
00776                snprintf(xferchan->name, sizeof (xferchan->name), "Transfered/%s",transferee->name);
00777                /* Make formats okay */
00778                xferchan->readformat = transferee->readformat;
00779                xferchan->writeformat = transferee->writeformat;
00780                ast_channel_masquerade(xferchan, transferee);
00781                ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
00782                xferchan->_state = AST_STATE_UP;
00783                ast_clear_flag(xferchan, AST_FLAGS_ALL);  
00784                xferchan->_softhangup = 0;
00785 
00786                if ((f = ast_read(xferchan))) {
00787                   ast_frfree(f);
00788                   f = NULL;
00789                }
00790                
00791             } else {
00792                ast_hangup(newchan);
00793                return -1;
00794             }
00795 
00796             newchan->_state = AST_STATE_UP;
00797             ast_clear_flag(newchan, AST_FLAGS_ALL);   
00798             newchan->_softhangup = 0;
00799 
00800             tobj = malloc(sizeof(struct ast_bridge_thread_obj));
00801             if (tobj) {
00802                memset(tobj,0,sizeof(struct ast_bridge_thread_obj));
00803                tobj->chan = xferchan;
00804                tobj->peer = newchan;
00805                tobj->bconfig = *config;
00806    
00807                if (!ast_strlen_zero(xfersound) && !ast_streamfile(newchan, xfersound, newchan->language)) {
00808                   if (ast_waitstream(newchan, "") < 0) {
00809                      ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
00810                   }
00811                }
00812                ast_bridge_call_thread_launch(tobj);
00813             } else {
00814                ast_log(LOG_WARNING, "Out of memory!\n");
00815                ast_hangup(xferchan);
00816                ast_hangup(newchan);
00817             }
00818             return -1;
00819             
00820          } else {
00821             ast_moh_stop(transferee);
00822             ast_autoservice_stop(transferee);
00823             ast_indicate(transferee, AST_CONTROL_UNHOLD);
00824             /* any reason besides user requested cancel and busy triggers the failed sound */
00825             if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY && !ast_strlen_zero(xferfailsound)) {
00826                res = ast_streamfile(transferer, xferfailsound, transferer->language);
00827                if (!res && (ast_waitstream(transferer, "") < 0)) {
00828                   return -1;
00829                }
00830             }
00831             return FEATURE_RETURN_SUCCESS;
00832          }
00833       } else {
00834          ast_log(LOG_WARNING, "Extension %s does not exist in context %s\n",xferto,transferer_real_context);
00835          ast_moh_stop(transferee);
00836          ast_autoservice_stop(transferee);
00837          ast_indicate(transferee, AST_CONTROL_UNHOLD);
00838          res = ast_streamfile(transferer, "beeperr", transferer->language);
00839          if (!res && (ast_waitstream(transferer, "") < 0)) {
00840             return -1;
00841          }
00842       }
00843    }  else {
00844       ast_log(LOG_WARNING, "Did not read data.\n");
00845       ast_moh_stop(transferee);
00846       ast_autoservice_stop(transferee);
00847       ast_indicate(transferee, AST_CONTROL_UNHOLD);
00848       res = ast_streamfile(transferer, "beeperr", transferer->language);
00849       if (ast_waitstream(transferer, "") < 0) {
00850          return -1;
00851       }
00852    }
00853    ast_moh_stop(transferee);
00854    ast_autoservice_stop(transferee);
00855    ast_indicate(transferee, AST_CONTROL_UNHOLD);
00856 
00857    return FEATURE_RETURN_SUCCESS;
00858 }
00859 
00860 
00861 /* add atxfer and automon as undefined so you can only use em if you configure them */
00862 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
00863 struct ast_call_feature builtin_features[] = 
00864  {
00865    { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF },
00866    { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF },
00867    { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF },
00868    { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF },
00869 };
00870 
00871 
00872 static AST_LIST_HEAD_STATIC(feature_list,ast_call_feature);
00873 
00874 /* register new feature into feature_list*/
00875 void ast_register_feature(struct ast_call_feature *feature)
00876 {
00877    if (!feature) {
00878       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00879          return;
00880    }
00881   
00882    AST_LIST_LOCK(&feature_list);
00883    AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00884    AST_LIST_UNLOCK(&feature_list);
00885 
00886    if (option_verbose >= 2) 
00887       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00888 }
00889 
00890 /* unregister feature from feature_list */
00891 void ast_unregister_feature(struct ast_call_feature *feature)
00892 {
00893    if (!feature) return;
00894 
00895    AST_LIST_LOCK(&feature_list);
00896    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00897    AST_LIST_UNLOCK(&feature_list);
00898    free(feature);
00899 }
00900 
00901 static void ast_unregister_features(void)
00902 {
00903    struct ast_call_feature *feature;
00904 
00905    AST_LIST_LOCK(&feature_list);
00906    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
00907       free(feature);
00908    AST_LIST_UNLOCK(&feature_list);
00909 }
00910 
00911 /* find a feature by name */
00912 static struct ast_call_feature *find_feature(char *name)
00913 {
00914    struct ast_call_feature *tmp;
00915 
00916    AST_LIST_LOCK(&feature_list);
00917    AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
00918       if (!strcasecmp(tmp->sname, name))
00919          break;
00920    }
00921    AST_LIST_UNLOCK(&feature_list);
00922 
00923    return tmp;
00924 }
00925 
00926 /* exec an app by feature */
00927 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
00928 {
00929    struct ast_app *app;
00930    struct ast_call_feature *feature;
00931    int res;
00932 
00933    AST_LIST_LOCK(&feature_list);
00934    AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) {
00935       if (!strcasecmp(feature->exten,code)) break;
00936    }
00937    AST_LIST_UNLOCK(&feature_list);
00938 
00939    if (!feature) { /* shouldn't ever happen! */
00940       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
00941       return -1; 
00942    }
00943    
00944    app = pbx_findapp(feature->app);
00945    if (app) {
00946       struct ast_channel *work = chan;
00947       if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
00948          work = peer;
00949       res = pbx_exec(work, app, feature->app_args, 1);
00950       if (res == AST_PBX_KEEPALIVE)
00951          return FEATURE_RETURN_PBX_KEEPALIVE;
00952       else if (res == AST_PBX_NO_HANGUP_PEER)
00953          return FEATURE_RETURN_NO_HANGUP_PEER;
00954       else if (res)
00955          return FEATURE_RETURN_SUCCESSBREAK;
00956    } else {
00957       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
00958       return -2;
00959    }
00960    
00961    return FEATURE_RETURN_SUCCESS;
00962 }
00963 
00964 static void unmap_features(void)
00965 {
00966    int x;
00967    for (x = 0; x < FEATURES_COUNT; x++)
00968       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
00969 }
00970 
00971 static int remap_feature(const char *name, const char *value)
00972 {
00973    int x;
00974    int res = -1;
00975    for (x = 0; x < FEATURES_COUNT; x++) {
00976       if (!strcasecmp(name, builtin_features[x].sname)) {
00977          ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
00978          if (option_verbose > 1)
00979             ast_verbose(VERBOSE_PREFIX_2 "Remapping feature %s (%s) to sequence '%s'\n", builtin_features[x].fname, builtin_features[x].sname, builtin_features[x].exten);
00980          res = 0;
00981       } else if (!strcmp(value, builtin_features[x].exten)) 
00982          ast_log(LOG_WARNING, "Sequence '%s' already mapped to function %s (%s) while assigning to %s\n", value, builtin_features[x].fname, builtin_features[x].sname, name);
00983    }
00984    return res;
00985 }
00986 
00987 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
00988 {
00989    int x;
00990    struct ast_flags features;
00991    int res = FEATURE_RETURN_PASSDIGITS;
00992    struct ast_call_feature *feature;
00993    char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
00994 
00995    if (sense == FEATURE_SENSE_CHAN)
00996       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);   
00997    else
00998       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);   
00999    ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
01000 
01001    for (x=0; x < FEATURES_COUNT; x++) {
01002       if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
01003           !ast_strlen_zero(builtin_features[x].exten)) {
01004          /* Feature is up for consideration */
01005          if (!strcmp(builtin_features[x].exten, code)) {
01006             res = builtin_features[x].operation(chan, peer, config, code, sense);
01007             break;
01008          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01009             if (res == FEATURE_RETURN_PASSDIGITS)
01010                res = FEATURE_RETURN_STOREDIGITS;
01011          }
01012       }
01013    }
01014 
01015 
01016    if (!ast_strlen_zero(dynamic_features)) {
01017       char *tmp = ast_strdupa(dynamic_features);
01018       char *tok;
01019 
01020       if (!tmp)
01021          return res;
01022       
01023       while ((tok = strsep(&tmp, "#")) != NULL) {
01024          feature = find_feature(tok);
01025          
01026          if (feature) {
01027             /* Feature is up for consideration */
01028             if (!strcmp(feature->exten, code)) {
01029                if (option_verbose > 2)
01030                   ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
01031                if (sense == FEATURE_SENSE_CHAN)
01032                   res = feature->operation(chan, peer, config, code, sense);
01033                else
01034                   res = feature->operation(peer, chan, config, code, sense);
01035                break;
01036             } else if (!strncmp(feature->exten, code, strlen(code))) {
01037                res = FEATURE_RETURN_STOREDIGITS;
01038             }
01039          }
01040       }
01041    }
01042    
01043    return res;
01044 }
01045 
01046 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
01047 {
01048    int x;
01049    
01050    ast_clear_flag(config, AST_FLAGS_ALL); 
01051    for (x = 0; x < FEATURES_COUNT; x++) {
01052       if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) {
01053          if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01054             ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01055 
01056          if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01057             ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01058       }
01059    }
01060    
01061    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01062       char *dynamic_features;
01063 
01064       dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01065 
01066       if (dynamic_features) {
01067          char *tmp = ast_strdupa(dynamic_features);
01068          char *tok;
01069          struct ast_call_feature *feature;
01070 
01071          if (!tmp) {
01072             return;
01073          }
01074 
01075          /* while we have a feature */
01076          while (NULL != (tok = strsep(&tmp, "#"))) {
01077             if ((feature = find_feature(tok))) {
01078                if (ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01079                   if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER))
01080                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01081                   if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
01082                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01083                }
01084             }
01085          }
01086       }
01087    }
01088 }
01089 
01090 
01091 static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name)
01092 {
01093    int state = 0;
01094    int cause = 0;
01095    int to;
01096    struct ast_channel *chan;
01097    struct ast_channel *monitor_chans[2];
01098    struct ast_channel *active_channel;
01099    struct ast_frame *f = NULL;
01100    int res = 0, ready = 0;
01101    
01102    if ((chan = ast_request(type, format, data, &cause))) {
01103       ast_set_callerid(chan, cid_num, cid_name, cid_num);
01104       ast_channel_inherit_variables(caller, chan); 
01105       if (!ast_call(chan, data, timeout)) {
01106          struct timeval started;
01107          int x, len = 0;
01108          char *disconnect_code = NULL, *dialed_code = NULL;
01109 
01110          ast_indicate(caller, AST_CONTROL_RINGING);
01111          /* support dialing of the featuremap disconnect code while performing an attended tranfer */
01112          for (x=0; x < FEATURES_COUNT; x++) {
01113             if (strcasecmp(builtin_features[x].sname, "disconnect"))
01114                continue;
01115 
01116             disconnect_code = builtin_features[x].exten;
01117             len = strlen(disconnect_code) + 1;
01118             dialed_code = alloca(len);
01119             memset(dialed_code, 0, len);
01120             break;
01121          }
01122          x = 0;
01123          started = ast_tvnow();
01124          to = timeout;
01125          while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
01126             monitor_chans[0] = caller;
01127             monitor_chans[1] = chan;
01128             active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01129 
01130             /* see if the timeout has been violated */
01131             if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01132                state = AST_CONTROL_UNHOLD;
01133                ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01134                break; /*doh! timeout*/
01135             }
01136 
01137             if (!active_channel) {
01138                continue;
01139             }
01140 
01141             if (chan && (chan == active_channel)){
01142                f = ast_read(chan);
01143                if (f == NULL) { /*doh! where'd he go?*/
01144                   state = AST_CONTROL_HANGUP;
01145                   res = 0;
01146                   break;
01147                }
01148                
01149                if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01150                   if (f->subclass == AST_CONTROL_RINGING) {
01151                      state = f->subclass;
01152                      if (option_verbose > 2)
01153                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
01154                      ast_indicate(caller, AST_CONTROL_RINGING);
01155                   } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01156                      state = f->subclass;
01157                      if (option_verbose > 2)
01158                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
01159                      ast_indicate(caller, AST_CONTROL_BUSY);
01160                      ast_frfree(f);
01161                      f = NULL;
01162                      break;
01163                   } else if (f->subclass == AST_CONTROL_ANSWER) {
01164                      /* This is what we are hoping for */
01165                      state = f->subclass;
01166                      ast_frfree(f);
01167                      f = NULL;
01168                      ready=1;
01169                      break;
01170                   } else {
01171                      ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01172                   }
01173                   /* else who cares */
01174                }
01175 
01176             } else if (caller && (active_channel == caller)) {
01177                f = ast_read(caller);
01178                if (f == NULL) { /*doh! where'd he go?*/
01179                   if (caller->_softhangup && !chan->_softhangup) {
01180                      /* make this a blind transfer */
01181                      ready = 1;
01182                      break;
01183                   }
01184                   state = AST_CONTROL_HANGUP;
01185                   res = 0;
01186                   break;
01187                }
01188                
01189                if (f->frametype == AST_FRAME_DTMF) {
01190                   dialed_code[x++] = f->subclass;
01191                   dialed_code[x] = '\0';
01192                   if (strlen(dialed_code) == len) {
01193                      x = 0;
01194                   } else if (x && strncmp(dialed_code, disconnect_code, x)) {
01195                      x = 0;
01196                      dialed_code[x] = '\0';
01197                   }
01198                   if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
01199                      /* Caller Canceled the call */
01200                      state = AST_CONTROL_UNHOLD;
01201                      ast_frfree(f);
01202                      f = NULL;
01203                      break;
01204                   }
01205                }
01206             }
01207             if (f) {
01208                ast_frfree(f);
01209             }
01210          }
01211       } else
01212          ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
01213    } else {
01214       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01215       switch(cause) {
01216       case AST_CAUSE_BUSY:
01217          state = AST_CONTROL_BUSY;
01218          break;
01219       case AST_CAUSE_CONGESTION:
01220          state = AST_CONTROL_CONGESTION;
01221          break;
01222       }
01223    }
01224    
01225    ast_indicate(caller, -1);
01226    if (chan && ready) {
01227       if (chan->_state == AST_STATE_UP) 
01228          state = AST_CONTROL_ANSWER;
01229       res = 0;
01230    } else if(chan) {
01231       res = -1;
01232       ast_hangup(chan);
01233       chan = NULL;
01234    } else {
01235       res = -1;
01236    }
01237    
01238    if (outstate)
01239       *outstate = state;
01240 
01241    if (chan && res <= 0) {
01242       if (!chan->cdr) {
01243          chan->cdr = ast_cdr_alloc();
01244       }
01245       if (chan->cdr) {
01246          char tmp[256];
01247          ast_cdr_init(chan->cdr, chan);
01248          snprintf(tmp, 256, "%s/%s", type, (char *)data);
01249          ast_cdr_setapp(chan->cdr,"Dial",tmp);
01250          ast_cdr_update(chan);
01251          ast_cdr_start(chan->cdr);
01252          ast_cdr_end(chan->cdr);
01253          /* If the cause wasn't handled properly */
01254          if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
01255             ast_cdr_failed(chan->cdr);
01256       } else {
01257          ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
01258       }
01259    }
01260    
01261    return chan;
01262 }
01263 
01264 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
01265 {
01266    /* Copy voice back and forth between the two channels.  Give the peer
01267       the ability to transfer calls with '#<extension' syntax. */
01268    struct ast_frame *f;
01269    struct ast_channel *who;
01270    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01271    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01272    int res;
01273    int diff;
01274    int hasfeatures=0;
01275    int hadfeatures=0;
01276    struct ast_option_header *aoh;
01277    struct timeval start = { 0 , 0 };
01278    struct ast_bridge_config backup_config;
01279    char *monitor_exec;
01280 
01281    memset(&backup_config, 0, sizeof(backup_config));
01282 
01283    config->start_time = ast_tvnow();
01284 
01285    if (chan && peer) {
01286       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01287       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01288    } else if (chan)
01289       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01290 
01291    if (monitor_ok) {
01292       if (!monitor_app) { 
01293          if (!(monitor_app = pbx_findapp("Monitor")))
01294             monitor_ok=0;
01295       }
01296       if (monitor_app) {
01297          if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01298             pbx_exec(chan, monitor_app, monitor_exec, 1);
01299          else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01300             pbx_exec(peer, monitor_app, monitor_exec, 1);
01301       }
01302    }
01303    
01304    set_config_flags(chan, peer, config);
01305    config->firstpass = 1;
01306 
01307    /* Answer if need be */
01308    if (ast_answer(chan))
01309       return -1;
01310    peer->appl = "Bridged Call";
01311    peer->data = chan->name;
01312 
01313    /* copy the userfield from the B-leg to A-leg if applicable */
01314    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01315       char tmp[256];
01316       if (!ast_strlen_zero(chan->cdr->userfield)) {
01317          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01318          ast_cdr_appenduserfield(chan, tmp);
01319       } else
01320          ast_cdr_setuserfield(chan, peer->cdr->userfield);
01321       /* free the peer's cdr without ast_cdr_free complaining */
01322       free(peer->cdr);
01323       peer->cdr = NULL;
01324    }
01325    for (;;) {
01326       if (config->feature_timer)
01327          start = ast_tvnow();
01328 
01329       res = ast_channel_bridge(chan, peer, config, &f, &who);
01330 
01331       if (config->feature_timer) {
01332          /* Update time limit for next pass */
01333          diff = ast_tvdiff_ms(ast_tvnow(), start);
01334          config->feature_timer -= diff;
01335          if (hasfeatures) {
01336             /* Running on backup config, meaning a feature might be being
01337                activated, but that's no excuse to keep things going 
01338                indefinitely! */
01339             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01340                ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01341                config->feature_timer = 0;
01342                who = chan;
01343                if (f)
01344                   ast_frfree(f);
01345                f = NULL;
01346                res = 0;
01347             } else if (config->feature_timer <= 0) {
01348                /* Not *really* out of time, just out of time for
01349                   digits to come in for features. */
01350                ast_log(LOG_DEBUG, "Timed out for feature!\n");
01351                if (!ast_strlen_zero(peer_featurecode)) {
01352                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01353                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
01354                }
01355                if (!ast_strlen_zero(chan_featurecode)) {
01356                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01357                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
01358                }
01359                if (f)
01360                   ast_frfree(f);
01361                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01362                if (!hasfeatures) {
01363                   /* Restore original (possibly time modified) bridge config */
01364                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01365                   memset(&backup_config, 0, sizeof(backup_config));
01366                }
01367                hadfeatures = hasfeatures;
01368                /* Continue as we were */
01369                continue;
01370             }
01371          } else {
01372             if (config->feature_timer <=0) {
01373                /* We ran out of time */
01374                config->feature_timer = 0;
01375                who = chan;
01376                if (f)
01377                   ast_frfree(f);
01378                f = NULL;
01379                res = 0;
01380             }
01381          }
01382       }
01383       if (res < 0) {
01384          ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01385          return -1;
01386       }
01387       
01388       if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || 
01389          (f->subclass == AST_CONTROL_CONGESTION)))) {
01390             res = -1;
01391             break;
01392       }
01393       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
01394          if (who == chan)
01395             ast_indicate(peer, AST_CONTROL_RINGING);
01396          else
01397             ast_indicate(chan, AST_CONTROL_RINGING);
01398       }
01399       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
01400          if (who == chan)
01401             ast_indicate(peer, -1);
01402          else
01403             ast_indicate(chan, -1);
01404       }
01405       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) {
01406          if (who == chan)
01407             ast_indicate(peer, AST_CONTROL_FLASH);
01408          else
01409             ast_indicate(chan, AST_CONTROL_FLASH);
01410       }
01411       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
01412          aoh = f->data;
01413          /* Forward option Requests */
01414          if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
01415             if (who == chan)
01416                ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01417             else
01418                ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01419          }
01420       }
01421       /* check for '*', if we find it it's time to disconnect */
01422       if (f && (f->frametype == AST_FRAME_DTMF)) {
01423          char *featurecode;
01424          int sense;
01425          struct ast_channel *other;
01426 
01427          hadfeatures = hasfeatures;
01428          /* This cannot overrun because the longest feature is one shorter than our buffer */
01429          if (who == chan) {
01430             other = peer;
01431             sense = FEATURE_SENSE_CHAN;
01432             featurecode = chan_featurecode;
01433          } else  {
01434             other = chan;
01435             sense = FEATURE_SENSE_PEER;
01436             featurecode = peer_featurecode;
01437          }
01438          featurecode[strlen(featurecode)] = f->subclass;
01439          /* Get rid of the frame before we start doing "stuff" with the channels */
01440          ast_frfree(f);
01441          f = NULL;
01442          config->feature_timer = backup_config.feature_timer;
01443          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01444          switch(res) {
01445          case FEATURE_RETURN_PASSDIGITS:
01446             ast_dtmf_stream(other, who, featurecode, 0);
01447             /* Fall through */
01448          case FEATURE_RETURN_SUCCESS:
01449             memset(featurecode, 0, sizeof(chan_featurecode));
01450             break;
01451          }
01452          if (res >= FEATURE_RETURN_PASSDIGITS) {
01453             res = 0;
01454          } else 
01455             break;
01456          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01457          if (hadfeatures && !hasfeatures) {
01458             /* Restore backup */
01459             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01460             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01461          } else if (hasfeatures) {
01462             if (!hadfeatures) {
01463                /* Backup configuration */
01464                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01465                /* Setup temporary config options */
01466                config->play_warning = 0;
01467                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01468                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01469                config->warning_freq = 0;
01470                config->warning_sound = NULL;
01471                config->end_sound = NULL;
01472                config->start_sound = NULL;
01473                config->firstpass = 0;
01474             }
01475             config->start_time = ast_tvnow();
01476             config->feature_timer = featuredigittimeout;
01477             ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01478          }
01479       }
01480       if (f)
01481          ast_frfree(f);
01482    }
01483    return res;
01484 }
01485 
01486 static void *do_parking_thread(void *ignore)
01487 {
01488    int ms, tms, max;
01489    struct parkeduser *pu, *pl, *pt = NULL;
01490    struct timeval tv;
01491    struct ast_frame *f;
01492    char exten[AST_MAX_EXTENSION];
01493    char *peername,*cp;
01494    char returnexten[AST_MAX_EXTENSION];
01495    struct ast_context *con;
01496    int x;
01497    fd_set rfds, efds;
01498    fd_set nrfds, nefds;
01499    FD_ZERO(&rfds);
01500    FD_ZERO(&efds);
01501 
01502    for (;;) {
01503       ms = -1;
01504       max = -1;
01505       ast_mutex_lock(&parking_lock);
01506       pl = NULL;
01507       pu = parkinglot;
01508       FD_ZERO(&nrfds);
01509       FD_ZERO(&nefds);
01510       while(pu) {
01511          if (pu->notquiteyet) {
01512             /* Pretend this one isn't here yet */
01513             pl = pu;
01514             pu = pu->next;
01515             continue;
01516          }
01517          tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
01518          if (tms > pu->parkingtime) {
01519             /* Stop music on hold */
01520             ast_moh_stop(pu->chan);
01521             ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
01522             /* Get chan, exten from derived kludge */
01523             if (pu->peername[0]) {
01524                peername = ast_strdupa(pu->peername);
01525                cp = strrchr(peername, '-');
01526                if (cp) 
01527                   *cp = 0;
01528                con = ast_context_find(parking_con_dial);
01529                if (!con) {
01530                   con = ast_context_create(NULL, parking_con_dial, registrar);
01531                   if (!con) {
01532                      ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
01533                   }
01534                }
01535                if (con) {
01536                   snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
01537                   ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
01538                }
01539                ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten));
01540                ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context));
01541                pu->chan->priority = 1;
01542 
01543             } else {
01544                /* They've been waiting too long, send them back to where they came.  Theoretically they
01545                   should have their original extensions and such, but we copy to be on the safe side */
01546                ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten));
01547                ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context));
01548                pu->chan->priority = pu->priority;
01549             }
01550 
01551             manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
01552                "Exten: %d\r\n"
01553                "Channel: %s\r\n"
01554                "CallerID: %s\r\n"
01555                "CallerIDName: %s\r\n"
01556                ,pu->parkingnum, pu->chan->name
01557                ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01558                ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01559                );
01560 
01561             if (option_verbose > 1) 
01562                ast_verbose(VERBOSE_PREFIX_2 "Timeout for %s parked on %d. Returning to %s,%s,%d\n", pu->chan->name, pu->parkingnum, pu->chan->context, pu->chan->exten, pu->chan->priority);
01563             /* Start up the PBX, or hang them up */
01564             if (ast_pbx_start(pu->chan))  {
01565                ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
01566                ast_hangup(pu->chan);
01567             }
01568             /* And take them out of the parking lot */
01569             if (pl) 
01570                pl->next = pu->next;
01571             else
01572                parkinglot = pu->next;
01573             pt = pu;
01574             pu = pu->next;
01575             con = ast_context_find(parking_con);
01576             if (con) {
01577                snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
01578                if (ast_context_remove_extension2(con, exten, 1, NULL))
01579                   ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01580             } else
01581                ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01582             free(pt);
01583          } else {
01584             for (x = 0; x < AST_MAX_FDS; x++) {
01585                if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
01586                   if (FD_ISSET(pu->chan->fds[x], &efds))
01587                      ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
01588                   else
01589                      ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
01590                   pu->chan->fdno = x;
01591                   /* See if they need servicing */
01592                   f = ast_read(pu->chan);
01593                   if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
01594                      if (f)
01595                         ast_frfree(f);
01596                      manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
01597                         "Exten: %d\r\n"
01598                         "Channel: %s\r\n"
01599                         "CallerID: %s\r\n"
01600                         "CallerIDName: %s\r\n"
01601                         ,pu->parkingnum, pu->chan->name
01602                         ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01603                         ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01604                         );
01605 
01606                      /* There's a problem, hang them up*/
01607                      if (option_verbose > 1) 
01608                         ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
01609                      ast_hangup(pu->chan);
01610                      /* And take them out of the parking lot */
01611                      if (pl) 
01612                         pl->next = pu->next;
01613                      else
01614                         parkinglot = pu->next;
01615                      pt = pu;
01616                      pu = pu->next;
01617                      con = ast_context_find(parking_con);
01618                      if (con) {
01619                         snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
01620                         if (ast_context_remove_extension2(con, exten, 1, NULL))
01621                            ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01622                      } else
01623                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01624                      free(pt);
01625                      break;
01626                   } else {
01627                      /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
01628                      ast_frfree(f);
01629                      if (pu->moh_trys < 3 && !pu->chan->generatordata) {
01630                         ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
01631                         ast_moh_start(pu->chan, NULL);
01632                         pu->moh_trys++;
01633                      }
01634                      goto std;   /* XXX Ick: jumping into an else statement??? XXX */
01635                   }
01636                }
01637             }
01638             if (x >= AST_MAX_FDS) {
01639 std:              for (x=0; x<AST_MAX_FDS; x++) {
01640                   /* Keep this one for next one */
01641                   if (pu->chan->fds[x] > -1) {
01642                      FD_SET(pu->chan->fds[x], &nrfds);
01643                      FD_SET(pu->chan->fds[x], &nefds);
01644                      if (pu->chan->fds[x] > max)
01645                         max = pu->chan->fds[x];
01646                   }
01647                }
01648                /* Keep track of our longest wait */
01649                if ((tms < ms) || (ms < 0))
01650                   ms = tms;
01651                pl = pu;
01652                pu = pu->next;
01653             }
01654          }
01655       }
01656       ast_mutex_unlock(&parking_lock);
01657       rfds = nrfds;
01658       efds = nefds;
01659       tv = ast_samp2tv(ms, 1000);
01660       /* Wait for something to happen */
01661       ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
01662       pthread_testcancel();
01663    }
01664    return NULL;   /* Never reached */
01665 }
01666 
01667 static int park_call_exec(struct ast_channel *chan, void *data)
01668 {
01669    /* Data is unused at the moment but could contain a parking
01670       lot context eventually */
01671    int res=0;
01672    struct localuser *u;
01673    LOCAL_USER_ADD(u);
01674    /* Setup the exten/priority to be s/1 since we don't know
01675       where this call should return */
01676    strcpy(chan->exten, "s");
01677    chan->priority = 1;
01678    if (chan->_state != AST_STATE_UP)
01679       res = ast_answer(chan);
01680    if (!res)
01681       res = ast_safe_sleep(chan, 1000);
01682    if (!res)
01683       res = ast_park_call(chan, chan, 0, NULL);
01684    LOCAL_USER_REMOVE(u);
01685    if (!res)
01686       res = AST_PBX_KEEPALIVE;
01687    return res;
01688 }
01689 
01690 static int park_exec(struct ast_channel *chan, void *data)
01691 {
01692    int res=0;
01693    struct localuser *u;
01694    struct ast_channel *peer=NULL;
01695    struct parkeduser *pu, *pl=NULL;
01696    char exten[AST_MAX_EXTENSION];
01697    struct ast_context *con;
01698    int park;
01699    int dres;
01700    struct ast_bridge_config config;
01701 
01702    if (!data) {
01703       ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
01704       return -1;
01705    }
01706    LOCAL_USER_ADD(u);
01707    park = atoi((char *)data);
01708    ast_mutex_lock(&parking_lock);
01709    pu = parkinglot;
01710    while(pu) {
01711       if (pu->parkingnum == park) {
01712          if (pl)
01713             pl->next = pu->next;
01714          else
01715             parkinglot = pu->next;
01716          break;
01717       }
01718       pl = pu;
01719       pu = pu->next;
01720    }
01721    ast_mutex_unlock(&parking_lock);
01722    if (pu) {
01723       peer = pu->chan;
01724       con = ast_context_find(parking_con);
01725       if (con) {
01726          snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
01727          if (ast_context_remove_extension2(con, exten, 1, NULL))
01728             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01729       } else
01730          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01731 
01732       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
01733          "Exten: %d\r\n"
01734          "Channel: %s\r\n"
01735          "From: %s\r\n"
01736          "CallerID: %s\r\n"
01737          "CallerIDName: %s\r\n"
01738          ,pu->parkingnum, pu->chan->name, chan->name
01739          ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01740          ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01741          );
01742 
01743       free(pu);
01744    }
01745    /* JK02: it helps to answer the channel if not already up */
01746    if (chan->_state != AST_STATE_UP) {
01747       ast_answer(chan);
01748    }
01749 
01750    if (peer) {
01751       /* Play a courtesy beep in the calling channel to prefix the bridge connecting */   
01752       if (!ast_strlen_zero(courtesytone)) {
01753          if (!ast_streamfile(chan, courtesytone, chan->language)) {
01754             if (ast_waitstream(chan, "") < 0) {
01755                ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01756                ast_hangup(peer);
01757                return -1;
01758             }
01759          }
01760       }
01761  
01762       ast_moh_stop(peer);
01763       ast_indicate(peer, AST_CONTROL_UNHOLD);
01764       res = ast_channel_make_compatible(chan, peer);
01765       if (res < 0) {
01766          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
01767          ast_hangup(peer);
01768          return -1;
01769       }
01770       /* This runs sorta backwards, since we give the incoming channel control, as if it
01771          were the person called. */
01772       if (option_verbose > 2) 
01773          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
01774 
01775       memset(&config, 0, sizeof(struct ast_bridge_config));
01776       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
01777       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
01778       config.timelimit = 0;
01779       config.play_warning = 0;
01780       config.warning_freq = 0;
01781       config.warning_sound=NULL;
01782       res = ast_bridge_call(chan, peer, &config);
01783 
01784       /* Simulate the PBX hanging up */
01785       if (res != AST_PBX_NO_HANGUP_PEER)
01786          ast_hangup(peer);
01787       return res;
01788    } else {
01789       /* XXX Play a message XXX */
01790       dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
01791       if (!dres)
01792             dres = ast_waitstream(chan, "");
01793       else {
01794          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
01795          dres = 0;
01796       }
01797       if (option_verbose > 2) 
01798          ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
01799       res = -1;
01800    }
01801    LOCAL_USER_REMOVE(u);
01802    return res;
01803 }
01804 
01805 static int handle_showfeatures(int fd, int argc, char *argv[])
01806 {
01807    int i;
01808    int fcount;
01809    struct ast_call_feature *feature;
01810    char format[] = "%-25s %-7s %-7s\n";
01811 
01812    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
01813    ast_cli(fd, format, "---------------", "-------", "-------");
01814 
01815    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
01816 
01817    fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
01818 
01819    for (i = 0; i < fcount; i++)
01820    {
01821       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
01822    }
01823    ast_cli(fd, "\n");
01824    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
01825    ast_cli(fd, format, "---------------", "-------", "-------");
01826    if (AST_LIST_EMPTY(&feature_list)) {
01827       ast_cli(fd, "(none)\n");
01828    }
01829    else {
01830       AST_LIST_LOCK(&feature_list);
01831       AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
01832          ast_cli(fd, format, feature->sname, "no def", feature->exten); 
01833       }
01834       AST_LIST_UNLOCK(&feature_list);
01835    }
01836    ast_cli(fd, "\nCall parking\n");
01837    ast_cli(fd, "------------\n");
01838    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
01839    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
01840    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
01841    ast_cli(fd,"\n");
01842    
01843    return RESULT_SUCCESS;
01844 }
01845 
01846 static char showfeatures_help[] =
01847 "Usage: show features\n"
01848 "       Lists currently configured features.\n";
01849 
01850 static struct ast_cli_entry showfeatures =
01851 { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help };
01852 
01853 static int handle_parkedcalls(int fd, int argc, char *argv[])
01854 {
01855    struct parkeduser *cur;
01856    int numparked = 0;
01857 
01858    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
01859       , "Context", "Extension", "Pri", "Timeout");
01860 
01861    ast_mutex_lock(&parking_lock);
01862 
01863    cur = parkinglot;
01864    while(cur) {
01865       ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
01866          ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
01867          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
01868 
01869       cur = cur->next;
01870       numparked++;
01871    }
01872    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
01873 
01874    ast_mutex_unlock(&parking_lock);
01875 
01876    return RESULT_SUCCESS;
01877 }
01878 
01879 static char showparked_help[] =
01880 "Usage: show parkedcalls\n"
01881 "       Lists currently parked calls.\n";
01882 
01883 static struct ast_cli_entry showparked =
01884 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
01885 
01886 /* Dump lot status */
01887 static int manager_parking_status( struct mansession *s, struct message *m )
01888 {
01889    struct parkeduser *cur;
01890    char *id = astman_get_header(m,"ActionID");
01891    char idText[256] = "";
01892 
01893    if (!ast_strlen_zero(id))
01894       snprintf(idText,256,"ActionID: %s\r\n",id);
01895 
01896    astman_send_ack(s, m, "Parked calls will follow");
01897 
01898         ast_mutex_lock(&parking_lock);
01899 
01900         cur=parkinglot;
01901         while(cur) {
01902          ast_cli(s->fd, "Event: ParkedCall\r\n"
01903          "Exten: %d\r\n"
01904          "Channel: %s\r\n"
01905          "Timeout: %ld\r\n"
01906          "CallerID: %s\r\n"
01907          "CallerIDName: %s\r\n"
01908          "%s"
01909          "\r\n"
01910                         ,cur->parkingnum, cur->chan->name
01911                         ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
01912          ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
01913          ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
01914          ,idText);
01915 
01916             cur = cur->next;
01917         }
01918 
01919    ast_cli(s->fd,
01920    "Event: ParkedCallsComplete\r\n"
01921    "%s"
01922    "\r\n",idText);
01923 
01924         ast_mutex_unlock(&parking_lock);
01925 
01926         return RESULT_SUCCESS;
01927 }
01928 
01929 
01930 int ast_pickup_call(struct ast_channel *chan)
01931 {
01932    struct ast_channel *cur = NULL;
01933    int res = -1;
01934 
01935    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
01936       if (!cur->pbx && 
01937          (cur != chan) &&
01938          (chan->pickupgroup & cur->callgroup) &&
01939          ((cur->_state == AST_STATE_RINGING) ||
01940           (cur->_state == AST_STATE_RING))) {
01941             break;
01942       }
01943       ast_mutex_unlock(&cur->lock);
01944    }
01945    if (cur) {
01946       if (option_debug)
01947          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
01948       res = ast_answer(chan);
01949       if (res)
01950          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
01951       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
01952       if (res)
01953          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
01954       res = ast_channel_masquerade(cur, chan);
01955       if (res)
01956          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
01957       ast_mutex_unlock(&cur->lock);
01958    } else   {
01959       if (option_debug)
01960          ast_log(LOG_DEBUG, "No call pickup possible...\n");
01961    }
01962    return res;
01963 }
01964 
01965 static int load_config(void) 
01966 {
01967    int start = 0, end = 0;
01968    struct ast_context *con = NULL;
01969    struct ast_config *cfg = NULL;
01970    struct ast_variable *var = NULL;
01971    char old_parking_ext[AST_MAX_EXTENSION];
01972    char old_parking_con[AST_MAX_EXTENSION] = "";
01973 
01974    if (!ast_strlen_zero(parking_con)) {
01975       strcpy(old_parking_ext, parking_ext);
01976       strcpy(old_parking_con, parking_con);
01977    } 
01978 
01979    /* Reset to defaults */
01980    strcpy(parking_con, "parkedcalls");
01981    strcpy(parking_con_dial, "park-dial");
01982    strcpy(parking_ext, "700");
01983    strcpy(pickup_ext, "*8");
01984    courtesytone[0] = '\0';
01985    strcpy(xfersound, "beep");
01986    strcpy(xferfailsound, "pbx-invalid");
01987    parking_start = 701;
01988    parking_stop = 750;
01989    parkfindnext = 0;
01990    adsipark = 0;
01991 
01992    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
01993    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
01994 
01995    cfg = ast_config_load("features.conf");
01996    if (!cfg) {
01997       cfg = ast_config_load("parking.conf");
01998       if (cfg)
01999          ast_log(LOG_NOTICE, "parking.conf is deprecated in favor of 'features.conf'.  Please rename it.\n");
02000    }
02001    if (cfg) {
02002       var = ast_variable_browse(cfg, "general");
02003       while(var) {
02004          if (!strcasecmp(var->name, "parkext")) {
02005             ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
02006          } else if (!strcasecmp(var->name, "context")) {
02007             ast_copy_string(parking_con, var->value, sizeof(parking_con));
02008          } else if (!strcasecmp(var->name, "parkingtime")) {
02009             if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
02010                ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
02011                parkingtime = DEFAULT_PARK_TIME;
02012             } else
02013                parkingtime = parkingtime * 1000;
02014          } else if (!strcasecmp(var->name, "parkpos")) {
02015             if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
02016                ast_log(LOG_WARNING, "Format for parking positions is a-b, where a and b are numbers at line %d of parking.conf\n", var->lineno);
02017             } else {
02018                parking_start = start;
02019                parking_stop = end;
02020             }
02021          } else if (!strcasecmp(var->name, "findslot")) {
02022             parkfindnext = (!strcasecmp(var->value, "next"));
02023          } else if (!strcasecmp(var->name, "adsipark")) {
02024             adsipark = ast_true(var->value);
02025          } else if (!strcasecmp(var->name, "transferdigittimeout")) {
02026             if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
02027                ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
02028                transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02029             } else
02030                transferdigittimeout = transferdigittimeout * 1000;
02031          } else if (!strcasecmp(var->name, "featuredigittimeout")) {
02032             if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
02033                ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
02034                featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02035             }
02036          } else if (!strcasecmp(var->name, "courtesytone")) {
02037             ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
02038          } else if (!strcasecmp(var->name, "xfersound")) {
02039             ast_copy_string(xfersound, var->value, sizeof(xfersound));
02040          } else if (!strcasecmp(var->name, "xferfailsound")) {
02041             ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
02042          } else if (!strcasecmp(var->name, "pickupexten")) {
02043             ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
02044          }
02045          var = var->next;
02046       }
02047 
02048       unmap_features();
02049       var = ast_variable_browse(cfg, "featuremap");
02050       while(var) {
02051          if (remap_feature(var->name, var->value))
02052             ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
02053          var = var->next;
02054       }
02055 
02056       /* Map a key combination to an application*/
02057       ast_unregister_features();
02058       var = ast_variable_browse(cfg, "applicationmap");
02059       while(var) {
02060          char *tmp_val=strdup(var->value);
02061          char *exten, *party=NULL, *app=NULL, *app_args=NULL; 
02062 
02063          if (!tmp_val) { 
02064             ast_log(LOG_ERROR, "res_features: strdup failed");
02065             continue;
02066          }
02067          
02068 
02069          exten=strsep(&tmp_val,",");
02070          if (exten) party=strsep(&tmp_val,",");
02071          if (party) app=strsep(&tmp_val,",");
02072 
02073          if (app) app_args=strsep(&tmp_val,",");
02074 
02075          if (!(app && strlen(app)) || !(exten && strlen(exten)) || !(party && strlen(party)) || !(var->name && strlen(var->name))) {
02076             ast_log(LOG_NOTICE, "Please check the feature Mapping Syntax, either extension, name, or app aren't provided %s %s %s %s\n",app,exten,party,var->name);
02077             free(tmp_val);
02078             var = var->next;
02079             continue;
02080          }
02081 
02082          {
02083             struct ast_call_feature *feature=find_feature(var->name);
02084             int mallocd=0;
02085             
02086             if (!feature) {
02087                feature=malloc(sizeof(struct ast_call_feature));
02088                mallocd=1;
02089             }
02090             if (!feature) {
02091                ast_log(LOG_NOTICE, "Malloc failed at feature mapping\n");
02092                free(tmp_val);
02093                var = var->next;
02094                continue;
02095             }
02096 
02097             memset(feature,0,sizeof(struct ast_call_feature));
02098             ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN);
02099             ast_copy_string(feature->app,app,FEATURE_APP_LEN);
02100             ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN);
02101             free(tmp_val);
02102             
02103             if (app_args) 
02104                ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN);
02105             
02106             ast_copy_string(feature->exten, exten,sizeof(feature->exten));
02107             feature->operation=feature_exec_app;
02108             ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF);
02109             
02110             if (!strcasecmp(party,"caller"))
02111                ast_set_flag(feature,AST_FEATURE_FLAG_CALLER);
02112             else if (!strcasecmp(party, "callee"))
02113                ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE);
02114             else {
02115                ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name);
02116                var = var->next;
02117                continue;
02118             }
02119 
02120             ast_register_feature(feature);
02121             
02122             if (option_verbose >=1) ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten);  
02123          }
02124          var = var->next;
02125       }   
02126    }
02127    ast_config_destroy(cfg);
02128 
02129    /* Remove the old parking extension */
02130    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
02131       ast_context_remove_extension2(con, old_parking_ext, 1, registrar);
02132       ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
02133    }
02134    
02135    if (!(con = ast_context_find(parking_con))) {
02136       if (!(con = ast_context_create(NULL, parking_con, registrar))) {
02137          ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
02138          return -1;
02139       }
02140    }
02141    return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
02142 }
02143 
02144 int reload(void) {
02145    return load_config();
02146 }
02147 
02148 int load_module(void)
02149 {
02150    int res;
02151    
02152    memset(parking_ext, 0, sizeof(parking_ext));
02153    memset(parking_con, 0, sizeof(parking_con));
02154 
02155    if ((res = load_config()))
02156       return res;
02157    ast_cli_register(&showparked);
02158    ast_cli_register(&showfeatures);
02159    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
02160    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
02161    if (!res)
02162       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
02163    if (!res) {
02164       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
02165    }
02166    return res;
02167 }
02168 
02169 
02170 int unload_module(void)
02171 {
02172    STANDARD_HANGUP_LOCALUSERS;
02173 
02174    ast_manager_unregister("ParkedCalls");
02175    ast_cli_unregister(&showfeatures);
02176    ast_cli_unregister(&showparked);
02177    ast_unregister_application(parkcall);
02178    return ast_unregister_application(parkedcall);
02179 }
02180 
02181 char *description(void)
02182 {
02183    return "Call Features Resource";
02184 }
02185 
02186 int usecount(void)
02187 {
02188    /* Never allow parking to be unloaded because it will
02189       unresolve needed symbols in the dialer */
02190 #if 0
02191    int res;
02192    STANDARD_USECOUNT(res);
02193    return res;
02194 #else
02195    return 1;
02196 #endif
02197 }
02198 
02199 char *key()
02200 {
02201    return ASTERISK_GPL_KEY;
02202 }

Generated on Sat Mar 24 22:55:18 2007 for Asterisk - the Open Source PBX by  doxygen 1.4.7