Merge Tilghman's voicemail broadcast improvements (thanks!)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@3287 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.0
Mark Spencer 21 years ago
parent 68248b91f0
commit 74fdefdf1e

@ -85,8 +85,6 @@ static inline void sql_close(void) { }
#define MAX_DATETIME_FORMAT 512 #define MAX_DATETIME_FORMAT 512
#define MAX_NUM_CID_CONTEXTS 10 #define MAX_NUM_CID_CONTEXTS 10
#define DIGITS_DIR AST_SOUNDS "/digits/"
struct baseio { struct baseio {
int iocp; int iocp;
@ -111,6 +109,7 @@ struct ast_vm_user {
char dialout[80]; char dialout[80];
char exit[80]; char exit[80];
int attach; int attach;
int delete;
int alloced; int alloced;
int saycid; int saycid;
int review; int review;
@ -163,8 +162,8 @@ static char *synopsis_vm =
"Leave a voicemail message"; "Leave a voicemail message";
static char *descrip_vm = static char *descrip_vm =
" VoiceMail([s|u|b]extension[@context]): Leaves voicemail for a given\n" " VoiceMail([s|u|b]extension[@context][&extension[@context]][...]): Leaves"
"extension (must be configured in voicemail.conf).\n" "voicemail for a given extension (must be configured in voicemail.conf).\n"
" If the extension is preceded by \n" " If the extension is preceded by \n"
"* 's' then instructions for leaving the message will be skipped.\n" "* 's' then instructions for leaving the message will be skipped.\n"
"* 'u' then the \"unavailable\" message will be played.\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" "extension 'a' in the current context.\n"
"If the requested mailbox does not exist, and there exists a priority\n" "If the requested mailbox does not exist, and there exists a priority\n"
"n + 101, then that priority will be taken next.\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" "Returns -1 on error or mailbox not found, or if the user hangs up.\n"
"Otherwise, it returns 0.\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); strncpy(vmu->serveremail, value, sizeof(vmu->serveremail) - 1);
} else if (!strcasecmp(var, "tz")) { } else if (!strcasecmp(var, "tz")) {
strncpy(vmu->zonetag, value, sizeof(vmu->zonetag) - 1); strncpy(vmu->zonetag, value, sizeof(vmu->zonetag) - 1);
} else if (!strcasecmp(var, "delete")) {
vmu->delete = ast_true(value);
} else if (!strcasecmp(var, "saycid")){ } else if (!strcasecmp(var, "saycid")){
if(ast_true(value)) if(ast_true(value))
vmu->saycid = 1; vmu->saycid = 1;
@ -1499,6 +1502,128 @@ static void free_zone(struct vm_zone *z)
free(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) static void run_externnotify(char *context, char *extension, int numvoicemails)
{ {
char arguments[255]; 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) static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail)
{ {
char comment[256];
char txtfile[256]; char txtfile[256];
FILE *txt; FILE *txt;
int res = 0; int res = 0;
@ -1529,18 +1653,24 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
char fmt[80]; char fmt[80];
char *context; char *context;
char ecodes[16] = "#"; char ecodes[16] = "#";
char *stringp; char tmp[256] = "", *tmpptr;
char tmp[256] = "";
struct ast_vm_user *vmu; struct ast_vm_user *vmu;
struct ast_vm_user svm; struct ast_vm_user svm;
strncpy(tmp, ext, sizeof(tmp) - 1); strncpy(tmp, ext, sizeof(tmp) - 1);
ext = tmp; ext = tmp;
context = strchr(tmp, '@'); context = strchr(tmp, '@');
if (context) { if (context) {
*context = '\0'; *context = '\0';
context++; context++;
tmpptr = strchr(context, '&');
} else {
tmpptr = strchr(ext, '&');
}
if (tmpptr) {
*tmpptr = '\0';
tmpptr++;
} }
if ((vmu = find_user(&svm, context, ext))) { 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; msgnum = 0;
do { do {
make_file(fn, sizeof(fn), dir, msgnum); 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) if (ast_fileexists(fn, NULL, chan->language) <= 0)
break; break;
msgnum++; msgnum++;
@ -1697,24 +1824,23 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
vm_delete(fn); vm_delete(fn);
goto leave_vm_out; goto leave_vm_out;
} }
stringp = fmt; /* Are there to be more recipients of this message? */
strsep(&stringp, "|"); while (tmpptr) {
/* Send e-mail if applicable */ struct ast_vm_user recipu, *recip;
if (strlen(vmu->email)) { char *exten, *context;
int attach_user_voicemail = attach_voicemail;
char *myserveremail = serveremail; exten = strsep(&tmpptr, "&");
if (vmu->attach > -1) context = strchr(exten, '@');
attach_user_voicemail = vmu->attach; if (context) {
if (strlen(vmu->serveremail)) *context = '\0';
myserveremail = vmu->serveremail; context++;
sendmail(myserveremail, vmu, msgnum, ext, chan->callerid, fn, fmt, duration, attach_user_voicemail); }
if ((recip = find_user(&recipu, context, exten))) {
copy_message(chan, vmu, 0, msgnum, duration, recip, fmt);
free_user(recip);
} }
if (strlen(vmu->pager)) {
char *myserveremail = serveremail;
if (strlen(vmu->serveremail))
myserveremail = vmu->serveremail;
sendpage(myserveremail, vmu->pager, msgnum, ext, chan->callerid, duration, vmu);
} }
notify_new_message(chan, vmu, msgnum, duration, fmt, chan->callerid);
} else { } else {
res = ast_streamfile(chan, "vm-mailboxfull", chan->language); res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
if (!res) if (!res)
@ -1731,43 +1857,10 @@ leave_vm_out:
if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid)) if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->callerid))
chan->priority+=100; 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; 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) static int count_messages(char *dir)
{ {
int x; int x;
@ -1787,45 +1880,6 @@ static int say_and_wait(struct ast_channel *chan, int num)
return d; 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) static int save_to_folder(char *dir, int msg, char *context, char *username, int box)
{ {
char sfn[256]; char sfn[256];
@ -2422,6 +2476,49 @@ static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu,
return cmd; 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) static int forward_message(struct ast_channel *chan, char *context, char *dir, int curmsg, struct ast_vm_user *sender, char *fmt)
{ {
char username[70]; char username[70];
@ -3363,12 +3460,10 @@ out:
snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context); 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)); 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)); run_externnotify(chan->context, ext_context, ast_app_has_voicemail(ext_context));
} }
LOCAL_USER_REMOVE(u); LOCAL_USER_REMOVE(u);
return res; return res;
} }
static int vm_exec(struct ast_channel *chan, void *data) static int vm_exec(struct ast_channel *chan, void *data)

@ -87,9 +87,9 @@ maxlogins=3
; ;
; Advanced options example is extension 4069 ; Advanced options example is extension 4069
; NOTE: All options can be expressed globally in the general section, and overriden in the per-mailbox ; 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 ; 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, ; saycid=yes ; Say the caller id information before the message. If not described,
; or set to no, it will be in the envelope ; or set to no, it will be in the envelope
@ -102,6 +102,8 @@ maxlogins=3
; reach an operator [OFF by default] ; reach an operator [OFF by default]
; envelope=no ; Turn on/off envelope playback before message playback. [ON 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 ; 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] [zonemessages]
eastern=America/New_York|'vm-received' Q 'digits/at' IMp 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 ;4300 => 3456,Ben Rigas,ben@american-computer.net
;4310 => 5432,Sales,sales@marko.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 ;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 ;4110 => 3443,Rob Flynn,rflynn@blueridge.net
; ;

@ -28,6 +28,7 @@
#include <stdio.h> #include <stdio.h>
#include <fcntl.h> #include <fcntl.h>
#include <dirent.h> #include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include "asterisk.h" #include "asterisk.h"
#include "astconf.h" #include "astconf.h"
@ -241,6 +242,7 @@ static int copy(char *infile, char *outfile)
int res; int res;
int len; int len;
char buf[4096]; char buf[4096];
if ((ifd = open(infile, O_RDONLY)) < 0) { if ((ifd = open(infile, O_RDONLY)) < 0) {
ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile); ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
return -1; return -1;
@ -343,6 +345,9 @@ static int ast_filehelper(char *filename, char *filename2, char *fmt, int action
/* Try each kind of extension */ /* Try each kind of extension */
stringp=exts; stringp=exts;
ext = strsep(&stringp, "|"); ext = strsep(&stringp, "|");
if (!strcmp(ext,"wav49")) {
ext = "WAV";
}
do { do {
fn = build_filename(filename, ext); fn = build_filename(filename, ext);
if (fn) { if (fn) {

Loading…
Cancel
Save