/*
* ImapProxy - a caching IMAP proxy daemon
* Copyright (C) 2002 Steven Van Acker
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
*/
#include <stdio.h>
#include <stdlib.h>
#define _GNU_SOURCE
#include <string.h>
#include <parsed_message.h>
#include <misc.h>
#include <output.h>
int init_parsed_message(Parsed_message *pm)
{
memset(pm,0,sizeof(Parsed_message));
return 0;
}
#define PARSE_MESSAGE_MODE_NONE 0
#define PARSE_MESSAGE_MODE_NORMAL 1
#define PARSE_MESSAGE_MODE_QUOTED 2
#define PARSE_MESSAGE_MODE_LITERAL 3
int make_parsed_message(struct message_t *m,Parsed_message *pm)
{
int mode = 0;
char *p,*q,*s, buffer[1024];
int end;
int tmpi;
int currindex = 0;
if(m->count < 1)
/* empty message ? */
return -1;
p = m->lines[currindex];
q = p;
mode = PARSE_MESSAGE_MODE_NONE;
while(p && *p)
{
switch(mode)
{
case PARSE_MESSAGE_MODE_NONE:
/* if we don't know what to do, start cleaning up the spaces */
while(*p == ' ')
p++;
/* the new string will start here */
q = p;
switch(*p)
{
case '\r':
case '\n':
p++;
case '\0':
/* reached end of string ! end loop */
break;
case '"':
mode = PARSE_MESSAGE_MODE_QUOTED;
break;
case '{':
mode = PARSE_MESSAGE_MODE_LITERAL;
break;
default:
mode = PARSE_MESSAGE_MODE_NORMAL;
break;
}
break;
case PARSE_MESSAGE_MODE_NORMAL:
/* in normal mode, we look for spaces. */
if(!(p = strchr(p,' ')))
{
/* let p point to end of string otherwise */
p = q + strlen(q);
/* string should end with \r\n, but lets not take risks */
if(strlen(q) > 2 && *(p-1) == '\n' && *(p-2) == '\r') p-=2;
}
/* add this argument to the list and mark it as normal ! */
if(parsed_message_add_arg(pm,q,p,PARSED_MESSAGE_NORMAL_STRING) < 0)
{
debug("make_parsed_message(): Adding argument failed.\n");
return -1;
}
mode = PARSE_MESSAGE_MODE_NONE;
break;
case PARSE_MESSAGE_MODE_QUOTED:
end = 0;
/* skip the first " */
p++;
while(*p && !end)
{
switch(*p)
{
case '\\':
/* skip all quoted stuff */
p+=2;
break;
case '"':
/* aha, the end of our misery */
p++;
end = 1;
break;
default:
p++;
break;
}
}
if(!end) /* abnormal end */
{
debug("make_parsed_message(): received a quoted string that was not terminated !\n");
return -1;
}
/* unquote the argument ! */
if(!(s = my_strndup(q,(int)(p-q))))
{
debug("make_parsed_message(): Out of memory ?\n");
return -1;
}
if(string_unquote(s,buffer,sizeof(buffer)))
{
debug("make_parsed_message(): Unquoting failed\n");
return -1;
}
/* add this argument to the list and mark it as quoted. */
if(parsed_message_add_arg(pm,buffer,buffer + strlen(buffer),PARSED_MESSAGE_QUOTED_STRING) < 0)
{
debug("make_parsed_message(): Adding argument failed.\n");
return -1;
}
/* and clean up */
free(s);
mode = PARSE_MESSAGE_MODE_NONE;
break;
case PARSE_MESSAGE_MODE_LITERAL:
if((tmpi = check_for_literal_count(p)) < 0)
{
debug("make_parsed_message(): a sneaky attempt at a literal. handling it as being a regular string !\n");
mode = PARSE_MESSAGE_MODE_NORMAL;
}
else
{
/* read tmpi chars from the next line, if there are so many
* add them to the list as a literal.
*/
currindex++;
if(currindex >= m->count)
{
debug("make_parsed_message(): a literal was found, but there is no more data !!\n");
return -1;
}
q = m->lines[currindex];
p = q + tmpi;
if(parsed_message_add_arg(pm,q,p,PARSED_MESSAGE_LITERAL_STRING) < 0)
{
debug("make_parsed_message(): Adding argument failed.\n");
return -1;
}
mode = PARSE_MESSAGE_MODE_NONE;
}
break;
default:
debug("huh ?\n");
break;
}
}
return -1;
}
int delete_parsed_message(Parsed_message *pm)
{
int i;
for(i = 0;i < pm->numargs; i++)
{
free(pm->args[i]);
}
if(pm->numargs)
free(pm->args);
if(pm->argsdesc)
free(pm->argsdesc);
init_parsed_message(pm);
return 0;
}
int parsed_message_count_args(Parsed_message *pm)
{
return pm->numargs;
}
char *parsed_message_get_idtag(Parsed_message *pm)
{
if(pm->numargs > 0)
return pm->args[0];
else
return NULL;
}
char *parsed_message_get_command(Parsed_message *pm)
{
if(pm->numargs > 1)
return pm->args[1];
else
return NULL;
}
char *parsed_message_get_arg(Parsed_message *pm,int i)
{
if(i < 2 || i > pm->numargs)
return NULL;
return pm->args[i];
}
/* this function quotes a string
* out_len represents the length of the output buffer
*/
int string_quote(char *in, char *out, int out_len)
{
int i = 0;
int o = 0;
int in_len = strlen(in) + 1;
out[o++] = '"';
while(i < in_len && o < out_len - 2)
{
switch(in[i])
{
case '\\':
out[o++] = '\\';
out[o++] = '\\';
i++;
break;
case '"':
out[o++] = '\\';
out[o++] = '"';
i++;
break;
default:
out[o++] = in[i++];
break;
}
}
if(i != in_len)
{
/* didn't get to end of the input string, which means the output buffer is too small */
return -1;
}
out[o++] = '"';
out[o] = '\0';
return 0;
}
/* this function unquotes a quoted string.
* out_len represents the length of the output buffer
*/
int string_unquote(char *in, char *out, int out_len)
{
/* start after the first " */
int i = 1;
int o = 0;
/* we don't want the last " */
int in_len = strlen(in) - 1;
if(in[0] != '"' || in[strlen(in) - 1] != '"')
{
debug("string_unquote(): This does not look like a quoted string !\n");
}
else
{
}
while(i < in_len && o < out_len - 1)
{
switch(in[i])
{
case '\\':
i++;
default:
out[o++] = in[i++];
break;
}
}
if(i != in_len)
{
/* didn't get to end of the input string, which means the output buffer is too small */
return -1;
}
out[o] = '\0';
return 0;
}
/* end needs to point to char after the char you want last */
int parsed_message_add_arg(Parsed_message *pm, char *start, char *end,int type)
{
int n = 0;
char *p = NULL;
pm->numargs++;
/* allocating space for the pointer to the argument */
if(!(pm->args = realloc(pm->args,pm->numargs * sizeof(char *))))
{
debug("parsed_message_add_arg(): Out of memory !\n");
return -1;
}
/* space for the type */
if(!(pm->argsdesc = realloc(pm->argsdesc,pm->numargs * sizeof(int))))
{
debug("parsed_message_add_arg(): Out of memory (%d)!\n",pm->numargs * sizeof(int));
return -1;
}
n = (int)(end - start) + 1;
/* space for the argument */
if(!(p = (char *)malloc(n)))
{
debug("parsed_message_add_arg(): Out of memory (%d)!\n",n);
return -1;
}
/* copying the argument */
strncpy(p,start,n - 1);
p[n - 1] = 0;
pm->args[pm->numargs - 1] = p;
pm->argsdesc[pm->numargs - 1] = type;
return 0;
}
void print_parsed_message(Parsed_message *pm)
{
int i;
char *desc;
for(i = 0;i < pm->numargs;i++)
{
switch(pm->argsdesc[i])
{
case PARSED_MESSAGE_NORMAL_STRING:
desc = "PARSED_MESSAGE_NORMAL_STRING";
break;
case PARSED_MESSAGE_QUOTED_STRING:
desc = "PARSED_MESSAGE_QUOTED_STRING";
break;
case PARSED_MESSAGE_LITERAL_STRING:
desc = "PARSED_MESSAGE_LITERAL_STRING";
break;
default:
desc = "UNKNOWN_TYPE";
break;
}
debug("Parsed message argument[%d] (%s) = \"%s\"\n",i,desc,pm->args[i]);
}
}
syntax highlighted by Code2HTML, v. 0.9.1