[asterisk-commits] mjordan: branch mjordan/voicemail_refactor_11_10_19 r341860 - in /team/mjorda...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Fri Oct 21 15:14:19 CDT 2011
Author: mjordan
Date: Fri Oct 21 15:14:17 2011
New Revision: 341860
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=341860
Log: (empty)
Added:
team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/
team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/include/
team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/include/voicemail.h (with props)
team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/include/voicemail_test.h (with props)
team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/vm_config_parser.c (with props)
Modified:
team/mjordan/voicemail_refactor_11_10_19/apps/Makefile
Modified: team/mjordan/voicemail_refactor_11_10_19/apps/Makefile
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/voicemail_refactor_11_10_19/apps/Makefile?view=diff&rev=341860&r1=341859&r2=341860
==============================================================================
--- team/mjordan/voicemail_refactor_11_10_19/apps/Makefile (original)
+++ team/mjordan/voicemail_refactor_11_10_19/apps/Makefile Fri Oct 21 15:14:17 2011
@@ -29,9 +29,13 @@
clean::
rm -f confbridge/*.o confbridge/*.i
+ rm -f voicemail/*.o voicemail/*.i
$(if $(filter app_confbridge,$(EMBEDDED_MODS)),modules.link,app_confbridge.so): $(subst .c,.o,$(wildcard confbridge/*.c))
$(subst .c,.o,$(wildcard confbridge/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,app_confbridge)
+
+$(if $(filter app_voicemail,$(EMBEDDED_MODS)),modules.link,app_voicemail.so): $(subst .c,.o,$(wildcard voicemail/*.c))
+$(subst .c,.o,$(wildcard voicemail/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,app_voicemail)
ifneq ($(findstring $(OSARCH), mingw32 cygwin ),)
LIBS+= -lres_features.so -lres_ael_share.so -lres_monitor.so -lres_speech.so
Added: team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/include/voicemail.h
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/include/voicemail.h?view=auto&rev=341860
==============================================================================
--- team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/include/voicemail.h (added)
+++ team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/include/voicemail.h Fri Oct 21 15:14:17 2011
@@ -1,0 +1,226 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 1999 - 2011, Digium, Inc.
+ *
+ * Mark Spencer <markster at digium.com>
+ *
+ * See http://www.asterisk.org for more information about
+ * the Asterisk project. Please do not directly contact
+ * any of the maintainers of this project for assistance;
+ * the project provides a web site, mailing lists and IRC
+ * channels for your use.
+ *
+ * This program is free software, distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+
+/*!
+ * \file
+ * \author Matt Jordan <mjordan at digium.com>
+ * \brief Comedian Mail - Voicemail System
+ *
+ */
+
+#ifndef VOICEMAIL_H_
+#define VOICEMAIL_H_
+
+#include "asterisk.h"
+#include "asterisk/channel.h"
+
+
+#define MAX_ADSI_FIELDS 4
+
+#define MAX_DTMF_LENGTH 16
+
+#define MAX_FORMAT_LENGTH 64
+
+#define MAX_NUM_CID_CONTEXTS 10
+
+enum vm_global_flags {
+ VM_REVIEW = (1 << 0), /*!< After recording, permit the caller to review the recording before saving */
+ VM_OPERATOR = (1 << 1), /*!< Allow 0 to be pressed to go to 'o' extension */
+ VM_SAYCID = (1 << 2), /*!< Repeat the CallerID info during envelope playback */
+ VM_SVMAIL = (1 << 3), /*!< Allow the user to compose a new VM from within VoicemailMain */
+ VM_ENVELOPE = (1 << 4), /*!< Play the envelope information (who-from, time received, etc.) */
+ VM_SAYDURATION = (1 << 5), /*!< Play the length of the message during envelope playback */
+ VM_SKIPAFTERCMD = (1 << 6), /*!< After deletion, assume caller wants to go to the next message */
+ VM_FORCENAME = (1 << 7), /*!< Have new users record their name */
+ VM_FORCEGREET = (1 << 8), /*!< Have new users record their greetings */
+ VM_PBXSKIP = (1 << 9), /*!< Skip the [PBX] preamble in the Subject line of emails */
+ VM_DIRECFORWARD = (1 << 10), /*!< Permit caller to use the Directory app for selecting to which mailbox to forward a VM */
+ VM_ATTACH = (1 << 11), /*!< Attach message to voicemail notifications? */
+ VM_DELETE = (1 << 12), /*!< Delete message after sending notification */
+ VM_ALLOCED = (1 << 13), /*!< Structure was malloc'ed, instead of placed in a return (usually static) buffer */
+ VM_SEARCH = (1 << 14), /*!< Search all contexts for a matching mailbox */
+ VM_TEMPGREETWARN = (1 << 15), /*!< Remind user tempgreeting is set */
+ VM_MOVEHEARD = (1 << 16), /*!< Move a "heard" message to Old after listening to it */
+ VM_MESSAGEWRAP = (1 << 17), /*!< Wrap around from the last message to the first, and vice-versa */
+ VM_FWDURGAUTO = (1 << 18), /*!< Autoset of Urgent flag on forwarded Urgent messages set globally */
+ VM_POLLMAILBOXES = (1 << 19) /*!< If set, poll mailboxes for changes */
+};
+
+enum vm_passwordlocation {
+ VM_OPT_PWLOC_VOICEMAILCONF = 0, /*!< The password should be obtained from voicemail.conf */
+ VM_OPT_PWLOC_SPOOLDIR = 1, /*!< The password should be obtained from secret.conf, in the user's spool directory */
+ VM_OPT_PWLOC_USERSCONF = 2, /*!< The password should be obtained from users.conf */
+};
+
+enum vm_password_change_flags {
+ VM_OPT_PWCHG_INTERNAL = (1 << 0),
+ VM_OPT_PWCHG_EXTERNAL = (1 << 1),
+};
+
+struct vm_sound_config {
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(vm_password);
+ AST_STRING_FIELD(vm_newpassword);
+ AST_STRING_FIELD(vm_invalid_password);
+ AST_STRING_FIELD(vm_password_changed);
+ AST_STRING_FIELD(vm_reenter_password);
+ AST_STRING_FIELD(vm_mismatch);
+ AST_STRING_FIELD(vm_pls_try_again);
+ );
+};
+
+struct vm_listen_control_config {
+ char listen_control_forward_key[MAX_DTMF_LENGTH];
+ char listen_control_reverse_key[MAX_DTMF_LENGTH];
+ char listen_control_pause_key[MAX_DTMF_LENGTH];
+ char listen_control_restart_key[MAX_DTMF_LENGTH];
+ char listen_control_stop_key[MAX_DTMF_LENGTH];
+};
+
+struct vm_smdi_config {
+ unsigned int enabled;
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(smdi_interface);
+ );
+};
+
+struct vm_adsi_config {
+ unsigned char adsifdn[MAX_ADSI_FIELDS];
+ unsigned char adsisec[MAX_ADSI_FIELDS];
+ unsigned int adsiver;
+};
+
+/*! Voicemail time zones */
+struct vm_timezone {
+ AST_LIST_ENTRY(vm_zone) list;
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(name); /*!< The name of the timezone */
+ AST_STRING_FIELD(timezone); /*!< The timezone code */
+ AST_STRING_FIELD(msg_format); /*!< Formatting code for the timezone */
+ );
+};
+
+struct ast_vm_user {
+ char context[AST_MAX_CONTEXT]; /*!< Voicemail context */
+ char mailbox[AST_MAX_EXTENSION]; /*!< Mailbox id, unique within vm context */
+ char language[MAX_LANGUAGE]; /*!< Config: Language setting */
+ char callback[AST_MAX_CONTEXT]; /*!< Callback context */
+ char dialout[AST_MAX_CONTEXT]; /*!< Dialout context */
+ char uniqueid[80]; /*!< Unique integer identifier TODO: make this an integer? */
+ char exit[AST_MAX_CONTEXT]; /*!< Context to exit out to */
+ char attachfmt[MAX_FORMAT_LENGTH]; /*!< Attachment format */
+ int min_say_duration; /*!< Minimum number of seconds for say */
+ int min_message_duration; /*!< Minimum number of seconds per message for this mailbox */
+ int max_messages; /*!< Maximum number of msgs per folder for this mailbox */
+ int max_deleted_messages; /*!< Maximum number of deleted msgs saved for this mailbox */
+ int max_message_duration; /*!< Maximum number of seconds per message for this mailbox */
+ int hash_key;
+ enum vm_passwordlocation password_location; /*!< Storage location of the password */
+ double volgain; /*!< Volume gain for voicemails sent via email */
+ struct ast_flags flags; /*!< VM_ flags */
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(fullname);
+ AST_STRING_FIELD(password);
+ AST_STRING_FIELD(email_address);
+ AST_STRING_FIELD(email_subject);
+ AST_STRING_FIELD(email_body);
+ AST_STRING_FIELD(pager_address);
+ AST_STRING_FIELD(pager_subject);
+ AST_STRING_FIELD(pager_body);
+ AST_STRING_FIELD(email_from_address);
+ AST_STRING_FIELD(mail_command);
+ AST_STRING_FIELD(zonetag);
+ AST_STRING_FIELD(timezone);
+ );
+};
+
+struct vm_config {
+ double volgain;
+ unsigned int max_silence;
+ unsigned int max_deleted_messages;
+ unsigned int max_messages;
+ unsigned int min_say_duration;
+ unsigned int min_message_duration;
+ unsigned int max_message_duration;
+ unsigned int max_message_greeting_length;
+ unsigned int skip_ms;
+ unsigned int min_password_length;
+ unsigned int silence_threshold;
+ unsigned int poll_frequency;
+ unsigned int max_logins;
+ enum vm_passwordlocation password_location;
+ char attach_format[MAX_FORMAT_LENGTH];
+ char format[MAX_FORMAT_LENGTH];
+ char dial_out_context[AST_MAX_CONTEXT];
+ char callback_context[AST_MAX_CONTEXT];
+ char op_exit_context[AST_MAX_CONTEXT];
+ char default_users_context[AST_MAX_CONTEXT];
+ char cid_internal_contexts[MAX_NUM_CID_CONTEXTS][AST_MAX_CONTEXT];
+ char extern_notify_cmd[PATH_MAX];
+ char extern_pass_cmd[PATH_MAX];
+ char extern_pass_check_cmd[PATH_MAX];
+ char directory_intro_path[PATH_MAX];
+ struct vm_sound_config * sound_config;
+ struct vm_listen_control_config * listen_control_config;
+ struct vm_smdi_config * smdi_config;
+ struct vm_adsi_config * adsi_config;
+ struct ast_flags globalflags;
+ struct ast_flags passwordflags;
+ AST_DECLARE_STRING_FIELDS(
+ AST_STRING_FIELD(mail_command);
+ AST_STRING_FIELD(email_from_string);
+ AST_STRING_FIELD(email_server);
+ AST_STRING_FIELD(email_date_format);
+ AST_STRING_FIELD(email_subject);
+ AST_STRING_FIELD(email_body);
+ AST_STRING_FIELD(pager_from_string);
+ AST_STRING_FIELD(pager_date_format);
+ AST_STRING_FIELD(pager_subject);
+ AST_STRING_FIELD(pager_body);
+ AST_STRING_FIELD(zonetag);
+ AST_STRING_FIELD(locale);
+ AST_STRING_FIELD(charset);
+ );
+};
+
+/*! \brief Obtain a reference to the current voicemail configuration
+ *
+ * \note The vm_config object is a ref counted object. Calling this method automatically
+ * increases that reference count by 1 - when finished with the object, the caller of this
+ * method must decrease the reference count.
+ *
+ * \note The voicemail configuration must be loaded before calling this method. See
+ * vm_get_config(void).
+ *
+ * \returns Pointer to the voicemail configuration object
+ */
+struct vm_config *vm_get_config(void);
+
+/*! \brief Load the voicemail configuration, the users, and timezones
+ * \param reload If 0, load the configuration for the first time. If 1, reload the configuration.
+ *
+ * \returns 0 on success
+ * \returns 1 on error during load
+ */
+int vm_load_config(int reload);
+
+struct ast_vm_user *vm_get_user(const char *context, const char *mailbox);
+
+struct vm_timezone *vm_get_timezone(const char *timezone);
+
+#endif /* VOICEMAIL_H_ */
Propchange: team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/include/voicemail.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/include/voicemail.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/include/voicemail.h
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/include/voicemail_test.h
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/include/voicemail_test.h?view=auto&rev=341860
==============================================================================
--- team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/include/voicemail_test.h (added)
+++ team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/include/voicemail_test.h Fri Oct 21 15:14:17 2011
@@ -1,0 +1,59 @@
+/*
+ * voicemail_test.h
+ *
+ * Created on: Oct 21, 2011
+ * Author: mjordan
+ */
+
+#ifndef TEST_VOICEMAIL_H_
+#define TEST_VOICEMAIL_H_
+
+#include "asterisk.h"
+#include "asterisk/test.h"
+
+#define VM_TEST_MEM_EQUAL(expected, actual, upperlimit) \
+ do { \
+ int i = 0; \
+ for (; i < upperlimit; i++) { \
+ if (memcmp(&(expected[i]), &(actual[i]), 1)) { \
+ ast_test_status_update(test, "Test failed for parameter %s: Expected [%02X], Actual [%02X] (Position %d)\n", #actual, expected[i], actual[i], i); \
+ result = AST_TEST_FAIL; \
+ break; \
+ }}} while (0)
+
+#define VM_TEST_STRING_EQUAL(expected, actual) \
+ do { \
+ if (strncmp(expected, actual, sizeof(expected))) { \
+ ast_test_status_update(test, "Test failed for parameter %s: Expected [%s], Actual [%s]\n", #actual, expected, actual); \
+ result = AST_TEST_FAIL; \
+ } } while (0)
+
+#define VM_TEST_STRING_NOT_EQUAL(expected, actual) \
+ do { \
+ if (!strncmp(expected, actual, sizeof(expected))) { \
+ ast_test_status_update(test, "Test failed for parameter %s: Expected NOT [%s], Actual [%s]\n", #actual, expected, actual); \
+ result = AST_TEST_FAIL; \
+ } } while (0)
+
+#define VM_TEST_NUMERIC_NOT_EQUAL(expected, actual) \
+ do { \
+ if (expected == actual) { \
+ ast_test_status_update(test, "Test failed for parameter %s: Expected NOT [%d], Actual [%d]\n", #actual, (int)expected, (int)actual); \
+ result = AST_TEST_FAIL; \
+ } } while (0)
+
+#define VM_TEST_NUMERIC_EQUAL(expected, actual) \
+ do { \
+ if (expected != actual) { \
+ ast_test_status_update(test, "Test failed for parameter %s: Expected [%d], Actual [%d]\n", #actual, (int)expected, (int)actual); \
+ result = AST_TEST_FAIL; \
+ } } while (0)
+
+void vm_register_config_tests(void);
+
+void vm_unregister_config_tests(void);
+
+/* TODO: add other backends / test entry points */
+
+#endif /* TEST_VOICEMAIL_H_ */
+
Propchange: team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/include/voicemail_test.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/include/voicemail_test.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/include/voicemail_test.h
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/vm_config_parser.c
URL: http://svnview.digium.com/svn/asterisk/team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/vm_config_parser.c?view=auto&rev=341860
==============================================================================
--- team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/vm_config_parser.c (added)
+++ team/mjordan/voicemail_refactor_11_10_19/apps/voicemail/vm_config_parser.c Fri Oct 21 15:14:17 2011
@@ -1,0 +1,1746 @@
+
+#include "asterisk.h"
+
+#include "asterisk/lock.h"
+#include "asterisk/paths.h"
+#include "asterisk/dsp.h"
+#include "include/voicemail.h"
+#include "include/voicemail_test.h"
+
+#define VOICEMAIL_CONFIG "voicemail.conf"
+#define USER_CONFIG "users.conf"
+#define SECRET_CONFIG "secret.conf"
+
+/* Forward declarations */
+static int timezone_hash_fn(const void *obj, const int flags);
+static int timezone_cmp_fn(void *obj, void *arg, int flags);
+static int voicemail_user_hash_fn(const void *obj, const int flags);
+static int voicemail_user_cmp_fn(void *obj, void *arg, int flags);
+static int init_configuration(void);
+static int is_valid_dtmf(const char *key);
+static int load_voicemail_options(struct vm_config *vmcfg, struct ast_config *cfg);
+static int load_timezones(const struct vm_config * const vmcfg, struct ast_config *cfg);
+static int load_voicemail_users(const struct vm_config * const vmcfg, struct ast_config *ucfg, int load_from_variable);
+static void populate_default_vm_config_options(struct vm_config *vmcfg);
+static void populate_default_listen_control(struct vm_config *vmcfg);
+static void populate_default_sounds(struct vm_config *vmcfg);
+static void populate_default_adsi(struct vm_config *vmcfg);
+static void populate_default_user_options(const struct vm_config * const vmcfg, struct ast_vm_user *vmu);
+static void populate_vmu_from_variable(const struct vm_config * const vmcfg, struct ast_vm_user *vmu, const char *context, struct ast_variable *var);
+static void populate_vmu_from_category(const struct vm_config * const vmcfg, struct ast_vm_user *vmu, struct ast_config *ucfg, const char *cat);
+static void apply_user_option(const struct vm_config * const vmcfg, struct ast_vm_user *vmu, const char *name, const char *value);
+static int validate_user(const struct vm_config * const vmcfg, struct ast_vm_user *vmu);
+static struct vm_config * voicemail_config_new(void);
+static void voicemail_config_destroy(void *obj);
+static struct ast_vm_user *voicemail_user_new(void);
+static void voicemail_user_destroy(void *obj);
+static struct vm_timezone *timezone_new(void);
+static void timezone_destroy(void *obj);
+
+/* custom password sounds */
+static const char *default_sound_vm_password = "vm-password";
+static const char *default_sound_vm_newpassword = "vm-newpassword";
+static const char *default_sound_vm_password_changed = "vm-passchanged";
+static const char *default_sound_vm_reenter_password = "vm-reenterpassword";
+static const char *default_sound_vm_mismatch = "vm-mismatch";
+static const char *default_sound_vm_invalid_password = "vm-invalid-password";
+static const char *default_sound_vm_pls_try_again = "vm-pls-try-again";
+
+/* DTMF control defaults */
+static const char *default_listen_control_forward_key = "#";
+static const char *default_listen_control_reverse_key = "*";
+static const char *default_listen_control_pause_key = "0";
+static const char *default_listen_control_restart_key = "2";
+static const char *default_listen_control_stop_key = "13456789";
+static const char *valid_dtmf = "1234567890*#ABCD";
+
+/*static const char *default_character_set = "ISO-8859-1";*/
+static const char *default_general_context = "general";
+static const char *default_timezone_context = "zonemessages";
+/*static const char *default_smdi_interface = "/dev/ttyS0";*/
+static const char *default_format_string = "wav";
+static const char *default_asterisk_username = "asterisk";
+static const char *default_users_context = "default";
+static char default_email_date_format[32] = "%A, %B %d, %Y at %r";
+static char default_pager_date_format[32] = "%A, %B %d, %Y at %r";
+static const char *default_mail_command = "/usr/sbin/sendmail -t";
+
+static const unsigned int default_skip_ms = 3000;
+static const unsigned int default_max_logins = 3;
+static const unsigned int default_min_say_duration = 2;
+static const unsigned int default_poll_frequency = 30;
+static const unsigned int default_max_messages = 100;
+static const unsigned int default_min_password_length = 0;
+static const unsigned int default_max_messages_limit = 9999;
+
+static unsigned char default_adsifdn[4] = "\x00\x00\x00\x0F";
+static unsigned char default_adsisec[4] = "\x9B\xDB\xF7\xAC";
+static unsigned int default_adsiver = 1;
+
+/*! \internal \brief The base directory for voicemail user's files */
+static char voicemail_spool_directory[PATH_MAX];
+
+/*! \internal \brief The voicemail configuration object */
+static struct vm_config *config = NULL;
+
+/*! \internal \brief The timezones container */
+static struct ao2_container *timezones = NULL;
+
+/*! \internal \brief The voicemail users container */
+static struct ao2_container *voicemail_users = NULL;
+
+/*! \internal \brief The mutex that protects access to the config object */
+AST_MUTEX_DEFINE_STATIC(config_lock);
+
+struct ast_vm_user *vm_get_user(const char *context, const char *mailbox)
+{
+ struct ast_vm_user *tmp_vmu;
+ struct ast_vm_user *vmu = NULL;
+
+ if (!(tmp_vmu = voicemail_user_new())) {
+ ast_log(AST_LOG_ERROR, "Failed to allocate sufficient memory for ast_vm_user object\n");
+ } else {
+ ast_copy_string(tmp_vmu->context, context, sizeof(tmp_vmu->context));
+ ast_copy_string(tmp_vmu->mailbox, mailbox, sizeof(tmp_vmu->mailbox));
+ vmu = ao2_find(voicemail_users, tmp_vmu, OBJ_POINTER);
+ ao2_ref(tmp_vmu, -1);
+ }
+
+ return vmu;
+}
+
+struct vm_timezone *vm_get_timezone(const char *timezone)
+{
+ struct vm_timezone *tmp_tmz;
+ struct vm_timezone *tmz = NULL;
+
+ if (!(tmp_tmz = timezone_new())) {
+ ast_log(AST_LOG_ERROR, "Failed to allocate sufficient memory for vm_timezone object\n");
+ } else {
+ ast_string_field_set(tmp_tmz, name, timezone);
+ tmz = ao2_find(timezones, tmp_tmz, OBJ_POINTER);
+ ao2_ref(tmz, -1);
+ }
+
+ return tmz;
+}
+
+struct vm_config *vm_get_config(void)
+{
+ struct vm_config *vmcfg;
+
+ ast_mutex_lock(&config_lock);
+ if (!config) {
+ ast_log(AST_LOG_WARNING, "Attempted to retrieve NULL voicemail configuration object\n");
+ vmcfg = NULL;
+ } else {
+ ao2_ref(config, 1);
+ vmcfg = config;
+ }
+ ast_mutex_unlock(&config_lock);
+
+ return vmcfg;
+}
+
+int vm_load_config(int reload)
+{
+ int res = 0;
+ struct vm_config *vmcfg = NULL;
+ struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
+ struct ast_config *cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
+ struct ast_config *ucfg = ast_config_load(USER_CONFIG, config_flags);
+
+ if (!(vmcfg = voicemail_config_new())) {
+ ast_log(AST_LOG_ERROR, "Failed to allocate sufficient memory for vm_config object\n");
+ return 1;
+ }
+
+ if (!reload) {
+ if (init_configuration()) {
+ return 1;
+ }
+ }
+
+ /* If both configs are unchanged exit; otherwise load both */
+ if (cfg == CONFIG_STATUS_FILEUNCHANGED && ucfg == CONFIG_STATUS_FILEUNCHANGED) {
+ return 0;
+ } else if (cfg == CONFIG_STATUS_FILEUNCHANGED && ucfg != CONFIG_STATUS_FILEUNCHANGED) {
+ ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
+ cfg = ast_config_load(VOICEMAIL_CONFIG, config_flags);
+ } else if (cfg != CONFIG_STATUS_FILEUNCHANGED && ucfg == CONFIG_STATUS_FILEUNCHANGED) {
+ ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
+ ucfg = ast_config_load(USER_CONFIG, config_flags);
+ }
+
+ if (!cfg || cfg == CONFIG_STATUS_FILEINVALID) {
+ if (ucfg && ucfg != CONFIG_STATUS_FILEINVALID) {
+ ast_config_destroy(ucfg);
+ }
+ ast_log(AST_LOG_ERROR, "Config file " VOICEMAIL_CONFIG " is in an invalid format. Aborting.\n");
+ return 1;
+ }
+
+ if (ucfg == CONFIG_STATUS_FILEINVALID) {
+ ast_log(AST_LOG_WARNING, "Config file " USER_CONFIG " is in an invalid format. Avoiding.\n");
+ ucfg = NULL;
+ }
+
+ populate_default_vm_config_options(vmcfg);
+
+ if (load_voicemail_options(vmcfg, cfg)) {
+ ast_log(AST_LOG_ERROR, "Failed to parse voicemail configuration\n");
+ ast_config_destroy(cfg);
+ ast_config_destroy(ucfg);
+ return 1;
+ }
+
+ /* From here on, the loading becomes destructive to the configuration that was previously loaded */
+ res |= load_timezones(vmcfg, cfg);
+
+ res |= load_voicemail_users(vmcfg, cfg, 1);
+ /* If a user config exists, load users from there as well */
+ if (ucfg) {
+ res |= load_voicemail_users(vmcfg, ucfg, 0);
+ }
+
+ /* Set the global config object to the one we just created */
+ ast_mutex_lock(&config_lock);
+ if (reload) {
+ ao2_ref(config, -1);
+ }
+ config = vmcfg;
+ ast_mutex_unlock(&config_lock);
+
+ ast_config_destroy(cfg);
+ ast_config_destroy(ucfg);
+
+ return res;
+}
+
+/*!
+ * \internal
+ * \brief Hash function used for timezones
+ */
+static int timezone_hash_fn(const void *obj, const int flags)
+{
+ const struct vm_timezone *tmz = obj;
+ return ast_str_case_hash(tmz->name);
+}
+
+/*!
+ * \internal
+ * \brief Comparison function used for timezones
+ */
+static int timezone_cmp_fn(void *obj, void *arg, int flags)
+{
+ const struct vm_timezone *tmz_left = obj;
+ const struct vm_timezone *tmz_right = arg;
+
+ return (!strcasecmp(tmz_left->name, tmz_right->name) ? CMP_MATCH | CMP_STOP : 0);
+}
+
+/*!
+ * \internal
+ * \brief Hash function used for voicemail users
+ */
+static int voicemail_user_hash_fn(const void *obj, const int flags)
+{
+ const struct ast_vm_user *vmu = obj;
+ return vmu->hash_key;
+}
+
+/*!
+ * \internal
+ * \brief Comparison function used for voicemail users
+ */
+static int voicemail_user_cmp_fn(void *obj, void *arg, int flags)
+{
+ const struct ast_vm_user *vmu_left = obj;
+ const struct ast_vm_user *vmu_right = arg;
+
+ if (vmu_left->hash_key == vmu_right->hash_key) {
+ return CMP_MATCH | CMP_STOP;
+ } else {
+ return 0;
+ }
+}
+
+/*!
+ * \internal
+ * \brief Determines if a DTMF key entered is valid.
+ * \param key The character to be compared. expects a single character. Though is capable of handling a string, this is internally copies using ast_strdupa.
+ *
+ * Tests the character entered against the set of valid DTMF characters.
+ * \return 1 if the character entered is a valid DTMF digit
+ * \return 0 if the character is invalid.
+ */
+static int is_valid_dtmf(const char *key)
+{
+ int i;
+ char *local_key = ast_strdupa(key);
+
+ for (i = 0; i < strlen(key); ++i) {
+ if (!strchr(valid_dtmf, *local_key)) {
+ ast_log(AST_LOG_WARNING, "Invalid DTMF key \"%c\" detected\n", *local_key);
+ return 0;
+ }
+ local_key++;
+ }
+ return 1;
+}
+
+/*! \internal \brief Initialize the containers and other objects needed for loading the configuration
+ * \returns 1 on failure
+ * \returns 0 on success
+ */
+static int init_configuration(void)
+{
+ snprintf(voicemail_spool_directory, sizeof(voicemail_spool_directory), "%s/voicemail/", ast_config_AST_SPOOL_DIR);
+
+ if (!(timezones = ao2_container_alloc(283, timezone_hash_fn, timezone_cmp_fn))) {
+ ast_log(AST_LOG_ERROR, "Failed to allocate sufficient memory for timezones container\n");
+ return 1;
+ }
+ if (!(voicemail_users = ao2_container_alloc(283, voicemail_user_hash_fn, voicemail_user_cmp_fn))) {
+ ast_log(AST_LOG_ERROR, "Failed to allocate sufficient memory for voicemail users container\n");
+ return 1;
+ }
+ return 0;
+}
+
+/*! \internal \brief Load the voicemail configuration options
+ * \param vmcfg The voicemail configuration object to populate
+ * \param cfg The Asterisk configuration object containing the values
+ * \returns 1 on failure
+ * \returns 0 on success
+ */
+static int load_voicemail_options(struct vm_config *vmcfg, struct ast_config *cfg)
+{
+ struct ast_variable *var;
+ int cidcounter = 0;
+ char * tempcontext;
+ char * tempvalue;
+ int i;
+ int tmp_adsi_buffer[MAX_ADSI_FIELDS];
+ struct ast_category *cat = ast_category_get(cfg, default_general_context);
+
+ if (!cat) {
+ ast_log(AST_LOG_ERROR, "No %s category defined in voicemail configuration\n", default_general_context);
+ return 1;
+ }
+
+ for (var = ast_category_first(cat); var; var = var->next) {
+ ast_debug(5, "Parsing voicemail configuration parameter [%s]: value [%s]", var->name, var->value);
+ if (!strcasecmp(var->name, "userscontext")) {
+ ast_copy_string(vmcfg->default_users_context, var->value, sizeof(vmcfg->default_users_context));
+ } else if (!strcasecmp(var->name, "attachfmt")) {
+ ast_copy_string(vmcfg->attach_format, var->value, sizeof(vmcfg->attach_format));
+ } else if (!strcasecmp(var->name, "directoryintro")) {
+ ast_copy_string(vmcfg->directory_intro_path, var->value, sizeof(vmcfg->directory_intro_path));
+ } else if (!strcasecmp(var->name, "attach")) {
+ ast_set2_flag(&(vmcfg->globalflags), ast_true(var->value), VM_ATTACH);
+ } else if (!strcasecmp(var->name, "searchcontexts")) {
+ ast_set2_flag(&(vmcfg->globalflags), ast_true(var->value), VM_SEARCH);
+ } else if (!strcasecmp(var->name, "volgain")) {
+ if (sscanf(var->value, "%30lf", &(vmcfg->volgain)) < 1) {
+ ast_log(AST_LOG_WARNING, "Failed to parse %s with value %s into parameter volgain\n", var->name, var->value);
+ }
+ } else if (!strcasecmp(var->name, "mailcmd")) {
+ ast_string_field_set(vmcfg, mail_command, var->value);
+ } else if (!strcasecmp(var->name, "maxsilence")) {
+ if (sscanf(var->value, "%30ud", &(vmcfg->max_silence)) < 1) {
+ ast_log(AST_LOG_WARNING, "Failed to parse %s with value %s into parameter max_silence\n", var->name, var->value);
+ }
+ } else if (!strcasecmp(var->name, "maxmsg")) {
+ if (sscanf(var->value, "%30ud", &(vmcfg->max_messages)) < 1) {
+ ast_log(AST_LOG_WARNING, "Failed to parse %s with value %s into parameter max_messages\n", var->name, var->value);
+ }
+ } else if (!strcasecmp(var->name, "backupdeleted")) {
+ /* Field can be either an absolute number of messages to delete, or a 'yes' / 'no' value */
+ if (sscanf(var->value, "%30ud", &(vmcfg->max_deleted_messages)) < 1) {
+ if (ast_true(var->value)) {
+ vmcfg->max_deleted_messages = default_max_messages;
+ } else {
+ vmcfg->max_deleted_messages = 0;
+ }
+ }
+ } else if (!strcasecmp(var->name, "emaildateformat")) {
+ ast_string_field_set(vmcfg, email_date_format, var->value);
+ } else if (!strcasecmp(var->name, "emailsubject")) {
+ ast_string_field_set(vmcfg, email_subject, var->value);
+ } else if (!strcasecmp(var->name, "emailbody")) {
+ ast_string_field_set(vmcfg, email_body, var->value);
+ } else if (!strcasecmp(var->name, "fromstring")) {
+ ast_string_field_set(vmcfg, email_from_string, var->value);
+ } else if (!strcasecmp(var->name, "charset")) {
+ ast_string_field_set(vmcfg, charset, var->value);
+ } else if (!strcasecmp(var->name, "tz")) {
+ ast_string_field_set(vmcfg, zonetag, var->value);
+ } else if (!strcasecmp(var->name, "locale")) {
+ ast_string_field_set(vmcfg, locale, var->value);
+ } else if (!strcasecmp(var->name, "pagerdateformat")) {
+ ast_string_field_set(vmcfg, pager_date_format, var->value);
+ } else if (!strcasecmp(var->name, "pagerfromstring")) {
+ ast_string_field_set(vmcfg, pager_from_string, var->value);
+ } else if (!strcasecmp(var->name, "pagersubject")) {
+ ast_string_field_set(vmcfg, pager_subject, var->value);
+ } else if (!strcasecmp(var->name, "pagerbody")) {
+ ast_string_field_set(vmcfg, pager_body, var->value);
+ } else if (!strcasecmp(var->name, "externpass")) {
+ ast_copy_string(vmcfg->extern_pass_cmd, var->value, sizeof(vmcfg->extern_pass_cmd));
+ ast_set2_flag(&(vmcfg->passwordflags), 1, VM_OPT_PWCHG_EXTERNAL);
+ ast_set2_flag(&(vmcfg->passwordflags), 0, VM_OPT_PWCHG_INTERNAL);
+ } else if (!strcasecmp(var->name, "externpassnotify")) {
+ ast_copy_string(vmcfg->extern_pass_cmd, var->value, sizeof(vmcfg->extern_pass_cmd));
+ ast_set2_flag(&(vmcfg->passwordflags), 1, VM_OPT_PWCHG_EXTERNAL);
+ ast_set2_flag(&(vmcfg->passwordflags), 1, VM_OPT_PWCHG_INTERNAL);
+ } else if (!strcasecmp(var->name, "externpasscheck")) {
+ ast_copy_string(vmcfg->extern_pass_check_cmd, var->value, sizeof(vmcfg->extern_pass_check_cmd));
+ } else if (!strcasecmp(var->name, "externnotify")) {
+ ast_copy_string(vmcfg->extern_notify_cmd, var->value, sizeof(vmcfg->extern_notify_cmd));
+ } else if (!strcasecmp(var->name, "silencethreshold")) {
+ if (sscanf(var->value, "%30ud", &(vmcfg->silence_threshold)) < 1) {
+ ast_log(AST_LOG_WARNING, "Failed to parse %s with value %s into parameter silence_threshold\n", var->name, var->value);
+ }
+ } else if (!strcasecmp(var->name, "serveremail")) {
+ ast_string_field_set(vmcfg, email_server, var->value);
+ } else if (!strcasecmp(var->name, "maxsecs")) {
+ if (sscanf(var->value, "%30ud", &(vmcfg->max_message_duration)) < 1) {
+ ast_log(AST_LOG_WARNING, "Failed to parse %s with value %s into parameter max_message_duration\n", var->name, var->value);
+ }
+ } else if (!strcasecmp(var->name, "maxmessage")) {
+ static int maxmessage_deprecate = 0;
+ if (!maxmessage_deprecate) {
+ maxmessage_deprecate = 1;
+ ast_log(AST_LOG_WARNING, "Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
+ }
+ if (sscanf(var->value, "%30ud", &(vmcfg->max_message_duration)) < 1) {
+ ast_log(AST_LOG_WARNING, "Failed to parse %s with value %s into parameter max_message_duration\n", var->name, var->value);
+ }
+ } else if (!strcasecmp(var->name, "minsecs")) {
+ if (sscanf(var->value, "%30ud", &(vmcfg->min_message_duration)) < 1) {
+ ast_log(AST_LOG_WARNING, "Failed to parse %s with value %s into parameter min_message_duration\n", var->name, var->value);
+ }
+ } else if (!strcasecmp(var->name, "minmessage")) {
+ static int minmessage_deprecate = 0;
+ if (!minmessage_deprecate) {
+ minmessage_deprecate = 1;
+ ast_log(AST_LOG_WARNING, "Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
+ }
+ if (sscanf(var->value, "%30ud", &(vmcfg->min_message_duration)) < 1) {
+ ast_log(AST_LOG_WARNING, "Failed to parse %s with value %s into parameter min_message_duration\n", var->name, var->value);
+ }
+ } else if (!strcasecmp(var->name, "format")) {
+ ast_copy_string(vmcfg->format, var->value, sizeof(vmcfg->format));
+ } else if (!strcasecmp(var->name, "maxgreet")) {
+ if (sscanf(var->value, "%30ud", &(vmcfg->max_message_greeting_length)) < 1) {
+ ast_log(AST_LOG_WARNING, "Failed to parse %s with value %s into parameter max_message_greeting_length\n", var->name, var->value);
+ }
+ } else if (!strcasecmp(var->name, "skipms")) {
+ if (sscanf(var->value, "%30ud", &(vmcfg->skip_ms)) < 1) {
+ ast_log(AST_LOG_WARNING, "Failed to parse %s with value %s into parameter skip_ms\n", var->name, var->value);
+ }
+ } else if (!strcasecmp(var->name, "maxlogins")) {
+ if (sscanf(var->value, "%30ud", &(vmcfg->max_logins)) < 1) {
+ ast_log(AST_LOG_WARNING, "Failed to parse %s with value %s into parameter max_logins\n", var->name, var->value);
+ }
+ } else if (!strcasecmp(var->name, "minpassword")) {
+ if (sscanf(var->value, "%30ud", &(vmcfg->min_password_length)) < 1) {
+ ast_log(AST_LOG_WARNING, "Failed to parse %s with value %s into parameter min_password_length\n", var->name, var->value);
+ }
+ } else if (!strcasecmp(var->name, "forcename")) {
+ ast_set2_flag(&(vmcfg->globalflags), ast_true(var->value), VM_FORCENAME);
+ } else if (!strcasecmp(var->name, "forcegreetings")) {
+ ast_set2_flag(&(vmcfg->globalflags), ast_true(var->value), VM_FORCEGREET);
+ } else if (!strcasecmp(var->name, "cidinternalcontexts")) {
+ tempvalue = ast_strdupa(var->value);
+ if (!ast_strlen_zero(tempvalue)) {
+ while ((tempcontext = strsep(&tempvalue, ","))) {
+ tempcontext = ast_strip(tempcontext);
+ if (cidcounter >= MAX_NUM_CID_CONTEXTS) {
+ ast_log(AST_LOG_WARNING, "CID Context #%d [%s] ignored; a maximum of %d contexts are supported\n", cidcounter, tempcontext, MAX_NUM_CID_CONTEXTS);
+ } else {
+ ast_copy_string(vmcfg->cid_internal_contexts[cidcounter], tempcontext, sizeof(vmcfg->cid_internal_contexts[cidcounter]));
+ }
+ ++cidcounter;
+ }
+ }
+ } else if (!strcasecmp(var->name, "review")) {
+ ast_set2_flag(&(vmcfg->globalflags), ast_true(var->value), VM_REVIEW);
+ } else if (!strcasecmp(var->name, "tempgreetwarn")) {
+ ast_set2_flag(&(vmcfg->globalflags), ast_true(var->value), VM_TEMPGREETWARN);
+ } else if (!strcasecmp(var->name, "messagewrap")) {
+ ast_set2_flag(&(vmcfg->globalflags), ast_true(var->value), VM_MESSAGEWRAP);
+ } else if (!strcasecmp(var->name, "operator")) {
+ ast_set2_flag(&(vmcfg->globalflags), ast_true(var->value), VM_OPERATOR);
+ } else if (!strcasecmp(var->name, "saycid")) {
+ ast_set2_flag(&(vmcfg->globalflags), ast_true(var->value), VM_SAYCID);
+ } else if (!strcasecmp(var->name, "sendvoicemail")) {
+ ast_set2_flag(&(vmcfg->globalflags), ast_true(var->value), VM_SVMAIL);
+ } else if (!strcasecmp(var->name, "envelope")) {
+ ast_set2_flag(&(vmcfg->globalflags), ast_true(var->value), VM_ENVELOPE);
+ } else if (!strcasecmp(var->name, "moveheard")) {
+ ast_set2_flag(&(vmcfg->globalflags), ast_true(var->value), VM_MOVEHEARD);
+ } else if (!strcasecmp(var->name, "forward_urgent_auto")) {
+ ast_set2_flag(&(vmcfg->globalflags), ast_true(var->value), VM_FWDURGAUTO);
+ } else if (!strcasecmp(var->name, "sayduration")) {
+ ast_set2_flag(&(vmcfg->globalflags), ast_true(var->value), VM_SAYDURATION);
+ } else if (!strcasecmp(var->name, "saydurationm")) {
+ if (sscanf(var->value, "%30ud", &vmcfg->min_say_duration) < 1) {
+ ast_log(AST_LOG_WARNING, "Failed to parse %s with value %s into parameter min_say_duration\n", var->name, var->value);
+ }
+ } else if (!strcasecmp(var->name, "nextaftercmd")) {
+ ast_set2_flag(&(vmcfg->globalflags), ast_true(var->value), VM_SKIPAFTERCMD);
+ } else if (!strcasecmp(var->name, "dialout")) {
+ ast_copy_string(vmcfg->dial_out_context, var->value, sizeof(vmcfg->dial_out_context));
+ } else if (!strcasecmp(var->name, "callback")) {
+ ast_copy_string(vmcfg->callback_context, var->value, sizeof(vmcfg->callback_context));
+ } else if (!strcasecmp(var->name, "exitcontext")) {
+ ast_copy_string(vmcfg->op_exit_context, var->value, sizeof(vmcfg->op_exit_context));
+ } else if (!strcasecmp(var->name, "usedirectory")) {
+ ast_set2_flag(&(vmcfg->globalflags), ast_true(var->value), VM_DIRECFORWARD);
+ } else if (!strcasecmp(var->name, "pbxskip")) {
+ ast_set2_flag(&(vmcfg->globalflags), ast_true(var->value), VM_PBXSKIP);
+ }else if (!strcasecmp(var->name, "passwordlocation")) {
+ if (!strcasecmp(var->value, "voicemail.conf")) {
+ vmcfg->password_location = VM_OPT_PWLOC_VOICEMAILCONF;
+ } else if (!strcasecmp(var->value, "spooldir")) {
+ vmcfg->password_location = VM_OPT_PWLOC_SPOOLDIR;
+ } else {
+ ast_log(AST_LOG_WARNING, "Unsupported password location [%s], using default of voicemail.conf\n", var->value);
+ vmcfg->password_location = VM_OPT_PWLOC_VOICEMAILCONF;
+ }
+ } else if (!strcasecmp(var->name, "pollfreq")) {
+ if (sscanf(var->value, "%30ud", &(vmcfg->poll_frequency)) < 1) {
+ ast_log(AST_LOG_WARNING, "Failed to parse %s with value %s into parameter poll_frequency\n", var->name, var->value);
+ }
+ } else if (!strcasecmp(var->name, "pollmailboxes")) {
+ ast_set2_flag(&(vmcfg->globalflags), ast_true(var->value), VM_POLLMAILBOXES);
+ } else if (!strcasecmp(var->name, "vm-password")) {
+ ast_string_field_set(vmcfg->sound_config, vm_password, var->value);
+ } else if (!strcasecmp(var->name, "vm-newpassword")) {
+ ast_string_field_set(vmcfg->sound_config, vm_newpassword, var->value);
+ } else if (!strcasecmp(var->name, "vm-invalid-password")) {
+ ast_string_field_set(vmcfg->sound_config, vm_invalid_password, var->value);
+ } else if (!strcasecmp(var->name, "vm-passchanged")) {
+ ast_string_field_set(vmcfg->sound_config, vm_password_changed, var->value);
+ } else if (!strcasecmp(var->name, "vm-reenterpassword")) {
+ ast_string_field_set(vmcfg->sound_config, vm_reenter_password, var->value);
+ } else if (!strcasecmp(var->name, "vm-mismatch")) {
+ ast_string_field_set(vmcfg->sound_config, vm_mismatch, var->value);
+ } else if (!strcasecmp(var->name, "vm-pls-try-again")) {
+ ast_string_field_set(vmcfg->sound_config, vm_pls_try_again, var->value);
+ } else if (!strcasecmp(var->name, "listen-control-forward-key")) {
+ if (is_valid_dtmf(var->value)) {
+ ast_copy_string(vmcfg->listen_control_config->listen_control_forward_key, var->value, sizeof(vmcfg->listen_control_config->listen_control_forward_key));
+ }
+ } else if (!strcasecmp(var->name, "listen-control-reverse-key")) {
+ if (is_valid_dtmf(var->value)) {
[... 1221 lines stripped ...]
More information about the asterisk-commits
mailing list