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