make app_queue 1.2 jump compliant (issue #5580)
[asterisk/asterisk.git] / apps / app_chanisavail.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 * James Golovich <james@gnuinter.net>
8 *
9 * See http://www.asterisk.org for more information about
10 * the Asterisk project. Please do not directly contact
11 * any of the maintainers of this project for assistance;
12 * the project provides a web site, mailing lists and IRC
13 * channels for your use.
14 *
15 * This program is free software, distributed under the terms of
16 * the GNU General Public License Version 2. See the LICENSE file
17 * at the top of the source tree.
18 */
19
20 /*! \file
21 * \brief Check if Channel is Available
22
23  * \ingroup applications
24  */
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <sys/ioctl.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/app.h"
44 #include "asterisk/devicestate.h"
45 #include "asterisk/options.h"
46
47 static char *tdesc = "Check if channel is available";
48
49 static char *app = "ChanIsAvail";
50
51 static char *synopsis = "Check if channel is available";
52
53 static char *descrip = 
54 "  ChanIsAvail(Technology/resource[&Technology2/resource2...][|option]): \n"
55 "Checks if any of the requested channels are available.  \n"
56 "If any of the requested channels are available, the dialplan will continue and:\n"
57 "  ${AVAILCHAN} will be set to the name of the available channel\n"
58 "  ${AVAILORIGCHAN} is the canonical channel name that was used to create the channel\n"
59 "  ${AVAILSTATUS} is the status code for the channel\n"
60 "If the option 's' is specified (state), will consider channel unavailable\n"
61 "when the channel is in use at all, even if it can take another call.\n"
62 "If none of the requested channels are available, then:\n"
63 "  if the option 'j' is specified (jump), the application will jump to n+101\n"
64 "    if it exists, otherwise the call will terminate\n"
65 "  if the option 'j' is not specified the dialplan will continue and\n"
66 "    ${AVAILCHAN} will be empty\n";
67
68 STANDARD_LOCAL_USER;
69
70 LOCAL_USER_DECL;
71
72 static int chanavail_exec(struct ast_channel *chan, void *data)
73 {
74         int res=-1, inuse=-1, option_state=0, priority_jump=0;
75         int status;
76         struct localuser *u;
77         char *info, tmp[512], trychan[512], *peers, *tech, *number, *rest, *cur, *options, *stringp;
78         struct ast_channel *tempchan;
79
80         if (ast_strlen_zero(data)) {
81                 ast_log(LOG_WARNING, "ChanIsAvail requires an argument (Zap/1&Zap/2)\n");
82                 return -1;
83         }
84
85         LOCAL_USER_ADD(u);
86
87         info = ast_strdupa(data); 
88         stringp = info;
89         strsep(&stringp, "|");
90         options = strsep(&stringp, "|");
91         if (options) {
92                 if (strchr(options, 's'))
93                         option_state = 1;
94                 if (strchr(options, 'j'))
95                         priority_jump = 1;
96         }
97         peers = info;
98         if (peers) {
99                 cur = peers;
100                 do {
101                         /* remember where to start next time */
102                         rest = strchr(cur, '&');
103                         if (rest) {
104                                 *rest = 0;
105                                 rest++;
106                         }
107                         tech = cur;
108                         number = strchr(tech, '/');
109                         if (!number) {
110                                 ast_log(LOG_WARNING, "ChanIsAvail argument takes format ([technology]/[device])\n");
111                                 LOCAL_USER_REMOVE(u);
112                                 return -1;
113                         }
114                         *number = '\0';
115                         number++;
116                         
117                         if (option_state) {
118                                 /* If the pbx says in use then don't bother trying further.
119                                    This is to permit testing if someone's on a call, even if the 
120                                    channel can permit more calls (ie callwaiting, sip calls, etc).  */
121                                
122                                 snprintf(trychan, sizeof(trychan), "%s/%s",cur,number);
123                                 status = inuse = ast_device_state(trychan);
124                         }
125                         if ((inuse <= 1) && (tempchan = ast_request(tech, chan->nativeformats, number, &status))) {
126                                         pbx_builtin_setvar_helper(chan, "AVAILCHAN", tempchan->name);
127                                         /* Store the originally used channel too */
128                                         snprintf(tmp, sizeof(tmp), "%s/%s", tech, number);
129                                         pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", tmp);
130                                         snprintf(tmp, sizeof(tmp), "%d", status);
131                                         pbx_builtin_setvar_helper(chan, "AVAILSTATUS", tmp);
132                                         ast_hangup(tempchan);
133                                         tempchan = NULL;
134                                         res = 1;
135                                         break;
136                         } else {
137                                 snprintf(tmp, sizeof(tmp), "%d", status);
138                                 pbx_builtin_setvar_helper(chan, "AVAILSTATUS", tmp);
139                         }
140                         cur = rest;
141                 } while (cur);
142         }
143         if (res < 1) {
144                 pbx_builtin_setvar_helper(chan, "AVAILCHAN", "");
145                 pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", "");
146                 if (priority_jump || option_priority_jumping) {
147                         if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
148                                 LOCAL_USER_REMOVE(u);
149                                 return -1;
150                         }
151                 }
152         }
153
154         LOCAL_USER_REMOVE(u);
155         return 0;
156 }
157
158 int unload_module(void)
159 {
160         int res = 0;
161
162         res = ast_unregister_application(app);
163
164         STANDARD_HANGUP_LOCALUSERS;
165         
166         return res;
167 }
168
169 int load_module(void)
170 {
171         return ast_register_application(app, chanavail_exec, synopsis, descrip);
172 }
173
174 char *description(void)
175 {
176         return tdesc;
177 }
178
179 int usecount(void)
180 {
181         int res;
182         STANDARD_USECOUNT(res);
183         return res;
184 }
185
186 char *key()
187 {
188         return ASTERISK_GPL_KEY;
189 }