update MANY more files with proper copyright/license info (thanks Ian!)
[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                                 return -1;
105                         }
106                         *number = '\0';
107                         number++;
108                         
109                         if (option_state) {
110                                 /* If the pbx says in use then don't bother trying further.
111                                    This is to permit testing if someone's on a call, even if the 
112                                    channel can permit more calls (ie callwaiting, sip calls, etc).  */
113                                
114                                 snprintf(trychan, sizeof(trychan), "%s/%s",cur,number);
115                                 status = inuse = ast_device_state(trychan);
116                         }
117                         if ((inuse < 1) && (tempchan = ast_request(tech, chan->nativeformats, number, &status))) {
118                                         pbx_builtin_setvar_helper(chan, "AVAILCHAN", tempchan->name);
119                                         /* Store the originally used channel too */
120                                         snprintf(tmp, sizeof(tmp), "%s/%s", tech, number);
121                                         pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", tmp);
122                                         snprintf(tmp, sizeof(tmp), "%d", status);
123                                         pbx_builtin_setvar_helper(chan, "AVAILSTATUS", tmp);
124                                         ast_hangup(tempchan);
125                                         tempchan = NULL;
126                                         res = 1;
127                                         break;
128                         } else {
129                                 snprintf(tmp, sizeof(tmp), "%d", status);
130                                 pbx_builtin_setvar_helper(chan, "AVAILSTATUS", tmp);
131                         }
132                         cur = rest;
133                 } while (cur);
134         }
135         if (res < 1) {
136                 pbx_builtin_setvar_helper(chan, "AVAILCHAN", "");
137                 pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", "");
138                 if (!ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101))
139                         return -1;
140         }
141
142         LOCAL_USER_REMOVE(u);
143         return 0;
144 }
145
146 int unload_module(void)
147 {
148         STANDARD_HANGUP_LOCALUSERS;
149         return ast_unregister_application(app);
150 }
151
152 int load_module(void)
153 {
154         return ast_register_application(app, chanavail_exec, synopsis, descrip);
155 }
156
157 char *description(void)
158 {
159         return tdesc;
160 }
161
162 int usecount(void)
163 {
164         int res;
165         STANDARD_USECOUNT(res);
166         return res;
167 }
168
169 char *key()
170 {
171         return ASTERISK_GPL_KEY;
172 }