security_events: Fix error caused by DTD validation error
[asterisk/asterisk.git] / res / res_mwi_external_ami.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Richard Mudgett <rmudgett@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18
19 /*!
20  * \file
21  * \brief AMI wrapper for external MWI.
22  *
23  * \author Richard Mudgett <rmudgett@digium.com>
24  *
25  * See Also:
26  * \arg \ref AstCREDITS
27  */
28
29 /*** MODULEINFO
30         <depend>res_mwi_external</depend>
31         <support_level>core</support_level>
32  ***/
33
34
35 /*** DOCUMENTATION
36         <manager name="MWIGet" language="en_US">
37                 <synopsis>
38                         Get selected mailboxes with message counts.
39                 </synopsis>
40                 <syntax>
41                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
42                         <parameter name="Mailbox" required="true">
43                                 <para>Mailbox ID in the form of
44                                 /<replaceable>regex</replaceable>/ for all mailboxes matching the regular
45                                 expression.  Otherwise it is for a specific mailbox.</para>
46                         </parameter>
47                 </syntax>
48                 <description>
49                         <para>Get a list of mailboxes with their message counts.</para>
50                 </description>
51         </manager>
52         <managerEvent language="en_US" name="MWIGet">
53                 <managerEventInstance class="EVENT_FLAG_REPORTING">
54                         <synopsis>
55                                 Raised in response to a MWIGet command.
56                         </synopsis>
57                         <syntax>
58                                 <parameter name="ActionID" required="false"/>
59                                 <parameter name="Mailbox">
60                                         <para>Specific mailbox ID.</para>
61                                 </parameter>
62                                 <parameter name="OldMessages">
63                                         <para>The number of old messages in the mailbox.</para>
64                                 </parameter>
65                                 <parameter name="NewMessages">
66                                         <para>The number of new messages in the mailbox.</para>
67                                 </parameter>
68                         </syntax>
69                         <see-also>
70                                 <ref type="manager">MWIGet</ref>
71                         </see-also>
72                 </managerEventInstance>
73         </managerEvent>
74         <managerEvent language="en_US" name="MWIGetComplete">
75                 <managerEventInstance class="EVENT_FLAG_REPORTING">
76                         <synopsis>
77                                 Raised in response to a MWIGet command.
78                         </synopsis>
79                         <syntax>
80                                 <parameter name="ActionID" required="false"/>
81                                 <parameter name="EventList" />
82                                 <parameter name="ListItems">
83                                         <para>The number of mailboxes reported.</para>
84                                 </parameter>
85                         </syntax>
86                         <see-also>
87                                 <ref type="manager">MWIGet</ref>
88                         </see-also>
89                 </managerEventInstance>
90         </managerEvent>
91         <manager name="MWIDelete" language="en_US">
92                 <synopsis>
93                         Delete selected mailboxes.
94                 </synopsis>
95                 <syntax>
96                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
97                         <xi:include xpointer="xpointer(/docs/manager[@name='MWIGet']/syntax/parameter[@name='Mailbox'])" />
98                 </syntax>
99                 <description>
100                         <para>Delete the specified mailboxes.</para>
101                 </description>
102         </manager>
103         <manager name="MWIUpdate" language="en_US">
104                 <synopsis>
105                         Update the mailbox message counts.
106                 </synopsis>
107                 <syntax>
108                         <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
109                         <parameter name="Mailbox" required="true">
110                                 <para>Specific mailbox ID.</para>
111                         </parameter>
112                         <parameter name="OldMessages">
113                                 <para>The number of old messages in the mailbox.  Defaults
114                                 to zero if missing.</para>
115                         </parameter>
116                         <parameter name="NewMessages">
117                                 <para>The number of new messages in the mailbox.  Defaults
118                                 to zero if missing.</para>
119                         </parameter>
120                 </syntax>
121                 <description>
122                         <para>Update the mailbox message counts.</para>
123                 </description>
124         </manager>
125  ***/
126
127
128 #include "asterisk.h"
129
130 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
131
132 #include "asterisk/module.h"
133 #include "asterisk/res_mwi_external.h"
134 #include "asterisk/manager.h"
135
136 /* ------------------------------------------------------------------- */
137
138 /*!
139  * \internal
140  * \brief Get the requested mailboxes.
141  * \since 12.1.0
142  *
143  * \param s AMI session.
144  * \param m AMI message.
145  *
146  * \retval 0 to keep AMI connection.
147  * \retval -1 to disconnect AMI connection.
148  */
149 static int mwi_mailbox_get(struct mansession *s, const struct message *m)
150 {
151         char id_text[256];
152         const char *id;
153         const char *mailbox_id = astman_get_header(m, "Mailbox");
154         const struct ast_mwi_mailbox_object *mailbox;
155         struct ao2_container *mailboxes;
156         unsigned count;
157         struct ao2_iterator iter;
158
159         if (ast_strlen_zero(mailbox_id)) {
160                 astman_send_error(s, m, "Missing mailbox parameter in request");
161                 return 0;
162         }
163
164         if (*mailbox_id == '/') {
165                 struct ast_str *regex_string;
166
167                 regex_string = ast_str_create(strlen(mailbox_id) + 1);
168                 if (!regex_string) {
169                         astman_send_error(s, m, "Memory Allocation Failure");
170                         return 0;
171                 }
172
173                 /* Make "/regex/" into "regex" */
174                 if (ast_regex_string_to_regex_pattern(mailbox_id, &regex_string) != 0) {
175                         astman_send_error_va(s, m, "Mailbox regex format invalid in: %s", mailbox_id);
176                         ast_free(regex_string);
177                         return 0;
178                 }
179
180                 mailboxes = ast_mwi_mailbox_get_by_regex(ast_str_buffer(regex_string));
181                 ast_free(regex_string);
182         } else {
183                 mailboxes = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, NULL, NULL);
184                 if (mailboxes) {
185                         mailbox = ast_mwi_mailbox_get(mailbox_id);
186                         if (mailbox) {
187                                 if (!ao2_link(mailboxes, (void *) mailbox)) {
188                                         ao2_ref(mailboxes, -1);
189                                         mailboxes = NULL;
190                                 }
191                                 ast_mwi_mailbox_unref(mailbox);
192                         }
193                 }
194         }
195         if (!mailboxes) {
196                 astman_send_error(s, m, "Mailbox container creation failure");
197                 return 0;
198         }
199
200         astman_send_listack(s, m, "Mailboxes will follow", "start");
201
202         id = astman_get_header(m, "ActionID");
203         if (!ast_strlen_zero(id)) {
204                 snprintf(id_text, sizeof(id_text), "ActionID: %s\r\n", id);
205         } else {
206                 id_text[0] = '\0';
207         }
208
209         /* Output mailbox list. */
210         count = 0;
211         iter = ao2_iterator_init(mailboxes, AO2_ITERATOR_UNLINK);
212         for (; (mailbox = ao2_iterator_next(&iter)); ast_mwi_mailbox_unref(mailbox)) {
213                 ++count;
214                 astman_append(s,
215                         "Event: MWIGet\r\n"
216                         "Mailbox: %s\r\n"
217                         "OldMessages: %u\r\n"
218                         "NewMessages: %u\r\n"
219                         "%s"
220                         "\r\n",
221                         ast_mwi_mailbox_get_id(mailbox),
222                         ast_mwi_mailbox_get_msgs_old(mailbox),
223                         ast_mwi_mailbox_get_msgs_new(mailbox),
224                         id_text);
225         }
226         ao2_iterator_destroy(&iter);
227         ao2_ref(mailboxes, -1);
228
229         astman_append(s,
230                 "Event: MWIGetComplete\r\n"
231                 "EventList: Complete\r\n"
232                 "ListItems: %d\r\n"
233                 "%s"
234                 "\r\n", count, id_text);
235
236         return 0;
237 }
238
239 /*!
240  * \internal
241  * \brief Delete the requested mailboxes.
242  * \since 12.1.0
243  *
244  * \param s AMI session.
245  * \param m AMI message.
246  *
247  * \retval 0 to keep AMI connection.
248  * \retval -1 to disconnect AMI connection.
249  */
250 static int mwi_mailbox_delete(struct mansession *s, const struct message *m)
251 {
252         const char *mailbox_id = astman_get_header(m, "Mailbox");
253
254         if (ast_strlen_zero(mailbox_id)) {
255                 astman_send_error(s, m, "Missing mailbox parameter in request");
256                 return 0;
257         }
258
259         if (*mailbox_id == '/') {
260                 struct ast_str *regex_string;
261
262                 regex_string = ast_str_create(strlen(mailbox_id) + 1);
263                 if (!regex_string) {
264                         astman_send_error(s, m, "Memory Allocation Failure");
265                         return 0;
266                 }
267
268                 /* Make "/regex/" into "regex" */
269                 if (ast_regex_string_to_regex_pattern(mailbox_id, &regex_string) != 0) {
270                         astman_send_error_va(s, m, "Mailbox regex format invalid in: %s", mailbox_id);
271                         ast_free(regex_string);
272                         return 0;
273                 }
274
275                 ast_mwi_mailbox_delete_by_regex(ast_str_buffer(regex_string));
276                 ast_free(regex_string);
277         } else {
278                 ast_mwi_mailbox_delete(mailbox_id);
279         }
280
281         astman_send_ack(s, m, NULL);
282         return 0;
283 }
284
285 /*!
286  * \internal
287  * \brief Update the specified mailbox.
288  * \since 12.1.0
289  *
290  * \param s AMI session.
291  * \param m AMI message.
292  *
293  * \retval 0 to keep AMI connection.
294  * \retval -1 to disconnect AMI connection.
295  */
296 static int mwi_mailbox_update(struct mansession *s, const struct message *m)
297 {
298         const char *mailbox_id = astman_get_header(m, "Mailbox");
299         const char *msgs_old = astman_get_header(m, "OldMessages");
300         const char *msgs_new = astman_get_header(m, "NewMessages");
301         struct ast_mwi_mailbox_object *mailbox;
302         unsigned int num_old;
303         unsigned int num_new;
304
305         if (ast_strlen_zero(mailbox_id)) {
306                 astman_send_error(s, m, "Missing mailbox parameter in request");
307                 return 0;
308         }
309
310         num_old = 0;
311         if (!ast_strlen_zero(msgs_old)) {
312                 if (sscanf(msgs_old, "%u", &num_old) != 1) {
313                         astman_send_error_va(s, m, "Invalid OldMessages: %s", msgs_old);
314                         return 0;
315                 }
316         }
317
318         num_new = 0;
319         if (!ast_strlen_zero(msgs_new)) {
320                 if (sscanf(msgs_new, "%u", &num_new) != 1) {
321                         astman_send_error_va(s, m, "Invalid NewMessages: %s", msgs_new);
322                         return 0;
323                 }
324         }
325
326         mailbox = ast_mwi_mailbox_alloc(mailbox_id);
327         if (!mailbox) {
328                 astman_send_error(s, m, "Mailbox object creation failure");
329                 return 0;
330         }
331
332         /* Update external mailbox. */
333         ast_mwi_mailbox_set_msgs_old(mailbox, num_old);
334         ast_mwi_mailbox_set_msgs_new(mailbox, num_new);
335         if (ast_mwi_mailbox_update(mailbox)) {
336                 astman_send_error(s, m, "Update attempt failed");
337         } else {
338                 astman_send_ack(s, m, NULL);
339         }
340         ast_mwi_mailbox_unref(mailbox);
341
342         return 0;
343 }
344
345 static int unload_module(void)
346 {
347         ast_manager_unregister("MWIGet");
348         ast_manager_unregister("MWIDelete");
349         ast_manager_unregister("MWIUpdate");
350
351         /* Must be done last */
352         ast_mwi_external_unref();
353         return 0;
354 }
355
356 static int load_module(void)
357 {
358         int res;
359
360         /* Must be done first */
361         ast_mwi_external_ref();
362
363         res = 0;
364         res |= ast_manager_register_xml_core("MWIGet", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, mwi_mailbox_get);
365         res |= ast_manager_register_xml_core("MWIDelete", EVENT_FLAG_CALL, mwi_mailbox_delete);
366         res |= ast_manager_register_xml_core("MWIUpdate", EVENT_FLAG_CALL, mwi_mailbox_update);
367         if (res) {
368                 unload_module();
369                 return AST_MODULE_LOAD_DECLINE;
370         }
371
372         return AST_MODULE_LOAD_SUCCESS;
373 }
374
375 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "AMI support for external MWI",
376         .load = load_module,
377         .unload = unload_module,
378 );
379