#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "eps.h"
static int atom_begin(header_t *);
static atom_t *atom_new(header_t *);
static int atom_kill(atom_t *);
static header_t *header_alloc(void);
static atom_t *header_fetch_atoms(header_t *, unsigned char *);
static int header_parse_atom(header_t *, unsigned char *);
int atom_begin(header_t *h)
{
h->atoms = (atom_t *)malloc(sizeof(atom_t));
if (h->atoms == NULL)
return 0;
h->atoms->next = NULL;
h->atail = h->atoms;
return 1;
}
atom_t *atom_new(header_t *h)
{
atom_t *a = NULL;
a = (atom_t *)malloc(sizeof(atom_t));
if (a) {
memset((atom_t *)a, 0, sizeof(atom_t));
a->next = NULL;
h->atail->next = a;
h->atail = a;
}
return a;
}
int atom_kill(atom_t *al)
{
atom_t *a = NULL, *oa = NULL;
if (!al)
return 0;
a = al;
while(a->next) {
oa = a->next;
a->next = a->next->next;
if (oa->name)
free(oa->name);
if (oa->data)
free(oa->data);
free(oa);
}
free(al);
return 1;
}
header_t *header_alloc(void)
{
header_t *h = NULL;
h = (header_t *)malloc(sizeof(header_t));
if (h == NULL)
return NULL;
memset((header_t *)h, 0, sizeof(header_t));
return h;
}
header_t *header_parse(unsigned char *line)
{
header_t *hdr = NULL;
unsigned char *data = NULL, *nlc = NULL, *orig = NULL;
hdr = header_alloc();
if (hdr == NULL)
return NULL;
orig = mstrdup(line);
if (orig == NULL)
return hdr;
nlc = rfc2822_remove_comments(line);
if (nlc == NULL) {
free(orig);
return hdr;
}
/*
data = rfc2822_next_token(nlc, ':', " ");
RFC2822 says to allow for obsolete/bad syntax on header names,
which includes allowing for spaces in the header name.
*/
data = rfc2822_next_token(nlc, ':', NULL);
if (((!data) || (!(*data))) || ((data) && (*data == ' '))) {
free(orig);
free(nlc);
return hdr;
}
*data++ = '\0';
if ((!(*data)) || (!(*nlc))) {
free(orig);
free(nlc);
return hdr;
}
hdr->orig = orig;
hdr->name = mstrdup(nlc);
while(*data == ' ')
data++;
hdr->data = mstrdup(data);
hdr->atoms = header_fetch_atoms(hdr, data);
free(nlc);
return hdr;
}
/*
Return an atom linked list if the header
is structured. Otherwise, return NULL.
FORMAT: atom; atom_name=atom_data; etc
*/
atom_t *header_fetch_atoms(header_t *hh, unsigned char *data)
{
unsigned char *h = NULL, *t = NULL, *p = NULL;
if (!data)
return NULL;
else if (!(*data))
return NULL;
#ifdef DEBUG
printf("HEADER FETCH ATOMS: BEGIN\n<-- %s\n", data);
#endif
atom_begin(hh);
for (p = t = data; ((h = rfc2822_next_token(p, ';', NULL)) != NULL);) {
#ifdef DEBUG
printf("HEADER FETCH ATOMS: Looping on atom token\n");
#endif
if (*h) {
/*
Remove WSP after atom
*/
if (rfc2822_is_wsp(*(h - 1))) {
h--;
for (; rfc2822_is_wsp(*h); h--);
++h; *h = '\0';
}
*h++ = '\0';
p = h;
}
/*
Remove WSP at the end of the line
set h to NULL so we know we're done.
*/
else {
if (rfc2822_is_wsp(*(h - 1))) {
--h;
for (; rfc2822_is_wsp(*h); h--);
h++; *h = '\0';
}
h = NULL;
}
/*
Skip any WSP before atom
*/
for (; rfc2822_is_wsp(*t); t++);
if (*t)
header_parse_atom(hh, t);
#ifdef DEBUG
else
printf("HEADER FETCH ATOMS: Atom is blank\n");
#endif
if (!h)
break;
t = p;
}
return hh->atoms;
}
/*
Parse just one peice of atom data.
We are not handed the trailing semi-colons
FORMATS:
data
name = ["]data["]
Returns 1 on success, 0 on 'failure'
*/
int header_parse_atom(header_t *hh, unsigned char *data)
{
atom_t *a = NULL;
unsigned char *h = NULL, *t = NULL, *p = NULL;
if ((!data) || (!(*data)))
return 1;
#ifdef DEBUG
printf("HEADER PARSE ATOM: BEGIN\n<-- %s\n", data);
#endif
/*
What's the point in allocating before we
even know if we have data. Let's not
allocate space for empty atoms.
Not sure if this breaks RFCs or not :)
<vol@inter7.com>
a = atom_new();
*/
a = NULL;
h = t = data;
h = rfc2822_next_token(data, '=', NULL);
/*
No equal sign.
*/
if ((!h) || (!(*h))) {
#ifdef DEBUG
printf("HEADER PARSE ATOM: No variable definition; just data\n");
#endif
if (!(*data)) {
#ifdef DEBUG
printf("HEADER PARSE ATOM: Blank atom, no allocations made\n");
#endif
return 1;
}
p = rfc2822_convert_literals(data);
if (*p) {
a = atom_new(hh);
a->data = mstrdup(p);
}
#ifdef DEBUG
else
printf("HEADER PARSE ATOM: Blank atom, no allocations made\n");
#endif
free(p);
return 1;
}
/*
Remove WSP after atom name
*/
if (rfc2822_is_wsp(*(h - 1))) {
p = (h - 1);
while(rfc2822_is_wsp(*(p - 1)))
p--;
*p = '\0';
}
*h++ = '\0';
/*
Remove WSP from before atom data
*/
if (rfc2822_is_wsp(*h))
h++;
if (!(*t)) {
#ifdef DEBUG
printf("HEADER PARSE ATOM: Blank atom, no allocations made\n");
#endif
return 1;
}
p = rfc2822_convert_literals(t);
if (*p) {
a = atom_new(hh);
a->name = mstrdup(p);
free(p);
p = rfc2822_convert_literals(h);
if (!(*p)) {
#ifdef DEBUG
printf("HEADER PARSE ATOM: Blank atom, no allocations made\n");
#endif
free(p);
return 1;
}
a->data = mstrdup(p);
free(p);
}
else {
#ifdef DEBUG
printf("HEADER PARSE ATOM: Blank atom, no allocations made\n");
#endif
free(p);
return 1;
}
#ifdef DEBUG
if (a) {
printf("HEADER PARSE ATOM: New atom\n");
if (a->name)
printf(" %s=%s\n", a->name, a->data);
else
printf(" %s\n", a->data);
}
else
printf("HEADER PARSE ATOM: Blank atom, no allocations made\n");
#endif
return 1;
}
void header_kill(header_t *h)
{
if (!h)
return;
if (h->name)
free(h->name);
if (h->data)
free(h->data);
if (h->orig)
free(h->orig);
if (h->atoms)
atom_kill(h->atoms);
free(h);
}
#ifdef HEADER_DEBUG
/*
Debugging. Show header data.
*/
void header_show(header_t *h)
{
atom_t *a = NULL;
if (!h)
return;
if ((h->name == NULL) || (h->data == NULL))
return;
printf("HEADER:\n" \
" Name: [%s]\n" \
" Original data: [%s]\n",
h->name, h->data);
if (h->atoms) {
printf(" ATOMS:\n");
for (a = h->atoms; a->next; a = a->next) {
if (a->next->name)
printf(" [%s] = [%s]\n", a->next->name, a->next->data);
else
printf(" [%s]\n", a->next->data);
}
}
}
#endif
/*
Return an atom's data by atom name from
a header structure
*/
unsigned char *header_fetch_atom(header_t *h, unsigned char *name)
{
atom_t *a = NULL;
if (!(h->atoms))
return NULL;
for (a = h->atoms; a->next; a = a->next) {
if (a->next->name) {
if (!(strcasecmp(a->next->name, name)))
return a->next->data;
}
}
return NULL;
}
syntax highlighted by Code2HTML, v. 0.9.1