diff --git a/src/low-level/mime/mailmime_decode.c b/src/low-level/mime/mailmime_decode.c index 80605e2..0c3ea6e 100644 --- a/src/low-level/mime/mailmime_decode.c +++ b/src/low-level/mime/mailmime_decode.c @@ -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. +}