the last round of file version tags
[asterisk/asterisk.git] / apps / app_chanisavail.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Check if Channel is Available
5  * 
6  * Copyright (C) 2003 - 2005, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  * James Golovich <james@gnuinter.net>
10  *
11  * This program is free software, distributed under the terms of
12  * the GNU General Public License
13  *
14  */
15
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <errno.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <sys/ioctl.h>
22
23 #include "asterisk.h"
24
25 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
26
27 #include "asterisk/lock.h"
28 #include "asterisk/file.h"
29 #include "asterisk/logger.h"
30 #include "asterisk/channel.h"
31 #include "asterisk/pbx.h"
32 #include "asterisk/module.h"
33 #include "asterisk/app.h"
34
35 static char *tdesc = "Check if channel is available";
36
37 static char *app = "ChanIsAvail";
38
39 static char *synopsis = "Check if channel is available";
40
41 static char *descrip = 
42 "  ChanIsAvail(Technology/resource[&Technology2/resource2...][|option]): \n"
43 "Checks is any of the requested channels are available.  If none\n"
44 "of the requested channels are available the new priority will be\n"
45 "n+101 (unless such a priority does not exist or on error, in which\n"
46 "case ChanIsAvail will return -1).\n"
47 "If any of the requested channels are available, the next priority will be n+1,\n"
48 "the channel variable ${AVAILCHAN} will be set to the name of the available channel\n"
49 "and the ChanIsAvail app will return 0.\n"
50 "${AVAILORIGCHAN} is the canonical channel name that was used to create the channel.\n"
51 "${AVAILSTATUS} is the status code for the channel.\n"
52 "If the option 's' is specified (state), will consider channel unavailable\n"
53 "when the channel is in use at all, even if it can take another call.\n";
54
55 STANDARD_LOCAL_USER;
56
57 LOCAL_USER_DECL;
58
59 static int chanavail_exec(struct ast_channel *chan, void *data)
60 {
61         int res=-1, inuse=-1, option_state=0;
62         int status;
63         struct localuser *u;
64         char info[512], tmp[512], trychan[512], *peers, *tech, *number, *rest, *cur, *options, *stringp;
65         struct ast_channel *tempchan;
66
67         if (!data) {
68                 ast_log(LOG_WARNING, "ChanIsAvail requires an argument (Zap/1&Zap/2)\n");
69                 return -1;
70         }
71         LOCAL_USER_ADD(u);
72
73         strncpy(info, (char *)data, sizeof(info)-1);
74         stringp = info;
75         strsep(&stringp, "|");
76         options = strsep(&stringp, "|");
77         if (options && *options == 's')
78                 option_state = 1;
79         peers = info;
80         if (peers) {
81                 cur = peers;
82                 do {
83                         /* remember where to start next time */
84                         rest = strchr(cur, '&');
85                         if (rest) {
86                                 *rest = 0;
87                                 rest++;
88                         }
89                         tech = cur;
90                         number = strchr(tech, '/');
91                         if (!number) {
92                                 ast_log(LOG_WARNING, "ChanIsAvail argument takes format ([technology]/[device])\n");
93                                 return -1;
94                         }
95                         *number = '\0';
96                         number++;
97                         
98                         if (option_state) {
99                                 /* If the pbx says in use then don't bother trying further.
100                                    This is to permit testing if someone's on a call, even if the 
101                                    channel can permit more calls (ie callwaiting, sip calls, etc).  */
102                                
103                                 snprintf(trychan, sizeof(trychan), "%s/%s",cur,number);
104                                 status = inuse = ast_device_state(trychan);
105                         }
106                         if ((inuse < 1) && (tempchan = ast_request(tech, chan->nativeformats, number, &status))) {
107                                         pbx_builtin_setvar_helper(chan, "AVAILCHAN", tempchan->name);
108                                         /* Store the originally used channel too */
109                                         snprintf(tmp, sizeof(tmp), "%s/%s", tech, number);
110                                         pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", tmp);
111                                         snprintf(tmp, sizeof(tmp), "%d", status);
112                                         pbx_builtin_setvar_helper(chan, "AVAILSTATUS", tmp);
113                                         ast_hangup(tempchan);
114                                         tempchan = NULL;
115                                         res = 1;
116                                         break;
117                         } else {
118                                 snprintf(tmp, sizeof(tmp), "%d", status);
119                                 pbx_builtin_setvar_helper(chan, "AVAILSTATUS", tmp);
120                         }
121                         cur = rest;
122                 } while (cur);
123         }
124         if (res < 1) {
125                 pbx_builtin_setvar_helper(chan, "AVAILCHAN", "");
126                 pbx_builtin_setvar_helper(chan, "AVAILORIGCHAN", "");
127                 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num))
128                         chan->priority+=100;
129                 else
130                         return -1;
131         }
132
133         LOCAL_USER_REMOVE(u);
134         return 0;
135 }
136
137 int unload_module(void)
138 {
139         STANDARD_HANGUP_LOCALUSERS;
140         return ast_unregister_application(app);
141 }
142
143 int load_module(void)
144 {
145         return ast_register_application(app, chanavail_exec, synopsis, descrip);
146 }
147
148 char *description(void)
149 {
150         return tdesc;
151 }
152
153 int usecount(void)
154 {
155         int res;
156         STANDARD_USECOUNT(res);
157         return res;
158 }
159
160 char *key()
161 {
162         return ASTERISK_GPL_KEY;
163 }