Merged revisions 27636 via svnmerge from
authorTilghman Lesher <tilghman@meg.abyt.es>
Wed, 17 May 2006 02:27:17 +0000 (02:27 +0000)
committerTilghman Lesher <tilghman@meg.abyt.es>
Wed, 17 May 2006 02:27:17 +0000 (02:27 +0000)
https://origsvn.digium.com/svn/asterisk/branches/1.2

........
r27636 | tilghman | 2006-05-16 21:19:50 -0500 (Tue, 16 May 2006) | 2 lines

Bug 7125 - Fix race condition between resequencing and leaving a message

........

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@27637 65c4cc65-6c06-0410-ace0-fbb531ad65f3

apps/app_voicemail.c

index 66ccf42..4e243a3 100644 (file)
@@ -2413,17 +2413,17 @@ struct leave_vm_options {
 
 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
 {
-       char tmptxtfile[256], txtfile[256];
+       char txtfile[256], tmptxtfile[256];
        char callerid[256];
        FILE *txt;
-       int res = 0;
+       int res = 0, txtdes;
        int msgnum;
        int duration = 0;
        int ausemacro = 0;
        int ousemacro = 0;
        int ouseexten = 0;
        char date[256];
-       char dir[256];
+       char dir[256], tmpdir[260];
        char fn[256];
        char prefile[256]="";
        char tempfile[256]="";
@@ -2475,6 +2475,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
        DISPOSE(tempfile, -1);
        /* It's easier just to try to make it than to check for its existence */
        create_dirpath(dir, sizeof(dir), vmu->context, ext, "INBOX");
+       create_dirpath(tmpdir, sizeof(tmpdir), vmu->context, ext, "tmp");
 
        /* Check current or macro-calling context for special extensions */
        if (ast_test_flag(vmu, VM_OPERATOR)) {
@@ -2579,121 +2580,129 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
        if (!ast_strlen_zero(fmt)) {
                msgnum = 0;
 
-               if (vm_lock_path(dir)) {
-                       free_user(vmu);
-                       return ERROR_LOCK_PATH;
+               if (count_messages(vmu, dir) >= vmu->maxmsg) {
+                       res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
+                       if (!res)
+                               res = ast_waitstream(chan, "");
+                       ast_log(LOG_WARNING, "No more messages possible\n");
+                       pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
+                       goto leave_vm_out;
                }
 
-               /* 
-                * This operation can be very expensive if done say over NFS or if the mailbox has 100+ messages
-                * in the folder.  So we should get this first so we don't cut off the first few seconds of the 
-                * message.  
-                */
-               do {
-                       make_file(fn, sizeof(fn), dir, msgnum);
-                       if (!EXISTS(dir,msgnum,fn,chan->language))
-                               break;
-                       msgnum++;
-               } while (msgnum < vmu->maxmsg);
+               snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
+               txtdes = mkstemp(tmptxtfile);
+               if (txtdes < 0) {
+                       res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
+                       if (!res)
+                               res = ast_waitstream(chan, "");
+                       ast_log(LOG_ERROR, "Unable to create message file: %s\n", strerror(errno));
+                       pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
+                       goto leave_vm_out;
+               }
 
                /* Now play the beep once we have the message number for our next message. */
                if (res >= 0) {
                        /* Unless we're *really* silent, try to send the beep */
                        res = ast_stream_and_wait(chan, "beep", chan->language, "");
                }
-               if (msgnum < vmu->maxmsg) {
-                       /* assign a variable with the name of the voicemail file */       
-                       pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
-                               
-                       /* Store information */
-                       snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
-                       snprintf(tmptxtfile, sizeof(tmptxtfile), "%s.txt.tmp", fn);
-                       txt = fopen(tmptxtfile, "w+");
-                       if (txt) {
-                               get_date(date, sizeof(date));
-                               fprintf(txt, 
-                                       ";\n"
-                                       "; Message Information file\n"
-                                       ";\n"
-                                       "[message]\n"
-                                       "origmailbox=%s\n"
-                                       "context=%s\n"
-                                       "macrocontext=%s\n"
-                                       "exten=%s\n"
-                                       "priority=%d\n"
-                                       "callerchan=%s\n"
-                                       "callerid=%s\n"
-                                       "origdate=%s\n"
-                                       "origtime=%ld\n"
-                                       "category=%s\n",
-                                       ext,
-                                       chan->context,
-                                       chan->macrocontext, 
-                                       chan->exten,
-                                       chan->priority,
-                                       chan->name,
-                                       ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"),
-                                       date, (long)time(NULL),
-                                       category ? category : ""); 
-                       } else
-                               ast_log(LOG_WARNING, "Error opening text file for output\n");
-                       res = play_record_review(chan, NULL, fn, vmmaxmessage, fmt, 1, vmu, &duration, dir, options->record_gain);
-                       if (res == '0') {
-                               if (txt && EXISTS(dir,msgnum,fn,chan->language)) {
-                                       fclose(txt);
-                                       rename(tmptxtfile, txtfile);
-                               } else if (txt && !EXISTS(dir,msgnum,fn,chan->language)) {
-                                       if (option_debug) 
-                                               ast_log(LOG_DEBUG, "The recorded media file is gone, so we should remove the .txt file too!\n");
-                                       fclose(txt);
-                                       unlink(tmptxtfile);     
-                               }
-                               goto transfer;
-                       }
-                       if (res > 0)
-                               res = 0;
-                       if (txt) {
-                               fprintf(txt, "duration=%d\n", duration);
-                               fclose(txt);
-                               rename(tmptxtfile, txtfile);
-                       }
-                               
+
+               /* Store information */
+               txt = fdopen(txtdes, "w+");
+               if (txt) {
+                       get_date(date, sizeof(date));
+                       fprintf(txt, 
+                               ";\n"
+                               "; Message Information file\n"
+                               ";\n"
+                               "[message]\n"
+                               "origmailbox=%s\n"
+                               "context=%s\n"
+                               "macrocontext=%s\n"
+                               "exten=%s\n"
+                               "priority=%d\n"
+                               "callerchan=%s\n"
+                               "callerid=%s\n"
+                               "origdate=%s\n"
+                               "origtime=%ld\n"
+                               "category=%s\n",
+                               ext,
+                               chan->context,
+                               chan->macrocontext, 
+                               chan->exten,
+                               chan->priority,
+                               chan->name,
+                               ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"),
+                               date, (long)time(NULL),
+                               category ? category : ""); 
+               } else
+                       ast_log(LOG_WARNING, "Error opening text file for output\n");
+               res = play_record_review(chan, NULL, tmptxtfile, vmmaxmessage, fmt, 1, vmu, &duration, NULL, options->record_gain);
+
+               if (txt) {
                        if (duration < vmminmessage) {
                                if (option_verbose > 2) 
                                        ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminmessage);
                                DELETE(dir,msgnum,fn);
-                               /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */
-                               pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
-                               goto leave_vm_out;
-                       }
-                       /* 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);
+                       } else {
+                               fprintf(txt, "duration=%d\n", duration);
+                               fclose(txt);
+                               if (vm_lock_path(dir)) {
+                                       ast_log(LOG_ERROR, "Couldn't lock directory %s.  Voicemail will be lost.\n", dir);
+                                       /* Delete files */
+                                       ast_filedelete(tmptxtfile, NULL);
+                                       unlink(tmptxtfile);
+                               } else {
+                                       for (;;) {
+                                               make_file(fn, sizeof(fn), dir, msgnum);
+                                               if (!EXISTS(dir, msgnum, fn, NULL))
+                                                       break;
+                                               msgnum++;
+                                       }
+
+                                       /* assign a variable with the name of the voicemail file */       
+                                       pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
+
+                                       snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
+                                       ast_filerename(tmptxtfile, fn, NULL);
+                                       rename(tmptxtfile, txtfile);
+
+                                       ast_unlock_path(dir);
+
+                                       /* 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);
+                                               }
+                                       }
+                                       if (ast_fileexists(fn, NULL, NULL)) {
+                                               STORE(dir, vmu->mailbox, vmu->context, msgnum);
+                                               notify_new_message(chan, vmu, msgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name);
+                                               DISPOSE(dir, msgnum);
+                                       }
                                }
                        }
-                       if (ast_fileexists(fn, NULL, NULL)) {
-                               STORE(dir, vmu->mailbox, vmu->context, msgnum);
-                               notify_new_message(chan, vmu, msgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name);
-                               DISPOSE(dir, msgnum);
-                       }
-                       pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
-               } else {
-                       ast_unlock_path(dir);
-                       res = ast_stream_and_wait(chan, "vm-mailboxfull", chan->language, "");
-                       ast_log(LOG_WARNING, "No more messages possible\n");
-                       pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
                }
+
+               if (res == '0') {
+                       goto transfer;
+               } else if (res > 0)
+                       res = 0;
+
+               if (duration < vmminmessage)
+                       /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */
+                       pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
+               else
+                       pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
        } else
                ast_log(LOG_WARNING, "No format for saving voicemail?\n");
  leave_vm_out: