2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2013, Digium, Inc.
6 * Richard Mudgett <rmudgett@digium.com>
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.
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.
21 * \brief Core external MWI support.
24 * The module manages the persistent message counts cache and supplies
25 * an API to allow the protocol specific modules to control the counts
28 * \author Richard Mudgett <rmudgett@digium.com>
31 * \arg \ref AstCREDITS
35 <defaultenabled>no</defaultenabled>
36 <conflict>app_voicemail</conflict>
37 <support_level>core</support_level>
41 <configInfo name="res_mwi_external" language="en_US">
42 <synopsis>Core external MWI support</synopsis>
43 <configFile name="sorcery.conf">
44 <configObject name="mailboxes">
45 <synopsis>Persistent cache of external MWI Mailboxs.</synopsis>
47 <para>Allows the alteration of sorcery backend mapping for
48 the persistent cache of external MWI mailboxes.</para>
58 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
60 #include "asterisk/app.h"
61 #include "asterisk/module.h"
62 #include "asterisk/res_mwi_external.h"
63 #include "asterisk/sorcery.h"
64 #include "asterisk/cli.h"
66 /* ------------------------------------------------------------------- */
69 * Define to include CLI commands to manipulate the external MWI mailboxes.
70 * Useful for testing the module functionality.
72 //#define MWI_DEBUG_CLI 1
74 #define MWI_ASTDB_PREFIX "mwi_external"
75 #define MWI_MAILBOX_TYPE "mailboxes"
77 struct ast_mwi_mailbox_object {
78 SORCERY_OBJECT(details);
79 /*! Number of new messages in mailbox. */
80 unsigned int msgs_new;
81 /*! Number of old messages in mailbox. */
82 unsigned int msgs_old;
85 static struct ast_sorcery *mwi_sorcery;
87 void ast_mwi_external_ref(void)
89 ast_module_ref(ast_module_info->self);
92 void ast_mwi_external_unref(void)
94 ast_module_unref(ast_module_info->self);
99 * \brief Post an update event to the MWI counts.
104 static void mwi_post_event(const struct ast_mwi_mailbox_object *mailbox)
106 ast_publish_mwi_state(ast_sorcery_object_get_id(mailbox), NULL,
107 mailbox->msgs_new, mailbox->msgs_old);
110 static void mwi_observe_update(const void *obj)
117 * \brief Post a count clearing event to the MWI counts.
122 static void mwi_observe_delete(const void *obj)
124 const struct ast_mwi_mailbox_object *mailbox = obj;
126 if (!mailbox->msgs_new && !mailbox->msgs_old) {
127 /* No need to post a count clearing event. */
131 /* Post a count clearing event. */
132 ast_publish_mwi_state(ast_sorcery_object_get_id(mailbox), NULL, 0, 0);
135 static const struct ast_sorcery_observer mwi_observers = {
136 .created = mwi_observe_update,
137 .updated = mwi_observe_update,
138 .deleted = mwi_observe_delete,
141 /*! \brief Internal function to allocate a mwi object */
142 static void *mwi_sorcery_object_alloc(const char *id)
144 return ast_sorcery_generic_alloc(sizeof(struct ast_mwi_mailbox_object), NULL);
149 * \brief Initialize sorcery for external MWI.
152 * \retval 0 on success.
153 * \retval -1 on error.
155 static int mwi_sorcery_init(void)
159 mwi_sorcery = ast_sorcery_open();
161 ast_log(LOG_ERROR, "MWI external: Sorcery failed to open.\n");
165 /* Map the external MWI wizards. */
166 res = !!ast_sorcery_apply_config(mwi_sorcery, "res_mwi_external");
167 res &= !!ast_sorcery_apply_default(mwi_sorcery, MWI_MAILBOX_TYPE, "astdb",
170 ast_log(LOG_ERROR, "MWI external: Sorcery could not setup wizards.\n");
174 res = ast_sorcery_object_register(mwi_sorcery, MWI_MAILBOX_TYPE,
175 mwi_sorcery_object_alloc, NULL, NULL);
177 ast_log(LOG_ERROR, "MWI external: Sorcery could not register object type '%s'.\n",
182 /* Define the MWI_MAILBOX_TYPE object fields. */
183 res |= ast_sorcery_object_field_register_nodoc(mwi_sorcery, MWI_MAILBOX_TYPE,
184 "msgs_new", "0", OPT_UINT_T, 0, FLDSET(struct ast_mwi_mailbox_object, msgs_new));
185 res |= ast_sorcery_object_field_register_nodoc(mwi_sorcery, MWI_MAILBOX_TYPE,
186 "msgs_old", "0", OPT_UINT_T, 0, FLDSET(struct ast_mwi_mailbox_object, msgs_old));
190 struct ao2_container *ast_mwi_mailbox_get_all(void)
192 return ast_sorcery_retrieve_by_fields(mwi_sorcery, MWI_MAILBOX_TYPE,
193 AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);
196 struct ao2_container *ast_mwi_mailbox_get_by_regex(const char *regex)
198 return ast_sorcery_retrieve_by_regex(mwi_sorcery, MWI_MAILBOX_TYPE, regex ?: "");
201 const struct ast_mwi_mailbox_object *ast_mwi_mailbox_get(const char *mailbox_id)
203 if (ast_strlen_zero(mailbox_id)) {
207 return ast_sorcery_retrieve_by_id(mwi_sorcery, MWI_MAILBOX_TYPE, mailbox_id);
210 struct ast_mwi_mailbox_object *ast_mwi_mailbox_alloc(const char *mailbox_id)
212 if (ast_strlen_zero(mailbox_id)) {
216 return ast_sorcery_alloc(mwi_sorcery, MWI_MAILBOX_TYPE, mailbox_id);
219 struct ast_mwi_mailbox_object *ast_mwi_mailbox_copy(const struct ast_mwi_mailbox_object *mailbox)
221 return ast_sorcery_copy(mwi_sorcery, mailbox);
224 const char *ast_mwi_mailbox_get_id(const struct ast_mwi_mailbox_object *mailbox)
226 return ast_sorcery_object_get_id(mailbox);
229 unsigned int ast_mwi_mailbox_get_msgs_new(const struct ast_mwi_mailbox_object *mailbox)
231 return mailbox->msgs_new;
234 unsigned int ast_mwi_mailbox_get_msgs_old(const struct ast_mwi_mailbox_object *mailbox)
236 return mailbox->msgs_old;
239 void ast_mwi_mailbox_set_msgs_new(struct ast_mwi_mailbox_object *mailbox, unsigned int num_msgs)
241 mailbox->msgs_new = num_msgs;
244 void ast_mwi_mailbox_set_msgs_old(struct ast_mwi_mailbox_object *mailbox, unsigned int num_msgs)
246 mailbox->msgs_old = num_msgs;
249 int ast_mwi_mailbox_update(struct ast_mwi_mailbox_object *mailbox)
251 const struct ast_mwi_mailbox_object *exists;
254 exists = ast_sorcery_retrieve_by_id(mwi_sorcery, MWI_MAILBOX_TYPE,
255 ast_sorcery_object_get_id(mailbox));
257 res = ast_sorcery_update(mwi_sorcery, mailbox);
258 ast_mwi_mailbox_unref(exists);
260 res = ast_sorcery_create(mwi_sorcery, mailbox);
267 * \brief Delete a mailbox.
270 * \param mailbox Mailbox object to delete from sorcery.
274 static void mwi_mailbox_delete(struct ast_mwi_mailbox_object *mailbox)
276 ast_sorcery_delete(mwi_sorcery, mailbox);
281 * \brief Delete all mailboxes in container.
284 * \param mailboxes Mailbox objects to delete from sorcery.
288 static void mwi_mailbox_delete_all(struct ao2_container *mailboxes)
290 struct ast_mwi_mailbox_object *mailbox;
291 struct ao2_iterator iter;
293 iter = ao2_iterator_init(mailboxes, AO2_ITERATOR_UNLINK);
294 for (; (mailbox = ao2_iterator_next(&iter)); ast_mwi_mailbox_unref(mailbox)) {
295 mwi_mailbox_delete(mailbox);
297 ao2_iterator_destroy(&iter);
300 int ast_mwi_mailbox_delete_all(void)
302 struct ao2_container *mailboxes;
304 mailboxes = ast_mwi_mailbox_get_all();
306 mwi_mailbox_delete_all(mailboxes);
307 ao2_ref(mailboxes, -1);
312 int ast_mwi_mailbox_delete_by_regex(const char *regex)
314 struct ao2_container *mailboxes;
316 mailboxes = ast_mwi_mailbox_get_by_regex(regex);
318 mwi_mailbox_delete_all(mailboxes);
319 ao2_ref(mailboxes, -1);
324 int ast_mwi_mailbox_delete(const char *mailbox_id)
326 const struct ast_mwi_mailbox_object *mailbox;
328 if (ast_strlen_zero(mailbox_id)) {
332 mailbox = ast_mwi_mailbox_get(mailbox_id);
334 mwi_mailbox_delete((struct ast_mwi_mailbox_object *) mailbox);
335 ast_mwi_mailbox_unref(mailbox);
348 * \brief Determine if the requested folder is valid for external MWI support.
351 * \param folder Folder name to check (NULL is valid).
353 * \return Enum of the supported folder.
355 static enum folder_map mwi_folder_map(const char *folder)
357 enum folder_map which_folder;
359 if (ast_strlen_zero(folder) || !strcasecmp(folder, "INBOX")) {
360 which_folder = FOLDER_INBOX;
361 } else if (!strcasecmp(folder, "Old")) {
362 which_folder = FOLDER_OLD;
364 which_folder = FOLDER_INVALID;
371 * \brief Gets the number of messages that exist in a mailbox folder.
374 * \param mailbox_id The mailbox name.
375 * \param folder The folder to look in. Default is INBOX if not provided.
377 * \return The number of messages in the mailbox folder (zero or more).
379 static int mwi_messagecount(const char *mailbox_id, const char *folder)
381 const struct ast_mwi_mailbox_object *mailbox;
383 enum folder_map which_folder;
385 which_folder = mwi_folder_map(folder);
386 if (which_folder == FOLDER_INVALID) {
390 mailbox = ast_mwi_mailbox_get(mailbox_id);
395 switch (which_folder) {
399 num_msgs = mailbox->msgs_new;
402 num_msgs = mailbox->msgs_old;
405 ast_mwi_mailbox_unref(mailbox);
412 * \brief Determines if the given folder has messages.
415 * \param mailboxes Comma or & delimited list of mailboxes.
416 * \param folder The folder to look in. Default is INBOX if not provided.
418 * \retval 1 if the folder has one or more messages.
419 * \retval 0 otherwise.
421 static int mwi_has_voicemail(const char *mailboxes, const char *folder)
425 enum folder_map which_folder;
427 which_folder = mwi_folder_map(folder);
428 if (which_folder == FOLDER_INVALID) {
432 /* For each mailbox in the list. */
433 parse = ast_strdupa(mailboxes);
434 while ((mailbox_id = strsep(&parse, ",&"))) {
435 const struct ast_mwi_mailbox_object *mailbox;
438 /* Get the specified mailbox. */
439 mailbox = ast_mwi_mailbox_get(mailbox_id);
444 /* Done if the found mailbox has any messages. */
446 switch (which_folder) {
450 num_msgs = mailbox->msgs_new;
453 num_msgs = mailbox->msgs_old;
456 ast_mwi_mailbox_unref(mailbox);
467 * \brief Gets the number of messages that exist for the mailbox list.
470 * \param mailboxes Comma or space delimited list of mailboxes.
471 * \param newmsgs Where to put the count of new messages. (Can be NULL)
472 * \param oldmsgs Where to put the count of old messages. (Can be NULL)
475 * Simultaneously determines the count of new and old
476 * messages. The total messages would then be the sum of these.
478 * \retval 0 on success
479 * \retval -1 on failure
481 static int mwi_inboxcount(const char *mailboxes, int *newmsgs, int *oldmsgs)
486 if (!newmsgs && !oldmsgs) {
487 /* Nowhere to accumulate counts */
491 /* For each mailbox in the list. */
492 parse = ast_strdupa(mailboxes);
493 while ((mailbox_id = strsep(&parse, ", "))) {
494 const struct ast_mwi_mailbox_object *mailbox;
496 /* Get the specified mailbox. */
497 mailbox = ast_mwi_mailbox_get(mailbox_id);
502 /* Accumulate the counts. */
504 *newmsgs += mailbox->msgs_new;
507 *oldmsgs += mailbox->msgs_old;
510 ast_mwi_mailbox_unref(mailbox);
518 * \brief Gets the number of messages that exist for the mailbox list.
521 * \param mailboxes Comma or space delimited list of mailboxes.
522 * \param urgentmsgs Where to put the count of urgent messages. (Can be NULL)
523 * \param newmsgs Where to put the count of new messages. (Can be NULL)
524 * \param oldmsgs Where to put the count of old messages. (Can be NULL)
527 * Simultaneously determines the count of new, old, and urgent
528 * messages. The total messages would then be the sum of these
531 * \retval 0 on success
532 * \retval -1 on failure
534 static int mwi_inboxcount2(const char *mailboxes, int *urgentmsgs, int *newmsgs, int *oldmsgs)
537 * This module does not support urgentmsgs. Just ignore them.
538 * The global API call has already set the count to zero.
540 return mwi_inboxcount(mailboxes, newmsgs, oldmsgs);
543 static const struct ast_vm_functions vm_table = {
544 .module_version = VM_MODULE_VERSION,
545 .module_name = AST_MODULE,
547 .has_voicemail = mwi_has_voicemail,
548 .inboxcount = mwi_inboxcount,
549 .inboxcount2 = mwi_inboxcount2,
550 .messagecount = mwi_messagecount,
553 #if defined(MWI_DEBUG_CLI)
554 static char *complete_mailbox(const char *word, int state)
556 struct ao2_iterator iter;
557 int wordlen = strlen(word);
561 const struct ast_mwi_mailbox_object *mailbox;
562 RAII_VAR(struct ao2_container *, mailboxes, NULL, ao2_cleanup);
564 regex = ast_alloca(2 + wordlen);
565 sprintf(regex, "^%s", word);/* Safe */
567 mailboxes = ast_mwi_mailbox_get_by_regex(regex);
572 iter = ao2_iterator_init(mailboxes, 0);
573 for (; (mailbox = ao2_iterator_next(&iter)); ast_mwi_mailbox_unref(mailbox)) {
574 if (++which > state) {
575 ret = ast_strdup(ast_sorcery_object_get_id(mailbox));
576 ast_mwi_mailbox_unref(mailbox);
580 ao2_iterator_destroy(&iter);
584 #endif /* defined(MWI_DEBUG_CLI) */
586 #if defined(MWI_DEBUG_CLI)
587 static char *handle_mwi_delete_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
591 e->command = "mwi delete all";
593 "Usage: mwi delete all\n"
594 " Delete all external MWI mailboxes.\n";
600 ast_mwi_mailbox_delete_all();
601 ast_cli(a->fd, "Deleted all external MWI mailboxes.\n");
604 #endif /* defined(MWI_DEBUG_CLI) */
606 #if defined(MWI_DEBUG_CLI)
607 static char *handle_mwi_delete_like(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
613 e->command = "mwi delete like";
615 "Usage: mwi delete like <pattern>\n"
616 " Delete external MWI mailboxes matching a regular expression.\n";
623 return CLI_SHOWUSAGE;
627 ast_mwi_mailbox_delete_by_regex(regex);
628 ast_cli(a->fd, "Deleted external MWI mailboxes matching '%s'.\n", regex);
631 #endif /* defined(MWI_DEBUG_CLI) */
633 #if defined(MWI_DEBUG_CLI)
634 static char *handle_mwi_delete_mailbox(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
636 const char *mailbox_id;
640 e->command = "mwi delete mailbox";
642 "Usage: mwi delete mailbox <mailbox_id>\n"
643 " Delete a specific external MWI mailbox.\n";
647 return complete_mailbox(a->word, a->n);
653 return CLI_SHOWUSAGE;
655 mailbox_id = a->argv[3];
657 ast_mwi_mailbox_delete(mailbox_id);
658 ast_cli(a->fd, "Deleted external MWI mailbox '%s'.\n", mailbox_id);
662 #endif /* defined(MWI_DEBUG_CLI) */
664 #define FORMAT_MAILBOX_HDR "%6s %6s %s\n"
665 #define FORMAT_MAILBOX_ROW "%6u %6u %s\n"
667 #if defined(MWI_DEBUG_CLI)
670 * \brief Print a mailbox list line to CLI.
673 * \param cli_fd File descriptor for CLI output.
674 * \param mailbox What to list.
678 static void mwi_cli_print_mailbox(int cli_fd, const struct ast_mwi_mailbox_object *mailbox)
680 ast_cli(cli_fd, FORMAT_MAILBOX_ROW, mailbox->msgs_new, mailbox->msgs_old,
681 ast_sorcery_object_get_id(mailbox));
683 #endif /* defined(MWI_DEBUG_CLI) */
685 #if defined(MWI_DEBUG_CLI)
688 * \brief List all mailboxes in the given container.
691 * \param cli_fd File descriptor for CLI output.
692 * \param mailboxes What to list.
696 static void mwi_cli_list_mailboxes(int cli_fd, struct ao2_container *mailboxes)
698 struct ao2_iterator iter;
699 const struct ast_mwi_mailbox_object *mailbox;
701 ast_cli(cli_fd, FORMAT_MAILBOX_HDR, "New", "Old", "Mailbox");
703 iter = ao2_iterator_init(mailboxes, 0);
704 for (; (mailbox = ao2_iterator_next(&iter)); ast_mwi_mailbox_unref(mailbox)) {
705 mwi_cli_print_mailbox(cli_fd, mailbox);
707 ao2_iterator_destroy(&iter);
709 #endif /* defined(MWI_DEBUG_CLI) */
711 #undef FORMAT_MAILBOX_HDR
712 #undef FORMAT_MAILBOX_ROW
714 #if defined(MWI_DEBUG_CLI)
715 static char *handle_mwi_list_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
717 struct ao2_container *mailboxes;
721 e->command = "mwi list all";
723 "Usage: mwi list all\n"
724 " List all external MWI mailboxes.\n";
730 mailboxes = ast_mwi_mailbox_get_all();
732 ast_cli(a->fd, "Failed to retrieve external MWI mailboxes.\n");
735 mwi_cli_list_mailboxes(a->fd, mailboxes);
736 ao2_ref(mailboxes, -1);
739 #endif /* defined(MWI_DEBUG_CLI) */
741 #if defined(MWI_DEBUG_CLI)
742 static char *handle_mwi_list_like(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
744 struct ao2_container *mailboxes;
749 e->command = "mwi list like";
751 "Usage: mwi list like <pattern>\n"
752 " List external MWI mailboxes matching a regular expression.\n";
759 return CLI_SHOWUSAGE;
763 mailboxes = ast_mwi_mailbox_get_by_regex(regex);
765 ast_cli(a->fd, "Failed to retrieve external MWI mailboxes.\n");
768 mwi_cli_list_mailboxes(a->fd, mailboxes);
769 ao2_ref(mailboxes, -1);
772 #endif /* defined(MWI_DEBUG_CLI) */
774 #if defined(MWI_DEBUG_CLI)
775 static char *handle_mwi_show_mailbox(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
777 const struct ast_mwi_mailbox_object *mailbox;
778 const char *mailbox_id;
782 e->command = "mwi show mailbox";
784 "Usage: mwi show mailbox <mailbox_id>\n"
785 " Show a specific external MWI mailbox.\n";
789 return complete_mailbox(a->word, a->n);
795 return CLI_SHOWUSAGE;
797 mailbox_id = a->argv[3];
799 mailbox = ast_mwi_mailbox_get(mailbox_id);
805 ast_sorcery_object_get_id(mailbox),
809 ast_mwi_mailbox_unref(mailbox);
811 ast_cli(a->fd, "External MWI mailbox '%s' not found.\n", mailbox_id);
816 #endif /* defined(MWI_DEBUG_CLI) */
818 #if defined(MWI_DEBUG_CLI)
819 static char *handle_mwi_update_mailbox(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
821 struct ast_mwi_mailbox_object *mailbox;
822 const char *mailbox_id;
823 unsigned int num_new;
824 unsigned int num_old;
828 e->command = "mwi update mailbox";
830 "Usage: mwi update mailbox <mailbox_id> [<new> [<old>]]\n"
831 " Update a specific external MWI mailbox.\n";
835 return complete_mailbox(a->word, a->n);
840 if (a->argc < 4 || 6 < a->argc) {
841 return CLI_SHOWUSAGE;
843 mailbox_id = a->argv[3];
847 const char *count_new = a->argv[4];
849 if (sscanf(count_new, "%u", &num_new) != 1) {
850 ast_cli(a->fd, "Invalid NewMessages: '%s'.\n", count_new);
851 return CLI_SHOWUSAGE;
857 const char *count_old = a->argv[5];
859 if (sscanf(count_old, "%u", &num_old) != 1) {
860 ast_cli(a->fd, "Invalid OldMessages: '%s'.\n", count_old);
861 return CLI_SHOWUSAGE;
865 mailbox = ast_mwi_mailbox_alloc(mailbox_id);
867 ast_mwi_mailbox_set_msgs_new(mailbox, num_new);
868 ast_mwi_mailbox_set_msgs_old(mailbox, num_old);
869 if (ast_mwi_mailbox_update(mailbox)) {
870 ast_cli(a->fd, "Could not update mailbox %s.\n",
871 ast_sorcery_object_get_id(mailbox));
873 ast_cli(a->fd, "Updated mailbox %s.\n", ast_sorcery_object_get_id(mailbox));
876 ast_mwi_mailbox_unref(mailbox);
881 #endif /* defined(MWI_DEBUG_CLI) */
883 #if defined(MWI_DEBUG_CLI)
884 static struct ast_cli_entry mwi_cli[] = {
885 AST_CLI_DEFINE(handle_mwi_delete_all, "Delete all external MWI mailboxes"),
886 AST_CLI_DEFINE(handle_mwi_delete_like, "Delete external MWI mailboxes matching regex"),
887 AST_CLI_DEFINE(handle_mwi_delete_mailbox, "Delete a specific external MWI mailbox"),
888 AST_CLI_DEFINE(handle_mwi_list_all, "List all external MWI mailboxes"),
889 AST_CLI_DEFINE(handle_mwi_list_like, "List external MWI mailboxes matching regex"),
890 AST_CLI_DEFINE(handle_mwi_show_mailbox, "Show a specific external MWI mailbox"),
891 AST_CLI_DEFINE(handle_mwi_update_mailbox, "Update a specific external MWI mailbox"),
893 #endif /* defined(MWI_DEBUG_CLI) */
897 * \brief Post initial MWI count events.
902 static void mwi_initial_events(void)
904 struct ao2_container *mailboxes;
905 const struct ast_mwi_mailbox_object *mailbox;
906 struct ao2_iterator iter;
908 /* Get all mailbox counts. */
909 mailboxes = ast_mwi_mailbox_get_all();
914 /* Post all mailbox counts. */
915 iter = ao2_iterator_init(mailboxes, AO2_ITERATOR_UNLINK);
916 for (; (mailbox = ao2_iterator_next(&iter)); ast_mwi_mailbox_unref(mailbox)) {
917 mwi_post_event(mailbox);
919 ao2_iterator_destroy(&iter);
921 ao2_ref(mailboxes, -1);
924 static int unload_module(void)
926 ast_vm_unregister(vm_table.module_name);
927 #if defined(MWI_DEBUG_CLI)
928 ast_cli_unregister_multiple(mwi_cli, ARRAY_LEN(mwi_cli));
929 #endif /* defined(MWI_DEBUG_CLI) */
930 ast_sorcery_observer_remove(mwi_sorcery, MWI_MAILBOX_TYPE, &mwi_observers);
932 ast_sorcery_unref(mwi_sorcery);
938 static int load_module(void)
940 if (mwi_sorcery_init()
941 || ast_sorcery_observer_add(mwi_sorcery, MWI_MAILBOX_TYPE, &mwi_observers)
942 #if defined(MWI_DEBUG_CLI)
943 || ast_cli_register_multiple(mwi_cli, ARRAY_LEN(mwi_cli))
944 #endif /* defined(MWI_DEBUG_CLI) */
945 || ast_vm_register(&vm_table)) {
947 return AST_MODULE_LOAD_DECLINE;
950 /* Post initial MWI count events. */
951 mwi_initial_events();
953 return AST_MODULE_LOAD_SUCCESS;
956 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "Core external MWI resource",
958 .unload = unload_module,
959 .load_pri = AST_MODPRI_CHANNEL_DEPEND - 5,