aboutsummaryrefslogtreecommitdiffstats
path: root/apps
diff options
context:
space:
mode:
authortilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2009-04-29 18:53:01 +0000
committertilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b>2009-04-29 18:53:01 +0000
commit8fc2c0f7245703d3dde31d7fa035f3f28c82daeb (patch)
tree972bdf8f96c18f1b9667469307af69385f4a75f3 /apps
parent6d9e0aa8817729e7914bb1b3fafe02dc96ae41b5 (diff)
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. Reviewboard: http://reviewboard.digium.com/r/174/ git-svn-id: http://svn.digium.com/svn/asterisk/trunk@191140 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'apps')
-rw-r--r--apps/app_exec.c22
-rw-r--r--apps/app_macro.c35
-rw-r--r--apps/app_minivm.c490
-rw-r--r--apps/app_voicemail.c314
4 files changed, 533 insertions, 328 deletions
diff --git a/apps/app_exec.c b/apps/app_exec.c
index 3b831ba6c..3c5be33b6 100644
--- a/apps/app_exec.c
+++ b/apps/app_exec.c
@@ -132,56 +132,61 @@ static char *app_execif = "ExecIf";
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 @@ static int tryexec_exec(struct ast_channel *chan, void *data)
}
}
+ ast_free(args);
return 0;
}
diff --git a/apps/app_macro.c b/apps/app_macro.c
index dfbd3b12c..458a93b37 100644
--- a/apps/app_macro.c
+++ b/apps/app_macro.c
@@ -231,13 +231,14 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
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 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
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 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
}
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));
@@ -337,6 +341,8 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
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';
chan->exten[1] = '\0';
@@ -415,8 +421,9 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
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 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
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 @@ static int _macro_exec(struct ast_channel *chan, void *data, int exclusive)
}
}
ast_channel_unlock(chan);
+ ast_free(tmp_subst);
return res;
}
diff --git a/apps/app_minivm.c b/apps/app_minivm.c
index 9148ee130..fffa714e0 100644
--- a/apps/app_minivm.c
+++ b/apps/app_minivm.c
@@ -483,11 +483,12 @@ AST_APP_OPTIONS(minivm_accmess_options, {
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 @@ struct minivm_account {
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 char default_vmformat[80];
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 int create_vmaccount(char *name, struct ast_variable *var, int realtime);
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 @@ static struct minivm_template *message_template_create(const char *name)
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 @@ static void message_template_free(struct minivm_template *template)
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 @@ static int message_template_build(const char *name, struct ast_variable *var)
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 @@ static struct minivm_template *message_template_find(const char *name)
}
-/*! \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 @@ static int b64_inbuf(struct b64_baseio *bio, FILE *fi)
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 @@ static int b64_inchar(struct b64_baseio *bio, FILE *fi)
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 @@ static int b64_ochar(struct b64_baseio *bio, int c, FILE *so)
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 @@ static int get_date(char *s, int len)
}
-/*! \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 @@ static void free_user(struct minivm_account *vmu)
-/*! \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 @@ static void prep_email_sub_vars(struct ast_channel *channel, const struct minivm
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 @@ static void populate_defaults(struct minivm_account *vmu)
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 @@ static struct minivm_account *mvm_user_alloc(void)
}
-/*! \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 @@ static void vmaccounts_destroy_list(void)
}
-/*! \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 @@ static struct minivm_account *find_account(const char *domain, const char *usern
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 @@ static struct minivm_account *find_user_realtime(const char *domain, const char
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,14 +1135,18 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu
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)) {
ast_copy_string(email, vmu->email, sizeof(email));
@@ -1160,51 +1260,71 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu
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;
+ fprintf(p, "Subject: %s\n", ast_str_buffer(str1));
}
-
- ast_debug(4, "Subject now: %s\n", pass_data);
-
- } else {
+ } 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);
fprintf(p, "MIME-Version: 1.0\n");
@@ -1215,19 +1335,13 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu
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 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu
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 @@ static int sendmail(struct minivm_template *template, struct minivm_account *vmu
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 @@ static int check_dirpath(char *dest, int len, char *domain, char *username, char
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 @@ static int create_dirpath(char *dest, int len, char *domain, char *username, cha
}
-/*! \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 @@ static int invent_message(struct ast_channel *chan, char *domain, char *username
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 @@ static int invent_message(struct ast_channel *chan, char *domain, char *username
}
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 @@ static int invent_message(struct ast_channel *chan, char *domain, char *username
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 @@ static int vm_delete(char *file)
}
-/*! \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 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
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 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
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 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
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 @@ static int play_record_review(struct ast_channel *chan, char *playfile, char *re
}
}
}
- if (outsidecaller)
+ if (outsidecaller)
ast_play_and_wait(chan, "vm-goodbye");
if (cmd == 't')
cmd = 0;
@@ -1521,10 +1643,11 @@ static void run_externnotify(struct ast_channel *chan, struct minivm_account *vm
chan->cid.cid_name, chan->cid.cid_num);
ast_debug(1, "Executing: %s\n", arguments);
- ast_safe_system(arguments);
+ ast_safe_system(arguments);
}
-/*! \brief Send message to voicemail account owner */
+/*!\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 @@ static int notify_new_message(struct ast_channel *chan, const char *templatename
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 @@ static int notify_new_message(struct ast_channel *chan, const char *templatename
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 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
snprintf(tmptxtfile, sizeof(tmptxtfile), "%s/XXXXXX", tmpdir);
-
/* XXX This file needs to be in temp directory */
txtdes = mkstemp(tmptxtfile);
@@ -1700,7 +1825,7 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
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 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
}
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 @@ static int leave_voicemail(struct ast_channel *chan, char *username, struct leav
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 @@ static void queue_mwi_event(const char *mbx, const char *ctx, int urgent, int ne
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 @@ static int minivm_mwi_exec(struct ast_channel *chan, void *data)
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@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@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 @@ static int minivm_notify_exec(struct ast_channel *chan, void *data)
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 @@ static int minivm_notify_exec(struct ast_channel *chan, void *data)
}
-/*! \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 @@ static int minivm_record_exec(struct ast_channel *chan, void *data)
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 @@ static int minivm_record_exec(struct ast_channel *chan, void *data)
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 @@ static int minivm_greet_exec(struct ast_channel *chan, void *data)
}
-/*! \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 @@ static int load_config(int reload)
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();
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c
index 27aabf4c7..b5d7f592e 100644
--- a/apps/app_voicemail.c
+++ b/apps/app_voicemail.c
@@ -3843,9 +3843,10 @@ static int base_encode(char *filename, FILE *so)
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 @@ static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu
/* 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);
+ snprintf(num, sizeof(num), "%d", msgnum);
+ pbx_builtin_setvar_helper(ast, "VM_MSGNUM", num);
pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
pbx_builtin_setvar_helper(ast, "VM_CALLERID", (!ast_strlen_zero(cidname) || !ast_strlen_zero(cidnum)) ?
@@ -3901,30 +3902,32 @@ static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu
/*!
* \brief Wraps a character sequence in double quotes, escaping occurences of quotes within the string.
* \param from The string to work with.
- * \param to The string to write the modified quoted string. This buffer should be sufficiently larger than the from string, so as to allow it to be expanded by the surrounding quotes and escaping of internal quotes.
+ * \param buf The buffer into which to write the modified quoted string.
+ * \param maxlen Always zero, but see \see ast_str
*
* \return The destination string with quotes wrapped on it (the to field).
*/
-static char *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;
+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);
+ }
}
- if (ptr < to + len - 1)
- *ptr++ = '"';
- *ptr = '\0';
- return to;
+ ast_str_append(buf, maxlen, "\"");
+
+ return ast_str_buffer(*buf);
}
/*! \brief
* fill in *tm for current time according to the proper timezone, if any.
- * Return tm so it can be used as a function argument.
+ * \return tm so it can be used as a function argument.
*/
static const struct ast_tm *vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
{
@@ -3967,46 +3970,47 @@ static int check_mime(const char *str)
* sections, separated by a space character, in order to facilitate
* breaking up the associated header across multiple lines.
*
- * \param start A string to be encoded
* \param end An expandable buffer for holding the result
+ * \param maxlen Always zero, but see \see ast_str
+ * \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.
* \retval The encoded string.
*/
-static char *encode_mime_str(const char *start, char *end, size_t endsize, size_t preamble, size_t postamble)
+static const char *ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
{
- char tmp[80];
+ struct ast_str *tmp = ast_str_alloca(80);
int first_section = 1;
- size_t endlen = 0, tmplen = 0;
*end = '\0';
- tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset);
+ 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 + tmplen > 70) ||
- (first_section && !need_encoding && preamble + tmplen > 72) ||
- (!first_section && need_encoding && tmplen > 70) ||
- (!first_section && !need_encoding && tmplen > 72)) {
+ 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 */
- endlen += snprintf(end + endlen, endsize - endlen, "%s%s?=", first_section ? "" : " ", tmp);
- tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset);
+ 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 == ' ') {
- tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "_");
+ ast_str_append(&tmp, -1, "_");
} else if (need_encoding) {
- tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "=%hhX", *start);
+ ast_str_append(&tmp, -1, "=%hhX", *start);
} else {
- tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "%c", *start);
+ ast_str_append(&tmp, -1, "%c", *start);
}
}
- snprintf(end + endlen, endsize - endlen, "%s%s?=%s", first_section ? "" : " ", tmp, endlen + postamble > 74 ? " " : "");
- return end;
+ 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);
}
/*!
@@ -4038,28 +4042,21 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
char dur[256];
struct ast_tm tm;
char enc_cidnum[256] = "", enc_cidname[256] = "";
- char *passdata = NULL, *passdata2;
- size_t len_passdata = 0, len_passdata2, tmplen;
+ struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
char *greeting_attachment;
char filename[256];
+ if (!str1 || !str2) {
+ ast_free(str1);
+ ast_free(str2);
+ return;
+ }
#ifdef IMAP_STORAGE
#define ENDL "\r\n"
#else
#define ENDL "\n"
#endif
- /* One alloca for multiple fields */
- len_passdata2 = strlen(vmu->fullname);
- if (emailsubject && (tmplen = strlen(emailsubject)) > len_passdata2) {
- len_passdata2 = tmplen;
- }
- if ((tmplen = strlen(fromstring)) > len_passdata2) {
- len_passdata2 = tmplen;
- }
- len_passdata2 = len_passdata2 * 3 + 200;
- passdata2 = alloca(len_passdata2);
-
if (cidnum) {
strip_control(cidnum, enc_cidnum, sizeof(enc_cidnum));
}
@@ -4068,14 +4065,16 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
}
gethostname(host, sizeof(host) - 1);
- if (strchr(srcemail, '@'))
+ if (strchr(srcemail, '@')) {
ast_copy_string(who, srcemail, sizeof(who));
- else
+ } else {
snprintf(who, sizeof(who), "%s@%s", srcemail, host);
+ }
greeting_attachment = strrchr(ast_strdupa(attach), '/');
- if (greeting_attachment)
+ if (greeting_attachment) {
*greeting_attachment++ = '\0';
+ }
snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
@@ -4088,23 +4087,22 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
struct ast_channel *ast;
if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
char *ptr;
- memset(passdata2, 0, len_passdata2);
- prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, passdata2, len_passdata2, category, flag);
- pbx_substitute_variables_helper(ast, fromstring, passdata2, len_passdata2);
- len_passdata = strlen(passdata2) * 3 + 300;
- passdata = alloca(len_passdata);
- if (check_mime(passdata2)) {
+ prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
+ ast_str_substitute_variables(&str1, 0, ast, fromstring);
+
+ if (check_mime(ast_str_buffer(str1))) {
int first_line = 1;
- encode_mime_str(passdata2, passdata, len_passdata, strlen("From: "), strlen(who) + 3);
- while ((ptr = strchr(passdata, ' '))) {
+ ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
+ while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
*ptr = '\0';
- fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", passdata);
+ fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", ast_str_buffer(str2));
first_line = 0;
- passdata = ptr + 1;
+ /* Substring is smaller, so this will never grow */
+ ast_str_set(&str2, 0, "%s", ptr + 1);
}
- fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", passdata, who);
+ fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
} else {
- fprintf(p, "From: %s <%s>" ENDL, quote(passdata2, passdata, len_passdata), who);
+ fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
}
ast = ast_channel_release(ast);
} else {
@@ -4117,44 +4115,39 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
if (check_mime(vmu->fullname)) {
int first_line = 1;
char *ptr;
- encode_mime_str(vmu->fullname, passdata2, len_passdata2, strlen("To: "), strlen(vmu->email) + 3);
- while ((ptr = strchr(passdata2, ' '))) {
+ ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(vmu->email) + 3);
+ while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
*ptr = '\0';
- fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", passdata2);
+ fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", ast_str_buffer(str2));
first_line = 0;
- passdata2 = ptr + 1;
+ /* Substring is smaller, so this will never grow */
+ ast_str_set(&str2, 0, "%s", ptr + 1);
}
- fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", passdata2, vmu->email);
+ fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), vmu->email);
} else {
- fprintf(p, "To: %s <%s>" ENDL, quote(vmu->fullname, passdata2, len_passdata2), vmu->email);
+ fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), vmu->email);
}
+
if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->emailsubject)) {
char *e_subj = !ast_strlen_zero(vmu->emailsubject) ? vmu->emailsubject : emailsubject;
struct ast_channel *ast;
if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
- int vmlen = strlen(e_subj) * 3 + 200;
- /* Only allocate more space if the previous was not large enough */
- if (vmlen > len_passdata) {
- passdata = alloca(vmlen);
- len_passdata = vmlen;
- }
-
- memset(passdata, 0, len_passdata);
- prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, len_passdata, category, flag);
- pbx_substitute_variables_helper(ast, e_subj, passdata, len_passdata);
- if (check_mime(passdata)) {
+ prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
+ ast_str_substitute_variables(&str1, 0, ast, e_subj);
+ if (check_mime(ast_str_buffer(str1))) {
int first_line = 1;
char *ptr;
- encode_mime_str(passdata, passdata2, len_passdata2, strlen("Subject: "), 0);
- while ((ptr = strchr(passdata2, ' '))) {
+ ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
+ while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
*ptr = '\0';
- fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2);
+ fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
first_line = 0;
- passdata2 = ptr + 1;
+ /* Substring is smaller, so this will never grow */
+ ast_str_set(&str2, 0, "%s", ptr + 1);
}
- fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2);
+ fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
} else {
- fprintf(p, "Subject: %s" ENDL, passdata);
+ fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
}
ast = ast_channel_release(ast);
} else {
@@ -4222,16 +4215,13 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in
char* e_body = vmu->emailbody ? vmu->emailbody : emailbody;
struct ast_channel *ast;
if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
- char *passdata;
- int vmlen = strlen(e_body) * 3 + 200;
- passdata = alloca(vmlen);
- memset(passdata, 0, vmlen);
- prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
- pbx_substitute_variables_helper(ast, e_body, passdata, vmlen);
- fprintf(p, "%s" ENDL, passdata);
+ prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
+ ast_str_substitute_variables(&str1, 0, ast, e_body);
+ fprintf(p, "%s" ENDL, ast_str_buffer(str1));
ast = ast_channel_release(ast);
- } else
+ } else {
ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
+ }
} else if (msgnum > -1) {
if (strcmp(vmu->mailbox, mailbox)) {
/* Forwarded type */
@@ -4296,6 +4286,8 @@ plain_message:
add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
}
}
+ ast_free(str1);
+ ast_free(str2);
}
static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum)
@@ -4349,7 +4341,6 @@ static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format,
}
return 0;
}
-#undef ENDL
static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, const char *flag)
{
@@ -4381,6 +4372,7 @@ static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *c
static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category, const char *flag)
{
+ char enc_cidnum[256], enc_cidname[256];
char date[256];
char host[MAXHOSTNAMELEN] = "";
char who[256];
@@ -4389,49 +4381,106 @@ static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char
char tmp2[PATH_MAX];
struct ast_tm tm;
FILE *p;
+ struct ast_str *str1 = ast_str_create(16), *str2 = ast_str_create(16);
+
+ if (!str1 || !str2) {
+ ast_free(str1);
+ ast_free(str2);
+ return -1;
+ }
+
+ if (cidnum) {
+ strip_control(cidnum, enc_cidnum, sizeof(enc_cidnum));
+ }
+ if (cidname) {
+ strip_control(cidname, enc_cidname, sizeof(enc_cidname));
+ }
if ((p = vm_mkftemp(tmp)) == NULL) {
ast_log(AST_LOG_WARNING, "Unable to launch '%s' (can't create temporary file)\n", mailcmd);
+ ast_free(str1);
+ ast_free(str2);
return -1;
}
gethostname(host, sizeof(host)-1);
- if (strchr(srcemail, '@'))
+ if (strchr(srcemail, '@')) {
ast_copy_string(who, srcemail, sizeof(who));
- else
+ } else {
snprintf(who, sizeof(who), "%s@%s", srcemail, host);
+ }
snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
ast_strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", vmu_tm(vmu, &tm));
fprintf(p, "Date: %s\n", date);
- if (*pagerfromstring) {
+ if (!ast_strlen_zero(pagerfromstring)) {
struct ast_channel *ast;
if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
- char *passdata;
- int vmlen = strlen(fromstring)*3 + 200;
- passdata = alloca(vmlen);
- memset(passdata, 0, vmlen);
- prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
- pbx_substitute_variables_helper(ast, pagerfromstring, passdata, vmlen);
- fprintf(p, "From: %s <%s>\n", passdata, who);
+ char *ptr;
+ prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
+ ast_str_substitute_variables(&str1, 0, ast, pagerfromstring);
+
+ if (check_mime(ast_str_buffer(str1))) {
+ int first_line = 1;
+ ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("From: "), strlen(who) + 3);
+ while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
+ *ptr = '\0';
+ fprintf(p, "%s %s" ENDL, 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>" ENDL, first_line ? "From:" : "", ast_str_buffer(str2), who);
+ } else {
+ fprintf(p, "From: %s <%s>" ENDL, ast_str_quote(&str2, 0, ast_str_buffer(str1)), who);
+ }
ast = ast_channel_release(ast);
- } else
+ } else {
ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
- } else
- fprintf(p, "From: Asterisk PBX <%s>\n", who);
- fprintf(p, "To: %s\n", pager);
- if (pagersubject) {
+ }
+ } else {
+ fprintf(p, "From: Asterisk PBX <%s>" ENDL, who);
+ }
+
+ if (check_mime(vmu->fullname)) {
+ int first_line = 1;
+ char *ptr;
+ ast_str_encode_mime(&str2, 0, vmu->fullname, strlen("To: "), strlen(pager) + 3);
+ while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
+ *ptr = '\0';
+ fprintf(p, "%s %s" ENDL, 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>" ENDL, first_line ? "To:" : "", ast_str_buffer(str2), pager);
+ } else {
+ fprintf(p, "To: %s <%s>" ENDL, ast_str_quote(&str2, 0, vmu->fullname), pager);
+ }
+
+ if (!ast_strlen_zero(pagersubject)) {
struct ast_channel *ast;
if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
- char *passdata;
- int vmlen = strlen(pagersubject) * 3 + 200;
- passdata = alloca(vmlen);
- memset(passdata, 0, vmlen);
- prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
- pbx_substitute_variables_helper(ast, pagersubject, passdata, vmlen);
- fprintf(p, "Subject: %s\n\n", passdata);
+ prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
+ ast_str_substitute_variables(&str1, 0, ast, pagersubject);
+ if (check_mime(ast_str_buffer(str1))) {
+ int first_line = 1;
+ char *ptr;
+ ast_str_encode_mime(&str2, 0, ast_str_buffer(str1), strlen("Subject: "), 0);
+ while ((ptr = strchr(ast_str_buffer(str2), ' '))) {
+ *ptr = '\0';
+ fprintf(p, "%s %s" ENDL, 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" ENDL, first_line ? "Subject:" : "", ast_str_buffer(str2));
+ } else {
+ fprintf(p, "Subject: %s" ENDL, ast_str_buffer(str1));
+ }
ast = ast_channel_release(ast);
- } else
+ } else {
ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
+ }
} else {
if (ast_strlen_zero(flag)) {
fprintf(p, "Subject: New VM\n\n");
@@ -4444,26 +4493,27 @@ static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char
if (pagerbody) {
struct ast_channel *ast;
if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Substitution/voicemail"))) {
- char *passdata;
- int vmlen = strlen(pagerbody) * 3 + 200;
- passdata = alloca(vmlen);
- memset(passdata, 0, vmlen);
- prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, passdata, vmlen, category, flag);
- pbx_substitute_variables_helper(ast, pagerbody, passdata, vmlen);
- fprintf(p, "%s\n", passdata);
+ prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
+ ast_str_substitute_variables(&str1, 0, ast, pagerbody);
+ fprintf(p, "%s" ENDL, ast_str_buffer(str1));
ast = ast_channel_release(ast);
- } else
+ } else {
ast_log(AST_LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
+ }
} else {
fprintf(p, "New %s long %s msg in box %s\n"
"from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
}
+
fclose(p);
snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
ast_safe_system(tmp2);
ast_debug(1, "Sent page to %s with command '%s'\n", pager, mailcmd);
+ ast_free(str1);
+ ast_free(str2);
return 0;
}
+#undef ENDL
/*!
* \brief Gets the current date and time, as formatted string.
@@ -5025,7 +5075,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
char fmt[80];
char *context;
char ecodes[17] = "#";
- char tmp[1024] = "";
+ struct ast_str *tmp = ast_str_create(16);
char *tmpptr;
struct ast_vm_user *vmu;
struct ast_vm_user svm;
@@ -5034,9 +5084,13 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_
const char *alldtmf = "0123456789ABCD*#";
char flag[80];
- ast_copy_string(tmp, ext, sizeof(tmp));
- ext = tmp;
- if ((context = strchr(tmp, '@'))) {
+ if (!tmp) {
+ return -1;
+ }
+
+ ast_str_set(&tmp, 0, "%s", ext);
+ ext = ast_str_buffer(tmp);
+ if ((context = strchr(ext, '@'))) {
*context++ = '\0';
tmpptr = strchr(context, '&');
} else {