Don't only accept AST_DEVICE_UNKNOWN when we're trying to determine if the device...
[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 /*
21  *
22  * Check if Channel is Available
23  * 
24  */
25
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <string.h>
30 #include <stdlib.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
46 static char *tdesc = "Check if channel is available";
47
48 static char *app = "ChanIsAvail";
49
50 static char *synopsis = "Check if channel is available";
51
52 static char *descrip = 
53 "  ChanIsAvail(Technology/resource[&Technology2/resource2...][|option]): \n"
54 "Checks is any of the requested channels are available.  If none\n"
55 "of the requested channels are available the new priority will be\n"
56 "n+101 (unless such a priority does not exist or on error, in which\n"
57 "case ChanIsAvail will return -1).\n"
58 "If any of the requested channels are available, the next priority will be n+1,\n"
59 "the channel variable ${AVAILCHAN} will be set to the name of the available channel\n"
60 "and the ChanIsAvail app will return 0.\n"
61 "${AVAILORIGCHAN} is the canonical channel name that was used to create the channel.\n"
62 "${AVAILSTATUS} is the status code for the channel.\n"
63 "If the option 's' is specified (state), will consider channel unavailable\n"
64 "when the channel is in use at all, even if it can take another call.\n";
65
66 STANDARD_LOCAL_USER;
67
68 LOCAL_USER_DECL;
69
70 static int chanavail_exec(struct ast_channel *chan, void *data)
71 {
72         int res=-1, inuse=-1, option_state=0;
73         int status;
74         struct localuser *u;
75         char info[512], tmp[512], trychan[512], *peers, *tech, *number, *rest, *cur, *options, *stringp;
76         struct ast_channel *tempchan;
77
78         if (!data) {
79                 ast_log(LOG_WARNING, "ChanIsAvail requires an argument (Zap/1&Zap/2)\n");
80                 return -1;
81         }
82         LOCAL_USER_ADD(u);
83
84         strncpy(info, (char *)data, sizeof(info)-1);
85         stringp = info;
86         strsep(&stringp, "|");
87         options = strsep(&stringp, "|");
88         if (options && *options == 's')
89                 option_state = 1;
90         peers = info;
91         if (peers) {
92                 cur = peers;
93                 do {
94                         /* remember where to start next time */
95                         rest = strchr(cur, '&');
96                         if (rest) {
97                                 *rest = 0;
98                                 rest++;
99                         }
100                         tech = cur;
101                         number = strchr(tech, '/');
102                         if (!number) {
103                                 ast_log(LOG_WARNING, "ChanIsAvail argument takes format ([technology]/[device])\n");
104                                 LOCAL_USER_REMOVE(u);
105                                 return -1;
106                         }
107                         *number = '\0';
108                         number++;
109                         
110                         if (option_state) {
111                                 /* If the pbx says in use then don't bother trying further.
112                                    This is to permit testing if someone's on a call, even if the 
113                                    channel can permit more calls (ie callwaiting, sip calls, etc).  */
114                                
115                                 snprintf(trychan, sizeof(trychan), "%s/%s",cur,number);
116                                 status = inuse = ast_device_state(trychan);
117                         }
118                         if ((inuse <= 1) && (tempchan = ast_request(tech, chan->nativeformats, number, &status))) {
119                                         pbx_builtin_setvar_helper(chan, "AVAILCHAN", tempchan->name);
120                                         /* Store the originally used channel too */
121                                         snprintf(tmp, sizeof(tmp), "%s/%s", tech, number);
122                                         pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", tmp);
123                                         snprintf(tmp, sizeof(tmp), "%d", status);
124                                         pbx_builtin_setvar_helper(chan, "AVAILSTATUS", tmp);
125                                         ast_hangup(tempchan);
126                                         tempchan = NULL;
127                                         res = 1;
128                                         break;
129                         } else {
130                                 snprintf(tmp, sizeof(tmp), "%d", status);
131                                 pbx_builtin_setvar_helper(chan, "AVAILSTATUS", tmp);
132                         }
133                         cur = rest;
134                 } while (cur);
135         }
136         if (res < 1) {
137                 pbx_builtin_setvar_helper(chan, "AVAILCHAN", "");
138                 pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", "");
139                 if (ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101)) {
140                         LOCAL_USER_REMOVE(u);
141                         return -1;
142                 }
143         }
144
145         LOCAL_USER_REMOVE(u);
146         return 0;
147 }
148
149 int unload_module(void)
150 {
151         STANDARD_HANGUP_LOCALUSERS;
152         return ast_unregister_application(app);
153 }
154
155 int load_module(void)
156 {
157         return ast_register_application(app, chanavail_exec, synopsis, descrip);
158 }
159
160 char *description(void)
161 {
162         return tdesc;
163 }
164
165 int usecount(void)
166 {
167         int res;
168         STANDARD_USECOUNT(res);
169         return res;
170 }
171
172 char *key()
173 {
174         return ASTERISK_GPL_KEY;
175 }