00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include "asterisk.h"
00029
00030 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 162343 $")
00031
00032 #include "asterisk/file.h"
00033 #include "asterisk/channel.h"
00034 #include "asterisk/pbx.h"
00035 #include "asterisk/module.h"
00036 #include "asterisk/lock.h"
00037 #include "asterisk/app.h"
00038 #include "asterisk/features.h"
00039
00040 #define PICKUPMARK "PICKUPMARK"
00041
00042 static const char *app = "Pickup";
00043 static const char *synopsis = "Directed Call Pickup";
00044 static const char *descrip =
00045 " Pickup([extension[@context][&extension2@[context]...]]): This application can\n"
00046 "pickup any ringing channel that is calling the specified extension. If no\n"
00047 "context is specified, the current context will be used. If you use the special\n"
00048 "string \"PICKUPMARK\" for the context parameter, for example 10@PICKUPMARK,\n"
00049 "this application tries to find a channel which has defined a ${PICKUPMARK}\n"
00050 "channel variable with the same value as \"extension\" (in this example, \"10\").\n"
00051 "When no parameter is specified, the application will pickup a channel matching\n"
00052 "the pickup group of the active channel.";
00053
00054
00055 static int pickup_do(struct ast_channel *chan, struct ast_channel *target)
00056 {
00057 int res = 0;
00058
00059 ast_debug(1, "Call pickup on '%s' by '%s'\n", target->name, chan->name);
00060
00061 if ((res = ast_answer(chan))) {
00062 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
00063 return -1;
00064 }
00065
00066 if ((res = ast_queue_control(chan, AST_CONTROL_ANSWER))) {
00067 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
00068 return -1;
00069 }
00070
00071 if ((res = ast_channel_masquerade(target, chan))) {
00072 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);
00073 return -1;
00074 }
00075
00076 return res;
00077 }
00078
00079
00080 static int can_pickup(struct ast_channel *chan)
00081 {
00082 if (!chan->pbx && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING || chan->_state == AST_STATE_DOWN))
00083 return 1;
00084 else
00085 return 0;
00086 }
00087
00088
00089 static int pickup_by_exten(struct ast_channel *chan, const char *exten, const char *context)
00090 {
00091 int res = -1;
00092 struct ast_channel *target = NULL;
00093
00094 while ((target = ast_channel_walk_locked(target))) {
00095 if ((!strcasecmp(target->macroexten, exten) || !strcasecmp(target->exten, exten)) &&
00096 !strcasecmp(target->dialcontext, context) &&
00097 can_pickup(target)) {
00098 res = pickup_do(chan, target);
00099 ast_channel_unlock(target);
00100 break;
00101 }
00102 ast_channel_unlock(target);
00103 }
00104
00105 return res;
00106 }
00107
00108
00109 static int pickup_by_mark(struct ast_channel *chan, const char *mark)
00110 {
00111 int res = -1;
00112 const char *tmp = NULL;
00113 struct ast_channel *target = NULL;
00114
00115 while ((target = ast_channel_walk_locked(target))) {
00116 if ((tmp = pbx_builtin_getvar_helper(target, PICKUPMARK)) &&
00117 !strcasecmp(tmp, mark) &&
00118 can_pickup(target)) {
00119 res = pickup_do(chan, target);
00120 ast_channel_unlock(target);
00121 break;
00122 }
00123 ast_channel_unlock(target);
00124 }
00125
00126 return res;
00127 }
00128
00129
00130 static int pickup_exec(struct ast_channel *chan, void *data)
00131 {
00132 int res = 0;
00133 char *tmp = ast_strdupa(data);
00134 char *exten = NULL, *context = NULL;
00135
00136 if (ast_strlen_zero(data)) {
00137 res = ast_pickup_call(chan);
00138 return res;
00139 }
00140
00141
00142 while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
00143 if ((context = strchr(exten, '@')))
00144 *context++ = '\0';
00145 if (!ast_strlen_zero(context) && !strcasecmp(context, PICKUPMARK)) {
00146 if (!pickup_by_mark(chan, exten))
00147 break;
00148 } else {
00149 if (!pickup_by_exten(chan, exten, !ast_strlen_zero(context) ? context : chan->context))
00150 break;
00151 }
00152 ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten);
00153 }
00154
00155 return res;
00156 }
00157
00158 static int unload_module(void)
00159 {
00160 int res;
00161
00162 res = ast_unregister_application(app);
00163
00164 return res;
00165 }
00166
00167 static int load_module(void)
00168 {
00169 return ast_register_application(app, pickup_exec, synopsis, descrip);
00170 }
00171
00172 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Directed Call Pickup Application");