#include #include #include #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 :) 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; }