Sat Nov 25 00:45:41 2006

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: 43924 $")
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 ast_bridge_config backup_config;
01278    char *monitor_exec;
01279 
01280    memset(&backup_config, 0, sizeof(backup_config));
01281 
01282    config->start_time = ast_tvnow();
01283 
01284    if (chan && peer) {
01285       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01286       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01287    } else if (chan)
01288       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01289 
01290    if (monitor_ok) {
01291       if (!monitor_app) { 
01292          if (!(monitor_app = pbx_findapp("Monitor")))
01293             monitor_ok=0;
01294       }
01295       if (monitor_app) {
01296          if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01297             pbx_exec(chan, monitor_app, monitor_exec, 1);
01298          else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01299             pbx_exec(peer, monitor_app, monitor_exec, 1);
01300       }
01301    }
01302    
01303    set_config_flags(chan, peer, config);
01304    config->firstpass = 1;
01305 
01306    /* Answer if need be */
01307    if (ast_answer(chan))
01308       return -1;
01309    peer->appl = "Bridged Call";
01310    peer->data = chan->name;
01311 
01312    /* copy the userfield from the B-leg to A-leg if applicable */
01313    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01314       char tmp[256];
01315       if (!ast_strlen_zero(chan->cdr->userfield)) {
01316          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01317          ast_cdr_appenduserfield(chan, tmp);
01318       } else
01319          ast_cdr_setuserfield(chan, peer->cdr->userfield);
01320       /* free the peer's cdr without ast_cdr_free complaining */
01321       free(peer->cdr);
01322       peer->cdr = NULL;
01323    }
01324    for (;;) {
01325       res = ast_channel_bridge(chan, peer, config, &f, &who);
01326 
01327       if (config->feature_timer) {
01328          /* Update time limit for next pass */
01329          diff = ast_tvdiff_ms(ast_tvnow(), config->start_time);
01330          config->feature_timer -= diff;
01331          if (hasfeatures) {
01332             /* Running on backup config, meaning a feature might be being
01333                activated, but that's no excuse to keep things going 
01334                indefinitely! */
01335             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01336                ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01337                config->feature_timer = 0;
01338                who = chan;
01339                if (f)
01340                   ast_frfree(f);
01341                f = NULL;
01342                res = 0;
01343             } else if (config->feature_timer <= 0) {
01344                /* Not *really* out of time, just out of time for
01345                   digits to come in for features. */
01346                ast_log(LOG_DEBUG, "Timed out for feature!\n");
01347                if (!ast_strlen_zero(peer_featurecode)) {
01348                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01349                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
01350                }
01351                if (!ast_strlen_zero(chan_featurecode)) {
01352                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01353                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
01354                }
01355                if (f)
01356                   ast_frfree(f);
01357                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01358                if (!hasfeatures) {
01359                   /* Restore original (possibly time modified) bridge config */
01360                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01361                   memset(&backup_config, 0, sizeof(backup_config));
01362                }
01363                hadfeatures = hasfeatures;
01364                /* Continue as we were */
01365                continue;
01366             } else if (!f) {
01367                /* The bridge returned without a frame and there is a feature in progress.
01368                 * However, we don't think the feature has quite yet timed out, so just
01369                 * go back into the bridge. */
01370                continue;
01371             }
01372          } else {
01373             if (config->feature_timer <=0) {
01374                /* We ran out of time */
01375                config->feature_timer = 0;
01376                who = chan;
01377                if (f)
01378                   ast_frfree(f);
01379                f = NULL;
01380                res = 0;
01381             }
01382          }
01383       }
01384       if (res < 0) {
01385          ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01386          return -1;
01387       }
01388       
01389       if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || 
01390          (f->subclass == AST_CONTROL_CONGESTION)))) {
01391             res = -1;
01392             break;
01393       }
01394       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
01395          if (who == chan)
01396             ast_indicate(peer, AST_CONTROL_RINGING);
01397          else
01398             ast_indicate(chan, AST_CONTROL_RINGING);
01399       }
01400       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
01401          if (who == chan)
01402             ast_indicate(peer, -1);
01403          else
01404             ast_indicate(chan, -1);
01405       }
01406       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) {
01407          if (who == chan)
01408             ast_indicate(peer, AST_CONTROL_FLASH);
01409          else
01410             ast_indicate(chan, AST_CONTROL_FLASH);
01411       }
01412       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
01413          aoh = f->data;
01414          /* Forward option Requests */
01415          if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
01416             if (who == chan)
01417                ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01418             else
01419                ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01420          }
01421       }
01422       /* check for '*', if we find it it's time to disconnect */
01423       if (f && (f->frametype == AST_FRAME_DTMF)) {
01424          char *featurecode;
01425          int sense;
01426          struct ast_channel *other;
01427 
01428          hadfeatures = hasfeatures;
01429          /* This cannot overrun because the longest feature is one shorter than our buffer */
01430          if (who == chan) {
01431             other = peer;
01432             sense = FEATURE_SENSE_CHAN;
01433             featurecode = chan_featurecode;
01434          } else  {
01435             other = chan;
01436             sense = FEATURE_SENSE_PEER;
01437             featurecode = peer_featurecode;
01438          }
01439          featurecode[strlen(featurecode)] = f->subclass;
01440          /* Get rid of the frame before we start doing "stuff" with the channels */
01441          ast_frfree(f);
01442          f = NULL;
01443          config->feature_timer = backup_config.feature_timer;
01444          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01445          switch(res) {
01446          case FEATURE_RETURN_PASSDIGITS:
01447             ast_dtmf_stream(other, who, featurecode, 0);
01448             /* Fall through */
01449          case FEATURE_RETURN_SUCCESS:
01450             memset(featurecode, 0, sizeof(chan_featurecode));
01451             break;
01452          }
01453          if (res >= FEATURE_RETURN_PASSDIGITS) {
01454             res = 0;
01455          } else 
01456             break;
01457          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01458          if (hadfeatures && !hasfeatures) {
01459             /* Restore backup */
01460             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01461             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01462          } else if (hasfeatures) {
01463             if (!hadfeatures) {
01464                /* Backup configuration */
01465                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01466                /* Setup temporary config options */
01467                config->play_warning = 0;
01468                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01469                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01470                config->warning_freq = 0;
01471                config->warning_sound = NULL;
01472                config->end_sound = NULL;
01473                config->start_sound = NULL;
01474                config->firstpass = 0;
01475             }
01476             config->start_time = ast_tvnow();
01477             config->feature_timer = featuredigittimeout;
01478             ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01479          }
01480       }
01481       if (f)
01482          ast_frfree(f);
01483    }
01484    return res;
01485 }
01486 
01487 static void *do_parking_thread(void *ignore)
01488 {
01489    int ms, tms, max;
01490    struct parkeduser *pu, *pl, *pt = NULL;
01491    struct timeval tv;
01492    struct ast_frame *f;
01493    char exten[AST_MAX_EXTENSION];
01494    char *peername,*cp;
01495    char returnexten[AST_MAX_EXTENSION];
01496    struct ast_context *con;
01497    int x;
01498    fd_set rfds, efds;
01499    fd_set nrfds, nefds;
01500    FD_ZERO(&rfds);
01501    FD_ZERO(&efds);
01502 
01503    for (;;) {
01504       ms = -1;
01505       max = -1;
01506       ast_mutex_lock(&parking_lock);
01507       pl = NULL;
01508       pu = parkinglot;
01509       FD_ZERO(&nrfds);
01510       FD_ZERO(&nefds);
01511       while(pu) {
01512          if (pu->notquiteyet) {
01513             /* Pretend this one isn't here yet */
01514             pl = pu;
01515             pu = pu->next;
01516             continue;
01517          }
01518          tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
01519          if (tms > pu->parkingtime) {
01520             /* Stop music on hold */
01521             ast_moh_stop(pu->chan);
01522             ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
01523             /* Get chan, exten from derived kludge */
01524             if (pu->peername[0]) {
01525                peername = ast_strdupa(pu->peername);
01526                cp = strrchr(peername, '-');
01527                if (cp) 
01528                   *cp = 0;
01529                con = ast_context_find(parking_con_dial);
01530                if (!con) {
01531                   con = ast_context_create(NULL, parking_con_dial, registrar);
01532                   if (!con) {
01533                      ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
01534                   }
01535                }
01536                if (con) {
01537                   snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
01538                   ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
01539                }
01540                ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten));
01541                ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context));
01542                pu->chan->priority = 1;
01543 
01544             } else {
01545                /* They've been waiting too long, send them back to where they came.  Theoretically they
01546                   should have their original extensions and such, but we copy to be on the safe side */
01547                ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten));
01548                ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context));
01549                pu->chan->priority = pu->priority;
01550             }
01551 
01552             manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
01553                "Exten: %d\r\n"
01554                "Channel: %s\r\n"
01555                "CallerID: %s\r\n"
01556                "CallerIDName: %s\r\n"
01557                ,pu->parkingnum, pu->chan->name
01558                ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01559                ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01560                );
01561 
01562             if (option_verbose > 1) 
01563                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);
01564             /* Start up the PBX, or hang them up */
01565             if (ast_pbx_start(pu->chan))  {
01566                ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
01567                ast_hangup(pu->chan);
01568             }
01569             /* And take them out of the parking lot */
01570             if (pl) 
01571                pl->next = pu->next;
01572             else
01573                parkinglot = pu->next;
01574             pt = pu;
01575             pu = pu->next;
01576             con = ast_context_find(parking_con);
01577             if (con) {
01578                snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
01579                if (ast_context_remove_extension2(con, exten, 1, NULL))
01580                   ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01581             } else
01582                ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01583             free(pt);
01584          } else {
01585             for (x = 0; x < AST_MAX_FDS; x++) {
01586                if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
01587                   if (FD_ISSET(pu->chan->fds[x], &efds))
01588                      ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
01589                   else
01590                      ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
01591                   pu->chan->fdno = x;
01592                   /* See if they need servicing */
01593                   f = ast_read(pu->chan);
01594                   if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
01595                      if (f)
01596                         ast_frfree(f);
01597                      manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
01598                         "Exten: %d\r\n"
01599                         "Channel: %s\r\n"
01600                         "CallerID: %s\r\n"
01601                         "CallerIDName: %s\r\n"
01602                         ,pu->parkingnum, pu->chan->name
01603                         ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01604                         ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01605                         );
01606 
01607                      /* There's a problem, hang them up*/
01608                      if (option_verbose > 1) 
01609                         ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
01610                      ast_hangup(pu->chan);
01611                      /* And take them out of the parking lot */
01612                      if (pl) 
01613                         pl->next = pu->next;
01614                      else
01615                         parkinglot = pu->next;
01616                      pt = pu;
01617                      pu = pu->next;
01618                      con = ast_context_find(parking_con);
01619                      if (con) {
01620                         snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
01621                         if (ast_context_remove_extension2(con, exten, 1, NULL))
01622                            ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01623                      } else
01624                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01625                      free(pt);
01626                      break;
01627                   } else {
01628                      /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
01629                      ast_frfree(f);
01630                      if (pu->moh_trys < 3 && !pu->chan->generatordata) {
01631                         ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
01632                         ast_moh_start(pu->chan, NULL);
01633                         pu->moh_trys++;
01634                      }
01635                      goto std;   /* XXX Ick: jumping into an else statement??? XXX */
01636                   }
01637                }
01638             }
01639             if (x >= AST_MAX_FDS) {
01640 std:              for (x=0; x<AST_MAX_FDS; x++) {
01641                   /* Keep this one for next one */
01642                   if (pu->chan->fds[x] > -1) {
01643                      FD_SET(pu->chan->fds[x], &nrfds);
01644                      FD_SET(pu->chan->fds[x], &nefds);
01645                      if (pu->chan->fds[x] > max)
01646                         max = pu->chan->fds[x];
01647                   }
01648                }
01649                /* Keep track of our longest wait */
01650                if ((tms < ms) || (ms < 0))
01651                   ms = tms;
01652                pl = pu;
01653                pu = pu->next;
01654             }
01655          }
01656       }
01657       ast_mutex_unlock(&parking_lock);
01658       rfds = nrfds;
01659       efds = nefds;
01660       tv = ast_samp2tv(ms, 1000);
01661       /* Wait for something to happen */
01662       ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
01663       pthread_testcancel();
01664    }
01665    return NULL;   /* Never reached */
01666 }
01667 
01668 static int park_call_exec(struct ast_channel *chan, void *data)
01669 {
01670    /* Data is unused at the moment but could contain a parking
01671       lot context eventually */
01672    int res=0;
01673    struct localuser *u;
01674    LOCAL_USER_ADD(u);
01675    /* Setup the exten/priority to be s/1 since we don't know
01676       where this call should return */
01677    strcpy(chan->exten, "s");
01678    chan->priority = 1;
01679    if (chan->_state != AST_STATE_UP)
01680       res = ast_answer(chan);
01681    if (!res)
01682       res = ast_safe_sleep(chan, 1000);
01683    if (!res)
01684       res = ast_park_call(chan, chan, 0, NULL);
01685    LOCAL_USER_REMOVE(u);
01686    if (!res)
01687       res = AST_PBX_KEEPALIVE;
01688    return res;
01689 }
01690 
01691 static int park_exec(struct ast_channel *chan, void *data)
01692 {
01693    int res=0;
01694    struct localuser *u;
01695    struct ast_channel *peer=NULL;
01696    struct parkeduser *pu, *pl=NULL;
01697    char exten[AST_MAX_EXTENSION];
01698    struct ast_context *con;
01699    int park;
01700    int dres;
01701    struct ast_bridge_config config;
01702 
01703    if (!data) {
01704       ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
01705       return -1;
01706    }
01707    LOCAL_USER_ADD(u);
01708    park = atoi((char *)data);
01709    ast_mutex_lock(&parking_lock);
01710    pu = parkinglot;
01711    while(pu) {
01712       if (pu->parkingnum == park) {
01713          if (pl)
01714             pl->next = pu->next;
01715          else
01716             parkinglot = pu->next;
01717          break;
01718       }
01719       pl = pu;
01720       pu = pu->next;
01721    }
01722    ast_mutex_unlock(&parking_lock);
01723    if (pu) {
01724       peer = pu->chan;
01725       con = ast_context_find(parking_con);
01726       if (con) {
01727          snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
01728          if (ast_context_remove_extension2(con, exten, 1, NULL))
01729             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01730       } else
01731          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01732 
01733       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
01734          "Exten: %d\r\n"
01735          "Channel: %s\r\n"
01736          "From: %s\r\n"
01737          "CallerID: %s\r\n"
01738          "CallerIDName: %s\r\n"
01739          ,pu->parkingnum, pu->chan->name, chan->name
01740          ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01741          ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01742          );
01743 
01744       free(pu);
01745    }
01746    /* JK02: it helps to answer the channel if not already up */
01747    if (chan->_state != AST_STATE_UP) {
01748       ast_answer(chan);
01749    }
01750 
01751    if (peer) {
01752       /* Play a courtesy beep in the calling channel to prefix the bridge connecting */   
01753       if (!ast_strlen_zero(courtesytone)) {
01754          if (!ast_streamfile(chan, courtesytone, chan->language)) {
01755             if (ast_waitstream(chan, "") < 0) {
01756                ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01757                ast_hangup(peer);
01758                return -1;
01759             }
01760          }
01761       }
01762  
01763       ast_moh_stop(peer);
01764       ast_indicate(peer, AST_CONTROL_UNHOLD);
01765       res = ast_channel_make_compatible(chan, peer);
01766       if (res < 0) {
01767          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
01768          ast_hangup(peer);
01769          return -1;
01770       }
01771       /* This runs sorta backwards, since we give the incoming channel control, as if it
01772          were the person called. */
01773       if (option_verbose > 2) 
01774          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
01775 
01776       memset(&config, 0, sizeof(struct ast_bridge_config));
01777       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
01778       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
01779       config.timelimit = 0;
01780       config.play_warning = 0;
01781       config.warning_freq = 0;
01782       config.warning_sound=NULL;
01783       res = ast_bridge_call(chan, peer, &config);
01784 
01785       /* Simulate the PBX hanging up */
01786       if (res != AST_PBX_NO_HANGUP_PEER)
01787          ast_hangup(peer);
01788       return res;
01789    } else {
01790       /* XXX Play a message XXX */
01791       dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
01792       if (!dres)
01793             dres = ast_waitstream(chan, "");
01794       else {
01795          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
01796          dres = 0;
01797       }
01798       if (option_verbose > 2) 
01799          ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
01800       res = -1;
01801    }
01802    LOCAL_USER_REMOVE(u);
01803    return res;
01804 }
01805 
01806 static int handle_showfeatures(int fd, int argc, char *argv[])
01807 {
01808    int i;
01809    int fcount;
01810    struct ast_call_feature *feature;
01811    char format[] = "%-25s %-7s %-7s\n";
01812 
01813    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
01814    ast_cli(fd, format, "---------------", "-------", "-------");
01815 
01816    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
01817 
01818    fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
01819 
01820    for (i = 0; i < fcount; i++)
01821    {
01822       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
01823    }
01824    ast_cli(fd, "\n");
01825    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
01826    ast_cli(fd, format, "---------------", "-------", "-------");
01827    if (AST_LIST_EMPTY(&feature_list)) {
01828       ast_cli(fd, "(none)\n");
01829    }
01830    else {
01831       AST_LIST_LOCK(&feature_list);
01832       AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
01833          ast_cli(fd, format, feature->sname, "no def", feature->exten); 
01834       }
01835       AST_LIST_UNLOCK(&feature_list);
01836    }
01837    ast_cli(fd, "\nCall parking\n");
01838    ast_cli(fd, "------------\n");
01839    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
01840    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
01841    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
01842    ast_cli(fd,"\n");
01843    
01844    return RESULT_SUCCESS;
01845 }
01846 
01847 static char showfeatures_help[] =
01848 "Usage: show features\n"
01849 "       Lists currently configured features.\n";
01850 
01851 static struct ast_cli_entry showfeatures =
01852 { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help };
01853 
01854 static int handle_parkedcalls(int fd, int argc, char *argv[])
01855 {
01856    struct parkeduser *cur;
01857    int numparked = 0;
01858 
01859    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
01860       , "Context", "Extension", "Pri", "Timeout");
01861 
01862    ast_mutex_lock(&parking_lock);
01863 
01864    cur = parkinglot;
01865    while(cur) {
01866       ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
01867          ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
01868          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
01869 
01870       cur = cur->next;
01871       numparked++;
01872    }
01873    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
01874 
01875    ast_mutex_unlock(&parking_lock);
01876 
01877    return RESULT_SUCCESS;
01878 }
01879 
01880 static char showparked_help[] =
01881 "Usage: show parkedcalls\n"
01882 "       Lists currently parked calls.\n";
01883 
01884 static struct ast_cli_entry showparked =
01885 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
01886 
01887 /* Dump lot status */
01888 static int manager_parking_status( struct mansession *s, struct message *m )
01889 {
01890    struct parkeduser *cur;
01891    char *id = astman_get_header(m,"ActionID");
01892    char idText[256] = "";
01893 
01894    if (!ast_strlen_zero(id))
01895       snprintf(idText,256,"ActionID: %s\r\n",id);
01896 
01897    astman_send_ack(s, m, "Parked calls will follow");
01898 
01899         ast_mutex_lock(&parking_lock);
01900 
01901         cur=parkinglot;
01902         while(cur) {
01903          ast_cli(s->fd, "Event: ParkedCall\r\n"
01904          "Exten: %d\r\n"
01905          "Channel: %s\r\n"
01906          "Timeout: %ld\r\n"
01907          "CallerID: %s\r\n"
01908          "CallerIDName: %s\r\n"
01909          "%s"
01910          "\r\n"
01911                         ,cur->parkingnum, cur->chan->name
01912                         ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
01913          ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
01914          ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
01915          ,idText);
01916 
01917             cur = cur->next;
01918         }
01919 
01920    ast_cli(s->fd,
01921    "Event: ParkedCallsComplete\r\n"
01922    "%s"
01923    "\r\n",idText);
01924 
01925         ast_mutex_unlock(&parking_lock);
01926 
01927         return RESULT_SUCCESS;
01928 }
01929 
01930 
01931 int ast_pickup_call(struct ast_channel *chan)
01932 {
01933    struct ast_channel *cur = NULL;
01934    int res = -1;
01935 
01936    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
01937       if (!cur->pbx && 
01938          (cur != chan) &&
01939          (chan->pickupgroup & cur->callgroup) &&
01940          ((cur->_state == AST_STATE_RINGING) ||
01941           (cur->_state == AST_STATE_RING))) {
01942             break;
01943       }
01944       ast_mutex_unlock(&cur->lock);
01945    }
01946    if (cur) {
01947       if (option_debug)
01948          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
01949       res = ast_answer(chan);
01950       if (res)
01951          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
01952       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
01953       if (res)
01954          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
01955       res = ast_channel_masquerade(cur, chan);
01956       if (res)
01957          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
01958       ast_mutex_unlock(&cur->lock);
01959    } else   {
01960       if (option_debug)
01961          ast_log(LOG_DEBUG, "No call pickup possible...\n");
01962    }
01963    return res;
01964 }
01965 
01966 static int load_config(void) 
01967 {
01968    int start = 0, end = 0;
01969    struct ast_context *con = NULL;
01970    struct ast_config *cfg = NULL;
01971    struct ast_variable *var = NULL;
01972    char old_parking_ext[AST_MAX_EXTENSION];
01973    char old_parking_con[AST_MAX_EXTENSION] = "";
01974 
01975    if (!ast_strlen_zero(parking_con)) {
01976       strcpy(old_parking_ext, parking_ext);
01977       strcpy(old_parking_con, parking_con);
01978    } 
01979 
01980    /* Reset to defaults */
01981    strcpy(parking_con, "parkedcalls");
01982    strcpy(parking_con_dial, "park-dial");
01983    strcpy(parking_ext, "700");
01984    strcpy(pickup_ext, "*8");
01985    courtesytone[0] = '\0';
01986    strcpy(xfersound, "beep");
01987    strcpy(xferfailsound, "pbx-invalid");
01988    parking_start = 701;
01989    parking_stop = 750;
01990    parkfindnext = 0;
01991    adsipark = 0;
01992 
01993    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
01994    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
01995 
01996    cfg = ast_config_load("features.conf");
01997    if (!cfg) {
01998       cfg = ast_config_load("parking.conf");
01999       if (cfg)
02000          ast_log(LOG_NOTICE, "parking.conf is deprecated in favor of 'features.conf'.  Please rename it.\n");
02001    }
02002    if (cfg) {
02003       var = ast_variable_browse(cfg, "general");
02004       while(var) {
02005          if (!strcasecmp(var->name, "parkext")) {
02006             ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
02007          } else if (!strcasecmp(var->name, "context")) {
02008             ast_copy_string(parking_con, var->value, sizeof(parking_con));
02009          } else if (!strcasecmp(var->name, "parkingtime")) {
02010             if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
02011                ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
02012                parkingtime = DEFAULT_PARK_TIME;
02013             } else
02014                parkingtime = parkingtime * 1000;
02015          } else if (!strcasecmp(var->name, "parkpos")) {
02016             if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
02017                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);
02018             } else {
02019                parking_start = start;
02020                parking_stop = end;
02021             }
02022          } else if (!strcasecmp(var->name, "findslot")) {
02023             parkfindnext = (!strcasecmp(var->value, "next"));
02024          } else if (!strcasecmp(var->name, "adsipark")) {
02025             adsipark = ast_true(var->value);
02026          } else if (!strcasecmp(var->name, "transferdigittimeout")) {
02027             if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
02028                ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
02029                transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02030             } else
02031                transferdigittimeout = transferdigittimeout * 1000;
02032          } else if (!strcasecmp(var->name, "featuredigittimeout")) {
02033             if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
02034                ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
02035                featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02036             }
02037          } else if (!strcasecmp(var->name, "courtesytone")) {
02038             ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
02039          } else if (!strcasecmp(var->name, "xfersound")) {
02040             ast_copy_string(xfersound, var->value, sizeof(xfersound));
02041          } else if (!strcasecmp(var->name, "xferfailsound")) {
02042             ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
02043          } else if (!strcasecmp(var->name, "pickupexten")) {
02044             ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
02045          }
02046          var = var->next;
02047       }
02048 
02049       unmap_features();
02050       var = ast_variable_browse(cfg, "featuremap");
02051       while(var) {
02052          if (remap_feature(var->name, var->value))
02053             ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
02054          var = var->next;
02055       }
02056 
02057       /* Map a key combination to an application*/
02058       ast_unregister_features();
02059       var = ast_variable_browse(cfg, "applicationmap");
02060       while(var) {
02061          char *tmp_val=strdup(var->value);
02062          char *exten, *party=NULL, *app=NULL, *app_args=NULL; 
02063 
02064          if (!tmp_val) { 
02065             ast_log(LOG_ERROR, "res_features: strdup failed\n");
02066             continue;
02067          }
02068          
02069 
02070          exten=strsep(&tmp_val,",");
02071          if (exten) party=strsep(&tmp_val,",");
02072          if (party) app=strsep(&tmp_val,",");
02073 
02074          if (app) app_args=strsep(&tmp_val,",");
02075 
02076          if (!(app && strlen(app)) || !(exten && strlen(exten)) || !(party && strlen(party)) || !(var->name && strlen(var->name))) {
02077             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);
02078             free(tmp_val);
02079             var = var->next;
02080             continue;
02081          }
02082 
02083          {
02084             struct ast_call_feature *feature=find_feature(var->name);
02085             int mallocd=0;
02086             
02087             if (!feature) {
02088                feature=malloc(sizeof(struct ast_call_feature));
02089                mallocd=1;
02090             }
02091             if (!feature) {
02092                ast_log(LOG_NOTICE, "Malloc failed at feature mapping\n");
02093                free(tmp_val);
02094                var = var->next;
02095                continue;
02096             }
02097 
02098             memset(feature,0,sizeof(struct ast_call_feature));
02099             ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN);
02100             ast_copy_string(feature->app,app,FEATURE_APP_LEN);
02101             ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN);
02102             free(tmp_val);
02103             
02104             if (app_args) 
02105                ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN);
02106             
02107             ast_copy_string(feature->exten, exten,sizeof(feature->exten));
02108             feature->operation=feature_exec_app;
02109             ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF);
02110             
02111             if (!strcasecmp(party,"caller"))
02112                ast_set_flag(feature,AST_FEATURE_FLAG_CALLER);
02113             else if (!strcasecmp(party, "callee"))
02114                ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE);
02115             else {
02116                ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name);
02117                var = var->next;
02118                continue;
02119             }
02120 
02121             ast_register_feature(feature);
02122             
02123             if (option_verbose >=1) ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten);  
02124          }
02125          var = var->next;
02126       }   
02127    }
02128    ast_config_destroy(cfg);
02129 
02130    /* Remove the old parking extension */
02131    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
02132       ast_context_remove_extension2(con, old_parking_ext, 1, registrar);
02133       ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
02134    }
02135    
02136    if (!(con = ast_context_find(parking_con))) {
02137       if (!(con = ast_context_create(NULL, parking_con, registrar))) {
02138          ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
02139          return -1;
02140       }
02141    }
02142    return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
02143 }
02144 
02145 int reload(void) {
02146    return load_config();
02147 }
02148 
02149 int load_module(void)
02150 {
02151    int res;
02152    
02153    memset(parking_ext, 0, sizeof(parking_ext));
02154    memset(parking_con, 0, sizeof(parking_con));
02155 
02156    if ((res = load_config()))
02157       return res;
02158    ast_cli_register(&showparked);
02159    ast_cli_register(&showfeatures);
02160    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
02161    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
02162    if (!res)
02163       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
02164    if (!res) {
02165       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
02166    }
02167    return res;
02168 }
02169 
02170 
02171 int unload_module(void)
02172 {
02173    STANDARD_HANGUP_LOCALUSERS;
02174 
02175    ast_manager_unregister("ParkedCalls");
02176    ast_cli_unregister(&showfeatures);
02177    ast_cli_unregister(&showparked);
02178    ast_unregister_application(parkcall);
02179    return ast_unregister_application(parkedcall);
02180 }
02181 
02182 char *description(void)
02183 {
02184    return "Call Features Resource";
02185 }
02186 
02187 int usecount(void)
02188 {
02189    /* Never allow parking to be unloaded because it will
02190       unresolve needed symbols in the dialer */
02191 #if 0
02192    int res;
02193    STANDARD_USECOUNT(res);
02194    return res;
02195 #else
02196    return 1;
02197 #endif
02198 }
02199 
02200 char *key()
02201 {
02202    return ASTERISK_GPL_KEY;
02203 }

Generated on Sat Nov 25 00:45:41 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.6