diff options
author | tilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b> | 2008-10-14 17:41:08 +0000 |
---|---|---|
committer | tilghman <tilghman@f38db490-d61c-443f-a65b-d21fe96a405b> | 2008-10-14 17:41:08 +0000 |
commit | 52256513d634fbfeaf1957a962b9ec8f28ef212c (patch) | |
tree | 4d1c8e9e355857a9d5404c86f14fd4a02af8f524 /apps/app_voicemail.c | |
parent | 4b8ec2d6a99db41ed02e405945b32851055800f8 (diff) |
Ensure that mail headers are 7-bit clean, even when UTF-8 characters are used
in headers like 'Subject' and 'To'.
Closes AST-107.
git-svn-id: http://svn.digium.com/svn/asterisk/branches/1.4@148916 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'apps/app_voicemail.c')
-rw-r--r-- | apps/app_voicemail.c | 160 |
1 files changed, 136 insertions, 24 deletions
diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index f6401b2b5..f104d6ee8 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -2979,6 +2979,70 @@ static const struct tm *vmu_tm(const struct ast_vm_user *vmu, struct tm *tm) return tm; } +/*!\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; +} + +/*!\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 start A string to be encoded + * \param end An expandable buffer for holding the result + * \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) +{ + char tmp[80]; + int first_section = 1; + size_t endlen = 0, tmplen = 0; + *end = '\0'; + + tmplen = snprintf(tmp, sizeof(tmp), "=?%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)) { + /* Start new line */ + endlen += snprintf(end + endlen, endsize - endlen, "%s%s?=", first_section ? "" : " ", tmp); + tmplen = snprintf(tmp, sizeof(tmp), "=?%s?Q?", charset); + first_section = 0; + } + if (need_encoding && *start == ' ') { + tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "_"); + } else if (need_encoding) { + tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "=%hhX", *start); + } else { + tmplen += snprintf(tmp + tmplen, sizeof(tmp) - tmplen, "%c", *start); + } + } + snprintf(end + endlen, endsize - endlen, "%s%s?=%s", first_section ? "" : " ", tmp, endlen + postamble > 74 ? " " : ""); + return end; +} + static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap) { char date[256]; @@ -2990,14 +3054,28 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in char tmpcmd[256]; char enc_cidnum[256] = "", enc_cidname[256] = ""; struct tm tm; - char *passdata2; - size_t len_passdata; + char *passdata = NULL, *passdata2; + size_t len_passdata, len_passdata2, tmplen; #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(emailtitle)) > 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)); } @@ -3020,37 +3098,71 @@ static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, in if (*fromstring) { struct ast_channel *ast; if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) { - char *passdata; - int vmlen = strlen(fromstring)*3 + 200; - if ((passdata = alloca(vmlen))) { - memset(passdata, 0, vmlen); - prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, enc_cidnum, enc_cidname, dur, date, passdata, vmlen, category); - pbx_substitute_variables_helper(ast, fromstring, passdata, vmlen); - len_passdata = strlen(passdata) * 2 + 3; - passdata2 = alloca(len_passdata); - fprintf(p, "From: %s <%s>" ENDL, quote(passdata, passdata2, len_passdata), who); - } else - ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n"); + char *ptr; + memset(passdata2, 0, len_passdata2); + prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, enc_cidnum, enc_cidname, dur, date, passdata2, len_passdata2, category); + pbx_substitute_variables_helper(ast, fromstring, passdata2, len_passdata2); + len_passdata = strlen(passdata2) * 3 + 300; + passdata = alloca(len_passdata); + if (check_mime(passdata2)) { + int first_line = 1; + encode_mime_str(passdata2, passdata, len_passdata, strlen("From: "), strlen(who) + 3); + while ((ptr = strchr(passdata, ' '))) { + *ptr = '\0'; + fprintf(p, "%s %s" ENDL, first_line ? "From:" : "", passdata); + first_line = 0; + passdata = ptr + 1; + } + fprintf(p, "%s %s <%s>" ENDL, first_line ? "From:" : "", passdata, who); + } else { + fprintf(p, "From: %s <%s>" ENDL, quote(passdata, passdata2, len_passdata2), who); + } ast_channel_free(ast); } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n"); } else fprintf(p, "From: Asterisk PBX <%s>" ENDL, who); - len_passdata = strlen(vmu->fullname) * 2 + 3; - passdata2 = alloca(len_passdata); - fprintf(p, "To: %s <%s>" ENDL, quote(vmu->fullname, passdata2, len_passdata), vmu->email); + + 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, ' '))) { + *ptr = '\0'; + fprintf(p, "%s %s" ENDL, first_line ? "To:" : "", passdata2); + first_line = 0; + passdata2 = ptr + 1; + } + fprintf(p, "%s %s <%s>" ENDL, first_line ? "To:" : "", passdata2, vmu->email); + } else { + fprintf(p, "To: %s <%s>" ENDL, quote(vmu->fullname, passdata2, len_passdata2), vmu->email); + } if (emailsubject) { struct ast_channel *ast; if ((ast = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, 0))) { - char *passdata; - int vmlen = strlen(emailsubject)*3 + 200; - if ((passdata = alloca(vmlen))) { - memset(passdata, 0, vmlen); - prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, cidnum, cidname, dur, date, passdata, vmlen, category); - pbx_substitute_variables_helper(ast, emailsubject, passdata, vmlen); - fprintf(p, "Subject: %s" ENDL, passdata); + int vmlen = strlen(emailsubject) * 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, cidnum, cidname, dur, date, passdata, len_passdata, category); + pbx_substitute_variables_helper(ast, emailsubject, passdata, len_passdata); + if (check_mime(passdata)) { + int first_line = 1; + char *ptr; + encode_mime_str(passdata, passdata2, len_passdata2, strlen("Subject: "), 0); + while ((ptr = strchr(passdata2, ' '))) { + *ptr = '\0'; + fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2); + first_line = 0; + passdata2 = ptr + 1; + } + fprintf(p, "%s %s" ENDL, first_line ? "Subject:" : "", passdata2); } else { - ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n"); + fprintf(p, "Subject: %s" ENDL, passdata); } ast_channel_free(ast); } else { |