Fri May 26 01:45:36 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: 18866 $")
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, transferee->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 courtesy tone!\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 courtesy tone!\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       res = ast_streamfile(transferer, "beeperr", transferer->language);
00846       if (ast_waitstream(transferer, "") < 0) {
00847          return -1;
00848       }
00849    }
00850    ast_moh_stop(transferee);
00851    ast_autoservice_stop(transferee);
00852    ast_indicate(transferee, AST_CONTROL_UNHOLD);
00853 
00854    return FEATURE_RETURN_SUCCESS;
00855 }
00856 
00857 
00858 /* add atxfer and automon as undefined so you can only use em if you configure them */
00859 #define FEATURES_COUNT (sizeof(builtin_features) / sizeof(builtin_features[0]))
00860 struct ast_call_feature builtin_features[] = 
00861  {
00862    { AST_FEATURE_REDIRECT, "Blind Transfer", "blindxfer", "#", "#", builtin_blindtransfer, AST_FEATURE_FLAG_NEEDSDTMF },
00863    { AST_FEATURE_REDIRECT, "Attended Transfer", "atxfer", "", "", builtin_atxfer, AST_FEATURE_FLAG_NEEDSDTMF },
00864    { AST_FEATURE_AUTOMON, "One Touch Monitor", "automon", "", "", builtin_automonitor, AST_FEATURE_FLAG_NEEDSDTMF },
00865    { AST_FEATURE_DISCONNECT, "Disconnect Call", "disconnect", "*", "*", builtin_disconnect, AST_FEATURE_FLAG_NEEDSDTMF },
00866 };
00867 
00868 
00869 static AST_LIST_HEAD(feature_list,ast_call_feature) feature_list;
00870 
00871 /* register new feature into feature_list*/
00872 void ast_register_feature(struct ast_call_feature *feature)
00873 {
00874    if (!feature) {
00875       ast_log(LOG_NOTICE,"You didn't pass a feature!\n");
00876          return;
00877    }
00878   
00879    AST_LIST_LOCK(&feature_list);
00880    AST_LIST_INSERT_HEAD(&feature_list,feature,feature_entry);
00881    AST_LIST_UNLOCK(&feature_list);
00882 
00883    if (option_verbose >= 2) 
00884       ast_verbose(VERBOSE_PREFIX_2 "Registered Feature '%s'\n",feature->sname);
00885 }
00886 
00887 /* unregister feature from feature_list */
00888 void ast_unregister_feature(struct ast_call_feature *feature)
00889 {
00890    if (!feature) return;
00891 
00892    AST_LIST_LOCK(&feature_list);
00893    AST_LIST_REMOVE(&feature_list,feature,feature_entry);
00894    AST_LIST_UNLOCK(&feature_list);
00895    free(feature);
00896 }
00897 
00898 static void ast_unregister_features(void)
00899 {
00900    struct ast_call_feature *feature;
00901 
00902    AST_LIST_LOCK(&feature_list);
00903    while ((feature = AST_LIST_REMOVE_HEAD(&feature_list,feature_entry)))
00904       free(feature);
00905    AST_LIST_UNLOCK(&feature_list);
00906 }
00907 
00908 /* find a feature by name */
00909 static struct ast_call_feature *find_feature(char *name)
00910 {
00911    struct ast_call_feature *tmp;
00912 
00913    AST_LIST_LOCK(&feature_list);
00914    AST_LIST_TRAVERSE(&feature_list, tmp, feature_entry) {
00915       if (!strcasecmp(tmp->sname, name))
00916          break;
00917    }
00918    AST_LIST_UNLOCK(&feature_list);
00919 
00920    return tmp;
00921 }
00922 
00923 /* exec an app by feature */
00924 static int feature_exec_app(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
00925 {
00926    struct ast_app *app;
00927    struct ast_call_feature *feature;
00928    int res;
00929 
00930    AST_LIST_LOCK(&feature_list);
00931    AST_LIST_TRAVERSE(&feature_list,feature,feature_entry) {
00932       if (!strcasecmp(feature->exten,code)) break;
00933    }
00934    AST_LIST_UNLOCK(&feature_list);
00935 
00936    if (!feature) { /* shouldn't ever happen! */
00937       ast_log(LOG_NOTICE, "Found feature before, but at execing we've lost it??\n");
00938       return -1; 
00939    }
00940    
00941    app = pbx_findapp(feature->app);
00942    if (app) {
00943       struct ast_channel *work = chan;
00944       if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
00945          work = peer;
00946       res = pbx_exec(work, app, feature->app_args, 1);
00947       if (res < 0)
00948          return res; 
00949    } else {
00950       ast_log(LOG_WARNING, "Could not find application (%s)\n", feature->app);
00951       return -2;
00952    }
00953    
00954    return FEATURE_RETURN_SUCCESS;
00955 }
00956 
00957 static void unmap_features(void)
00958 {
00959    int x;
00960    for (x = 0; x < FEATURES_COUNT; x++)
00961       strcpy(builtin_features[x].exten, builtin_features[x].default_exten);
00962 }
00963 
00964 static int remap_feature(const char *name, const char *value)
00965 {
00966    int x;
00967    int res = -1;
00968    for (x = 0; x < FEATURES_COUNT; x++) {
00969       if (!strcasecmp(name, builtin_features[x].sname)) {
00970          ast_copy_string(builtin_features[x].exten, value, sizeof(builtin_features[x].exten));
00971          if (option_verbose > 1)
00972             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);
00973          res = 0;
00974       } else if (!strcmp(value, builtin_features[x].exten)) 
00975          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);
00976    }
00977    return res;
00978 }
00979 
00980 static int ast_feature_interpret(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config, char *code, int sense)
00981 {
00982    int x;
00983    struct ast_flags features;
00984    int res = FEATURE_RETURN_PASSDIGITS;
00985    struct ast_call_feature *feature;
00986    char *dynamic_features=pbx_builtin_getvar_helper(chan,"DYNAMIC_FEATURES");
00987 
00988    if (sense == FEATURE_SENSE_CHAN)
00989       ast_copy_flags(&features, &(config->features_caller), AST_FLAGS_ALL);   
00990    else
00991       ast_copy_flags(&features, &(config->features_callee), AST_FLAGS_ALL);   
00992    ast_log(LOG_DEBUG, "Feature interpret: chan=%s, peer=%s, sense=%d, features=%d\n", chan->name, peer->name, sense, features.flags);
00993 
00994    for (x=0; x < FEATURES_COUNT; x++) {
00995       if ((ast_test_flag(&features, builtin_features[x].feature_mask)) &&
00996           !ast_strlen_zero(builtin_features[x].exten)) {
00997          /* Feature is up for consideration */
00998          if (!strcmp(builtin_features[x].exten, code)) {
00999             res = builtin_features[x].operation(chan, peer, config, code, sense);
01000             break;
01001          } else if (!strncmp(builtin_features[x].exten, code, strlen(code))) {
01002             if (res == FEATURE_RETURN_PASSDIGITS)
01003                res = FEATURE_RETURN_STOREDIGITS;
01004          }
01005       }
01006    }
01007 
01008 
01009    if (!ast_strlen_zero(dynamic_features)) {
01010       char *tmp = ast_strdupa(dynamic_features);
01011       char *tok;
01012 
01013       if (!tmp)
01014          return res;
01015       
01016       while ((tok = strsep(&tmp, "#")) != NULL) {
01017          feature = find_feature(tok);
01018          
01019          if (feature) {
01020             /* Feature is up for consideration */
01021             if (!strcmp(feature->exten, code)) {
01022                if (option_verbose > 2)
01023                   ast_verbose(VERBOSE_PREFIX_3 " Feature Found: %s exten: %s\n",feature->sname, tok);
01024                res = feature->operation(chan, peer, config, code, sense);
01025                break;
01026             } else if (!strncmp(feature->exten, code, strlen(code))) {
01027                res = FEATURE_RETURN_STOREDIGITS;
01028             }
01029          }
01030       }
01031    }
01032    
01033    return res;
01034 }
01035 
01036 static void set_config_flags(struct ast_channel *chan, struct ast_channel *peer, struct ast_bridge_config *config)
01037 {
01038    int x;
01039    
01040    ast_clear_flag(config, AST_FLAGS_ALL); 
01041    for (x = 0; x < FEATURES_COUNT; x++) {
01042       if (ast_test_flag(builtin_features + x, AST_FEATURE_FLAG_NEEDSDTMF)) {
01043          if (ast_test_flag(&(config->features_caller), builtin_features[x].feature_mask))
01044             ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01045 
01046          if (ast_test_flag(&(config->features_callee), builtin_features[x].feature_mask))
01047             ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01048       }
01049    }
01050    
01051    if (chan && peer && !(ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_0) && ast_test_flag(config, AST_BRIDGE_DTMF_CHANNEL_1))) {
01052       char *dynamic_features;
01053 
01054       dynamic_features = pbx_builtin_getvar_helper(chan, "DYNAMIC_FEATURES");
01055 
01056       if (dynamic_features) {
01057          char *tmp = ast_strdupa(dynamic_features);
01058          char *tok;
01059          struct ast_call_feature *feature;
01060 
01061          if (!tmp) {
01062             return;
01063          }
01064 
01065          /* while we have a feature */
01066          while (NULL != (tok = strsep(&tmp, "#"))) {
01067             if ((feature = find_feature(tok))) {
01068                if (ast_test_flag(feature, AST_FEATURE_FLAG_NEEDSDTMF)) {
01069                   if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLER))
01070                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_0);
01071                   if (ast_test_flag(feature, AST_FEATURE_FLAG_CALLEE))
01072                      ast_set_flag(config, AST_BRIDGE_DTMF_CHANNEL_1);
01073                }
01074             }
01075          }
01076       }
01077    }
01078 }
01079 
01080 
01081 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)
01082 {
01083    int state = 0;
01084    int cause = 0;
01085    int to;
01086    struct ast_channel *chan;
01087    struct ast_channel *monitor_chans[2];
01088    struct ast_channel *active_channel;
01089    struct ast_frame *f = NULL;
01090    int res = 0, ready = 0;
01091    
01092    if ((chan = ast_request(type, format, data, &cause))) {
01093       ast_set_callerid(chan, cid_num, cid_name, cid_num);
01094       ast_channel_inherit_variables(caller, chan); 
01095       if (!ast_call(chan, data, timeout)) {
01096          struct timeval started;
01097          int x, len = 0;
01098          char *disconnect_code = NULL, *dialed_code = NULL;
01099 
01100          ast_indicate(caller, AST_CONTROL_RINGING);
01101          /* support dialing of the featuremap disconnect code while performing an attended tranfer */
01102          for (x=0; x < FEATURES_COUNT; x++) {
01103             if (strcasecmp(builtin_features[x].sname, "disconnect"))
01104                continue;
01105 
01106             disconnect_code = builtin_features[x].exten;
01107             len = strlen(disconnect_code) + 1;
01108             dialed_code = alloca(len);
01109             memset(dialed_code, 0, len);
01110             break;
01111          }
01112          x = 0;
01113          started = ast_tvnow();
01114          to = timeout;
01115          while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
01116             monitor_chans[0] = caller;
01117             monitor_chans[1] = chan;
01118             active_channel = ast_waitfor_n(monitor_chans, 2, &to);
01119 
01120             /* see if the timeout has been violated */
01121             if(ast_tvdiff_ms(ast_tvnow(), started) > timeout) {
01122                state = AST_CONTROL_UNHOLD;
01123                ast_log(LOG_NOTICE, "We exceeded our AT-timeout\n");
01124                break; /*doh! timeout*/
01125             }
01126 
01127             if (!active_channel) {
01128                continue;
01129             }
01130 
01131             if (chan && (chan == active_channel)){
01132                f = ast_read(chan);
01133                if (f == NULL) { /*doh! where'd he go?*/
01134                   state = AST_CONTROL_HANGUP;
01135                   res = 0;
01136                   break;
01137                }
01138                
01139                if (f->frametype == AST_FRAME_CONTROL || f->frametype == AST_FRAME_DTMF || f->frametype == AST_FRAME_TEXT) {
01140                   if (f->subclass == AST_CONTROL_RINGING) {
01141                      state = f->subclass;
01142                      if (option_verbose > 2)
01143                         ast_verbose( VERBOSE_PREFIX_3 "%s is ringing\n", chan->name);
01144                      ast_indicate(caller, AST_CONTROL_RINGING);
01145                   } else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01146                      state = f->subclass;
01147                      if (option_verbose > 2)
01148                         ast_verbose( VERBOSE_PREFIX_3 "%s is busy\n", chan->name);
01149                      ast_indicate(caller, AST_CONTROL_BUSY);
01150                      ast_frfree(f);
01151                      f = NULL;
01152                      break;
01153                   } else if (f->subclass == AST_CONTROL_ANSWER) {
01154                      /* This is what we are hoping for */
01155                      state = f->subclass;
01156                      ast_frfree(f);
01157                      f = NULL;
01158                      ready=1;
01159                      break;
01160                   } else {
01161                      ast_log(LOG_NOTICE, "Don't know what to do about control frame: %d\n", f->subclass);
01162                   }
01163                   /* else who cares */
01164                }
01165 
01166             } else if (caller && (active_channel == caller)) {
01167                f = ast_read(caller);
01168                if (f == NULL) { /*doh! where'd he go?*/
01169                   if (caller->_softhangup && !chan->_softhangup) {
01170                      /* make this a blind transfer */
01171                      ready = 1;
01172                      break;
01173                   }
01174                   state = AST_CONTROL_HANGUP;
01175                   res = 0;
01176                   break;
01177                }
01178                
01179                if (f->frametype == AST_FRAME_DTMF) {
01180                   dialed_code[x++] = f->subclass;
01181                   dialed_code[x] = '\0';
01182                   if (strlen(dialed_code) == len) {
01183                      x = 0;
01184                   } else if (x && strncmp(dialed_code, disconnect_code, x)) {
01185                      x = 0;
01186                      dialed_code[x] = '\0';
01187                   }
01188                   if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
01189                      /* Caller Canceled the call */
01190                      state = AST_CONTROL_UNHOLD;
01191                      ast_frfree(f);
01192                      f = NULL;
01193                      break;
01194                   }
01195                }
01196             }
01197             if (f) {
01198                ast_frfree(f);
01199             }
01200          }
01201       } else
01202          ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
01203    } else {
01204       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01205       switch(cause) {
01206       case AST_CAUSE_BUSY:
01207          state = AST_CONTROL_BUSY;
01208          break;
01209       case AST_CAUSE_CONGESTION:
01210          state = AST_CONTROL_CONGESTION;
01211          break;
01212       }
01213    }
01214    
01215    ast_indicate(caller, -1);
01216    if (chan && ready) {
01217       if (chan->_state == AST_STATE_UP) 
01218          state = AST_CONTROL_ANSWER;
01219       res = 0;
01220    } else if(chan) {
01221       res = -1;
01222       ast_hangup(chan);
01223       chan = NULL;
01224    } else {
01225       res = -1;
01226    }
01227    
01228    if (outstate)
01229       *outstate = state;
01230 
01231    if (chan && res <= 0) {
01232       if (!chan->cdr) {
01233          chan->cdr = ast_cdr_alloc();
01234       }
01235       if (chan->cdr) {
01236          char tmp[256];
01237          ast_cdr_init(chan->cdr, chan);
01238          snprintf(tmp, 256, "%s/%s", type, (char *)data);
01239          ast_cdr_setapp(chan->cdr,"Dial",tmp);
01240          ast_cdr_update(chan);
01241          ast_cdr_start(chan->cdr);
01242          ast_cdr_end(chan->cdr);
01243          /* If the cause wasn't handled properly */
01244          if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
01245             ast_cdr_failed(chan->cdr);
01246       } else {
01247          ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
01248       }
01249    }
01250    
01251    return chan;
01252 }
01253 
01254 int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
01255 {
01256    /* Copy voice back and forth between the two channels.  Give the peer
01257       the ability to transfer calls with '#<extension' syntax. */
01258    struct ast_frame *f;
01259    struct ast_channel *who;
01260    char chan_featurecode[FEATURE_MAX_LEN + 1]="";
01261    char peer_featurecode[FEATURE_MAX_LEN + 1]="";
01262    int res;
01263    int diff;
01264    int hasfeatures=0;
01265    int hadfeatures=0;
01266    struct ast_option_header *aoh;
01267    struct timeval start = { 0 , 0 };
01268    struct ast_bridge_config backup_config;
01269    char *monitor_exec;
01270 
01271    memset(&backup_config, 0, sizeof(backup_config));
01272 
01273    config->start_time = ast_tvnow();
01274 
01275    if (chan && peer) {
01276       pbx_builtin_setvar_helper(chan, "BRIDGEPEER", peer->name);
01277       pbx_builtin_setvar_helper(peer, "BRIDGEPEER", chan->name);
01278    } else if (chan)
01279       pbx_builtin_setvar_helper(chan, "BLINDTRANSFER", NULL);
01280 
01281    if (monitor_ok) {
01282       if (!monitor_app) { 
01283          if (!(monitor_app = pbx_findapp("Monitor")))
01284             monitor_ok=0;
01285       }
01286       if (monitor_app) {
01287          if ((monitor_exec = pbx_builtin_getvar_helper(chan, "AUTO_MONITOR"))) 
01288             pbx_exec(chan, monitor_app, monitor_exec, 1);
01289          else if ((monitor_exec = pbx_builtin_getvar_helper(peer, "AUTO_MONITOR")))
01290             pbx_exec(peer, monitor_app, monitor_exec, 1);
01291       }
01292    }
01293    
01294    set_config_flags(chan, peer, config);
01295    config->firstpass = 1;
01296 
01297    /* Answer if need be */
01298    if (ast_answer(chan))
01299       return -1;
01300    peer->appl = "Bridged Call";
01301    peer->data = chan->name;
01302 
01303    /* copy the userfield from the B-leg to A-leg if applicable */
01304    if (chan->cdr && peer->cdr && !ast_strlen_zero(peer->cdr->userfield)) {
01305       char tmp[256];
01306       if (!ast_strlen_zero(chan->cdr->userfield)) {
01307          snprintf(tmp, sizeof(tmp), "%s;%s", chan->cdr->userfield, peer->cdr->userfield);
01308          ast_cdr_appenduserfield(chan, tmp);
01309       } else
01310          ast_cdr_setuserfield(chan, peer->cdr->userfield);
01311       /* free the peer's cdr without ast_cdr_free complaining */
01312       free(peer->cdr);
01313       peer->cdr = NULL;
01314    }
01315    for (;;) {
01316       if (config->feature_timer)
01317          start = ast_tvnow();
01318 
01319       res = ast_channel_bridge(chan, peer, config, &f, &who);
01320 
01321       if (config->feature_timer) {
01322          /* Update time limit for next pass */
01323          diff = ast_tvdiff_ms(ast_tvnow(), start);
01324          config->feature_timer -= diff;
01325          if (hasfeatures) {
01326             /* Running on backup config, meaning a feature might be being
01327                activated, but that's no excuse to keep things going 
01328                indefinitely! */
01329             if (backup_config.feature_timer && ((backup_config.feature_timer -= diff) <= 0)) {
01330                ast_log(LOG_DEBUG, "Timed out, realtime this time!\n");
01331                config->feature_timer = 0;
01332                who = chan;
01333                if (f)
01334                   ast_frfree(f);
01335                f = NULL;
01336                res = 0;
01337             } else if (config->feature_timer <= 0) {
01338                /* Not *really* out of time, just out of time for
01339                   digits to come in for features. */
01340                ast_log(LOG_DEBUG, "Timed out for feature!\n");
01341                if (!ast_strlen_zero(peer_featurecode)) {
01342                   ast_dtmf_stream(chan, peer, peer_featurecode, 0);
01343                   memset(peer_featurecode, 0, sizeof(peer_featurecode));
01344                }
01345                if (!ast_strlen_zero(chan_featurecode)) {
01346                   ast_dtmf_stream(peer, chan, chan_featurecode, 0);
01347                   memset(chan_featurecode, 0, sizeof(chan_featurecode));
01348                }
01349                if (f)
01350                   ast_frfree(f);
01351                hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01352                if (!hasfeatures) {
01353                   /* Restore original (possibly time modified) bridge config */
01354                   memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01355                   memset(&backup_config, 0, sizeof(backup_config));
01356                }
01357                hadfeatures = hasfeatures;
01358                /* Continue as we were */
01359                continue;
01360             }
01361          } else {
01362             if (config->feature_timer <=0) {
01363                /* We ran out of time */
01364                config->feature_timer = 0;
01365                who = chan;
01366                if (f)
01367                   ast_frfree(f);
01368                f = NULL;
01369                res = 0;
01370             }
01371          }
01372       }
01373       if (res < 0) {
01374          ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
01375          return -1;
01376       }
01377       
01378       if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) || 
01379          (f->subclass == AST_CONTROL_CONGESTION)))) {
01380             res = -1;
01381             break;
01382       }
01383       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
01384          if (who == chan)
01385             ast_indicate(peer, AST_CONTROL_RINGING);
01386          else
01387             ast_indicate(chan, AST_CONTROL_RINGING);
01388       }
01389       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == -1)) {
01390          if (who == chan)
01391             ast_indicate(peer, -1);
01392          else
01393             ast_indicate(chan, -1);
01394       }
01395       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_FLASH)) {
01396          if (who == chan)
01397             ast_indicate(peer, AST_CONTROL_FLASH);
01398          else
01399             ast_indicate(chan, AST_CONTROL_FLASH);
01400       }
01401       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
01402          aoh = f->data;
01403          /* Forward option Requests */
01404          if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
01405             if (who == chan)
01406                ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01407             else
01408                ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
01409          }
01410       }
01411       /* check for '*', if we find it it's time to disconnect */
01412       if (f && (f->frametype == AST_FRAME_DTMF)) {
01413          char *featurecode;
01414          int sense;
01415          struct ast_channel *other;
01416 
01417          hadfeatures = hasfeatures;
01418          /* This cannot overrun because the longest feature is one shorter than our buffer */
01419          if (who == chan) {
01420             other = peer;
01421             sense = FEATURE_SENSE_CHAN;
01422             featurecode = chan_featurecode;
01423          } else  {
01424             other = chan;
01425             sense = FEATURE_SENSE_PEER;
01426             featurecode = peer_featurecode;
01427          }
01428          featurecode[strlen(featurecode)] = f->subclass;
01429          config->feature_timer = backup_config.feature_timer;
01430          res = ast_feature_interpret(chan, peer, config, featurecode, sense);
01431          switch(res) {
01432          case FEATURE_RETURN_PASSDIGITS:
01433             ast_dtmf_stream(other, who, featurecode, 0);
01434             /* Fall through */
01435          case FEATURE_RETURN_SUCCESS:
01436             memset(featurecode, 0, sizeof(chan_featurecode));
01437             break;
01438          }
01439          if (res >= FEATURE_RETURN_PASSDIGITS) {
01440             res = 0;
01441          } else {
01442             ast_frfree(f);
01443             break;
01444          }
01445          hasfeatures = !ast_strlen_zero(chan_featurecode) || !ast_strlen_zero(peer_featurecode);
01446          if (hadfeatures && !hasfeatures) {
01447             /* Restore backup */
01448             memcpy(config, &backup_config, sizeof(struct ast_bridge_config));
01449             memset(&backup_config, 0, sizeof(struct ast_bridge_config));
01450          } else if (hasfeatures) {
01451             if (!hadfeatures) {
01452                /* Backup configuration */
01453                memcpy(&backup_config, config, sizeof(struct ast_bridge_config));
01454                /* Setup temporary config options */
01455                config->play_warning = 0;
01456                ast_clear_flag(&(config->features_caller), AST_FEATURE_PLAY_WARNING);
01457                ast_clear_flag(&(config->features_callee), AST_FEATURE_PLAY_WARNING);
01458                config->warning_freq = 0;
01459                config->warning_sound = NULL;
01460                config->end_sound = NULL;
01461                config->start_sound = NULL;
01462                config->firstpass = 0;
01463             }
01464             config->feature_timer = featuredigittimeout;
01465             ast_log(LOG_DEBUG, "Set time limit to %ld\n", config->feature_timer);
01466          }
01467       }
01468       if (f)
01469          ast_frfree(f);
01470    }
01471    return res;
01472 }
01473 
01474 static void *do_parking_thread(void *ignore)
01475 {
01476    int ms, tms, max;
01477    struct parkeduser *pu, *pl, *pt = NULL;
01478    struct timeval tv;
01479    struct ast_frame *f;
01480    char exten[AST_MAX_EXTENSION];
01481    char *peername,*cp;
01482    char returnexten[AST_MAX_EXTENSION];
01483    struct ast_context *con;
01484    int x;
01485    fd_set rfds, efds;
01486    fd_set nrfds, nefds;
01487    FD_ZERO(&rfds);
01488    FD_ZERO(&efds);
01489 
01490    for (;;) {
01491       ms = -1;
01492       max = -1;
01493       ast_mutex_lock(&parking_lock);
01494       pl = NULL;
01495       pu = parkinglot;
01496       FD_ZERO(&nrfds);
01497       FD_ZERO(&nefds);
01498       while(pu) {
01499          if (pu->notquiteyet) {
01500             /* Pretend this one isn't here yet */
01501             pl = pu;
01502             pu = pu->next;
01503             continue;
01504          }
01505          tms = ast_tvdiff_ms(ast_tvnow(), pu->start);
01506          if (tms > pu->parkingtime) {
01507             /* Stop music on hold */
01508             ast_moh_stop(pu->chan);
01509             ast_indicate(pu->chan, AST_CONTROL_UNHOLD);
01510             /* Get chan, exten from derived kludge */
01511             if (pu->peername[0]) {
01512                peername = ast_strdupa(pu->peername);
01513                cp = strrchr(peername, '-');
01514                if (cp) 
01515                   *cp = 0;
01516                con = ast_context_find(parking_con_dial);
01517                if (!con) {
01518                   con = ast_context_create(NULL, parking_con_dial, registrar);
01519                   if (!con) {
01520                      ast_log(LOG_ERROR, "Parking dial context '%s' does not exist and unable to create\n", parking_con_dial);
01521                   }
01522                }
01523                if (con) {
01524                   snprintf(returnexten, sizeof(returnexten), "%s||t", peername);
01525                   ast_add_extension2(con, 1, peername, 1, NULL, NULL, "Dial", strdup(returnexten), FREE, registrar);
01526                }
01527                ast_copy_string(pu->chan->exten, peername, sizeof(pu->chan->exten));
01528                ast_copy_string(pu->chan->context, parking_con_dial, sizeof(pu->chan->context));
01529                pu->chan->priority = 1;
01530 
01531             } else {
01532                /* They've been waiting too long, send them back to where they came.  Theoretically they
01533                   should have their original extensions and such, but we copy to be on the safe side */
01534                ast_copy_string(pu->chan->exten, pu->exten, sizeof(pu->chan->exten));
01535                ast_copy_string(pu->chan->context, pu->context, sizeof(pu->chan->context));
01536                pu->chan->priority = pu->priority;
01537             }
01538 
01539             manager_event(EVENT_FLAG_CALL, "ParkedCallTimeOut",
01540                "Exten: %d\r\n"
01541                "Channel: %s\r\n"
01542                "CallerID: %s\r\n"
01543                "CallerIDName: %s\r\n"
01544                ,pu->parkingnum, pu->chan->name
01545                ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01546                ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01547                );
01548 
01549             if (option_verbose > 1) 
01550                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);
01551             /* Start up the PBX, or hang them up */
01552             if (ast_pbx_start(pu->chan))  {
01553                ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
01554                ast_hangup(pu->chan);
01555             }
01556             /* And take them out of the parking lot */
01557             if (pl) 
01558                pl->next = pu->next;
01559             else
01560                parkinglot = pu->next;
01561             pt = pu;
01562             pu = pu->next;
01563             con = ast_context_find(parking_con);
01564             if (con) {
01565                snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
01566                if (ast_context_remove_extension2(con, exten, 1, NULL))
01567                   ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01568             } else
01569                ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01570             free(pt);
01571          } else {
01572             for (x = 0; x < AST_MAX_FDS; x++) {
01573                if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
01574                   if (FD_ISSET(pu->chan->fds[x], &efds))
01575                      ast_set_flag(pu->chan, AST_FLAG_EXCEPTION);
01576                   else
01577                      ast_clear_flag(pu->chan, AST_FLAG_EXCEPTION);
01578                   pu->chan->fdno = x;
01579                   /* See if they need servicing */
01580                   f = ast_read(pu->chan);
01581                   if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass ==  AST_CONTROL_HANGUP))) {
01582                      if (f)
01583                         ast_frfree(f);
01584                      manager_event(EVENT_FLAG_CALL, "ParkedCallGiveUp",
01585                         "Exten: %d\r\n"
01586                         "Channel: %s\r\n"
01587                         "CallerID: %s\r\n"
01588                         "CallerIDName: %s\r\n"
01589                         ,pu->parkingnum, pu->chan->name
01590                         ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01591                         ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01592                         );
01593 
01594                      /* There's a problem, hang them up*/
01595                      if (option_verbose > 1) 
01596                         ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
01597                      ast_hangup(pu->chan);
01598                      /* And take them out of the parking lot */
01599                      if (pl) 
01600                         pl->next = pu->next;
01601                      else
01602                         parkinglot = pu->next;
01603                      pt = pu;
01604                      pu = pu->next;
01605                      con = ast_context_find(parking_con);
01606                      if (con) {
01607                         snprintf(exten, sizeof(exten), "%d", pt->parkingnum);
01608                         if (ast_context_remove_extension2(con, exten, 1, NULL))
01609                            ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01610                      } else
01611                         ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01612                      free(pt);
01613                      break;
01614                   } else {
01615                      /* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
01616                      ast_frfree(f);
01617                      if (pu->moh_trys < 3 && !pu->chan->generatordata) {
01618                         ast_log(LOG_DEBUG, "MOH on parked call stopped by outside source.  Restarting.\n");
01619                         ast_moh_start(pu->chan, NULL);
01620                         pu->moh_trys++;
01621                      }
01622                      goto std;   /* XXX Ick: jumping into an else statement??? XXX */
01623                   }
01624                }
01625             }
01626             if (x >= AST_MAX_FDS) {
01627 std:              for (x=0; x<AST_MAX_FDS; x++) {
01628                   /* Keep this one for next one */
01629                   if (pu->chan->fds[x] > -1) {
01630                      FD_SET(pu->chan->fds[x], &nrfds);
01631                      FD_SET(pu->chan->fds[x], &nefds);
01632                      if (pu->chan->fds[x] > max)
01633                         max = pu->chan->fds[x];
01634                   }
01635                }
01636                /* Keep track of our longest wait */
01637                if ((tms < ms) || (ms < 0))
01638                   ms = tms;
01639                pl = pu;
01640                pu = pu->next;
01641             }
01642          }
01643       }
01644       ast_mutex_unlock(&parking_lock);
01645       rfds = nrfds;
01646       efds = nefds;
01647       tv = ast_samp2tv(ms, 1000);
01648       /* Wait for something to happen */
01649       ast_select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
01650       pthread_testcancel();
01651    }
01652    return NULL;   /* Never reached */
01653 }
01654 
01655 static int park_call_exec(struct ast_channel *chan, void *data)
01656 {
01657    /* Data is unused at the moment but could contain a parking
01658       lot context eventually */
01659    int res=0;
01660    struct localuser *u;
01661    LOCAL_USER_ADD(u);
01662    /* Setup the exten/priority to be s/1 since we don't know
01663       where this call should return */
01664    strcpy(chan->exten, "s");
01665    chan->priority = 1;
01666    if (chan->_state != AST_STATE_UP)
01667       res = ast_answer(chan);
01668    if (!res)
01669       res = ast_safe_sleep(chan, 1000);
01670    if (!res)
01671       res = ast_park_call(chan, chan, 0, NULL);
01672    LOCAL_USER_REMOVE(u);
01673    if (!res)
01674       res = AST_PBX_KEEPALIVE;
01675    return res;
01676 }
01677 
01678 static int park_exec(struct ast_channel *chan, void *data)
01679 {
01680    int res=0;
01681    struct localuser *u;
01682    struct ast_channel *peer=NULL;
01683    struct parkeduser *pu, *pl=NULL;
01684    char exten[AST_MAX_EXTENSION];
01685    struct ast_context *con;
01686    int park;
01687    int dres;
01688    struct ast_bridge_config config;
01689 
01690    if (!data) {
01691       ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
01692       return -1;
01693    }
01694    LOCAL_USER_ADD(u);
01695    park = atoi((char *)data);
01696    ast_mutex_lock(&parking_lock);
01697    pu = parkinglot;
01698    while(pu) {
01699       if (pu->parkingnum == park) {
01700          if (pl)
01701             pl->next = pu->next;
01702          else
01703             parkinglot = pu->next;
01704          break;
01705       }
01706       pl = pu;
01707       pu = pu->next;
01708    }
01709    ast_mutex_unlock(&parking_lock);
01710    if (pu) {
01711       peer = pu->chan;
01712       con = ast_context_find(parking_con);
01713       if (con) {
01714          snprintf(exten, sizeof(exten), "%d", pu->parkingnum);
01715          if (ast_context_remove_extension2(con, exten, 1, NULL))
01716             ast_log(LOG_WARNING, "Whoa, failed to remove the extension!\n");
01717       } else
01718          ast_log(LOG_WARNING, "Whoa, no parking context?\n");
01719 
01720       manager_event(EVENT_FLAG_CALL, "UnParkedCall",
01721          "Exten: %d\r\n"
01722          "Channel: %s\r\n"
01723          "From: %s\r\n"
01724          "CallerID: %s\r\n"
01725          "CallerIDName: %s\r\n"
01726          ,pu->parkingnum, pu->chan->name, chan->name
01727          ,(pu->chan->cid.cid_num ? pu->chan->cid.cid_num : "<unknown>")
01728          ,(pu->chan->cid.cid_name ? pu->chan->cid.cid_name : "<unknown>")
01729          );
01730 
01731       free(pu);
01732    }
01733    /* JK02: it helps to answer the channel if not already up */
01734    if (chan->_state != AST_STATE_UP) {
01735       ast_answer(chan);
01736    }
01737 
01738    if (peer) {
01739       /* Play a courtesy beep in the calling channel to prefix the bridge connecting */   
01740       if (!ast_strlen_zero(courtesytone)) {
01741          if (!ast_streamfile(chan, courtesytone, chan->language)) {
01742             if (ast_waitstream(chan, "") < 0) {
01743                ast_log(LOG_WARNING, "Failed to play courtesy tone!\n");
01744                ast_hangup(peer);
01745                return -1;
01746             }
01747          }
01748       }
01749  
01750       ast_moh_stop(peer);
01751       ast_indicate(peer, AST_CONTROL_UNHOLD);
01752       res = ast_channel_make_compatible(chan, peer);
01753       if (res < 0) {
01754          ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
01755          ast_hangup(peer);
01756          return -1;
01757       }
01758       /* This runs sorta backwards, since we give the incoming channel control, as if it
01759          were the person called. */
01760       if (option_verbose > 2) 
01761          ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
01762 
01763       memset(&config, 0, sizeof(struct ast_bridge_config));
01764       ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
01765       ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
01766       config.timelimit = 0;
01767       config.play_warning = 0;
01768       config.warning_freq = 0;
01769       config.warning_sound=NULL;
01770       res = ast_bridge_call(chan, peer, &config);
01771 
01772       /* Simulate the PBX hanging up */
01773       if (res != AST_PBX_NO_HANGUP_PEER)
01774          ast_hangup(peer);
01775       return res;
01776    } else {
01777       /* XXX Play a message XXX */
01778       dres = ast_streamfile(chan, "pbx-invalidpark", chan->language);
01779       if (!dres)
01780             dres = ast_waitstream(chan, "");
01781       else {
01782          ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark", chan->name);
01783          dres = 0;
01784       }
01785       if (option_verbose > 2) 
01786          ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to nonexistent parked call %d\n", chan->name, park);
01787       res = -1;
01788    }
01789    LOCAL_USER_REMOVE(u);
01790    return res;
01791 }
01792 
01793 static int handle_showfeatures(int fd, int argc, char *argv[])
01794 {
01795    int i;
01796    int fcount;
01797    struct ast_call_feature *feature;
01798    char format[] = "%-25s %-7s %-7s\n";
01799 
01800    ast_cli(fd, format, "Builtin Feature", "Default", "Current");
01801    ast_cli(fd, format, "---------------", "-------", "-------");
01802 
01803    ast_cli(fd, format, "Pickup", "*8", ast_pickup_ext());      /* default hardcoded above, so we'll hardcode it here */
01804 
01805    fcount = sizeof(builtin_features) / sizeof(builtin_features[0]);
01806 
01807    for (i = 0; i < fcount; i++)
01808    {
01809       ast_cli(fd, format, builtin_features[i].fname, builtin_features[i].default_exten, builtin_features[i].exten);
01810    }
01811    ast_cli(fd, "\n");
01812    ast_cli(fd, format, "Dynamic Feature", "Default", "Current");
01813    ast_cli(fd, format, "---------------", "-------", "-------");
01814    if (AST_LIST_EMPTY(&feature_list)) {
01815       ast_cli(fd, "(none)\n");
01816    }
01817    else {
01818       AST_LIST_LOCK(&feature_list);
01819       AST_LIST_TRAVERSE(&feature_list, feature, feature_entry) {
01820          ast_cli(fd, format, feature->sname, "no def", feature->exten); 
01821       }
01822       AST_LIST_UNLOCK(&feature_list);
01823    }
01824    ast_cli(fd, "\nCall parking\n");
01825    ast_cli(fd, "------------\n");
01826    ast_cli(fd,"%-20s:   %s\n", "Parking extension", parking_ext);
01827    ast_cli(fd,"%-20s:   %s\n", "Parking context", parking_con);
01828    ast_cli(fd,"%-20s:   %d-%d\n", "Parked call extensions", parking_start, parking_stop);
01829    ast_cli(fd,"\n");
01830    
01831    return RESULT_SUCCESS;
01832 }
01833 
01834 static char showfeatures_help[] =
01835 "Usage: show features\n"
01836 "       Lists currently configured features.\n";
01837 
01838 static struct ast_cli_entry showfeatures =
01839 { { "show", "features", NULL }, handle_showfeatures, "Lists configured features", showfeatures_help };
01840 
01841 static int handle_parkedcalls(int fd, int argc, char *argv[])
01842 {
01843    struct parkeduser *cur;
01844    int numparked = 0;
01845 
01846    ast_cli(fd, "%4s %25s (%-15s %-12s %-4s) %-6s \n", "Num", "Channel"
01847       , "Context", "Extension", "Pri", "Timeout");
01848 
01849    ast_mutex_lock(&parking_lock);
01850 
01851    cur = parkinglot;
01852    while(cur) {
01853       ast_cli(fd, "%4d %25s (%-15s %-12s %-4d) %6lds\n"
01854          ,cur->parkingnum, cur->chan->name, cur->context, cur->exten
01855          ,cur->priority, cur->start.tv_sec + (cur->parkingtime/1000) - time(NULL));
01856 
01857       cur = cur->next;
01858       numparked++;
01859    }
01860    ast_cli(fd, "%d parked call%s.\n", numparked, (numparked != 1) ? "s" : "");
01861 
01862    ast_mutex_unlock(&parking_lock);
01863 
01864    return RESULT_SUCCESS;
01865 }
01866 
01867 static char showparked_help[] =
01868 "Usage: show parkedcalls\n"
01869 "       Lists currently parked calls.\n";
01870 
01871 static struct ast_cli_entry showparked =
01872 { { "show", "parkedcalls", NULL }, handle_parkedcalls, "Lists parked calls", showparked_help };
01873 
01874 /* Dump lot status */
01875 static int manager_parking_status( struct mansession *s, struct message *m )
01876 {
01877    struct parkeduser *cur;
01878    char *id = astman_get_header(m,"ActionID");
01879    char idText[256] = "";
01880 
01881    if (!ast_strlen_zero(id))
01882       snprintf(idText,256,"ActionID: %s\r\n",id);
01883 
01884    astman_send_ack(s, m, "Parked calls will follow");
01885 
01886         ast_mutex_lock(&parking_lock);
01887 
01888         cur=parkinglot;
01889         while(cur) {
01890          ast_cli(s->fd, "Event: ParkedCall\r\n"
01891          "Exten: %d\r\n"
01892          "Channel: %s\r\n"
01893          "Timeout: %ld\r\n"
01894          "CallerID: %s\r\n"
01895          "CallerIDName: %s\r\n"
01896          "%s"
01897          "\r\n"
01898                         ,cur->parkingnum, cur->chan->name
01899                         ,(long)cur->start.tv_sec + (long)(cur->parkingtime/1000) - (long)time(NULL)
01900          ,(cur->chan->cid.cid_num ? cur->chan->cid.cid_num : "")
01901          ,(cur->chan->cid.cid_name ? cur->chan->cid.cid_name : "")
01902          ,idText);
01903 
01904             cur = cur->next;
01905         }
01906 
01907    ast_cli(s->fd,
01908    "Event: ParkedCallsComplete\r\n"
01909    "%s"
01910    "\r\n",idText);
01911 
01912         ast_mutex_unlock(&parking_lock);
01913 
01914         return RESULT_SUCCESS;
01915 }
01916 
01917 
01918 int ast_pickup_call(struct ast_channel *chan)
01919 {
01920    struct ast_channel *cur = NULL;
01921    int res = -1;
01922 
01923    while ( (cur = ast_channel_walk_locked(cur)) != NULL) {
01924       if (!cur->pbx && 
01925          (cur != chan) &&
01926          (chan->pickupgroup & cur->callgroup) &&
01927          ((cur->_state == AST_STATE_RINGING) ||
01928           (cur->_state == AST_STATE_RING))) {
01929             break;
01930       }
01931       ast_mutex_unlock(&cur->lock);
01932    }
01933    if (cur) {
01934       if (option_debug)
01935          ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n",cur->name, chan->name);
01936       res = ast_answer(chan);
01937       if (res)
01938          ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
01939       res = ast_queue_control(chan, AST_CONTROL_ANSWER);
01940       if (res)
01941          ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
01942       res = ast_channel_masquerade(cur, chan);
01943       if (res)
01944          ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, cur->name);     /* Done */
01945       ast_mutex_unlock(&cur->lock);
01946    } else   {
01947       if (option_debug)
01948          ast_log(LOG_DEBUG, "No call pickup possible...\n");
01949    }
01950    return res;
01951 }
01952 
01953 static int load_config(void) 
01954 {
01955    int start = 0, end = 0;
01956    struct ast_context *con = NULL;
01957    struct ast_config *cfg = NULL;
01958    struct ast_variable *var = NULL;
01959    char old_parking_ext[AST_MAX_EXTENSION];
01960    char old_parking_con[AST_MAX_EXTENSION] = "";
01961 
01962    if (!ast_strlen_zero(parking_con)) {
01963       strcpy(old_parking_ext, parking_ext);
01964       strcpy(old_parking_con, parking_con);
01965    } 
01966 
01967    /* Reset to defaults */
01968    strcpy(parking_con, "parkedcalls");
01969    strcpy(parking_con_dial, "park-dial");
01970    strcpy(parking_ext, "700");
01971    strcpy(pickup_ext, "*8");
01972    courtesytone[0] = '\0';
01973    strcpy(xfersound, "beep");
01974    strcpy(xferfailsound, "pbx-invalid");
01975    parking_start = 701;
01976    parking_stop = 750;
01977    parkfindnext = 0;
01978    adsipark = 0;
01979 
01980    transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
01981    featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
01982 
01983    cfg = ast_config_load("features.conf");
01984    if (!cfg) {
01985       cfg = ast_config_load("parking.conf");
01986       if (cfg)
01987          ast_log(LOG_NOTICE, "parking.conf is deprecated in favor of 'features.conf'.  Please rename it.\n");
01988    }
01989    if (cfg) {
01990       var = ast_variable_browse(cfg, "general");
01991       while(var) {
01992          if (!strcasecmp(var->name, "parkext")) {
01993             ast_copy_string(parking_ext, var->value, sizeof(parking_ext));
01994          } else if (!strcasecmp(var->name, "context")) {
01995             ast_copy_string(parking_con, var->value, sizeof(parking_con));
01996          } else if (!strcasecmp(var->name, "parkingtime")) {
01997             if ((sscanf(var->value, "%d", &parkingtime) != 1) || (parkingtime < 1)) {
01998                ast_log(LOG_WARNING, "%s is not a valid parkingtime\n", var->value);
01999                parkingtime = DEFAULT_PARK_TIME;
02000             } else
02001                parkingtime = parkingtime * 1000;
02002          } else if (!strcasecmp(var->name, "parkpos")) {
02003             if (sscanf(var->value, "%d-%d", &start, &end) != 2) {
02004                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);
02005             } else {
02006                parking_start = start;
02007                parking_stop = end;
02008             }
02009          } else if (!strcasecmp(var->name, "findslot")) {
02010             parkfindnext = (!strcasecmp(var->value, "next"));
02011          } else if (!strcasecmp(var->name, "adsipark")) {
02012             adsipark = ast_true(var->value);
02013          } else if (!strcasecmp(var->name, "transferdigittimeout")) {
02014             if ((sscanf(var->value, "%d", &transferdigittimeout) != 1) || (transferdigittimeout < 1)) {
02015                ast_log(LOG_WARNING, "%s is not a valid transferdigittimeout\n", var->value);
02016                transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
02017             } else
02018                transferdigittimeout = transferdigittimeout * 1000;
02019          } else if (!strcasecmp(var->name, "featuredigittimeout")) {
02020             if ((sscanf(var->value, "%d", &featuredigittimeout) != 1) || (featuredigittimeout < 1)) {
02021                ast_log(LOG_WARNING, "%s is not a valid featuredigittimeout\n", var->value);
02022                featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
02023             }
02024          } else if (!strcasecmp(var->name, "courtesytone")) {
02025             ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
02026          } else if (!strcasecmp(var->name, "xfersound")) {
02027             ast_copy_string(xfersound, var->value, sizeof(xfersound));
02028          } else if (!strcasecmp(var->name, "xferfailsound")) {
02029             ast_copy_string(xferfailsound, var->value, sizeof(xferfailsound));
02030          } else if (!strcasecmp(var->name, "pickupexten")) {
02031             ast_copy_string(pickup_ext, var->value, sizeof(pickup_ext));
02032          }
02033          var = var->next;
02034       }
02035 
02036       unmap_features();
02037       var = ast_variable_browse(cfg, "featuremap");
02038       while(var) {
02039          if (remap_feature(var->name, var->value))
02040             ast_log(LOG_NOTICE, "Unknown feature '%s'\n", var->name);
02041          var = var->next;
02042       }
02043 
02044       /* Map a key combination to an application*/
02045       ast_unregister_features();
02046       var = ast_variable_browse(cfg, "applicationmap");
02047       while(var) {
02048          char *tmp_val=strdup(var->value);
02049          char *exten, *party=NULL, *app=NULL, *app_args=NULL; 
02050 
02051          if (!tmp_val) { 
02052             ast_log(LOG_ERROR, "res_features: strdup failed");
02053             continue;
02054          }
02055          
02056 
02057          exten=strsep(&tmp_val,",");
02058          if (exten) party=strsep(&tmp_val,",");
02059          if (party) app=strsep(&tmp_val,",");
02060 
02061          if (app) app_args=strsep(&tmp_val,",");
02062 
02063          if (!(app && strlen(app)) || !(exten && strlen(exten)) || !(party && strlen(party)) || !(var->name && strlen(var->name))) {
02064             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);
02065             free(tmp_val);
02066             var = var->next;
02067             continue;
02068          }
02069 
02070          {
02071             struct ast_call_feature *feature=find_feature(var->name);
02072             int mallocd=0;
02073             
02074             if (!feature) {
02075                feature=malloc(sizeof(struct ast_call_feature));
02076                mallocd=1;
02077             }
02078             if (!feature) {
02079                ast_log(LOG_NOTICE, "Malloc failed at feature mapping\n");
02080                free(tmp_val);
02081                var = var->next;
02082                continue;
02083             }
02084 
02085             memset(feature,0,sizeof(struct ast_call_feature));
02086             ast_copy_string(feature->sname,var->name,FEATURE_SNAME_LEN);
02087             ast_copy_string(feature->app,app,FEATURE_APP_LEN);
02088             ast_copy_string(feature->exten, exten,FEATURE_EXTEN_LEN);
02089             free(tmp_val);
02090             
02091             if (app_args) 
02092                ast_copy_string(feature->app_args,app_args,FEATURE_APP_ARGS_LEN);
02093             
02094             ast_copy_string(feature->exten, exten,sizeof(feature->exten));
02095             feature->operation=feature_exec_app;
02096             ast_set_flag(feature,AST_FEATURE_FLAG_NEEDSDTMF);
02097             
02098             if (!strcasecmp(party,"caller"))
02099                ast_set_flag(feature,AST_FEATURE_FLAG_CALLER);
02100             else if (!strcasecmp(party, "callee"))
02101                ast_set_flag(feature,AST_FEATURE_FLAG_CALLEE);
02102             else {
02103                ast_log(LOG_NOTICE, "Invalid party specification for feature '%s', must be caller, or callee\n", var->name);
02104                var = var->next;
02105                continue;
02106             }
02107 
02108             ast_register_feature(feature);
02109             
02110             if (option_verbose >=1) ast_verbose(VERBOSE_PREFIX_2 "Mapping Feature '%s' to app '%s' with code '%s'\n", var->name, app, exten);  
02111          }
02112          var = var->next;
02113       }   
02114    }
02115    ast_config_destroy(cfg);
02116 
02117    /* Remove the old parking extension */
02118    if (!ast_strlen_zero(old_parking_con) && (con = ast_context_find(old_parking_con))) {
02119       ast_context_remove_extension2(con, old_parking_ext, 1, registrar);
02120       ast_log(LOG_DEBUG, "Removed old parking extension %s@%s\n", old_parking_ext, old_parking_con);
02121    }
02122    
02123    if (!(con = ast_context_find(parking_con))) {
02124       if (!(con = ast_context_create(NULL, parking_con, registrar))) {
02125          ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
02126          return -1;
02127       }
02128    }
02129    return ast_add_extension2(con, 1, ast_parking_ext(), 1, NULL, NULL, parkcall, strdup(""), FREE, registrar);
02130 }
02131 
02132 int reload(void) {
02133    return load_config();
02134 }
02135 
02136 int load_module(void)
02137 {
02138    int res;
02139    
02140    AST_LIST_HEAD_INIT(&feature_list);
02141    memset(parking_ext, 0, sizeof(parking_ext));
02142    memset(parking_con, 0, sizeof(parking_con));
02143 
02144    if ((res = load_config()))
02145       return res;
02146    ast_cli_register(&showparked);
02147    ast_cli_register(&showfeatures);
02148    ast_pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
02149    res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
02150    if (!res)
02151       res = ast_register_application(parkcall, park_call_exec, synopsis2, descrip2);
02152    if (!res) {
02153       ast_manager_register("ParkedCalls", 0, manager_parking_status, "List parked calls" );
02154    }
02155    return res;
02156 }
02157 
02158 
02159 int unload_module(void)
02160 {
02161    STANDARD_HANGUP_LOCALUSERS;
02162 
02163    ast_manager_unregister("ParkedCalls");
02164    ast_cli_unregister(&showfeatures);
02165    ast_cli_unregister(&showparked);
02166    ast_unregister_application(parkcall);
02167    return ast_unregister_application(parkedcall);
02168 }
02169 
02170 char *description(void)
02171 {
02172    return "Call Features Resource";
02173 }
02174 
02175 int usecount(void)
02176 {
02177    /* Never allow parking to be unloaded because it will
02178       unresolve needed symbols in the dialer */
02179 #if 0
02180    int res;
02181    STANDARD_USECOUNT(res);
02182    return res;
02183 #else
02184    return 1;
02185 #endif
02186 }
02187 
02188 char *key()
02189 {
02190    return ASTERISK_GPL_KEY;
02191 }

Generated on Fri May 26 01:45:36 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.6