fix simultaneous voicemail messages -- Thanks Robert! (bug #3394)

git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4914 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Russell Bryant
2005-01-29 06:53:33 +00:00
parent 1ef98ac6de
commit 081e28667e
3 changed files with 101 additions and 32 deletions

79
app.c
View File

@@ -518,7 +518,7 @@ int ast_play_and_wait(struct ast_channel *chan, char *fn)
static int global_silence_threshold = 128; static int global_silence_threshold = 128;
static int global_maxsilence = 0; static int global_maxsilence = 0;
int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int silencethreshold, int maxsilence) int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path)
{ {
char d, *fmts; char d, *fmts;
char comment[256]; char comment[256];
@@ -528,7 +528,7 @@ int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfi
char *sfmt[MAX_OTHER_FORMATS]; char *sfmt[MAX_OTHER_FORMATS];
char *stringp=NULL; char *stringp=NULL;
time_t start, end; time_t start, end;
struct ast_dsp *sildet; /* silence detector dsp */ struct ast_dsp *sildet=NULL; /* silence detector dsp */
int totalsilence = 0; int totalsilence = 0;
int dspsilence = 0; int dspsilence = 0;
int gotsilence = 0; /* did we timeout for silence? */ int gotsilence = 0; /* did we timeout for silence? */
@@ -585,18 +585,22 @@ int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfi
} }
} }
sildet = ast_dsp_new(); /* Create the silence detector */ if (path)
if (!sildet) { ast_unlock_path(path);
ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
return -1;
}
ast_dsp_set_threshold(sildet, silencethreshold);
if (maxsilence > 0) { if (maxsilence > 0) {
sildet = ast_dsp_new(); /* Create the silence detector */
if (!sildet) {
ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
return -1;
}
ast_dsp_set_threshold(sildet, silencethreshold);
rfmt = chan->readformat; rfmt = chan->readformat;
res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
if (res < 0) { if (res < 0) {
ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
ast_dsp_free(sildet);
return -1; return -1;
} }
} }
@@ -640,13 +644,13 @@ int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfi
totalsilence = 0; totalsilence = 0;
if (totalsilence > maxsilence) { if (totalsilence > maxsilence) {
/* Ended happily with silence */ /* Ended happily with silence */
if (option_verbose > 2) if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000); ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
ast_frfree(f); ast_frfree(f);
gotsilence = 1; gotsilence = 1;
outmsg=2; outmsg=2;
break; break;
} }
} }
/* Exit on any error */ /* Exit on any error */
@@ -725,6 +729,8 @@ int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfi
if(!ast_streamfile(chan, "auth-thankyou", chan->language)) if(!ast_streamfile(chan, "auth-thankyou", chan->language))
ast_waitstream(chan, ""); ast_waitstream(chan, "");
} }
if (sildet)
ast_dsp_free(sildet);
return res; return res;
} }
@@ -960,3 +966,46 @@ int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordf
return res; return res;
} }
int ast_lock_path(const char *path)
{
char *s;
char *fs;
int res;
int fd;
time_t start;
s = alloca(strlen(path) + 10);
fs = alloca(strlen(path) + 20);
if (!fs || !s) {
ast_log(LOG_WARNING, "Out of memory!\n");
return -1;
}
snprintf(fs, strlen(path) + 19, "%s/%s-%08x", path, ".lock", rand());
fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd < 0) {
fprintf(stderr, "Unable to create lock file: %s\n", strerror(errno));
return -1;
}
close(fd);
snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
time(&start);
while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
usleep(1);
if (res < 0) {
ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
}
unlink(fs);
ast_log(LOG_DEBUG, "Locked path '%s'\n", path);
return res;
}
int ast_unlock_path(const char *path)
{
char *s;
s = alloca(strlen(path) + 10);
if (!s)
return -1;
snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
return unlink(s);
}

View File

@@ -176,7 +176,7 @@ struct vm_state {
}; };
static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option); static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option);
static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context); static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration); static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir);
static int vm_delete(char *file); static int vm_delete(char *file);
static int vm_play_folder_name(struct ast_channel *chan, char *mbox); static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
@@ -713,11 +713,13 @@ static int last_message_index(char *dir)
{ {
int x; int x;
char fn[256]; char fn[256];
for (x=0;x<MAXMSG;x++) { ast_lock_path(dir);
for (x=0;x<MAXMSG;x++) {
make_file(fn, sizeof(fn), dir, x); make_file(fn, sizeof(fn), dir, x);
if (ast_fileexists(fn, NULL, NULL) < 1) if (ast_fileexists(fn, NULL, NULL) < 1)
break; break;
} }
ast_unlock_path(dir);
return x-1; return x-1;
} }
@@ -1255,6 +1257,7 @@ static void copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int
make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox); make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
make_file(frompath, sizeof(frompath), fromdir, msgnum); make_file(frompath, sizeof(frompath), fromdir, msgnum);
ast_lock_path(topath);
recipmsgnum = 0; recipmsgnum = 0;
do { do {
make_file(topath, sizeof(topath), todir, recipmsgnum); make_file(topath, sizeof(topath), todir, recipmsgnum);
@@ -1271,7 +1274,7 @@ static void copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int
} else { } else {
ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context); ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
} }
ast_unlock_path(topath);
notify_new_message(chan, recip, recipmsgnum, duration, fmt, chan->callerid); notify_new_message(chan, recip, recipmsgnum, duration, fmt, chan->callerid);
} }
@@ -1444,18 +1447,19 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
strncpy(fmt, vmfmts, sizeof(fmt) - 1); strncpy(fmt, vmfmts, sizeof(fmt) - 1);
if (!ast_strlen_zero(fmt)) { if (!ast_strlen_zero(fmt)) {
msgnum = 0; msgnum = 0;
do {
make_file(fn, sizeof(fn), dir, msgnum);
if (ast_fileexists(fn, NULL, chan->language) <= 0)
break;
msgnum++;
} while(msgnum < MAXMSG);
if (res >= 0) { if (res >= 0) {
/* Unless we're *really* silent, try to send the beep */ /* Unless we're *really* silent, try to send the beep */
res = ast_streamfile(chan, "beep", chan->language); res = ast_streamfile(chan, "beep", chan->language);
if (!res) if (!res)
res = ast_waitstream(chan, ""); res = ast_waitstream(chan, "");
} }
ast_lock_path(dir);
do {
make_file(fn, sizeof(fn), dir, msgnum);
if (ast_fileexists(fn, NULL, chan->language) <= 0)
break;
msgnum++;
} while(msgnum < MAXMSG);
if (msgnum < MAXMSG) { if (msgnum < MAXMSG) {
/* Store information */ /* Store information */
snprintf(txtfile, sizeof(txtfile), "%s.txt", fn); snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
@@ -1487,7 +1491,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
fclose(txt); fclose(txt);
} else } else
ast_log(LOG_WARNING, "Error opening text file for output\n"); ast_log(LOG_WARNING, "Error opening text file for output\n");
res = play_record_review(chan, NULL, fn, vmmaxmessage, fmt, 1, vmu, &duration); res = play_record_review(chan, NULL, fn, vmmaxmessage, fmt, 1, vmu, &duration, dir);
if (res == '0') if (res == '0')
goto transfer; goto transfer;
if (res > 0) if (res > 0)
@@ -1527,6 +1531,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
if (ast_fileexists(fn, NULL, NULL)) if (ast_fileexists(fn, NULL, NULL))
notify_new_message(chan, vmu, msgnum, duration, fmt, chan->callerid); notify_new_message(chan, vmu, msgnum, duration, fmt, chan->callerid);
} else { } else {
ast_unlock_path(dir);
res = ast_streamfile(chan, "vm-mailboxfull", chan->language); res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
if (!res) if (!res)
res = ast_waitstream(chan, ""); res = ast_waitstream(chan, "");
@@ -1579,6 +1584,7 @@ static void resequence_mailbox(char * dir)
char stxt[256]; char stxt[256];
char dtxt[256]; char dtxt[256];
ast_lock_path(dir);
for (x=0,dest=0;x<MAXMSG;x++) { for (x=0,dest=0;x<MAXMSG;x++) {
make_file(sfn, sizeof(sfn), dir, x); make_file(sfn, sizeof(sfn), dir, x);
if (ast_fileexists(sfn, NULL, NULL) > 0) { if (ast_fileexists(sfn, NULL, NULL) > 0) {
@@ -1595,6 +1601,7 @@ static void resequence_mailbox(char * dir)
dest++; dest++;
} }
} }
ast_unlock_path(dir);
} }
@@ -1617,19 +1624,23 @@ static int save_to_folder(char *dir, int msg, char *context, char *username, int
make_file(sfn, sizeof(sfn), dir, msg); make_file(sfn, sizeof(sfn), dir, msg);
make_dir(ddir, sizeof(ddir), context, username, dbox); make_dir(ddir, sizeof(ddir), context, username, dbox);
mkdir(ddir, 0700); mkdir(ddir, 0700);
ast_lock_path(ddir);
for (x=0;x<MAXMSG;x++) { for (x=0;x<MAXMSG;x++) {
make_file(dfn, sizeof(dfn), ddir, x); make_file(dfn, sizeof(dfn), ddir, x);
if (ast_fileexists(dfn, NULL, NULL) < 0) if (ast_fileexists(dfn, NULL, NULL) < 0)
break; break;
} }
if (x >= MAXMSG) if (x >= MAXMSG) {
ast_unlock_path(ddir);
return -1; return -1;
}
ast_filecopy(sfn, dfn, NULL); ast_filecopy(sfn, dfn, NULL);
if (strcmp(sfn, dfn)) { if (strcmp(sfn, dfn)) {
snprintf(txt, sizeof(txt), "%s.txt", sfn); snprintf(txt, sizeof(txt), "%s.txt", sfn);
snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn); snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
copy(txt, ntxt); copy(txt, ntxt);
} }
ast_unlock_path(ddir);
return 0; return 0;
} }
@@ -2619,6 +2630,7 @@ static void close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
char txt[256] = ""; char txt[256] = "";
if (vms->lastmsg > -1) { if (vms->lastmsg > -1) {
/* Get the deleted messages fixed */ /* Get the deleted messages fixed */
ast_lock_path(vms->curdir);
vms->curmsg = -1; vms->curmsg = -1;
for (x=0;x < MAXMSG;x++) { for (x=0;x < MAXMSG;x++) {
if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) { if (!vms->deleted[x] && (strcasecmp(vms->curbox, "INBOX") || !vms->heard[x])) {
@@ -2645,6 +2657,7 @@ static void close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
break; break;
vm_delete(vms->fn); vm_delete(vms->fn);
} }
ast_unlock_path(vms->curdir);
} }
memset(vms->deleted, 0, sizeof(vms->deleted)); memset(vms->deleted, 0, sizeof(vms->deleted));
memset(vms->heard, 0, sizeof(vms->heard)); memset(vms->heard, 0, sizeof(vms->heard));
@@ -3123,15 +3136,15 @@ static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct
switch (cmd) { switch (cmd) {
case '1': case '1':
snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/unavail",vmu->context, vms->username); snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/unavail",vmu->context, vms->username);
cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration); cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL);
break; break;
case '2': case '2':
snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/busy",vmu->context, vms->username); snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/busy",vmu->context, vms->username);
cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration); cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL);
break; break;
case '3': case '3':
snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/greet",vmu->context, vms->username); snprintf(prefile,sizeof(prefile),"voicemail/%s/%s/greet",vmu->context, vms->username);
cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration); cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL);
break; break;
case '4': case '4':
if (vmu->password[0] == '-') { if (vmu->password[0] == '-') {
@@ -4583,7 +4596,7 @@ static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, s
static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration) static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir)
{ {
/* Record message & let caller review or re-record it, or set options if applicable */ /* Record message & let caller review or re-record it, or set options if applicable */
int res = 0; int res = 0;
@@ -4636,7 +4649,7 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
} }
recorded = 1; recorded = 1;
/* After an attempt has been made to record message, we have to take care of INTRO and beep for incoming messages, but not for greetings */ /* After an attempt has been made to record message, we have to take care of INTRO and beep for incoming messages, but not for greetings */
cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence); cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir);
if (cmd == -1) if (cmd == -1)
/* User has hung up, no options to give */ /* User has hung up, no options to give */
return cmd; return cmd;

View File

@@ -62,12 +62,19 @@ int ast_play_and_wait(struct ast_channel *chan, char *fn);
//! Record a file for a max amount of time (in seconds), in a given list of formats separated by '|', outputting the duration of the recording, and with a maximum //! Record a file for a max amount of time (in seconds), in a given list of formats separated by '|', outputting the duration of the recording, and with a maximum
// permitted silence time in milliseconds of 'maxsilence' under 'silencethreshold' or use '-1' for either or both parameters for defaults. // permitted silence time in milliseconds of 'maxsilence' under 'silencethreshold' or use '-1' for either or both parameters for defaults.
int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime_sec, char *fmt, int *duration, int silencethreshold, int maxsilence_ms); // calls ast_unlock_path() on 'path' if passed
int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime_sec, char *fmt, int *duration, int silencethreshold, int maxsilence_ms, const char *path);
//! Record a message and prepend the message to the given record file after playing the optional playfile (or a beep), storing the duration in 'duration' and with a maximum //! Record a message and prepend the message to the given record file after playing the optional playfile (or a beep), storing the duration in 'duration' and with a maximum
// permitted silence time in milliseconds of 'maxsilence' under 'silencethreshold' or use '-1' for either or both parameters for defaults. // permitted silence time in milliseconds of 'maxsilence' under 'silencethreshold' or use '-1' for either or both parameters for defaults.
int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime_sec, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence_ms); int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime_sec, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence_ms);
/* Lock a path */
int ast_lock_path(const char *path);
/* Unlock a path */
int ast_unlock_path(const char *path);
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
} }
#endif #endif