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