Commit a6483b11 a6483b1164098d209d8d7a69533b9fe187591120 by Alain Magloire

New batch of files.

1 parent eaaa3d36
......@@ -11,10 +11,17 @@ SUBDIRS = include pop3 mbox
lib_LTLIBRARIES = libmailbox.la
libmailbox_la_SOURCES = \
address.c \
attribute.c \
bstream.c \
envelope.c \
fstream.c \
iterator.c \
list.c \
md5-rsa.c \
mstream.c \
observable.c \
observer.c \
parse822.c \
stream.c \
tcp.c
tcpstream.c
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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 <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <errno.h>
#include <mailutils/parse822.h>
#include <mailutils/mutil.h>
#include <mailutils/sys/address.h>
/* Get email address from rfc822 address. */
int
address_create (address_t *a, const char *s)
{
/* 'paddress' must exist, and can't already have been initialized
*/
int status;
if (!a)
return EINVAL;
*a = NULL;
status = parse822_address_list (a, (char*) s);
if (status == 0)
{
/* And address-list may contain 0 addresses but parse correctly.
*/
if (!*a)
return ENOENT;
(*a)->addr = strdup (s);
if (!(*a)->addr)
{
address_destroy (*a);
return ENOMEM;
}
}
return status;
}
int
address_destroy (address_t address)
{
if (address)
{
address_t current;
for (; address; address = current)
{
if (address->addr)
free (address->addr);
if (address->comments)
free (address->comments);
if (address->personal)
free (address->personal);
if (address->email)
free (address->email);
if (address->local_part)
free (address->local_part);
if (address->domain)
free (address->domain);
if (address->route)
free (address->route);
current = address->next;
free (address);
}
}
return 0;
}
int
address_get_personal (address_t addr, size_t no, char *buf, size_t len,
size_t *n)
{
size_t i, j;
int status = ENOENT;
if (addr == NULL)
return EINVAL;
for (i = 0, j = 1; addr; addr = addr->next, j++)
{
if (j == no)
{
i = util_cpystr (buf, addr->personal, len);
status = 0;
break;
}
}
if (n)
*n = i;
return status;
}
int
address_get_comments (address_t addr, size_t no, char *buf, size_t len,
size_t *n)
{
size_t i, j;
int status = ENOENT;
if (addr == NULL)
return EINVAL;
for (j = 1; addr; addr = addr->next, j++)
{
if (j == no)
{
i = util_cpystr (buf, addr->comments, len);
if (n)
*n = i;
status = 0;
break;
}
}
return status;
}
int
address_get_email (address_t addr, size_t no, char *buf, size_t len, size_t *n)
{
size_t i, j;
int status = ENOENT;
if (addr == NULL)
return EINVAL;
for (j = 1; addr; addr = addr->next, j++)
{
if (j == no)
{
i = util_cpystr (buf, addr->email, len);
if (n)
*n = i;
status = 0;
break;
}
}
return status;
}
int
address_get_local_part (address_t addr, size_t no, char *buf, size_t len, size_t *n)
{
size_t i, j;
int status = ENOENT;
if (addr == NULL)
return EINVAL;
for (j = 1; addr; addr = addr->next, j++)
{
if (j == no)
{
i = util_cpystr (buf, addr->local_part, len);
if (n)
*n = i;
status = 0;
break;
}
}
return status;
}
int
address_get_domain (address_t addr, size_t no, char *buf, size_t len, size_t *n)
{
size_t i, j;
int status = ENOENT;
if (addr == NULL)
return EINVAL;
for (j = 1; addr; addr = addr->next, j++)
{
if (j == no)
{
i = util_cpystr (buf, addr->domain, len);
if (n)
*n = i;
status = 0;
break;
}
}
return status;
}
int
address_get_route (address_t addr, size_t no, char *buf, size_t len, size_t *n)
{
size_t i, j;
int status = ENOENT;
if (addr == NULL)
return EINVAL;
for (j = 1; addr; addr = addr->next, j++)
{
if (j == no)
{
i = util_cpystr (buf, addr->route, len);
if (n)
*n = i;
status = 0;
break;
}
}
return status;
}
int
address_is_group (address_t addr, size_t no, int* yes)
{
size_t j;
int status = ENOENT;
if(addr == NULL)
return EINVAL;
for (j = 1; addr; addr = addr->next, j++)
{
if (j == no)
{
status = 0;
if(yes)
{
*yes = 0;
if(addr->personal && !addr->local_part && !addr->domain)
*yes = 1;
}
break;
}
}
return status;
}
int
address_to_string (address_t addr, char *buf, size_t len, size_t *n)
{
size_t i;
if (addr == NULL)
return EINVAL;
if (buf)
*buf = '\0';
i = util_cpystr (buf, addr->addr, len);
if (n)
*n = i;
return 0;
}
int
address_get_count (address_t addr, size_t *pcount)
{
size_t j;
for (j = 0; addr; addr = addr->next, j++)
;
if (pcount)
*pcount = j;
return 0;
}
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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 <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <mailutils/error.h>
#include <mailutils/sys/attribute.h>
int
(attribute_add_ref) (attribute_t attribute)
{
if (attribute == NULL || attribute->vtable == NULL
|| attribute->vtable->add_ref == NULL)
return MU_ERROR_NOT_SUPPORTED;
return attribute->vtable->add_ref (attribute);
}
int
(attribute_release) (attribute_t attribute)
{
if (attribute == NULL || attribute->vtable == NULL
|| attribute->vtable->release == NULL)
return MU_ERROR_NOT_SUPPORTED;
return attribute->vtable->release (attribute);
}
int
(attribute_destroy) (attribute_t attribute)
{
if (attribute == NULL || attribute->vtable == NULL
|| attribute->vtable->destroy == NULL)
return MU_ERROR_NOT_SUPPORTED;
return attribute->vtable->destroy (attribute);
}
int
(attribute_get_flags) (attribute_t attribute, int *pflags)
{
if (attribute == NULL || attribute->vtable == NULL
|| attribute->vtable->get_flags == NULL)
return MU_ERROR_NOT_SUPPORTED;
return attribute->vtable->get_flags (attribute, pflags);
}
int
(attribute_set_flags) (attribute_t attribute, int flags)
{
if (attribute == NULL || attribute->vtable == NULL
|| attribute->vtable->set_flags == NULL)
return MU_ERROR_NOT_SUPPORTED;
return attribute->vtable->set_flags (attribute, flags);
}
int
(attribute_unset_flags) (attribute_t attribute, int flags)
{
if (attribute == NULL || attribute->vtable == NULL
|| attribute->vtable->unset_flags == NULL)
return MU_ERROR_NOT_SUPPORTED;
return attribute->vtable->unset_flags (attribute, flags);
}
int
(attribute_clear_flags) (attribute_t attribute)
{
if (attribute == NULL || attribute->vtable == NULL
|| attribute->vtable->clear_flags == NULL)
return MU_ERROR_NOT_SUPPORTED;
return attribute->vtable->clear_flags (attribute);
}
/* Stub helpers for the wellknown flags. */
int
attribute_set_seen (attribute_t attribute)
{
if (attribute == NULL)
return MU_ERROR_INVALID_PARAMETER;
return attribute_set_flags (attribute, MU_ATTRIBUTE_SEEN);
}
int
attribute_set_answered (attribute_t attribute)
{
if (attribute == NULL)
return MU_ERROR_INVALID_PARAMETER;
return attribute_set_flags (attribute, MU_ATTRIBUTE_ANSWERED);
}
int
attribute_set_flagged (attribute_t attribute)
{
if (attribute == NULL)
return MU_ERROR_INVALID_PARAMETER;
return attribute_set_flags (attribute, MU_ATTRIBUTE_FLAGGED);
}
int
attribute_set_read (attribute_t attribute)
{
if (attribute == NULL)
return MU_ERROR_INVALID_PARAMETER;
return attribute_set_flags (attribute, MU_ATTRIBUTE_READ);
}
int
attribute_set_deleted (attribute_t attribute)
{
if (attribute == NULL)
return MU_ERROR_INVALID_PARAMETER;
return attribute_set_flags (attribute, MU_ATTRIBUTE_DELETED);
}
int
attribute_set_draft (attribute_t attribute)
{
if (attribute == NULL)
return MU_ERROR_INVALID_PARAMETER;
return attribute_set_flags (attribute, MU_ATTRIBUTE_DRAFT);
}
int
attribute_set_recent (attribute_t attribute)
{
if (attribute == NULL)
return MU_ERROR_INVALID_PARAMETER;
attribute_unset_flags (attribute, MU_ATTRIBUTE_READ);
return attribute_unset_flags (attribute, MU_ATTRIBUTE_SEEN);
}
int
attribute_set_modified (attribute_t attribute)
{
if (attribute == NULL)
return MU_ERROR_INVALID_PARAMETER;
return attribute_set_flags (attribute, MU_ATTRIBUTE_MODIFIED);
}
int
attribute_is_seen (attribute_t attribute)
{
int flags = 0;
if (attribute == NULL)
return 0;
attribute_get_flags (attribute, &flags);
return flags & MU_ATTRIBUTE_SEEN;
}
int
attribute_is_answered (attribute_t attribute)
{
int flags = 0;
if (attribute == NULL)
return 0;
attribute_get_flags (attribute, &flags);
return flags & MU_ATTRIBUTE_ANSWERED;
}
int
attribute_is_flagged (attribute_t attribute)
{
int flags = 0;
if (attribute == NULL)
return 0;
attribute_get_flags (attribute, &flags);
return flags & MU_ATTRIBUTE_FLAGGED;
}
int
attribute_is_read (attribute_t attribute)
{
int flags = 0;
if (attribute == NULL)
return 0;
attribute_get_flags (attribute, &flags);
return flags & MU_ATTRIBUTE_READ;
}
int
attribute_is_deleted (attribute_t attribute)
{
int flags = 0;
if (attribute == NULL)
return 0;
attribute_get_flags (attribute, &flags);
return flags & MU_ATTRIBUTE_DELETED;
}
int
attribute_is_draft (attribute_t attribute)
{
int flags = 0;
if (attribute == NULL)
return 0;
attribute_get_flags (attribute, &flags);
return flags & MU_ATTRIBUTE_DRAFT;
}
int
attribute_is_recent (attribute_t attribute)
{
int flags = 0;
if (attribute == NULL)
return 0;
attribute_get_flags (attribute, &flags);
/* Something is recent when it is not read and not seen. */
return (flags == 0
|| ! ((flags & MU_ATTRIBUTE_SEEN) || (flags & MU_ATTRIBUTE_READ)));
}
int
attribute_is_modified (attribute_t attribute)
{
int flags = 0;
if (attribute == NULL)
return 0;
attribute_get_flags (attribute, &flags);
return flags & MU_ATTRIBUTE_MODIFIED;
}
int
attribute_unset_seen (attribute_t attribute)
{
if (attribute == NULL)
return 0;
return attribute_unset_flags (attribute, MU_ATTRIBUTE_SEEN);
}
int
attribute_unset_answered (attribute_t attribute)
{
if (attribute == NULL)
return 0;
return attribute_unset_flags (attribute, MU_ATTRIBUTE_ANSWERED);
}
int
attribute_unset_flagged (attribute_t attribute)
{
if (attribute == NULL)
return 0;
return attribute_unset_flags (attribute, MU_ATTRIBUTE_FLAGGED);
}
int
attribute_unset_read (attribute_t attribute)
{
if (attribute == NULL)
return 0;
return attribute_unset_flags (attribute, MU_ATTRIBUTE_READ);
}
int
attribute_unset_deleted (attribute_t attribute)
{
if (attribute == NULL)
return 0;
return attribute_unset_flags (attribute, MU_ATTRIBUTE_DELETED);
}
int
attribute_unset_draft (attribute_t attribute)
{
if (attribute == NULL)
return 0;
return attribute_unset_flags (attribute, MU_ATTRIBUTE_DRAFT);
}
int
attribute_unset_recent (attribute_t attribute)
{
if (attribute == NULL)
return 0;
return attribute_unset_flags (attribute, MU_ATTRIBUTE_SEEN);
}
int
attribute_unset_modified (attribute_t attribute)
{
if (attribute == NULL)
return 0;
return attribute_unset_flags (attribute, MU_ATTRIBUTE_MODIFIED);
}
/* Miscellaneous. */
int
attribute_is_equal (attribute_t attribute1, attribute_t attribute2)
{
int flags1 = 0;
int flags2 = 0;
if (attribute1)
attribute_get_flags (attribute1, &flags1);
if (attribute2)
attribute_get_flags (attribute2, &flags2);
return flags1 == flags2;
}
int
attribute_copy (attribute_t dest, attribute_t src)
{
int sflags = 0;
if (dest == NULL || src == NULL)
return MU_ERROR_INVALID_PARAMETER;
attribute_get_flags (src, &sflags);
attribute_clear_flags (dest);
attribute_set_flags (dest, sflags);
return 0;
}
static int
_da_add_ref (attribute_t attribute)
{
struct _da *da = (struct _da *)attribute;
int status;
monitor_lock (da->lock);
status = ++da->ref;
monitor_unlock (da->lock);
return status;
}
static int
_da_destroy (attribute_t attribute)
{
struct _da *da = (struct _da *)attribute;
monitor_destroy (da->lock);
free (da);
return 0;
}
static int
_da_release (attribute_t attribute)
{
struct _da *da = (struct _da *)attribute;
int status;
monitor_lock (da->lock);
status = --da->ref;
if (status <= 0)
{
monitor_unlock (da->lock);
_da_destroy (attribute);
return 0;
}
monitor_unlock (da->lock);
return status;
}
static int
_da_get_flags (attribute_t attribute, int *pflags)
{
struct _da *da = (struct _da *)attribute;
monitor_lock (da->lock);
if (pflags)
*pflags = da->flags;
monitor_unlock (da->lock);
return 0;
}
static int
_da_set_flags (attribute_t attribute, int flags)
{
struct _da *da = (struct _da *)attribute;
monitor_lock (da->lock);
da->flags |= (flags | MU_ATTRIBUTE_MODIFIED);
monitor_unlock (da->lock);
return 0;
}
static int
_da_unset_flags (attribute_t attribute, int flags)
{
struct _da *da = (struct _da *)attribute;
monitor_lock (da->lock);
da->flags &= ~flags;
/* If Modified was being unset do not reset it. */
if (!(flags & MU_ATTRIBUTE_MODIFIED))
da->flags |= MU_ATTRIBUTE_MODIFIED;
monitor_unlock (da->lock);
return 0;
}
static int
_da_clear_flags (attribute_t attribute)
{
struct _da *da = (struct _da *)attribute;
monitor_lock (da->lock);
da->flags = 0;
monitor_unlock (da->lock);
return 0;
}
static struct _attribute_vtable _da_vtable =
{
_da_add_ref,
_da_release,
_da_destroy,
_da_get_flags,
_da_set_flags,
_da_unset_flags,
_da_clear_flags
};
int
attribute_create (attribute_t *pattribute)
{
struct _da *da;
if (pattribute == NULL)
return MU_ERROR_INVALID_PARAMETER;
da = calloc (1, sizeof *da);
if (da == NULL)
return MU_ERROR_NO_MEMORY;
da->base.vtable = &_da_vtable;
da->ref = 1;
da->flags = 0;
monitor_create (&(da->lock));
*pattribute = &da->base;
return 0;
}
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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 <mailutils/error.h>
#include <mailutils/sys/envelope.h>
int
(envelope_add_ref) (envelope_t envelope)
{
if (envelope == NULL || envelope->vtable == NULL
|| envelope->vtable->add_ref == NULL)
return MU_ERROR_NOT_SUPPORTED;
return envelope->vtable->add_ref (envelope);
}
int
(envelope_release) (envelope_t envelope)
{
if (envelope == NULL || envelope->vtable == NULL
|| envelope->vtable->release == NULL)
return MU_ERROR_NOT_SUPPORTED;
return envelope->vtable->release (envelope);
}
int
(envelope_destroy) (envelope_t envelope)
{
if (envelope == NULL || envelope->vtable == NULL
|| envelope->vtable->destroy == NULL)
return MU_ERROR_NOT_SUPPORTED;
return envelope->vtable->destroy (envelope);
}
int
(envelope_sender) (envelope_t envelope, address_t *paddr)
{
if (envelope == NULL || envelope->vtable == NULL
|| envelope->vtable->sender == NULL)
return MU_ERROR_NOT_SUPPORTED;
return envelope->vtable->sender (envelope, paddr);
}
int
(envelope_recipient) (envelope_t envelope, address_t *paddr)
{
if (envelope == NULL || envelope->vtable == NULL
|| envelope->vtable->recipient == NULL)
return MU_ERROR_NOT_SUPPORTED;
return envelope->vtable->recipient (envelope, paddr);
}
int
(envelope_date) (envelope_t envelope, struct tm *tm, struct mu_timezone *tz)
{
if (envelope == NULL || envelope->vtable == NULL
|| envelope->vtable->date == NULL)
return MU_ERROR_NOT_SUPPORTED;
return envelope->vtable->date (envelope, tm, tz);
}
......@@ -26,8 +26,9 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <mailutils/sys/fstream.h>
#include <mailutils/error.h>
......@@ -76,7 +77,7 @@ static int
_fs_read (stream_t stream, void *optr, size_t osize, size_t *nbytes)
{
struct _fs *fs = (struct _fs *)stream;
size_t n;
size_t n = 0;
int err = 0;
if (fs->file)
......@@ -123,7 +124,7 @@ static int
_fs_write (stream_t stream, const void *iptr, size_t isize, size_t *nbytes)
{
struct _fs *fs = (struct _fs *)stream;
size_t n;
size_t n = 0;
int err = 0;
if (fs->file)
......@@ -334,7 +335,7 @@ _fs_open (stream_t stream, const char *filename, int port, int flags)
|| fdbuf.st_ino != filebuf.st_ino
|| fdbuf.st_nlink != 1
|| filebuf.st_nlink != 1
|| (fdbuf.st_mode & S_IFMT) != S_IFREG)
|| !S_ISREG(fdbuf.st_mode))
{
mu_error ("%s must be a plain file with one link\n", filename);
close (fd);
......
# Use automake to process this file -*-Makefile-*-
SUBDIRS = sys
pkginclude_HEADERS = \
address.h \
attribute.h \
base.h \
envelope.h \
error.h \
iterator.h \
list.h \
mbox.h \
md5-rsa.h \
monitor.h \
mutil.h \
observer.h \
parse822.h \
pop3.h \
stream.h
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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. */
#ifndef _MAILUTILS_ADDRESS_H
#define _MAILUTILS_ADDRESS_H
#include <sys/types.h>
#ifndef __P
# ifdef __STDC__
# define __P(args) args
# else
# define __P(args) ()
# endif
#endif /*__P */
#ifdef __cplusplus
extern "C" {
#endif
struct _address;
typedef struct _address *address_t;
extern int address_create __P ((address_t *, const char *));
extern int address_add_ref __P ((address_t));
extern int address_release __P ((address_t));
extern int address_destroy __P ((address_t));
extern int address_get_email
__P ((address_t, size_t, char *, size_t, size_t *));
extern int address_get_local_part
__P ((address_t, size_t, char *, size_t, size_t *));
extern int address_get_domain
__P ((address_t, size_t, char *, size_t, size_t *));
extern int address_get_personal
__P ((address_t, size_t, char *, size_t, size_t *));
extern int address_get_comments
__P ((address_t, size_t, char *, size_t, size_t *));
extern int address_get_route
__P ((address_t, size_t, char *, size_t, size_t *));
extern int address_is_group
__P ((address_t, size_t, int*));
extern int address_to_string __P ((address_t, char *, size_t, size_t *));
extern int address_get_count __P ((address_t, size_t *));
#ifdef __cplusplus
}
#endif
#endif /* _MAILUTILS_ADDRESS_H */
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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. */
#ifndef _MAILUTILS_ATTRIBUTE_H
#define _MAILUTILS_ATTRIBUTE_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __P
# ifdef __STDC__
# define __P(args) args
# else
# define __P(args) ()
# endif
#endif /*__P */
struct _attribute;
typedef struct _attribute * attribute_t;
#define MU_ATTRIBUTE_ANSWERED 0x0001
#define MU_ATTRIBUTE_FLAGGED 0x0002
#define MU_ATTRIBUTE_DELETED 0x0004
#define MU_ATTRIBUTE_DRAFT 0x0008
#define MU_ATTRIBUTE_SEEN 0x0010
#define MU_ATTRIBUTE_READ 0x0020
#define MU_ATTRIBUTE_MODIFIED 0x1000
#define MU_ATTRIBUTE_RECENT 0x0000
extern int attribute_create __P ((attribute_t *));
extern int attribute_add_ref __P ((attribute_t));
extern int attribute_release __P ((attribute_t));
extern int attribute_destroy __P ((attribute_t));
extern int attribute_is_seen __P ((attribute_t));
extern int attribute_is_answered __P ((attribute_t));
extern int attribute_is_flagged __P ((attribute_t));
extern int attribute_is_deleted __P ((attribute_t));
extern int attribute_is_draft __P ((attribute_t));
extern int attribute_is_recent __P ((attribute_t));
extern int attribute_is_read __P ((attribute_t));
extern int attribute_is_modified __P ((attribute_t));
extern int attribute_set_seen __P ((attribute_t));
extern int attribute_set_answered __P ((attribute_t));
extern int attribute_set_flagged __P ((attribute_t));
extern int attribute_set_deleted __P ((attribute_t));
extern int attribute_set_draft __P ((attribute_t));
extern int attribute_set_recent __P ((attribute_t));
extern int attribute_set_read __P ((attribute_t));
extern int attribute_set_modified __P ((attribute_t));
extern int attribute_unset_seen __P ((attribute_t));
extern int attribute_unset_answered __P ((attribute_t));
extern int attribute_unset_flagged __P ((attribute_t));
extern int attribute_unset_deleted __P ((attribute_t));
extern int attribute_unset_draft __P ((attribute_t));
extern int attribute_unset_recent __P ((attribute_t));
extern int attribute_unset_read __P ((attribute_t));
extern int attribute_unset_modified __P ((attribute_t));
extern int attribute_get_flags __P ((attribute_t, int *));
extern int attribute_set_flags __P ((attribute_t, int));
extern int attribute_unset_flags __P ((attribute_t, int));
extern int attribute_clear_flags __P ((attribute_t));
extern int attribute_is_equal __P ((attribute_t, attribute_t));
extern int attribute_copy __P ((attribute_t dst, attribute_t src));
#ifdef __cplusplus
}
#endif
#endif /* _MAILUTILS_ATTRIBUTE_H */
......@@ -57,12 +57,6 @@ struct _mime *mime_t;
struct _message;
typedef struct _message *message_t;
struct _attribute;
typedef struct _attribute *attribute_t;
struct _envelope;
typedef struct _envelope *envelope_t;
struct _header;
typedef struct _header *header_t;
......@@ -75,36 +69,18 @@ typedef struct _ticket *ticket_t;
struct _authority;
typedef struct _authority *authority_t;
struct _observable;
typedef struct _observable *observable_t;
struct _locker;
typedef struct _locker *locker_t;
struct _address;
typedef struct _address *address_t;
struct _debug;
typedef struct _debug *mu_debug_t;
struct _stream;
typedef struct _stream *stream_t;
struct _filter;
typedef struct _filter *filter_t;
struct _iterator;
typedef struct _iterator *iterator_t;
struct _property;
typedef struct _property *property_t;
struct _monitor;
typedef struct _monitor *monitory_t;
struct _list;
typedef struct _list *list_t;
__MAILUTILS_END_DECLS
#endif /*_MAILUTILS_BASE_H */
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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. */
#ifndef _MAILUTILS_ENVELOPE_H
# define _MAILUTILS_ENVELOPE_H
#include <mailutils/address.h>
#include <mailutils/mutil.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __P
# ifdef __STDC__
# define __P(args) args
# else
# define __P(args) ()
# endif
#endif /*__P */
struct _envelope;
typedef struct _envelope *envelope_t;
extern int envelope_add_ref __P ((envelope_t));
extern int envelope_release __P ((envelope_t));
extern int envelope_destroy __P ((envelope_t));
extern int envelope_sender __P ((envelope_t, address_t *));
extern int envelope_recipient __P ((envelope_t, address_t *));
extern int envelope_date __P ((envelope_t, struct tm *, struct mu_timezone *));
#ifdef __cplusplus
}
#endif
#endif /* _MAILUTILS_ENVELOPE_H */
......@@ -18,9 +18,20 @@
#ifndef _MAILUTILS_ITERATOR_H
#define _MAILUTILS_ITERATOR_H
#include <mailutils/base.h>
#ifdef __cplusplus
extern "C" {
#endif
__MAILUTILS_BEGIN_DECLS
#ifndef __P
# ifdef __STDC__
# define __P(args) args
# else
# define __P(args) ()
# endif /* __STDC__ */
#endif /* __P */
struct _iterator;
typedef struct _iterator *iterator_t;
extern int iterator_add_ref __P ((iterator_t));
extern int iterator_destroy __P ((iterator_t));
......@@ -31,6 +42,8 @@ extern int iterator_next __P ((iterator_t));
extern int iterator_current __P ((iterator_t, void *));
extern int iterator_is_done __P ((iterator_t));
__MAILUTILS_END_DECLS
#ifdef __cplusplus
}
#endif
#endif /* _MAILUTILS_ITERATOR_H */
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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. */
#ifndef _MAILUTILS_LIST_H
#define _MAILUTILS_LIST_H
#include <sys/types.h>
#include <mailutils/iterator.h>
#ifndef __P
# ifdef __STDC__
# define __P(args) args
# else
# define __P(args) ()
# endif
#endif /*__P */
#ifdef __cplusplus
extern "C" {
#endif
struct _list;
typedef struct _list *list_t;
extern int list_create __P ((list_t *));
extern int list_destroy __P ((list_t));
extern int list_append __P ((list_t, void *));
extern int list_prepend __P ((list_t, void *));
extern int list_is_empty __P ((list_t));
extern int list_count __P ((list_t, size_t *));
extern int list_remove __P ((list_t, void *));
extern int list_get __P ((list_t, size_t, void **));
extern int list_get_iterator __P ((list_t, iterator_t *));
#ifdef __cplusplus
}
#endif
#endif /* _MAILUTILS_LIST_H */
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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. */
#ifndef _MAILUTILS_OBSERVER_H
#define _MAILUTILS_OBSERVER_H
#include <sys/types.h>
#include <mailutils/base.h>
#ifndef __P
#ifdef __STDC__
#define __P(args) args
#else
#define __P(args) ()
#endif
#endif /*__P */
#ifdef __cplusplus
extern "C" {
#endif
struct _observer;
struct _observable;
typedef struct _observer * observer_t;
typedef struct _observable * observable_t;
struct event
{
int type;
union
{
mailbox_t mailbox; /* For corrupted mailbox. */
int msgno; /* For new message. */
int percentage; /* Scan progress. */
message_t message; /* message sent. */
} data ;
};
#define MU_EVT_MESSAGE_ADD 0x010
#define MU_EVT_MAILBOX_PROGRESS 0x020
#define MU_EVT_AUTHORITY_FAILED 0x030
#define MU_EVT_MAILBOX_CORRUPT 0x040
#define MU_EVT_MAILER_MESSAGE_SENT 0x080
extern int observer_create __P ((observer_t *, int (*action)
__P ((void *, struct event)), void *));
extern int observer_add_ref __P ((observer_t));
extern int observer_release __P ((observer_t));
extern int observer_destroy __P ((observer_t));
extern int observer_action __P ((observer_t, struct event));
extern int observable_create __P ((observable_t *));
extern int observable_release __P ((observable_t));
extern int observable_destroy __P ((observable_t));
extern int observable_attach __P ((observable_t, int, observer_t));
extern int observable_detach __P ((observable_t, observer_t));
extern int observable_notify_all __P ((observable_t, struct event));
#ifdef __cplusplus
}
#endif
#endif /* _MAILUTILS_OBSERVER_H */
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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. */
/**
* Parses syntatic elements defined in RFC 822.
*/
#ifndef _MAILUTILS_PARSE822_H
#define _MAILUTILS_PARSE822_H
#include <mailutils/address.h>
#include <mailutils/mutil.h>
#ifndef __P
# ifdef __STDC__
# define __P(args) args
# else
# define __P(args) ()
# endif
#endif /*__P */
#ifdef __cplusplus
extern "C" {
#endif
/**
* Reads an RFC822 defined lexical token from an input. All names are
* as close as possible to those used in the extended BNF of the RFC.
*/
/* From RFC 822, 3.3 Lexical Tokens */
extern int parse822_is_char __P ((char c));
extern int parse822_is_digit __P ((char c));
extern int parse822_is_ctl __P ((char c));
extern int parse822_is_space __P ((char c));
extern int parse822_is_htab __P ((char c));
extern int parse822_is_lwsp_char __P ((char c));
extern int parse822_is_special __P ((char c));
extern int parse822_is_atom_char __P ((char c));
extern int parse822_is_q_text __P ((char c));
extern int parse822_is_d_text __P ((char c));
extern int parse822_is_smtp_q __P ((char c));
extern int parse822_skip_crlf __P ((const char** p, const char* e));
extern int parse822_skip_lwsp_char __P ((const char** p, const char* e));
extern int parse822_skip_lwsp __P ((const char** p, const char* e));
extern int parse822_skip_comments __P ((const char** p, const char* e));
extern int parse822_skip_nl __P ((const char** p, const char* e));
extern int parse822_digits __P ((const char** p, const char* e, int min, int max, int* digits));
extern int parse822_special __P ((const char** p, const char* e, char c));
extern int parse822_comment __P ((const char** p, const char* e, char** comment));
extern int parse822_atom __P ((const char** p, const char* e, char** atom));
extern int parse822_quoted_pair __P ((const char** p, const char* e, char** qpair));
extern int parse822_quoted_string __P ((const char** p, const char* e, char** qstr));
extern int parse822_word __P ((const char** p, const char* e, char** word));
extern int parse822_phrase __P ((const char** p, const char* e, char** phrase));
extern int parse822_d_text __P ((const char** p, const char* e, char** dtext));
/* From RFC 822, 6.1 Address Specification Syntax */
extern int parse822_address_list __P ((address_t* a, const char* s));
extern int parse822_mail_box __P ((const char** p, const char* e, address_t* a));
extern int parse822_group __P ((const char** p, const char* e, address_t* a));
extern int parse822_address __P ((const char** p, const char* e, address_t* a));
extern int parse822_route_addr __P ((const char** p, const char* e, address_t* a));
extern int parse822_route __P ((const char** p, const char* e, char** route));
extern int parse822_addr_spec __P ((const char** p, const char* e, address_t* a));
extern int parse822_unix_mbox __P ((const char** p, const char* e, address_t* a));
extern int parse822_local_part __P ((const char** p, const char* e, char** local_part));
extern int parse822_domain __P ((const char** p, const char* e, char** domain));
extern int parse822_sub_domain __P ((const char** p, const char* e, char** sub_domain));
extern int parse822_domain_ref __P ((const char** p, const char* e, char** domain_ref));
extern int parse822_domain_literal __P ((const char** p, const char* e, char** domain_literal));
/* RFC 822 Quoting Functions
* Various elements must be quoted if then contain non-safe characters. What
* characters are allowed depend on the element. The following functions will
* allocate a quoted version of the raw element, it may not actually be
* quoted if no unsafe characters were in the raw string.
*/
extern int parse822_quote_string __P ((char** quoted, const char* raw));
extern int parse822_quote_local_part __P ((char** quoted, const char* raw));
extern int parse822_field_body __P ((const char** p, const char *e, char** fieldbody));
extern int parse822_field_name __P ((const char** p, const char *e, char** fieldname));
/***** From RFC 822, 5.1 Date and Time Specification Syntax *****/
extern int parse822_day __P ((const char** p, const char* e, int* day));
extern int parse822_date __P ((const char** p, const char* e, int* day, int* mon, int* year));
extern int parse822_time __P ((const char** p, const char* e, int* h, int* m, int* s, int* tz, const char** tz_name));
extern int parse822_date_time __P ((const char** p, const char* e, struct tm* tm, mu_timezone* tz));
#ifdef __cplusplus
}
#endif
#endif /* _MAILUTILS_PARSE822_H */
......@@ -21,7 +21,17 @@
#include <mailutils/iterator.h>
#include <mailutils/stream.h>
__MAILUTILS_BEGIN_DECLS
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __P
# ifdef __STDC__
# define __P(args) args
# else
# define __P(args) ()
# endif
#endif /*__P */
struct _pop3;
typedef struct _pop3* pop3_t;
......@@ -72,6 +82,8 @@ extern int pop3_writeline __P ((pop3_t, const char *, ...));
extern int pop3_sendline __P ((pop3_t, const char *));
extern int pop3_send __P ((pop3_t));
__MAILUTILS_END_DECLS
#ifdef __cplusplus
}
#endif
#endif /* _MAILUTILS_POP3_H */
......
......@@ -16,12 +16,13 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _MAILUTILS_STREAM_H
# define _MAILUTILS_STREAM_H
#define _MAILUTILS_STREAM_H
#include <mailutils/base.h>
#include <sys/types.h>
__MAILUTILS_BEGIN_DECLS
#ifdef __cplusplus
extern "C" {
#endif
#define MU_STREAM_READ 0x00000001
#define MU_STREAM_WRITE 0x00000002
......@@ -46,6 +47,9 @@ enum stream_state
MU_STREAM_STATE_CLOSE
};
struct _stream;
typedef struct _stream *stream_t;
extern int stream_add_ref __P ((stream_t));
extern int stream_release __P ((stream_t));
extern int stream_destroy __P ((stream_t));
......@@ -75,6 +79,8 @@ extern int stream_memory_create __P ((stream_t *));
extern int stream_tcp_create __P ((stream_t *));
extern int stream_buffer_create __P ((stream_t *, stream_t, size_t));
__MAILUTILS_END_DECLS
#ifdef __cplusplus
}
#endif
#endif /* _MAILUTILS_STREAM_H */
......
# Use automake to process this file -*-Makefile-*-
pkginclude_HEADERS = \
address.h \
attribute.h \
bstream.h \
envelope.h \
fstream.h \
iterator.h \
list.h \
mbox.h \
mstream.h \
observer.h \
pop3.h \
stream.h \
tcpstream.h
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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. */
#ifndef _ADDRESS0_H
#define _ADDRESS0_H
#ifdef DMALLOC
# include <dmalloc.h>
#endif
#include <mailutils/address.h>
#ifndef __P
# ifdef __STDC__
# define __P(args) args
# else
# define __P(args) ()
# endif
#endif /*__P */
#ifdef __cplusplus
extern "C" {
#endif
/*
* The data-structure representing an RFC822 MAILBOX. It may be
* one MAILBOX or a list of them, as found in an ADDRESS or
* a MAILBOX list (as found in a GROUP).
*
* Capitalized names are from RFC 822, section 6.1 (Address Syntax).
*/
struct _address
{
char *addr;
/* the original string that this list of addresses was created
* from, only present at the head of the list */
char *comments;
/* the collection of comments stripped during parsing this MAILBOX */
char *personal;
/* the PHRASE portion of a MAILBOX, called the DISPLAY-NAME in drums */
char *email;
/* the ADDR-SPEC, the LOCAL-PART@DOMAIN */
char *local_part;
/* the LOCAL-PART of a MAILBOX */
char *domain;
/* the DOMAIN of a MAILBOX */
char *route;
/* the optional ROUTE in the ROUTE-ADDR form of MAILBOX */
/* size_t num; this didn't appear to be used anywhere... so I commented
it out, is that ok? -sam */
struct _address *next;
};
#ifdef __cplusplus
}
#endif
#endif /* _ADDRESS0_H */
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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. */
#ifndef _MAILUTILS_SYS_ATTRIBUTE_H
# define _MAILUTILS_SYS_ATTRIBUTE_H
#ifdef DMALLOC
# include <dmalloc.h>
#endif
#include <mailutils/attribute.h>
#include <mailutils/monitor.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __P
# ifdef __STDC__
# define __P(args) args
# else
# define __P(args) ()
# endif
#endif /*__P */
struct _attribute_vtable
{
int (*add_ref) __P ((attribute_t));
int (*release) __P ((attribute_t));
int (*destroy) __P ((attribute_t));
int (*get_flags) __P ((attribute_t, int *));
int (*set_flags) __P ((attribute_t, int));
int (*unset_flags) __P ((attribute_t, int));
int (*clear_flags) __P ((attribute_t));
};
struct _attribute
{
struct _attribute_vtable *vtable;
};
/* A simple default attribute implementation. */
struct _da
{
struct _attribute base;
int ref;
int flags;
monitor_t lock;
};
#define attribute_add_ref(a) ((a)->vtable->add_ref)(s)
#define attribute_release(a) ((a)->vtable->release)(s)
#define attribute_destroy(a) ((a)->vtable->destroy)(s)
#define attribute_get_flags(a,pf) ((a)->vtable->get_flags)(a,pf)
#define attribute_set_flags(a,f) ((a)->vtable->set_flags)(a,f)
#define attribute_unset_flags(a,f) ((a)->vtable->unset_flags)(a,f)
#define attribute_clear_flags(a) ((a)->vtable->clear_flags)(a)
#ifdef __cplusplus
}
#endif
#endif /* _MAILUTILS_SYS_ATTRIBUTE_H */
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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. */
#ifndef _MAILUTILS_SYS_ENVELOPE_H
#define _MAILUTILS_SYS_ENVELOPE_H
#ifdef DMALLOC
#include <dmalloc.h>
#endif
#include <mailutils/envelope.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __P
# ifdef __STDC__
# define __P(args) args
# else
# define __P(args) ()
# endif
#endif /*__P */
struct _envelope_vtable
{
int (*add_ref) __P ((envelope_t));
int (*release) __P ((envelope_t));
int (*destroy) __P ((envelope_t));
int (*sender) __P ((envelope_t, address_t *));
int (*recipient) __P ((envelope_t, address_t *));
int (*date) __P ((envelope_t, struct tm *, struct mu_timezone *));
};
struct _envelope
{
struct _envelope_vtable *vtable;
};
#ifdef __cplusplus
}
#endif
#endif /* _MAILUTILS_SYS_ENVELOPE_H */
......@@ -20,7 +20,9 @@
#include <mailutils/iterator.h>
__MAILUTILS_BEGIN_DECLS
#ifdef __cplusplus
extern "C" {
#endif
struct _iterator_vtable
{
......@@ -50,6 +52,8 @@ struct _iterator
#define iterator_current(i,a) ((i)->vtable->current)(i,a)
#define iterator_is_done(i) ((i)->vtable->is_done)(i)
__MAILUTILS_END_DECLS
#ifdef __cplusplus
}
#endif
#endif /* _MAILUTILS_SYS_ITERATOR_H */
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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. */
#ifndef _MAILUTILS_SYS_LIST_H
#define _MAILUTILS_SYS_LIST_H
#ifdef DMALLOC
# include <dmalloc.h>
#endif
#include <sys/types.h>
#include <mailutils/list.h>
#include <mailutils/monitor.h>
#include <mailutils/sys/iterator.h>
#ifndef __P
#ifdef __STDC__
#define __P(args) args
#else
#define __P(args) ()
#endif
#endif /*__P */
#ifdef __cplusplus
extern "C" {
#endif
struct list_data
{
void *item;
struct list_data *next;
struct list_data *prev;
};
struct _list
{
struct list_data head;
size_t count;
size_t index;
monitor_t lock;
};
struct l_iterator
{
struct _iterator base;
unsigned int ref;
list_t list;
struct list_data *current;
monitor_t lock;
};
#ifdef __cplusplus
}
#endif
#endif /* _MAILUTILS_SYS_LIST_H */
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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. */
#ifndef _MAILUTILS_SYS_OBSERVER_H
#define _MAILUTILS_SYS_OBSERVER_H
#ifdef DMALLOC
# include <dmalloc.h>
#endif
#include <mailutils/monitor.h>
#include <mailutils/observer.h>
#include <mailutils/list.h>
#ifndef __P
#ifdef __STDC__
#define __P(args) args
#else
#define __P(args) ()
#endif
#endif /*__P */
#ifdef __cplusplus
extern "C" {
#endif
struct _observer_vtable
{
int (*add_ref) __P ((observer_t));
int (*release) __P ((observer_t));
int (*destroy) __P ((observer_t));
int (*action) __P ((observer_t, struct event));
};
struct _observer
{
struct _observer_vtable *vtable;
};
struct _observable
{
list_t list;
};
struct _dobserver
{
struct _observer base;
int ref;
void *arg;
int (*action) __P ((void *, struct event));
monitor_t lock;
};
#ifdef __cplusplus
}
#endif
#endif /* _MAILUTILS_SYS_OBSERVER_H */
......@@ -30,7 +30,9 @@
# include <dmalloc.h>
#endif
__MAILUTILS_BEGIN_DECLS
#ifdef __cplusplus
extern "C" {
#endif
enum pop3_state
{
......@@ -150,6 +152,8 @@ do \
} \
while (0)
__MAILUTILS_END_DECLS
#ifdef __cplusplus
}
#endif
#endif /* _MAILUTILS_SYS_POP3_H */
......
......@@ -18,10 +18,11 @@
#ifndef _MAILUTILS_SYS_STREAM_H
#define _MAILUTILS_SYS_STREAM_H
#include <mailutils/base.h>
#include <mailutils/stream.h>
__MAILUTILS_BEGIN_DECLS
#ifdef __cplusplus
extern "C" {
#endif
struct _stream_vtable
{
......@@ -75,6 +76,8 @@ struct _stream
#define stream_get_flags(s,f) ((s)->vtable->get_flags)(s,f)
#define stream_get_state(s,f) ((s)->vtable->get_state)(s,f)
__MAILUTILS_END_DECLS
#ifdef __cplusplus
}
#endif
#endif /* _MAILUTILS_SYS_STREAM_H */
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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 <errno.h>
#include <stdlib.h>
#include <mailutils/error.h>
#include <mailutils/sys/list.h>
/* Simple double (circular)link list. We rollup our own because we
need to be thread-safe. */
int
list_create (list_t *plist)
{
list_t list;
int status;
if (plist == NULL)
return EINVAL;
list = calloc (sizeof (*list), 1);
if (list == NULL)
return ENOMEM;
status = monitor_create (&(list->lock));
if (status != 0)
{
free (list);
return status;
}
list->head.next = &(list->head);
list->head.prev = &(list->head);
list->count = 0;
*plist = list;
return 0;
}
int
list_destroy (list_t list)
{
if (list)
{
struct list_data *current;
struct list_data *previous;
monitor_lock (list->lock);
for (current = list->head.next; current != &(list->head);)
{
previous = current;
current = current->next;
free (previous);
}
monitor_unlock (list->lock);
monitor_destroy (list->lock);
free (list);
}
return 0;
}
int
list_append (list_t list, void *item)
{
struct list_data *ldata;
struct list_data *last;
if (list == NULL)
return EINVAL;
last = list->head.prev;
ldata = calloc (sizeof (*ldata), 1);
if (ldata == NULL)
return ENOMEM;
ldata->item = item;
monitor_lock (list->lock);
ldata->next = &(list->head);
ldata->prev = list->head.prev;
last->next = ldata;
list->head.prev = ldata;
list->count++;
monitor_unlock (list->lock);
return 0;
}
int
list_prepend (list_t list, void *item)
{
struct list_data *ldata;
struct list_data *first;
if (list == NULL)
return EINVAL;
first = list->head.next;
ldata = calloc (sizeof (*ldata), 1);
if (ldata == NULL)
return ENOMEM;
ldata->item = item;
monitor_lock (list->lock);
ldata->prev = &(list->head);
ldata->next = list->head.next;
first->prev = ldata;
list->head.next = ldata;
list->count++;
monitor_unlock (list->lock);
return 0;
}
int
list_is_empty (list_t list)
{
size_t n = 0;
list_count (list, &n);
return (n == 0);
}
int
list_count (list_t list, size_t *pcount)
{
if (list == NULL || pcount == NULL)
return EINVAL;
*pcount = list->count;
return 0;
}
int
list_remove (list_t list, void *item)
{
struct list_data *current, *previous;
int status = ENOENT;
if (list == NULL)
return EINVAL;
monitor_lock (list->lock);
for (previous = &(list->head), current = list->head.next;
current != &(list->head); previous = current, current = current->next)
{
if ((int)current->item == (int)item)
{
previous->next = current->next;
current->next->prev = previous;
free (current);
list->count--;
status = 0;
break;
}
}
monitor_unlock (list->lock);
return ENOENT;
}
int
list_get (list_t list, size_t index, void **pitem)
{
struct list_data *current;
size_t count;
int status = ENOENT;
if (list == NULL || pitem == NULL)
return EINVAL;
monitor_lock (list->lock);
for (current = list->head.next, count = 0; current != &(list->head);
current = current->next, count++)
{
if (count == index)
{
*pitem = current->item;
status = 0;
break;
}
}
monitor_unlock (list->lock);
return status;
}
static int l_add_ref __P ((iterator_t));
static int l_release __P ((iterator_t));
static int l_destroy __P ((iterator_t));
static int l_first __P ((iterator_t));
static int l_next __P ((iterator_t));
static int l_current __P ((iterator_t, void *));
static int l_is_done __P ((iterator_t));
static struct _iterator_vtable l_i_vtable =
{
/* Base. */
l_add_ref,
l_release,
l_destroy,
l_first,
l_next,
l_current,
l_is_done
};
int
list_get_iterator (list_t list, iterator_t *piterator)
{
struct l_iterator *l_iterator;
if (list == NULL || piterator == NULL)
return MU_ERROR_INVALID_PARAMETER;
l_iterator = malloc (sizeof *l_iterator);
if (l_iterator == NULL)
return MU_ERROR_NO_MEMORY;
l_iterator->base.vtable = &l_i_vtable;
l_iterator->ref = 1;
l_iterator->list = list;
l_iterator->current = NULL;
monitor_create (&(l_iterator->lock));
*piterator = &l_iterator->base;
return 0;
}
static int
l_add_ref (iterator_t iterator)
{
int status = 0;
struct l_iterator *l_iterator = (struct l_iterator *)iterator;
if (l_iterator)
{
monitor_lock (l_iterator->lock);
status = ++l_iterator->ref;
monitor_unlock (l_iterator->lock);
}
return status;
}
static int
l_release (iterator_t iterator)
{
int status = 0;
struct l_iterator *l_iterator = (struct l_iterator *)iterator;
if (l_iterator)
{
monitor_lock (l_iterator->lock);
status = --l_iterator->ref;
if (status <= 0)
{
monitor_unlock (l_iterator->lock);
l_destroy (iterator);
return 0;
}
monitor_unlock (l_iterator->lock);
}
return status;
}
static int
l_destroy (iterator_t iterator)
{
struct l_iterator *l_iterator = (struct l_iterator *)iterator;
monitor_destroy (l_iterator->lock);
free (l_iterator);
return 0;
}
static int
l_first (iterator_t iterator)
{
struct l_iterator *l_iterator = (struct l_iterator *)iterator;
list_t list = l_iterator->list;
if (list)
{
monitor_lock (list->lock);
l_iterator->current = l_iterator->list->head.next;
monitor_unlock (list->lock);
}
return 0;
}
static int
l_next (iterator_t iterator)
{
struct l_iterator *l_iterator = (struct l_iterator *)iterator;
list_t list = l_iterator->list;
if (list)
{
if (l_iterator->current)
{
monitor_lock (list->lock);
l_iterator->current = l_iterator->current->next;
monitor_unlock (list->lock);
}
else
l_first (iterator);
}
return 0;
}
static int
l_is_done (iterator_t iterator)
{
struct l_iterator *l_iterator = (struct l_iterator *)iterator;
int done = 0;
list_t list = l_iterator->list;
if (list)
{
monitor_lock (list->lock);
done = (l_iterator->current == &(list->head));
monitor_unlock (list->lock);
}
return done;
}
static int
l_current (iterator_t iterator, void *item)
{
struct l_iterator *l_iterator = (struct l_iterator *)iterator;
list_t list = l_iterator->list;
if (list)
{
monitor_lock (list->lock);
if (l_iterator->current)
*((void **)item) = l_iterator->current->item;
else
*((void **)item) = NULL;
monitor_unlock (list->lock);
}
return 0;
}
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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 <errno.h>
#include <stdlib.h>
#include <mailutils/iterator.h>
#include <mailutils/error.h>
#include <mailutils/sys/observer.h>
struct observer_info
{
int type;
observer_t observer;
};
int
observable_create (observable_t *pobservable)
{
observable_t observable;
int status;
if (pobservable == NULL)
return MU_ERROR_INVALID_PARAMETER;
observable = calloc (sizeof (*observable), 1);
if (observable == NULL)
return MU_ERROR_NO_MEMORY;
status = list_create (&(observable->list));
if (status != 0 )
{
free (observable);
return status;
}
*pobservable = observable;
return 0;
}
int
observable_release (observable_t observable)
{
(void)observable;
return 1;
}
int
observable_destroy (observable_t observable)
{
if (observable)
{
iterator_t iterator = NULL;
int status = list_get_iterator (observable->list, &iterator);
if (status == 0)
{
struct observer_info *info;
for (iterator_first (iterator); !iterator_is_done (iterator);
iterator_next (iterator))
{
info = NULL;
iterator_current (iterator, (void **)&info);
if (info)
{
observer_release (info->observer);
free (info);
}
}
iterator_release (iterator);
}
list_destroy (observable->list);
free (observable);
}
return 0;
}
int
observable_attach (observable_t observable, int type, observer_t observer)
{
struct observer_info *info;
if (observable == NULL || observer == NULL)
return MU_ERROR_INVALID_PARAMETER;
info = calloc (1, sizeof *info);
if (info == NULL)
return MU_ERROR_NO_MEMORY;
info->type = type;
info->observer = observer;
return list_append (observable->list, info);
}
int
observable_detach (observable_t observable, observer_t observer)
{
iterator_t iterator = NULL;
int status;
int found = 0;
struct observer_info *info;
if (observable == NULL ||observer == NULL)
return EINVAL;
status = list_get_iterator (observable->list, &iterator);
if (status != 0)
return status;
for (iterator_first (iterator); !iterator_is_done (iterator);
iterator_next (iterator))
{
info = NULL;
iterator_current (iterator, (void **)&info);
if (info && (int)(info->observer) == (int)observer)
{
found = 1;
break;
}
}
iterator_release (iterator);
if (found)
{
status = list_remove (observable->list, info);
free (info);
}
return status;
}
int
observable_notify_all (observable_t observable, struct event evt)
{
iterator_t iterator;
struct observer_info *info;
int status = 0;
if (observable == NULL)
return MU_ERROR_INVALID_PARAMETER;
status = list_get_iterator (observable->list, &iterator);
if (status != 0)
return status;
for (iterator_first (iterator); !iterator_is_done (iterator);
iterator_next (iterator))
{
info = NULL;
iterator_current (iterator, (void **)&info);
if (info && info->type & evt.type)
{
status |= observer_action (info->observer, evt);
}
}
iterator_release (iterator);
return status;
}
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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 <errno.h>
#include <stdlib.h>
#include <mailutils/error.h>
#include <mailutils/sys/observer.h>
int
(observer_add_ref) (observer_t observer)
{
if (observer == NULL || observer->vtable == NULL
|| observer->vtable->add_ref == NULL)
return MU_ERROR_NOT_SUPPORTED;
return observer->vtable->add_ref (observer);
}
int
(observer_release) (observer_t observer)
{
if (observer == NULL || observer->vtable == NULL
|| observer->vtable->release == NULL)
return MU_ERROR_NOT_SUPPORTED;
return observer->vtable->release (observer);
}
int
(observer_destroy) (observer_t observer)
{
if (observer == NULL || observer->vtable == NULL
|| observer->vtable->destroy == NULL)
return MU_ERROR_NOT_SUPPORTED;
return observer->vtable->destroy (observer);
}
int
(observer_action) (observer_t observer, struct event evt)
{
if (observer == NULL || observer->vtable == NULL
|| observer->vtable->action == NULL)
return MU_ERROR_NOT_SUPPORTED;
return observer->vtable->action (observer, evt);
}
static int
_dobserver_add_ref (observer_t observer)
{
struct _dobserver *dobserver = (struct _dobserver *)observer;
int status;
monitor_lock (dobserver->lock);
status = ++dobserver->ref;
monitor_unlock (dobserver->lock);
return status;
}
static int
_dobserver_destroy (observer_t observer)
{
struct _dobserver *dobserver = (struct _dobserver *)observer;
monitor_destroy (dobserver->lock);
free (dobserver);
return 0;
}
static int
_dobserver_release (observer_t observer)
{
int status;
struct _dobserver *dobserver = (struct _dobserver *)observer;
monitor_lock (dobserver->lock);
status = --dobserver->ref;
if (status <= 0)
{
monitor_unlock (dobserver->lock);
return _dobserver_destroy (observer);
}
monitor_unlock (dobserver->lock);
return status;
}
static int
_dobserver_action (observer_t observer, struct event evt)
{
struct _dobserver *dobserver = (struct _dobserver *)observer;
if (dobserver->action)
return dobserver->action (dobserver->arg, evt);
return 0;
}
static struct _observer_vtable _dobserver_vtable =
{
_dobserver_add_ref,
_dobserver_release,
_dobserver_destroy,
_dobserver_action
};
/* Implement a default observer. */
int
observer_create (observer_t *pobserver,
int (*action) (void *arg, struct event), void *arg)
{
struct _dobserver * dobserver;
if (pobserver)
return MU_ERROR_INVALID_PARAMETER;
dobserver = calloc (1, sizeof *dobserver);
if (dobserver)
return MU_ERROR_NO_MEMORY;
dobserver->base.vtable = &_dobserver_vtable;
dobserver->ref = 1;
dobserver->arg = arg;
dobserver->action = action;
monitor_create (&(dobserver->lock));
*pobserver = &dobserver->base;
return 0;
}
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 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. */
/*
Things to consider:
- When parsing phrase, should I ignore non-ascii, or replace with a
'?' character? Right now parsing fails.
- Are comments allowed in domain-literals?
- Need a way to mark the *end* of a group. Maybe add a field to _address,
int group_end;, so if you care, you can search for the end of
a group with address_is_group_end();
- Need a way to parse "<>", it's a valid SMTP address...
- Need a way to parse ",,,", it's a valid address-list, it just doesn't
have any addresses.
- The personal for ""Sam"" <sam@here> is "Sam", and for "'s@b'" <s@b>
is 's@b', should I strip those outside parentheses, or is that
too intrusive? Maybe an apps business if it wants to?
- Should we do best effort parsing, so parsing "sam@locahost, foo@"
gets one address, or just say it is or it isn't in RFC format?
Right now we're strict, we'll see how it goes.
- parse Received: field?
- test for memory leaks on malloc failure
- fix the realloc, try a struct _string { char* b, size_t sz };
The lexer finds consecutive sequences of characters, so it should
define:
struct parse822_token_t {
const char* b; // beginning of token
const char* e; // one past end of token
}
typedef struc parse822_token_t TOK;
Then I can have str_append_token(), and the lexer functions can
look like:
int parse822_atom(const char** p, const char* e, TOK* atom);
Just a quick though, I'll have to see how many functions that will
actually help.
- get example addresses from rfc2822, and from the perl code.
*/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <assert.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <mailutils/sys/address.h>
#include <mailutils/parse822.h>
#ifdef EOK
# undef EOK
#endif
#define EOK 0
#define EPARSE ENOENT
/*
* Some convenience functions for dealing with dynamically re-sized
* strings.
*/
static int str_append_n(char** to, const char* from, size_t n)
{
size_t l = 0;
/* if not to, then silently discard data */
if(!to) {
return EOK;
}
if(*to) {
char* bigger;
l = strlen(*to);
bigger = realloc(*to, l + n + 1);
if(!bigger) {
return ENOMEM;
}
*to = bigger;
} else {
*to = malloc(n + 1);
}
strncpy(&to[0][l], from, n);
/* strncpy is lame, nul terminate our buffer */
to[0][l + n] = 0;
return EOK;
}
static int str_append(char** to, const char* from)
{
return str_append_n(to, from, strlen(from));
}
static int str_append_char(char** to, char c)
{
return str_append_n(to, &c, 1);
}
static int str_append_range(char** to, const char* b, const char* e)
{
return str_append_n(to, b, e - b);
}
static void str_free(char** s)
{
if(s && *s) {
free(*s);
*s = 0;
}
}
/*
* Character Classification - could be rewritten in a C library
* independent way, my system's C library matches the RFC
* definitions. I don't know if that's guaranteed.
*
* Note that all return values are:
* 1 -> TRUE
* 0 -> FALSE
* This may be appear different than the 0 == success return
* values of the other functions, but I was getting lost in
* boolean arithmetic.
*/
int parse822_is_char(char c)
{
return isascii(c);
}
int parse822_is_digit(char c)
{
/* digit = <any ASCII decimal digit> */
return isdigit((unsigned)c);
}
int parse822_is_ctl(char c)
{
return iscntrl((unsigned)c) || c == 127 /* DEL */;
}
int parse822_is_space(char c)
{
return c == ' ';
}
int parse822_is_htab(char c)
{
return c == '\t';
}
int parse822_is_lwsp_char(char c)
{
return parse822_is_space(c) || parse822_is_htab(c);
}
int parse822_is_special(char c)
{
return strchr("()<>@,;:\\\".[]", c) ? 1 : 0;
}
int parse822_is_atom_char(char c)
{
return
parse822_is_char(c) &&
!parse822_is_special(c) &&
!parse822_is_space(c) &&
!parse822_is_ctl(c)
;
}
int parse822_is_q_text(char c)
{
return
parse822_is_char(c)
&& c != '"'
&& c != '\\'
&& c != '\r'
;
}
int parse822_is_d_text(char c)
{
return
parse822_is_char(c)
&& c != '['
&& c != ']'
&& c != '\\'
&& c != '\r'
;
}
/*
* SMTP's version of qtext, called <q> in the RFC 821 syntax,
* also excludes <LF>.
*/
int parse822_is_smtp_q(char c)
{
return parse822_is_q_text(c)
&& c != '\n';
}
/***** From RFC 822, 3.3 Lexical Tokens *****/
int parse822_skip_nl(const char** p, const char* e)
{
/* Here we consider a new-line (NL) to be either a bare LF, or
* a CRLF pair as required by the RFC.
*/
const char* s = *p;
if(
(&s[1] < e) &&
s[0] == '\r' &&
s[1] == '\n'
)
{
*p += 2;
return EOK;
}
if(
(&s[0] < e) &&
s[0] == '\n'
)
{
*p += 1;
return EOK;
}
return EPARSE;
}
int parse822_skip_lwsp_char(const char** p, const char* e)
{
if(*p < e && parse822_is_lwsp_char(**p)) {
*p += 1;
return EOK;
}
return EPARSE;
}
int parse822_skip_lwsp(const char** p, const char* e)
{
/*
* linear-white-space = 1*([[CR]LF] LWSP-char)
*
* We interpret a bare LF as identical to the canonical CRLF
* line ending, I don't know another way since on a Unix system
* all CRLF will be translated to the local convention, a bare
* LF, and thus we can not deal with bare NLs in the message.
*/
int space = 0;
while(*p != e) {
const char* save = *p;
if(parse822_skip_lwsp_char(p, e) == EOK) {
space = 1;
continue;
}
if(parse822_skip_nl(p, e) == EOK) {
if(parse822_skip_lwsp_char(p, e) == EOK) {
continue;
}
*p = save;
return EPARSE;
}
break;
}
return space ? EOK : EPARSE;
}
int parse822_skip_comments(const char** p, const char* e)
{
int status;
while((status = parse822_comment(p, e, 0)) == EOK)
;
return EOK;
}
int parse822_digits(const char** p, const char* e,
int min, int max, int* digits)
{
const char* save = *p;
int i = 0;
assert(digits);
*digits = 0;
while(*p < e && parse822_is_digit(**p)) {
*digits = *digits * 10 + **p - '0';
*p += 1;
++i;
if(max != 0 && i == max) {
break;
}
}
if(i < min) {
*p = save;
return EPARSE;
}
return EOK;
}
int parse822_special(const char** p, const char* e, char c)
{
parse822_skip_lwsp(p, e); /* not comments, they start with a special... */
if((*p != e) && **p == c) {
*p += 1;
return EOK;
}
return EPARSE;
}
int parse822_comment(const char** p, const char* e, char** comment)
{
/* comment = "(" *(ctext / quoted-pair / comment) ")"
* ctext = <any char except "(", ")", "\", & CR, including lwsp>
*/
const char* save = *p;
int rc;
if((rc = parse822_special(p, e, '('))) {
return rc;
}
while(*p != e) {
char c = **p;
if(c == ')') {
*p += 1;
return EOK; /* found end-of-comment */
} else if(c == '(') {
rc = parse822_comment(p, e, comment);
} else if(c == '\\') {
rc = parse822_quoted_pair(p, e, comment);
} else if(c == '\r') {
/* invalid character... */
*p += 1;
} else if(parse822_is_char(c)) {
rc = str_append_char(comment, c);
*p += 1;
} else {
/* invalid character... */
*p += 1;
}
if(rc != EOK)
break;
}
if(*p == e) {
rc = EPARSE; /* end-of-comment not found */
}
*p = save;
assert(rc != EOK);
return rc;
}
int parse822_atom(const char** p, const char* e, char** atom)
{
/* atom = 1*<an atom char> */
const char* save = *p;
int rc = EPARSE;
parse822_skip_comments(p, e);
save = *p;
while((*p != e) && parse822_is_atom_char(**p))
{
rc = str_append_char(atom, **p);
*p += 1;
if(rc != EOK) {
*p = save;
break;
}
}
return rc;
}
int parse822_quoted_pair(const char** p, const char* e, char** qpair)
{
/* quoted-pair = "\" char */
int rc;
/* need TWO characters to be available */
if((e - *p) < 2)
return EPARSE;
if(**p != '\\')
return EPARSE;
if((rc = str_append_char(qpair, *(*p + 1))))
return rc;
*p += 2;
return EOK;
}
int parse822_quoted_string(const char** p, const char* e, char** qstr)
{
/* quoted-string = <"> *(qtext/quoted-pair) <">
* qtext = char except <">, "\", & CR, including lwsp-char
*/
const char* save = *p;
int rc;
parse822_skip_comments(p, e);
save = *p;
if((rc = parse822_special(p, e, '"')))
return rc;
while(*p != e)
{
char c = **p;
if(c == '"') {
*p += 1;
return EOK; /* found end-of-qstr */
} else if(c == '\\') {
rc = parse822_quoted_pair(p, e, qstr);
} else if(c == '\r') {
/* invalid character... */
*p += 1;
} else if(parse822_is_char(c)) {
rc = str_append_char(qstr, c);
*p += 1;
} else {
/* invalid character... */
*p += 1;
}
if(rc) {
*p = save;
return rc;
}
}
*p = save;
return EPARSE; /* end-of-qstr not found */
}
int parse822_word(const char** p, const char* e, char** word)
{
/* word = atom / quoted-string */
const char* save = *p;
int rc = EOK;
parse822_skip_comments(p, e);
save = *p;
{
char* qstr = 0;
if((rc = parse822_quoted_string(p, e, &qstr)) == EOK) {
rc = str_append(word, qstr);
str_free(&qstr);
if(rc != EOK)
*p = save;
return rc;
}
}
if(rc != EPARSE) {
/* it's fatal */
return rc;
}
/* Necessary because the quoted string could have found
* a partial string (invalid syntax). Thus reset, the atom
* will fail to if the syntax is invalid.
*/
{
char* atom = 0;
if(parse822_atom(p, e, &atom) == EOK) {
rc = str_append(word, atom);
str_free(&atom);
if(rc != EOK)
*p = save;
return rc;
}
}
return EPARSE;
}
int parse822_phrase(const char** p, const char* e, char** phrase)
{
/* phrase = 1*word */
const char* save = *p;
int rc;
if((rc = parse822_word(p, e, phrase)))
return rc;
/* ok, got the 1 word, now append all the others we can */
{
char* word = 0;
while((rc = parse822_word(p, e, &word)) == EOK) {
rc = str_append_char(phrase, ' ');
if(rc == EOK)
rc = str_append(phrase, word);
str_free(&word);
if(rc != EOK)
break;
}
if(rc == EPARSE)
rc = EOK; /* its not an error to find no more words */
}
if(rc)
*p = save;
return rc;
}
/***** From RFC 822, 6.1 Address Specification Syntax *****/
static address_t new_mb(void) {
return calloc(1, sizeof(struct _address));
}
static int fill_mb(
address_t* a,
char* comments, char* personal, char* local, char* domain)
{
int rc = EOK;
*a = new_mb();
if(!*a) {
return ENOMEM;
}
(*a)->comments = comments;
(*a)->personal = personal;
do {
/* loop exists only to break out of */
if(!local || !domain) {
/* no email to construct */
break;
}
if((rc = parse822_quote_local_part(&(*a)->email, local)))
break;
if((rc = str_append(&(*a)->email, "@")))
break;
if((rc = str_append(&(*a)->email, domain)))
break;
} while(0);
(*a)->local_part = local;
(*a)->domain = domain;
if(rc != EOK) {
/* note that the arguments have NOT been freed, we only own
* them on success. */
free(*a);
}
return rc;
}
int parse822_address_list(address_t* a, const char* s)
{
/* address-list = #(address) */
const char** p = &s;
const char* e = &s[strlen(s)];
int rc = EOK;
address_t* n = a; /* the next address we'll be creating */
rc = parse822_address(p, e, n);
/* A list may start with a leading <,>, we'll find out if
* that's not the case at the top of the while, but give
* this a conditional OK unless there was some other kind
* of error.
*/
if(rc != EOK && rc != EPARSE) {
return rc;
}
while(*p < e)
{
parse822_skip_comments(p, e);
/* An address can contain a group, so an entire
* list of addresses may have been appended, or no
* addresses at all. Walk to the end.
*/
while(*n) {
n = &(*n)->next;
}
/* Remember that ',,a@b' is a valid list! So, we must find
* the <,>, but the address after it can be empty.
*/
if((rc = parse822_special(p, e, ','))) {
break;
}
parse822_skip_comments(p, e);
rc = parse822_address(p, e, n);
if(rc == EOK || rc == EPARSE) {
/* that's cool, it may be a <,>, we'll find out if it isn't
* at the top of the loop
*/
rc = EOK;
} else {
/* anything else is a fatal error, break out */
break;
}
}
if(rc) {
address_destroy(*a);
}
return rc;
}
int parse822_address(const char** p, const char* e, address_t* a)
{
/* address = mailbox / group / unix-mbox */
int rc;
if((rc = parse822_mail_box(p, e, a)) == EPARSE) {
if((rc = parse822_group(p, e, a)) == EPARSE) {
rc = parse822_unix_mbox(p, e, a);
}
}
return rc;
}
int parse822_group(const char** p, const char* e, address_t* a)
{
/* group = phrase ":" [#mailbox] ";" */
const char* save = *p;
address_t* asave = a; /* so we can destroy these if parsing fails */
int rc;
char* phrase = 0;
parse822_skip_comments(p, e);
*p = save;
if((rc = parse822_phrase(p, e, &phrase))) {
return rc;
}
parse822_skip_comments(p, e);
if((rc = parse822_special(p, e, ':'))) {
*p = save;
return rc;
}
/* fake up an address node for the group's descriptive phrase, if
* it fails, clean-up will happen after the loop
*/
if((rc = fill_mb(a, 0, phrase, 0, 0)) == EOK) {
a = &(*a)->next;
} else {
str_free(&phrase);
}
/* Basically, on each loop, we may find a mailbox, but we must find
* a comma after the mailbox, otherwise we've popped off the end
* of the list.
*/
while(!rc) {
parse822_skip_comments(p, e);
/* it's ok not be a mailbox, but other errors are fatal */
rc = parse822_mail_box(p, e, a);
if(rc == EOK) {
a = &(*a)->next;
parse822_skip_comments(p, e);
} else if(rc != EPARSE) {
break;
}
if((rc = parse822_special(p, e, ','))) {
/* the commas aren't optional */
break;
}
}
if(rc == EPARSE) {
rc = EOK; /* ok, as long as we find the ";" next */
}
if(rc || (rc = parse822_special(p, e, ';'))) {
*p = save;
address_destroy(*asave);
}
return rc;
}
int parse822_mail_box(const char** p, const char* e, address_t* a)
{
/* mailbox =
* addr-spec [ "(" comment ")" ] /
* [phrase] route-addr
*
* Note: we parse the ancient comment on the right since
* it's such "common practice". :-(
* Note: phrase is called display-name in drums.
* Note: phrase is optional in drums, though not in RFC 822.
*/
const char* save = *p;
int rc;
/* -> addr-spec */
if((rc = parse822_addr_spec(p, e, a)) == EOK) {
parse822_skip_lwsp(p, e);
/* yuck. */
if((rc = parse822_comment(p, e, &(*a)->personal)) == EPARSE) {
rc = EOK;
/* cool if there's no comment, */
}
/* but if something else is wrong, destroy the address */
if(rc) {
address_destroy(*a);
*p = save;
}
return rc;
}
/* -> phrase route-addr */
{
char* phrase = 0;
rc = parse822_phrase(p, e, &phrase);
if(rc != EPARSE && rc != EOK) {
return rc;
}
if((rc = parse822_route_addr(p, e, a)) == EOK) {
/* add the phrase */
(*a)->personal = phrase;
return EOK;
} else if(rc != EPARSE) {
/* some internal error, fail out */
*p = save;
str_free(&phrase);
return rc;
}
*p = save;
return rc;
}
return rc;
}
int parse822_route_addr(const char** p, const char* e, address_t* a)
{
/* route-addr = "<" [route] addr-spec ">" */
const char* save = *p;
char* route = 0;
int rc;
parse822_skip_comments(p, e);
if((rc = parse822_special(p, e, '<'))) {
*p = save;
return rc;
}
parse822_route(p, e, &route);
if((rc = parse822_addr_spec(p, e, a))) {
*p = save;
str_free(&route);
return rc;
}
(*a)->route = route; /* now we don't have to free our local */
parse822_skip_comments(p, e);
if((rc = parse822_special(p, e, '>'))) {
*p = save;
address_destroy(*a);
return rc;
}
return EOK;
}
int parse822_route(const char** p, const char* e, char** route)
{
/* route = 1#("@" domain ) ":" */
const char* save = *p;
char* accumulator = 0;
int rc = EOK;
for(;;) {
parse822_skip_comments(p, e);
if((rc = parse822_special(p, e, '@'))) {
break;
}
if((rc = str_append(&accumulator, "@"))) {
break;
}
parse822_skip_comments(p, e);
if((rc = parse822_domain(p, e, &accumulator))) {
/* it looked like a route, but there's no domain! */
break;
}
parse822_skip_comments(p, e);
if((rc = parse822_special(p, e, ',')) == EPARSE) {
/* no more routes, but we got one so its ok */
rc = EOK;
break;
}
if((rc = str_append(&accumulator, ", "))) {
break;
}
}
parse822_skip_comments(p, e);
if(!rc) {
rc = parse822_special(p, e, ':');
}
if(!rc) {
rc = str_append(route, accumulator);
}
if(rc) {
str_free(&accumulator);
*p = save;
}
return rc;
}
int parse822_addr_spec(const char** p, const char* e, address_t* a)
{
/* addr-spec = local-part "@" domain */
const char* save = *p;
char* local_part = 0;
char* domain = 0;
int rc;
rc = parse822_local_part(p, e, &local_part);
parse822_skip_comments(p, e);
if(!rc) {
rc = parse822_special(p, e, '@');
}
if(!rc) {
rc = parse822_domain(p, e, &domain);
}
if(!rc) {
rc = fill_mb(a, 0, 0, local_part, domain);
}
if(rc) {
*p = save;
str_free(&local_part);
str_free(&domain);
}
return rc;
}
int parse822_unix_mbox(const char** p, const char* e, address_t* a)
{
/* unix-mbox = atom */
const char* save = *p;
char* mbox = 0;
int rc;
parse822_skip_comments(p, e);
rc = parse822_atom(p, e, &mbox);
if(!rc) {
rc = fill_mb(a, 0, 0, mbox, 0);
}
if(rc) {
*p = save;
str_free(&mbox);
}
return rc;
}
int parse822_local_part(const char** p, const char* e, char** local_part)
{
/* local-part = word *("." word)
*
* Note: rewrite as -> word ["." local-part]
*/
const char* save = *p;
const char* save2 = *p;
int rc;
parse822_skip_comments(p, e);
if((rc = parse822_word(p, e, local_part))) {
*p = save;
return rc;
}
/* We've got a local-part, but keep looking for more. */
parse822_skip_comments(p, e);
/* If we get a parse error, we roll back to save2, but if
* something else failed, we have to roll back to save.
*/
save2 = *p;
rc = parse822_special(p, e, '.');
if(!rc) {
char* more = 0;
if((rc = parse822_local_part(p, e, &more)) == EOK) {
/* append more */
if((rc = str_append(local_part, ".")) == EOK) {
rc = str_append(local_part, more);
}
str_free(&more);
}
}
if(rc == EPARSE) {
/* if we didn't get more ("." word) pairs, that's ok */
*p = save2;
rc = EOK;
}
if(rc) {
/* if anything else failed, that's real */
*p = save;
str_free(local_part);
}
return rc;
}
int parse822_domain(const char** p, const char* e, char** domain)
{
/* domain = sub-domain *("." sub-domain)
*
* Note: rewrite as -> sub-domain ("." domain)
*/
const char* save = *p;
const char* save2 = 0;
int rc;
parse822_skip_comments(p, e);
if((rc = parse822_sub_domain(p, e, domain))) {
*p = save;
return rc;
}
/* We save before skipping comments to preserve the comment
* at the end of a domain, the addr-spec may want to abuse it
* for a personal name.
*/
save2 = *p;
/* we've got the 1, keep looking for more */
parse822_skip_comments(p, e);
rc = parse822_special(p, e, '.');
if(!rc) {
char* more = 0;
if((rc = parse822_domain(p, e, &more)) == EOK) {
if((rc = str_append(domain, ".")) == EOK) {
rc = str_append(domain, more);
}
str_free(&more);
}
}
if(rc == EPARSE) {
/* we didn't parse more ("." sub-domain) pairs, that's ok */
*p = save2;
rc = EOK;
}
if(rc) {
/* something else failed, roll it all back */
*p = save;
str_free(domain);
}
return rc;
}
int parse822_sub_domain(const char** p, const char* e, char** sub_domain)
{
/* sub-domain = domain-ref / domain-literal
*/
int rc;
if((rc = parse822_domain_ref(p, e, sub_domain)) == EPARSE)
rc = parse822_domain_literal(p, e, sub_domain);
return rc;
}
int parse822_domain_ref(const char** p, const char* e, char** domain_ref)
{
/* domain-ref = atom */
return parse822_atom(p, e, domain_ref);
}
int parse822_d_text(const char** p, const char* e, char** dtext)
{
/* d-text = 1*dtext
*
* Note: dtext is only defined as a character class in
* RFC822, but this definition is more useful for
* slurping domain literals.
*/
const char* start = *p;
int rc = EOK;
while(*p < e && parse822_is_d_text(**p)) {
*p += 1;
}
if(start == *p) {
return EPARSE;
}
if((rc = str_append_range(dtext, start, *p))) {
*p = start;
}
return rc;
}
int parse822_domain_literal(const char** p, const char* e, char** domain_literal)
{
/* domain-literal = "[" *(dtext / quoted-pair) "]" */
const char* save = *p;
char* literal = 0;
int rc;
if((rc = parse822_special(p, e, '['))) {
return rc;
}
if((rc = str_append_char(&literal, '['))) {
*p = save;
return rc;
}
while(
(rc = parse822_d_text(p, e, &literal)) == EOK ||
(rc = parse822_quoted_pair(p, e, &literal)) == EOK
) {
/* Eat all of this we can get! */
}
if(rc == EPARSE) {
rc = EOK;
}
if(!rc) {
rc = parse822_special(p, e, ']');
}
if(!rc) {
rc = str_append_char(&literal, ']');
}
if(!rc) {
rc = str_append(domain_literal, literal);
}
str_free(&literal);
if(rc) {
*p = save;
}
return rc;
}
/***** From RFC 822, 5.1 Date and Time Specification Syntax *****/
int parse822_day(const char** p, const char* e, int* day)
{
/* day = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun" */
const char* days[] = {
"Mon",
"Tue",
"Wed",
"Thu",
"Fri",
"Sat",
"Sun",
NULL
};
int d;
parse822_skip_comments(p, e);
if((e - *p) < 3)
return EPARSE;
for(d = 0; days[d]; d++) {
if(strncasecmp(*p, days[d], 3) == 0) {
*p += 3;
if(day)
*day = d;
return EOK;
}
}
return EPARSE;
}
int parse822_date(const char** p, const char* e, int* day, int* mon, int* year)
{
/* date = 1*2DIGIT month 2*4DIGIT
* month = "Jan" / "Feb" / "Mar" / "Apr"
* / "May" / "Jun" / "Jul" / "Aug"
* / "Sep" / "Oct" / "Nov" / "Dec"
*/
const char* mons[] = {
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec",
NULL
};
const char* save = *p;
int rc = EOK;
int m = 0;
int yr = 0;
const char* yrbeg = 0;
parse822_skip_comments(p, e);
if((rc = parse822_digits(p, e, 1, 2, day))) {
*p = save;
return rc;
}
parse822_skip_comments(p, e);
if((e - *p) < 3)
return EPARSE;
for(m = 0; mons[m]; m++) {
if(strncasecmp(*p, mons[m], 3) == 0) {
*p += 3;
if(mon)
*mon = m;
break;
}
}
if(!mons[m]) {
*p = save;
return EPARSE;
}
parse822_skip_comments(p, e);
/* We need to count how many digits their were, and adjust the
* interpretation of the year accordingly. This is from RFC 2822,
* Section 4.3, Obsolete Date and Time. */
yrbeg = *p;
if((rc = parse822_digits(p, e, 2, 4, &yr))) {
*p = save;
return rc;
}
/* rationalize year to four digit, then adjust to tz notation */
switch(*p - yrbeg)
{
case 2:
if(yr >= 0 && yr <= 49) {
yr += 2000;
break;
}
case 3:
yr += 1900;
break;
}
if(year)
*year = yr - 1900;
return EOK;
}
int parse822_time(const char** p, const char* e,
int* hour, int* min, int* sec, int* tz, const char** tz_name)
{
/* time = hour zone
* hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] ; 00:00:00 - 23:59:59
* zone = "UT" / "GMT" ; Universal Time
* ; North American : UT
* / "EST" / "EDT" ; Eastern: - 5/ - 4
* / "CST" / "CDT" ; Central: - 6/ - 5
* / "MST" / "MDT" ; Mountain: - 7/ - 6
* / "PST" / "PDT" ; Pacific: - 8/ - 7
* / 1ALPHA ; RFC 822 was wrong, RFC 2822
* ; says treat these all as -0000.
* / ( ("+" / "-") 4DIGIT ) ; Local differential
* ; hours+min. (HHMM)
*/
struct {
const char* tzname;
int tz;
} tzs[] = {
{ "UT", 0 * 60 * 60 },
{ "UTC", 0 * 60 * 60 },
{ "GMT", 0 * 60 * 60 },
{ "EST", -5 * 60 * 60 },
{ "EDT", -4 * 60 * 60 },
{ "CST", -6 * 60 * 60 },
{ "CDT", -5 * 60 * 60 },
{ "MST", -7 * 60 * 60 },
{ "MDT", -6 * 60 * 60 },
{ "PST", -8 * 60 * 60 },
{ "PDT", -7 * 60 * 60 },
{ NULL, 0 }
};
const char* save = *p;
int rc = EOK;
int z = 0;
char* zone = NULL;
parse822_skip_comments(p, e);
if((rc = parse822_digits(p, e, 1, 2, hour))) {
*p = save;
return rc;
}
if((rc = parse822_special(p, e, ':'))) {
*p = save;
return rc;
}
if((rc = parse822_digits(p, e, 1, 2, min))) {
*p = save;
return rc;
}
if((rc = parse822_special(p, e, ':'))) {
*sec = 0;
} else if((rc = parse822_digits(p, e, 1, 2, sec))) {
*p = save;
return rc;
}
parse822_skip_comments(p, e);
if((rc = parse822_atom(p, e, &zone))) {
/* zone is optional */
if(tz)
*tz = 0;
return EOK;
}
/* see if it's a timezone */
for( ; tzs[z].tzname; z++) {
if(strcasecmp(zone, tzs[z].tzname) == 0)
break;
}
if(tzs[z].tzname) {
if(tz_name)
*tz_name = tzs[z].tzname;
if(tz)
*tz = tzs[z].tz;
} else if(strlen(zone) > 5 || strlen(zone) < 4) {
str_free(&zone);
return EPARSE;
} else {
/* zone = ( + / - ) hhmm */
int hh;
int mm;
int sign;
char* zp = zone;
switch(zp[0])
{
case '-': sign = -1; zp++; break;
case '+': sign = +1; zp++; break;
default: sign = 1; break;
}
if(strspn(zp, "0123456789") != 4) {
*p = save;
str_free(&zone);
return EPARSE;
}
/* convert to seconds from UTC */
hh = (zone[1] - '0') * 10 + (zone[2] - '0');
mm = (zone[3] - '0') * 10 + (zone[4] - '0');
if(tz)
*tz = sign * (hh * 60 * 60 + mm * 60);
}
str_free(&zone);
return EOK;
};
#if 0
For reference, especially the for the required range and values of the
integer fields.
struct tm
{
int tm_sec; /* Seconds. [0-60] (1 leap second) */
int tm_min; /* Minutes. [0-59] */
int tm_hour; /* Hours. [0-23] */
int tm_mday; /* Day. [1-31] */
int tm_mon; /* Month. [0-11] */
int tm_year; /* Year - 1900. */
int tm_wday; /* Day of week. [0-6] */
int tm_yday; /* Days in year.[0-365] */
int tm_isdst; /* DST. [-1/0/1]*/
int tm_gmtoff; /* Seconds east of UTC. */
const char *tm_zone; /* Timezone abbreviation. */
};
#endif
int parse822_date_time(const char** p, const char* e, struct tm* tm, struct mu_timezone* tz)
{
/* date-time = [ day "," ] date time */
const char* save = *p;
int rc = 0;
int wday = 0;
int mday = 0;
int mon = 0;
int year = 0;
int hour = 0;
int min = 0;
int sec = 0;
int tzoffset = 0;
const char* tz_name = 0;
if((rc = parse822_day(p, e, &wday))) {
if(rc != EPARSE)
return rc;
} else {
/* If we got a day, we MUST have a ','. */
parse822_skip_comments(p, e);
if((rc = parse822_special(p, e, ','))) {
*p = save;
return rc;
}
}
if((rc = parse822_date(p, e, &mday, &mon, &year))) {
*p = save;
return rc;
}
if((rc = parse822_time(p, e, &hour, &min, &sec, &tzoffset, &tz_name))) {
*p = save;
return rc;
}
if(tm) {
memset (tm, 0, sizeof (*tm));
tm->tm_wday = wday;
tm->tm_mday = mday;
tm->tm_mon = mon;
tm->tm_year = year;
tm->tm_hour = hour;
tm->tm_min = min;
tm->tm_sec = sec;
#ifdef HAVE_TM_ISDST
tm->tm_isdst = -1; /* unknown whether it's dst or not */
#endif
#ifdef HAVE_TM_GMTOFF
tm->tm_gmtoff = tzoffset;
#endif
#ifdef HAVE_TM_ZONE
tm->tm_zone = tz_name;
#endif
}
if(tz)
{
tz->utc_offset = tzoffset;
tz->tz_name = tz_name;
}
return EOK;
}
/***** From RFC 822, 3.2 Header Field Definitions *****/
int parse822_field_name(const char** p, const char* e, char** fieldname)
{
/* field-name = 1*<any char, excluding ctlS, space, and ":"> ":" */
const char *save = *p;
char *fn = NULL;
while(*p != e) {
char c = **p;
if(!parse822_is_char(c))
break;
if(parse822_is_ctl(c))
break;
if(parse822_is_space(c))
break;
if(c == ':')
break;
str_append_char(&fn, c);
*p += 1;
}
/* must be at least one char in the field name */
if(!fn) {
*p = save;
return EPARSE;
}
parse822_skip_comments(p, e);
if(!parse822_special(p, e, ':')) {
*p = save;
if (fn)
free (fn);
return EPARSE;
}
*fieldname = fn;
return EOK;
}
int parse822_field_body(const char **p, const char *e, char** fieldbody)
{
/* field-body = *text [CRLF lwsp-char field-body] */
/*const char *save = *p; */
char *fb = NULL;
for(;;)
{
const char *eol = *p;
while(eol != e) {
/*char c = *eol; */
if(eol[0] == '\r' && (eol+1) != e && eol[1] == '\n')
break;
++eol;
}
str_append_range(&fb, *p, eol);
*p = eol;
if(eol == e)
break; /* no more, so we're done */
/*assert(p[0] == '\r'); */
/*assert(p[1] == '\n'); */
*p += 2;
if(*p == e)
break; /* no more, so we're done */
/* check if next line is a continuation line */
if(**p != ' ' && **p != '\t')
break;
}
*fieldbody = fb;
return EOK;
}
/***** RFC 822 Quoting Functions *****/
int parse822_quote_string(char** quoted, const char* raw)
{
/* quoted-string = <"> *(qtext/quoted-pair) <">
*
* So double quote the string, and back quote anything that
* isn't qtext.
*/
int rc = EOK;
const char* s;
if(!raw || !quoted || *quoted) {
return EINVAL;
}
s = raw;
rc = str_append_char(quoted, '"');
while(!rc && *s) {
if(!parse822_is_q_text(*s)) {
rc = str_append_char(quoted, '\\');
}
if(!rc) {
rc = str_append_char(quoted, *s);
}
++s;
}
if(!rc) {
rc = str_append_char(quoted, '"');
}
if(rc) {
str_free(quoted);
}
return rc;
}
int parse822_quote_local_part(char** quoted, const char* raw)
{
/* local-part = word * ("." word)
* word = atom / quoted-string
*
* So, if any character isn't a "." or an atom character, we quote
* the whole thing as a string, for simplicity, otherwise just
* copy it.
*/
const char* s = 0;
if(!raw || !quoted || *quoted) {
return EINVAL;
}
s = raw;
while(*s) {
if(*s != '.' && !parse822_is_atom_char(*s)) {
return parse822_quote_string(quoted, raw);
}
++s;
}
/* if we don't have to quote it, just copy it over */
return str_append(quoted, raw);
}