84f350746372473acd0fe9160c637cda7fca145f
[asterisk/asterisk.git] / apps / app_directed_pickup.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2005, Joshua Colp
5  *
6  * Joshua Colp <jcolp@asterlink.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*! \file
20  *
21  * \brief Directed Call Pickup Support
22  *
23  */
24
25 #include <stdlib.h>
26 #include <unistd.h>
27 #include <string.h>
28
29 #include "asterisk.h"
30
31 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
32
33 #include "asterisk/file.h"
34 #include "asterisk/logger.h"
35 #include "asterisk/channel.h"
36 #include "asterisk/pbx.h"
37 #include "asterisk/module.h"
38 #include "asterisk/lock.h"
39 #include "asterisk/app.h"
40
41 static const char *tdesc = "Directed Call Pickup Application";
42 static const char *app = "Pickup";
43 static const char *synopsis = "Directed Call Pickup application.";
44 static const char *descrip =
45 " Pickup(extension@context):\n"
46 "Steals any calls to a specified extension that are in a ringing state and bridges them to the current channel. Context is an optional argument.\n";
47
48 STANDARD_LOCAL_USER;
49
50 LOCAL_USER_DECL;
51
52 static int pickup_exec(struct ast_channel *chan, void *data)
53 {
54         int res = 0;
55         struct localuser *u = NULL;
56         struct ast_channel *origin = NULL, *target = NULL;
57         char *tmp = NULL, *exten = NULL, *context = NULL;
58         char workspace[256] = "";
59
60         if (ast_strlen_zero(data)) {
61                 ast_log(LOG_WARNING, "Pickup requires an argument (extension) !\n");
62                 return -1;      
63         }
64
65         LOCAL_USER_ADD(u);
66         
67         /* Get the extension and context if present */
68         exten = data;
69         context = strchr(data, '@');
70         if (context) {
71                 *context = '\0';
72                 context++;
73         }
74
75         /* Find a channel to pickup */
76         origin = ast_get_channel_by_exten_locked(exten, context);
77         if (origin) {
78                 ast_cdr_getvar(origin->cdr, "dstchannel", &tmp, workspace,
79                                sizeof(workspace), 0);
80                 if (tmp) {
81                         /* We have a possible channel... now we need to find it! */
82                         target = ast_get_channel_by_name_locked(tmp);
83                 } else {
84                         ast_log(LOG_DEBUG, "No target channel found.\n");
85                         res = -1;
86                 }
87                 ast_mutex_unlock(&origin->lock);
88         } else {
89                 ast_log(LOG_DEBUG, "No originating channel found.\n");
90         }
91         
92         if (res)
93                 goto out;
94
95         if (target && (!target->pbx) && ((target->_state == AST_STATE_RINGING) || (target->_state == AST_STATE_RING))) {
96                 ast_log(LOG_DEBUG, "Call pickup on chan '%s' by '%s'\n", target->name,
97                         chan->name);
98                 res = ast_answer(chan);
99                 if (res) {
100                         ast_log(LOG_WARNING, "Unable to answer '%s'\n", chan->name);
101                         res = -1;
102                         goto out;
103                 }
104                 res = ast_queue_control(chan, AST_CONTROL_ANSWER);
105                 if (res) {
106                         ast_log(LOG_WARNING, "Unable to queue answer on '%s'\n",
107                                 chan->name);
108                         res = -1;
109                         goto out;
110                 }
111                 res = ast_channel_masquerade(target, chan);
112                 if (res) {
113                         ast_log(LOG_WARNING, "Unable to masquerade '%s' into '%s'\n", chan->name, target->name);
114                         res = -1;
115                         goto out;
116                 }
117         } else {
118                 ast_log(LOG_DEBUG, "No call pickup possible...\n");
119                 res = -1;
120         }
121         /* Done */
122  out:
123         if (target) 
124                 ast_mutex_unlock(&target->lock);
125         
126         LOCAL_USER_REMOVE(u);
127
128         return res;
129 }
130
131 int unload_module(void)
132 {
133         int res;
134
135         res = ast_unregister_application(app);
136         
137         STANDARD_HANGUP_LOCALUSERS;
138
139         return res;
140 }
141
142 int load_module(void)
143 {
144         return ast_register_application(app, pickup_exec, synopsis, descrip);
145 }
146
147 char *description(void)
148 {
149         return (char *) tdesc;
150 }
151
152 int usecount(void)
153 {
154         int res;
155
156         STANDARD_USECOUNT(res);
157
158         return res;
159 }
160
161 char *key()
162 {
163         return ASTERISK_GPL_KEY;
164 }