[asterisk-commits] tilghman: trunk r191140 - in /trunk: ./ apps/ cdr/ funcs/ include/asterisk/ m...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Apr 29 13:53:06 CDT 2009


Author: tilghman
Date: Wed Apr 29 13:53:01 2009
New Revision: 191140

URL: http://svn.digium.com/svn-view/asterisk?view=rev&rev=191140
Log:
Merge str_substitution branch.
This branch adds additional methods to dialplan functions, whereby the result
buffers are now dynamic buffers, which can be expanded to the size of any
result.  No longer are variable substitutions limited to 4095 bytes of data.
In addition, the common case of needing buffers much smaller than that will
enable substitution to only take up the amount of memory actually needed.
The existing variable substitution routines are still available, but users
of those API calls should transition to using the dynamic-buffer APIs.

Added:
    trunk/tests/test_substitution.c   (with props)
Modified:
    trunk/apps/app_exec.c
    trunk/apps/app_macro.c
    trunk/apps/app_minivm.c
    trunk/apps/app_voicemail.c
    trunk/cdr/cdr_custom.c
    trunk/configure   (contents, props changed)
    trunk/funcs/func_aes.c
    trunk/funcs/func_base64.c
    trunk/funcs/func_blacklist.c
    trunk/funcs/func_callerid.c
    trunk/funcs/func_curl.c
    trunk/funcs/func_cut.c
    trunk/funcs/func_db.c
    trunk/funcs/func_dialplan.c
    trunk/funcs/func_env.c
    trunk/funcs/func_extstate.c
    trunk/funcs/func_groupcount.c
    trunk/funcs/func_lock.c
    trunk/funcs/func_logic.c
    trunk/funcs/func_md5.c
    trunk/funcs/func_module.c
    trunk/funcs/func_rand.c
    trunk/funcs/func_sha1.c
    trunk/funcs/func_speex.c
    trunk/funcs/func_strings.c
    trunk/funcs/func_sysinfo.c
    trunk/funcs/func_timeout.c
    trunk/funcs/func_vmcount.c
    trunk/include/asterisk/ast_expr.h
    trunk/include/asterisk/autoconfig.h.in
    trunk/include/asterisk/pbx.h
    trunk/main/ast_expr2f.c
    trunk/main/pbx.c
    trunk/main/strings.c
    trunk/res/res_agi.c
    trunk/res/res_config_curl.c
    trunk/res/res_phoneprov.c

Modified: trunk/apps/app_exec.c
URL: http://svn.digium.com/svn-view/asterisk/trunk/apps/app_exec.c?view=diff&rev=191140&r1=191139&r2=191140
==============================================================================
--- trunk/apps/app_exec.c (original)
+++ trunk/apps/app_exec.c Wed Apr 29 13:53:01 2009
@@ -132,56 +132,61 @@
 static int exec_exec(struct ast_channel *chan, void *data)
 {
 	int res = 0;
-	char *s, *appname, *endargs, args[MAXRESULT];
+	char *s, *appname, *endargs;
 	struct ast_app *app;
+	struct ast_str *args = NULL;
 
 	if (ast_strlen_zero(data))
 		return 0;
 
 	s = ast_strdupa(data);
-	args[0] = 0;
 	appname = strsep(&s, "(");
 	if (s) {
 		endargs = strrchr(s, ')');
 		if (endargs)
 			*endargs = '\0';
-		pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1);
+		if ((args = ast_str_create(16))) {
+			ast_str_substitute_variables(&args, 0, chan, s);
+		}
 	}
 	if (appname) {
 		app = pbx_findapp(appname);
 		if (app) {
-			res = pbx_exec(chan, app, args);
+			res = pbx_exec(chan, app, args ? ast_str_buffer(args) : NULL);
 		} else {
 			ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
 			res = -1;
 		}
 	}
 
+	ast_free(args);
 	return res;
 }
 
 static int tryexec_exec(struct ast_channel *chan, void *data)
 {
 	int res = 0;
-	char *s, *appname, *endargs, args[MAXRESULT];
+	char *s, *appname, *endargs;
 	struct ast_app *app;
+	struct ast_str *args = NULL;
 
 	if (ast_strlen_zero(data))
 		return 0;
 
 	s = ast_strdupa(data);
-	args[0] = 0;
 	appname = strsep(&s, "(");
 	if (s) {
 		endargs = strrchr(s, ')');
 		if (endargs)
 			*endargs = '\0';
-		pbx_substitute_variables_helper(chan, s, args, MAXRESULT - 1);
+		if ((args = ast_str_create(16))) {
+			ast_str_substitute_variables(&args, 0, chan, s);
+		}
 	}
 	if (appname) {
 		app = pbx_findapp(appname);
 		if (app) {
-			res = pbx_exec(chan, app, args);
+			res = pbx_exec(chan, app, args ? ast_str_buffer(args) : NULL);
 			pbx_builtin_setvar_helper(chan, "TRYSTATUS", res ? "FAILED" : "SUCCESS");
 		} else {
 			ast_log(LOG_WARNING, "Could not find application (%s)\n", appname);
@@ -189,6 +194,7 @@
 		}
 	}
 
+	ast_free(args);
 	return 0;
 }
 

Modified: trunk/apps/app_macro.c
URL: http://svn.digium.com/svn-view/asterisk/trunk/apps/app_macro.c?view=diff&rev=191140&r1=191139&r2=191140
==============================================================================
--- trunk/apps/app_macro.c (original)
+++ trunk/apps/app_macro.c Wed Apr 29 13:53:01 2009
@@ -231,13 +231,14 @@
 	int offset, depth = 0, maxdepth = 7;
 	int setmacrocontext=0;
 	int autoloopflag, inhangup = 0;
+	struct ast_str *tmp_subst = NULL;
   
 	char *save_macro_exten;
 	char *save_macro_context;
 	char *save_macro_priority;
 	char *save_macro_offset;
 	struct ast_datastore *macro_store = ast_channel_datastore_find(chan, &macro_ds_info, NULL);
- 
+
 	if (ast_strlen_zero(data)) {
 		ast_log(LOG_WARNING, "Macro() requires arguments. See \"core show application macro\" for help.\n");
 		return -1;
@@ -281,7 +282,6 @@
 		return 0;
 	}
 	snprintf(depthc, sizeof(depthc), "%d", depth + 1);
-	pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
 
 	tmp = ast_strdupa(data);
 	rest = tmp;
@@ -311,7 +311,11 @@
 		}
 		ast_autoservice_stop(chan);
 	}
-	
+
+	if (!(tmp_subst = ast_str_create(16))) {
+		return -1;
+	}
+
 	/* Save old info */
 	oldpriority = chan->priority;
 	ast_copy_string(oldexten, chan->exten, sizeof(oldexten));
@@ -336,6 +340,8 @@
   
 	save_macro_offset = ast_strdup(pbx_builtin_getvar_helper(chan, "MACRO_OFFSET"));
 	pbx_builtin_setvar_helper(chan, "MACRO_OFFSET", NULL);
+
+	pbx_builtin_setvar_helper(chan, "MACRO_DEPTH", depthc);
 
 	/* Setup environment for new run */
 	chan->exten[0] = 's';
@@ -415,8 +421,9 @@
 			gosub_level++;
 			ast_debug(1, "Incrementing gosub_level\n");
 		} else if (!strcasecmp(runningapp, "GOSUBIF")) {
-			char tmp2[1024], *cond, *app_arg, *app2 = tmp2;
-			pbx_substitute_variables_helper(chan, runningdata, tmp2, sizeof(tmp2) - 1);
+			char *cond, *app_arg, *app2;
+			ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
+			app2 = ast_str_buffer(tmp_subst);
 			cond = strsep(&app2, "?");
 			app_arg = strsep(&app2, ":");
 			if (pbx_checkcondition(cond)) {
@@ -438,19 +445,24 @@
 			ast_debug(1, "Decrementing gosub_level\n");
 		} else if (!strncasecmp(runningapp, "EXEC", 4)) {
 			/* Must evaluate args to find actual app */
-			char tmp2[1024], *tmp3 = NULL;
-			pbx_substitute_variables_helper(chan, runningdata, tmp2, sizeof(tmp2) - 1);
+			char *tmp2, *tmp3 = NULL;
+			ast_str_substitute_variables(&tmp_subst, 0, chan, runningdata);
+			tmp2 = ast_str_buffer(tmp_subst);
 			if (!strcasecmp(runningapp, "EXECIF")) {
 				tmp3 = strchr(tmp2, '|');
-				if (tmp3)
+				if (tmp3) {
 					*tmp3++ = '\0';
-				if (!pbx_checkcondition(tmp2))
+				}
+				if (!pbx_checkcondition(tmp2)) {
 					tmp3 = NULL;
-			} else
+				}
+			} else {
 				tmp3 = tmp2;
-
-			if (tmp3)
+			}
+
+			if (tmp3) {
 				ast_debug(1, "Last app: %s\n", tmp3);
+			}
 
 			if (tmp3 && !strncasecmp(tmp3, "GOSUB", 5)) {
 				gosub_level++;
@@ -547,6 +559,7 @@
 		}
 	}
 	ast_channel_unlock(chan);
+	ast_free(tmp_subst);
 
 	return res;
 }

Modified: trunk/apps/app_minivm.c
URL: http://svn.digium.com/svn-view/asterisk/trunk/apps/app_minivm.c?view=diff&rev=191140&r1=191139&r2=191140
==============================================================================
--- trunk/apps/app_minivm.c (original)
+++ trunk/apps/app_minivm.c Wed Apr 29 13:53:01 2009
@@ -483,11 +483,12 @@
 	AST_APP_OPTION('n', OPT_NAME_GREETING),
 });
 
-/*! \brief Structure for linked list of Mini-Voicemail users: \ref minivm_accounts */
+/*!\internal
+ * \brief Structure for linked list of Mini-Voicemail users: \ref minivm_accounts */
 struct minivm_account {
 	char username[AST_MAX_CONTEXT];	/*!< Mailbox username */
 	char domain[AST_MAX_CONTEXT];	/*!< Voicemail domain */
-	
+
 	char pincode[10];		/*!< Secret pin code, numbers only */
 	char fullname[120];		/*!< Full name, for directory app */
 	char email[80];			/*!< E-mail address - override */
@@ -502,18 +503,20 @@
 	char attachfmt[80];		/*!< Format for voicemail audio file attachment */
 	char etemplate[80];		/*!< Pager template */
 	char ptemplate[80];		/*!< Voicemail format */
-	unsigned int flags;		/*!< MVM_ flags */	
+	unsigned int flags;		/*!< MVM_ flags */
 	struct ast_variable *chanvars;	/*!< Variables for e-mail template */
 	double volgain;			/*!< Volume gain for voicemails sent via e-mail */
-	AST_LIST_ENTRY(minivm_account) list;	
+	AST_LIST_ENTRY(minivm_account) list;
 };
 
-/*! \brief The list of e-mail accounts */
+/*!\internal
+ * \brief The list of e-mail accounts */
 static AST_LIST_HEAD_STATIC(minivm_accounts, minivm_account);
 
-/*! \brief Linked list of e-mail templates in various languages 
-	These are used as templates for e-mails, pager messages and jabber messages
-	\ref message_templates
+/*!\internal
+ * \brief Linked list of e-mail templates in various languages
+ * These are used as templates for e-mails, pager messages and jabber messages
+ * \ref message_templates
 */
 struct minivm_template {
 	char	name[80];		/*!< Template name */
@@ -588,11 +591,11 @@
 
 static struct ast_flags globalflags = {0};	/*!< Global voicemail flags */
 static int global_saydurationminfo;
-static char global_charset[32];			/*!< Global charset in messages */
 
 static double global_volgain;	/*!< Volume gain for voicmemail via e-mail */
 
-/*! \brief Default dateformat, can be overridden in configuration file */
+/*!\internal
+ * \brief Default dateformat, can be overridden in configuration file */
 #define DEFAULT_DATEFORMAT 	"%A, %B %d, %Y at %r"
 #define DEFAULT_CHARSET		"ISO-8859-1"
 
@@ -603,7 +606,8 @@
 static struct minivm_account *find_user_realtime(const char *domain, const char *username);
 static char *handle_minivm_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 
-/*! \brief Create message template */
+/*!\internal
+ * \brief Create message template */
 static struct minivm_template *message_template_create(const char *name)
 {
 	struct minivm_template *template;
@@ -622,7 +626,8 @@
 	return template;
 }
 
-/*! \brief Release memory allocated by message template */
+/*!\internal
+ * \brief Release memory allocated by message template */
 static void message_template_free(struct minivm_template *template)
 {
 	if (template->body)
@@ -631,7 +636,8 @@
 	ast_free (template);
 }
 
-/*! \brief Build message template from configuration */
+/*!\internal
+ * \brief Build message template from configuration */
 static int message_template_build(const char *name, struct ast_variable *var)
 {
 	struct minivm_template *template;
@@ -693,7 +699,8 @@
 	return error;
 }
 
-/*! \brief Find named template */
+/*!\internal
+ * \brief Find named template */
 static struct minivm_template *message_template_find(const char *name)
 {
 	struct minivm_template *this, *res = NULL;
@@ -714,18 +721,21 @@
 }
 
 
-/*! \brief Clear list of templates */
+/*!\internal
+ * \brief Clear list of templates */
 static void message_destroy_list(void)
 {
 	struct minivm_template *this;
 	AST_LIST_LOCK(&message_templates);
-	while ((this = AST_LIST_REMOVE_HEAD(&message_templates, list))) 
+	while ((this = AST_LIST_REMOVE_HEAD(&message_templates, list))) {
 		message_template_free(this);
-		
+	}
+
 	AST_LIST_UNLOCK(&message_templates);
 }
 
-/*! \brief read buffer from file (base64 conversion) */
+/*!\internal
+ * \brief read buffer from file (base64 conversion) */
 static int b64_inbuf(struct b64_baseio *bio, FILE *fi)
 {
 	int l;
@@ -747,7 +757,8 @@
 	return 1;
 }
 
-/*! \brief read character from file to buffer (base64 conversion) */
+/*!\internal
+ * \brief read character from file to buffer (base64 conversion) */
 static int b64_inchar(struct b64_baseio *bio, FILE *fi)
 {
 	if (bio->iocp >= bio->iolen) {
@@ -758,7 +769,8 @@
 	return bio->iobuf[bio->iocp++];
 }
 
-/*! \brief write buffer to file (base64 conversion) */
+/*!\internal
+ * \brief write buffer to file (base64 conversion) */
 static int b64_ochar(struct b64_baseio *bio, int c, FILE *so)
 {
 	if (bio->linelength >= B64_BASELINELEN) {
@@ -776,7 +788,8 @@
 	return 1;
 }
 
-/*! \brief Encode file to base64 encoding for email attachment (base64 conversion) */
+/*!\internal
+ * \brief Encode file to base64 encoding for email attachment (base64 conversion) */
 static int base_encode(char *filename, FILE *so)
 {
 	unsigned char dtable[B64_BASEMAXINLINE];
@@ -859,7 +872,8 @@
 }
 
 
-/*! \brief Free user structure - if it's allocated */
+/*!\internal
+ * \brief Free user structure - if it's allocated */
 static void free_user(struct minivm_account *vmu)
 {
 	if (vmu->chanvars)
@@ -869,8 +883,9 @@
 
 
 
-/*! \brief Prepare for voicemail template by adding channel variables 
-	to the channel
+/*!\internal
+ * \brief Prepare for voicemail template by adding channel variables
+ * to the channel
 */
 static void prep_email_sub_vars(struct ast_channel *channel, const struct minivm_account *vmu, const char *cidnum, const char *cidname, const char *dur, const char *date, const char *counter)
 {
@@ -899,7 +914,8 @@
 		pbx_builtin_setvar_helper(channel, "MVM_COUNTER", counter);
 }
 
-/*! \brief Set default values for Mini-Voicemail users */
+/*!\internal
+ * \brief Set default values for Mini-Voicemail users */
 static void populate_defaults(struct minivm_account *vmu)
 {
 	ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);	
@@ -907,26 +923,8 @@
 	vmu->volgain = global_volgain;
 }
 
-/*! \brief Fix quote of mail headers for non-ascii characters */
-static char *mailheader_quote(const char *from, char *to, size_t len)
-{
-	char *ptr = to;
-	*ptr++ = '"';
-	for (; ptr < to + len - 1; from++) {
-		if (*from == '"')
-			*ptr++ = '\\';
-		else if (*from == '\0')
-			break;
-		*ptr++ = *from;
-	}
-	if (ptr < to + len - 1)
-		*ptr++ = '"';
-	*ptr = '\0';
-	return to;
-}
-
-
-/*! \brief Allocate new vm user and set default values */
+/*!\internal
+ * \brief Allocate new vm user and set default values */
 static struct minivm_account *mvm_user_alloc(void)
 {
 	struct minivm_account *new;
@@ -940,7 +938,8 @@
 }
 
 
-/*! \brief Clear list of users */
+/*!\internal
+ * \brief Clear list of users */
 static void vmaccounts_destroy_list(void)
 {
 	struct minivm_account *this;
@@ -951,7 +950,8 @@
 }
 
 
-/*! \brief Find user from static memory object list */
+/*!\internal
+ * \brief Find user from static memory object list */
 static struct minivm_account *find_account(const char *domain, const char *username, int createtemp)
 {
 	struct minivm_account *vmu = NULL, *cur;
@@ -992,8 +992,9 @@
 	return vmu;
 }
 
-/*! \brief Find user in realtime storage 
-	Returns pointer to minivm_account structure
+/*!\internal
+ * \brief Find user in realtime storage
+ * \return pointer to minivm_account structure
 */
 static struct minivm_account *find_user_realtime(const char *domain, const char *username)
 {
@@ -1023,7 +1024,102 @@
 	return retval;
 }
 
-/*! \brief Send voicemail with audio file as an attachment */
+/*!\internal
+ * \brief Check if the string would need encoding within the MIME standard, to
+ * avoid confusing certain mail software that expects messages to be 7-bit
+ * clean.
+ */
+static int check_mime(const char *str)
+{
+	for (; *str; str++) {
+		if (*str > 126 || *str < 32 || strchr("()<>@,:;/\"[]?.=", *str)) {
+			return 1;
+		}
+	}
+	return 0;
+}
+
+/*!\internal
+ * \brief Encode a string according to the MIME rules for encoding strings
+ * that are not 7-bit clean or contain control characters.
+ *
+ * Additionally, if the encoded string would exceed the MIME limit of 76
+ * characters per line, then the encoding will be broken up into multiple
+ * sections, separated by a space character, in order to facilitate
+ * breaking up the associated header across multiple lines.
+ *
+ * \param end An expandable buffer for holding the result
+ * \param maxlen \see ast_str
+ * \param charset Character set in which the result should be encoded
+ * \param start A string to be encoded
+ * \param preamble The length of the first line already used for this string,
+ * to ensure that each line maintains a maximum length of 76 chars.
+ * \param postamble the length of any additional characters appended to the
+ * line, used to ensure proper field wrapping.
+ * \return The encoded string.
+ */
+static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *charset, const char *start, size_t preamble, size_t postamble)
+{
+	struct ast_str *tmp = ast_str_alloca(80);
+	int first_section = 1;
+	*end = '\0';
+
+	ast_str_reset(*end);
+	ast_str_set(&tmp, -1, "=?%s?Q?", charset);
+	for (; *start; start++) {
+		int need_encoding = 0;
+		if (*start < 33 || *start > 126 || strchr("()<>@,:;/\"[]?.=_", *start)) {
+			need_encoding = 1;
+		}
+		if ((first_section && need_encoding && preamble + ast_str_strlen(tmp) > 70) ||
+			(first_section && !need_encoding && preamble + ast_str_strlen(tmp) > 72) ||
+			(!first_section && need_encoding && ast_str_strlen(tmp) > 70) ||
+			(!first_section && !need_encoding && ast_str_strlen(tmp) > 72)) {
+			/* Start new line */
+			ast_str_append(end, maxlen, "%s%s?=", first_section ? "" : " ", ast_str_buffer(tmp));
+			ast_str_set(&tmp, -1, "=?%s?Q?", charset);
+			first_section = 0;
+		}
+		if (need_encoding && *start == ' ') {
+			ast_str_append(&tmp, -1, "_");
+		} else if (need_encoding) {
+			ast_str_append(&tmp, -1, "=%hhX", *start);
+		} else {
+			ast_str_append(&tmp, -1, "%c", *start);
+		}
+	}
+	ast_str_append(end, maxlen, "%s%s?=%s", first_section ? "" : " ", ast_str_buffer(tmp), ast_str_strlen(tmp) + postamble > 74 ? " " : "");
+	return ast_str_buffer(*end);
+}
+
+/*!\internal
+ * \brief Wraps a character sequence in double quotes, escaping occurences of quotes within the string.
+ * \param from The string to work with.
+ * \param buf The destination buffer to write the modified quoted string.
+ * \param maxlen Always zero.  \see ast_str
+ *
+ * \return The destination string with quotes wrapped on it (the to field).
+ */
+static const char *ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
+{
+	const char *ptr;
+
+	/* We're only ever passing 0 to maxlen, so short output isn't possible */
+	ast_str_set(buf, maxlen, "\"");
+	for (ptr = from; *ptr; ptr++) {
+		if (*ptr == '"' || *ptr == '\\') {
+			ast_str_append(buf, maxlen, "\\%c", *ptr);
+		} else {
+			ast_str_append(buf, maxlen, "%c", *ptr);
+		}
+	}
+	ast_str_append(buf, maxlen, "\"");
+
+	return ast_str_buffer(*buf);
+}
+
+/*!\internal
+ * \brief Send voicemail with audio file as an attachment */
 static int sendmail(struct minivm_template *template, struct minivm_account *vmu, char *cidnum, char *cidname, const char *filename, char *format, int duration, int attach_user_voicemail, enum mvm_messagetype type, const char *counter)
 {
 	FILE *p = NULL;
@@ -1039,13 +1135,17 @@
 	struct timeval now;
 	struct ast_tm tm;
 	struct minivm_zone *the_zone = NULL;
-	int len_passdata;
 	struct ast_channel *ast;
 	char *finalfilename;
-	char *passdata = NULL;
-	char *passdata2 = NULL;
+	struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
 	char *fromaddress;
 	char *fromemail;
+
+	if (!str1 || !str2) {
+		ast_free(str1);
+		ast_free(str2);
+		return -1;
+	}
 
 	if (type == MVM_MESSAGE_EMAIL) {
 		if (vmu && !ast_strlen_zero(vmu->email)) {
@@ -1160,50 +1260,70 @@
 	if (ast_strlen_zero(fromaddress)) {
 		fprintf(p, "From: Asterisk PBX <%s>\n", who);
 	} else {
-		/* Allocate a buffer big enough for variable substitution */
-		int vmlen = strlen(fromaddress) * 3 + 200;
-
 		ast_debug(4, "Fromaddress template: %s\n", fromaddress);
-		if ((passdata = alloca(vmlen))) {
-			pbx_substitute_variables_helper(ast, fromaddress, passdata, vmlen);
-			len_passdata = strlen(passdata) * 2 + 3;
-			passdata2 = alloca(len_passdata);
-			fprintf(p, "From: %s <%s>\n", mailheader_quote(passdata, passdata2, len_passdata), who);
-		} else  {
-			ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
-			fclose(p);
-			return -1;	
+		ast_str_substitute_variables(&str1, 0, ast, fromaddress);
+		if (check_mime(ast_str_buffer(str1))) {
+			int first_line = 1;
+			char *ptr;
+			ast_str_encode_mime(&str2, 0, template->charset, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
+			while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
+				*ptr = '\0';
+				fprintf(p, "%s %s\n", first_line ? "From:" : "", ast_str_buffer(str2));
+				first_line = 0;
+				/* Substring is smaller, so this will never grow */
+				ast_str_set(&str2, 0, "%s", ptr + 1);
+			}
+			fprintf(p, "%s %s <%s>\n", first_line ? "From:" : "", ast_str_buffer(str2), who);
+		} else {
+			fprintf(p, "From: %s <%s>\n", ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
 		}
 	} 
-	ast_debug(4, "Fromstring now: %s\n", ast_strlen_zero(passdata) ? "-default-" : passdata);
 
 	fprintf(p, "Message-ID: <Asterisk-%d-%s-%d-%s>\n", (unsigned int)ast_random(), vmu->username, (int)getpid(), who);
-	len_passdata = strlen(vmu->fullname) * 2 + 3;
-	passdata2 = alloca(len_passdata);
-	if (!ast_strlen_zero(vmu->email))
-		fprintf(p, "To: %s <%s>\n", mailheader_quote(vmu->fullname, passdata2, len_passdata), vmu->email);
-	else
-		fprintf(p, "To: %s <%s@%s>\n", mailheader_quote(vmu->fullname, passdata2, len_passdata), vmu->username, vmu->domain);
+
+	if (ast_strlen_zero(vmu->email)) {
+		snprintf(email, sizeof(email), "%s@%s", vmu->username, vmu->domain);
+	} else {
+		ast_copy_string(email, vmu->email, sizeof(email));
+	}
+
+	if (check_mime(vmu->fullname)) {
+		int first_line = 1;
+		char *ptr;
+		ast_str_encode_mime(&str2, 0, template->charset, vmu->fullname, strlen("To: "), strlen(email) + 3);
+		while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
+			*ptr = '\0';
+			fprintf(p, "%s %s\n", first_line ? "To:" : "", ast_str_buffer(str2));
+			first_line = 0;
+			/* Substring is smaller, so this will never grow */
+			ast_str_set(&str2, 0, "%s", ptr + 1);
+		}
+		fprintf(p, "%s %s <%s>\n", first_line ? "To:" : "", ast_str_buffer(str2), email);
+	} else {
+		fprintf(p, "To: %s <%s>\n", ast_str_quote(&str2, 0, vmu->fullname), email);
+	}
 
 	if (!ast_strlen_zero(template->subject)) {
-		char *pass_data;
-		int vmlen = strlen(template->subject) * 3 + 200;
-		if ((pass_data = alloca(vmlen))) {
-			pbx_substitute_variables_helper(ast, template->subject, pass_data, vmlen);
-			fprintf(p, "Subject: %s\n", pass_data);
+		ast_str_substitute_variables(&str1, 0, ast, template->subject);
+		if (check_mime(ast_str_buffer(str1))) {
+			int first_line = 1;
+			char *ptr;
+			ast_str_encode_mime(&str2, 0, template->charset, ast_str_buffer(str1), strlen("Subject: "), 0);
+			while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
+				*ptr = '\0';
+				fprintf(p, "%s %s\n", first_line ? "Subject:" : "", ast_str_buffer(str2));
+				first_line = 0;
+				/* Substring is smaller, so this will never grow */
+				ast_str_set(&str2, 0, "%s", ptr + 1);
+			}
+			fprintf(p, "%s %s\n", first_line ? "Subject:" : "", ast_str_buffer(str2));
 		} else {
-			ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
-			fclose(p);
-			return -1;	
-		}
-
-		ast_debug(4, "Subject now: %s\n", pass_data);
-
-	} else  {
+			fprintf(p, "Subject: %s\n", ast_str_buffer(str1));
+		}
+	} else {
 		fprintf(p, "Subject: New message in mailbox %s@%s\n", vmu->username, vmu->domain);
 		ast_debug(1, "Using default subject for this email \n");
 	}
-
 
 	if (option_debug > 2)
 		fprintf(p, "X-Asterisk-debug: template %s user account %s@%s\n", template->name, vmu->username, vmu->domain);
@@ -1215,19 +1335,13 @@
 	fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"\n\n\n", bound);
 
 	fprintf(p, "--%s\n", bound);
-	fprintf(p, "Content-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n", global_charset);
+	fprintf(p, "Content-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n", template->charset);
 	if (!ast_strlen_zero(template->body)) {
-		char *pass_data;
-		int vmlen = strlen(template->body)*3 + 200;
-		if ((pass_data = alloca(vmlen))) {
-			pbx_substitute_variables_helper(ast, template->body, pass_data, vmlen);
-			ast_debug(3, "Message now: %s\n-----\n", pass_data);
-			fprintf(p, "%s\n", pass_data);
-		} else
-			ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
+		ast_str_substitute_variables(&str1, 0, ast, template->body);
+		ast_debug(3, "Message now: %s\n-----\n", ast_str_buffer(str1));
+		fprintf(p, "%s\n", ast_str_buffer(str1));
 	} else {
 		fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message \n"
-
 			"in mailbox %s from %s, on %s so you might\n"
 			"want to check it when you get a chance.  Thanks!\n\n\t\t\t\t--Asterisk\n\n", vmu->fullname, 
 			dur,  vmu->username, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
@@ -1239,7 +1353,7 @@
 		ast_debug(3, "Attaching file to message: %s\n", fname);
 		if (!strcasecmp(format, "ogg"))
 			ctype = "application/";
-	
+
 		fprintf(p, "--%s\n", bound);
 		fprintf(p, "Content-Type: %s%s; name=\"voicemailmsg.%s\"\n", ctype, format, format);
 		fprintf(p, "Content-Transfer-Encoding: base64\n");
@@ -1257,16 +1371,20 @@
 	if (ast) {
 		ast = ast_channel_release(ast);
 	}
+	ast_free(str1);
+	ast_free(str2);
 	return 0;
 }
 
-/*! \brief Create directory based on components */
+/*!\internal
+ * \brief Create directory based on components */
 static int make_dir(char *dest, int len, const char *domain, const char *username, const char *folder)
 {
 	return snprintf(dest, len, "%s%s/%s%s%s", MVM_SPOOL_DIR, domain, username, ast_strlen_zero(folder) ? "" : "/", folder ? folder : "");
 }
 
-/*! \brief Checks if directory exists. Does not create directory, but builds string in dest
+/*!\internal
+ * \brief Checks if directory exists. Does not create directory, but builds string in dest
  * \param dest    String. base directory.
  * \param len    Int. Length base directory string.
  * \param domain String. Ignored if is null or empty string.
@@ -1284,11 +1402,12 @@
 		return TRUE;
 }
 
-/*! \brief basically mkdir -p $dest/$domain/$username/$folder
+/*!\internal
+ * \brief basically mkdir -p $dest/$domain/$username/$folder
  * \param dest    String. base directory.
  * \param len     Length of directory string
  * \param domain  String. Ignored if is null or empty string.
- * \param folder  String. Ignored if is null or empty string. 
+ * \param folder  String. Ignored if is null or empty string.
  * \param username  String. Ignored if is null or empty string.
  * \return -1 on failure, 0 on success.
  */
@@ -1305,8 +1424,9 @@
 }
 
 
-/*! \brief Play intro message before recording voicemail 
-*/
+/*!\internal
+ * \brief Play intro message before recording voicemail
+ */
 static int invent_message(struct ast_channel *chan, char *domain, char *username, int busy, char *ecodes)
 {
 	int res;
@@ -1328,7 +1448,7 @@
 		char *i = username;
 
 		ast_debug(2, "No personal prompts. Using default prompt set for language\n");
-		
+
 		while (*i)  {
 			ast_debug(2, "Numeric? Checking %c\n", *i);
 			if (!isdigit(*i)) {
@@ -1339,16 +1459,16 @@
 		}
 
 		if (numericusername) {
-			if(ast_streamfile(chan, "vm-theperson", chan->language))
+			if (ast_streamfile(chan, "vm-theperson", chan->language))
 				return -1;
 			if ((res = ast_waitstream(chan, ecodes)))
 				return res;
-	
+
 			res = ast_say_digit_str(chan, username, ecodes, chan->language);
 			if (res)
 				return res;
 		} else {
-			if(ast_streamfile(chan, "vm-theextensionis", chan->language))
+			if (ast_streamfile(chan, "vm-theextensionis", chan->language))
 				return -1;
 			if ((res = ast_waitstream(chan, ecodes)))
 				return res;
@@ -1362,7 +1482,8 @@
 	return res;
 }
 
-/*! \brief Delete media files and attribute file */
+/*!\internal
+ * \brief Delete media files and attribute file */
 static int vm_delete(char *file)
 {
 	int res;
@@ -1375,30 +1496,31 @@
 }
 
 
-/*! \brief Record voicemail message & let caller review or re-record it, or set options if applicable */
+/*!\internal
+ * \brief Record voicemail message & let caller review or re-record it, or set options if applicable */
 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt,
 			      int outsidecaller, struct minivm_account *vmu, int *duration, const char *unlockdir,
 			      signed char record_gain)
 {
- 	int cmd = 0;
- 	int max_attempts = 3;
- 	int attempts = 0;
- 	int recorded = 0;
- 	int message_exists = 0;
+	int cmd = 0;
+	int max_attempts = 3;
+	int attempts = 0;
+	int recorded = 0;
+	int message_exists = 0;
 	signed char zero_gain = 0;
 	char *acceptdtmf = "#";
 	char *canceldtmf = "";
 
- 	/* Note that urgent and private are for flagging messages as such in the future */
- 
+	/* Note that urgent and private are for flagging messages as such in the future */
+
 	/* barf if no pointer passed to store duration in */
 	if (duration == NULL) {
 		ast_log(LOG_WARNING, "Error play_record_review called without duration pointer\n");
 		return -1;
 	}
 
- 	cmd = '3';	 /* Want to start by recording */
- 
+	cmd = '3';	 /* Want to start by recording */
+
 	while ((cmd >= 0) && (cmd != 't')) {
 		switch (cmd) {
 		case '1':
@@ -1406,23 +1528,23 @@
 			ast_stream_and_wait(chan, "vm-msgsaved", "");
 			cmd = 't';
 			break;
- 		case '2':
- 			/* Review */
+		case '2':
+			/* Review */
 			ast_verb(3, "Reviewing the message\n");
- 			ast_streamfile(chan, recordfile, chan->language);
- 			cmd = ast_waitstream(chan, AST_DIGIT_ANY);
- 			break;
- 		case '3':
- 			message_exists = 0;
- 			/* Record */
- 			if (recorded == 1) 
+			ast_streamfile(chan, recordfile, chan->language);
+			cmd = ast_waitstream(chan, AST_DIGIT_ANY);
+			break;
+		case '3':
+			message_exists = 0;
+			/* Record */
+			if (recorded == 1) 
 				ast_verb(3, "Re-recording the message\n");
- 			else
+			else
 				ast_verb(3, "Recording the message\n");
 			if (recorded && outsidecaller) 
- 				cmd = ast_play_and_wait(chan, "beep");
- 			recorded = 1;
- 			/* 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 */
+				cmd = ast_play_and_wait(chan, "beep");
+			recorded = 1;
+			/* 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);
 			if (ast_test_flag(vmu, MVM_OPERATOR))
@@ -1430,10 +1552,10 @@
 			cmd = ast_play_and_record_full(chan, playfile, recordfile, maxtime, fmt, duration, global_silencethreshold, global_maxsilence, unlockdir, acceptdtmf, canceldtmf);
 			if (record_gain)
 				ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
- 			if (cmd == -1) /* User has hung up, no options to give */
- 				return cmd;
- 			if (cmd == '0')
- 				break;
+			if (cmd == -1) /* User has hung up, no options to give */
+				return cmd;
+			if (cmd == '0')
+				break;
  			else if (cmd == '*')
  				break;
  			else {
@@ -1484,7 +1606,7 @@
  				if (!cmd)
  					cmd = ast_waitfordigit(chan, 600);
  			}
- 			
+
  			if (!cmd && outsidecaller && ast_test_flag(vmu, MVM_OPERATOR)) {
  				cmd = ast_play_and_wait(chan, "vm-reachoper");
  				if (!cmd)
@@ -1500,7 +1622,7 @@
  			}
  		}
  	}
- 	if (outsidecaller)  
+	if (outsidecaller)
 		ast_play_and_wait(chan, "vm-goodbye");
  	if (cmd == 't')
  		cmd = 0;
@@ -1521,10 +1643,11 @@
 		chan->cid.cid_name, chan->cid.cid_num);
 
 	ast_debug(1, "Executing: %s\n", arguments);
-  	ast_safe_system(arguments);
-}
-
-/*! \brief Send message to voicemail account owner */
+	ast_safe_system(arguments);
+}
+
+/*!\internal
+ * \brief Send message to voicemail account owner */
 static int notify_new_message(struct ast_channel *chan, const char *templatename, struct minivm_account *vmu, const char *filename, long duration, const char *format, char *cidnum, char *cidname)
 {
 	char *stringp;
@@ -1537,8 +1660,9 @@
 	if (!ast_strlen_zero(vmu->attachfmt)) {
 		if (strstr(format, vmu->attachfmt)) {
 			format = vmu->attachfmt;
-		} else 
+		} else {
 			ast_log(LOG_WARNING, "Attachment format '%s' is not one of the recorded formats '%s'.  Falling back to default format for '%s@%s'.\n", vmu->attachfmt, format, vmu->username, vmu->domain);
+		}
 	}
 
 	etemplate = message_template_find(vmu->etemplate);
@@ -1595,13 +1719,15 @@
 
 	run_externnotify(chan, vmu);		/* Run external notification */
 
-	if (etemplate->locale) 
+	if (etemplate->locale) {
 		setlocale(LC_TIME, oldlocale); /* Rest to old locale */
+	}
 	return res;
 }
 
  
-/*! \brief Record voicemail message, store into file prepared for sending e-mail */
+/*!\internal
+ * \brief Record voicemail message, store into file prepared for sending e-mail */
 static int leave_voicemail(struct ast_channel *chan, char *username, struct leave_vm_options *options)
 {
 	char tmptxtfile[PATH_MAX];
@@ -1663,7 +1789,6 @@
 
 
 	snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
-	
 
 	/* XXX This file needs to be in temp directory */
 	txtdes = mkstemp(tmptxtfile);
@@ -1700,7 +1825,7 @@
 		get_date(date, sizeof(date));
 		ast_localtime(&now, &tm, NULL);
 		ast_strftime(timebuf, sizeof(timebuf), "%H:%M:%S", &tm);
-		
+
 		snprintf(logbuf, sizeof(logbuf),
 			/* "Mailbox:domain:macrocontext:exten:priority:callerchan:callerid:origdate:origtime:duration:durationstatus:accountcode" */
 			"%s:%s:%s:%s:%d:%s:%s:%s:%s:%d:%s:%s\n",
@@ -1751,12 +1876,14 @@
 	}
 	global_stats.lastreceived = ast_tvnow();
 	global_stats.receivedmessages++;
-//	/* Go ahead and delete audio files from system, they're not needed any more */
-//	if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
-//		ast_filedelete(tmptxtfile, NULL);
-//		 /* Even not being used at the moment, it's better to convert ast_log to ast_debug anyway */
-//		ast_debug(2, "-_-_- Deleted audio file after notification :: %s \n", tmptxtfile);
-//	}
+#if 0
+	/* Go ahead and delete audio files from system, they're not needed any more */
+	if (ast_fileexists(tmptxtfile, NULL, NULL) <= 0) {
+		ast_filedelete(tmptxtfile, NULL);
+		 /* Even not being used at the moment, it's better to convert ast_log to ast_debug anyway */
+		ast_debug(2, "-_-_- Deleted audio file after notification :: %s \n", tmptxtfile);
+	}
+#endif
 
 	if (res > 0)
 		res = 0;
@@ -1768,7 +1895,8 @@
 	return res;
 }
 
-/*! \brief Queue a message waiting event */
+/*!\internal
+ * \brief Queue a message waiting event */
 static void queue_mwi_event(const char *mbx, const char *ctx, int urgent, int new, int old)
 {
 	struct ast_event *event;
@@ -1792,7 +1920,8 @@
 	ast_event_queue_and_cache(event);
 }
 
-/*! \brief Send MWI using interal Asterisk event subsystem */
+/*!\internal
+ * \brief Send MWI using interal Asterisk event subsystem */
 static int minivm_mwi_exec(struct ast_channel *chan, void *data)
 {
 	int argc;
@@ -1803,37 +1932,38 @@
 	char *mailbox;
 	char *domain;
 	if (ast_strlen_zero(data))  {
-                ast_log(LOG_ERROR, "Minivm needs at least an account argument \n");
-                return -1;
-        }
-        tmpptr = ast_strdupa((char *)data);
-        if (!tmpptr) {
-                ast_log(LOG_ERROR, "Out of memory\n");
-                return -1;
-        }
-        argc = ast_app_separate_args(tmpptr, ',', argv, ARRAY_LEN(argv));
+		ast_log(LOG_ERROR, "Minivm needs at least an account argument \n");
+		return -1;
+	}
+	tmpptr = ast_strdupa((char *)data);
+	if (!tmpptr) {
+		ast_log(LOG_ERROR, "Out of memory\n");
+		return -1;
+	}
+	argc = ast_app_separate_args(tmpptr, ',', argv, ARRAY_LEN(argv));
 	if (argc < 4) {
 		ast_log(LOG_ERROR, "%d arguments passed to MiniVM_MWI, need 4.\n", argc);
 		return -1;
 	}
-        ast_copy_string(tmp, argv[0], sizeof(tmp));
-        mailbox = tmp;
-        domain = strchr(tmp, '@');
-        if (domain) {
-                *domain = '\0';
-                domain++;
-        }
-        if (ast_strlen_zero(domain) || ast_strlen_zero(mailbox)) {
-                ast_log(LOG_ERROR, "Need mailbox at context as argument. Sorry. Argument 0 %s\n", argv[0]);
-                return -1;
-        }
+	ast_copy_string(tmp, argv[0], sizeof(tmp));
+	mailbox = tmp;
+	domain = strchr(tmp, '@');
+	if (domain) {
+		*domain = '\0';
+		domain++;
+	}
+	if (ast_strlen_zero(domain) || ast_strlen_zero(mailbox)) {
+		ast_log(LOG_ERROR, "Need mailbox at context as argument. Sorry. Argument 0 %s\n", argv[0]);
+		return -1;
+	}
 	queue_mwi_event(mailbox, domain, atoi(argv[1]), atoi(argv[2]), atoi(argv[3]));
 
 	return res;
 }
 
 
-/*! \brief Notify voicemail account owners - either generic template or user specific */
+/*!\internal
+ * \brief Notify voicemail account owners - either generic template or user specific */
 static int minivm_notify_exec(struct ast_channel *chan, void *data)
 {
 	int argc;
@@ -1848,7 +1978,7 @@
 	const char *filename;
 	const char *format;
 	const char *duration_string;
-	
+
 	if (ast_strlen_zero(data))  {
 		ast_log(LOG_ERROR, "Minivm needs at least an account argument \n");
 		return -1;
@@ -1912,7 +2042,8 @@
 
 }
 
-/*! \brief Dialplan function to record voicemail */
+/*!\internal
+ * \brief Dialplan function to record voicemail */
 static int minivm_record_exec(struct ast_channel *chan, void *data)
 {
 	int res = 0;
@@ -1922,7 +2053,7 @@
 	char *argv[2];
 	struct ast_flags flags = { 0 };
 	char *opts[OPT_ARG_ARRAY_SIZE];
-		
+
 	memset(&leave_options, 0, sizeof(leave_options));
 
 	/* Answer channel if it's not already answered */
@@ -1968,7 +2099,8 @@
 	return res;
 }
 
-/*! \brief Play voicemail prompts - either generic or user specific */
+/*!\internal
+ * \brief Play voicemail prompts - either generic or user specific */
 static int minivm_greet_exec(struct ast_channel *chan, void *data)
 {
 	struct leave_vm_options leave_options = { 0, '\0'};
@@ -2154,12 +2286,13 @@
 
 }
 
-/*! \brief Dialplan application to delete voicemail */
+/*!\internal
+ * \brief Dialplan application to delete voicemail */
 static int minivm_delete_exec(struct ast_channel *chan, void *data)
 {
 	int res = 0;
 	char filename[BUFSIZ];
-		
+
 	if (!ast_strlen_zero(data)) {
 		ast_copy_string(filename, (char *) data, sizeof(filename));
 	} else {
@@ -2609,7 +2742,6 @@
 	ast_copy_string(default_vmformat, "wav", sizeof(default_vmformat));
 	ast_set2_flag((&globalflags), FALSE, MVM_REVIEW);	
 	ast_set2_flag((&globalflags), FALSE, MVM_OPERATOR);	
-	strcpy(global_charset, "ISO-8859-1");
 	/* Reset statistics */
 	memset(&global_stats, 0, sizeof(global_stats));
 	global_stats.reset = ast_tvnow();

Modified: trunk/apps/app_voicemail.c
URL: http://svn.digium.com/svn-view/asterisk/trunk/apps/app_voicemail.c?view=diff&rev=191140&r1=191139&r2=191140
==============================================================================
--- trunk/apps/app_voicemail.c (original)
+++ trunk/apps/app_voicemail.c Wed Apr 29 13:53:01 2009
@@ -3843,9 +3843,10 @@
 	return 1;
 }
 
-static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *dur, char *date, char *passdata, size_t passdatasize, const char *category, const char *flag)
+static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *dur, char *date, const char *category, const char *flag)
 {
 	char callerid[256];
+	char num[12];
 	char fromdir[256], fromfile[256];
 	struct ast_config *msg_cfg;
 	const char *origcallerid, *origtime;
@@ -3856,8 +3857,8 @@
 	/* Prepare variables for substitution in email body and subject */
 	pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
 	pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
-	snprintf(passdata, passdatasize, "%d", msgnum);
-	pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);

[... 3857 lines stripped ...]



More information about the asterisk-commits mailing list