Wed Aug 18 22:33:41 2010

Asterisk developer's documentation


app_directed_pickup.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2005, Joshua Colp
00005  *
00006  * Joshua Colp <jcolp@digium.com>
00007  *
00008  * Portions merged from app_pickupchan, which was
00009  * Copyright (C) 2008, Gary Cook
00010  *
00011  * See http://www.asterisk.org for more information about
00012  * the Asterisk project. Please do not directly contact
00013  * any of the maintainers of this project for assistance;
00014  * the project provides a web site, mailing lists and IRC
00015  * channels for your use.
00016  *
00017  * This program is free software, distributed under the terms of
00018  * the GNU General Public License Version 2. See the LICENSE file
00019  * at the top of the source tree.
00020  */
00021 
00022 /*! \file
00023  *
00024  * \brief Directed Call Pickup Support
00025  *
00026  * \author Joshua Colp <jcolp@digium.com>
00027  * \author Gary Cook
00028  *
00029  * \ingroup applications
00030  */
00031 
00032 #include "asterisk.h"
00033 
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 218227 $")
00035 
00036 #include "asterisk/file.h"
00037 #include "asterisk/channel.h"
00038 #include "asterisk/pbx.h"
00039 #include "asterisk/module.h"
00040 #include "asterisk/lock.h"
00041 #include "asterisk/app.h"
00042 #include "asterisk/features.h"
00043 
00044 #define PICKUPMARK "PICKUPMARK"
00045 
00046 static const char *app = "Pickup";
00047 static const char *synopsis = "Directed Call Pickup";
00048 static const char *descrip =
00049 "  Pickup([extension[@context][&extension2@[context]...]]):  This application can\n"
00050 "pickup any ringing channel that is calling the specified extension.  If no\n"
00051 "context is specified, the current context will be used. If you use the special\n"
00052 "string \"PICKUPMARK\" for the context parameter, for example 10@PICKUPMARK,\n"
00053 "this application tries to find a channel which has defined a ${PICKUPMARK}\n"
00054 "channel variable with the same value as \"extension\" (in this example, \"10\").\n"
00055 "When no parameter is specified, the application will pickup a channel matching\n"
00056 "the pickup group of the active channel.";
00057 
00058 static const char *app2 = "PickupChan";
00059 static const char *synopsis2 = "Pickup a ringing channel";
00060 static const char *descrip2 =
00061 "  PickupChan(channel[&channel...]): This application can pickup any ringing channel\n";
00062 
00063 /*! \todo This application should return a result code, like PICKUPRESULT */
00064 
00065 /* Perform actual pickup between two channels */
00066 static int pickup_do(struct ast_channel *chan, struct ast_channel *target)
00067 {
00068    int res = 0;
00069 
00070    ast_debug(1, "Call pickup on '%s' by '%s'\n", target->name, chan->name);
00071 
00072    if ((res = ast_answer(chan))) {
00073       ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
00074       return -1;
00075    }
00076 
00077    if ((res = ast_queue_control(chan, AST_CONTROL_ANSWER))) {
00078       ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
00079       return -1;
00080    }
00081 
00082    if ((res = ast_channel_masquerade(target, chan))) {
00083       ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);
00084       return -1;
00085    }
00086 
00087    return res;
00088 }
00089 
00090 /* Helper function that determines whether a channel is capable of being picked up */
00091 static int can_pickup(struct ast_channel *chan)
00092 {
00093    if (!chan->pbx && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING || chan->_state == AST_STATE_DOWN))
00094       return 1;
00095    else
00096       return 0;
00097 }
00098 
00099 /*! \brief Helper Function to walk through ALL channels checking NAME and STATE */
00100 static struct ast_channel *my_ast_get_channel_by_name_locked(char *channame)
00101 {
00102    struct ast_channel *chan;
00103    char *chkchan = alloca(strlen(channame) + 2);
00104 
00105    /* need to append a '-' for the comparison so we check full channel name,
00106     * i.e SIP/hgc- , use a temporary variable so original stays the same for
00107     * debugging.
00108     */
00109    strcpy(chkchan, channame);
00110    strcat(chkchan, "-");
00111 
00112    for (chan = ast_walk_channel_by_name_prefix_locked(NULL, channame, strlen(channame));
00113        chan;
00114        chan = ast_walk_channel_by_name_prefix_locked(chan, channame, strlen(channame))) {
00115       if (!strncasecmp(chan->name, chkchan, strlen(chkchan)) && can_pickup(chan))
00116          return chan;
00117       ast_channel_unlock(chan);
00118    }
00119    return NULL;
00120 }
00121 
00122 /*! \brief Attempt to pick up specified channel named , does not use context */
00123 static int pickup_by_channel(struct ast_channel *chan, char *pickup)
00124 {
00125    int res = 0;
00126    struct ast_channel *target;
00127 
00128    if (!(target = my_ast_get_channel_by_name_locked(pickup)))
00129       return -1;
00130 
00131    /* Just check that we are not picking up the SAME as target */
00132    if (chan->name != target->name && chan != target) {
00133       res = pickup_do(chan, target);
00134    }
00135    ast_channel_unlock(target);
00136 
00137    return res;
00138 }
00139 
00140 /* Attempt to pick up specified extension with context */
00141 static int pickup_by_exten(struct ast_channel *chan, const char *exten, const char *context)
00142 {
00143    int res = -1;
00144    struct ast_channel *target = NULL;
00145 
00146    while ((target = ast_channel_walk_locked(target))) {
00147       if ((!strcasecmp(target->macroexten, exten) || !strcasecmp(target->exten, exten)) &&
00148          !strcasecmp(target->dialcontext, context) &&
00149          (chan != target) && can_pickup(target)) {
00150          res = pickup_do(chan, target);
00151          ast_channel_unlock(target);
00152          break;
00153       }
00154       ast_channel_unlock(target);
00155    }
00156 
00157    return res;
00158 }
00159 
00160 /* Attempt to pick up specified mark */
00161 static int pickup_by_mark(struct ast_channel *chan, const char *mark)
00162 {
00163    int res = -1;
00164    const char *tmp = NULL;
00165    struct ast_channel *target = NULL;
00166 
00167    while ((target = ast_channel_walk_locked(target))) {
00168       if ((tmp = pbx_builtin_getvar_helper(target, PICKUPMARK)) &&
00169          !strcasecmp(tmp, mark) &&
00170          can_pickup(target)) {
00171          res = pickup_do(chan, target);
00172          ast_channel_unlock(target);
00173          break;
00174       }
00175       ast_channel_unlock(target);
00176    }
00177 
00178    return res;
00179 }
00180 
00181 /* application entry point for Pickup() */
00182 static int pickup_exec(struct ast_channel *chan, void *data)
00183 {
00184    int res = 0;
00185    char *tmp = ast_strdupa(data);
00186    char *exten = NULL, *context = NULL;
00187 
00188    if (ast_strlen_zero(data)) {
00189       res = ast_pickup_call(chan);
00190       return res;
00191    }
00192    
00193    /* Parse extension (and context if there) */
00194    while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
00195       if ((context = strchr(exten, '@')))
00196          *context++ = '\0';
00197       if (!ast_strlen_zero(context) && !strcasecmp(context, PICKUPMARK)) {
00198          if (!pickup_by_mark(chan, exten))
00199             break;
00200       } else {
00201          if (!pickup_by_exten(chan, exten, !ast_strlen_zero(context) ? context : chan->context))
00202             break;
00203       }
00204       ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten);
00205    }
00206 
00207    return res;
00208 }
00209 
00210 /* application entry point for PickupChan() */
00211 static int pickupchan_exec(struct ast_channel *chan, void *data)
00212 {
00213    int res = 0;
00214    char *tmp = ast_strdupa(data);
00215    char *pickup = NULL;
00216 
00217    if (ast_strlen_zero(data)) {
00218       ast_log(LOG_WARNING, "PickupChan requires an argument (channel)!\n");
00219       return -1;  
00220    }
00221 
00222    /* Parse channel */
00223    while (!ast_strlen_zero(tmp) && (pickup = strsep(&tmp, "&"))) {
00224       if (!strncasecmp(chan->name, pickup, strlen(pickup))) {
00225          ast_log(LOG_NOTICE, "Cannot pickup your own channel %s.\n", pickup);
00226       } else {
00227          if (!pickup_by_channel(chan, pickup)) {
00228             break;
00229          }
00230          ast_log(LOG_NOTICE, "No target channel found for %s.\n", pickup);
00231       }
00232    }
00233 
00234    return res;
00235 }
00236 
00237 static int unload_module(void)
00238 {
00239    int res;
00240 
00241    res = ast_unregister_application(app);
00242    res |= ast_unregister_application(app2);
00243 
00244    return res;
00245 }
00246 
00247 static int load_module(void)
00248 {
00249    int res;
00250 
00251    res = ast_register_application(app, pickup_exec, synopsis, descrip);
00252    res |= ast_register_application(app2, pickupchan_exec, synopsis2, descrip2);
00253 
00254    return res;
00255 }
00256 
00257 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Directed Call Pickup Application");

Generated on Wed Aug 18 22:33:41 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7