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: 67626 $")
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 static int pickup_do(struct ast_channel *chan, struct ast_channel *target)
00059 {
00060 int res = 0;
00061
00062 if (option_debug)
00063 ast_log(LOG_DEBUG, "Call pickup on '%s' by '%s'\n", target->name, chan->name);
00064
00065 if ((res = ast_answer(chan))) {
00066 ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
00067 return -1;
00068 }
00069
00070 if ((res = ast_queue_control(chan, AST_CONTROL_ANSWER))) {
00071 ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n", chan->name);
00072 return -1;
00073 }
00074
00075 if ((res = ast_channel_masquerade(target, chan))) {
00076 ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);
00077 return -1;
00078 }
00079
00080 return res;
00081 }
00082
00083
00084 static int can_pickup(struct ast_channel *chan)
00085 {
00086 if (!chan->pbx && (chan->_state == AST_STATE_RINGING || chan->_state == AST_STATE_RING))
00087 return 1;
00088 else
00089 return 0;
00090 }
00091
00092
00093 static int pickup_by_exten(struct ast_channel *chan, char *exten, char *context)
00094 {
00095 int res = -1;
00096 struct ast_channel *target = NULL;
00097
00098 while ((target = ast_channel_walk_locked(target))) {
00099 if ((!strcasecmp(target->macroexten, exten) || !strcasecmp(target->exten, exten)) &&
00100 !strcasecmp(target->dialcontext, context) &&
00101 can_pickup(target)) {
00102 res = pickup_do(chan, target);
00103 ast_channel_unlock(target);
00104 break;
00105 }
00106 ast_channel_unlock(target);
00107 }
00108
00109 return res;
00110 }
00111
00112
00113 static int pickup_by_mark(struct ast_channel *chan, char *mark)
00114 {
00115 int res = -1;
00116 const char *tmp = NULL;
00117 struct ast_channel *target = NULL;
00118
00119 while ((target = ast_channel_walk_locked(target))) {
00120 if ((tmp = pbx_builtin_getvar_helper(target, PICKUPMARK)) &&
00121 !strcasecmp(tmp, mark) &&
00122 can_pickup(target)) {
00123 res = pickup_do(chan, target);
00124 ast_channel_unlock(target);
00125 break;
00126 }
00127 ast_channel_unlock(target);
00128 }
00129
00130 return res;
00131 }
00132
00133
00134 static int pickup_exec(struct ast_channel *chan, void *data)
00135 {
00136 int res = 0;
00137 struct ast_module_user *u = NULL;
00138 char *tmp = ast_strdupa(data);
00139 char *exten = NULL, *context = NULL;
00140
00141 if (ast_strlen_zero(data)) {
00142 ast_log(LOG_WARNING, "Pickup requires an argument (extension)!\n");
00143 return -1;
00144 }
00145
00146 u = ast_module_user_add(chan);
00147
00148
00149 while (!ast_strlen_zero(tmp) && (exten = strsep(&tmp, "&"))) {
00150 if ((context = strchr(exten, '@')))
00151 *context++ = '\0';
00152 if (context && !strcasecmp(context, PICKUPMARK)) {
00153 if (!pickup_by_mark(chan, exten))
00154 break;
00155 } else {
00156 if (!pickup_by_exten(chan, exten, context ? context : chan->context))
00157 break;
00158 }
00159 ast_log(LOG_NOTICE, "No target channel found for %s.\n", exten);
00160 }
00161
00162 ast_module_user_remove(u);
00163
00164 return res;
00165 }
00166
00167 static int unload_module(void)
00168 {
00169 int res;
00170
00171 res = ast_unregister_application(app);
00172
00173 return res;
00174 }
00175
00176 static int load_module(void)
00177 {
00178 return ast_register_application(app, pickup_exec, synopsis, descrip);
00179 }
00180
00181 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Directed Call Pickup Application");