|
|
|
@ -71,6 +71,9 @@
|
|
|
|
|
static int mailmime_charset_parse(const char * message, size_t length,
|
|
|
|
|
size_t * indx, char ** charset);
|
|
|
|
|
|
|
|
|
|
static int detect_CRCR(const char * message, size_t length,
|
|
|
|
|
size_t * indx);
|
|
|
|
|
|
|
|
|
|
enum {
|
|
|
|
|
MAILMIME_ENCODING_B,
|
|
|
|
|
MAILMIME_ENCODING_Q
|
|
|
|
@ -124,12 +127,16 @@ int mailmime_encoded_phrase_parse(const char * default_fromcode,
|
|
|
|
|
|
|
|
|
|
type = TYPE_ERROR; /* XXX - removes a gcc warning */
|
|
|
|
|
|
|
|
|
|
// Start parsing
|
|
|
|
|
while (1) {
|
|
|
|
|
int has_fwd;
|
|
|
|
|
|
|
|
|
|
word = NULL;
|
|
|
|
|
|
|
|
|
|
// Try to parse this part of the message as mime-encoded
|
|
|
|
|
r = mailmime_encoded_word_parse(message, length, &cur_token, &word, &has_fwd, &missing_closing_quote);
|
|
|
|
|
if (r == MAILIMF_NO_ERROR) {
|
|
|
|
|
// Either it was mime-encoded or there was no error.
|
|
|
|
|
if ((!first) && has_fwd) {
|
|
|
|
|
if (type != TYPE_ENCODED_WORD) {
|
|
|
|
|
if (mmap_string_append_c(gphrase, ' ') == NULL) {
|
|
|
|
@ -171,6 +178,7 @@ int mailmime_encoded_phrase_parse(const char * default_fromcode,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (wordutf8 != NULL) {
|
|
|
|
|
// append the word (converted to the proper charset)
|
|
|
|
|
if (mmap_string_append(gphrase, wordutf8) == NULL) {
|
|
|
|
|
mailmime_encoded_word_free(word);
|
|
|
|
|
free(wordutf8);
|
|
|
|
@ -183,17 +191,38 @@ int mailmime_encoded_phrase_parse(const char * default_fromcode,
|
|
|
|
|
first = FALSE;
|
|
|
|
|
}
|
|
|
|
|
else if (r == MAILIMF_ERROR_PARSE) {
|
|
|
|
|
// Wasn't mime-encoded
|
|
|
|
|
/* do nothing */
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Some error condition we didn't expect
|
|
|
|
|
res = r;
|
|
|
|
|
goto free;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r == MAILIMF_ERROR_PARSE) {
|
|
|
|
|
// Not mime-encoded, so parse as if it isn't
|
|
|
|
|
char * raw_word;
|
|
|
|
|
|
|
|
|
|
raw_word = NULL;
|
|
|
|
|
|
|
|
|
|
// Check for special case of word=^CRCR.
|
|
|
|
|
// We need to be sure we advanced the cur_token
|
|
|
|
|
// past it. Usually with an empty string.
|
|
|
|
|
if (first) {
|
|
|
|
|
r = detect_CRCR(message, length, &cur_token);
|
|
|
|
|
if (r == MAILIMF_NO_ERROR) {
|
|
|
|
|
// We've advanced the token and pretend
|
|
|
|
|
// the first CR isn't there. Let the algorithm
|
|
|
|
|
// take care of the legit CRLF.
|
|
|
|
|
if (mmap_string_append_c(gphrase, ' ') == NULL) {
|
|
|
|
|
res = MAILIMF_ERROR_MEMORY;
|
|
|
|
|
goto free;
|
|
|
|
|
}
|
|
|
|
|
first = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
r = mailmime_non_encoded_word_parse(message, length,
|
|
|
|
|
&cur_token, &raw_word, &has_fwd);
|
|
|
|
|
if (r == MAILIMF_NO_ERROR) {
|
|
|
|
@ -296,17 +325,21 @@ mailmime_non_encoded_word_parse(const char * message, size_t length,
|
|
|
|
|
cur_token = * indx;
|
|
|
|
|
|
|
|
|
|
has_fwd = 0;
|
|
|
|
|
|
|
|
|
|
// Check to see if it starts with folding whitespace
|
|
|
|
|
r = mailimf_fws_parse(message, length, &cur_token);
|
|
|
|
|
if (r == MAILIMF_NO_ERROR) {
|
|
|
|
|
if (r == MAILIMF_NO_ERROR) { // it does
|
|
|
|
|
has_fwd = 1;
|
|
|
|
|
}
|
|
|
|
|
if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
|
|
|
|
|
// legit error
|
|
|
|
|
res = r;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
begin = cur_token;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Get the word up to the next =? or whitespace
|
|
|
|
|
state = 0;
|
|
|
|
|
end = FALSE;
|
|
|
|
|
while (1) {
|
|
|
|
@ -325,7 +358,7 @@ mailmime_non_encoded_word_parse(const char * message, size_t length,
|
|
|
|
|
state = 1;
|
|
|
|
|
break;
|
|
|
|
|
case '?':
|
|
|
|
|
if (state == 1) {
|
|
|
|
|
if (state == 1) { // begin of mime-encoding?
|
|
|
|
|
cur_token --;
|
|
|
|
|
end = TRUE;
|
|
|
|
|
}
|
|
|
|
@ -340,7 +373,7 @@ mailmime_non_encoded_word_parse(const char * message, size_t length,
|
|
|
|
|
cur_token ++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (cur_token - begin == 0) {
|
|
|
|
|
if (cur_token - begin == 0) { // we processed nothing, bail
|
|
|
|
|
res = MAILIMF_ERROR_PARSE;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
@ -389,14 +422,15 @@ int mailmime_encoded_word_parse(const char * message, size_t length,
|
|
|
|
|
missing_closing_quote = 0;
|
|
|
|
|
has_fwd = 0;
|
|
|
|
|
r = mailimf_fws_parse(message, length, &cur_token);
|
|
|
|
|
if (r == MAILIMF_NO_ERROR) {
|
|
|
|
|
if (r == MAILIMF_NO_ERROR) { // there was folding whitespace, now consumed
|
|
|
|
|
has_fwd = 1;
|
|
|
|
|
}
|
|
|
|
|
if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) {
|
|
|
|
|
if ((r != MAILIMF_NO_ERROR) && (r != MAILIMF_ERROR_PARSE)) { // actual error
|
|
|
|
|
res = r;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// check for opening quote, consume if so
|
|
|
|
|
opening_quote = FALSE;
|
|
|
|
|
r = mailimf_char_parse(message, length, &cur_token, '\"');
|
|
|
|
|
if (r == MAILIMF_NO_ERROR) {
|
|
|
|
@ -410,42 +444,50 @@ int mailmime_encoded_word_parse(const char * message, size_t length,
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Check for MIME encoded-word syntax
|
|
|
|
|
// =?charset?encoding?encoded text?=
|
|
|
|
|
r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "=?");
|
|
|
|
|
if (r != MAILIMF_NO_ERROR) {
|
|
|
|
|
res = r;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get charset
|
|
|
|
|
r = mailmime_charset_parse(message, length, &cur_token, &charset);
|
|
|
|
|
if (r != MAILIMF_NO_ERROR) {
|
|
|
|
|
res = r;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// charset terminator
|
|
|
|
|
r = mailimf_char_parse(message, length, &cur_token, '?');
|
|
|
|
|
if (r != MAILIMF_NO_ERROR) {
|
|
|
|
|
res = r;
|
|
|
|
|
goto free_charset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get encoding
|
|
|
|
|
r = mailmime_encoding_parse(message, length, &cur_token, &encoding);
|
|
|
|
|
if (r != MAILIMF_NO_ERROR) {
|
|
|
|
|
res = r;
|
|
|
|
|
goto free_charset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// encoding terminator
|
|
|
|
|
r = mailimf_char_parse(message, length, &cur_token, '?');
|
|
|
|
|
if (r != MAILIMF_NO_ERROR) {
|
|
|
|
|
res = r;
|
|
|
|
|
goto free_charset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// get encoded text
|
|
|
|
|
end = FALSE;
|
|
|
|
|
end_encoding = cur_token;
|
|
|
|
|
while (1) {
|
|
|
|
|
if (end_encoding >= length)
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
// are we done?
|
|
|
|
|
if (end_encoding + 1 < length) {
|
|
|
|
|
if ((message[end_encoding] == '?') && (message[end_encoding + 1] == '=')) {
|
|
|
|
|
end = TRUE;
|
|
|
|
@ -458,44 +500,49 @@ int mailmime_encoded_word_parse(const char * message, size_t length,
|
|
|
|
|
end_encoding ++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// decode text
|
|
|
|
|
decoded_len = 0;
|
|
|
|
|
decoded = NULL;
|
|
|
|
|
switch (encoding) {
|
|
|
|
|
case MAILMIME_ENCODING_B:
|
|
|
|
|
r = mailmime_base64_body_parse(message, end_encoding,
|
|
|
|
|
&cur_token, &decoded,
|
|
|
|
|
&decoded_len);
|
|
|
|
|
|
|
|
|
|
if (r != MAILIMF_NO_ERROR) {
|
|
|
|
|
res = r;
|
|
|
|
|
goto free_charset;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case MAILMIME_ENCODING_Q:
|
|
|
|
|
r = mailmime_quoted_printable_body_parse(message, end_encoding,
|
|
|
|
|
&cur_token, &decoded,
|
|
|
|
|
&decoded_len, TRUE);
|
|
|
|
|
|
|
|
|
|
if (r != MAILIMF_NO_ERROR) {
|
|
|
|
|
res = r;
|
|
|
|
|
goto free_charset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
case MAILMIME_ENCODING_B:
|
|
|
|
|
r = mailmime_base64_body_parse(message, end_encoding,
|
|
|
|
|
&cur_token, &decoded,
|
|
|
|
|
&decoded_len);
|
|
|
|
|
|
|
|
|
|
if (r != MAILIMF_NO_ERROR) {
|
|
|
|
|
res = r;
|
|
|
|
|
goto free_charset;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case MAILMIME_ENCODING_Q:
|
|
|
|
|
r = mailmime_quoted_printable_body_parse(message, end_encoding,
|
|
|
|
|
&cur_token, &decoded,
|
|
|
|
|
&decoded_len, TRUE);
|
|
|
|
|
|
|
|
|
|
if (r != MAILIMF_NO_ERROR) {
|
|
|
|
|
res = r;
|
|
|
|
|
goto free_charset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
text = malloc(decoded_len + 1);
|
|
|
|
|
if (text == NULL) {
|
|
|
|
|
res = MAILIMF_ERROR_MEMORY;
|
|
|
|
|
goto free_charset;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copy decoded text
|
|
|
|
|
if (decoded_len > 0)
|
|
|
|
|
memcpy(text, decoded, decoded_len);
|
|
|
|
|
text[decoded_len] = '\0';
|
|
|
|
|
|
|
|
|
|
mailmime_decoded_part_free(decoded);
|
|
|
|
|
|
|
|
|
|
// Detect if we stopped parsing the *encoded* text (before we sent it off to
|
|
|
|
|
// be decoded because we hit the terminator, or because we hit the end
|
|
|
|
|
// of the specified length
|
|
|
|
|
r = mailimf_token_case_insensitive_parse(message, length, &cur_token, "?=");
|
|
|
|
|
#if 0
|
|
|
|
|
if (r != MAILIMF_NO_ERROR) {
|
|
|
|
@ -618,3 +665,20 @@ static int mailmime_etoken_parse(const char * message, size_t length,
|
|
|
|
|
indx, result,
|
|
|
|
|
is_etoken_char);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int detect_CRCR(const char * message, size_t length,
|
|
|
|
|
size_t * indx) {
|
|
|
|
|
size_t cur_token = *indx;
|
|
|
|
|
int r = mailimf_char_parse(message, length, &cur_token, '\r');
|
|
|
|
|
if (r == MAILIMF_NO_ERROR) {
|
|
|
|
|
r = mailimf_char_parse(message, length, &cur_token, '\r');
|
|
|
|
|
if (r == MAILIMF_NO_ERROR) {
|
|
|
|
|
// Yup, there was a CRCR here.
|
|
|
|
|
// Advance token past the first \r
|
|
|
|
|
*indx = (*indx) + 1;
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Leave indx alone and move on.
|
|
|
|
|
return MAILIMF_ERROR_PARSE; // not actual error. Usual behaviour.
|
|
|
|
|
}
|
|
|
|
|