2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2005, Joshua Colp
6 * Joshua Colp <jcolp@digium.com>
8 * Portions merged from app_pickupchan, which was
9 * Copyright (C) 2008, Gary Cook
11 * See http://www.asterisk.org for more information about
12 * the Asterisk project. Please do not directly contact
13 * any of the maintainers of this project for assistance;
14 * the project provides a web site, mailing lists and IRC
15 * channels for your use.
17 * This program is free software, distributed under the terms of
18 * the GNU General Public License Version 2. See the LICENSE file
19 * at the top of the source tree.
24 * \brief Directed Call Pickup Support
26 * \author Joshua Colp <jcolp@digium.com>
29 * \ingroup applications
34 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
36 #include "asterisk/file.h"
37 #include "asterisk/channel.h"
38 #include "asterisk/pbx.h"
39 #include "asterisk/module.h"
40 #include "asterisk/lock.h"
41 #include "asterisk/app.h"
42 #include "asterisk/features.h"
44 #define PICKUPMARK "PICKUPMARK"
46 static const char *app
= "Pickup";
47 static const char *synopsis
= "Directed Call Pickup";
48 static const char *descrip
=
49 " Pickup([extension[@context][&extension2@[context]...]]): This application can\n"
50 "pickup any ringing channel that is calling the specified extension. If no\n"
51 "context is specified, the current context will be used. If you use the special\n"
52 "string \"PICKUPMARK\" for the context parameter, for example 10@PICKUPMARK,\n"
53 "this application tries to find a channel which has defined a ${PICKUPMARK}\n"
54 "channel variable with the same value as \"extension\" (in this example, \"10\").\n"
55 "When no parameter is specified, the application will pickup a channel matching\n"
56 "the pickup group of the active channel.";
58 static const char *app2
= "PickupChan";
59 static const char *synopsis2
= "Pickup a ringing channel";
60 static const char *descrip2
=
61 " PickupChan(channel[&channel...]): This application can pickup any ringing channel\n";
63 /*! \todo This application should return a result code, like PICKUPRESULT */
65 /* Perform actual pickup between two channels */
66 static int pickup_do(struct ast_channel
*chan
, struct ast_channel
*target
)
70 ast_debug(1, "Call pickup on '%s' by '%s'\n", target
->name
, chan
->name
);
72 if ((res
= ast_answer(chan
))) {
73 ast_log(LOG_WARNING
, "Unable to answer '%s'\n", chan
->name
);
77 if ((res
= ast_queue_control(chan
, AST_CONTROL_ANSWER
))) {
78 ast_log(LOG_WARNING
, "Unable to queue answer on '%s'\n", chan
->name
);
82 if ((res
= ast_channel_masquerade(target
, chan
))) {
83 ast_log(LOG_WARNING
, "Unable to masquerade '%s' into '%s'\n", chan
->name
, target
->name
);
90 /* Helper function that determines whether a channel is capable of being picked up */
91 static int can_pickup(struct ast_channel
*chan
)
93 if (!chan
->pbx
&& (chan
->_state
== AST_STATE_RINGING
|| chan
->_state
== AST_STATE_RING
))
99 /*! \brief Helper Function to walk through ALL channels checking NAME and STATE */
100 static struct ast_channel
*my_ast_get_channel_by_name_locked(char *channame
)
102 struct ast_channel
*chan
;
103 char *chkchan
= alloca(strlen(channame
) + 2);
105 /* need to append a '-' for the comparison so we check full channel name,
106 * i.e SIP/hgc- , use a temporary variable so original stays the same for
109 strcpy(chkchan
, channame
);
110 strcat(chkchan
, "-");
112 for (chan
= ast_walk_channel_by_name_prefix_locked(NULL
, channame
, strlen(channame
));
114 chan
= ast_walk_channel_by_name_prefix_locked(chan
, channame
, strlen(channame
))) {
115 if (!strncasecmp(chan
->name
, chkchan
, strlen(chkchan
)) && can_pickup(chan
))
117 ast_channel_unlock(chan
);
122 /*! \brief Attempt to pick up specified channel named , does not use context */
123 static int pickup_by_channel(struct ast_channel
*chan
, char *pickup
)
126 struct ast_channel
*target
;
128 if (!(target
= my_ast_get_channel_by_name_locked(pickup
)))
131 /* Just check that we are not picking up the SAME as target */
132 if (chan
->name
!= target
->name
&& chan
!= target
) {
133 res
= pickup_do(chan
, target
);
134 ast_channel_unlock(target
);
140 /* Attempt to pick up specified extension with context */
141 static int pickup_by_exten(struct ast_channel
*chan
, const char *exten
, const char *context
)
144 struct ast_channel
*target
= NULL
;
146 while ((target
= ast_channel_walk_locked(target
))) {
147 if ((!strcasecmp(target
->macroexten
, exten
) || !strcasecmp(target
->exten
, exten
)) &&
148 !strcasecmp(target
->dialcontext
, context
) &&
149 can_pickup(target
)) {
150 res
= pickup_do(chan
, target
);
151 ast_channel_unlock(target
);
154 ast_channel_unlock(target
);
160 /* Attempt to pick up specified mark */
161 static int pickup_by_mark(struct ast_channel
*chan
, const char *mark
)
164 const char *tmp
= NULL
;
165 struct ast_channel
*target
= NULL
;
167 while ((target
= ast_channel_walk_locked(target
))) {
168 if ((tmp
= pbx_builtin_getvar_helper(target
, PICKUPMARK
)) &&
169 !strcasecmp(tmp
, mark
) &&
170 can_pickup(target
)) {
171 res
= pickup_do(chan
, target
);
172 ast_channel_unlock(target
);
175 ast_channel_unlock(target
);
181 /* application entry point for Pickup() */
182 static int pickup_exec(struct ast_channel
*chan
, void *data
)
185 char *tmp
= ast_strdupa(data
);
186 char *exten
= NULL
, *context
= NULL
;
188 if (ast_strlen_zero(data
)) {
189 res
= ast_pickup_call(chan
);
193 /* Parse extension (and context if there) */
194 while (!ast_strlen_zero(tmp
) && (exten
= strsep(&tmp
, "&"))) {
195 if ((context
= strchr(exten
, '@')))
197 if (!ast_strlen_zero(context
) && !strcasecmp(context
, PICKUPMARK
)) {
198 if (!pickup_by_mark(chan
, exten
))
201 if (!pickup_by_exten(chan
, exten
, !ast_strlen_zero(context
) ? context
: chan
->context
))
204 ast_log(LOG_NOTICE
, "No target channel found for %s.\n", exten
);
210 /* application entry point for PickupChan() */
211 static int pickupchan_exec(struct ast_channel
*chan
, void *data
)
214 char *tmp
= ast_strdupa(data
);
217 if (ast_strlen_zero(data
)) {
218 ast_log(LOG_WARNING
, "PickupChan requires an argument (channel)!\n");
223 while (!ast_strlen_zero(tmp
) && (pickup
= strsep(&tmp
, "&"))) {
224 if (!strncasecmp(chan
->name
, pickup
, strlen(pickup
))) {
225 ast_log(LOG_NOTICE
, "Cannot pickup your own channel %s.\n", pickup
);
227 if (!pickup_by_channel(chan
, pickup
)) {
230 ast_log(LOG_NOTICE
, "No target channel found for %s.\n", pickup
);
237 static int unload_module(void)
241 res
= ast_unregister_application(app
);
242 res
|= ast_unregister_application(app2
);
247 static int load_module(void)
251 res
= ast_register_application(app
, pickup_exec
, synopsis
, descrip
);
252 res
|= ast_register_application(app2
, pickupchan_exec
, synopsis2
, descrip2
);
257 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY
, "Directed Call Pickup Application");