voicemail API callbacks: Extract the sayname API call to its own registerd callback.
authorRichard Mudgett <rmudgett@digium.com>
Fri, 20 Jun 2014 17:06:42 +0000 (17:06 +0000)
committerRichard Mudgett <rmudgett@digium.com>
Fri, 20 Jun 2014 17:06:42 +0000 (17:06 +0000)
* Extract the sayname API call to its own registerd callback.  This allows
the app_directory and app_chanspy applications to say a mailbox owner's
name using an alternate provider when app_voicemail is not available
because you are using res_mwi_external.  app_directory still uses the
voicemail.conf file.

AFS-64 #close
Reported by: Mark Michelson

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@416830 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/app_chanspy.c
apps/app_directory.c
apps/app_voicemail.c
include/asterisk/app.h
main/app.c

index 306e6e8..47f755e 100644 (file)
@@ -864,6 +864,15 @@ static struct ast_autochan *next_channel(struct ast_channel_iterator *iter,
        return NULL;
 }
 
+static int spy_sayname(struct ast_channel *chan, const char *mailbox, const char *context)
+{
+       char *mailbox_id;
+
+       mailbox_id = ast_alloca(strlen(mailbox) + strlen(context) + 2);
+       sprintf(mailbox_id, "%s@%s", mailbox, context); /* Safe */
+       return ast_app_sayname(chan, mailbox_id);
+}
+
 static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
        int volfactor, const int fd, struct spy_dtmf_options *user_options,
        const char *mygroup, const char *myenforced, const char *spec, const char *exten,
@@ -1078,8 +1087,9 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags,
                                if (ast_test_flag(flags, OPTION_NAME)) {
                                        const char *local_context = S_OR(name_context, "default");
                                        const char *local_mailbox = S_OR(mailbox, ptr);
+
                                        if (local_mailbox) {
-                                               res = ast_app_sayname(chan, local_mailbox, local_context);
+                                               res = spy_sayname(chan, local_mailbox, local_context);
                                        } else {
                                                res = -1;
                                        }
index 3afb19f..350401e 100644 (file)
@@ -26,7 +26,6 @@
  */
 
 /*** MODULEINFO
-       <depend>app_voicemail</depend>
        <support_level>core</support_level>
  ***/
 #include "asterisk.h"
@@ -290,7 +289,13 @@ static int play_mailbox_owner(struct ast_channel *chan, const char *context,
        const char *ext, const char *name, struct ast_flags *flags)
 {
        int res = 0;
-       if ((res = ast_app_sayname(chan, ext, context)) >= 0) {
+       char *mailbox_id;
+
+       mailbox_id = ast_alloca(strlen(ext) + strlen(context) + 2);
+       sprintf(mailbox_id, "%s@%s", ext, context); /* Safe */
+
+       res = ast_app_sayname(chan, mailbox_id);
+       if (res >= 0) {
                ast_stopstream(chan);
                /* If Option 'e' was specified, also read the extension number with the name */
                if (ast_test_flag(flags, OPT_SAYEXTENSION)) {
index 891d233..d392dd5 100644 (file)
@@ -13669,6 +13669,29 @@ static int sayname(struct ast_channel *chan, const char *mailbox, const char *co
        return res;
 }
 
+/*!
+ * \internal
+ * \brief Play a recorded user name for the mailbox to the specified channel.
+ *
+ * \param chan Where to play the recorded name file.
+ * \param mailbox_id The mailbox name.
+ *
+ * \retval 0 Name played without interruption
+ * \retval dtmf ASCII value of the DTMF which interrupted playback.
+ * \retval -1 Unable to locate mailbox or hangup occurred.
+ */
+static int vm_sayname(struct ast_channel *chan, const char *mailbox_id)
+{
+       char *context;
+       char *mailbox;
+
+       if (ast_strlen_zero(mailbox_id)
+               || separate_mailbox(ast_strdupa(mailbox_id), &mailbox, &context)) {
+               return -1;
+       }
+       return sayname(chan, mailbox, context);
+}
+
 static void read_password_from_file(const char *secretfn, char *password, int passwordlen) {
        struct ast_config *pwconf;
        struct ast_flags config_flags = { 0 };
@@ -14286,7 +14309,6 @@ static const struct ast_vm_functions vm_table = {
        .inboxcount = inboxcount,
        .inboxcount2 = inboxcount2,
        .messagecount = messagecount,
-       .sayname = sayname,
        .copy_recording_to_vm = msg_create_from_file,
        .index_to_foldername = vm_index_to_foldername,
        .mailbox_snapshot_create = vm_mailbox_snapshot_create,
@@ -14297,6 +14319,13 @@ static const struct ast_vm_functions vm_table = {
        .msg_play = vm_msg_play,
 };
 
+static const struct ast_vm_greeter_functions vm_greeter_table = {
+       .module_version = VM_GREETER_MODULE_VERSION,
+       .module_name = AST_MODULE,
+
+       .sayname = vm_sayname,
+};
+
 static int reload(void)
 {
        return load_config(1);
@@ -14327,6 +14356,7 @@ static int unload_module(void)
 #endif
        ast_cli_unregister_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
        ast_vm_unregister(vm_table.module_name);
+       ast_vm_greeter_unregister(vm_greeter_table.module_name);
 #ifdef TEST_FRAMEWORK
        ast_uninstall_vm_test_functions();
 #endif
@@ -14394,8 +14424,10 @@ static int load_module(void)
 #endif
 
        res |= ast_vm_register(&vm_table);
-       if (res)
+       res |= ast_vm_greeter_register(&vm_greeter_table);
+       if (res) {
                return res;
+       }
 
        ast_cli_register_multiple(cli_voicemail, ARRAY_LEN(cli_voicemail));
        ast_data_register_multiple(vm_data_providers, ARRAY_LEN(vm_data_providers));
index 65d74dc..d5a0e27 100644 (file)
@@ -392,17 +392,16 @@ typedef int (ast_inboxcount2_fn)(const char *mailboxes, int *urgentmsgs, int *ne
 typedef int (ast_messagecount_fn)(const char *mailbox_id, const char *folder);
 
 /*!
- * \brief Play a recorded user name for the mailbox.
+ * \brief Play a recorded user name for the mailbox to the specified channel.
  *
  * \param chan Where to play the recorded name file.
- * \param user The user part of user@context.
- * \param context The context part of user@context.  Must be explicit.
+ * \param mailbox_id The mailbox name.
  *
  * \retval 0 Name played without interruption
- * \retval dtmf ASCII value of the DTMF which interrupted playback
- * \retval -1 on failure
+ * \retval dtmf ASCII value of the DTMF which interrupted playback.
+ * \retval -1 Unable to locate mailbox or hangup occurred.
  */
-typedef int (ast_sayname_fn)(struct ast_channel *chan, const char *user, const char *context);
+typedef int (ast_sayname_fn)(struct ast_channel *chan, const char *mailbox_id);
 
 /*!
  * \brief Creates a voicemail based on a specified file to a mailbox.
@@ -534,7 +533,7 @@ typedef int (ast_vm_msg_forward_fn)(const char *from_mailbox, const char *from_c
 typedef int (ast_vm_msg_play_fn)(struct ast_channel *chan, const char *mailbox,
        const char *context, const char *folder, const char *msg_num, ast_vm_msg_play_cb *cb);
 
-#define VM_MODULE_VERSION 1
+#define VM_MODULE_VERSION 2
 
 /*! \brief Voicemail function table definition. */
 struct ast_vm_functions {
@@ -554,7 +553,6 @@ struct ast_vm_functions {
        ast_inboxcount_fn *inboxcount;
        ast_inboxcount2_fn *inboxcount2;
        ast_messagecount_fn *messagecount;
-       ast_sayname_fn *sayname;
        ast_copy_recording_to_vm_fn *copy_recording_to_vm;
        ast_vm_index_to_foldername_fn *index_to_foldername;
        ast_vm_mailbox_snapshot_create_fn *mailbox_snapshot_create;
@@ -569,8 +567,8 @@ struct ast_vm_functions {
  * \brief Determine if a voicemail provider is registered.
  * \since 12.0.0
  *
- * \retval 0 if no privider registered.
- * \retval 1 if a privider is registered.
+ * \retval 0 if no provider registered.
+ * \retval 1 if a provider is registered.
  */
 int ast_vm_is_registered(void);
 
@@ -597,6 +595,59 @@ int __ast_vm_register(const struct ast_vm_functions *vm_table, struct ast_module
  */
 void ast_vm_unregister(const char *module_name);
 
+#define VM_GREETER_MODULE_VERSION 1
+
+/*! \brief Voicemail greeter function table definition. */
+struct ast_vm_greeter_functions {
+       /*!
+        * \brief The version of this function table.
+        *
+        * \note If the ABI for this table changes, the module version
+        * (\ref VM_GREETER_MODULE_VERSION) should be incremented.
+        */
+       unsigned int module_version;
+       /*! \brief The name of the module that provides the voicemail greeter functionality */
+       const char *module_name;
+       /*! \brief The module for the voicemail greeter provider */
+       struct ast_module *module;
+
+       ast_sayname_fn *sayname;
+};
+
+/*!
+ * \brief Determine if a voicemail greeter provider is registered.
+ * \since 13.0.0
+ *
+ * \retval 0 if no provider registered.
+ * \retval 1 if a provider is registered.
+ */
+int ast_vm_greeter_is_registered(void);
+
+/*!
+ * \brief Set voicemail greeter function callbacks
+ * \since 13.0.0
+ *
+ * \param vm_table Voicemail greeter function table to install.
+ * \param module Pointer to the module implementing the interface
+ *
+ * \retval 0 on success.
+ * \retval -1 on error.
+ */
+int __ast_vm_greeter_register(const struct ast_vm_greeter_functions *vm_table, struct ast_module *module);
+
+/*! \brief See \ref __ast_vm_greeter_register() */
+#define ast_vm_greeter_register(vm_table) __ast_vm_greeter_register(vm_table, ast_module_info ? ast_module_info->self : NULL)
+
+/*!
+ * \brief Unregister the specified voicemail greeter provider
+ * \since 13.0.0
+ *
+ * \param The module name of the provider to unregister
+ *
+ * \return Nothing
+ */
+void ast_vm_greeter_unregister(const char *module_name);
+
 #ifdef TEST_FRAMEWORK
 typedef int (ast_vm_test_create_user_fn)(const char *context, const char *user);
 typedef int (ast_vm_test_destroy_user_fn)(const char *context, const char *user);
@@ -652,16 +703,16 @@ int ast_app_inboxcount(const char *mailboxes, int *newmsgs, int *oldmsgs);
 int ast_app_inboxcount2(const char *mailboxes, int *urgentmsgs, int *newmsgs, int *oldmsgs);
 
 /*!
- * \brief Given a mailbox and context, play that mailbox owner's name to the channel specified
- * \param[in] chan Channel on which to play the name
- * \param[in] mailbox Mailbox number from which to retrieve the recording
- * \param[in] context Mailbox context from which to locate the mailbox number
+ * \brief Play a recorded user name for the mailbox to the specified channel.
+ *
+ * \param chan Where to play the recorded name file.
+ * \param mailbox_id The mailbox name.
+ *
  * \retval 0 Name played without interruption
  * \retval dtmf ASCII value of the DTMF which interrupted playback.
  * \retval -1 Unable to locate mailbox or hangup occurred.
- * \since 1.6.1
  */
-int ast_app_sayname(struct ast_channel *chan, const char *mailbox, const char *context);
+int ast_app_sayname(struct ast_channel *chan, const char *mailbox_id);
 
 /*!
  * \brief Get the number of messages in a given mailbox folder
index 3c2f33c..822fe6c 100644 (file)
@@ -519,6 +519,66 @@ void ast_vm_unregister(const char *module_name)
        ao2_cleanup(table);
 }
 
+/*! \brief The container for the voicemail greeter provider */
+static AO2_GLOBAL_OBJ_STATIC(vm_greeter_provider);
+
+/*! Voicemail greeter not registered warning */
+static int vm_greeter_warnings;
+
+int ast_vm_greeter_is_registered(void)
+{
+       struct ast_vm_greeter_functions *table;
+       int is_registered;
+
+       table = ao2_global_obj_ref(vm_greeter_provider);
+       is_registered = table ? 1 : 0;
+       ao2_cleanup(table);
+       return is_registered;
+}
+
+int __ast_vm_greeter_register(const struct ast_vm_greeter_functions *vm_table, struct ast_module *module)
+{
+       RAII_VAR(struct ast_vm_greeter_functions *, table, NULL, ao2_cleanup);
+
+       if (!vm_table->module_name) {
+               ast_log(LOG_ERROR, "Voicemail greeter provider missing required information.\n");
+               return -1;
+       }
+       if (vm_table->module_version != VM_GREETER_MODULE_VERSION) {
+               ast_log(LOG_ERROR, "Voicemail greeter provider '%s' has incorrect version\n",
+                       vm_table->module_name);
+               return -1;
+       }
+
+       table = ao2_global_obj_ref(vm_greeter_provider);
+       if (table) {
+               ast_log(LOG_WARNING, "Voicemail greeter provider already registered by %s.\n",
+                       table->module_name);
+               return -1;
+       }
+
+       table = ao2_alloc_options(sizeof(*table), NULL, AO2_ALLOC_OPT_LOCK_NOLOCK);
+       if (!table) {
+               return -1;
+       }
+       *table = *vm_table;
+       table->module = module;
+
+       ao2_global_obj_replace_unref(vm_greeter_provider, table);
+       return 0;
+}
+
+void ast_vm_greeter_unregister(const char *module_name)
+{
+       struct ast_vm_greeter_functions *table;
+
+       table = ao2_global_obj_ref(vm_greeter_provider);
+       if (table && !strcmp(table->module_name, module_name)) {
+               ao2_global_obj_release(vm_greeter_provider);
+       }
+       ao2_cleanup(table);
+}
+
 #ifdef TEST_FRAMEWORK
 static ast_vm_test_create_user_fn *ast_vm_test_create_user_func = NULL;
 static ast_vm_test_destroy_user_fn *ast_vm_test_destroy_user_func = NULL;
@@ -546,7 +606,8 @@ static void vm_warn_no_provider(void)
 
 #define VM_API_CALL(res, api_call, api_parms)                                                          \
        do {                                                                                                                                    \
-               struct ast_vm_functions *table = ao2_global_obj_ref(vm_provider);       \
+               struct ast_vm_functions *table;                                                                         \
+               table = ao2_global_obj_ref(vm_provider);                                                        \
                if (!table) {                                                                                                           \
                        vm_warn_no_provider();                                                                                  \
                } else if (table->api_call) {                                                                           \
@@ -557,6 +618,27 @@ static void vm_warn_no_provider(void)
                ao2_cleanup(table);                                                                                                     \
        } while (0)
 
+static void vm_greeter_warn_no_provider(void)
+{
+       if (vm_greeter_warnings++ % 10 == 0) {
+               ast_verb(3, "No voicemail greeter provider registered.\n");
+       }
+}
+
+#define VM_GREETER_API_CALL(res, api_call, api_parms)                                          \
+       do {                                                                                                                                    \
+               struct ast_vm_greeter_functions *table;                                                         \
+               table = ao2_global_obj_ref(vm_greeter_provider);                                        \
+               if (!table) {                                                                                                           \
+                       vm_greeter_warn_no_provider();                                                                  \
+               } else if (table->api_call) {                                                                           \
+                       ast_module_ref(table->module);                                                                  \
+                       (res) = table->api_call api_parms;                                                              \
+                       ast_module_unref(table->module);                                                                \
+               }                                                                                                                                       \
+               ao2_cleanup(table);                                                                                                     \
+       } while (0)
+
 int ast_app_has_voicemail(const char *mailboxes, const char *folder)
 {
        int res = 0;
@@ -612,11 +694,11 @@ int ast_app_inboxcount2(const char *mailboxes, int *urgentmsgs, int *newmsgs, in
        return res;
 }
 
-int ast_app_sayname(struct ast_channel *chan, const char *mailbox, const char *context)
+int ast_app_sayname(struct ast_channel *chan, const char *mailbox_id)
 {
        int res = -1;
 
-       VM_API_CALL(res, sayname, (chan, mailbox, context));
+       VM_GREETER_API_CALL(res, sayname, (chan, mailbox_id));
        return res;
 }