Commit 985d3a58 985d3a580a54ded105a5616ae7ce206ef846fd37 by Alain Magloire

header.c header0.h rfc822.c

collpase everything in header.c
1 parent 920daf3b
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Library Public License as published by
the Free Software Foundation; either version 2, 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 Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <header0.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
int
header_init (header_t *ph, const char *blurb, size_t len,
int flag, void *owner)
{
if (flag != MU_HEADER_RFC822)
return ENOTSUP;
return rfc822_init (ph, blurb, len, owner);
}
void
header_destroy (header_t *ph, void *owner)
{
if (ph && *ph)
(*ph)->_destroy (ph, owner);
}
/* stub functions */
int
header_set_value (header_t h, const char *fn, const char *fb, size_t n,
int replace)
{
if (h == NULL || h->_set_value == NULL)
return EINVAL;
return h->_set_value (h, fn, fb, n, replace);
}
int
header_get_value (header_t h, const char *fn, char *fb,
size_t len, size_t *n)
{
if (h == NULL || h->_get_value == NULL )
return EINVAL;
return h->_get_value (h, fn, fb, len, n);
}
int
header_entry_name (header_t h, size_t num, char *buf, size_t len, size_t *n)
{
if (h == NULL || h->_entry_name == NULL)
return EINVAL;
return h->_entry_name (h, num, buf, len, n);
}
int
header_entry_value (header_t h, size_t num, char *buf, size_t len, size_t *n)
{
if (h == NULL || h->_entry_value == NULL)
return EINVAL;
return h->_entry_value (h, num, buf, len, n);
}
int
header_entry_count (header_t h, size_t *num)
{
if (h == NULL || h->_entry_count)
return EINVAL;
return h->_entry_count (h, num);
}
int
header_get_istream (header_t h, istream_t *pis)
{
if (h == NULL || pis == NULL || h->_get_istream == NULL)
return EINVAL;
return h->_get_istream (h, pis);
}
int
header_get_ostream (header_t h, ostream_t *pos)
{
if (h == NULL || pos == NULL || h->_get_ostream == NULL)
return EINVAL;
return h->_get_ostream (h, pos);
}
......@@ -33,8 +33,6 @@
extern "C" {
#endif
#define MU_HEADER_RFC822 0
#define MU_HEADER_UNIX_FROM "From "
#define MU_HEADER_RETURN_PATH "Return-Path"
#define MU_HEADER_RECEIVED "Received"
......@@ -69,7 +67,7 @@ struct _header;
typedef struct _header * header_t;
extern int header_init __P ((header_t *, const char *blurb,
size_t ln, int flag, void *owner));
size_t ln, void *owner));
extern void header_destroy __P ((header_t *, void *owner));
extern int header_set_value __P ((header_t, const char *fn,
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as published by
the Free Software Foundation; either version 2, 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 Library General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _HEADER0_H
#define _HEADER0_H
#include <sys/types.h>
#include <header.h>
#include <io0.h>
#ifndef __P
#ifdef __STDC__
#define __P(args) args
#else
#define __P(args) ()
#endif
#endif /*__P */
#ifdef _cpluscplus
extern "C" {
#endif
struct _hdr
{
char *fn;
char *fn_end;
char *fv;
char *fv_end;
};
typedef struct _hdr *hdr_t;
struct _header
{
size_t num;
/* Data */
void *data;
/* streams */
istream_t is;
ostream_t os;
/* owner ? */
void *owner;
int ref_count;
/* Functions */
int (*_init) __P ((header_t *, const char *, size_t, void *owner));
void (*_destroy) __P ((header_t *, void *owner));
int (*_set_value) __P ((header_t, const char *fn, const char *fv,
size_t n, int replace));
int (*_get_value) __P ((header_t, const char *fn, char *fv,
size_t len, size_t *n));
int (*_entry_count) __P ((header_t, size_t *));
int (*_entry_name) __P ((header_t, size_t num, char *buf,
size_t buflen, size_t *nwritten));
int (*_entry_value) __P ((header_t, size_t num, char *buf,
size_t buflen, size_t *nwritten));
int (*_get_istream) __P ((header_t h, istream_t *is));
int (*_get_ostream) __P ((header_t h, ostream_t *os));
int (*_parse) __P ((header_t, const char *blurb, size_t len));
};
/* rfc822 */
extern int rfc822_init __P ((header_t *ph, const char *blurb,
size_t len, void *owner));
extern void rfc822_destroy __P ((header_t *ph, void *owner));
#ifdef _cpluscplus
}
#endif
#endif /* HEADER0_H */
......@@ -1318,8 +1318,7 @@ mailbox_unix_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
}
/* set the header */
if ((status = header_init (&header, pbuf,
offset, MU_HEADER_RFC822, mum)) != 0 ||
if ((status = header_init (&header, pbuf, offset, mum)) != 0 ||
(status = message_set_header (msg, header, mum)) != 0)
{
free (pbuf);
......
......@@ -74,7 +74,7 @@ int message_clone (message_t omsg, message_t *pmsg)
} while (nread > 0);
status = header_init (&header, pbuf, offset, MU_HEADER_RFC822, NULL);
status = header_init (&header, pbuf, offset, NULL);
if (status != 0)
{
free (pbuf);
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Library Public License as published by
the Free Software Foundation; either version 2, 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 Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <header0.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
static int rfc822_parse (header_t h, const char *blurb, size_t len);
static int rfc822_set_value (header_t h, const char *fn, const char *fb,
size_t n, int replace);
static int rfc822_get_value (header_t h, const char *fn, char *fb,
size_t len, size_t *n);
static int rfc822_entry_count (header_t, size_t *num);
static int rfc822_entry_name (header_t h, size_t num, char *buf,
size_t buflen, size_t *total);
static int rfc822_entry_value (header_t h, size_t num, char *buf,
size_t buflen, size_t *total);
static int rfc822_get_istream (header_t h, istream_t *pis);
static int rfc822_get_ostream (header_t h, ostream_t *pos);
static int rfc822_read (istream_t is, char *buf, size_t buflen,
off_t off, ssize_t *pnread);
struct _rfc822
{
char *blurb;
size_t blurb_len;
size_t hdr_count;
struct _hdr *hdr;
};
typedef struct _rfc822 * rfc822_t;
int
rfc822_init (header_t *ph, const char *blurb, size_t len, void *owner)
{
header_t h;
int status;
h = calloc (1, sizeof (*h));
if (h == NULL)
return ENOMEM;
h->owner = owner;
h->_init = rfc822_init;
h->_destroy = rfc822_destroy;
h->_parse = rfc822_parse;
h->_get_value = rfc822_get_value;
h->_set_value = rfc822_set_value;
h->_entry_count = rfc822_entry_count;
h->_entry_name = rfc822_entry_name;
h->_entry_value = rfc822_entry_value;
h->_get_istream = rfc822_get_istream;
h->_get_ostream = rfc822_get_ostream;
status = h->_parse (h, blurb, len);
if (status != 0)
free (h);
*ph = h;
return status;
}
void
rfc822_destroy (header_t *ph, void *owner)
{
if (ph && *ph)
{
header_t h = *ph;
/* if destroy is call always decremente */
h->ref_count--;
/* can we destroy ? */
if ((h->owner && h->owner == owner) ||
(h->owner == NULL && h->ref_count <= 0))
{
/* io */
istream_destroy (&(h->is), owner);
ostream_destroy (&(h->os), owner);
if (h->data)
{
rfc822_t rfc = (rfc822_t)h->data;
free (rfc->hdr);
free (rfc->blurb);
free (rfc);
}
free (h);
}
*ph = NULL;
}
}
/*
* Parsing is done in a rather simple fashion.
* meaning we just consider an entry to be
* a field-name an a field-value. So they
* maybe duplicate of field-name like "Received"
* they are just put in the array, see _get_value()
* on how to handle the case.
*/
static int
rfc822_parse (header_t h, const char *blurb, size_t len)
{
rfc822_t rfc;
char *header_end;
char *header_start;
char *header_start2;
struct _hdr *hdr;
if (h == NULL || blurb == NULL || len == 0)
return EINVAL;
rfc = calloc (1, sizeof (*rfc));
if (rfc == NULL)
return ENOMEM;
rfc->blurb = calloc (1, len);
if (rfc->blurb == NULL)
{
free (rfc);
return ENOMEM;
}
rfc->blurb_len = len;
memcpy (rfc->blurb, blurb, len);
for (header_start = rfc->blurb;; header_start = ++header_end)
{
/* get a header, a header is :
* field-name ':' ' ' field-value '\r' '\n'
* [ (' ' | '\t') field-value '\r' '\n' ]
*/
for (header_start2 = header_start;;header_start2 = ++header_end)
{
header_end = memchr (header_start2, '\n', len);
if (header_end == NULL)
break;
else
{
len -= (header_end - header_start2 + 1);
if (len == 0)
{
header_end = NULL;
break;
}
if (header_end[1] != ' '
&& header_end[1] != '\t')
break; /* new header break the inner for */
}
/* *header_end = ' '; smash LF */
}
if (header_end == NULL)
break; /* bail out */
hdr = realloc (rfc->hdr, (rfc->hdr_count + 1) * sizeof (*hdr));
if (hdr == NULL)
{
free (rfc->blurb);
free (rfc->hdr);
free (rfc);
return ENOMEM;
}
rfc->hdr = hdr;
rfc->hdr_count++;
/* Treats unix "From " specially */
if ((header_end - header_start >= 5)
&& strncmp (header_start, "From ", 5) == 0)
{
rfc->hdr[rfc->hdr_count - 1].fn = header_start;
rfc->hdr[rfc->hdr_count - 1].fn_end = header_start + 6;
rfc->hdr[rfc->hdr_count - 1].fv = header_start + 6;
rfc->hdr[rfc->hdr_count - 1].fv_end = header_end;
}
else
{
char *colon = memchr (header_start, ':', header_end - header_start);
if (colon == NULL)
{
/* Houston we have a problem */
free (rfc->blurb);
free (rfc->hdr);
free (rfc);
return EINVAL;
}
rfc->hdr[rfc->hdr_count - 1].fn = header_start;
rfc->hdr[rfc->hdr_count - 1].fn_end = colon;
/* skip leading spaces */
while (*(++colon) == ' ');
rfc->hdr[rfc->hdr_count - 1].fv = colon;
rfc->hdr[rfc->hdr_count - 1].fv_end = header_end;
}
}
h->data = rfc;
return 0;
}
static int
rfc822_set_value (header_t h, const char *fn, const char *fv,
size_t n, int replace)
{
(void)h; (void)fn; (void)fv; (void)n; (void)replace;
return ENOSYS;
}
static int
rfc822_get_value (header_t h, const char *name, char *buffer,
size_t buflen, size_t *n)
{
size_t i = 0;
size_t name_len;
size_t total = 0, fn_len = 0, fv_len = 0;
int threshold;
rfc822_t rfc;
if (h == NULL || name == NULL ||
(rfc = (rfc822_t)h->data) == NULL)
return EINVAL;
/* we set the threshold to be 1 less for the null */
threshold = --buflen;
/*
* Caution: We may have more then one value for a field
* name, for example a "Received" field-name is added by
* each passing MTA. The way that the parsing (_parse())
* is done it's not take to account. So we just stuff in
* the buffer all the field-values to a corresponding field-name.
* FIXME: Should we kosher the output ? meaning replace
* occurences of " \t\r\n" for spaces ? for now we don't.
*/
for (name_len = strlen (name), i = 0; i < rfc->hdr_count; i++)
{
fn_len = rfc->hdr[i].fn_end - rfc->hdr[i].fn;
if (fn_len == name_len && memcmp (rfc->hdr[i].fn, name, fn_len) == 0)
{
fv_len = (rfc->hdr[i].fv_end - rfc->hdr[i].fv);
total += fv_len;
/* can everything fit in the buffer */
if (buffer && threshold > 0)
{
threshold -= fv_len;
if (threshold > 0)
{
memcpy (buffer, rfc->hdr[i].fv, fv_len);
buffer += fv_len;
}
else if (threshold < 0)
{
threshold += fv_len;
memcpy (buffer, rfc->hdr[i].fv, threshold);
buffer += threshold;
threshold = 0;
}
}
}
}
if (buffer)
*buffer = '\0'; /* null terminated */
if (n)
*n = total;
return 0;
}
static int
rfc822_entry_count (header_t h, size_t *num)
{
rfc822_t rfc;
if (h == NULL || (rfc = (rfc822_t)h->data) == NULL)
return EINVAL;
if (num)
*num = rfc->hdr_count;
return 0;
}
static int
rfc822_entry_name (header_t h, size_t num, char *buf,
size_t buflen, size_t *nwritten)
{
rfc822_t rfc;
size_t len;
if (h == NULL || (rfc = (rfc822_t)h->data) == NULL)
return EINVAL;
if (rfc->hdr_count == 0 || num > rfc->hdr_count)
return ENOENT;
len = rfc->hdr[num].fn_end - rfc->hdr[num].fn;
/* save one for the null */
--buflen;
if (buf && buflen > 0)
{
buflen = (len > buflen) ? buflen : len;
memcpy (buf, rfc->hdr[num].fn, buflen);
buf[buflen] = '\0';
}
if (nwritten)
*nwritten = len;
return 0;
}
static int
rfc822_entry_value (header_t h, size_t num, char *buf,
size_t buflen, size_t *nwritten)
{
rfc822_t rfc;
size_t len;
if (h == NULL || (rfc = (rfc822_t)h->data) == NULL)
return EINVAL;
if (rfc->hdr_count == 0 || num > rfc->hdr_count)
return ENOENT;
len = rfc->hdr[num].fv_end - rfc->hdr[num].fv;
/* save one for the null */
--buflen;
if (buf && buflen > 0)
{
buflen = (len > buflen) ? buflen : len;
memcpy (buf, rfc->hdr[num].fv, buflen);
buf[buflen] = '\0';
}
if (nwritten)
*nwritten = len;
return 0;
}
static int
rfc822_read (istream_t is, char *buf, size_t buflen,
off_t off, ssize_t *pnread)
{
header_t h;
rfc822_t rfc = NULL;
ssize_t len;
if (is == NULL || (h = (header_t)is->owner) == NULL ||
(rfc = (rfc822_t)h->data) == NULL)
return EINVAL;
len = rfc->blurb_len - off;
if ((rfc->blurb_len - off) > 0)
{
if (buf)
{
len = (buflen < (size_t)len) ? buflen : len;
memcpy (buf, rfc->blurb + off, len);
}
}
else
len = 0;
if (pnread)
*pnread = len;
return 0;
}
int
rfc822_get_istream (header_t h, istream_t *pis)
{
int err;
if (h == NULL || pis == NULL)
return EINVAL;
/* already done */
if (h->is)
*pis = h->is;
err = istream_init (&(h->is), rfc822_read, h->owner);
if (err != 0)
return err;
/* tell the world this is ours */
h->is->owner = h;
h->is->_read = rfc822_read;
*pis = h->is;
return 0;
}
int
rfc822_get_ostream (header_t h, ostream_t *pos)
{
if (h == NULL || pos == NULL)
return EINVAL;
return ENOSYS;
}