imap-parser.c revision 00395881d1dbbf37178d1efc193a7e9804aaff3b
/* Copyright (C) 2002 Timo Sirainen */
#include "lib.h"
#include "istream.h"
#include "ostream.h"
#include "strescape.h"
#include "imap-parser.h"
#define is_linebreak(c) \
((c) == '\r' || (c) == '\n')
#define LIST_INIT_COUNT 7
enum arg_parse_type {
ARG_PARSE_NONE = 0,
};
struct imap_parser {
/* permanent */
enum imap_parser_flags flags;
/* reset by imap_parser_reset(): */
enum arg_parse_type cur_type;
int str_first_escape; /* ARG_PARSE_STRING: index to first '\' */
const char *error;
unsigned int literal_skip_crlf:1;
unsigned int literal_nonsync:1;
unsigned int eol:1;
unsigned int fatal_error:1;
};
struct imap_parser *
{
struct imap_parser *parser;
return parser;
}
{
}
{
parser->str_first_escape = 0;
parser->literal_size = 0;
}
{
}
/* skip over everything parsed so far, plus the following whitespace */
const unsigned char **data,
{
size_t i;
if ((*data)[i] != ' ')
break;
}
*data += i;
*data_size -= i;
return *data_size > 0;
}
{
return arg;
}
{
}
{
/* we're not inside list */
return FALSE;
}
} else {
}
return TRUE;
}
{
char *str;
case ARG_PARSE_ATOM:
/* NIL argument */
} else {
/* simply save the string */
}
break;
case ARG_PARSE_STRING:
/* data is quoted and may contain escapes. */
/* remove the escapes */
if (parser->str_first_escape >= 0 &&
/* -1 because we skipped the '"' prefix */
}
break;
case ARG_PARSE_LITERAL_DATA:
/* save literal size */
IMAP_PARSE_FLAG_LITERAL_TYPE) != 0) {
} else {
}
break;
default:
i_unreached();
}
}
{
if (IS_ATOM_SPECIAL_INPUT((unsigned char)chr)) {
return FALSE;
} else if ((chr & 0x80) != 0) {
return FALSE;
}
return TRUE;
}
{
size_t i;
/* read until we've found space, CR or LF. */
is_linebreak(data[i])) {
break;
return FALSE;
}
}
{
size_t i;
/* read until we've found non-escaped ", CR or LF */
if (data[i] == '"') {
i++; /* skip the trailing '"' too */
break;
}
if (data[i] == '\\') {
if (i+1 == data_size) {
/* known data ends with '\' - leave it to
next time as well if it happens to be \" */
break;
}
/* save the first escaped char */
if (parser->str_first_escape < 0)
parser->str_first_escape = i;
/* skip the escaped char */
i++;
}
string always ends with '"', so it's an error if we found
a linebreak.. */
if (is_linebreak(data[i])) {
return FALSE;
}
}
}
{
/* too long string, abort. */
return FALSE;
}
}
}
return TRUE;
}
const unsigned char *data,
{
/* expecting digits + "}" */
if (data[i] == '}') {
return imap_parser_literal_end(parser);
}
if (parser->literal_nonsync) {
return FALSE;
}
if (data[i] == '+') {
continue;
}
return FALSE;
}
/* wrapped around, abort. */
return FALSE;
}
}
return FALSE;
}
const unsigned char *data,
{
if (parser->literal_skip_crlf) {
/* skip \r\n or \n, anything else gives an error */
if (data_size == 0)
return FALSE;
if (*data == '\r') {
if (data_size == 0)
return FALSE;
}
if (*data != '\n') {
return FALSE;
}
}
/* now we just wait until we've read enough data */
return FALSE;
else {
return TRUE;
}
} else {
/* we want to save only literal size, not the literal itself. */
return TRUE;
}
}
/* Returns TRUE if argument was fully processed. Also returns TRUE if
an argument inside a list was processed. */
{
const unsigned char *data;
if (data_size == 0)
return FALSE;
/* we haven't started parsing yet */
return FALSE;
switch (data[0]) {
case '\r':
case '\n':
/* unexpected end of line */
return FALSE;
case '"':
break;
case '{':
parser->literal_size = 0;
break;
case '(':
break;
case ')':
if (!imap_parser_close_list(parser))
return FALSE;
/* end of argument */
return TRUE;
}
break;
default:
return FALSE;
break;
}
}
case ARG_PARSE_ATOM:
return FALSE;
break;
case ARG_PARSE_STRING:
return FALSE;
break;
case ARG_PARSE_LITERAL:
return FALSE;
/* pass through to parsing data. since input->skip was
modified, we need to get the data start position again. */
/* fall through */
case ARG_PARSE_LITERAL_DATA:
return FALSE;
break;
default:
i_unreached();
}
return TRUE;
}
/* ARG_PARSE_NONE checks that last argument isn't only partially parsed. */
#define IS_UNFINISHED(parser) \
{
return -1;
}
/* fill the missing parameters with NILs */
}
return count;
}
enum imap_parser_flags flags,
{
if (!imap_parser_read_arg(parser))
break;
break;
}
}
/* error, abort */
return -1;
/* all arguments read / end of line. */
} else {
/* need more data */
return -2;
}
}
enum imap_parser_flags flags,
{
const unsigned char *data;
int ret;
if (ret == -2) {
/* we should have noticed end of everything except atom */
}
}
}
{
const unsigned char *data;
for (i = 0; i < data_size; i++) {
break;
}
if (i < data_size) {
} else {
return NULL;
}
}
{
case IMAP_ARG_NIL:
return "";
case IMAP_ARG_ATOM:
case IMAP_ARG_STRING:
case IMAP_ARG_LITERAL:
default:
return NULL;
}
}
{
#ifndef ATTRS_DEFINED
return NULL;
#endif
}
{
#ifndef ATTRS_DEFINED
return 0;
#endif
}
{
#ifndef ATTRS_DEFINED
return NULL;
#endif
}