message-header-decode.c revision d65a556a5ec078cd7f1d0060adb16fc860d66b27
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen#include "lib.h"
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen#include "base64.h"
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen#include "buffer.h"
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen#include "quoted-printable.h"
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen#include "message-header-decode.h"
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic bool split_encoded(const unsigned char *data, size_t *size_p,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const char **charset, const char **encoding,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const unsigned char **text, size_t *text_size_r)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen size_t size, pos, textpos;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen size = *size_p;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* get charset */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen for (pos = 0; pos < size && data[pos] != '?'; pos++) ;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (data[pos] != '?') return FALSE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen *charset = t_strndup(data, pos);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* get encoding */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen pos++;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (pos+2 >= size || data[pos+1] != '?')
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return FALSE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (data[pos] == 'Q' || data[pos] == 'q')
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen *encoding = "Q";
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen else if (data[pos] == 'B' || data[pos] == 'b')
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen *encoding = "B";
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen else
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return FALSE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* get text */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen pos += 2;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen textpos = pos;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen while (pos < size && data[pos] != '?') pos++;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (data[pos] != '?' || pos+1 >= size || data[pos+1] != '=')
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return FALSE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen *text = data + textpos;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen *text_size_r = pos - textpos;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen *size_p = pos+2;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return TRUE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenstatic bool
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenmessage_header_decode_encoded(const unsigned char *data, size_t *size,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen message_header_decode_callback_t *callback,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen void *context)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const unsigned char *text;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen const char *charset, *encoding;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen buffer_t *decodebuf;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen size_t text_size;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen int ret;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen t_push();
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* first split the string charset?encoding?text?= */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (!split_encoded(data, size, &charset, &encoding,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen &text, &text_size)) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen t_pop();
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return TRUE;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen decodebuf = buffer_create_static_hard(pool_datastack_create(),
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen text_size);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (*encoding == 'Q')
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen quoted_printable_decode(text, text_size, NULL, decodebuf);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen else {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (base64_decode(text, text_size, NULL, decodebuf) < 0) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* corrupted encoding */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen t_pop();
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return TRUE;
24acd68c82dc137b88bb3ba3258b9d1f7ebcb44dTimo Sirainen }
24acd68c82dc137b88bb3ba3258b9d1f7ebcb44dTimo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen ret = decodebuf->used == 0 ? FALSE :
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen callback(decodebuf->data, decodebuf->used, charset, context);
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen t_pop();
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return ret;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen}
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainenvoid message_header_decode(const unsigned char *data, size_t size,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen message_header_decode_callback_t *callback,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen void *context)
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen{
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen size_t pos, start_pos, subsize;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen start_pos = pos = 0;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen while (pos < size) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (data[pos] == '=' && pos+1 < size && data[pos+1] == '?') {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* encoded string beginning */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (pos != start_pos) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen /* send the unencoded data so far */
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (!callback(data + start_pos, pos - start_pos,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen NULL, context))
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen pos += 2;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen subsize = size - pos;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (!message_header_decode_encoded(data + pos, &subsize,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen callback, context))
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen return;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen pos += subsize;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen start_pos = pos;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen } else {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen pos++;
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen }
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen if (size > start_pos) {
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen (void)callback(data + start_pos, size - start_pos,
51cbc45fc1ac5dde29bc2adbb175945df1b4f7d4Timo Sirainen NULL, context);
24acd68c82dc137b88bb3ba3258b9d1f7ebcb44dTimo Sirainen }
24acd68c82dc137b88bb3ba3258b9d1f7ebcb44dTimo Sirainen}
24acd68c82dc137b88bb3ba3258b9d1f7ebcb44dTimo Sirainen