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: 318734 $")
00031
00032 #include <stdlib.h>
00033 #include <stdio.h>
00034 #include <string.h>
00035 #include <unistd.h>
00036
00037 #include "asterisk/file.h"
00038 #include "asterisk/logger.h"
00039 #include "asterisk/channel.h"
00040 #include "asterisk/pbx.h"
00041 #include "asterisk/module.h"
00042 #include "asterisk/lock.h"
00043 #include "asterisk/app.h"
00044 #include "asterisk/options.h"
00045
00046 #define PICKUPMARK "PICKUPMARK"
00047
00048 static const char *app = "Pickup";
00049 static const char *synopsis = "Directed Call Pickup";
00050 static const char *descrip =
00051 " Pickup(extension[@context][&extension2@context...]): This application can pickup any ringing channel\n"
00052 "that is calling the specified extension. If no context is specified, the current\n"
00053 "context will be used. If you use the special string \"PICKUPMARK\" for the context parameter, for example\n"
00054 "10@PICKUPMARK, this application tries to find a channel which has defined a channel variable with the same content\n"
00055 "as \"extension\".";
00056
00057
00058
00059
00060
00061
00062 static int pickup_do(struct ast_channel *chan, struct ast_channel *target)
00063 {
00064 if (option_debug)
00065 ast_log(LOG_DEBUG, "Call pickup on '%s' by '%s'\n", target->name, chan->name);
00066
00067 if (ast_answer(chan)) {
00068 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
00069 return -1;
00070 }
00071
00072 if (ast_queue_control(chan, AST_CONTROL_ANSWER)) {
00073 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
00074 return -1;
00075 }
00076
00077 if (ast_channel_masquerade(target, chan)) {
00078 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);
00079 return -1;
00080 }
00081
00082 return 0;
00083 }
00084
00085
00086 static int can_pickup(struct ast_channel *chan)
00087 {
00088 if (!chan->pbx && !chan->masq &&
00089 !ast_test_flag(chan, AST_FLAG_ZOMBIE) &&
00090 (chan->_state == AST_STATE_RINGING ||
00091 chan->_state == AST_STATE_RING ||
00092 chan->_state == AST_STATE_DOWN)) {
00093 return 1;
00094 }
00095 return 0;
00096 }
00097
00098
00099 static int pickup_by_exten(struct ast_channel *chan, char *exten, char *context)
00100 {
00101 int res = -1;
00102 struct ast_channel *target = NULL;
00103
00104 while ((target = ast_channel_walk_locked(target))) {
00105 if ((!strcasecmp(target->macroexten, exten) || !strcasecmp(target->exten, exten)) &&
00106 !strcasecmp(target->dialcontext, context) &&
00107 (chan != target) && can_pickup(target)) {
00108 res = pickup_do(chan, target);
00109 ast_channel_unlock(target);
00110 break;
00111 }
00112 ast_channel_unlock(target);
00113 }
00114
00115 return res;
00116 }
00117
00118
00119 static int pickup_by_mark(struct ast_channel *chan, char *mark)
00120 {
00121 int res = -1;
00122 const char *tmp = NULL;
00123 struct ast_channel *target = NULL;
00124
00125 while ((target = ast_channel_walk_locked(target))) {
00126 if ((tmp = pbx_builtin_getvar_helper(target, PICKUPMARK)) &&
00127 !strcasecmp(tmp, mark) &&
00128 can_pickup(target)) {
00129 res = pickup_do(chan, target);
00130 ast_channel_unlock(target);
00131 break;
00132 }
00133 ast_channel_unlock(target);
00134 }
00135
00136 return res;
00137 }
00138
00139
00140 static int pickup_exec(struct ast_channel *chan, void *data)
00141 {
00142 int res = 0;
00143 struct ast_module_user *u = NULL;
00144 char *tmp = ast_strdupa(data);
00145 char *exten = NULL, *context = NULL;
00146
00147 if (ast_strlen_zero(data)) {
00148 ast_log(LOG_WARNING, "Pickup requires an argument (extension)!\n");
00149 return -1;
00150 }
00151
00152 u = ast_module_user_add(chan);
00153
00154
00155 while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
00156 if ((context = strchr(exten, '@')))
00157 *context++ = '\0';
00158 if (context && !strcasecmp(context, PICKUPMARK)) {
00159 if (!pickup_by_mark(chan, exten))
00160 break;
00161 } else {
00162 if (!pickup_by_exten(chan, exten, context ? context : chan->context))
00163 break;
00164 }
00165 ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten);
00166 }
00167
00168 ast_module_user_remove(u);
00169
00170 return res;
00171 }
00172
00173 static int unload_module(void)
00174 {
00175 int res;
00176
00177 res = ast_unregister_application(app);
00178
00179 return res;
00180 }
00181
00182 static int load_module(void)
00183 {
00184 return ast_register_application(app, pickup_exec, synopsis, descrip);
00185 }
00186
00187 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Directed Call Pickup Application");