]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
fix simultaneous voicemail messages -- Thanks Robert! (bug #3394)
authorRussell Bryant <russell@russellbryant.com>
Sat, 29 Jan 2005 06:53:33 +0000 (06:53 +0000)
committerRussell Bryant <russell@russellbryant.com>
Sat, 29 Jan 2005 06:53:33 +0000 (06:53 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/v1-0@4914 65c4cc65-6c06-0410-ace0-fbb531ad65f3

app.c
apps/app_voicemail.c
include/asterisk/app.h

diff --git a/app.c b/app.c
index 61cb63cd4cfcf737d053eea2c14b0a380e03f60b..4ecc452681db7eebd1a3937ae038bab98ba1c049 100755 (executable)
--- a/app.c
+++ b/app.c
@@ -518,7 +518,7 @@ int ast_play_and_wait(struct ast_channel *chan, char *fn)
 static int global_silence_threshold = 128;
 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 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 *stringp=NULL;
        time_t start, end;
-       struct ast_dsp *sildet;         /* silence detector dsp */
+       struct ast_dsp *sildet=NULL;    /* silence detector dsp */
        int totalsilence = 0;
        int dspsilence = 0;
        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 (!sildet) {
-               ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
-               return -1;
-       }
-       ast_dsp_set_threshold(sildet, silencethreshold);
+       if (path)
+               ast_unlock_path(path);
+
        
        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;
                res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
                if (res < 0) {
                        ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
+                       ast_dsp_free(sildet);
                        return -1;
                }
        }
@@ -640,13 +644,13 @@ int ast_play_and_record(struct ast_channel *chan, char *playfile, char *recordfi
                                                totalsilence = 0;
 
                                        if (totalsilence > maxsilence) {
-                                       /* Ended happily with silence */
-                                        if (option_verbose > 2)
-                                                ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
-                                       ast_frfree(f);
-                                       gotsilence = 1;
-                                       outmsg=2;
-                                       break;
+                                               /* Ended happily with silence */
+                                               if (option_verbose > 2)
+                                                       ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
+                                               ast_frfree(f);
+                                               gotsilence = 1;
+                                               outmsg=2;
+                                               break;
                                        }
                                }
                                /* 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))
                        ast_waitstream(chan, "");
        }
+       if (sildet)
+               ast_dsp_free(sildet);
        return res;
 }
 
@@ -960,3 +966,46 @@ int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordf
        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);
+}
+
index 391130eaa85062134ccab50e7f11bd014de70f6e..8f6b185461a1f95dab51c1bf6fc8901610acbea3 100755 (executable)
@@ -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 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_play_folder_name(struct ast_channel *chan, char *mbox);
 
@@ -713,11 +713,13 @@ static int last_message_index(char *dir)
 {
         int x;
         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);
                 if (ast_fileexists(fn, NULL, NULL) < 1)
                         break;
         }
+       ast_unlock_path(dir);
         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_file(frompath, sizeof(frompath), fromdir, msgnum);
+       ast_lock_path(topath);
        recipmsgnum = 0;
        do {
                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 {
                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);
 }
 
@@ -1444,18 +1447,19 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
                strncpy(fmt, vmfmts, sizeof(fmt) - 1);
                if (!ast_strlen_zero(fmt)) {
                        msgnum = 0;
+                       if (res >= 0) {
+                               /* Unless we're *really* silent, try to send the beep */
+                               res = ast_streamfile(chan, "beep", chan->language);
+                               if (!res)
+                                       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 (res >= 0) {
-                               /* Unless we're *really* silent, try to send the beep */
-                               res = ast_streamfile(chan, "beep", chan->language);
-                               if (!res)
-                                       res = ast_waitstream(chan, "");
-                       }       
                        if (msgnum < MAXMSG) {
                                /* Store information */
                                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);
                                } else
                                        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')
                                        goto transfer;
                                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))     
                                        notify_new_message(chan, vmu, msgnum, duration, fmt, chan->callerid);
                        } else {
+                               ast_unlock_path(dir);
                                res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
                                if (!res)
                                        res = ast_waitstream(chan, "");
@@ -1579,6 +1584,7 @@ static void resequence_mailbox(char * dir)
        char stxt[256];
        char dtxt[256];
 
+       ast_lock_path(dir);
        for (x=0,dest=0;x<MAXMSG;x++) {
                make_file(sfn, sizeof(sfn), dir, x);
                if (ast_fileexists(sfn, NULL, NULL) > 0) {
@@ -1595,6 +1601,7 @@ static void resequence_mailbox(char * dir)
                        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_dir(ddir, sizeof(ddir), context, username, dbox);
        mkdir(ddir, 0700);
+       ast_lock_path(ddir);
        for (x=0;x<MAXMSG;x++) {
                make_file(dfn, sizeof(dfn), ddir, x);
                if (ast_fileexists(dfn, NULL, NULL) < 0)
                        break;
        }
-       if (x >= MAXMSG)
+       if (x >= MAXMSG) {
+               ast_unlock_path(ddir);
                return -1;
+       }
        ast_filecopy(sfn, dfn, NULL);
        if (strcmp(sfn, dfn)) {
                snprintf(txt, sizeof(txt), "%s.txt", sfn);
                snprintf(ntxt, sizeof(ntxt), "%s.txt", dfn);
                copy(txt, ntxt);
        }
+       ast_unlock_path(ddir);
        return 0;
 }
 
@@ -2619,6 +2630,7 @@ static void close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
        char txt[256] = "";
        if (vms->lastmsg > -1) { 
                /* Get the deleted messages fixed */ 
+               ast_lock_path(vms->curdir);
                vms->curmsg = -1; 
                for (x=0;x < MAXMSG;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;
                        vm_delete(vms->fn);
                } 
+               ast_unlock_path(vms->curdir);
        } 
        memset(vms->deleted, 0, sizeof(vms->deleted)); 
        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) {
                case '1':
                        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;
                case '2': 
                        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;
                case '3': 
                        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;
                case '4':
                        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 */
        int res = 0;
@@ -4636,7 +4649,7 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
                        }
                        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 */
-                       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)
                        /* User has hung up, no options to give */
                                return cmd;
index 4b26a73eac1951d0db2efbe704295d18cbc87723..6330467da51f65d27e2e7e8624c56ec6b36d12bb 100755 (executable)
@@ -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
 //  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
 //  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);
 
+/* 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)
 }
 #endif