imap-parser.c revision 69c0e4402662eb420853c11b8c27223a0bb8f0db
/* Copyright (C) 2002 Timo Sirainen */
#include "lib.h"
#include "iobuffer.h"
#include "imap-parser.h"
#define is_linebreak(c) \
((c) == '\r' || (c) == '\n')
typedef enum {
ARG_PARSE_NONE = 0,
} ArgParseType;
struct _ImapParser {
unsigned int pos;
int str_first_escape; /* ARG_PARSE_STRING: index to first '\' */
unsigned int literal_skip_crlf:1;
unsigned int inside_bracket:1;
unsigned int eol:1;
unsigned int error:1;
};
{
return parser;
}
{
}
{
}
{
size_t i;
if ((*data)[i] != ' ')
break;
}
*data += i;
*data_size -= i;
return *data_size > 0;
}
{
/* create new argument into list */
}
{
}
{
ImapArgList **list;
/* we're not inside list */
return FALSE;
}
/* end of argument */
return TRUE;
}
/* skip to end of the upper list */
return TRUE;
}
{
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:
/* simply save the string */
} else {
/* save literal size */
}
break;
default:
i_assert(0);
}
}
{
size_t i;
/* read until we've found space, CR or LF. Data inside '[' and ']'
characters are an exception though, allow spaces inside them. */
if (parser->inside_bracket) {
/* a) nested '[' characters not allowed
(too much trouble and imap doesn't need)
b) missing ']' character */
return FALSE;
}
if (data[i] == ']') {
}
} else {
if (data[i] == '[')
is_linebreak(data[i])) {
break;
}
}
}
return TRUE;
}
{
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;
}
}
return TRUE;
}
{
/* too long string, abort. */
return FALSE;
}
}
return TRUE;
}
{
/* expecting digits + "}" */
if (data[i] == '}') {
if (!imap_parser_literal_end(parser))
return FALSE;
break;
}
return FALSE;
/* wrapped around, abort. */
return FALSE;
}
}
return TRUE;
}
{
if (parser->literal_skip_crlf) {
/* skip \r\n or \n, anything else gives an error */
if (*data == '\r') {
if (data_size == 1)
return TRUE;
}
if (*data != '\n')
return FALSE;
}
/* now we just wait until we've read enough data */
}
} 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. */
{
char *data;
if (data_size == 0)
return FALSE;
/* beginning to parse a new argument */
}
/* 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:
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 inbuf->skip was
modified, we need to get the data start position again. */
case ARG_PARSE_LITERAL_DATA:
break;
default:
i_assert(0);
}
/* NOTE: data and data_size are invalid here, the functions above
may have changed them. */
}
{
unsigned int args_size;
args_size = 0;
}
break;
/* jump to next argument, unless we're processing a list */
}
/* all arguments read / end of line */
/* error, abort */
return -1;
} else {
/* need more data */
return -2;
}
}
{
char *data;
/* get the beginning of data in input buffer */
for (i = 0; i < data_size; i++) {
break;
}
if (i < data_size) {
} else {
return NULL;
}
}
{
char *data;
/* get the beginning of data in input buffer */
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:
default:
return NULL;
}
}