Allow overriding of IMAP server settings on a user by user basis
authorMatthew Jordan <mjordan@digium.com>
Fri, 23 Dec 2011 21:19:52 +0000 (21:19 +0000)
committerMatthew Jordan <mjordan@digium.com>
Fri, 23 Dec 2011 21:19:52 +0000 (21:19 +0000)
This patch allows the imapserver, imapport, and imapflags settings to be
overridden for any voicemail user.  It also documents the settings in
the sample voicemail.conf file, and updates the voicemail schema to
allow storage of those columns.

(closes issue ASTERISK-16489)
Reporter: Hubert Mickael
Tested by: Matt Jordan

Review: https://reviewboard.asterisk.org/r/1614/

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

CHANGES
apps/app_voicemail.c
configs/voicemail.conf.sample
contrib/realtime/mysql/voicemail.sql

diff --git a/CHANGES b/CHANGES
index 30ba4d4..b0eb2a5 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -21,6 +21,12 @@ ConfBridge
  * Added menu action participant_count.  This will playback the number of current
    participants in a conference.
 
+Voicemail
+------------------
+ * Addition of the VM_INFO function - see Dialplan function changes
+ * The imapserver, imapport, and imapflags configuration options can now be
+   overriden on a user by user basis.
+
 SIP Changes
 -----------
  * Asterisk will no longer substitute CID number for CID name into display
index f4414d6..8be69e5 100644 (file)
@@ -466,7 +466,7 @@ static void vmstate_delete(struct vm_state *vms);
 static void set_update(MAILSTREAM * stream);
 static void init_vm_state(struct vm_state *vms);
 static int save_body(BODY *body, struct vm_state *vms, char *section, char *format, int is_intro);
-static void get_mailbox_delimiter(MAILSTREAM *stream);
+static void get_mailbox_delimiter(struct vm_state *vms, MAILSTREAM *stream);
 static void mm_parsequota (MAILSTREAM *stream, unsigned char *msg, QUOTALIST *pquota);
 static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int box, int target);
 static int imap_store_file(const char *dir, const char *mailboxuser, const char *mailboxcontext, int msgnum, struct ast_channel *chan, struct ast_vm_user *vmu, char *fmt, int duration, struct vm_state *vms, const char *flag);
@@ -726,6 +726,9 @@ struct ast_vm_user {
        int maxsecs;                     /*!< Maximum number of seconds per message for this mailbox */
        int passwordlocation;            /*!< Storage location of the password */
 #ifdef IMAP_STORAGE
+       char imapserver[48];             /*!< IMAP server address */
+       char imapport[8];                /*!< IMAP server port */
+       char imapflags[128];             /*!< IMAP optional flags */
        char imapuser[80];               /*!< IMAP server login */
        char imappassword[80];           /*!< IMAP server password if authpassword not defined */
        char imapfolder[64];             /*!< IMAP voicemail folder */
@@ -773,6 +776,9 @@ struct vm_state {
        int vmArrayIndex;
        char imapuser[80];                   /*!< IMAP server login */
        char imapfolder[64];                 /*!< IMAP voicemail folder */
+       char imapserver[48];                 /*!< IMAP server address */
+       char imapport[8];                    /*!< IMAP server port */
+       char imapflags[128];                 /*!< IMAP optional flags */
        int imapversion;
        int interactive;
        char introfn[PATH_MAX];              /*!< Name of prepended file */
@@ -1110,6 +1116,9 @@ static void populate_defaults(struct ast_vm_user *vmu)
        vmu->emailbody = NULL;
 #ifdef IMAP_STORAGE
        ast_copy_string(vmu->imapfolder, imapfolder, sizeof(vmu->imapfolder));
+       ast_copy_string(vmu->imapserver, imapserver, sizeof(vmu->imapserver));
+       ast_copy_string(vmu->imapport, imapport, sizeof(vmu->imapport));
+       ast_copy_string(vmu->imapflags, imapflags, sizeof(vmu->imapflags));
 #endif
 }
 
@@ -1146,11 +1155,21 @@ static void apply_option(struct ast_vm_user *vmu, const char *var, const char *v
        } else if (!strcasecmp(var, "imapuser")) {
                ast_copy_string(vmu->imapuser, value, sizeof(vmu->imapuser));
                vmu->imapversion = imapversion;
+       } else if (!strcasecmp(var, "imapserver")) {
+               ast_copy_string(vmu->imapserver, value, sizeof(vmu->imapserver));
+               vmu->imapversion = imapversion;
+       } else if (!strcasecmp(var, "imapport")) {
+               ast_copy_string(vmu->imapport, value, sizeof(vmu->imapport));
+               vmu->imapversion = imapversion;
+       } else if (!strcasecmp(var, "imapflags")) {
+               ast_copy_string(vmu->imapflags, value, sizeof(vmu->imapflags));
+               vmu->imapversion = imapversion;
        } else if (!strcasecmp(var, "imappassword") || !strcasecmp(var, "imapsecret")) {
                ast_copy_string(vmu->imappassword, value, sizeof(vmu->imappassword));
                vmu->imapversion = imapversion;
        } else if (!strcasecmp(var, "imapfolder")) {
                ast_copy_string(vmu->imapfolder, value, sizeof(vmu->imapfolder));
+               vmu->imapversion = imapversion;
        } else if (!strcasecmp(var, "imapvmshareid")) {
                ast_copy_string(vmu->imapvmshareid, value, sizeof(vmu->imapvmshareid));
                vmu->imapversion = imapversion;
@@ -1417,11 +1436,21 @@ static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *
                } else if (!strcasecmp(var->name, "imapuser")) {
                        ast_copy_string(retval->imapuser, var->value, sizeof(retval->imapuser));
                        retval->imapversion = imapversion;
+               } else if (!strcasecmp(var->name, "imapserver")) {
+                       ast_copy_string(retval->imapserver, var->value, sizeof(retval->imapserver));
+                       retval->imapversion = imapversion;
+               } else if (!strcasecmp(var->name, "imapport")) {
+                       ast_copy_string(retval->imapport, var->value, sizeof(retval->imapport));
+                       retval->imapversion = imapversion;
+               } else if (!strcasecmp(var->name, "imapflags")) {
+                       ast_copy_string(retval->imapflags, var->value, sizeof(retval->imapflags));
+                       retval->imapversion = imapversion;
                } else if (!strcasecmp(var->name, "imappassword") || !strcasecmp(var->name, "imapsecret")) {
                        ast_copy_string(retval->imappassword, var->value, sizeof(retval->imappassword));
                        retval->imapversion = imapversion;
                } else if (!strcasecmp(var->name, "imapfolder")) {
                        ast_copy_string(retval->imapfolder, var->value, sizeof(retval->imapfolder));
+                       retval->imapversion = imapversion;
                } else if (!strcasecmp(var->name, "imapvmshareid")) {
                        ast_copy_string(retval->imapvmshareid, var->value, sizeof(retval->imapvmshareid));
                        retval->imapversion = imapversion;
@@ -2584,15 +2613,16 @@ static void imap_mailbox_name(char *spec, size_t len, struct vm_state *vms, int
        }
 
        /* Build up server information */
-       ast_build_string(&t, &left, "{%s:%s/imap", imapserver, imapport);
+       ast_build_string(&t, &left, "{%s:%s/imap", S_OR(vms->imapserver, imapserver), S_OR(vms->imapport, imapport));
 
        /* Add authentication user if present */
        if (!ast_strlen_zero(authuser))
                ast_build_string(&t, &left, "/authuser=%s", authuser);
 
        /* Add flags if present */
-       if (!ast_strlen_zero(imapflags))
-               ast_build_string(&t, &left, "/%s", imapflags);
+       if (!ast_strlen_zero(imapflags) || !(ast_strlen_zero(vms->imapflags))) {
+               ast_build_string(&t, &left, "/%s", S_OR(vms->imapflags, imapflags));
+       }
 
        /* End with username */
 #if 1
@@ -2651,7 +2681,7 @@ static int init_mailstream(struct vm_state *vms, int box)
                        ast_log(LOG_ERROR, "Can't connect to imap server %s\n", tmp);
                        return -1;
                }
-               get_mailbox_delimiter(stream);
+               get_mailbox_delimiter(vms, stream);
                /* update delimiter in imapfolder */
                for (cp = vms->imapfolder; *cp; cp++)
                        if (*cp == '/')
@@ -2684,6 +2714,9 @@ static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
 
        ast_copy_string(vms->imapuser, vmu->imapuser, sizeof(vms->imapuser));
        ast_copy_string(vms->imapfolder, vmu->imapfolder, sizeof(vms->imapfolder));
+       ast_copy_string(vms->imapserver, vmu->imapserver, sizeof(vms->imapserver));
+       ast_copy_string(vms->imapport, vmu->imapport, sizeof(vms->imapport));
+       ast_copy_string(vms->imapflags, vmu->imapflags, sizeof(vms->imapflags));
        vms->imapversion = vmu->imapversion;
        ast_debug(3, "Before init_mailstream, user is %s\n", vmu->imapuser);
 
@@ -3049,6 +3082,9 @@ static struct vm_state *create_vm_state_from_user(struct ast_vm_user *vmu)
                return NULL;
        ast_copy_string(vms_p->imapuser, vmu->imapuser, sizeof(vms_p->imapuser));
        ast_copy_string(vms_p->imapfolder, vmu->imapfolder, sizeof(vms_p->imapfolder));
+       ast_copy_string(vms_p->imapserver, vmu->imapserver, sizeof(vms_p->imapserver));
+       ast_copy_string(vms_p->imapport, vmu->imapport, sizeof(vms_p->imapport));
+       ast_copy_string(vms_p->imapflags, vmu->imapflags, sizeof(vms_p->imapflags));
        ast_copy_string(vms_p->username, vmu->mailbox, sizeof(vms_p->username)); /* save for access from interactive entry point */
        ast_copy_string(vms_p->context, vmu->context, sizeof(vms_p->context));
        vms_p->mailstream = NIL; /* save for access from interactive entry point */
@@ -3280,14 +3316,15 @@ static int save_body(BODY *body, struct vm_state *vms, char *section, char *form
 
 /*! 
  * \brief Get delimiter via mm_list callback 
+ * \param vms          The voicemail state object
  * \param stream
  *
  * Determines the delimiter character that is used by the underlying IMAP based mail store.
  */
 /* MUTEX should already be held */
-static void get_mailbox_delimiter(MAILSTREAM *stream) {
+static void get_mailbox_delimiter(struct vm_state *vms, MAILSTREAM *stream) {
        char tmp[50];
-       snprintf(tmp, sizeof(tmp), "{%s}", imapserver);
+       snprintf(tmp, sizeof(tmp), "{%s}", S_OR(vms->imapserver, imapserver));
        mail_list(stream, tmp, "*");
 }
 
@@ -10877,7 +10914,7 @@ AST_TEST_DEFINE(test_voicemail_vmuser)
                "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
 #ifdef IMAP_STORAGE
        static const char option_string2[] = "imapuser=imapuser|imappassword=imappasswd|"
-               "imapfolder=INBOX|imapvmshareid=6000";
+               "imapfolder=INBOX|imapvmshareid=6000|imapserver=imapserver|imapport=1234|imapflags=flagged";
 #endif
 
        switch (cmd) {
@@ -11031,6 +11068,18 @@ AST_TEST_DEFINE(test_voicemail_vmuser)
                ast_test_status_update(test, "Parse failure for imapvmshareid option\n");
                res = 1;
        }
+       if (strcasecmp(vmu->imapserver, "imapserver")) {
+               ast_test_status_update(test, "Parse failure for imapserver option\n");
+               res = 1;
+       }
+       if (strcasecmp(vmu->imapport, "1234")) {
+               ast_test_status_update(test, "Parse failure for imapport option\n");
+               res = 1;
+       }
+       if (strcasecmp(vmu->imapflags, "flagged")) {
+               ast_test_status_update(test, "Parse failure for imapflags option\n");
+               res = 1;
+       }
 #endif
 
        free_user(vmu);
@@ -11823,6 +11872,9 @@ static int manager_list_voicemail_users(struct mansession *s, const struct messa
 #ifdef IMAP_STORAGE
                        "OldMessageCount: %d\r\n"
                        "IMAPUser: %s\r\n"
+                       "IMAPServer: %s\r\n"
+                       "IMAPPort: %s\r\n"
+                       "IMAPFlags: %s\r\n"
 #endif
                        "\r\n",
                        actionid,
@@ -11851,7 +11903,11 @@ static int manager_list_voicemail_users(struct mansession *s, const struct messa
                        vmu->maxmsg,
                        vmu->maxsecs,
 #ifdef IMAP_STORAGE
-                       new, old, vmu->imapuser
+                       new, old,
+                       vmu->imapuser,
+                       vmu->imapserver,
+                       vmu->imapport,
+                       vmu->imapflags
 #else
                        count_messages(vmu, dirname)
 #endif
index c2cbdf2..a92e7a1 100644 (file)
@@ -185,20 +185,43 @@ pagerdateformat=%A, %B %d, %Y at %r
 ;pollfreq=30         ;   If the "pollmailboxes" option is enabled, this option
 ;                    ; sets the polling frequency.  The default is once every
 ;                    ; 30 seconds.
-; If using IMAP storage, specify whether voicemail greetings should be stored
-; via IMAP. If no, then greetings are stored as if IMAP storage were not enabled
-;imapgreetings=no
-; If imapgreetings=yes, then specify which folder to store your greetings in. If
-; you do not specify a folder, then INBOX will be used
-;greetingsfolder=INBOX
-; Some IMAP server implementations store folders under INBOX instead of
-; using a top level folder (ex. INBOX/Friends).  In this case, user
-; imapparentfolder to set the parent folder. For example, Cyrus IMAP does
-; NOT use INBOX as the parent. Default is to have no parent folder set.
-;imapparentfolder=INBOX
-;
 ;
+
+; -----------------------------------------------------------------------------
+; IMAP configuration settings only
+;   These settings are only applicable when Asterisk is compiled with IMAP support.
+;
+;imapgreetings=no        ; If using IMAP storage, specify whether voicemail greetings
+                         ; should be stored via IMAP. If no, then greetings are stored
+                         ; as if IMAP storage were not enabled.
+;greetingsfolder=INBOX   ; If imapgreetings=yes, then specify which folder to store
+                         ; your greetings in. If you do not specify a folder, then INBOX
+                         ; will be used
+;imapparentfolder=INBOX  ; Some IMAP server implementations store folders under INBOX
+                         ; instead of using a top level folder (ex. INBOX/Friends).  In
+                         ; this case, user imapparentfolder to set the parent folder. For
+                         ; example, Cyrus IMAP does NOT use INBOX as the parent. Default
+                         ; is to have no parent folder set.
+;imapserver=localhost    ; The address of the IMAP server
+;imapport=143            ; The port of the IMAP server
+;imapflags=ssl           ; Optional flags to pass to the IMAP server in the IMAP mailbox
+                         ; name.  For example, setting this to 'ssl' will enable OpenSSL
+                         ; encryption, assuming the IMAP libraries were compiled with
+                         ; OpenSSL support.
+;imapfolder=INBOX        ; The folder in which to store voicemail messages on the IMAP
+                         ; server.  By default, they are stored in INBOX.
+;authuser=user           ; The master user to use for connecting to the IMAP server, if
+                         ; the server is configured with a single user that has access to
+                         ; all mailboxes
+;authpassword=password   ; The password for the authuser, if used
+;imapopentimeout=60      ; The TCP open timeout (in seconds)
+;imapclosetimeout=60     ; The TCP close timeout (in seconds)
+;imapreadtimeout=60      ; The TCP read timeout (in seconds)
+;imapwritetimeout=60     ; The TCP write timeout (in seconds)
+
+; -----------------------------------------------------------------------------
 ;
+
 ; Each mailbox is listed in the form <mailbox>=<password>,<name>,<email>,<pager_email>,<options>
 ; if the e-mail is specified, a message will be sent when a message is
 ; received, to the given mailbox. If pager is specified, a message will be
@@ -413,9 +436,19 @@ european=Europe/Copenhagen|'vm-received' a d b 'digits/at' HM
 ;112 => 6262,Nancy,nancy@acme-widgets.com
 ;
 
-;
-; When using IMAP storage, imapuser, imappassword, and imapfolder can be used to specify the
-; user's credentials.
+; ---------------------------------------------------------------------------
+; IMAP user settings and overrides.  These are only applicable when Asterisk is
+; compiled with IMAP support.
+;
+; imapuser=username                ; The IMAP username of the mailbox to access
+; imappassword=password            ; The IMAP password of the user
+; imapvmshareid=xxxx               ; A shared mailbox ID to use for the IMAP mailbox
+                                   ; login, as opposed to the mailbox dialed
+; imapfolder                       ; Overrides the global imapfolder setting
+; imapserver                       ; Overrides the global imapserver setting
+; imapport                         ; Overrides the global imapport setting
+; imapflags                        ; Overrides the global imapflags setting
+
 ;
 ;[imapvm]
 ;4324 => 7764,Ellis Redding,red@buxton.us,,imapuser=eredding|imappassword=g3tbusy|imapfolder=notinbox
index c8148cf..bd924f4 100644 (file)
@@ -60,5 +60,11 @@ CREATE TABLE voicemail (
        imapuser VARCHAR(80),
        -- IMAP password for authentication (if using IMAP storage)
        imappassword VARCHAR(80),
+       -- IMAP server location (if using IMAP storage)
+       imapsever VARCHAR(80),
+       -- IMAP port (if using IMAP storage)
+       imapport VARCHAR(8),
+       -- IMAP flags (if using IMAP storage)
+       imapflags VARCHAR(80),
        stamp timestamp
 );