]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Merge Tilghman's voicemail broadcast improvements (thanks!)
authorMark Spencer <markster@digium.com>
Wed, 23 Jun 2004 18:00:50 +0000 (18:00 +0000)
committerMark Spencer <markster@digium.com>
Wed, 23 Jun 2004 18:00:50 +0000 (18:00 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@3287 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/app_voicemail.c
configs/voicemail.conf.sample
file.c

index e1d29430b0fe24d5855571074796e1de937a03d5..f5f242a85410c32cc44e7f1f7af54345f1b281a0 100755 (executable)
@@ -85,8 +85,6 @@ static inline void sql_close(void) { }
 #define MAX_DATETIME_FORMAT    512
 #define MAX_NUM_CID_CONTEXTS 10
 
-#define DIGITS_DIR     AST_SOUNDS "/digits/"
-
 
 struct baseio {
        int iocp;
@@ -111,6 +109,7 @@ struct ast_vm_user {
        char dialout[80];
        char exit[80];
        int attach;
+       int delete;
        int alloced;
        int saycid;
        int review;
@@ -163,8 +162,8 @@ static char *synopsis_vm =
 "Leave a voicemail message";
 
 static char *descrip_vm =
-"  VoiceMail([s|u|b]extension[@context]):  Leaves voicemail for a given\n"
-"extension (must be configured in voicemail.conf).\n"
+"  VoiceMail([s|u|b]extension[@context][&extension[@context]][...]):  Leaves"
+"voicemail for a given extension (must be configured in voicemail.conf).\n"
 " If the extension is preceded by \n"
 "* 's' then instructions for leaving the message will be skipped.\n"
 "* 'u' then the \"unavailable\" message will be played.\n"
@@ -176,6 +175,8 @@ static char *descrip_vm =
 "extension 'a' in the current context.\n"
 "If the requested mailbox does not exist, and there exists a priority\n"
 "n + 101, then that priority will be taken next.\n"
+"When multiple mailboxes are specified, the unavailable or busy message\n"
+"will be taken from the first mailbox specified.\n"
 "Returns -1 on error or mailbox not found, or if the user hangs up.\n"
 "Otherwise, it returns 0.\n";
 
@@ -288,6 +289,8 @@ static void apply_options(struct ast_vm_user *vmu, char *options)
                                strncpy(vmu->serveremail, value, sizeof(vmu->serveremail) - 1);
                        } else if (!strcasecmp(var, "tz")) {
                                strncpy(vmu->zonetag, value, sizeof(vmu->zonetag) - 1);
+                       } else if (!strcasecmp(var, "delete")) {
+                               vmu->delete = ast_true(value);
                        } else if (!strcasecmp(var, "saycid")){
                                if(ast_true(value))
                                        vmu->saycid = 1;
@@ -1499,6 +1502,128 @@ static void free_zone(struct vm_zone *z)
        free(z);
 }
 
+static char *mbox(int id)
+{
+       switch(id) {
+       case 0:
+               return "INBOX";
+       case 1:
+               return "Old";
+       case 2:
+               return "Work";
+       case 3:
+               return "Family";
+       case 4:
+               return "Friends";
+       case 5:
+               return "Cust1";
+       case 6:
+               return "Cust2";
+       case 7:
+               return "Cust3";
+       case 8:
+               return "Cust4";
+       case 9:
+               return "Cust5";
+       default:
+               return "Unknown";
+       }
+}
+
+static int copy(char *infile, char *outfile)
+{
+       int ifd;
+       int ofd;
+       int res;
+       int len;
+       char buf[4096];
+
+#ifdef HARDLINK_WHEN_POSSIBLE
+       /* Hard link if possible; saves disk space & is faster */
+       if (link(infile, outfile)) {
+#endif
+               if ((ifd = open(infile, O_RDONLY)) < 0) {
+                       ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
+                       return -1;
+               }
+               if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
+                       ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
+                       close(ifd);
+                       return -1;
+               }
+               do {
+                       len = read(ifd, buf, sizeof(buf));
+                       if (len < 0) {
+                               ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
+                               close(ifd);
+                               close(ofd);
+                               unlink(outfile);
+                       }
+                       if (len) {
+                               res = write(ofd, buf, len);
+                               if (res != len) {
+                                       ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
+                                       close(ifd);
+                                       close(ofd);
+                                       unlink(outfile);
+                               }
+                       }
+               } while(len);
+               close(ifd);
+               close(ofd);
+               return 0;
+#ifdef HARDLINK_WHEN_POSSIBLE
+       } else {
+               /* Hard link succeeded */
+               return 0;
+       }
+#endif
+}
+
+static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *callerid);
+
+static void copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt)
+{
+       char fromdir[256], todir[256], frompath[256], topath[256];
+       char *frombox = mbox(imbox);
+       int recipmsgnum;
+
+       ast_log(LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
+
+       make_dir(todir, sizeof(todir), recip->context, "", "");
+       /* It's easier just to try to make it than to check for its existence */
+       if (mkdir(todir, 0700) && (errno != EEXIST))
+               ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno));
+       make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "");
+       /* It's easier just to try to make it than to check for its existence */
+       if (mkdir(todir, 0700) && (errno != EEXIST))
+               ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno));
+       make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
+       if (mkdir(todir, 0700) && (errno != EEXIST))
+               ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno));
+
+       make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
+       make_file(frompath, sizeof(frompath), fromdir, msgnum);
+       recipmsgnum = 0;
+       do {
+               make_file(topath, sizeof(topath), todir, recipmsgnum);
+               if (ast_fileexists(topath, NULL, chan->language) <= 0) 
+                       break;
+               recipmsgnum++;
+       } while(recipmsgnum < MAXMSG);
+       if (recipmsgnum < MAXMSG) {
+               char frompath2[256],topath2[256];
+               ast_filecopy(frompath, topath, NULL);
+               snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
+               snprintf(topath2, sizeof(topath2), "%s.txt", topath);
+               copy(frompath2, topath2);
+       } else {
+               ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
+       }
+
+       notify_new_message(chan, recip, recipmsgnum, duration, fmt, chan->callerid);
+}
+
 static void run_externnotify(char *context, char *extension, int numvoicemails)
 {
        char arguments[255];
@@ -1514,7 +1639,6 @@ static void run_externnotify(char *context, char *extension, int numvoicemails)
 
 static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail)
 {
-       char comment[256];
        char txtfile[256];
        FILE *txt;
        int res = 0;
@@ -1529,18 +1653,24 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
        char fmt[80];
        char *context;
        char ecodes[16] = "#";
-       char *stringp;
-       char tmp[256] = "";
+       char tmp[256] = "", *tmpptr;
        struct ast_vm_user *vmu;
        struct ast_vm_user svm;
 
-
        strncpy(tmp, ext, sizeof(tmp) - 1);
        ext = tmp;
        context = strchr(tmp, '@');
        if (context) {
                *context = '\0';
                context++;
+               tmpptr = strchr(context, '&');
+       } else {
+               tmpptr = strchr(ext, '&');
+       }
+
+       if (tmpptr) {
+               *tmpptr = '\0';
+               tmpptr++;
        }
 
        if ((vmu = find_user(&svm, context, ext))) {
@@ -1641,9 +1771,6 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
                        msgnum = 0;
                        do {
                                make_file(fn, sizeof(fn), dir, msgnum);
-                               snprintf(comment, sizeof(comment), "Voicemail from %s to %s (%s) on %s\n",
-                                                                       (chan->callerid ? chan->callerid : "Unknown"), 
-                                                                       vmu->fullname, ext, chan->name);
                                if (ast_fileexists(fn, NULL, chan->language) <= 0) 
                                        break;
                                msgnum++;
@@ -1697,24 +1824,23 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
                                        vm_delete(fn);
                                        goto leave_vm_out;
                                }
-                               stringp = fmt;
-                               strsep(&stringp, "|");
-                               /* Send e-mail if applicable */
-                               if (strlen(vmu->email)) {
-                                       int attach_user_voicemail = attach_voicemail;
-                                       char *myserveremail = serveremail;
-                                       if (vmu->attach > -1)
-                                               attach_user_voicemail = vmu->attach;
-                                       if (strlen(vmu->serveremail))
-                                               myserveremail = vmu->serveremail;
-                                               sendmail(myserveremail, vmu, msgnum, ext, chan->callerid, fn, fmt, duration, attach_user_voicemail);
-                               }
-                               if (strlen(vmu->pager)) {
-                                       char *myserveremail = serveremail;
-                                       if (strlen(vmu->serveremail))
-                                               myserveremail = vmu->serveremail;
-                                       sendpage(myserveremail, vmu->pager, msgnum, ext, chan->callerid, duration, vmu);
+                               /* Are there to be more recipients of this message? */
+                               while (tmpptr) {
+                                       struct ast_vm_user recipu, *recip;
+                                       char *exten, *context;
+
+                                       exten = strsep(&tmpptr, "&");
+                                       context = strchr(exten, '@');
+                                       if (context) {
+                                               *context = '\0';
+                                               context++;
+                                       }
+                                       if ((recip = find_user(&recipu, context, exten))) {
+                                               copy_message(chan, vmu, 0, msgnum, duration, recip, fmt);
+                                               free_user(recip);
+                                       }
                                }
+                               notify_new_message(chan, vmu, msgnum, duration, fmt, chan->callerid);
                        } else {
                                res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
                                if (!res)
@@ -1722,52 +1848,19 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
                                ast_log(LOG_WARNING, "No more messages possible\n");
                        }
                } else
-                       ast_log(LOG_WARNING, "No format for saving voicemail?\n");                                      
+                       ast_log(LOG_WARNING, "No format for saving voicemail?\n");
 leave_vm_out:
                free_user(vmu);
        } else {
                ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
-                       /*Send the call to n+101 priority, where n is the current priority*/
-                       if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
-                               chan->priority+=100;
+               /*Send the call to n+101 priority, where n is the current priority*/
+               if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
+                       chan->priority+=100;
        }
-       /* Leave voicemail for someone */
-       manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, ast_app_has_voicemail(ext_context));
-
-       /* If an external program is specified to be run after leaving a voicemail */
-       run_externnotify(chan->context, ext_context, ast_app_has_voicemail(ext_context));
 
        return res;
 }
 
-static char *mbox(int id)
-{
-       switch(id) {
-       case 0:
-               return "INBOX";
-       case 1:
-               return "Old";
-       case 2:
-               return "Work";
-       case 3:
-               return "Family";
-       case 4:
-               return "Friends";
-       case 5:
-               return "Cust1";
-       case 6:
-               return "Cust2";
-       case 7:
-               return "Cust3";
-       case 8:
-               return "Cust4";
-       case 9:
-               return "Cust5";
-       default:
-               return "Unknown";
-       }
-}
-
 static int count_messages(char *dir)
 {
        int x;
@@ -1787,45 +1880,6 @@ static int say_and_wait(struct ast_channel *chan, int num)
        return d;
 }
 
-static int copy(char *infile, char *outfile)
-{
-       int ifd;
-       int ofd;
-       int res;
-       int len;
-       char buf[4096];
-       if ((ifd = open(infile, O_RDONLY)) < 0) {
-               ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
-               return -1;
-       }
-       if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
-               ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
-               close(ifd);
-               return -1;
-       }
-       do {
-               len = read(ifd, buf, sizeof(buf));
-               if (len < 0) {
-                       ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
-                       close(ifd);
-                       close(ofd);
-                       unlink(outfile);
-               }
-               if (len) {
-                       res = write(ofd, buf, len);
-                       if (res != len) {
-                               ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
-                               close(ifd);
-                               close(ofd);
-                               unlink(outfile);
-                       }
-               }
-       } while(len);
-       close(ifd);
-       close(ofd);
-       return 0;
-}
-
 static int save_to_folder(char *dir, int msg, char *context, char *username, int box)
 {
        char sfn[256];
@@ -2422,6 +2476,49 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu,
        return cmd;
 }
 
+static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *callerid)
+{
+       char todir[256], fn[256], *stringp;
+
+       make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX");
+       make_file(fn, sizeof(fn), todir, msgnum);
+
+       /* Attach only the first format */
+       fmt = ast_strdupa(fmt);
+       if (fmt) {
+               stringp = fmt;
+               strsep(&stringp, "|");
+
+               if (strlen(vmu->email)) {
+                       int attach_user_voicemail = attach_voicemail;
+                       char *myserveremail = serveremail;
+                       if (vmu->attach > -1)
+                               attach_user_voicemail = vmu->attach;
+                       if (strlen(vmu->serveremail))
+                               myserveremail = vmu->serveremail;
+                       sendmail(myserveremail, vmu, msgnum, vmu->mailbox, callerid, fn, fmt, duration, attach_user_voicemail);
+               }
+
+               if (strlen(vmu->pager)) {
+                       char *myserveremail = serveremail;
+                       if (strlen(vmu->serveremail))
+                               myserveremail = vmu->serveremail;
+                       sendpage(myserveremail, vmu->pager, msgnum, vmu->mailbox, callerid, duration, vmu);
+               }
+       } else {
+               ast_log(LOG_ERROR, "Out of memory\n");
+       }
+
+       if (vmu->delete) {
+               vm_delete(fn);
+       }
+
+       /* Leave voicemail for someone */
+       manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", vmu->mailbox, ast_app_has_voicemail(vmu->mailbox));
+       run_externnotify(chan->context, vmu->mailbox, ast_app_has_voicemail(vmu->mailbox));
+       return 0;
+}
+
 static int forward_message(struct ast_channel *chan, char *context, char *dir, int curmsg, struct ast_vm_user *sender, char *fmt)
 {
        char username[70];
@@ -3363,12 +3460,10 @@ out:
                snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context);
                manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, ast_app_has_voicemail(ext_context));
                run_externnotify(chan->context, ext_context, ast_app_has_voicemail(ext_context));
-
        }
        LOCAL_USER_REMOVE(u);
 
        return res;
-
 }
 
 static int vm_exec(struct ast_channel *chan, void *data)
index 2b61333f512554a463c3ea8df47a83105b4e5eee..b39f32ffb5e3f76b6bd54bdf18a9a5bc1085b086 100755 (executable)
@@ -87,9 +87,9 @@ maxlogins=3
 ;
 ; Advanced options example is extension 4069
 ; NOTE: All options can be expressed globally in the general section, and overriden in the per-mailbox 
-; settings.
+; settings, unless listed otherwise.
 ; 
-; tz=central           ; Timezone from zonemessages above
+; tz=central           ; Timezone from zonemessages above.  Irrelevant if envelope=no.
 ; attach=yes           ; Attach the voicemail to the notification email *NOT* the pager email
 ; saycid=yes           ; Say the caller id information before the message. If not described, 
                        ;     or set to no, it will be in the envelope
@@ -102,6 +102,8 @@ maxlogins=3
                        ;     reach an operator  [OFF by default]
 ; envelope=no          ; Turn on/off envelope playback before message playback. [ON by default] 
                        ;     This does NOT affect option 3,3 from the advanced options menu
+; delete=yes           ; After notification, the voicemail is deleted from the server. [per-mailbox only]
+                       ;     This is intended for use with users who wish to receive their voicemail ONLY by email.
                        
 [zonemessages]
 eastern=America/New_York|'vm-received' Q 'digits/at' IMp
@@ -114,6 +116,7 @@ central24=America/Chicago|'vm-received' q 'digits/at' H 'digits/hundred' M 'hour
 ;4300 => 3456,Ben Rigas,ben@american-computer.net
 ;4310 => 5432,Sales,sales@marko.net
 ;4069 => 6522,Matt Brooks,matt@marko.net,,|tz=central|attach=yes|saycid=yes|dialout=fromvm|callback=fromvm|review=yes|operator=yes|envelope=yes
+;4073 => 1099,Bianca Paige,bianca@biancapaige.com,,delete=1
 ;4110 => 3443,Rob Flynn,rflynn@blueridge.net
 
 ;
diff --git a/file.c b/file.c
index d5d1f8e940b2a5387e3e49580bf66cc98ac33e4a..d23879edf29da00c16fd0d908cebb517089dfa35 100755 (executable)
--- a/file.c
+++ b/file.c
@@ -28,6 +28,7 @@
 #include <stdio.h>
 #include <fcntl.h>
 #include <dirent.h>
+#include <sys/types.h>
 #include <sys/stat.h>
 #include "asterisk.h"
 #include "astconf.h"
@@ -241,6 +242,7 @@ static int copy(char *infile, char *outfile)
        int res;
        int len;
        char buf[4096];
+
        if ((ifd = open(infile, O_RDONLY)) < 0) {
                ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
                return -1;
@@ -343,6 +345,9 @@ static int ast_filehelper(char *filename, char *filename2, char *fmt, int action
                        /* Try each kind of extension */
                        stringp=exts;
                        ext = strsep(&stringp, "|");
+                       if (!strcmp(ext,"wav49")) {
+                               ext = "WAV";
+                       }
                        do {
                                fn = build_filename(filename, ext);
                                if (fn) {