diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index 306e6e84b4..47f755e5f8 100644 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -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; } diff --git a/apps/app_directory.c b/apps/app_directory.c index 3afb19f29d..350401e464 100644 --- a/apps/app_directory.c +++ b/apps/app_directory.c @@ -26,7 +26,6 @@ */ /*** MODULEINFO - app_voicemail core ***/ #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)) { diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 891d233605..d392dd515b 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -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)); diff --git a/include/asterisk/app.h b/include/asterisk/app.h index 65d74dcd13..d5a0e27b5a 100644 --- a/include/asterisk/app.h +++ b/include/asterisk/app.h @@ -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 diff --git a/main/app.c b/main/app.c index 3c2f33c51f..822fe6c454 100644 --- a/main/app.c +++ b/main/app.c @@ -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; }