quoted-printable.c revision 1a1fcdbe27a8cee9a4c453a6b2f625a5be572a32
02c335c23bf5fa225a467c19f2c063fb0dc7b8c3Timo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "lib.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "buffer.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "hex-binary.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen#include "quoted-printable.h"
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen#define QP_IS_TRAILING_SPACE(c) \
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen ((c) == ' ' || (c) == '\t')
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenvoid quoted_printable_decode(const unsigned char *src, size_t src_size,
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen size_t *src_pos_r, buffer_t *dest)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen char hexbuf[3];
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen size_t src_pos, pos, next;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen hexbuf[2] = '\0';
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen next = 0;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen for (src_pos = 0; src_pos < src_size; src_pos++) {
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen if (src[src_pos] != '=' && src[src_pos] != '\n')
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen continue;
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if (src[src_pos] == '\n') {
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen /* drop trailing whitespace */
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen pos = src_pos;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (pos > 0 && src[pos-1] == '\r')
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen pos--;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen while (pos > 0 && QP_IS_TRAILING_SPACE(src[pos-1]))
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen pos--;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen buffer_append(dest, src + next, pos - next);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen next = src_pos+1;
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen buffer_append(dest, "\r\n", 2);
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen continue;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen }
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen /* '=' */
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen buffer_append(dest, src + next, src_pos - next);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen next = src_pos;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (src_pos+1 >= src_size)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen break;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (src[src_pos+1] == '\n') {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen /* =\n -> skip both */
2f4f603d4cebab2cc956c72164efb02da83515c5Timo Sirainen src_pos += 2;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen next += 2;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen continue;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen }
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (src_pos+2 >= src_size)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen break;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (src[src_pos+1] == '\r' && src[src_pos+2] == '\n') {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen /* =\r\n -> skip both */
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen src_pos += 3;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen next += 3;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen continue;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen }
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen /* =<hex> */
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen hexbuf[0] = src[src_pos+1];
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen hexbuf[1] = src[src_pos+2];
46b823ac3bce2c0f9f0fc73911e48d3a77b04fbeTimo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (hex_to_binary(hexbuf, dest) == 0) {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen src_pos += 2;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen next = src_pos + 1;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen } else {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen /* non-hex data, show as-is */
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen next = src_pos;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen }
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen }
e245fb1302121d2bc2580f61e040c2c8a558ee9eTimo Sirainen if (src_pos == src_size) {
e245fb1302121d2bc2580f61e040c2c8a558ee9eTimo Sirainen /* add everything but trailing spaces */
e245fb1302121d2bc2580f61e040c2c8a558ee9eTimo Sirainen if (src_pos > 0 && src[src_pos-1] == '\r')
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen src_pos--;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen while (src_pos > 0 && QP_IS_TRAILING_SPACE(src[src_pos-1]))
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen src_pos--;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen buffer_append(dest, src + next, src_pos - next);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen next = src_pos;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen }
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen *src_pos_r = next;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainenvoid quoted_printable_q_decode(const unsigned char *src, size_t src_size,
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen buffer_t *dest)
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen{
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen char hexbuf[3];
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen size_t src_pos, next;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen hexbuf[2] = '\0';
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen next = 0;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen for (src_pos = 0; src_pos < src_size; src_pos++) {
d5e839aea288aceaddae28a1578cebda3c9e3b58Timo Sirainen if (src[src_pos] != '_' && src[src_pos] != '=')
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen continue;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen buffer_append(dest, src + next, src_pos - next);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen next = src_pos;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (src[src_pos] == '_') {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen buffer_append_c(dest, ' ');
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen next++;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen continue;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen }
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen if (src_pos+2 >= src_size)
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen break;
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen /* =<hex> */
25ec868bd8b5375e1c1c4c3331d761667ddfe26cTimo Sirainen hexbuf[0] = src[src_pos+1];
baf346e71ebd7b44fcba4b48f4d39845453b778bTimo Sirainen hexbuf[1] = src[src_pos+2];
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen if (hex_to_binary(hexbuf, dest) == 0) {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen src_pos += 2;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen next = src_pos+1;
8a8a3b43987b5ade914f22765e51c9e3de8179d3Timo Sirainen } else {
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen /* non-hex data, show as-is */
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen next = src_pos;
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen }
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen }
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen buffer_append(dest, src + next, src_size - next);
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen}
cf636afb3826f0d8e15c248aa1fc04ce72820e08Timo Sirainen