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
00033
00034
00035
00036 #include "asterisk.h"
00037
00038 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 329199 $")
00039
00040 #include "asterisk/file.h"
00041 #include "asterisk/channel.h"
00042 #include "asterisk/pbx.h"
00043 #include "asterisk/module.h"
00044 #include "asterisk/lock.h"
00045 #include "asterisk/app.h"
00046 #include "asterisk/features.h"
00047 #include "asterisk/manager.h"
00048 #include "asterisk/callerid.h"
00049 #include "asterisk/cel.h"
00050
00051 #define PICKUPMARK "PICKUPMARK"
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102 static const char app[] = "Pickup";
00103 static const char app2[] = "PickupChan";
00104
00105
00106 struct pickup_by_name_args {
00107 const char *name;
00108 size_t len;
00109 };
00110
00111 static int pickup_by_name_cb(void *obj, void *arg, void *data, int flags)
00112 {
00113 struct ast_channel *target = obj;
00114 struct pickup_by_name_args *args = data;
00115
00116 ast_channel_lock(target);
00117 if (!strncasecmp(target->name, args->name, args->len) && ast_can_pickup(target)) {
00118
00119 return CMP_MATCH | CMP_STOP;
00120 }
00121 ast_channel_unlock(target);
00122
00123 return 0;
00124 }
00125
00126
00127 static struct ast_channel *my_ast_get_channel_by_name_locked(const char *channame)
00128 {
00129 char *chkchan;
00130 struct pickup_by_name_args pickup_args;
00131
00132
00133
00134
00135 if (strchr(channame, '-')) {
00136
00137 pickup_args.len = strlen(channame);
00138 pickup_args.name = channame;
00139 } else {
00140
00141
00142
00143
00144 pickup_args.len = strlen(channame) + 1;
00145 chkchan = alloca(pickup_args.len + 1);
00146 strcpy(chkchan, channame);
00147 strcat(chkchan, "-");
00148 pickup_args.name = chkchan;
00149 }
00150
00151 return ast_channel_callback(pickup_by_name_cb, NULL, &pickup_args, 0);
00152 }
00153
00154
00155 static int pickup_by_channel(struct ast_channel *chan, char *pickup)
00156 {
00157 int res = -1;
00158 struct ast_channel *target;
00159
00160 target = my_ast_get_channel_by_name_locked(pickup);
00161 if (target) {
00162
00163 if (chan != target) {
00164 res = ast_do_pickup(chan, target);
00165 }
00166 ast_channel_unlock(target);
00167 target = ast_channel_unref(target);
00168 }
00169
00170 return res;
00171 }
00172
00173
00174 static int pickup_by_exten(struct ast_channel *chan, const char *exten, const char *context)
00175 {
00176 struct ast_channel *target = NULL;
00177 struct ast_channel_iterator *iter;
00178 int res = -1;
00179
00180 if (!(iter = ast_channel_iterator_by_exten_new(exten, context))) {
00181 return -1;
00182 }
00183
00184 while ((target = ast_channel_iterator_next(iter))) {
00185 ast_channel_lock(target);
00186 if ((chan != target) && ast_can_pickup(target)) {
00187 ast_log(LOG_NOTICE, "%s pickup by %s\n", target->name, chan->name);
00188 break;
00189 }
00190 ast_channel_unlock(target);
00191 target = ast_channel_unref(target);
00192 }
00193
00194 ast_channel_iterator_destroy(iter);
00195
00196 if (target) {
00197 res = ast_do_pickup(chan, target);
00198 ast_channel_unlock(target);
00199 target = ast_channel_unref(target);
00200 }
00201
00202 return res;
00203 }
00204
00205 static int find_by_mark(void *obj, void *arg, void *data, int flags)
00206 {
00207 struct ast_channel *target = obj;
00208 const char *mark = data;
00209 const char *tmp;
00210
00211 ast_channel_lock(target);
00212 tmp = pbx_builtin_getvar_helper(target, PICKUPMARK);
00213 if (tmp && !strcasecmp(tmp, mark) && ast_can_pickup(target)) {
00214
00215 return CMP_MATCH | CMP_STOP;
00216 }
00217 ast_channel_unlock(target);
00218
00219 return 0;
00220 }
00221
00222
00223 static int pickup_by_mark(struct ast_channel *chan, const char *mark)
00224 {
00225 struct ast_channel *target;
00226 int res = -1;
00227
00228
00229 target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0);
00230 if (target) {
00231 res = ast_do_pickup(chan, target);
00232 ast_channel_unlock(target);
00233 target = ast_channel_unref(target);
00234 }
00235
00236 return res;
00237 }
00238
00239 static int find_channel_by_group(void *obj, void *arg, void *data, int flags)
00240 {
00241 struct ast_channel *target = obj;
00242 struct ast_channel *chan = data;
00243
00244 ast_channel_lock(target);
00245 if (chan != target && (chan->pickupgroup & target->callgroup)
00246 && ast_can_pickup(target)) {
00247
00248 return CMP_MATCH | CMP_STOP;
00249 }
00250 ast_channel_unlock(target);
00251
00252 return 0;
00253 }
00254
00255 static int pickup_by_group(struct ast_channel *chan)
00256 {
00257 struct ast_channel *target;
00258 int res = -1;
00259
00260
00261 target = ast_channel_callback(find_channel_by_group, NULL, chan, 0);
00262 if (target) {
00263 ast_log(LOG_NOTICE, "pickup %s attempt by %s\n", target->name, chan->name);
00264 res = ast_do_pickup(chan, target);
00265 ast_channel_unlock(target);
00266 target = ast_channel_unref(target);
00267 }
00268
00269 return res;
00270 }
00271
00272
00273 static int pickup_exec(struct ast_channel *chan, const char *data)
00274 {
00275 char *tmp = ast_strdupa(data);
00276 char *exten = NULL, *context = NULL;
00277
00278 if (ast_strlen_zero(data)) {
00279 return pickup_by_group(chan) ? 0 : -1;
00280 }
00281
00282
00283 while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
00284 if ((context = strchr(exten, '@')))
00285 *context++ = '\0';
00286 if (!ast_strlen_zero(context) && !strcasecmp(context, PICKUPMARK)) {
00287 if (!pickup_by_mark(chan, exten)) {
00288
00289 return -1;
00290 }
00291 } else {
00292 if (!pickup_by_exten(chan, exten, !ast_strlen_zero(context) ? context : chan->context)) {
00293
00294 return -1;
00295 }
00296 }
00297 ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten);
00298 }
00299
00300
00301 return 0;
00302 }
00303
00304
00305 static int find_by_part(void *obj, void *arg, void *data, int flags)
00306 {
00307 struct ast_channel *target = obj;
00308 const char *part = data;
00309 int len = strlen(part);
00310
00311 ast_channel_lock(target);
00312 if (len <= strlen(target->name) && !strncmp(target->name, part, len)
00313 && ast_can_pickup(target)) {
00314
00315 return CMP_MATCH | CMP_STOP;
00316 }
00317 ast_channel_unlock(target);
00318
00319 return 0;
00320 }
00321
00322
00323 static int pickup_by_part(struct ast_channel *chan, const char *part)
00324 {
00325 struct ast_channel *target;
00326 int res = -1;
00327
00328
00329 target = ast_channel_callback(find_by_part, NULL, (char *) part, 0);
00330 if (target) {
00331 res = ast_do_pickup(chan, target);
00332 ast_channel_unlock(target);
00333 target = ast_channel_unref(target);
00334 }
00335
00336 return res;
00337 }
00338
00339
00340 static int pickupchan_exec(struct ast_channel *chan, const char *data)
00341 {
00342 int partial_pickup = 0;
00343 char *pickup = NULL;
00344 char *parse = ast_strdupa(data);
00345 AST_DECLARE_APP_ARGS(args,
00346 AST_APP_ARG(channel);
00347 AST_APP_ARG(options);
00348 );
00349 AST_STANDARD_APP_ARGS(args, parse);
00350
00351 if (ast_strlen_zero(args.channel)) {
00352 ast_log(LOG_WARNING, "PickupChan requires an argument (channel)!\n");
00353
00354 return 0;
00355 }
00356
00357 if (!ast_strlen_zero(args.options) && strchr(args.options, 'p')) {
00358 partial_pickup = 1;
00359 }
00360
00361
00362 while (!ast_strlen_zero(args.channel) && (pickup = strsep(&args.channel, "&"))) {
00363 if (!strncasecmp(chan->name, pickup, strlen(pickup))) {
00364 ast_log(LOG_NOTICE, "Cannot pickup your own channel %s.\n", pickup);
00365 } else {
00366 if (partial_pickup) {
00367 if (!pickup_by_part(chan, pickup)) {
00368
00369 return -1;
00370 }
00371 } else if (!pickup_by_channel(chan, pickup)) {
00372
00373 return -1;
00374 }
00375 ast_log(LOG_NOTICE, "No target channel found for %s.\n", pickup);
00376 }
00377 }
00378
00379
00380 return 0;
00381 }
00382
00383 static int unload_module(void)
00384 {
00385 int res;
00386
00387 res = ast_unregister_application(app);
00388 res |= ast_unregister_application(app2);
00389
00390 return res;
00391 }
00392
00393 static int load_module(void)
00394 {
00395 int res;
00396
00397 res = ast_register_application_xml(app, pickup_exec);
00398 res |= ast_register_application_xml(app2, pickupchan_exec);
00399
00400 return res;
00401 }
00402
00403 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Directed Call Pickup Application");