Add support for GROUP_MATCH_COUNT regex matching on category
[asterisk/asterisk.git] / funcs / func_groupcount.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16
17 /*! \file
18  *
19  * \brief Channel group related dialplan functions
20  * 
21  * \ingroup functions
22  */
23
24 #include "asterisk.h"
25
26 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
27
28 #include "asterisk/module.h"
29 #include "asterisk/channel.h"
30 #include "asterisk/pbx.h"
31 #include "asterisk/utils.h"
32 #include "asterisk/app.h"
33
34 /*** DOCUMENTATION
35         <function name="GROUP_COUNT" language="en_US">
36                 <synopsis>
37                         Counts the number of channels in the specified group.
38                 </synopsis>
39                 <syntax argsep="@">
40                         <parameter name="groupname">
41                                 <para>Group name.</para>
42                         </parameter>
43                         <parameter name="category">
44                                 <para>Category name</para>
45                         </parameter>
46                 </syntax>
47                 <description>
48                         <para>Calculates the group count for the specified group, or uses the
49                         channel's current group if not specifed (and non-empty).</para>
50                 </description>
51         </function>
52         <function name="GROUP_MATCH_COUNT" language="en_US">
53                 <synopsis>
54                         Counts the number of channels in the groups matching the specified pattern.
55                 </synopsis>
56                 <syntax argsep="@">
57                         <parameter name="groupmatch" required="true">
58                                 <para>A standard regular expression used to match a group name.</para>
59                         </parameter>
60                         <parameter name="category">
61                                 <para>A standard regular expression used to match a category name.</para>
62                         </parameter>
63                 </syntax>
64                 <description>
65                         <para>Calculates the group count for all groups that match the specified pattern.
66                         Note: category matching is applied after matching based on group.
67                         Uses standard regular expression matching on both (see regex(7)).</para>
68                 </description>
69         </function>
70         <function name="GROUP" language="en_US">
71                 <synopsis>
72                         Gets or sets the channel group.
73                 </synopsis>
74                 <syntax>
75                         <parameter name="category">
76                                 <para>Category name.</para>
77                         </parameter>
78                 </syntax>
79                 <description>
80                         <para><replaceable>category</replaceable> can be employed for more fine grained group management. Each channel 
81                         can only be member of exactly one group per <replaceable>category</replaceable>.</para>
82                 </description>
83         </function>
84         <function name="GROUP_LIST" language="en_US">
85                 <synopsis>
86                         Gets a list of the groups set on a channel.
87                 </synopsis>
88                 <syntax />
89                 <description>
90                         <para>Gets a list of the groups set on a channel.</para>
91                 </description>
92         </function>
93
94  ***/
95
96 static int group_count_function_read(struct ast_channel *chan, const char *cmd,
97                                      char *data, char *buf, size_t len)
98 {
99         int ret = -1;
100         int count = -1;
101         char group[80] = "", category[80] = "";
102
103         ast_app_group_split_group(data, group, sizeof(group), category,
104                                   sizeof(category));
105
106         /* If no group has been provided let's find one */
107         if (ast_strlen_zero(group)) {
108                 struct ast_group_info *gi = NULL;
109
110                 ast_app_group_list_rdlock();
111                 for (gi = ast_app_group_list_head(); gi; gi = AST_LIST_NEXT(gi, group_list)) {
112                         if (gi->chan != chan)
113                                 continue;
114                         if (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))
115                                 break;
116                 }
117                 if (gi) {
118                         ast_copy_string(group, gi->group, sizeof(group));
119                         if (!ast_strlen_zero(gi->category))
120                                 ast_copy_string(category, gi->category, sizeof(category));
121                 }
122                 ast_app_group_list_unlock();
123         }
124
125         if ((count = ast_app_group_get_count(group, category)) == -1) {
126                 ast_log(LOG_NOTICE, "No group could be found for channel '%s'\n", chan->name);
127         } else {
128                 snprintf(buf, len, "%d", count);
129                 ret = 0;
130         }
131
132         return ret;
133 }
134
135 static struct ast_custom_function group_count_function = {
136         .name = "GROUP_COUNT",
137         .read = group_count_function_read,
138         .read_max = 12,
139 };
140
141 static int group_match_count_function_read(struct ast_channel *chan,
142                                            const char *cmd, char *data, char *buf,
143                                            size_t len)
144 {
145         int count;
146         char group[80] = "";
147         char category[80] = "";
148
149         ast_app_group_split_group(data, group, sizeof(group), category,
150                                   sizeof(category));
151
152         if (!ast_strlen_zero(group)) {
153                 count = ast_app_group_match_get_count(group, category);
154                 snprintf(buf, len, "%d", count);
155                 return 0;
156         }
157
158         return -1;
159 }
160
161 static struct ast_custom_function group_match_count_function = {
162         .name = "GROUP_MATCH_COUNT",
163         .read = group_match_count_function_read,
164         .read_max = 12,
165         .write = NULL,
166 };
167
168 static int group_function_read(struct ast_channel *chan, const char *cmd,
169                                char *data, char *buf, size_t len)
170 {
171         int ret = -1;
172         struct ast_group_info *gi = NULL;
173         
174         ast_app_group_list_rdlock();
175         
176         for (gi = ast_app_group_list_head(); gi; gi = AST_LIST_NEXT(gi, group_list)) {
177                 if (gi->chan != chan)
178                         continue;
179                 if (ast_strlen_zero(data))
180                         break;
181                 if (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, data))
182                         break;
183         }
184         
185         if (gi) {
186                 ast_copy_string(buf, gi->group, len);
187                 ret = 0;
188         }
189         
190         ast_app_group_list_unlock();
191         
192         return ret;
193 }
194
195 static int group_function_write(struct ast_channel *chan, const char *cmd,
196                                 char *data, const char *value)
197 {
198         char grpcat[256];
199
200         if (!value) {
201                 return -1;
202         }
203
204         if (!ast_strlen_zero(data)) {
205                 snprintf(grpcat, sizeof(grpcat), "%s@%s", value, data);
206         } else {
207                 ast_copy_string(grpcat, value, sizeof(grpcat));
208         }
209
210         if (ast_app_group_set_channel(chan, grpcat))
211                 ast_log(LOG_WARNING,
212                                 "Setting a group requires an argument (group name)\n");
213
214         return 0;
215 }
216
217 static struct ast_custom_function group_function = {
218         .name = "GROUP",
219         .read = group_function_read,
220         .write = group_function_write,
221 };
222
223 static int group_list_function_read(struct ast_channel *chan, const char *cmd,
224                                     char *data, char *buf, size_t len)
225 {
226         struct ast_group_info *gi = NULL;
227         char tmp1[1024] = "";
228         char tmp2[1024] = "";
229
230         if (!chan)
231                 return -1;
232
233         ast_app_group_list_rdlock();
234
235         for (gi = ast_app_group_list_head(); gi; gi = AST_LIST_NEXT(gi, group_list)) {
236                 if (gi->chan != chan)
237                         continue;
238                 if (!ast_strlen_zero(tmp1)) {
239                         ast_copy_string(tmp2, tmp1, sizeof(tmp2));
240                         if (!ast_strlen_zero(gi->category))
241                                 snprintf(tmp1, sizeof(tmp1), "%s %s@%s", tmp2, gi->group, gi->category);
242                         else
243                                 snprintf(tmp1, sizeof(tmp1), "%s %s", tmp2, gi->group);
244                 } else {
245                         if (!ast_strlen_zero(gi->category))
246                                 snprintf(tmp1, sizeof(tmp1), "%s@%s", gi->group, gi->category);
247                         else
248                                 snprintf(tmp1, sizeof(tmp1), "%s", gi->group);
249                 }
250         }
251         
252         ast_app_group_list_unlock();
253
254         ast_copy_string(buf, tmp1, len);
255
256         return 0;
257 }
258
259 static struct ast_custom_function group_list_function = {
260         .name = "GROUP_LIST",
261         .read = group_list_function_read,
262         .write = NULL,
263 };
264
265 static int unload_module(void)
266 {
267         int res = 0;
268
269         res |= ast_custom_function_unregister(&group_count_function);
270         res |= ast_custom_function_unregister(&group_match_count_function);
271         res |= ast_custom_function_unregister(&group_list_function);
272         res |= ast_custom_function_unregister(&group_function);
273
274         return res;
275 }
276
277 static int load_module(void)
278 {
279         int res = 0;
280
281         res |= ast_custom_function_register(&group_count_function);
282         res |= ast_custom_function_register(&group_match_count_function);
283         res |= ast_custom_function_register(&group_list_function);
284         res |= ast_custom_function_register(&group_function);
285
286         return res;
287 }
288
289 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "Channel group dialplan functions");