/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "hex-binary.h"
#include "qp-decoder.h"
/* quoted-printable lines can be max 76 characters. if we've seen more than
that much whitespace, it means there really shouldn't be anything else left
in the line except trailing whitespace. */
#define QP_IS_TRAILING_WHITESPACE(c) \
((c) == ' ' || (c) == '\t')
enum qp_state {
STATE_TEXT = 0,
};
struct qp_decoder {
char hexchar;
};
{
return qp;
}
{
}
static size_t
{
for (i = 0; i < src_size; i++) {
if (src[i] > '=') {
/* fast path */
continue;
}
switch (src[i]) {
case '=':
break;
case '\r':
break;
case '\n':
/* LF without preceding CR */
start = i+1;
continue;
case ' ':
case '\t':
break;
default:
continue;
}
ret = i+1;
break;
}
return ret;
}
{
case STATE_EQUALS:
*error_r = "'=' not followed by two hex digits";
break;
case STATE_HEX2:
*error_r = "'=<hex>' not followed by a hex digit";
break;
case STATE_EQUALS_WHITESPACE:
*error_r = "'=<whitespace>' not followed by newline";
break;
case STATE_CR:
*error_r = "CR not followed by LF";
break;
case STATE_SOFTCR:
*error_r = "CR not followed by LF";
break;
case STATE_TEXT:
case STATE_WHITESPACE:
i_unreached();
}
}
const char **error_r)
{
const char *error;
size_t i;
for (i = 0; i < src_size; ) {
case STATE_TEXT:
/* don't increment i any more than we already did,
so continue instead of break */
continue;
case STATE_WHITESPACE:
if (QP_IS_TRAILING_WHITESPACE(src[i])) {
/* more whitespace */
} else if (src[i] == '\r') {
} else if (src[i] == '\n') {
/* drop the trailing whitespace */
} else {
/* this wasn't trailing whitespace.
put it back. */
0, (size_t)-1);
/* we already truncated some of the
whitespace away, because the line
is too long */
*invalid_src_pos_r = i;
*error_r = "Too much whitespace";
}
}
continue; /* don't increment i */
}
break;
case STATE_EQUALS:
/* lowercase hex isn't strictly valid, but allow */
} else if (QP_IS_TRAILING_WHITESPACE(src[i])) {
} else if (src[i] == '\r')
else if (src[i] == '\n') {
} else {
/* invalid input */
*invalid_src_pos_r = i;
}
continue; /* don't increment i */
}
break;
case STATE_HEX2:
i_unreached();
} else {
/* invalid input */
*invalid_src_pos_r = i;
}
continue; /* don't increment i */
}
break;
case STATE_EQUALS_WHITESPACE:
if (QP_IS_TRAILING_WHITESPACE(src[i])) {
else {
/* if this isn't going to get truncated
anyway, it's going to be an error */
}
} else if (src[i] == '\r')
else if (src[i] == '\n') {
} else {
/* =<whitespace> not followed by [CR]LF
is invalid. */
*invalid_src_pos_r = i;
}
continue; /* don't increment i */
}
break;
case STATE_CR:
case STATE_SOFTCR:
if (src[i] == '\n') {
} else {
*invalid_src_pos_r = i;
}
continue; /* don't increment i */
}
break;
}
i++;
}
}
{
int ret;
ret = 0;
} else {
ret = -1;
}
return ret;
}