[asterisk-commits] branch 1.2 r27636 - /branches/1.2/apps/app_voicemail.c

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Tue May 16 19:19:51 MST 2006


Author: tilghman
Date: Tue May 16 21:19:50 2006
New Revision: 27636

URL: http://svn.digium.com/view/asterisk?rev=27636&view=rev
Log:
Bug 7125 - Fix race condition between resequencing and leaving a message

Modified:
    branches/1.2/apps/app_voicemail.c

Modified: branches/1.2/apps/app_voicemail.c
URL: http://svn.digium.com/view/asterisk/branches/1.2/apps/app_voicemail.c?rev=27636&r1=27635&r2=27636&view=diff
==============================================================================
--- branches/1.2/apps/app_voicemail.c (original)
+++ branches/1.2/apps/app_voicemail.c Tue May 16 21:19:50 2006
@@ -2364,17 +2364,17 @@
 
 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]="";
@@ -2429,6 +2429,7 @@
 	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)) {
@@ -2535,22 +2536,25 @@
 	if (!ast_strlen_zero(fmt)) {
 		msgnum = 0;
 
-		if (vm_lock_path(dir)) {
-			free_user(vmu);
-			return ERROR_LOCK_PATH;
-		}
-
-		/* 
-		 * This operation can be very expensive if done say over NFS or if the mailbox has 100+ messages
-		 * in the mailbox.  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);
+		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;
+		}
+
+		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) {
@@ -2559,101 +2563,104 @@
 			if (!res)
 				res = ast_waitstream(chan, "");
 		}
-		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++;
+			} 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 ((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 (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_unlock_path(dir);
-			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");
-		}
 	} else
 		ast_log(LOG_WARNING, "No format for saving voicemail?\n");
  leave_vm_out:



More information about the asterisk-commits mailing list