--- app_voicemail.c.cvs	2005-01-06 08:03:06.000000000 -0500
+++ app_voicemail.c	2005-01-06 07:58:46.000000000 -0500
@@ -46,6 +46,9 @@
 #include <sys/mman.h>
 #include <time.h>
 #include <dirent.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/stat.h>
 
 #include "../asterisk.h"
 #include "../astconf.h"
@@ -88,6 +91,20 @@
 #define VM_DELETE		(1 << 12)
 #define VM_ALLOCED		(1 << 13)
 
+struct vm_dist_ext {
+	char extension[256];
+	char context[256];
+	struct vm_dist_ext *next;
+};
+
+struct vm_dist_list {
+	char name[256];
+	char voice_file[256];				// Points to the file name of our recorded list name
+	struct vm_dist_ext *extensions; 		// Points to our first ext in this list
+	struct vm_dist_list *lists;			// Points to our sublists
+	struct vm_dist_list *next;			// Points to the next list in our set
+};
+
 static int load_config(void);
 
 /* Syntaxes supported, not really language codes.
@@ -190,6 +207,14 @@
 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 vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc);
 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
+static struct vm_dist_list *vm_dist_list_read(struct ast_vm_user *vmu, char *listfile);
+static struct vm_dist_list *vm_dist_list_loop(struct ast_vm_user *vmu, struct ast_channel *chan);
+static int vm_dist_list_add(struct ast_vm_user *vmu, struct ast_channel *chan, struct vm_dist_list *list);
+static void vm_dist_list_free( struct vm_dist_list *list);
+static int vm_dist_list_write( struct vm_dist_list *list, char *file);
+static void vm_dist_leave_voicemail(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, int duration, char *fmt, struct vm_dist_list *list);
+
+
 
 #ifdef USE_ODBC_STORAGE
 static char odbc_database[80];
@@ -4504,6 +4529,589 @@
 	return 0;
 }
 
+
+
+static int leave_distributed_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail, struct vm_dist_list *list)
+{
+	char txtfile[256];
+	char callerid[256];
+	FILE *txt;
+	int res = 0;
+	int msgnum;
+	int fd;
+	int duration = 0;
+	int ausemacro = 0;
+	int ousemacro = 0;
+	char date[256];
+	char dir[256];
+	char fn[256];
+	char prefile[256]="";
+	char ext_context[256] = "";
+	char fmt[80];
+	char *context;
+	char ecodes[16] = "#";
+	char tmp[256] = "", *tmpptr;
+	struct ast_vm_user *vmu;
+	struct ast_vm_user svm;
+
+	strncpy(tmp, ext, sizeof(tmp) - 1);
+	ext = tmp;
+	context = strchr(tmp, '@');
+	if (context) {
+		*context = '\0';
+		context++;
+		tmpptr = strchr(context, '&');
+	} else {
+		tmpptr = strchr(ext, '&');
+	}
+
+	if (tmpptr) {
+		*tmpptr = '\0';
+		tmpptr++;
+	}
+
+	if ((vmu = find_user(&svm, context, ext))) {
+		/* Setup pre-file if appropriate */
+		if (strcmp(vmu->context, "default"))
+			snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
+		else
+			strncpy(ext_context, vmu->context, sizeof(ext_context) - 1);
+		if (busy)
+			snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/busy", vmu->context, ext);
+		else if (unavail)
+			snprintf(prefile, sizeof(prefile), "voicemail/%s/%s/unavail", vmu->context, ext);
+		make_dir(dir, sizeof(dir), vmu->context, "", "");
+		/* It's easier just to try to make it than to check for its existence */
+		if (mkdir(dir, 0700) && (errno != EEXIST))
+			ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
+		make_dir(dir, sizeof(dir), vmu->context, ext, "");
+		/* It's easier just to try to make it than to check for its existence */
+		if (mkdir(dir, 0700) && (errno != EEXIST))
+			ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
+		make_dir(dir, sizeof(dir), vmu->context, ext, "INBOX");
+		if (mkdir(dir, 0700) && (errno != EEXIST))
+			ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
+
+		/* Check current or macro-calling context for special extensions */
+		if (!ast_strlen_zero(vmu->exit)) {
+			if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num))
+				strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
+		} else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num))
+			strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
+		else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) {
+			strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
+			ousemacro = 1;
+		}
+
+		if (!ast_strlen_zero(vmu->exit)) {
+			if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num))
+				strncat(ecodes, "*", sizeof(ecodes) -  strlen(ecodes) - 1);
+		} else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num))
+			strncat(ecodes, "*", sizeof(ecodes) -  strlen(ecodes) - 1);
+		else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) {
+			strncat(ecodes, "*", sizeof(ecodes) -  strlen(ecodes) - 1);
+			ausemacro = 1;
+		}
+
+		/* Play the beginning intro if desired */
+		if (!ast_strlen_zero(prefile)) {
+			if (ast_fileexists(prefile, NULL, NULL) > 0) {
+				if (ast_streamfile(chan, prefile, chan->language) > -1) 
+					res = ast_waitstream(chan, ecodes);
+			} else {
+				ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
+				res = invent_message(chan, vmu->context, ext, busy, ecodes);
+			}
+			if (res < 0) {
+				ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
+				free_user(vmu);
+				return -1;
+			}
+		}
+		if (res == '#') {
+			/* On a '#' we skip the instructions */
+			silent = 1;
+			res = 0;
+		}
+		if (!res && !silent) {
+			res = ast_streamfile(chan, INTRO, chan->language);
+			if (!res)
+				res = ast_waitstream(chan, ecodes);
+			if (res == '#') {
+				silent = 1;
+				res = 0;
+			}
+		}
+		if (res > 0)
+			ast_stopstream(chan);
+		/* Check for a '*' here in case the caller wants to escape from voicemail to something
+		other than the operator -- an automated attendant or mailbox login for example */
+		if (res == '*') {
+			strncpy(chan->exten, "a", sizeof(chan->exten) - 1);
+			if (!ast_strlen_zero(vmu->exit)) {
+				strncpy(chan->context, vmu->exit, sizeof(chan->context) - 1);
+			} else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
+				strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
+			}
+			chan->priority = 0;
+			free_user(vmu);
+			return 0;
+		}
+		/* Check for a '0' here */
+		if (res == '0') {
+		transfer:
+			strncpy(chan->exten, "o", sizeof(chan->exten) - 1);
+			if (!ast_strlen_zero(vmu->exit)) {
+				strncpy(chan->context, vmu->exit, sizeof(chan->context) - 1);
+			} else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
+				strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
+			}
+			chan->priority = 0;
+			free_user(vmu);
+			return 0;
+		}
+		if (res < 0) {
+			free_user(vmu);
+			return -1;
+		}
+		/* The meat of recording the message...  All the announcements and beeps have been played*/
+		strncpy(fmt, vmfmts, sizeof(fmt) - 1);
+		if (!ast_strlen_zero(fmt)) {
+			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) {
+				/* 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);
+ 				txt = fopen(txtfile, "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",
+	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));
+					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);
+				if (res == '0')
+					goto transfer;
+				if (res > 0)
+					res = 0;
+				fd = open(txtfile, O_APPEND | O_WRONLY);
+				if (fd > -1) {
+					txt = fdopen(fd, "a");
+					if (txt) {
+						fprintf(txt, "duration=%d\n", duration);
+						fclose(txt);
+					} else
+						close(fd);
+				}
+				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);
+					vm_delete(fn);
+					/* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */
+					goto leave_vm_out;
+				}
+				/* Are there to be more recipients of this message? */
+				vm_dist_leave_voicemail(chan, vmu, msgnum, duration, fmt, list);
+				
+				
+			} else {
+				res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
+				if (!res)
+					res = ast_waitstream(chan, "");
+				ast_log(LOG_WARNING, "No more messages possible\n");
+			}
+		} else
+			ast_log(LOG_WARNING, "No format for saving voicemail?\n");
+leave_vm_out:
+		free_user(vmu);
+	} else {
+		ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
+		/*Send the call to n+101 priority, where n is the current priority*/
+		if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num))
+			chan->priority+=100;
+	}
+
+	return res;
+}
+
+static void vm_dist_leave_voicemail( struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, int duration, char *fmt, struct vm_dist_list *list) {
+	struct ast_vm_user *tmpvmu, recipu;
+	struct vm_dist_ext *tmpext;
+
+	ast_log(LOG_WARNING, "List: %s\n", list->name);
+
+	// First send to all the extensions of the main list
+	tmpext = list->extensions;
+
+	while(tmpext != NULL) {
+		if((tmpvmu = find_user(&recipu, vmu->context, tmpext->extension)))
+			copy_message(chan, vmu, 0, msgnum, duration, tmpvmu, fmt);
+
+		tmpext = tmpext->next;
+	}
+
+	// Child lists
+	if(list->lists != NULL)
+		vm_dist_leave_voicemail(chan, vmu, msgnum, duration, fmt, list->lists);
+
+	// Sibling lists
+	list = list->next;
+	while(list != NULL) {
+		vm_dist_leave_voicemail(chan, vmu, msgnum, duration, fmt, list);
+		list = list->next;
+	}
+}
+
+static void vm_dist_list_free( struct vm_dist_list *list) {
+	struct vm_dist_ext *ext = NULL, *tmp = NULL;
+
+	if(list != NULL) {
+		// First loop through all the extensions and free them all
+		if(list->extensions != NULL) {
+			ext = list->extensions;
+
+			while(ext->next != NULL) {
+				tmp = ext->next;
+				free(ext);
+				ext = tmp;
+			}
+			free(ext);
+		}
+
+		// Now free each list below this
+		if(list->lists != NULL) {
+			vm_dist_list_free(list->lists);
+		}
+
+		// See if we point to another list
+		if(list->next != NULL) {
+			vm_dist_list_free(list->next);
+		}
+
+		// Finally free this list
+		free(list);
+	}
+}
+static int vm_dist_list_add(struct ast_vm_user *vmu, struct ast_channel *chan, struct vm_dist_list *list) {
+	int res;
+	char tmp[256];
+	struct vm_dist_list *tmplist = NULL, *tmplist2 = NULL;
+	struct vm_dist_ext *distext = NULL;
+
+	// Give our instructions
+	ast_streamfile(chan, "vm-dist-add-ext", vmu->language);
+	
+	res = ast_readstring(chan, tmp, 255, 5000, 6000, "#");
+	while((strlen(tmp) != 0) && (res == 0)) {
+		ast_log(LOG_WARNING, "%d\n", res);
+		// Are we dealing with extensions or lists
+		if(strlen(tmp) <= 2) {
+			tmplist = vm_dist_list_read(vmu, tmp);
+		
+			if(tmplist != NULL) {
+				if(list->lists == NULL) {
+					list->lists = tmplist;
+				}
+				else {
+					tmplist2 = list->lists;
+					while(tmplist2->next != NULL) 
+						tmplist2 = tmplist2->next;
+
+						tmplist2->next = tmplist;
+				}
+				ast_log(LOG_WARNING, "List %s successfully added\n", tmp);
+			}
+			else {
+				ast_play_and_wait(chan, "vm-dist-add-invalid");
+			}
+		}
+		else {
+			// Create our extension
+			if(list->extensions == NULL) { // First extension for the list
+				list->extensions = malloc(sizeof(struct vm_dist_ext));
+				bzero(list->extensions, sizeof(struct vm_dist_ext));
+				distext = list->extensions;
+			}
+			else {
+				distext = list->extensions;
+
+				while(distext->next != NULL)
+					distext = distext->next;
+
+				distext->next = malloc(sizeof(struct vm_dist_ext));
+				bzero(distext->next, sizeof(struct vm_dist_ext));
+				distext = distext->next;
+			}
+
+			// Now populate our extension
+			strncpy(distext->extension, tmp, 255);
+			ast_log(LOG_WARNING, "Extension %s successfully added\n", tmp);
+		}
+
+		bzero(tmp, 256);
+		res = ast_readstring(chan, tmp, 255, 5000, 6000, "#");
+	}
+
+	// Verify we want to save these changes
+	res = 0;
+	while((tmp[0] != '1') || (tmp[0] != '2')) {
+		ast_streamfile(chan, "vm-dist-add-confirm", vmu->language);
+		ast_readstring(chan, tmp, 1, 5000, 5000, "");
+
+		if(tmp[0] == '1') 		// Yes
+			return 0;
+		else if(tmp[0] == '2')		// No
+			return -1;
+
+		bzero(tmp, 256);
+	}
+
+	// Should never be here
+	return -1;
+}
+
+
+static struct vm_dist_list *vm_dist_list_loop(struct ast_vm_user *vmu, struct ast_channel *chan) {
+	DIR *dp = NULL;
+	struct dirent *ep = NULL;
+	int res = 0;
+	char choice[2];
+	char dir[256];
+	struct vm_dist_list *list = NULL;
+
+	// Build our directory name
+	snprintf(dir, 255, "%s/%s/dist/", VM_SPOOL_DIR, vmu->mailbox);
+
+	// Get our directory list
+	if((dp = opendir(dir)) == NULL)
+		return NULL;
+
+	// Now loop through the files, play the name, and wait for *
+	while((ep = readdir(dp)) != NULL) {
+
+		if(ep->d_type == DT_REG) {
+			if(	(strcmp(ep->d_name, ".") == 0) ||
+				(strcmp(ep->d_name, "..") == 0) ||
+				(strcmp(ep->d_name, "names") == 0))
+				continue;
+
+			if((list = vm_dist_list_read(vmu, ep->d_name)) != NULL) {
+				
+				// Play and wait for #
+				ast_streamfile(chan, list->voice_file, vmu->language);
+				res = ast_readstring(chan, choice, 1, 3000, 3000, "#");
+				
+				if((res == 0) && (strlen(choice) == 0)) // # was pressed
+					return list;
+			}
+
+			// Clean up if this isn't the one we want.
+			vm_dist_list_free(list);
+		}
+	}
+
+	// Should never make it here; Nothing was selected
+	return NULL;
+}
+
+// list: The list to write
+// file: The file to write to
+static int vm_dist_list_write( struct vm_dist_list *list, char *file) {
+	FILE *fd;
+	struct vm_dist_ext *ext = NULL;
+	struct vm_dist_list *tmplist = NULL;
+
+	if((list != NULL) && (file != NULL)) {
+		if((fd = fopen(file, "w")) == NULL) {
+			ast_log(LOG_WARNING, "Error writing distribution list: %s\n", file);
+			return -1;
+		}
+
+		if(list->voice_file == NULL) {
+			ast_log(LOG_WARNING, "No voice file given for distribution list\n");
+			return -1;
+		}
+
+		// This should point to the file that is the recorded name of the list
+		fprintf(fd, "file=%s\n", list->voice_file);
+		
+		ast_log(LOG_WARNING, "file=%s\n", list->voice_file);
+
+		// Now loop through all the extensions
+		if(list->extensions != NULL) {
+			ext = list->extensions;
+			
+			while(ext->next != NULL) {
+				if(ext->extension != NULL) {
+					ast_log(LOG_WARNING, "ext=>%s\n", ext->extension);
+					fprintf(fd, "ext=>%s\n", ext->extension);
+				}
+
+				ext = ext->next;
+			}
+			if(ext->extension != NULL)  {
+				ast_log(LOG_WARNING, "ext=>%s\n", ext->extension);
+				fprintf(fd, "ext=>%s\n", ext->extension);
+			}
+		}
+
+		// And now all of the sublists
+		if(list->lists != NULL) {
+			tmplist = list->lists;
+
+			while(tmplist->next != NULL) {
+				if(tmplist->name != NULL)  {
+					ast_log(LOG_WARNING, "list=>%s\n", tmplist->name);
+					fprintf(fd, "list=>%s\n", tmplist->name);
+				}
+
+				tmplist = tmplist->next;
+			}
+			if(tmplist->name != NULL) {
+				ast_log(LOG_WARNING, "list=>%s\n", tmplist->name);
+				fprintf(fd, "list=>%s\n", tmplist->name);
+			}
+		}
+
+		ast_log(LOG_WARNING, "Distribution list successfully created\n");
+
+		fclose(fd);
+		return 0;
+	}
+
+	// Shouldn't be here
+	return -1;
+}
+
+// list: The filename of the stored distribution list
+// vmu: Our voicemail user structure
+static struct vm_dist_list *vm_dist_list_read(struct ast_vm_user *vmu, char *listfile) {
+	FILE 			*fd 				= NULL;
+	char 			chDistFile[256]; 				// Will hold our distribution list file name
+	char 			*chLine 			= NULL;		// Holds our line from the config file
+	struct 			vm_dist_list *list = NULL, *curList = NULL;	// Our distribution list
+	struct			vm_dist_ext *ext;
+	size_t 			len 				= 0;
+	char 			file[256];
+
+	// Make sure we were given something to work with
+	if((listfile == NULL) || (vmu == NULL)) 
+		return NULL;
+	
+	// Our distribution list name
+	snprintf(chDistFile, 255, "%s/%s/dist/%s", VM_SPOOL_DIR, vmu->mailbox, listfile);
+
+	// Open file
+	if((fd = fopen(chDistFile, "r")) == NULL) 
+		return NULL;
+
+	// Create our list for storage
+	list = malloc(sizeof(struct vm_dist_list));
+	bzero(list, sizeof(struct vm_dist_list));
+
+	// Set our list name
+	strncpy(list->name, listfile, 255);
+
+	// Loop through our file creating our lists as we go
+	while(getline(&chLine, &len, fd) != -1) {
+
+		// Get rid of any newline characters
+		*(strchr(chLine, '\n')) = '\0';
+
+		// File location
+		if(strstr(chLine, "file=")) {
+			// Copy our filename into file
+			strncpy(list->voice_file, chLine + 5, 255);
+		}
+
+		// Extensions
+		else if(strstr(chLine, "ext=>")) {
+			if(list->extensions == NULL) {
+				list->extensions = malloc(sizeof(struct vm_dist_ext));
+				bzero(list->extensions, sizeof(struct vm_dist_ext));
+
+				// Create our current working extensions
+				ext = list->extensions;
+			}
+			else {
+				// We need to iterate through our already existing list until we find the end
+				ext = list->extensions;
+				while(ext->next != NULL) {
+					ext = ext->next;
+				}
+
+				// We need to create a new one
+				ext->next = malloc(sizeof(struct vm_dist_ext));
+				bzero(ext->next, sizeof(struct vm_dist_ext));
+					
+				// Work with our new extension
+				ext = ext->next;
+			}
+
+			strncpy(ext->extension, chLine + 5, 255);
+			strncpy(ext->context, vmu->context, strlen(vmu->context));
+		}
+
+		// Sub lists
+		else if(strstr(chLine, "list=>")) {
+			// Get our listname
+			strncpy(file, chLine + 6, 255);
+
+			if(list->lists == NULL) {
+				list->lists = vm_dist_list_read(vmu, file);
+			}
+			else {
+				curList = list->lists;
+				while(curList->next != NULL) {
+					curList = curList->next;
+				}
+
+				curList->next = vm_dist_list_read(vmu, file);
+			}
+		}
+
+		// Clean up
+		free(chLine);
+		chLine = NULL;
+	}
+			
+	// Clean up
+	fclose(fd);
+
+	return list;
+}
 static int vm_execmain(struct ast_channel *chan, void *data)
 {
 	/* XXX This is, admittedly, some pretty horrendus code.  For some
@@ -4525,7 +5133,11 @@
 	struct ast_vm_user *vmu = NULL, vmus;
 	char *context=NULL;
 	int silentexit = 0;
-
+	char chDistExt[3], file[256], distnamefile[256];
+	int duration = 0;
+	FILE *fd;
+	struct vm_dist_list *list = NULL;
+	
 	LOCAL_USER_ADD(u);
 	memset(&vms, 0, sizeof(vms));
 	memset(&vmus, 0, sizeof(vmus));
@@ -4709,7 +5321,254 @@
 							cmd = ast_play_and_wait(chan,"vm-sorry");
 						cmd='t';
 						break;
-					
+					case '6': /* Distribution list management */
+						/* Proposed file format
+						 * file=Recorded_name.wav
+						 * ext=>1234
+						 * list=>another_list (Allows for inclusion of other lists)
+						 */
+
+						/* Need menu announcements */
+						// 1. Create List
+						// 2. Edit List
+						// 3. Delete List  
+				
+						// Read our config file in
+								
+						while(( cmd > -1) && (cmd != '#')) {
+							cmd = ast_play_and_wait(chan, "vm-dist-main");
+
+							switch(cmd) {
+								case '1': // Create a distribution list
+
+									// Play message that says to enter a two digit name for this list
+									ast_streamfile(chan, "vm-dist-enterid", vmu->language);
+
+									// Get the name for our new list
+									ast_readstring(chan, chDistExt, 2, 5000, 6000, "");
+									
+									// Check to see if this list already exists
+									snprintf(file, sizeof(file) - 1, "%s/%s/dist/%s", VM_SPOOL_DIR, vmu->mailbox,
+											chDistExt);
+
+									if((fd = fopen(file, "r")) != NULL) {
+										// Play message stating this list already exists and to delete it first
+										ast_log(LOG_WARNING, "Distribution list %s already exists\n", 
+												file);
+
+										ast_play_and_wait(chan, "vm-dist-already-exists");
+										fclose(fd);
+										break;
+									}
+
+									// Make sure all of the directories exist
+									snprintf(tmp, sizeof(tmp) - 1, "%s/%s/dist/", 
+											VM_SPOOL_DIR, vmu->mailbox);
+
+									if(mkdir(tmp, S_IRWXG | S_IRWXU) != 0) {
+										if(errno != EEXIST) {
+											ast_log(LOG_WARNING, "Error while creating directory\n");
+											break;
+										}
+									}
+
+									snprintf(tmp, sizeof(tmp) - 1, "%s/%s/dist/names/", 
+											VM_SPOOL_DIR, vmu->mailbox);
+
+									if(mkdir(tmp, S_IRWXG | S_IRWXU) != 0) {
+										if(errno != EEXIST) {
+											ast_log(LOG_WARNING, "Error while creating directory\n");
+											break;
+										}
+									}
+
+									// Play message stating to record a name
+									ast_play_and_wait(chan, "vm-dist-record-name");
+									ast_play_and_wait(chan, "beep");
+
+									// Record a name for this list
+									snprintf(distnamefile, sizeof(distnamefile) - 1, "%s/%s/dist/names/%s", 
+											VM_SPOOL_DIR, vmu->mailbox, chDistExt);
+
+									cmd = ast_play_and_record(
+											chan, NULL, distnamefile, 10, vmfmts, &duration, -1, 1500); 
+									if((cmd == -1) || (cmd == '0')) {
+										ast_log(LOG_WARNING, "Error while recording distribution file: %s", 
+												distnamefile);
+										vm_delete(distnamefile);
+										break;
+									}
+
+									// We're ready to start retrieving exts so create our list
+									list = malloc(sizeof(struct vm_dist_list));
+									bzero(list, sizeof(struct vm_dist_list));
+
+									strncpy(list->voice_file,distnamefile, 255);
+
+									// Now we have our list, now lets save it to file
+									if(vm_dist_list_add(vmu, chan, list) == 0) {
+										snprintf(tmp, 255,  "%s/%s/dist/%s", VM_SPOOL_DIR, vmu->mailbox, chDistExt);
+										if(vm_dist_list_write(list, tmp) == 0) 
+											ast_play_and_wait(chan, "vm-dist-success");
+										// Note: Add message to let the user know there was a problem
+									}
+									else {
+										vm_delete(list->voice_file);
+									}
+									
+									// Remember to clean up, memory leaks bad!!! :)
+									vm_dist_list_free(list);
+
+									// So we drop back to the menu
+									cmd = 0;
+
+									break;
+
+								case '2': // Edit distribution list
+									// Play a message that says to enter the code, or press * to loop
+									ast_streamfile(chan, "vm-dist-edit", vmu->language);
+
+									// Read our choice
+									if(ast_readstring(chan, tmp, 255, 5000, 6000, "#") != 0) 
+										break;
+
+									// Loop if just # was entered
+									if(strlen(tmp) == 0)
+										list = vm_dist_list_loop(vmu, chan);
+									else
+										list = vm_dist_list_read(vmu, tmp); 
+
+									if(list == NULL) {
+										ast_play_and_wait(chan, "vm-dist-edit-invalid");
+										break;
+									}
+
+									// Let them choose
+									cmd = ast_play_and_wait(chan, "vm-dist-edit-add-remove");
+
+									switch(cmd) {
+										case '1': // Additions
+											res = vm_dist_list_add(vmu, chan, list);
+											break;
+										case '2': // Deletions
+											// Note: Add code to make deletions
+											break;
+									}
+								      
+									if(res == 0) {
+										snprintf(tmp, 255,  "%s/%s/dist/%s", VM_SPOOL_DIR, vmu->mailbox, list->name);
+								      		if(vm_dist_list_write(list, tmp) == 0)
+											ast_play_and_wait(chan, "vm-dist-success");
+										// Note: Add code to message saying something went wrong
+									}
+									
+									// Cleanup
+									vm_dist_list_free(list);
+
+									break;
+								case '3': // Delete distribution list
+
+									// Play a message that says to enter the code, or press * to loop
+									ast_streamfile(chan, "vm-dist-edit", vmu->language);
+
+									// Read our choice
+									if(ast_readstring(chan, tmp, 255, 5000, 6000, "#") != 0) 
+										break;
+
+									// Loop if just # was entered
+									if(strlen(tmp) == 0)
+										list = vm_dist_list_loop(vmu, chan);
+									else
+										list = vm_dist_list_read(vmu, tmp); 
+
+									if(list == NULL) {
+										ast_play_and_wait(chan, "vm-dist-edit-invalid");
+										break;
+									}
+
+									// Confirm the deletion
+									ast_streamfile(chan, "vm-dist-add-confirm", vmu->language);
+									ast_readstring(chan, tmp, 1, 5000, 5000, "");
+
+									if(tmp[0] == '1') { // Yes
+										// Delete the list file and the saved name
+										snprintf(tmp, 255, "%s/%s/dist/%s", VM_SPOOL_DIR, vmu->mailbox, list->name);
+
+										// Delete our list file
+										if(remove(tmp) != 0) 
+											ast_log(LOG_WARNING, "Error deleting file: %s\n", tmp);
+
+										// Continue trying to remove the voice files
+										if(strstr(vmfmts, "wav") != NULL) {
+											// wav
+											snprintf(tmp, 255, "%s.wav", list->voice_file);
+											
+											if(remove(tmp) != 0) 
+												ast_log(LOG_WARNING, "Error deleting file: %s\n", tmp);
+
+											// WAV
+											snprintf(tmp, 255, "%s.WAV", list->voice_file);
+
+											if(remove(tmp) != 0)
+												ast_log(LOG_WARNING, "Error deleting file: %s\n", tmp);
+										}
+
+										if(strstr(vmfmts, "gsm") != NULL) {
+											// GSM
+											snprintf(tmp, 255, "%s.gsm", list->voice_file);
+
+											if(remove(tmp) != 0) 
+												ast_log(LOG_WARNING, "Error deleting file: %s\n", tmp);
+
+										}
+
+										// Play our success message
+										ast_play_and_wait(chan, "vm-dist-success");
+
+									}
+									
+									// Cleanup
+									vm_dist_list_free(list);
+
+									break;
+
+								case '4': // Send distributed message
+
+									// Play a message that says to enter the code, or press * to loop
+									ast_streamfile(chan, "vm-dist-edit", vmu->language);
+
+									// Read our choice
+									if(ast_readstring(chan, tmp, 255, 5000, 6000, "#") != 0) 
+										break;
+
+									// Loop if just # was entered
+									if(strlen(tmp) == 0)
+										list = vm_dist_list_loop(vmu, chan);
+									else
+										list = vm_dist_list_read(vmu, tmp); 
+
+									if(list == NULL) {
+										ast_play_and_wait(chan, "vm-dist-edit-invalid");
+										break;
+									}
+
+									
+									// Confirm the deletion
+									ast_streamfile(chan, "vm-dist-add-confirm", vmu->language);
+									ast_readstring(chan, tmp, 1, 5000, 5000, "");
+
+									if(tmp[0] == '1') { // Yes
+										// Record and send our message
+										leave_distributed_voicemail(chan, vmu->mailbox, 0, 0, 0, list);
+									}
+									
+									// Cleanup
+									vm_dist_list_free(list);
+
+									break;
+							}
+						}
+						break;
 					case '*': /* Return to main menu */
 						cmd = 't';
 						break;
@@ -4747,10 +5606,6 @@
 				}
 				break;
 
-
-
-
-
 			case '4':
 				if (vms.curmsg) {
 					vms.curmsg--;
@@ -5965,4 +6820,3 @@
 {
 	return ASTERISK_GPL_KEY;
 }
-
