make app_queue 1.2 jump compliant (issue #5580)
[asterisk/asterisk.git] / apps / app_transfer.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.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 Transfer a caller
22  * 
23  * Requires transfer support from channel driver
24  *
25  * \ingroup applications
26  */
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <unistd.h>
32
33 #include "asterisk.h"
34
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
36
37 #include "asterisk/lock.h"
38 #include "asterisk/file.h"
39 #include "asterisk/logger.h"
40 #include "asterisk/channel.h"
41 #include "asterisk/pbx.h"
42 #include "asterisk/module.h"
43 #include "asterisk/options.h"
44 #include "asterisk/app.h"
45
46 STANDARD_LOCAL_USER;
47
48 LOCAL_USER_DECL;
49
50 static const char *tdesc = "Transfer";
51
52 static const char *app = "Transfer";
53
54 static const char *synopsis = "Transfer caller to remote extension";
55
56 static const char *descrip = 
57 "  Transfer([Tech/]dest[|options]):  Requests the remote caller be transferred\n"
58 "to a given destination. If TECH (SIP, IAX2, LOCAL etc) is used, only\n"
59 "an incoming call with the same channel technology will be transfered.\n"
60 "Note that for SIP, if you transfer before call is setup, a 302 redirect\n"
61 "SIP message will be returned to the caller.\n"
62 "\nThe result of the application will be reported in the TRANSFERSTATUS\n"
63 "channel variable:\n"
64 "       SUCCESS      Transfer succeeded\n"
65 "       FAILURE      Transfer failed\n"
66 "       UNSUPPORTED  Transfer unsupported by channel driver\n"
67 "The option string many contain the following character:\n"
68 "'j' -- jump to n+101 priority if the channel transfer attempt\n"
69 "       fails\n";
70
71 static int transfer_exec(struct ast_channel *chan, void *data)
72 {
73         int res;
74         int len;
75         struct localuser *u;
76         char *slash;
77         char *tech = NULL;
78         char *dest = NULL;
79         char *status;
80         char *parse;
81         int priority_jump = 0;
82         AST_DECLARE_APP_ARGS(args,
83                 AST_APP_ARG(dest);
84                 AST_APP_ARG(options);
85         );
86
87         LOCAL_USER_ADD(u);
88
89         if (ast_strlen_zero((char *)data)) {
90                 ast_log(LOG_WARNING, "Transfer requires an argument ([Tech/]destination[|options])\n");
91                 LOCAL_USER_REMOVE(u);
92                 pbx_builtin_setvar_helper(chan, "TRANSFERSTATUS", "FAILURE");
93                 return 0;
94         } else {
95                 parse = ast_strdupa(data);
96                 if (!parse) {
97                         ast_log(LOG_ERROR, "Out of memory!\n");
98                         LOCAL_USER_REMOVE(u);
99                         return -1;
100                 }
101         }
102
103         AST_STANDARD_APP_ARGS(args, parse);
104
105         if (args.options) {
106                 if (strchr(args.options, 'j'))
107                         priority_jump = 1;
108         }
109
110         dest = args.dest;
111
112         if ((slash = strchr(dest, '/')) && (len = (slash - dest))) {
113                 tech = dest;
114                 dest = slash + 1;
115                 /* Allow execution only if the Tech/destination agrees with the type of the channel */
116                 if (strncasecmp(chan->type, tech, len)) {
117                         pbx_builtin_setvar_helper(chan, "TRANSFERSTATUS", "FAILURE");
118                         LOCAL_USER_REMOVE(u);
119                         return 0;
120                 }
121         }
122
123         /* Check if the channel supports transfer before we try it */
124         if (!chan->tech->transfer) {
125                 pbx_builtin_setvar_helper(chan, "TRANSFERSTATUS", "UNSUPPORTED");
126                 LOCAL_USER_REMOVE(u);
127                 return 0;
128         }
129
130         res = ast_transfer(chan, dest);
131
132         if (res < 0) {
133                 status = "FAILURE";
134                 if (priority_jump || option_priority_jumping)
135                         ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
136                 res = 0;
137         } else {
138                 status = "SUCCESS";
139                 res = 0;
140         }
141
142         pbx_builtin_setvar_helper(chan, "TRANSFERSTATUS", status);
143
144         LOCAL_USER_REMOVE(u);
145
146         return res;
147 }
148
149 int unload_module(void)
150 {
151         int res;
152
153         res = ast_unregister_application(app);
154
155         STANDARD_HANGUP_LOCALUSERS;
156
157         return res;     
158 }
159
160 int load_module(void)
161 {
162         return ast_register_application(app, transfer_exec, synopsis, descrip);
163 }
164
165 char *description(void)
166 {
167         return (char *) tdesc;
168 }
169
170 int usecount(void)
171 {
172         int res;
173
174         STANDARD_USECOUNT(res);
175
176         return res;
177 }
178
179 char *key()
180 {
181         return ASTERISK_GPL_KEY;
182 }