Index: apps/app_voicemail.c
===================================================================
--- apps/app_voicemail.c	(revision 177349)
+++ apps/app_voicemail.c	(working copy)
@@ -406,6 +406,7 @@
 #define VM_MOVEHEARD     (1 << 16)  /*!< Move a "heard" message to Old after listening to it */
 #define VM_MESSAGEWRAP   (1 << 17)  /*!< Wrap around from the last message to the first, and vice-versa */
 #define VM_FWDURGAUTO    (1 << 18)  /*!< Autoset of Urgent flag on forwarded Urgent messages set globally */
+#define VM_FORWARDMULTI  (1 << 19)  /*!< Allow a messages to be forwarded to more than one recipient */
 #define ERROR_LOCK_PATH  -100
 
 
@@ -2319,7 +2320,7 @@
 		ast_variables_destroy(var);
 		return vmu;
 	} else {
-		free(vmu);
+		ast_free(vmu);
 		return NULL;
 	}
 }
@@ -4873,14 +4874,16 @@
 /*!
  * \brief Prompts the user and records a voicemail to a mailbox.
  * \param chan
- * \param ext
+ * \param ext a list of one or more user@context, delimited by '&'. This used to be a char*, but has been updated to use struct ast_str* during forward multiple (#011837) feature
+ *  We assume this parameter is not null, and has been previously allocated and populated (and will eventually be ast_free()'d) by the caller.
+ *
  * \param options OPT_BUSY_GREETING, OPT_UNAVAIL_GREETING
  * 
  * 
  * 
  * \return zero on success, -1 on error.
  */
-static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
+static int leave_voicemail(struct ast_channel *chan, struct ast_str *ext_str, struct leave_vm_options *options)
 {
 #ifdef IMAP_STORAGE
 	int newmsgs, oldmsgs;
@@ -4912,7 +4915,9 @@
 	char fmt[80];
 	char *context;
 	char ecodes[17] = "#";
-	char tmp[1024] = "";
+	/*char tmp[1024] = ""; */
+	char *tmp;
+	char *ext;
 	char *tmpptr;
 	struct ast_vm_user *vmu;
 	struct ast_vm_user svm;
@@ -4921,8 +4926,19 @@
 	const char *alldtmf = "0123456789ABCD*#";
 	char flag[80];
 
+/* Before when this function used char* strings,
+  this ensured that the string we worked with was only up to 1024 characters.
+  But now that this has been replaced with the ast_str API, we don't need to do this checking.
+*/
+/*
 	ast_copy_string(tmp, ext, sizeof(tmp));
 	ext = tmp;
+*/
+	tmp = ast_str_buffer(ext_str);
+	ext = ast_str_buffer(ext_str);
+
+	/* If the context that the message should be sent to is our current context,
+     then remove the conext from the original string. */
 	if ((context = strchr(tmp, '@'))) {
 		*context++ = '\0';
 		tmpptr = strchr(context, '&');
@@ -6289,21 +6305,29 @@
 	int todircount=0;
 	struct vm_state *dstvms;
 #endif
-	char username[70]="";
-	char fn[PATH_MAX]; /* for playback of name greeting */
+	char username[70]=""; /* the most recent entered extension */
 	char ecodes[16] = "#";
 	int res = 0, cmd = 0;
-	struct ast_vm_user *receiver = NULL, *vmtmp;
+	struct ast_vm_user *receiver = NULL;
+	struct ast_vm_user *vmtmp;
 	AST_LIST_HEAD_NOLOCK_STATIC(extensions, ast_vm_user);
 	char *stringp;
 	const char *s;
-	int saved_messages = 0, found = 0;
+	int saved_messages = 0;
+	int found = 0;
 	int valid_extensions = 0;
 	char *dir;
 	int curmsg;
 	char urgent_str[7] = "";
 	char tmptxtfile[PATH_MAX];
 
+	/* forward multiple */
+	int add_recipient = 0;
+	struct ast_str *recipients; /* accumulator for extension(s) entered */
+
+/* recipients is a dynamic string, we just initialize its buffer size to this AST_MAX_EXTENSION */
+	recipients = ast_str_create(AST_MAX_EXTENSION); 
+
 	if (ast_test_flag((&globalflags), VM_FWDURGAUTO)) {
 		ast_copy_string(urgent_str, urgent ? "Urgent" : "", sizeof(urgent_str));
 	}
@@ -6313,13 +6337,16 @@
 	curmsg = vms->curmsg;
 
 	tmptxtfile[0] = '\0';
-	while (!res && !valid_extensions) {
+
+	forward_message_read_extension:
+	while (!res && !valid_extensions && !add_recipient) {
 		int use_directory = 0;
+		int add_recipient = 0;
 		if (ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
 			int done = 0;
 			int retries = 0;
 			cmd=0;
-			while ((cmd >= 0) && !done ){
+			while ((cmd >= 0) && !done ) {
 				if (cmd)
 					retries = 0;
 				switch (cmd) {
@@ -6395,11 +6422,14 @@
 		/* start all over if no username */
 		if (ast_strlen_zero(username))
 			continue;
+
 		stringp = username;
 		s = strsep(&stringp, "*");
 		/* start optimistic */
 		valid_extensions = 1;
 		while (s) {
+			char fn[PATH_MAX]; /* for playback of name greeting */
+
 			if ((is_new_message == 1 || strcmp(s, sender->mailbox)) && (receiver = find_user(NULL, context, s))) {
 				AST_LIST_INSERT_HEAD(&extensions, receiver, list);
 				found++;
@@ -6432,24 +6462,102 @@
 
 			s = strsep(&stringp, "*");
 		}
-		/* break from the loop of reading the extensions */
-		if (valid_extensions)
+
+
+		if (!valid_extensions) {
+			/* "I am sorry, that's not a valid extension.  Please try again." */
+			res = ast_play_and_wait(chan, "pbx-invalid");
+			continue;
+		}
+
+		/* at this point a valid extension was read */
+		/* store the extension onto the dynamic buffer */
+		/* This used to be done below in the leave voicemail mode */
+
+		ast_str_append(&recipients, 0, "%s@%s", username, context);
+
+		/* forward multiple */
+		if (ast_test_flag((&globalflags), VM_FORWARDMULTI)) {
+			int done = 0;
+			int retries = 0;
+			cmd=0;
+			while ((cmd >= 0) && !done ) {
+				if (cmd)
+					retries = 0;
+				switch (cmd) {
+
+			case '1':
+				add_recipient = 0;
+				done = 1;
+				break;
+
+			case '2':
+				add_recipient = 1;
+				done=1;
+				break;
+
+			case '*':
+				cmd = 't';
+				done = 1;
+				break;
+
+				default:
+					/* Press 1 to enter an send message, press 2 add another recipient */
+					cmd = ast_play_and_wait(chan,"vm-forward-multiple");
+					if (!cmd)
+						cmd = ast_waitfordigit(chan,3000);
+
+					if (!cmd)
+						retries++;
+
+					if (retries > 3) {
+						cmd = 't';
+						done = 1;
+					}
+
+				} /* switch (vm-forward-multiple prompt)*/
+			} /* while (cmd) */
+
+			if (cmd < 0 || cmd == 't')
+				goto forward_message_read_extension; /*break forward_message_read_extension; */
+
+		} /* if VM_FORWARD_MULTI option enabled */
+
+		if (add_recipient) {
+			/* we have just previously read in an extension, and are to go back to add another extension */
+			/* the dynamic recipients buffer we are building needs to delimit each extension with '&' */
+			/* as that is what the leave_voicemail() expects and interprets as the delimiter between individual extensions. */
+			ast_str_append(&recipients, 0, "&");
+			continue;
+		}
+
+		/* break from the loop of reading the extensions when we have read a valid extension */
+		/* and when choose to not append another one (if VM_FORWARD_MULTI option enabled) */
 			break;
-		/* "I am sorry, that's not a valid extension.  Please try again." */
-		res = ast_play_and_wait(chan, "pbx-invalid");
-	}
+	} /* loop to read extension(s) */
+
 	/* check if we're clear to proceed */
 	if (AST_LIST_EMPTY(&extensions) || !valid_extensions)
 		return res;
 	if (is_new_message == 1) {
 		struct leave_vm_options leave_options;
+
+		/* converted to asterisk string for forward multiple, and done above inside the read extensions loop */
+		/*
 		char mailbox[AST_MAX_EXTENSION * 2 + 2];
 		snprintf(mailbox, sizeof(mailbox), "%s@%s", username, context);
+		*/
 
 		/* Send VoiceMail */
 		memset(&leave_options, 0, sizeof(leave_options));
 		leave_options.record_gain = record_gain;
-		cmd = leave_voicemail(chan, mailbox, &leave_options);
+
+		/* Changed the existing leave_voicemail() method signature to use ast_str, for the forward multiple feature.*/
+		cmd = leave_voicemail(chan, recipients, &leave_options);
+		if (recipients != NULL) {
+			ast_free(recipients);
+			recipients = NULL;
+		}	
 	} else {
 		/* Forward VoiceMail */
 		long duration = 0;
@@ -9469,6 +9577,7 @@
 {
 	int res = 0;
 	char *tmp;
+	struct ast_str *recipient;
 	struct leave_vm_options leave_options;
 	struct ast_flags flags = { 0 };
 	char *opts[OPT_ARG_ARRAY_SIZE];
@@ -9514,7 +9623,14 @@
 		args.argv0 = ast_strdupa(temp);
 	}
 
-	res = leave_voicemail(chan, args.argv0, &leave_options);
+	/* method signature of leave_voicemail() has changed to take on ast_str */
+	recipient = ast_str_create(AST_MAX_EXTENSION);
+	ast_str_set(&recipient, 0, "%s", args.argv0);
+	res = leave_voicemail(chan, recipient, &leave_options);
+	if (recipient != NULL) {
+		ast_free(recipient);
+		recipient = NULL;
+	}
 
 	if (res == ERROR_LOCK_PATH) {
 		ast_log(AST_LOG_ERROR, "Could not leave voicemail. The path is already locked.\n");
@@ -10748,6 +10864,10 @@
 			val = "no";
 		ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);	
 
+		if (!(val = ast_variable_retrieve(cfg, "general", "forwardmultiple")))
+			val = "no";
+		ast_set2_flag((&globalflags), ast_true(val), VM_FORWARDMULTI);
+
 		poll_freq = DEFAULT_POLL_FREQ;
 		if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
 			if (sscanf(val, "%u", &poll_freq) != 1) {
@@ -11189,8 +11309,13 @@
 			struct ast_vm_user vmu2;
 			if (find_user(&vmu2, vmu->context, num)) {
 				struct leave_vm_options leave_options;
-				char mailbox[AST_MAX_EXTENSION * 2 + 2];
+				/* leave_voicemail() signature changed to work with ast_str API for forward multiple feature */
+				/*
+				char mailbox[AST_MAX_EXTENSION * 2 + 2]; 
 				snprintf(mailbox, sizeof(mailbox), "%s@%s", num, vmu->context);
+				*/
+				struct ast_str *mailbox = ast_str_create(AST_MAX_EXTENSION * 2 + 2);
+				ast_str_set(&mailbox, 0, "%s@%s", num, vmu->context);
 
 				ast_verb(3, "Leaving voicemail for '%s' in context '%s'\n", num, vmu->context);
 				
@@ -11199,6 +11324,12 @@
 				res = leave_voicemail(chan, mailbox, &leave_options);
 				if (!res)
 					res = 't';
+
+				if (mailbox != NULL) {
+					ast_free(mailbox);
+					mailbox = NULL;
+				}
+
 				ast_config_destroy(msg_cfg);
 				return res;
 			} else {
Index: configs/voicemail.conf.sample
===================================================================
--- configs/voicemail.conf.sample	(revision 174876)
+++ configs/voicemail.conf.sample	(working copy)
@@ -55,6 +55,10 @@
 ; Move heard messages to the 'Old' folder automagically.  Defaults to on.
 ;moveheard=yes
 ;
+; Allow for the leave voicemail option to prompt you to add another recipient.
+; Defaults to off (not prompt for additional recipients)
+forwardmultiple=no
+;
 ; Forward an urgent message as an urgent message.  Defaults to no so
 ; sender can set the urgency on the envelope of the forwarded message.
 ;forward_urgent_auto=no
