add GROUP_COUNT and GROU_MATCH_COUNT functions, deprecate GroupCount and GroupMatchCo...
[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
21 #include "asterisk/file.h"
22 #include "asterisk/logger.h"
23 #include "asterisk/options.h"
24 #include "asterisk/channel.h"
25 #include "asterisk/pbx.h"
26 #include "asterisk/module.h"
27 #include "asterisk/utils.h"
28 #include "asterisk/cli.h"
29 #include "asterisk/app.h"
30
31 STANDARD_LOCAL_USER;
32
33 LOCAL_USER_DECL;
34
35 static int deprecation_warning = 0;
36
37 static char *group_count_function_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) 
38 {
39         int count;
40         struct localuser *u;
41         char group[80] = "";
42         char category[80] = "";
43         char *grp;
44
45         LOCAL_USER_ADD(u);
46
47         ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category));
48
49         if (ast_strlen_zero(group)) {
50                 grp = pbx_builtin_getvar_helper(chan, category);
51                 strncpy(group, grp, sizeof(group) - 1);
52         }
53
54         count = ast_app_group_get_count(group, category);
55         snprintf(buf, len, "%d", count);
56
57         LOCAL_USER_REMOVE(u);
58
59         return buf;
60 }
61
62 static struct ast_custom_function_obj group_count_function_obj = {
63         .name = "GROUP_COUNT",
64         .desc = "Calculates the group count for the specified group, or uses the current channel's group if not specifed (and non-empty).",
65         .syntax = "GROUP_COUNT([groupname][@category])",
66         .read = group_count_function_read,
67         .write = NULL,
68 };
69
70 static char *group_match_count_function_read(struct ast_channel *chan, char *cmd, char *data, char *buf, size_t len) 
71 {
72         int count;
73         struct localuser *u;
74         char group[80] = "";
75         char category[80] = "";
76
77         LOCAL_USER_ADD(u);
78
79         ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category));
80
81         if (!ast_strlen_zero(group)) {
82                 count = ast_app_group_match_get_count(group, category);
83                 snprintf(buf, len, "%d", count);
84         }
85
86         LOCAL_USER_REMOVE(u);
87
88         return buf;
89 }
90
91 static struct ast_custom_function_obj group_match_count_function_obj = {
92         .name = "GROUP_MATCH_COUNT",
93         .desc = "Calculates the group count for all groups that match the specified pattern. Uses standard regular expression matching (see regex(7)).",
94         .syntax = "GROUP_MATCH_COUNT(groupmatch[@category])",
95         .read = group_match_count_function_read,
96         .write = NULL,
97 };
98
99 static int group_count_exec(struct ast_channel *chan, void *data)
100 {
101         int res = 0;
102         int count;
103         struct localuser *u;
104         char group[80] = "";
105         char category[80] = "";
106         char ret[80] = "";
107         char *grp;
108
109         LOCAL_USER_ADD(u);
110
111         if (!deprecation_warning) {
112                 ast_log(LOG_WARNING, "The GetGroupCount and GetGroupMatchCount applications have been deprecated, please use the GROUP_COUNT and GROUP_MATCH_COUNT functions.\n");
113                 deprecation_warning = 1;
114         }
115
116         ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category));
117
118         if (ast_strlen_zero(group)) {
119                 grp = pbx_builtin_getvar_helper(chan, category);
120                 strncpy(group, grp, sizeof(group) - 1);
121         }
122
123         count = ast_app_group_get_count(group, category);
124         snprintf(ret, sizeof(ret), "%d", count);
125         pbx_builtin_setvar_helper(chan, "GROUPCOUNT", ret);
126
127         LOCAL_USER_REMOVE(u);
128
129         return res;
130 }
131
132 static int group_match_count_exec(struct ast_channel *chan, void *data)
133 {
134         int res = 0;
135         int count;
136         struct localuser *u;
137         char group[80] = "";
138         char category[80] = "";
139         char ret[80] = "";
140
141         LOCAL_USER_ADD(u);
142
143         if (!deprecation_warning) {
144                 ast_log(LOG_WARNING, "The GetGroupCount and GetGroupMatchCount applications have been deprecated, please use the GROUP_COUNT and GROUP_MATCH_COUNT functions.\n");
145                 deprecation_warning = 1;
146         }
147
148         ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category));
149
150         if (!ast_strlen_zero(group)) {
151                 count = ast_app_group_match_get_count(group, category);
152                 snprintf(ret, sizeof(ret), "%d", count);
153                 pbx_builtin_setvar_helper(chan, "GROUPCOUNT", ret);
154         }
155
156         LOCAL_USER_REMOVE(u);
157
158         return res;
159 }
160
161 static int group_set_exec(struct ast_channel *chan, void *data)
162 {
163         int res = 0;
164         struct localuser *u;
165
166         LOCAL_USER_ADD(u);
167
168         if (ast_app_group_set_channel(chan, data))
169                 ast_log(LOG_WARNING, "SetGroup requires an argument (group name)\n");
170
171         LOCAL_USER_REMOVE(u);
172         return res;
173 }
174
175 static int group_check_exec(struct ast_channel *chan, void *data)
176 {
177         int res = 0;
178         int max, count;
179         struct localuser *u;
180         char limit[80]="";
181         char category[80]="";
182
183         LOCAL_USER_ADD(u);
184
185         if (!data || ast_strlen_zero(data)) {
186                 ast_log(LOG_WARNING, "CheckGroup requires an argument(max[@category])\n");
187                 return res;
188         }
189
190         ast_app_group_split_group(data, limit, sizeof(limit), category, sizeof(category));
191
192         if ((sscanf(limit, "%d", &max) == 1) && (max > -1)) {
193                 count = ast_app_group_get_count(pbx_builtin_getvar_helper(chan, category), category);
194                 if (count > max) {
195                         if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num))
196                                 chan->priority += 100;
197                         else
198                                 res = -1;
199                 }
200         } else
201                 ast_log(LOG_WARNING, "CheckGroup requires a positive integer argument (max)\n");
202
203         LOCAL_USER_REMOVE(u);
204         return res;
205 }
206
207 static int group_show_channels(int fd, int argc, char *argv[])
208 {
209 #define FORMAT_STRING  "%-25s  %-20s  %-20s\n"
210
211         struct ast_channel *c = NULL;
212         int numchans = 0;
213         struct ast_var_t *current;
214         struct varshead *headp;
215         regex_t regexbuf;
216         int havepattern = 0;
217
218         if (argc < 3 || argc > 4)
219                 return RESULT_SHOWUSAGE;
220         
221         if (argc == 4) {
222                 if (regcomp(&regexbuf, argv[3], REG_EXTENDED | REG_NOSUB))
223                         return RESULT_SHOWUSAGE;
224                 havepattern = 1;
225         }
226
227         c = ast_channel_walk_locked(NULL);
228         ast_cli(fd, FORMAT_STRING, "Channel", "Group", "Category");
229         while(c) {
230                 headp=&c->varshead;
231                 AST_LIST_TRAVERSE(headp,current,entries) {
232                         if (!strncmp(ast_var_name(current), GROUP_CATEGORY_PREFIX "_", strlen(GROUP_CATEGORY_PREFIX) + 1)) {
233                                 if (!havepattern || !regexec(&regexbuf, ast_var_value(current), 0, NULL, 0)) {
234                                         ast_cli(fd, FORMAT_STRING, c->name, ast_var_value(current),
235                                                 (ast_var_name(current) + strlen(GROUP_CATEGORY_PREFIX) + 1));
236                                         numchans++;
237                                 }
238                         } else if (!strcmp(ast_var_name(current), GROUP_CATEGORY_PREFIX)) {
239                                 if (!havepattern || !regexec(&regexbuf, ast_var_value(current), 0, NULL, 0)) {
240                                         ast_cli(fd, FORMAT_STRING, c->name, ast_var_value(current), "(default)");
241                                         numchans++;
242                                 }
243                         }
244                 }
245                 numchans++;
246                 ast_mutex_unlock(&c->lock);
247                 c = ast_channel_walk_locked(c);
248         }
249
250         if (havepattern)
251                 regfree(&regexbuf);
252
253         ast_cli(fd, "%d active channel(s)\n", numchans);
254         return RESULT_SUCCESS;
255 }
256
257 static char *tdesc = "Group Management Routines";
258
259 static char *app_group_count = "GetGroupCount";
260 static char *app_group_set = "SetGroup";
261 static char *app_group_check = "CheckGroup";
262 static char *app_group_match_count = "GetGroupMatchCount";
263
264 static char *group_count_synopsis = "Get the channel count of a group";
265 static char *group_set_synopsis = "Set the channel's group";
266 static char *group_check_synopsis = "Check the channel count of a group against a limit";
267 static char *group_match_count_synopsis = "Get the channel count of all groups that match a pattern";
268
269 static char *group_count_descrip =
270 "Usage: GetGroupCount([groupname][@category])\n"
271 "  Calculates the group count for the specified group, or uses\n"
272 "the current channel's group if not specifed (and non-empty).\n"
273 "Stores result in GROUPCOUNT.  Always returns 0.\n"
274 "This application has been deprecated, please use the function\n"
275 "GroupCount.\n";
276
277 static char *group_set_descrip =
278 "Usage: SetGroup(groupname[@category])\n"
279 "  Sets the channel group to the specified value.  Equivalent to\n"
280 "SetVar(GROUP=group).  Always returns 0.\n";
281
282 static char *group_check_descrip =
283 "Usage: CheckGroup(max[@category])\n"
284 "  Checks that the current number of total channels in the\n"
285 "current channel's group does not exceed 'max'.  If the number\n"
286 "does not exceed 'max', we continue to the next step. If the\n"
287 "number does in fact exceed max, if priority n+101 exists, then\n"
288 "execution continues at that step, otherwise -1 is returned.\n";
289
290 static char *group_match_count_descrip =
291 "Usage: GetGroupMatchCount(groupmatch[@category])\n"
292 "  Calculates the group count for all groups that match the specified\n"
293 "pattern. Uses standard regular expression matching (see regex(7)).\n"
294 "Stores result in GROUPCOUNT.  Always returns 0.\n"
295 "This application has been deprecated, please use the function\n"
296 "GroupMatchCount.\n";
297
298 static char show_channels_usage[] = 
299 "Usage: group show channels [pattern]\n"
300 "       Lists all currently active channels with channel group(s) specified.\n       Optional regular expression pattern is matched to group names for each channel.\n";
301
302 static struct ast_cli_entry  cli_show_channels =
303         { { "group", "show", "channels", NULL }, group_show_channels, "Show active channels with group(s)", show_channels_usage};
304
305 int unload_module(void)
306 {
307         int res;
308         STANDARD_HANGUP_LOCALUSERS;
309         ast_cli_unregister(&cli_show_channels);
310         res = ast_unregister_application(app_group_count);
311         res |= ast_unregister_application(app_group_set);
312         res |= ast_unregister_application(app_group_check);
313         res |= ast_unregister_application(app_group_match_count);
314         res |= ast_custom_function_unregister(&group_count_function_obj);
315         res |= ast_custom_function_unregister(&group_match_count_function_obj);
316         return res;
317 }
318
319 int load_module(void)
320 {
321         int res;
322         res = ast_register_application(app_group_count, group_count_exec, group_count_synopsis, group_count_descrip);
323         res |= ast_register_application(app_group_set, group_set_exec, group_set_synopsis, group_set_descrip);
324         res |= ast_register_application(app_group_check, group_check_exec, group_check_synopsis, group_check_descrip);
325         res |= ast_register_application(app_group_match_count, group_match_count_exec, group_match_count_synopsis, group_match_count_descrip);
326         res |= ast_custom_function_register(&group_count_function_obj);
327         res |= ast_custom_function_register(&group_match_count_function_obj);
328         ast_cli_register(&cli_show_channels);
329         return res;
330 }
331
332 char *description(void)
333 {
334         return tdesc;
335 }
336
337 int usecount(void)
338 {
339         int res;
340         STANDARD_USECOUNT(res);
341         return res;
342 }
343
344 char *key()
345 {
346         return ASTERISK_GPL_KEY;
347 }