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
00029
00030
00031
00032 #include "asterisk.h"
00033
00034 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 179905 $")
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
00064
00065
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
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
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
00106
00107
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
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
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
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 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
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
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
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
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
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");