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