[svn-commits] branch oej/voicemail-ng r12490 - /team/oej/voicemail-ng/apps/app_voicemail.c

svn-commits at lists.digium.com svn-commits at lists.digium.com
Fri Mar 10 01:10:19 MST 2006


Author: oej
Date: Fri Mar 10 02:10:17 2006
New Revision: 12490

URL: http://svn.digium.com/view/asterisk?rev=12490&view=rev
Log:
Issue #6512 - ast_vm_message abstraction

Modified:
    team/oej/voicemail-ng/apps/app_voicemail.c

Modified: team/oej/voicemail-ng/apps/app_voicemail.c
URL: http://svn.digium.com/view/asterisk/team/oej/voicemail-ng/apps/app_voicemail.c?rev=12490&r1=12489&r2=12490&view=diff
==============================================================================
--- team/oej/voicemail-ng/apps/app_voicemail.c (original)
+++ team/oej/voicemail-ng/apps/app_voicemail.c Fri Mar 10 02:10:17 2006
@@ -288,11 +288,107 @@
 	int (*has_voicemail)(const char *mailbox, const char *folder);
 };
 
+/* Message abstraction */
+
+/* flags */
+#define VM_MSG_FILE_RETRIEVED 0x01 /*!< file has been retrieved from storage */
+#define VM_MSG_IS_NEW         0x02 /*!< message is newly created */
+
+/*! Message handle.  This should be a mostly opaque type; direct
+  access to its members is strongly discouraged except from within the
+  ast_vm_message_* functions.
+
+  Instances of this structure shouldn't stay around for long; the user
+  object stored in them is owned by the calling code (for now), and the
+  directory where the voicemail is stored is locked for the lifetime of
+  this object.  These objects should be instantiated, used, and then
+  immediately released.
+ */
+
+struct ast_vm_message
+{
+	char context[256];        /*!< The context of this voicemail box */
+	char mailbox[256];        /*!< The mailbox for this voicemail */
+	char dir[256];            /*!< The directory where the voicemail files are stored */
+	char fn[256];             /*!< The base filename (without .txt, .gsm,
+				       etc.) for the voicemail files.  Each voicemail is
+				       stored in several files, which are formed by
+				       adding various extensions to this member. */
+	char fmt[80];             /*!< A |-separated list of the formats this voicemail is stored in */
+	int msgnum;               /*!< The index number of this message within its folder */
+	struct ast_vm_user *user; /*!< The user structure this voicemail is for */
+	int flags;                /*!< Flags; see VM_MSG_* above */
+
+	struct ast_channel *chan; /*!< HACK: The channel associated with a new message */
+	int duration;             /*!< HACK: The duration of a new message, once it's known */
+};
+
+/*! Create a new voicemail message.  Only used when an actual new voicemail
+    is being recorded.
+
+    \param vmu  The user for whom the voicemail's being left.  Do not free this
+                  while the message handle still exists.
+    \param chan The channel from which the voicemail's being recorded
+    \param fmt  A |-separated list of formats in which the message should be stored
+    \return     A new message handle; call ast_vm_message_release() on it when you're done.
+ */
+static struct ast_vm_message *ast_vm_message_create(struct ast_vm_user *vmu, struct ast_channel *chan, const char *fmt);
+
+/*! Create a new voicemail message from another.
+
+    Warning: Using this to make another copy of a message within the same folder
+    will cause a deadlock.
+
+    \param src   The message to copy
+    \param recip The user to send the copy of the voicemail to
+    \param chan  The channel from which the original voicemail was recorded (for
+                   caller ID data)
+    \param fmt   A |-separated list of formats in which the message should be stored 
+*/
+static struct ast_vm_message *ast_vm_message_create_copy(struct ast_vm_message *src, struct ast_vm_user *recip, struct ast_channel *chan, char *fmt);
+
+/*! Release a voicemail message handle, unlocking the directory and freeing
+    the in-memory storage.
+
+    \param message  The message to release
+*/
+static void ast_vm_message_release(struct ast_vm_message *message);
+
+/*! Delete a voicemail message, and release the handle which was being used
+    to access the message.
+
+    Currently this only works properly for canceling new messages.
+
+    \param message  The message to delete
+*/
+static void ast_vm_message_delete_and_release(struct ast_vm_message *message);
+
+/*! Get the sound file associated with a message.
+
+    \param message     The message to get the data for
+    \param filename    A buffer to store the filename in
+    \param filenamelen The size of the buffer
+    \param fmt         The format desired.  NULL means any format.  "" means
+                       to return the raw filename (before appending the
+		       format extension).
+    \return            0 on success, nonzero on failure
+*/
+static int ast_vm_message_get_data(struct ast_vm_message *message, char *filename, int filenamelen, char *fmt);
+
+/*! Write metadata associated with a message.
+
+    \param message The message to write metadata for
+    \param fmt     printf arguments to print to the metadata file.
+*/
+static void ast_vm_message_printf_metadata(struct ast_vm_message *message, const char *fmt, ...);
+
+/* End message abstraction */
+
 static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg,
 			    int option, signed char record_gain);
 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, const char *unlockdir,
+			      char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration,
 			      signed char record_gain);
 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
@@ -2292,42 +2388,6 @@
 	return 0;
 }
 
-static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname);
-
-static int 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);
-
-	create_dirpath(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
-  
-	make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
-	make_file(frompath, sizeof(frompath), fromdir, msgnum);
-
-	if (vm_lock_path(todir))
-		return ERROR_LOCK_PATH;
-
-	recipmsgnum = 0;
-	do {
-		make_file(topath, sizeof(topath), todir, recipmsgnum);
-		if (!storage->message_exists(todir, recipmsgnum, topath, chan->language))
-			break;
-		recipmsgnum++;
-	} while (recipmsgnum < recip->maxmsg);
-	if (recipmsgnum < recip->maxmsg) {
-		storage->copy_file(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
-	} else {
-		ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
-	}
-	ast_unlock_path(todir);
-	notify_new_message(chan, recip, recipmsgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name);
-	
-	return 0;
-}
-
 static void run_externnotify(char *context, char *extension)
 {
 	char arguments[255];
@@ -2381,16 +2441,11 @@
 
 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
 {
-	char txtfile[256];
 	char callerid[256];
-	FILE *txt;
 	int res = 0;
-	int msgnum;
-	int duration = 0;
 	int ausemacro = 0;
 	int ousemacro = 0;
 	char date[256];
-	char dir[256];
 	char fn[256];
 	char prefile[256]="";
 	char tempfile[256]="";
@@ -2402,6 +2457,8 @@
 	struct ast_vm_user *vmu;
 	struct ast_vm_user svm;
 	const char *category = NULL;
+	struct ast_vm_message *message = NULL;
+	char duration_string[256];
 
 	ast_copy_string(tmp, ext, sizeof(tmp));
 	ext = tmp;
@@ -2443,8 +2500,6 @@
 	if (ast_fileexists(tempfile, NULL, NULL) > 0)
 		ast_copy_string(prefile, tempfile, sizeof(prefile));
 	storage->dispose_file(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");
 
 	/* Check current or macro-calling context for special extensions */
 	if (!ast_strlen_zero(vmu->exit)) {
@@ -2543,28 +2598,17 @@
 		pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
 		return -1;
 	}
-	/* The meat of recording the message...  All the announcements and beeps have been played*/
+       /* The meat of recording the message...  All the announcements have been played, but not the beep */
 	ast_copy_string(fmt, vmfmts, sizeof(fmt));
 	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 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 (!storage->message_exists(dir,msgnum,fn,chan->language))
-				break;
-			msgnum++;
-		} while (msgnum < vmu->maxmsg);
-
+
+		message = ast_vm_message_create(vmu, chan, fmt);
+	    
 		/* 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 */
@@ -2572,16 +2616,24 @@
 			if (!res)
 				res = ast_waitstream(chan, "");
 		}
-		if (msgnum < vmu->maxmsg) {
+		if (message != NULL) {
+			get_date(date, sizeof(date));
+
+			ast_vm_message_get_data(message, fn, sizeof(fn), "");
+
 			/* assign a variable with the name of the voicemail file */	  
 			pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
 				
+			/* duration is a HACK */
+			res = play_record_review(chan, NULL, fn, vmmaxmessage, fmt, 1, vmu, &(message->duration), options->record_gain);
+
+			if (res != '0')
+				snprintf(duration_string, sizeof(duration_string), "duration=%d\n", message->duration);
+			else
+				duration_string[0] = '0';
+
 			/* Store information */
-			snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
-			txt = fopen(txtfile, "w+");
-			if (txt) {
-				get_date(date, sizeof(date));
-				fprintf(txt, 
+			ast_vm_message_printf_metadata(message,
 					";\n"
 					"; Message Information file\n"
 					";\n"
@@ -2595,7 +2647,8 @@
 					"callerid=%s\n"
 					"origdate=%s\n"
 					"origtime=%ld\n"
-					"category=%s\n",
+					"category=%s\n"
+					"%s",
 					ext,
 					chan->context,
 					chan->macrocontext, 
@@ -2604,26 +2657,19 @@
 					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)
-					fclose(txt);
+					category ? category : "",
+					duration_string); 
+
+			if (res == '0')
 				goto transfer;
-			}
 			if (res > 0)
 				res = 0;
-			if (txt) {
-				fprintf(txt, "duration=%d\n", duration);
-				fclose(txt);
-			}
 				
-			if (duration < vmminmessage) {
+			if (message->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);
-				storage->delete_file(dir,msgnum,fn);
+					ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", message->duration, vmminmessage);
+				ast_vm_message_delete_and_release(message);
+
 				/* 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;
@@ -2640,18 +2686,20 @@
 					context++;
 				}
 				if ((recip = find_user(&recipu, context, exten))) {
-					copy_message(chan, vmu, 0, msgnum, duration, recip, fmt);
+					struct ast_vm_message *copy;
+					copy = ast_vm_message_create_copy(message, recip, chan, fmt);
+					if (copy)
+						ast_vm_message_release(copy);
+					else
+						ast_log(LOG_WARNING, "Couldn't copy message to %s\n", recip->mailbox);
 					free_user(recip);
 				}
 			}
-			if (ast_fileexists(fn, NULL, NULL)) {
-				storage->store_file(dir, vmu->mailbox, vmu->context, msgnum);
-				notify_new_message(chan, vmu, msgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name);
-				storage->dispose_file(dir, msgnum);
-			}
+			ast_vm_message_release(message);
 			pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
 		} else {
-			ast_unlock_path(dir);
+			/* FIXME -- we assume that any problem is a full mailbox, which isn't always true */
+		    
 			res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
 			if (!res)
 				res = ast_waitstream(chan, "");
@@ -4724,7 +4772,7 @@
 	/* If forcename is set, have the user record their name */	
 	if (ast_test_flag(vmu, VM_FORCENAME)) {
 		snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
-		cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain);
+		cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, record_gain);
 		if (cmd < 0 || cmd == 't' || cmd == '#')
 			return cmd;
 	}
@@ -4732,11 +4780,11 @@
 	/* If forcegreetings is set, have the user record their greetings */
 	if (ast_test_flag(vmu, VM_FORCEGREET)) {
 		snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
-		cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain);
+		cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, record_gain);
 		if (cmd < 0 || cmd == 't' || cmd == '#')
 			return cmd;
 		snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
-		cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain);
+		cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, record_gain);
 		if (cmd < 0 || cmd == 't' || cmd == '#')
 			return cmd;
 	}
@@ -4770,15 +4818,15 @@
 		switch (cmd) {
 		case '1':
 			snprintf(prefile,sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, vms->username);
-			cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain);
+			cmd = play_record_review(chan,"vm-rec-unv",prefile, maxgreet, fmtc, 0, vmu, &duration, record_gain);
 			break;
 		case '2': 
 			snprintf(prefile,sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, vms->username);
-			cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain);
+			cmd = play_record_review(chan,"vm-rec-busy",prefile, maxgreet, fmtc, 0, vmu, &duration, record_gain);
 			break;
 		case '3': 
 			snprintf(prefile,sizeof(prefile), "%s%s/%s/greet", VM_SPOOL_DIR, vmu->context, vms->username);
-			cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain);
+			cmd = play_record_review(chan,"vm-rec-name",prefile, maxgreet, fmtc, 0, vmu, &duration, record_gain);
 			break;
 		case '4': 
 			cmd = vm_tempgreeting(chan, vmu, vms, fmtc, record_gain);
@@ -4864,12 +4912,12 @@
 			retries = 0;
 		storage->retrieve_file(prefile, -1);
 		if (ast_fileexists(prefile, NULL, NULL) <= 0) {
-			play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain);
+			play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, record_gain);
 			cmd = 't';	
 		} else {
 			switch (cmd) {
 			case '1':
-				cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, record_gain);
+				cmd = play_record_review(chan, "vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, record_gain);
 				break;
 			case '2':
 				storage->delete_file(prefile, -1, prefile);
@@ -6720,7 +6768,7 @@
 }
  
 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,
+			      int outsidecaller, struct ast_vm_user *vmu, int *duration,
 			      signed char record_gain)
 {
 	/* Record message & let caller review or re-record it, or set options if applicable */
@@ -6779,7 +6827,7 @@
  			/* 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 */
 			if (record_gain)
 				ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
-			cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, unlockdir);
+			cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, NULL);
 			if (record_gain)
 				ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
  			if (cmd == -1) {
@@ -6896,6 +6944,129 @@
  }
  
 
+struct ast_vm_message *ast_vm_message_create(struct ast_vm_user *vmu, struct ast_channel *chan, const char *fmt)
+{
+	struct ast_vm_message *message;
+
+	message = (struct ast_vm_message *) malloc(sizeof(struct ast_vm_message));
+	
+	strncpy(message->context, vmu->context, sizeof(message->context));
+	strncpy(message->mailbox, vmu->mailbox, sizeof(message->mailbox));
+	strncpy(message->fmt, fmt, sizeof(message->fmt));
+	message->chan = chan;
+
+	/* It's easier just to try to make it than to check for its existence */
+	if (!create_dirpath(message->dir, sizeof(message->dir), vmu->context, vmu->mailbox, "INBOX")) {
+		free(message);
+		return NULL;
+	}
+	
+	if (vm_lock_path(message->dir)) {
+		ast_log(LOG_WARNING, "Can't lock directory %s\n", message->dir);
+		free(message);
+		return NULL;
+	}
+
+	message->msgnum = 0;
+	do {
+		make_file(message->fn, sizeof(message->fn), message->dir, message->msgnum);
+		if (!storage->message_exists(message->dir,message->msgnum,message->fn,chan->language))
+			break;
+		message->msgnum++;
+	} while (message->msgnum < vmu->maxmsg);
+	if (message->msgnum >= vmu->maxmsg) {
+		ast_log(LOG_WARNING, "Mailbox full writing message to %s\n", message->dir);
+		ast_unlock_path(message->dir);
+		free(message);
+		return NULL;
+	}
+
+	make_file(message->fn, sizeof(message->fn), message->dir, message->msgnum);
+	message->user = vmu;
+	message->flags = (VM_MSG_FILE_RETRIEVED | VM_MSG_IS_NEW);
+	message->duration = 0; /* HACK */
+
+	return message;
+}
+
+/* FIXME deadlock when copying a message to the same directory as the source */
+struct ast_vm_message *ast_vm_message_create_copy(struct ast_vm_message *src, struct ast_vm_user *recip, struct ast_channel *chan, char *fmt)
+{
+	struct ast_vm_message *dest;
+
+	ast_log(LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", src->mailbox, src->context, recip->mailbox, recip->context);
+
+	dest = ast_vm_message_create(recip, chan, fmt);
+	if (dest) {
+	    storage->copy_file(src->dir, src->msgnum, dest->dir, dest->msgnum, recip->mailbox, recip->context, src->fn, dest->fn);
+	    dest->duration = src->duration;
+	} else
+	    ast_log(LOG_ERROR, "Can't copy message from %s@%s to %s@%s\n", src->mailbox, src->context, recip->mailbox, recip->context);
+
+	return dest;
+}
+
+void ast_vm_message_release(struct ast_vm_message *message)
+{
+	if (message->flags & VM_MSG_IS_NEW) {
+		/* FIXME eliminating ast_fileexists test... do we need it? */
+		storage->store_file(message->dir, message->mailbox, message->context, message->msgnum);
+		notify_new_message(message->chan, message->user, message->msgnum, message->duration, message->fmt, message->chan->cid.cid_num, message->chan->cid.cid_name);
+	}
+	if (message->flags & VM_MSG_FILE_RETRIEVED)
+		storage->dispose_file(message->dir, message->msgnum);
+	ast_unlock_path(message->dir);
+	free(message);
+}
+
+void ast_vm_message_delete_and_release(struct ast_vm_message *message)
+{
+	/* FIXME only works for newly-created messages for now */
+	if (message->flags & VM_MSG_IS_NEW)
+		storage->delete_file(message->dir,message->msgnum,message->fn);
+	ast_unlock_path(message->dir);
+	free(message);
+}
+
+/* FIXME format handling could be better */
+int ast_vm_message_get_data(struct ast_vm_message *message, char *filename, int filenamelen, char *fmt)
+{
+	if (!(message->flags & VM_MSG_FILE_RETRIEVED)) {
+		storage->retrieve_file(message->dir, message->msgnum);
+		message->flags |= VM_MSG_FILE_RETRIEVED;
+	}
+	if (fmt == NULL)
+		fmt = message->fmt;
+	if (fmt == "") {
+		strncpy(filename, message->fn, filenamelen);
+		return 0;
+	} else {
+		char one_fmt[80];
+		char *p, *q;
+		strncpy(one_fmt, fmt, sizeof(one_fmt));
+		q = strsep(&p, "|");
+		snprintf(filename, filenamelen, "%s.%s", message->fn, q);
+		return 0;
+	}
+}
+
+void ast_vm_message_printf_metadata(struct ast_vm_message *message, const char *fmt, ...)
+{
+	va_list vars;
+	FILE *txt;
+	char txtfile[256];
+
+	snprintf(txtfile, sizeof(txtfile), "%s.txt", message->fn);
+	txt = fopen(txtfile, "w+");
+	if (txt) {
+		va_start(vars, fmt);
+		vfprintf(txt, fmt, vars);
+		va_end(vars);
+		fclose(txt);
+	} else
+		ast_log(LOG_WARNING, "Error opening text file %s for output\n", txtfile);
+}
+
 int usecount(void)
 {
 	int res;



More information about the svn-commits mailing list