Index: apps/app_voicemail.c =================================================================== RCS file: /usr/cvsroot/asterisk/apps/app_voicemail.c,v retrieving revision 1.114 diff -u -r1.114 app_voicemail.c --- apps/app_voicemail.c 22 Jun 2004 17:42:13 -0000 1.114 +++ apps/app_voicemail.c 23 Jun 2004 16:25:19 -0000 @@ -86,8 +86,6 @@ #define MAX_DATETIME_FORMAT 512 #define MAX_NUM_CID_CONTEXTS 10 -#define DIGITS_DIR AST_SOUNDS "/digits/" - struct baseio { int iocp; @@ -112,6 +110,7 @@ char dialout[80]; char exit[80]; int attach; + int delete; int alloced; int saycid; int review; @@ -164,8 +163,8 @@ "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" @@ -177,6 +176,8 @@ "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"; @@ -289,6 +290,8 @@ 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; @@ -1500,6 +1503,128 @@ 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]; @@ -1515,7 +1640,6 @@ 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; @@ -1530,18 +1654,24 @@ 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))) { @@ -1642,9 +1772,6 @@ 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++; @@ -1698,24 +1825,23 @@ 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) @@ -1723,52 +1849,19 @@ 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; @@ -1788,45 +1881,6 @@ 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]; @@ -2423,6 +2477,49 @@ 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]; @@ -3364,12 +3461,10 @@ 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: file.c =================================================================== RCS file: /usr/cvsroot/asterisk/file.c,v retrieving revision 1.42 diff -u -r1.42 file.c --- file.c 9 Jun 2004 01:45:07 -0000 1.42 +++ file.c 23 Jun 2004 16:25:19 -0000 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include "asterisk.h" #include "astconf.h" @@ -241,6 +242,7 @@ 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 @@ /* Try each kind of extension */ stringp=exts; ext = strsep(&stringp, "|"); + if (!strcmp(ext,"wav49")) { + ext = "WAV"; + } do { fn = build_filename(filename, ext); if (fn) { Index: configs/voicemail.conf.sample =================================================================== RCS file: /usr/cvsroot/asterisk/configs/voicemail.conf.sample,v retrieving revision 1.32 diff -u -r1.32 voicemail.conf.sample --- configs/voicemail.conf.sample 5 Jun 2004 23:00:16 -0000 1.32 +++ configs/voicemail.conf.sample 23 Jun 2004 16:25:20 -0000 @@ -87,9 +87,9 @@ ; ; 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 @@ ; 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 @@ ;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 ;