don't use '%i' at all, since we have no current use cases that need non base-10 parsi...
[asterisk/asterisk.git] / apps / app_groupcount.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Group Manipulation Applications
5  *
6  * Copyright (c) 2004 - 2005, Digium Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <string.h>
18 #include <sys/types.h>
19 #include <regex.h>
20 #include "asterisk/file.h"
21 #include "asterisk/logger.h"
22 #include "asterisk/options.h"
23 #include "asterisk/channel.h"
24 #include "asterisk/pbx.h"
25 #include "asterisk/module.h"
26 #include "asterisk/utils.h"
27 #include "asterisk/cli.h"
28 #include "asterisk/app.h"
29
30 STANDARD_LOCAL_USER;
31
32 LOCAL_USER_DECL;
33
34 static int group_count_exec(struct ast_channel *chan, void *data)
35 {
36         int res = 0;
37         int count;
38         struct localuser *u;
39         char group[80] = "";
40         char category[80] = "";
41         char ret[80] = "";
42         char *grp;
43
44         LOCAL_USER_ADD(u);
45
46         ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category));
47
48         if (ast_strlen_zero(group)) {
49                 grp = pbx_builtin_getvar_helper(chan, category);
50                 strncpy(group, grp, sizeof(group) - 1);
51         }
52
53         count = ast_app_group_get_count(group, category);
54         snprintf(ret, sizeof(ret), "%d", count);
55         pbx_builtin_setvar_helper(chan, "GROUPCOUNT", ret);
56
57         LOCAL_USER_REMOVE(u);
58
59         return res;
60 }
61
62 static int group_match_count_exec(struct ast_channel *chan, void *data)
63 {
64         int res = 0;
65         int count;
66         struct localuser *u;
67         char group[80] = "";
68         char category[80] = "";
69         char ret[80] = "";
70
71         LOCAL_USER_ADD(u);
72
73         ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category));
74
75         if (!ast_strlen_zero(group)) {
76                 count = ast_app_group_match_get_count(group, category);
77                 snprintf(ret, sizeof(ret), "%d", count);
78                 pbx_builtin_setvar_helper(chan, "GROUPCOUNT", ret);
79         }
80
81         LOCAL_USER_REMOVE(u);
82
83         return res;
84 }
85
86 static int group_set_exec(struct ast_channel *chan, void *data)
87 {
88         int res = 0;
89         struct localuser *u;
90
91         LOCAL_USER_ADD(u);
92
93         if (ast_app_group_set_channel(chan, data))
94                 ast_log(LOG_WARNING, "SetGroup requires an argument (group name)\n");
95
96         LOCAL_USER_REMOVE(u);
97         return res;
98 }
99
100 static int group_check_exec(struct ast_channel *chan, void *data)
101 {
102         int res = 0;
103         int max, count;
104         struct localuser *u;
105         char limit[80]="";
106         char category[80]="";
107
108         LOCAL_USER_ADD(u);
109
110         if (!data || ast_strlen_zero(data)) {
111                 ast_log(LOG_WARNING, "CheckGroup requires an argument(max[@category])\n");
112                 return res;
113         }
114
115         ast_app_group_split_group(data, limit, sizeof(limit), category, sizeof(category));
116
117         if ((sscanf(limit, "%d", &max) == 1) && (max > -1)) {
118                 count = ast_app_group_get_count(pbx_builtin_getvar_helper(chan, category), category);
119                 if (count > max) {
120                         if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num))
121                                 chan->priority += 100;
122                         else
123                                 res = -1;
124                 }
125         } else
126                 ast_log(LOG_WARNING, "CheckGroup requires a positive integer argument (max)\n");
127
128         LOCAL_USER_REMOVE(u);
129         return res;
130 }
131
132 static int group_show_channels(int fd, int argc, char *argv[])
133 {
134 #define FORMAT_STRING  "%-25s  %-20s  %-20s\n"
135
136         struct ast_channel *c = NULL;
137         int numchans = 0;
138         struct ast_var_t *current;
139         struct varshead *headp;
140         regex_t regexbuf;
141         int havepattern = 0;
142
143         if (argc < 3 || argc > 4)
144                 return RESULT_SHOWUSAGE;
145         
146         if (argc == 4) {
147                 if (regcomp(&regexbuf, argv[3], REG_EXTENDED | REG_NOSUB))
148                         return RESULT_SHOWUSAGE;
149                 havepattern = 1;
150         }
151
152         c = ast_channel_walk_locked(NULL);
153         ast_cli(fd, FORMAT_STRING, "Channel", "Group", "Category");
154         while(c) {
155                 headp=&c->varshead;
156                 AST_LIST_TRAVERSE(headp,current,entries) {
157                         if (!strncmp(ast_var_name(current), GROUP_CATEGORY_PREFIX "_", strlen(GROUP_CATEGORY_PREFIX) + 1)) {
158                                 if (!havepattern || !regexec(&regexbuf, ast_var_value(current), 0, NULL, 0)) {
159                                         ast_cli(fd, FORMAT_STRING, c->name, ast_var_value(current),
160                                                 (ast_var_name(current) + strlen(GROUP_CATEGORY_PREFIX) + 1));
161                                         numchans++;
162                                 }
163                         } else if (!strcmp(ast_var_name(current), GROUP_CATEGORY_PREFIX)) {
164                                 if (!havepattern || !regexec(&regexbuf, ast_var_value(current), 0, NULL, 0)) {
165                                         ast_cli(fd, FORMAT_STRING, c->name, ast_var_value(current), "(default)");
166                                         numchans++;
167                                 }
168                         }
169                 }
170                 numchans++;
171                 ast_mutex_unlock(&c->lock);
172                 c = ast_channel_walk_locked(c);
173         }
174
175         if (havepattern)
176                 regfree(&regexbuf);
177
178         ast_cli(fd, "%d active channel(s)\n", numchans);
179         return RESULT_SUCCESS;
180 }
181
182 static char *tdesc = "Group Management Routines";
183
184 static char *app_group_count = "GetGroupCount";
185 static char *app_group_set = "SetGroup";
186 static char *app_group_check = "CheckGroup";
187 static char *app_group_match_count = "GetGroupMatchCount";
188
189 static char *group_count_synopsis = "Get the channel count of a group";
190 static char *group_set_synopsis = "Set the channel's group";
191 static char *group_check_synopsis = "Check the channel count of a group against a limit";
192 static char *group_match_count_synopsis = "Get the channel count of all groups that match a pattern";
193
194 static char *group_count_descrip =
195 "Usage: GetGroupCount([groupname][@category])\n"
196 "  Calculates the group count for the specified group, or uses\n"
197 "the current channel's group if not specifed (and non-empty).\n"
198 "Stores result in GROUPCOUNT.  Always returns 0.\n";
199
200 static char *group_set_descrip =
201 "Usage: SetGroup(groupname[@category])\n"
202 "  Sets the channel group to the specified value.  Equivalent to\n"
203 "SetVar(GROUP=group).  Always returns 0.\n";
204
205 static char *group_check_descrip =
206 "Usage: CheckGroup(max[@category])\n"
207 "  Checks that the current number of total channels in the\n"
208 "current channel's group does not exceed 'max'.  If the number\n"
209 "does not exceed 'max', we continue to the next step. If the\n"
210 "number does in fact exceed max, if priority n+101 exists, then\n"
211 "execution continues at that step, otherwise -1 is returned.\n";
212
213 static char *group_match_count_descrip =
214 "Usage: GetGroupMatchCount(groupmatch[@category])\n"
215 "  Calculates the group count for all groups that match the specified\n"
216 "pattern. Uses standard regular expression matching (see regex(7)).\n"
217 "Stores result in GROUPCOUNT.  Always returns 0.\n";
218
219 static char show_channels_usage[] = 
220 "Usage: group show channels [pattern]\n"
221 "       Lists all currently active channels with channel group(s) specified.\n       Optional regular expression pattern is matched to group names for each channel.\n";
222
223 static struct ast_cli_entry  cli_show_channels =
224         { { "group", "show", "channels", NULL }, group_show_channels, "Show active channels with group(s)", show_channels_usage};
225
226 int unload_module(void)
227 {
228         int res;
229         STANDARD_HANGUP_LOCALUSERS;
230         ast_cli_unregister(&cli_show_channels);
231         res = ast_unregister_application(app_group_count);
232         res |= ast_unregister_application(app_group_set);
233         res |= ast_unregister_application(app_group_check);
234         res |= ast_unregister_application(app_group_match_count);
235         return res;
236 }
237
238 int load_module(void)
239 {
240         int res;
241         res = ast_register_application(app_group_count, group_count_exec, group_count_synopsis, group_count_descrip);
242         res |= ast_register_application(app_group_set, group_set_exec, group_set_synopsis, group_set_descrip);
243         res |= ast_register_application(app_group_check, group_check_exec, group_check_synopsis, group_check_descrip);
244         res |= ast_register_application(app_group_match_count, group_match_count_exec, group_match_count_synopsis, group_match_count_descrip);
245         ast_cli_register(&cli_show_channels);
246         return res;
247 }
248
249 char *description(void)
250 {
251         return tdesc;
252 }
253
254 int usecount(void)
255 {
256         int res;
257         STANDARD_USECOUNT(res);
258         return res;
259 }
260
261 char *key()
262 {
263         return ASTERISK_GPL_KEY;
264 }