Fix null pointer dereference in app_groupcount.c (bug 1588)
[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 Digium
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 <asterisk/file.h>
19 #include <asterisk/logger.h>
20 #include <asterisk/options.h>
21 #include <asterisk/channel.h>
22 #include <asterisk/pbx.h>
23 #include <asterisk/module.h>
24
25 static char *tdesc = "Group Management Routines";
26
27 static char *app_group_count = "GetGroupCount";
28 static char *app_group_set = "SetGroup";
29 static char *app_group_check = "CheckGroup";
30
31 static char *group_count_synopsis = "GetGroupCount([groupname])";
32 static char *group_set_synopsis = "SetGroup([groupname])";
33 static char *group_check_synopsis = "CheckGroup(max)";
34
35 static char *group_count_descrip =
36 "GetGroupCount([group])\n"
37 "  Calculates the group count for the specified group, or uses\n"
38 "the current channel's group if not specifed (and non-empty).\n"
39 "Stores result in GROUPCOUNT.  Always returns 0.\n";
40
41 static char *group_set_descrip =
42 "SetGroup(group)\n"
43 "  Sets the channel group to the specified value.  Equivalent to\n"
44 "SetVar(GROUP=group).  Always returns 0.\n";
45
46 static char *group_check_descrip =
47 "CheckGroup(max)\n"
48 "  Checks that the current number of total channels in the\n"
49 "current channel's group does not exceed 'max'.  If the number\n"
50 "does not exceed 'max', we continue to the next step. If the\n"
51 "number does in fact exceed max, if priority n+101 exists, then\n"
52 "execution continues at that step, otherwise -1 is returned.\n";
53
54 STANDARD_LOCAL_USER;
55
56 LOCAL_USER_DECL;
57
58 static int group_get_count(char *group)
59 {
60         /* XXX ast_channel_walk needs to be modified to
61                prevent a race in which after we return the channel
62                    is no longer valid (or ast_channel_free can be modified
63                    just as well) XXX */
64         struct ast_channel *chan;
65         int count = 0;
66         char *test;
67         if (group && strlen(group)) {
68                 chan = ast_channel_walk(NULL);
69                 while(chan) {
70                         test = pbx_builtin_getvar_helper(chan, "GROUP");
71                         if (test && !strcasecmp(test, group))
72                                 count++;
73                         chan = ast_channel_walk(chan);
74                 }
75         }
76         return count;
77 }
78
79 static int group_count_exec(struct ast_channel *chan, void *data)
80 {
81         int res=0;
82         int count;
83         struct localuser *u;
84         char *group=NULL;
85         char ret[80];
86
87         LOCAL_USER_ADD(u);
88
89         /* Check and parse arguments */
90         if (data && strlen(data)) {
91                 group = (char *)data;
92         } else {
93                 group = pbx_builtin_getvar_helper(chan, "GROUP");
94         }
95         count = group_get_count(group);
96         snprintf(ret, sizeof(ret), "%d", count);
97         pbx_builtin_setvar_helper(chan, "GROUPCOUNT", ret);
98         LOCAL_USER_REMOVE(u);
99         return res;
100 }
101
102 static int group_set_exec(struct ast_channel *chan, void *data)
103 {
104         int res=0;
105         struct localuser *u;
106
107         LOCAL_USER_ADD(u);
108         /* Check and parse arguments */
109         if (data && strlen(data)) {
110                 pbx_builtin_setvar_helper(chan, "GROUP", (char *)data);
111         } else
112                 ast_log(LOG_WARNING, "GroupSet requires an argument (group name)\n");
113
114         LOCAL_USER_REMOVE(u);
115         return res;
116 }
117
118 static int group_check_exec(struct ast_channel *chan, void *data)
119 {
120         int res=0;
121         int max, count;
122         struct localuser *u;
123
124         LOCAL_USER_ADD(u);
125
126         if (data && (sscanf((char *)data, "%i", &max) == 1) && (max > -1)) {    
127                 count = group_get_count(pbx_builtin_getvar_helper(chan, "GROUP"));
128                 if (count > max) {
129                         if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
130                                 chan->priority += 100;
131                         else
132                                 res = -1;
133                 }
134         } else
135                 ast_log(LOG_WARNING, "GroupCheck requires a positive integer argument (max)\n");
136         LOCAL_USER_REMOVE(u);
137         return res;
138 }
139
140 int unload_module(void)
141 {
142         int res;
143         STANDARD_HANGUP_LOCALUSERS;
144         res = ast_unregister_application(app_group_count);
145         res |= ast_unregister_application(app_group_set);
146         res |= ast_unregister_application(app_group_check);
147         return res;
148 }
149
150 int load_module(void)
151 {
152         int res;
153         res = ast_register_application(app_group_count, group_count_exec, group_count_synopsis, group_count_descrip);
154         res |= ast_register_application(app_group_set, group_set_exec, group_set_synopsis, group_set_descrip);
155         res |= ast_register_application(app_group_check, group_check_exec, group_check_synopsis, group_check_descrip);
156         return res;
157 }
158
159 char *description(void)
160 {
161         return tdesc;
162 }
163
164 int usecount(void)
165 {
166         int res;
167         STANDARD_USECOUNT(res);
168         return res;
169 }
170
171 char *key()
172 {
173         return ASTERISK_GPL_KEY;
174 }