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: 290376 $")
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 #include "asterisk/manager.h"
00044 #include "asterisk/callerid.h"
00045 #include "asterisk/cel.h"
00046
00047 #define PICKUPMARK "PICKUPMARK"
00048
00049
00050
00051
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 static const char app[] = "Pickup";
00097 static const char app2[] = "PickupChan";
00098
00099
00100
00101 static int pickup_do(struct ast_channel *chan, struct ast_channel *target)
00102 {
00103 int res = 0;
00104 struct ast_party_connected_line connected_caller;
00105 struct ast_channel *chans[2] = { chan, target };
00106
00107 ast_debug(1, "Call pickup on '%s' by '%s'\n", target->name, chan->name);
00108 ast_cel_report_event(target, AST_CEL_PICKUP, NULL, NULL, chan);
00109
00110 ast_party_connected_line_init(&connected_caller);
00111 ast_party_connected_line_copy(&connected_caller, &target->connected);
00112 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
00113 if (ast_channel_connected_line_macro(NULL, chan, &connected_caller, 0, 0)) {
00114 ast_channel_update_connected_line(chan, &connected_caller, NULL);
00115 }
00116 ast_party_connected_line_free(&connected_caller);
00117
00118 ast_channel_lock(chan);
00119 ast_connected_line_copy_from_caller(&connected_caller, &chan->caller);
00120 ast_channel_unlock(chan);
00121 connected_caller.source = AST_CONNECTED_LINE_UPDATE_SOURCE_ANSWER;
00122 ast_channel_queue_connected_line_update(chan, &connected_caller, NULL);
00123 ast_party_connected_line_free(&connected_caller);
00124
00125 if ((res = ast_answer(chan))) {
00126 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
00127 return -1;
00128 }
00129
00130 if ((res = ast_queue_control(chan, AST_CONTROL_ANSWER))) {
00131 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
00132 return -1;
00133 }
00134
00135 if ((res = ast_channel_masquerade(target, chan))) {
00136 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);
00137 return -1;
00138 }
00139
00140
00141 ast_manager_event_multichan(EVENT_FLAG_CALL, "Pickup", 2, chans,
00142 "Channel: %s\r\nTargetChannel: %s\r\n", chan->name, target->name);
00143
00144 return res;
00145 }
00146
00147
00148 static int can_pickup(struct ast_channel *chan)
00149 {
00150 if (!chan->pbx && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING || chan->_state == AST_STATE_DOWN))
00151 return 1;
00152 else
00153 return 0;
00154 }
00155
00156 struct pickup_by_name_args {
00157 const char *name;
00158 size_t len;
00159 };
00160
00161 static int pickup_by_name_cb(void *obj, void *arg, void *data, int flags)
00162 {
00163 struct ast_channel *chan = obj;
00164 struct pickup_by_name_args *args = data;
00165
00166 ast_channel_lock(chan);
00167 if (!strncasecmp(chan->name, args->name, args->len) && can_pickup(chan)) {
00168
00169 return CMP_MATCH | CMP_STOP;
00170 }
00171 ast_channel_unlock(chan);
00172
00173 return 0;
00174 }
00175
00176
00177 static struct ast_channel *my_ast_get_channel_by_name_locked(const char *channame)
00178 {
00179 char *chkchan;
00180 struct pickup_by_name_args pickup_args;
00181
00182
00183
00184
00185 if (strchr(channame, '-')) {
00186
00187 pickup_args.len = strlen(channame);
00188 pickup_args.name = channame;
00189 } else {
00190
00191
00192
00193
00194 pickup_args.len = strlen(channame) + 1;
00195 chkchan = alloca(pickup_args.len + 1);
00196 strcpy(chkchan, channame);
00197 strcat(chkchan, "-");
00198 pickup_args.name = chkchan;
00199 }
00200
00201 return ast_channel_callback(pickup_by_name_cb, NULL, &pickup_args, 0);
00202 }
00203
00204
00205 static int pickup_by_channel(struct ast_channel *chan, char *pickup)
00206 {
00207 int res = 0;
00208 struct ast_channel *target;
00209
00210 if (!(target = my_ast_get_channel_by_name_locked(pickup))) {
00211 return -1;
00212 }
00213
00214
00215 if (chan != target) {
00216 res = pickup_do(chan, target);
00217 }
00218
00219 ast_channel_unlock(target);
00220 target = ast_channel_unref(target);
00221
00222 return res;
00223 }
00224
00225
00226 static int pickup_by_exten(struct ast_channel *chan, const char *exten, const char *context)
00227 {
00228 struct ast_channel *target = NULL;
00229 struct ast_channel_iterator *iter;
00230 int res = -1;
00231
00232 if (!(iter = ast_channel_iterator_by_exten_new(exten, context))) {
00233 return -1;
00234 }
00235
00236 while ((target = ast_channel_iterator_next(iter))) {
00237 ast_channel_lock(target);
00238 if ((chan != target) && can_pickup(target)) {
00239 break;
00240 }
00241 ast_channel_unlock(target);
00242 target = ast_channel_unref(target);
00243 }
00244
00245 ast_channel_iterator_destroy(iter);
00246
00247 if (target) {
00248 res = pickup_do(chan, target);
00249 ast_channel_unlock(target);
00250 target = ast_channel_unref(target);
00251 }
00252
00253 return res;
00254 }
00255
00256 static int find_by_mark(void *obj, void *arg, void *data, int flags)
00257 {
00258 struct ast_channel *c = obj;
00259 const char *mark = data;
00260 const char *tmp;
00261 int res;
00262
00263 ast_channel_lock(c);
00264
00265 res = (tmp = pbx_builtin_getvar_helper(c, PICKUPMARK)) &&
00266 !strcasecmp(tmp, mark) &&
00267 can_pickup(c);
00268
00269 ast_channel_unlock(c);
00270
00271 return res ? CMP_MATCH | CMP_STOP : 0;
00272 }
00273
00274
00275 static int pickup_by_mark(struct ast_channel *chan, const char *mark)
00276 {
00277 struct ast_channel *target;
00278 int res = -1;
00279
00280 if ((target = ast_channel_callback(find_by_mark, NULL, (char *) mark, 0))) {
00281 ast_channel_lock(target);
00282 res = pickup_do(chan, target);
00283 ast_channel_unlock(target);
00284 target = ast_channel_unref(target);
00285 }
00286
00287 return res;
00288 }
00289
00290
00291 static int pickup_exec(struct ast_channel *chan, const char *data)
00292 {
00293 int res = 0;
00294 char *tmp = ast_strdupa(data);
00295 char *exten = NULL, *context = NULL;
00296
00297 if (ast_strlen_zero(data)) {
00298 res = ast_pickup_call(chan);
00299 return res;
00300 }
00301
00302
00303 while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
00304 if ((context = strchr(exten, '@')))
00305 *context++ = '\0';
00306 if (!ast_strlen_zero(context) && !strcasecmp(context, PICKUPMARK)) {
00307 if (!pickup_by_mark(chan, exten))
00308 break;
00309 } else {
00310 if (!pickup_by_exten(chan, exten, !ast_strlen_zero(context) ? context : chan->context))
00311 break;
00312 }
00313 ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten);
00314 }
00315
00316 return res;
00317 }
00318
00319
00320 static int find_by_part(void *obj, void *arg, void *data, int flags)
00321 {
00322 struct ast_channel *c = obj;
00323 const char *part = data;
00324 int res = 0;
00325 int len = strlen(part);
00326
00327 ast_channel_lock(c);
00328 if (len <= strlen(c->name)) {
00329 res = !(strncmp(c->name, part, len)) && (can_pickup(c));
00330 }
00331 ast_channel_unlock(c);
00332
00333 return res ? CMP_MATCH | CMP_STOP : 0;
00334 }
00335
00336
00337 static int pickup_by_part(struct ast_channel *chan, const char *part)
00338 {
00339 struct ast_channel *target;
00340 int res = -1;
00341
00342 if ((target = ast_channel_callback(find_by_part, NULL, (char *) part, 0))) {
00343 ast_channel_lock(target);
00344 res = pickup_do(chan, target);
00345 ast_channel_unlock(target);
00346 target = ast_channel_unref(target);
00347 }
00348
00349 return res;
00350 }
00351
00352
00353 static int pickupchan_exec(struct ast_channel *chan, const char *data)
00354 {
00355 int res = 0;
00356 int partial_pickup = 0;
00357 char *pickup = NULL;
00358 char *parse = ast_strdupa(data);
00359 AST_DECLARE_APP_ARGS(args,
00360 AST_APP_ARG(channel);
00361 AST_APP_ARG(options);
00362 );
00363 AST_STANDARD_APP_ARGS(args, parse);
00364
00365 if (ast_strlen_zero(args.channel)) {
00366 ast_log(LOG_WARNING, "PickupChan requires an argument (channel)!\n");
00367 return -1;
00368 }
00369
00370 if (!ast_strlen_zero(args.options) && strchr(args.options, 'p')) {
00371 partial_pickup = 1;
00372 }
00373
00374
00375 while (!ast_strlen_zero(args.channel) && (pickup = strsep(&args.channel, "&"))) {
00376 if (!strncasecmp(chan->name, pickup, strlen(pickup))) {
00377 ast_log(LOG_NOTICE, "Cannot pickup your own channel %s.\n", pickup);
00378 } else {
00379 if (partial_pickup) {
00380 if (!pickup_by_part(chan, pickup)) {
00381 break;
00382 }
00383 } else if (!pickup_by_channel(chan, pickup)) {
00384 break;
00385 }
00386 ast_log(LOG_NOTICE, "No target channel found for %s.\n", pickup);
00387 }
00388 }
00389
00390 return res;
00391 }
00392
00393 static int unload_module(void)
00394 {
00395 int res;
00396
00397 res = ast_unregister_application(app);
00398 res |= ast_unregister_application(app2);
00399
00400 return res;
00401 }
00402
00403 static int load_module(void)
00404 {
00405 int res;
00406
00407 res = ast_register_application_xml(app, pickup_exec);
00408 res |= ast_register_application_xml(app2, pickupchan_exec);
00409
00410 return res;
00411 }
00412
00413 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Directed Call Pickup Application");