Commit 0d65dd09 0d65dd09b50588c3546bfe2a4131bd10fdd77a8f by Alain Magloire

Another big change we're trying, for the future to be able to load

via dlopen() different type of mailboxes and mailer.  For that
the client must register the mailbox.  So in the future
we can have something like plugin  ... still a hack/draft.

Commited some code to be able to send mail with sendmail or
via SMTP.
1 parent 9924892e
......@@ -145,41 +145,61 @@ int message_save_attachment(message_t msg, const char *filename, void **data)
if ( ret == 0 && ( ret = _attachment_setup( &info, msg, &stream, data) ) != 0 )
return ret;
if ( ret != EAGAIN && info )
_attachment_free(info, ret);
return ret;
}
#if 0
int message_encapsulate(message_t msg, message_t *newmsg, void **data)
{
stream_t stream;
char *header;
stream_t istream, ostream;
const char *header;
struct _msg_info *info = NULL;
int ret;
int ret = 0;
size_t nbytes;
body_t body;
if ( msg == NULL || newmsg == NULL)
return EINVAL;
if ( ( ret = message_create(&(info->msg), NULL) ) == 0 ) {
if ( ( ret = _attachment_setup( &info, msg, &ostream, data) ) != 0 )
return ret;
if ( info->msg == NULL && ( ret = message_create(&(info->msg), NULL) ) == 0 ) {
header = "Content-Type: message/rfc822\nContent-Transfer-Encoding: 7bit\n\n";
if ( ( ret = header_create( &(info->hdr), header, strlen(header), msg ) ) == 0 ) {
message_set_header(info->msg, info->hdr, NULL);
if ( ( ret = header_create( &(info->hdr), header, strlen(header), msg ) ) == 0 )
ret = message_set_header(info->msg, info->hdr, NULL);
}
if ( ret == 0 && ( ret = message_get_stream(msg, &istream ) ) == 0 ) {
if ( ( ret = message_get_body(info->msg, &body) ) == 0 &&
( ret = body_get_stream(body, &ostream) ) == 0 ) {
if ( info->nbytes )
memmove( info->buf, info->buf + (BUF_SIZE - info->nbytes), info->nbytes);
while ( (ret == 0 && info->nbytes) || ( ( ret = stream_read(istream, info->buf, BUF_SIZE, info->ioffset, &info->nbytes) ) == 0 && info->nbytes ) ) {
info->ioffset += info->nbytes;
while( info->nbytes ) {
if ( ( ret = stream_write(ostream, info->buf, info->nbytes, info->ooffset, &nbytes ) ) != 0 )
break;
info->nbytes -= nbytes;
info->ooffset += nbytes;
}
}
}
}
if ( ret == 0 )
*newmsg = info->msg;
if ( ret != EAGAIN && info )
_attachment_free(info, ret);
return ret;
}
#endif
/* If the message interface parsed headers on write this would be easy */
int message_unencapsulate(message_t msg, message_t *newmsg, void **data)
{
size_t size, nbytes;
int ret = 0, header_done = 0;
char *content_type, *cp;
int ret = 0;
char *content_type;
header_t hdr;
body_t body;
stream_t istream, ostream;
struct _msg_info *info = NULL;
......@@ -190,60 +210,22 @@ int message_unencapsulate(message_t msg, message_t *newmsg, void **data)
header_get_value(hdr, "Content-Type", NULL, 0, &size);
if ( size ) {
if ( ( content_type = alloca(size+1) ) == NULL )
ret = ENOMEM;
return ENOMEM;
header_get_value(hdr, "Content-Type", content_type, size+1, 0);
if ( strncasecmp(content_type, "message/rfc822", strlen(content_type)) != 0 )
ret = EINVAL;
return EINVAL;
} else
return EINVAL;
}
if ( ret == 0 && ( ret = _attachment_setup( &info, msg, &istream, data) ) != 0 )
if ( ( ret = _attachment_setup( &info, msg, &istream, data) ) != 0 )
return ret;
if ( ret == 0 && info->hdr == NULL ) {
while ( !header_done && ( ret = stream_read(istream, info->buf, BUF_SIZE, info->ioffset, &info->nbytes) ) == 0 && info->nbytes ) {
cp = info->buf;
while ( info->nbytes && !header_done ) {
info->line[info->line_ndx] = *cp;
info->line_ndx++;
if ( *cp == '\n' ) {
if ( info->header_len + info->line_ndx > info->header_size) {
char *nhb;
if ( ( nhb = realloc( info->header_buf, info->header_len + info->line_ndx + 128 ) ) == NULL ) {
header_done = 1;
ret = ENOMEM;
break;
}
info->header_buf = nhb;
info->header_size = info->header_len + info->line_ndx + 128;
}
info->header_len += info->line_ndx;
memcpy(info->header_buf, info->line, info->line_ndx);
if ( info->line_ndx == 1 ) {
header_done = 1;
break;
}
info->line_ndx = 0;
}
if ( info->line_ndx == MAX_HDR_LEN ) /* prevent overflow */
info->line_ndx--;
info->ioffset++;
info->nbytes--;
cp++;
}
}
}
if ( ret == 0 && info->msg == NULL ) {
if ( ( ret = message_create(&(info->msg), NULL) ) == 0)
if ( ( ret = header_create(&(info->hdr), info->header_buf, info->header_len, info->msg) ) == 0 )
ret = message_set_header(info->msg, hdr, NULL);
}
if ( info->msg == NULL )
ret = message_create(&(info->msg), NULL);
if ( ret == 0 ) {
message_get_body(info->msg, &body);
body_get_stream( body, &ostream);
message_get_stream(info->msg, &ostream);
if ( info->nbytes )
memmove( info->buf, info->buf + (BUF_SIZE - info->nbytes), info->nbytes);
while ( info->nbytes || ( ( ret = stream_read(istream, info->buf, BUF_SIZE, info->ioffset, &info->nbytes) ) == 0 && info->nbytes ) ) {
while ( (ret == 0 && info->nbytes) || ( ( ret = stream_read(istream, info->buf, BUF_SIZE, info->ioffset, &info->nbytes) ) == 0 && info->nbytes ) ) {
info->ioffset += info->nbytes;
while( info->nbytes ) {
if ( ( ret = stream_write(ostream, info->buf, info->nbytes, info->ooffset, &nbytes ) ) != 0 )
......@@ -253,6 +235,8 @@ int message_unencapsulate(message_t msg, message_t *newmsg, void **data)
}
}
}
if ( ret == 0 )
*newmsg = info->msg;
if ( ret != EAGAIN && info )
_attachment_free(info, ret);
return ret;
......
......@@ -14,6 +14,9 @@
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>
......@@ -50,6 +53,12 @@ attribute_destroy (attribute_t *pattr, void *owner)
return;
}
void *
attribute_get_owner (attribute_t attr)
{
return (attr) ? attr->owner : NULL;
}
int
attribute_get_flags (attribute_t attr, int *pflags)
{
......
......@@ -14,96 +14,206 @@
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 <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <termios.h>
#include <mailutils/mailbox.h>
#include <auth0.h>
#include <cpystr.h>
#include <misc.h>
static void
echo_off(struct termios *stored_settings)
{
struct termios new_settings;
tcgetattr (0, stored_settings);
new_settings = *stored_settings;
new_settings.c_lflag &= (~ECHO);
tcsetattr (0, TCSANOW, &new_settings);
}
static void
echo_on(struct termios *stored_settings)
{
tcsetattr (0, TCSANOW, stored_settings);
}
int
auth_create (auth_t *pauth, void *owner)
ticket_create (ticket_t *pticket, void *owner)
{
auth_t auth;
if (pauth == NULL)
ticket_t ticket;
if (pticket == NULL)
return EINVAL;
auth = calloc (1, sizeof (*auth));
if (auth == NULL)
ticket = calloc (1, sizeof (*ticket));
if (ticket == NULL)
return ENOMEM;
auth->owner = owner;
*pauth = auth;
ticket->owner = owner;
*pticket = ticket;
return 0;
}
void
auth_destroy (auth_t *pauth, void *owner)
ticket_destroy (ticket_t *pticket, void *owner)
{
if (pauth && *pauth)
if (pticket && *pticket)
{
auth_t auth = *pauth;
if (auth->owner == owner)
free (auth);
*pauth = NULL;
ticket_t ticket = *pticket;
if (ticket->owner == owner)
{
if (ticket->type)
free (ticket->type);
free (ticket);
}
}
*pticket = NULL;
}
void *
ticket_get_owner (ticket_t ticket)
{
return (ticket) ? ticket->owner : NULL;
}
int
auth_set_authenticate (auth_t auth,
int (*_authenticate)(auth_t, char **, char **),
void *owner)
ticket_pop (ticket_t ticket, const char *challenge, char **parg)
{
if (auth == NULL)
if (ticket == NULL || parg == NULL)
return EINVAL;
if (auth->owner != owner)
return EPERM;
auth->_authenticate = _authenticate;
if (ticket->_pop)
return ticket->_pop (ticket, challenge, parg);
else
{
char arg[256];
struct termios stored_settings;
int echo = 1;
/* Being smart if we see "Passwd" and turning off echo. */
if (strstr (challenge, "ass") != NULL
|| strstr (challenge, "ASS") != NULL)
echo = 0;
printf ("%s", challenge);
fflush (stdout);
if (!echo)
echo_off (&stored_settings);
fgets (arg, sizeof (arg), stdin);
if (!echo)
echo_on (&stored_settings);
arg [strlen (arg) - 1] = '\0'; /* nuke the trailing line. */
*parg = strdup (arg);
}
return 0;
}
int
ticket_get_type (ticket_t ticket, char *type, size_t len, size_t *pwriten)
{
size_t n;
if (ticket == NULL || type == NULL)
return EINVAL;
n = _cpystr (type, ticket->type, len);
if (pwriten)
*pwriten = n;
return 0;
}
int
auth_authenticate (auth_t auth, char **user, char **passwd)
ticket_set_type (ticket_t ticket, char *type)
{
if (auth == NULL || auth->_authenticate == NULL)
if (ticket == NULL)
return EINVAL;
return auth->_authenticate (auth, user, passwd);
ticket->type = strdup ((type) ? type : "");
return 0;
}
int
auth_set_epilogue (auth_t auth, int (*_epilogue)(auth_t), void *owner)
authority_create (authority_t *pauthority, ticket_t ticket, void *owner)
{
if (auth == NULL)
authority_t authority;
if (pauthority == NULL)
return EINVAL;
if (auth->owner != owner)
return EPERM;
auth->_epilogue = _epilogue;
authority = calloc (1, sizeof (*authority));
if (authority == NULL)
return ENOMEM;
authority->ticket = ticket;
authority->owner = owner;
*pauthority = authority;
return 0;
}
void
authority_destroy (authority_t *pauthority, void *owner)
{
if (pauthority && *pauthority)
{
authority_t authority = *pauthority;
if (authority->owner == owner)
{
ticket_destroy (&(authority->ticket), authority);
free (authority);
}
*pauthority = NULL;
}
}
void *
authority_get_owner (authority_t authority)
{
return (authority) ? authority->owner : NULL;
}
int
auth_epilogue (auth_t auth)
authority_set_ticket (authority_t authority, ticket_t ticket)
{
if (auth == NULL || auth->_epilogue == NULL)
if (authority == NULL)
return EINVAL;
return auth->_epilogue (auth);
ticket_destroy (&(authority->ticket), authority);
authority->ticket = ticket;
return 0;
}
int
auth_set_prologue (auth_t auth, int (*_prologue)(auth_t), void *owner)
authority_get_ticket (authority_t authority, ticket_t *pticket)
{
if (auth == NULL)
if (authority == NULL || pticket == NULL)
return EINVAL;
if (auth->owner != owner)
return EPERM;
auth->_prologue = _prologue;
if (authority->ticket == NULL)
{
int status = ticket_create (&(authority->ticket), authority);
if (status != 0)
return status;
}
*pticket = authority->ticket;
return 0;
}
int
authority_authenticate (authority_t authority)
{
if (authority && authority->_authenticate)
{
return authority->_authenticate (authority);
}
return 0;
}
int
auth_prologue (auth_t auth)
authority_set_authenticate (authority_t authority,
int (*_authenticate) __P ((authority_t)),
void *owner)
{
if (auth == NULL || auth->_prologue == NULL)
if (authority == NULL)
return EINVAL;
return auth->_prologue (auth);
if (authority->owner != owner)
return EACCES;
authority->_authenticate = _authenticate;
return 0;
}
......
......@@ -14,6 +14,9 @@
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>
......@@ -187,7 +190,7 @@ bio_write (bio_t bio, const char *ptr, size_t n, size_t *pnwriten)
int
bio_readline (bio_t bio, char *ptr, size_t maxlen, size_t *pwriten)
{
int rc = 0;
size_t rc = 0;
size_t n = 0;
int err;
char c;
......
......@@ -14,6 +14,9 @@
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 <stdio.h>
......@@ -21,8 +24,8 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <mailutils/stream.h>
#include <body0.h>
#include <stream0.h>
static int body_read (stream_t is, char *buf, size_t buflen,
......@@ -66,6 +69,12 @@ body_destroy (body_t *pbody, void *owner)
}
}
void *
body_get_owner (body_t body)
{
return (body) ? body->owner : NULL;
}
int
body_get_stream (body_t body, stream_t *pstream)
{
......@@ -182,10 +191,10 @@ static int
body_read (stream_t is, char *buf, size_t buflen,
off_t off, size_t *pnread )
{
body_t body;
body_t body = stream_get_owner (is);
size_t nread = 0;
if (is == NULL || (body = is->owner) == NULL)
if (body == NULL)
return EINVAL;
/* check if they want to read from a file */
......@@ -232,10 +241,10 @@ static int
body_write (stream_t os, const char *buf, size_t buflen,
off_t off, size_t *pnwrite)
{
body_t body;
body_t body = stream_get_owner (os);
size_t nwrite = 0;
if (os == NULL || (body = os->owner) == NULL)
if (body == NULL)
return EINVAL;
/* FIXME: security issues, Refuse to write to an unknow file */
......@@ -275,9 +284,9 @@ body_write (stream_t os, const char *buf, size_t buflen,
static int
body_get_fd (stream_t stream, int *pfd)
{
body_t body;
body_t body = stream_get_owner (stream);
if (stream == NULL || (body = stream->owner) == NULL)
if (body == NULL)
return EINVAL;
/* Probably being lazy, then create a body for the stream */
......
/* 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 <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <debug0.h>
int
debug_create (debug_t *pdebug, void *owner)
{
debug_t debug;
if (pdebug == NULL)
return EINVAL;
debug = calloc (sizeof (*debug), 1);
if (debug == NULL)
return ENOMEM;
debug->owner = owner;
*pdebug = debug;
return 0;
}
void
debug_destroy (debug_t *pdebug, void *owner)
{
if (pdebug && *pdebug)
{
debug_t debug = *pdebug;
if (debug->owner == owner)
{
free (*pdebug);
*pdebug = NULL;
}
}
}
void *
debug_get_owner (debug_t debug)
{
return (debug) ? debug->owner : NULL;
}
int
debug_set_level (debug_t debug, size_t level)
{
if (debug == NULL)
return EINVAL;
debug->level = level;
return 0;
}
int
debug_get_level (debug_t debug, size_t *plevel)
{
if (debug == NULL)
return EINVAL;
if (plevel)
*plevel = debug->level;
return 0;
}
int
debug_set_print (debug_t debug, int (*_print)
__P ((debug_t, const char *, va_list)), void *owner)
{
if (debug == NULL)
return EINVAL;
if (debug->owner != owner)
return EACCES;
debug->_print = _print;
return 0;
}
/* FIXME: We use a fix size, we should use vasprinf or something
similar to get rid of this arbitrary limitation. */
int
debug_print (debug_t debug, size_t level, const char *format, ...)
{
va_list ap;
if (debug == NULL)
return EINVAL;
if (!(debug->level & level))
return 0;
va_start (ap, format);
if (debug->_print)
debug->_print (debug, format, ap);
else
vfprintf (stderr, format, ap);
va_end (ap);
return 0;
}
......@@ -15,6 +15,9 @@
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 <stdio.h>
......@@ -26,7 +29,7 @@
#include <fcntl.h>
#include <unistd.h>
#include <stream0.h>
#include <mailutils/stream.h>
struct _file_stream
{
......@@ -37,7 +40,7 @@ struct _file_stream
static void
_file_destroy (stream_t stream)
{
struct _file_stream *fs = stream->owner;
struct _file_stream *fs = stream_get_owner (stream);
if (fs && fs->file)
fclose (fs->file);
......@@ -48,7 +51,7 @@ static int
_file_read (stream_t stream, char *optr, size_t osize,
off_t offset, size_t *nbytes)
{
struct _file_stream *fs = stream->owner;
struct _file_stream *fs = stream_get_owner (stream);
size_t n;
int err = 0;
......@@ -80,7 +83,7 @@ static int
_file_readline (stream_t stream, char *optr, size_t osize,
off_t offset, size_t *nbytes)
{
struct _file_stream *fs = stream->owner;
struct _file_stream *fs = stream_get_owner (stream);
size_t n = 0;
int err = 0;
......@@ -116,7 +119,7 @@ static int
_file_write (stream_t stream, const char *iptr, size_t isize,
off_t offset, size_t *nbytes)
{
struct _file_stream *fs = stream->owner;
struct _file_stream *fs = stream_get_owner (stream);
size_t n;
int err;
......@@ -147,7 +150,7 @@ _file_write (stream_t stream, const char *iptr, size_t isize,
static int
_file_truncate (stream_t stream, off_t len)
{
struct _file_stream *fs = stream->owner;
struct _file_stream *fs = stream_get_owner (stream);
if (fs == NULL)
return EINVAL;
......@@ -159,7 +162,7 @@ _file_truncate (stream_t stream, off_t len)
static int
_file_size (stream_t stream, off_t *psize)
{
struct _file_stream *fs = stream->owner;
struct _file_stream *fs = stream_get_owner (stream);
struct stat stbuf;
if (fs == NULL)
......@@ -175,7 +178,7 @@ _file_size (stream_t stream, off_t *psize)
static int
_file_flush (stream_t stream)
{
struct _file_stream *fs = stream->owner;
struct _file_stream *fs = stream_get_owner (stream);
if (fs == NULL)
return EINVAL;
......@@ -185,7 +188,7 @@ _file_flush (stream_t stream)
static int
_file_get_fd (stream_t stream, int *pfd)
{
struct _file_stream *fs = stream->owner;
struct _file_stream *fs = stream_get_owner (stream);
if (fs == NULL)
return EINVAL;
......@@ -197,7 +200,7 @@ _file_get_fd (stream_t stream, int *pfd)
static int
_file_close (stream_t stream)
{
struct _file_stream *fs = stream->owner;
struct _file_stream *fs = stream_get_owner (stream);
int err = 0;
if (fs == NULL)
......@@ -214,7 +217,7 @@ _file_close (stream_t stream)
static int
_file_open (stream_t stream, const char *filename, int port, int flags)
{
struct _file_stream *fs = stream->owner;
struct _file_stream *fs = stream_get_owner (stream);
int flg;
int fd;
const char *mode;
......@@ -313,7 +316,7 @@ _file_open (stream_t stream, const char *filename, int port, int flags)
free (iobuffer);
}
#endif
stream_set_flags (stream, flags |MU_STREAM_NO_CHECK, fs);
stream_set_flags (stream, flags |MU_STREAM_NO_CHECK);
return 0;
}
......
......@@ -19,13 +19,14 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <mailutils/stream.h>
#include <header0.h>
#include <stream0.h>
static int header_parse (header_t h, const char *blurb, int len);
static int header_read (stream_t is, char *buf, size_t buflen,
......@@ -72,6 +73,12 @@ header_destroy (header_t *ph, void *owner)
}
}
void *
header_get_owner (header_t header)
{
return (header) ? header->owner : 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
......@@ -243,14 +250,29 @@ header_set_value (header_t header, const char *fn, const char *fv, int replace)
}
/* Replacing was taking care of above now just add to the end the new
header. Really not cute. */
len = strlen (fn) + strlen (fv) + 1 + 1 + 1 + 1;
blurb = calloc (header->blurb_len + len, 1);
header. Really not cute.
COLON SPACE NL = 3 ; */
len = strlen (fn) + strlen (fv) + 3;
/* Add one for the NULL and leak a bit by adding one more
it will be the separtor \n from the body if the first
blurb did not have it. */
blurb = calloc (header->blurb_len + len + 2, 1);
if (blurb == NULL)
return ENOMEM;
sprintf (blurb, "%s: %s\n", fn, fv);
memcpy (blurb + len - 1, header->blurb, header->blurb_len);
if (header->blurb)
{
memcpy (blurb + len, header->blurb, header->blurb_len);
free (header->blurb);
}
/* before parsing the new blurb make sure it is properly terminated
by \n\n. The trailing NL separtor. */
if (blurb[header->blurb_len + len - 1] != '\n'
|| blurb[header->blurb_len + len - 2] != '\n')
{
blurb[header->blurb_len + len] = '\n';
len++;
}
header_parse (header, blurb, len + header->blurb_len);
free (blurb);
return 0;
......@@ -469,6 +491,8 @@ fill_blurb (header_t header)
}
return status;
}
if (nread > 0)
{
tbuf = realloc (header->temp_blurb, header->temp_blurb_len + nread);
if (tbuf == NULL)
{
......@@ -481,6 +505,7 @@ fill_blurb (header_t header)
memcpy (header->temp_blurb + header->temp_blurb_len, buf, nread);
header->temp_blurb_len += nread;
}
}
while (nread > 0);
/* parse it. */
......@@ -495,8 +520,8 @@ static int
header_write (stream_t os, const char *buf, size_t buflen,
off_t off, size_t *pnwrite)
{
header_t header;
if (os == NULL || (header = (header_t)os->owner) == NULL)
header_t header = stream_get_owner (os);
if (os == NULL || header == NULL)
return EINVAL;
(void)buf; (void)off;
......@@ -513,10 +538,10 @@ static int
header_read (stream_t is, char *buf, size_t buflen,
off_t off, size_t *pnread)
{
header_t header;
header_t header = stream_get_owner (is);
int len;
if (is == NULL || (header = (header_t)is->owner) == NULL)
if (is == NULL || header == NULL)
return EINVAL;
len = header->blurb_len - off;
......
......@@ -33,13 +33,19 @@
extern "C" {
#endif
struct _auth
struct _ticket
{
void *owner;
char *challenge;
char *type;
int (*_pop) __P ((ticket_t, const char *challenge, char **));
};
int (*_prologue) (auth_t);
int (*_authenticate) (auth_t, char **user, char **passwd);
int (*_epilogue) (auth_t);
struct _authority
{
void *owner;
ticket_t ticket;
int (*_authenticate) __P ((authority_t));
};
......
/* 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. */
#ifndef _MAILUTILS_DEBUG0_H
#define _MAILUTILS_DEBUG0_H
#ifndef __P
#ifdef __STDC__
#define __P(args) args
#else
#define __P(args) ()
#endif
#endif /*__P */
#include <mailutils/debug.h>
#ifdef _cplusplus
extern "C" {
#endif
struct _debug
{
size_t level;
char *buffer;
size_t buflen;
void *owner;
int (*_print) __P ((debug_t, const char *, va_list));
};
#ifdef _cplusplus
}
#endif
#endif /* _MAILUTILS_DEBUG0_H */
......@@ -19,7 +19,6 @@
#define _HEADER0_H
#include <mailutils/header.h>
#include <stream0.h>
#include <sys/types.h>
#ifdef _cplusplus
......
......@@ -2,7 +2,7 @@
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
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.
......@@ -15,22 +15,33 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _MBX_UNIX_H
#define _MBX_UNIX_H 1
#ifndef _ITERATOR0_H
#define _ITERATOR0_H
#include <mailbox0.h>
#include <mailutils/iterator.h>
#ifdef __cplucplus
#ifndef __P
#ifdef __STDC__
#define __P(args) args
#else
#define __P(args) ()
#endif
#endif /*__P */
#ifdef _cplusplus
extern "C" {
#endif
extern int mailbox_unix_create __P ((mailbox_t *mbox, const char *name));
extern void mailbox_unix_destroy __P ((mailbox_t *mbox));
struct _iterator
{
list_t list;
size_t index;
};
extern struct mailbox_type _mailbox_unix_type;
#ifdef __cplucplus
#ifdef _cplusplus
}
#endif
#endif /* _MBX_UNIX_H */
#endif /* _ITERATOR0_H */
......
/* 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. */
#ifndef _LIST0_H
#define _LIST0_H
#ifdef HAVE_PTHREAD_H
# define __USE_UNIX98 /* ?? */
# include <pthread.h>
#endif
#include <mailutils/list.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 list_data
{
void *item;
struct list_data *next;
struct list_data *prev;
};
struct _list
{
struct list_data head;
size_t count;
#ifdef WITH_PTHREAD
pthread_rwlock_t rwlock;
#endif
};
#ifdef _cplusplus
}
#endif
#endif /* _LIST0_H */
......@@ -18,12 +18,16 @@
#ifndef _MAILBOX0_H
#define _MAILBOX0_H
#include <mailutils/mailbox.h>
#include <mailutils/event.h>
#ifdef HAVE_PTHREAD_H
# define __USE_UNIX98 /* ?? */
# include <pthread.h>
#endif
#include <sys/types.h>
#include <stdio.h>
#include <mailutils/mailbox.h>
#ifdef __cplusplus
extern "C" {
#endif
......@@ -39,30 +43,26 @@ extern "C" {
struct _mailbox
{
/* Data */
char *name;
auth_t auth;
observable_t observable;
debug_t debug;
ticket_t ticket;
authority_t authority;
locker_t locker;
stream_t stream;
url_t url;
int flags;
/* register events */
event_t event;
size_t event_num;
/* debug information */
int debug_level;
void *debug_arg;
char *debug_buffer;
size_t debug_bufsize;
int (*debug_print) __P ((void *arg, const char *, size_t));
#ifdef WITH_PTHREAD
pthread_rwlock_t rwlock;
#endif
/* Back pointer to the specific mailbox */
void *data;
/* Public methods */
int (*_create) __P ((mailbox_t *, const char *));
void (*_destroy) __P ((mailbox_t *));
int (*_init) __P ((mailbox_t));
void (*_destroy) __P ((mailbox_t));
int (*_open) __P ((mailbox_t, int flag));
int (*_close) __P ((mailbox_t));
......@@ -78,16 +78,27 @@ struct _mailbox
int (*_size) __P ((mailbox_t, off_t *size));
/* private */
int (*_num_deleted) __P ((mailbox_t, size_t *));
};
/* private */
extern int mailbox_num_deleted __P ((mailbox_t, size_t *));
extern int mailbox_notification __P ((mailbox_t mbox, size_t type));
extern int mailbox_debug __P ((mailbox_t, int level, const char *fmt, ...));
/* To manipulate mailbox rwlock. */
extern int mailbox_rdlock __P ((mailbox_t));
extern int mailbox_wrlock __P ((mailbox_t));
extern int mailbox_unlock __P ((mailbox_t));
#define MAILBOX_NOTIFY(mbox, type) \
if (mbox->observer) observer_notify (mbox->observer, type)
/* Moro(?)ic kluge. */
#define MAILBOX_DEBUG0(mbox, type, format) \
if (mbox->debug) debug_print (mbox->debug, type, format)
#define MAILBOX_DEBUG1(mbox, type, format, arg1) \
if (mbox->debug) debug_print (mbox->debug, type, format, arg1)
#define MAILBOX_DEBUG2(mbox, type, format, arg1, arg2) \
if (mbox->debug) debug_print (mbox->debug, type, format, arg1, arg2)
#define MAILBOX_DEBUG3(mbox, type, format, arg1, arg2, arg3) \
if (mbox->debug) debug_print (mbox->debug, type, format, arg1, arg2, arg3)
#define MAILBOX_DEBUG4(mbox, type, format, arg1, arg2, arg3, arg4) \
if (mbox->debug) debug_print (mbox->debug, type, format, arg1, arg2, arg3, arg4)
#ifdef __cplusplus
}
......
......@@ -20,7 +20,10 @@
#include <sys/types.h>
#include <mailutils/mailer.h>
#ifdef HAVE_PTHREAD_H
# define __USE_UNIX98 /* ?? */
# include <pthread.h>
#endif
#ifdef _cplusplus
extern "C" {
#endif
......@@ -50,16 +53,32 @@ extern "C" {
struct _mailer
{
int socket;
char *hostname;
char line_buf[MAILER_LINE_BUF_SIZE];
int offset;
int state;
int add_dot;
stream_t stream;
char last_char;
observable_t observable;
debug_t debug;
url_t url;
int flags;
#ifdef WITH_PTHREAD
pthread_rwlock_t rwlock;
#endif
/* Pointer to the specific mailer data. */
void *data;
/* Public methods. */
int (*_init) __P ((mailer_t));
void (*_destroy) __P ((mailer_t));
int (*_open) __P ((mailer_t, int flags));
int (*_close) __P ((mailer_t));
int (*_send_message) __P ((mailer_t, const char *from, const char *rcpt,
int dsn, message_t));
};
/* Mail locks. */
extern int mailer_rdlock __P ((mailer_t));
extern int mailer_wrlock __P ((mailer_t));
extern int mailer_unlock __P ((mailer_t));
#ifdef _cplusplus
}
#endif
......
/* 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 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 _MBX_IMAP_H
#define _MBX_IMAP_H 1
#include <mailbox0.h>
extern int mailbox_imap_create __P ((mailbox_t *mbox, const char *name));
extern void mailbox_imap_destroy __P ((mailbox_t *mbox));
extern struct mailbox_type _mailbox_imap_type;
#endif /* _MBX_IMAP_H */
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999 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 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 _MBX_MBOX_H
#define _MBX_MBOX_H 1
#include <mailutils/mailbox.h>
extern int mailbox_mbox_create __P ((mailbox_t *mbox, const char *name));
extern void mailbox_mbox_destroy __P ((mailbox_t *mbox));
extern struct mailbox_type _mailbox_mbox_type;
#endif /* _MBX_MBOX_H */
/* 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 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 _MBX_MDIR_H
#define _MBX_MDIR_H 1
#include <mailbox0.h>
extern int mailbox_maildir_create __P ((mailbox_t *mbox, const char *name));
extern void mailbox_maildir_destroy __P ((mailbox_t *mbox));
extern struct mailbox_type _mailbox_maildir_type;
#endif /* _MBX_MDIR_H */
/* 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 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 _MBX_MMDF_H
#define _MBX_MMDF_H 1
#include <mailbox0.h>
extern int mailbox_mmdf_create __P ((mailbox_t *mbox, const char *name));
extern void mailbox_mmdf_destroy __P ((mailbox_t *mbox));
extern struct mailbox_type _mailbox_mmdf_type;
#endif /* _MBX_MMDF_H */
/* 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 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 _MBX_POP_H
#define _MBX_POP_H 1
#include <mailbox0.h>
extern int mailbox_pop_create __P ((mailbox_t *mbox, const char *name));
extern void mailbox_pop_destroy __P ((mailbox_t *mbox));
extern struct mailbox_type _mailbox_pop_type;
#endif /* _MBX_POP_H */
......@@ -18,12 +18,8 @@
#ifndef _MESSAGE0_H
#define _MESSAGE0_H
#include <mailutils/attribute.h>
#include <mailutils/header.h>
#include <mailutils/message.h>
#include <mailutils/mime.h>
#include <mailutils/mailbox.h>
#include <mailutils/event.h>
#include <sys/types.h>
#include <stdio.h>
......@@ -50,9 +46,7 @@ struct _message
body_t body;
attribute_t attribute;
mime_t mime;
event_t event;
size_t event_num;
observable_t observable;
/* Holder for message_write. */
char *hdr_buf;
......@@ -73,5 +67,4 @@ struct _message
}
#endif
extern void message_notification (message_t msg, size_t type);
#endif /* _MESSAGE_H */
#endif /* _MESSAGE0_H */
......
......@@ -47,6 +47,9 @@ extern "C" {
#define MIME_PARSER_ACTIVE 0x80000000
#define MIME_PARSER_HAVE_CR 0x40000000
#define MIME_NEW_MESSAGE 0x20000000
#define MIME_ADDED_CONTENT_TYPE 0x10000000
#define MIME_ADDED_MULTIPART 0x08000000
#define MIME_INSERT_BOUNDARY 0x04000000
struct _mime
{
......@@ -59,12 +62,14 @@ struct _mime
int tparts;
int nmtp_parts;
struct _mime_part **mtp_parts; /* list of parts in the msg */
char *boundary;
int cur_offset;
int cur_part;
int part_offset;
/* parser state */
char *boundary;
char *cur_line;
int line_ndx;
int cur_offset;
char *cur_buf;
int buf_size;
char *header_buf;
......@@ -72,17 +77,17 @@ struct _mime
int header_length;
int body_offset;
int body_length;
int body_lines;
int parser_state;
};
struct _mime_part
{
char sig[4];
mime_t mime;
header_t hdr;
message_t msg;
int body_offset;
int body_len;
int offset;
size_t len;
size_t lines;
};
#ifdef _cplusplus
......
......@@ -15,8 +15,12 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifndef _CPYSTR_H
#define _CPYSTR_H
#ifndef _MISC_H
#define _MISC_H
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/types.h>
......@@ -32,9 +36,45 @@ extern "C" {
# endif
#endif
extern size_t _cpystr __P ((char *dst, const char *src, size_t size));
extern int parseaddr __P ((const char *addr, char *buf, size_t bufsz));
#ifdef HAVE_PTHREAD_H
# define __USE_UNIX98
# include <pthread.h>
#endif
#ifdef WITH_PTHREAD
# if 0
# define RWLOCK_INIT(rwl, attr) pthread_mutex_init (rwl, attr)
# define RWLOCK_DESTROY(rwl) pthread_mutex_destroy (rwl)
# define RWLOCK_RDLOCK(rwl) pthread_mutex_lock (rwl)
# define RWLOCK_TRYRDLOCK(rwl) pthread_mutex_trylock (rwl)
# define RWLOCK_WRLOCK(rwl) pthread_mutex_lock (rwl)
# define RWLOCK_TRYWRLOCK(rwl) pthread_mutex_trylock (rwl)
# define RWLOCK_UNLOCK(rwl) pthread_mutex_unlock (rwl)
# else
# define RWLOCK_INIT(rwl, attr) pthread_rwlock_init (rwl, attr)
# define RWLOCK_DESTROY(rwl) pthread_rwlock_destroy (rwl)
# define RWLOCK_RDLOCK(rwl) pthread_rwlock_rdlock (rwl)
# define RWLOCK_TRYRDLOCK(rwl) pthread_rwlock_tryrdlock (rwl)
# define RWLOCK_WRLOCK(rwl) pthread_rwlock_wrlock (rwl)
# define RWLOCK_TRYWRLOCK(rwl) pthread_rwlock_trywrlock (rwl)
# define RWLOCK_UNLOCK(rwl) pthread_rwlock_unlock (rwl)
# endif
#else
# define RWLOCK_INIT(rwl, attr) 0
# define RWLOCK_DESTROY(rwl)
# define RWLOCK_RDLOCK(rwl)
# define RWLOCK_TRYRDLOCK(rwl)
# define RWLOCK_WRLOCK(rwl)
# define RWLOCK_TRYWRLOCK(rwl)
# define RWLOCK_UNLOCK(rwl)
# define flockfile(arg)
# define funlockfile(arg)
#endif
#ifdef __cplusplus
}
#endif
#endif
#endif /* _MISC_H */
......
/* 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. */
#ifndef _OBSERVER0_H
#define _OBSERVER0_H
#include <mailutils/observer.h>
#ifndef __P
#ifdef __STDC__
#define __P(args) args
#else
#define __P(args) ()
#endif
#endif /*__P */
#ifdef _cplusplus
extern "C" {
#endif
struct _observer
{
int flags;
void *owner;
int (*_action) __P ((observer_t, size_t));
int (*_destroy) __P ((observer_t));
};
struct _observable
{
void *owner;
list_t list;
};
#ifdef _cplusplus
}
#endif
#endif /* _OBSERVER0_H */
......@@ -20,7 +20,6 @@
#include <mailutils/registrar.h>
#ifdef __cplusplus
extern "C" {
#endif
......@@ -33,58 +32,18 @@ extern "C" {
# endif
#endif /*__P */
/*
Builtin mailbox types.
A circular list is use for the builtin.
Proper locking is not done when accessing the list.
FIXME: not thread-safe. */
struct _registrar
struct _record
{
struct url_registrar *ureg;
struct mailbox_registrar *mreg;
const char *scheme;
mailbox_entry_t mailbox;
mailer_entry_t mailer;
int is_allocated;
struct _registrar *next;
void *onwer;
int (*_is_scheme) __P ((record_t, const char *));
int (*_get_mailbox) __P ((record_t, mailbox_entry_t *_mailbox));
int (*_get_mailer) __P ((record_t, mailer_entry_t *_mailer));
};
/* This is function is obsolete use the registrar_entry_*() ones */
extern int registrar_list __P ((struct url_registrar **ureg,
struct mailbox_registrar **mreg,
int *id, registrar_t *reg));
extern int registrar_entry_count __P ((size_t *num));
extern int registrar_entry __P ((size_t num, struct url_registrar **ureg,
struct mailbox_registrar **mreg,
int *id));
/* IMAP */
extern struct mailbox_registrar _mailbox_imap_registrar;
extern struct url_registrar _url_imap_registrar;
/* FILE */
extern struct url_registrar _url_file_registrar;
/* MBOX */
extern struct mailbox_registrar _mailbox_mbox_registrar;
extern struct url_registrar _url_mbox_registrar;
/* MAILTO */
extern struct mailbox_registrar _mailbox_mailto_registrar;
extern struct url_registrar _url_mailto_registrar;
/* MDIR */
extern struct mailbox_registrar _mailbox_maildir_registrar;
extern struct url_registrar _url_maildir_registrar;
/* MMDF */
extern struct mailbox_registrar _mailbox_mmdf_registrar;
extern struct url_registrar _url_mmdf_registrar;
/* UNIX */
extern struct mailbox_registrar _mailbox_unix_registrar;
extern struct url_registrar _url_unix_registrar;
/* POP */
extern struct mailbox_registrar _mailbox_pop_registrar;
extern struct url_registrar _url_pop_registrar;
#ifdef __cplusplus
}
#endif
......
......@@ -35,62 +35,34 @@ extern "C" {
struct _url
{
/* Data */
char *name;
char *scheme;
char *user;
char *passwd; /* encoded ?? */
char *auth;
char *host;
long port;
char *path;
char *query;
int id;
void *data;
int (*_create) __P ((url_t *url, const char *name));
void (*_destroy) __P ((url_t *url));
int (*_init) __P ((url_t url));
void (*_destroy) __P ((url_t url));
/* Methods */
int (*_get_id) __P ((const url_t, int *id));
int (*_get_scheme) __P ((const url_t, char *scheme,
size_t len, size_t *n));
int (*_get_user) __P ((const url_t, char *user,
size_t len, size_t *n));
int (*_get_passwd) __P ((const url_t, char *passwd,
size_t len, size_t *n));
int (*_get_host) __P ((const url_t, char *host,
size_t len, size_t *n));
int (*_get_port) __P ((const url_t, long *port));
int (*_get_path) __P ((const url_t, char *path,
size_t len, size_t *n));
int (*_get_query) __P ((const url_t, char *query,
size_t len, size_t *n));
int (*_get_scheme) __P ((const url_t, char *, size_t, size_t *));
int (*_get_user) __P ((const url_t, char *, size_t, size_t *));
int (*_get_passwd) __P ((const url_t, char *, size_t, size_t *));
int (*_get_auth) __P ((const url_t, char *, size_t, size_t *));
int (*_get_host) __P ((const url_t, char *, size_t, size_t *));
int (*_get_port) __P ((const url_t, long *));
int (*_get_path) __P ((const url_t, char *, size_t, size_t *));
int (*_get_query) __P ((const url_t, char *, size_t, size_t *));
};
/* IMAP */
/* Mailto */
/* UNIX MBOX */
/* Maildir */
/* MMDF */
/* POP3 */
#define MU_POP_PORT 110
/* UNIX MBOX */
#ifdef __cplusplus
}
#endif
......
/* 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 <errno.h>
#include <stdlib.h>
#include <iterator0.h>
int
iterator_create (iterator_t *piterator, list_t list)
{
iterator_t iterator;
if (piterator == NULL || list == NULL)
return EINVAL;
iterator = calloc (sizeof (*iterator), 1);
if (iterator == NULL)
return ENOMEM;
iterator->list = list;
*piterator = iterator;
return 0;
}
void
iterator_destroy (iterator_t *piterator)
{
if (piterator && *piterator)
{
free (*piterator);
*piterator = NULL;
}
}
int
iterator_first (iterator_t iterator)
{
iterator->index = 0;
return 0;
}
int
iterator_next (iterator_t iterator)
{
iterator->index++;
return 0;
}
int
iterator_current (iterator_t iterator, void **pitem)
{
return list_get (iterator->list, iterator->index, pitem);
}
int
iterator_is_done (iterator_t iterator)
{
size_t count;
int status;
if (iterator == NULL)
return 1;
status = list_count (iterator->list, &count);
if (status != 0)
return 1;
return (iterator->index >= count);
}
/* 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 <errno.h>
#include <stdlib.h>
#include <misc.h>
#include <list0.h>
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 = RWLOCK_INIT (&(list->rwlock), NULL);
if (status != 0)
{
free (list);
return status;
}
list->head.next = &(list->head);
list->head.prev = &(list->head);
*plist = list;
return 0;
}
void
list_destroy (list_t *plist)
{
if (plist && *plist)
{
list_t list = *plist;
struct list_data *current;
struct list_data *previous;
RWLOCK_WRLOCK (&(list->rwlock));
for (current = list->head.next; current != &(list->head);)
{
previous = current;
current = current->next;
free (previous);
}
RWLOCK_UNLOCK (&(list->rwlock));
RWLOCK_DESTROY (&(list->rwlock));
free (list);
*plist = NULL;
}
}
int
list_append (list_t list, void *item)
{
struct list_data *ldata;
struct list_data *last = list->head.prev;
ldata = calloc (sizeof (*ldata), 1);
if (ldata == NULL)
return ENOMEM;
ldata->item = item;
RWLOCK_WRLOCK (&(list->rwlock));
ldata->next = &(list->head);
ldata->prev = list->head.prev;
last->next = ldata;
list->head.prev = ldata;
list->count++;
RWLOCK_UNLOCK (&(list->rwlock));
return 0;
}
int
list_prepend (list_t list, void *item)
{
struct list_data *ldata;
struct list_data *first = list->head.next;
ldata = calloc (sizeof (*ldata), 1);
if (ldata == NULL)
return ENOMEM;
ldata->item = item;
RWLOCK_WRLOCK (&(list->rwlock));
ldata->prev = &(list->head);
ldata->next = list->head.next;
first->prev = ldata;
list->head.next = ldata;
list->count++;
RWLOCK_UNLOCK (&(list->rwlock));
return 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;
if (list == NULL)
return EINVAL;
RWLOCK_WRLOCK (&(list->rwlock));
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;
free (current);
list->count--;
RWLOCK_UNLOCK (&(list->rwlock));
return 0;
}
}
RWLOCK_UNLOCK (&(list->rwlock));
return ENOENT;
}
int
list_get (list_t list, size_t index, void **pitem)
{
struct list_data *current;
size_t count;
if (list == NULL || pitem == NULL)
return EINVAL;
RWLOCK_RDLOCK (&(list->rwlock));
for (current = list->head.next, count = 0; current != &(list->head);
current = current->next, count++)
{
if (count == index)
{
*pitem = current->item;
RWLOCK_UNLOCK (&(list->rwlock));
return 0;
}
}
RWLOCK_UNLOCK (&(list->rwlock));
return ENOENT;
}
......@@ -15,6 +15,10 @@
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 <sys/types.h>
#include <stdlib.h>
......
......@@ -19,56 +19,92 @@
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <mailbox0.h>
#include <message0.h>
#include <mailutils/registrar.h>
#include <mailutils/locker.h>
#include <mailutils/iterator.h>
#include <mailutils/registrar.h>
#include <misc.h>
#include <mailbox0.h>
/*
* Point of entry.
* Simple, first check if they ask for something specific; with the ID.
* Then try to discover the type of mailbox with the url(name).
* Then we call the appropriate mailbox_*type*_create() function.
*/
/* The Mailbox Factory.
We create an iterator for the mailbox_register and see if any scheme
match, if not we check in the mailbox_manager register for a match.
Then we call the mailbox's >url_create() to parse the URL. Last
initiliaze the concrete mailbox. */
int
mailbox_create (mailbox_t *pmbox, const char *name, int id)
{
int status = EINVAL;
struct mailbox_registrar *mreg;
url_t url = NULL;
record_t record = NULL;
mailbox_entry_t entry = NULL;
iterator_t iterator;
list_t list;
int found = 0;
(void)id;
if (pmbox == NULL)
return EINVAL;
url_create (&url, name);
/* 1st guest: if an ID is specify, shortcut */
if (id)
/* Look in the mailbox_register, for a match */
registrar_get_list (&list);
status = iterator_create (&iterator, list);
if (status != 0)
return status;
for (iterator_first (iterator); !iterator_is_done (iterator);
iterator_next (iterator))
{
iterator_current (iterator, (void **)&record);
if (record_is_scheme (record, name))
{
status = registrar_get (id, NULL, &mreg);
status = record_get_mailbox (record, &entry);
if (status == 0)
status = mreg->_create (pmbox, name);
found = 1;
break;
}
}
/* 2nd fallback: Use the URL */
else if (url != NULL)
iterator_destroy (&iterator);
if (found)
{
url_get_id (url, &id);
status = registrar_get (id, NULL, &mreg);
if (status == 0)
status = mreg->_create (pmbox, name);
url_t url = NULL;
mailbox_t mbox = NULL;
/* Allocate memory for mbox. */
mbox = calloc (1, sizeof (*mbox));
if (mbox == NULL)
return ENOMEM;
/* Initialize the internal lock, now so the concrete mailbox
could use it. */
status = RWLOCK_INIT (&(mbox->rwlock), NULL);
if (status != 0)
{
mailbox_destroy (&mbox);
return status;
}
/* set the URL */
if (status == 0)
(*pmbox)->url = url;
/* Parse the url, it may be a bad one and we should bailout if this
failed. */
if ((status = url_create (&url, name)) != 0
|| (status = entry->_url_init (url)) != 0)
{
mailbox_destroy (&mbox);
return status;
}
mbox->url = url;
/* Create the concrete mailbox type. */
status = entry->_mailbox_init (mbox);
if (status != 0)
{
mailbox_destroy (&mbox);
}
else
url_destroy (&url);
*pmbox = mbox;
}
return status;
}
......@@ -76,9 +112,52 @@ void
mailbox_destroy (mailbox_t *pmbox)
{
if (pmbox && *pmbox)
(*pmbox)->_destroy (pmbox);
{
mailbox_t mbox = *pmbox;
#ifdef WITH_PTHREAD
pthread_rwlock_t rwlock = mbox->rwlock;
#endif
/* Notify the observers. */
if (mbox->observable)
{
observable_notify (mbox->observable, MU_EVT_MAILBOX_DESTROY);
observable_destroy (&(mbox->observable), mbox);
}
/* Call the concrete mailbox. */
if (mbox->_destroy)
mbox->_destroy (mbox);
RWLOCK_WRLOCK (&(rwlock));
/* Nuke the stream and close it */
if (mbox->stream)
{
stream_close (mbox->stream);
stream_destroy (&(mbox->stream), mbox);
}
if (mbox->authority)
authority_destroy (&(mbox->authority), mbox);
if (mbox->url)
url_destroy (&(mbox->url));
if (mbox->locker)
locker_destroy (&(mbox->locker));
if (mbox->debug)
debug_destroy (&(mbox->debug), mbox);
free (mbox);
*pmbox = NULL;
RWLOCK_UNLOCK (&(rwlock));
RWLOCK_DESTROY (&(rwlock));
}
}
/* -------------- stub functions ------------------- */
int
......@@ -131,14 +210,6 @@ mailbox_expunge (mailbox_t mbox)
}
int
mailbox_num_deleted (mailbox_t mbox, size_t *num)
{
if (mbox == NULL || mbox->_num_deleted == NULL)
return ENOSYS;
return mbox->_num_deleted (mbox, num);
}
int
mailbox_is_updated (mailbox_t mbox)
{
if (mbox == NULL || mbox->_is_updated == NULL)
......@@ -185,21 +256,21 @@ mailbox_get_locker (mailbox_t mbox, locker_t *plocker)
}
int
mailbox_set_auth (mailbox_t mbox, auth_t auth)
mailbox_set_ticket (mailbox_t mbox, ticket_t ticket)
{
if (mbox == NULL)
return EINVAL;
mbox->auth = auth;
mbox->ticket = ticket;
return 0;
}
int
mailbox_get_auth (mailbox_t mbox, auth_t *pauth)
mailbox_get_ticket (mailbox_t mbox, ticket_t *pticket)
{
if (mbox == NULL || pauth == NULL)
if (mbox == NULL || pticket == NULL)
return EINVAL;
if (pauth)
*pauth = mbox->auth;
if (pticket)
*pticket = mbox->ticket;
return 0;
}
......@@ -223,132 +294,81 @@ mailbox_get_stream (mailbox_t mbox, stream_t *pstream)
}
int
mailbox_register (mailbox_t mbox, size_t type,
int (*action) (size_t type, void *arg),
void *arg)
mailbox_get_observable (mailbox_t mbox, observable_t *pobservable)
{
size_t i;
event_t event;
/* FIXME: I should check for invalid types */
if (mbox == NULL || action == NULL)
if (mbox == NULL || pobservable == NULL)
return EINVAL;
/* find a free spot */
for (i = 0; i < mbox->event_num; i++)
if (mbox->observable == NULL)
{
event = &(mbox->event[i]);
if (event->_action == NULL)
{
event->_action = action;
event->type = type;
event->arg = arg;
return 0;
}
int status = observable_create (&(mbox->observable), mbox);
if (status != 0)
return status;
}
/* a new one */
event = realloc (mbox->event, (mbox->event_num + 1) * sizeof (*event));
if (event == NULL)
return ENOMEM;
mbox->event = event;
event[mbox->event_num]._action = action;
event[mbox->event_num].type = type;
event[mbox->event_num].arg = arg;
mbox->event_num++;
*pobservable = mbox->observable;
return 0;
}
int
mailbox_deregister (mailbox_t mbox, void *action)
mailbox_set_debug (mailbox_t mbox, debug_t debug)
{
size_t i;
event_t event;
for (i = 0; i < mbox->event_num; i++)
{
event = &(mbox->event[i]);
if ((int)event->_action == (int)action)
{
event->type = 0;
event->_action = NULL;
event->arg = NULL;
if (mbox == NULL)
return EINVAL;
debug_destroy (&(mbox->debug), mbox);
mbox->debug = debug;
return 0;
}
}
return ENOENT;
}
int
mailbox_notification (mailbox_t mbox, size_t type)
mailbox_get_debug (mailbox_t mbox, debug_t *pdebug)
{
size_t i;
event_t event;
int status = 0;
for (i = 0; i < mbox->event_num; i++)
if (mbox == NULL || pdebug == NULL)
return EINVAL;
if (mbox->debug == NULL)
{
event = &(mbox->event[i]);
if ((event->_action) && (event->type & type))
status |= event->_action (type, event->arg);
}
int status = debug_create (&(mbox->debug), mbox);
if (status != 0)
return status;
}
int
mailbox_set_debug_level (mailbox_t mbox, size_t level)
{
if (mbox == NULL)
return EINVAL;
mbox->debug_level = level;
}
*pdebug = mbox->debug;
return 0;
}
/* Mailbox Internal Locks. Put the name of the functions in parenteses To make
sure it will not be redefine by a macro. If the flags was non-blocking we
should not block on the lock, so we try with pthread_rwlock_try*lock(). */
int
mailbox_get_debug_level (mailbox_t mbox, size_t *plevel)
(mailbox_rdlock) (mailbox_t mbox)
{
if (mbox == NULL || plevel == NULL)
return EINVAL;
*plevel = mbox->debug_level;
#ifdef WITH_PTHREAD
int err = (mbox->flags & MU_STREAM_NONBLOCK) ?
RWLOCK_TRYRDLOCK (&(mbox->rwlock)) :
RWLOCK_RDLOCK (&(mbox->rwlock)) ;
if (err != 0 && err != EDEADLK)
return err;
#endif
return 0;
}
int
mailbox_set_debug_print (mailbox_t mbox, int (*debug_print)
(void *arg, const char *, size_t), void *arg)
(mailbox_wrlock) (mailbox_t mbox)
{
if (mbox == NULL)
return EINVAL;
mbox->debug_print = debug_print;
mbox->debug_arg = arg;
#ifdef WITH_PTHREAD
int err = (mbox->flags & MU_STREAM_NONBLOCK) ?
RWLOCK_TRYWRLOCK (&(mbox->rwlock)) :
RWLOCK_WRLOCK (&(mbox->rwlock)) ;
if (err != 0 && err != EDEADLK)
return err;
#endif
return 0;
}
int
mailbox_debug (mailbox_t mbox, int level, const char *fmt, ...)
(mailbox_unlock) (mailbox_t mbox)
{
va_list ap;
if (mbox == NULL)
return EINVAL;
if (!(mbox->debug_level & level))
return 0;
va_start (ap, fmt);
if (mbox->debug_print)
{
int writen;
if (mbox->debug_buffer == NULL)
{
mbox->debug_bufsize = 255;
mbox->debug_buffer = malloc (mbox->debug_bufsize);
if (mbox->debug_buffer)
return ENOMEM; }
writen = vsnprintf (mbox->debug_buffer, mbox->debug_bufsize, fmt, ap);
mbox->debug_print (mbox->debug_arg, mbox->debug_buffer, writen);
}
else
vfprintf (stderr, fmt, ap);
va_end (ap);
#ifdef WITH_PTHREAD
return RWLOCK_UNLOCK (&(mbox->rwlock));
#else
return 0;
#endif
}
......
......@@ -15,402 +15,260 @@
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 <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <mailutils/registrar.h>
#include <mailutils/iterator.h>
#include <misc.h>
#include <mailer0.h>
int _mailer_sock_connect(char *host, int port);
char *_mailer_find_mailbox(char *addr);
int _mailer_send_command(mailer_t ml, message_t msg, int cmd);
char *nb_fgets(char *buf, int size, int s);
const char *nb_fprintf(int s, const char *format, ...);
static int _mailer_rctp(mailer_t ml, char *str);
#define nb_read read
#define nb_write write
#define BUFFSIZE 4096
/*
*/
int
mailer_create(mailer_t *pml, message_t msg)
mailer_create (mailer_t *pmailer, const char *name, int id)
{
mailer_t ml;
(void)msg;
if (!pml)
int status = EINVAL;
record_t record = NULL;
mailer_entry_t entry = NULL;
list_t list = NULL;
iterator_t iterator;
int found;
(void)id;
if (pmailer == NULL)
return EINVAL;
ml = calloc (1, sizeof (*ml));
if (ml == NULL)
return (ENOMEM);
*pml = ml;
return (0);
}
int
mailer_destroy(mailer_t *pml)
{
mailer_t ml;
if (!pml)
return (EINVAL);
ml = *pml;
if (ml->hostname)
free(ml->hostname);
mailer_disconnect(ml);
free(ml);
*pml = NULL;
return (0);
}
int
mailer_connect(mailer_t ml, char *host)
{
if (!ml || !host)
return (EINVAL);
if ((ml->socket = _mailer_sock_connect(host, 25)) < 0)
return (-1);
do
registrar_get_list (&list);
status = iterator_create (&iterator, list);
if (status != 0)
return status;
for (iterator_first (iterator); !iterator_is_done (iterator);
iterator_next (iterator))
{
nb_fgets(ml->line_buf, MAILER_LINE_BUF_SIZE, ml->socket); /* read header line */
} while ( strlen(ml->line_buf) > 4 && *(ml->line_buf+3) == '-');
return (0);
}
int
mailer_disconnect(mailer_t ml)
{
if (!ml || (ml->socket != -1))
return (EINVAL);
iterator_current (iterator, (void **)&record);
if (record_is_scheme (record, name))
{
status = record_get_mailer (record, &entry);
if (status == 0)
found = 1;
break;
}
}
iterator_destroy (&iterator);
close(ml->socket);
return (0);
}
if (found)
{
url_t url = NULL;
mailer_t mailer = NULL;
int
mailer_send_header(mailer_t ml, message_t msg)
{
header_t hdr;
char buf[64];
/* Allocate memory for mailer. */
mailer = calloc (1, sizeof (*mailer));
if (mailer == NULL)
return ENOMEM;
if (!ml || !msg || (ml->socket == -1))
return (EINVAL);
RWLOCK_INIT (&(mailer->rwlock), NULL);
if (!ml->hostname)
/* Parse the url, it may be a bad one and we should bailout if this
failed. */
if ((status = url_create (&url, name)) != 0
|| (status = entry->_url_init (url)) != 0)
{
if (gethostname(buf, 64) < 0)
return (-1);
ml->hostname = strdup(buf);
mailer_destroy (&mailer);
return status;
}
mailer->url = url;
if (_mailer_send_command(ml, msg, MAILER_HELO) != 0)
return (-1);
if (_mailer_send_command(ml, msg, MAILER_MAIL) != 0)
return (-1);
if (_mailer_send_command(ml, msg, MAILER_RCPT) != 0)
return (-1);
if (_mailer_send_command(ml, msg, MAILER_DATA) != 0)
return (-1);
message_get_header(msg, &hdr);
header_get_stream(hdr, &(ml->stream));
ml->state = MAILER_STATE_HDR;
status = entry->_mailer_init (mailer);
if (status != 0)
{
mailer_destroy (&mailer);
}
else
*pmailer = mailer;
}
return (0);
return status;
}
int
mailer_send_message(mailer_t ml, message_t msg)
void
mailer_destroy (mailer_t *pmailer)
{
int status, data_len = 0;
size_t consumed = 0, len = 0;
char *data, *p, *q;
if (!ml || !msg || (ml->socket == -1))
return (EINVAL);
// alloca
if (!(data = alloca(MAILER_LINE_BUF_SIZE)))
return (ENOMEM);
memset(data, 0, 1000);
if ((status = stream_read(ml->stream, data, MAILER_LINE_BUF_SIZE, ml->offset, &len)) != 0)
return (-1);
if ((len == 0) && (ml->state == MAILER_STATE_HDR))
if (pmailer && *pmailer)
{
ml->state = MAILER_STATE_MSG;
ml->offset = 0;
message_get_stream(msg, &(ml->stream));
return (1);
}
else if (len == 0)
mailer_t mailer = *pmailer;
#ifdef WITH_PTHREAD
pthread_rwlock_t rwlock = mailer->rwlock;
#endif
if (mailer->observable)
{
strcpy(ml->line_buf, "\r\n.\r\n");
consumed = strlen(data);
observable_notify (mailer->observable, MU_EVT_MAILER_DESTROY);
observable_destroy (&(mailer->observable), mailer);
}
else
{
p = data;
q = ml->line_buf;
memset(ml->line_buf, 0, MAILER_LINE_BUF_SIZE);
while (consumed < len)
{
// RFC821: if the first character on a line is a '.' you must add an
// extra '.' to the line which will get stipped off at the other end
if ((*p == '.') && (ml->last_char == '\n'))
ml->add_dot = 1;
ml->last_char = *p;
*q++ = *p++; // store the character
data_len++; // increase the length by 1
consumed++;
if (((MAILER_LINE_BUF_SIZE - data_len) > 1) && (ml->add_dot == 1))
/* Call the object. */
if (mailer->_destroy)
mailer->_destroy (mailer);
RWLOCK_WRLOCK (&rwlock);
if (mailer->stream)
{
*q++ = '.';
data_len++;
ml->add_dot = 0;
}
stream_close (mailer->stream);
stream_destroy (&(mailer->stream), mailer);
}
if (mailer->url)
url_destroy (&(mailer->url));
if (mailer->debug)
debug_destroy (&(mailer->debug), mailer);
free (mailer);
*pmailer = NULL;
RWLOCK_UNLOCK (&rwlock);
RWLOCK_DESTROY (&rwlock);
}
}
ml->offset += consumed;
nb_fprintf(ml->socket, "%s\r\n", ml->line_buf);
if (len == 0)
{
ml->state = MAILER_STATE_COMPLETE;
return (0);
}
/* -------------- stub functions ------------------- */
return (consumed);
int
mailer_open (mailer_t mailer, int flag)
{
if (mailer == NULL || mailer->_open == NULL)
return ENOSYS;
return mailer->_open (mailer, flag);
}
int
_mailer_sock_connect(char *host, int port)
mailer_close (mailer_t mailer)
{
struct sockaddr_in saddr;
struct hostent *hp;
int s;
memset(&saddr, 0, sizeof(struct sockaddr_in));
saddr.sin_family = AF_INET;
saddr.sin_port = htons(port);
if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
return (-1);
if ((hp = gethostbyname(host)) == 0)
return (-1);
memcpy(&saddr.sin_addr, hp->h_addr, hp->h_length);
if (connect(s, (struct sockaddr *)&saddr, sizeof(saddr)) == 0)
return (s);
close(s);
return (-1);
if (mailer == NULL || mailer->_close == NULL)
return ENOSYS;
return mailer->_close (mailer);
}
char *
_mailer_find_mailbox(char *addr)
/* messages */
int
mailer_send_message (mailer_t mailer, const char *from, const char *rcpt,
int dsn, message_t msg)
{
char *p, *c;
p = addr;
if ( (c = strchr( p, '<')) != 0)
{
p = c+1;
if ( (c = strchr( p, '>')) )
*c = '\0';
}
else if ( (c = strchr( p, '(' )) != 0 )
{
--c;
while ( c > p && *c && isspace( *c ) ) {
*c = '\0';
--c;
}
}
return p;
if (mailer == NULL || mailer->_send_message == NULL)
return ENOSYS;
return mailer->_send_message (mailer, from, rcpt, dsn, msg);
}
static int
_mailer_rctp(mailer_t ml, char *str)
int
mailer_set_stream (mailer_t mailer, stream_t stream)
{
char *p, *c = NULL, *q = NULL;
if (mailer == NULL)
return EINVAL;
mailer->stream = stream;
return 0;
}
for (q = p = str; q && *p; p = q+1)
{
if ( (q = strchr( p, ',')) )
*q = '\0';
while ( p && *p && isspace( *p ) )
p++;
c = strdup(p);
p = _mailer_find_mailbox(c);
nb_fprintf(ml->socket, "RCPT TO:<%s>\r\n", p);
free(c);
nb_fgets(ml->line_buf, sizeof(ml->line_buf), ml->socket);
if (strncmp(ml->line_buf, "250", 3))
return (-strtol(ml->line_buf, 0, 10));
}
return (0);
int
mailer_get_stream (mailer_t mailer, stream_t *pstream)
{
if (mailer == NULL || pstream == NULL)
return EINVAL;
if (pstream)
*pstream = mailer->stream;
return 0;
}
int
_mailer_send_command(mailer_t ml, message_t msg, int cmd)
mailer_attach (mailer_t mailer, observer_t observer)
{
header_t hdr;
char *p;
char str[128];
size_t str_len;
const char *success = "250";
/* FIXME: I should check for invalid types */
if (mailer == NULL || observer == NULL)
return EINVAL;
switch (cmd)
if (mailer->observable == NULL)
{
case MAILER_HELO:
nb_fprintf(ml->socket, "HELO %s\r\n", ml->hostname);
break;
case MAILER_MAIL:
message_get_header(msg, &hdr);
header_get_value(hdr, MU_HEADER_FROM, str, 128, &str_len);
str[str_len] = '\0';
p = _mailer_find_mailbox(str);
nb_fprintf(ml->socket, "MAIL From: %s\r\n", p);
break;
case MAILER_RCPT:
message_get_header(msg, &hdr);
header_get_value(hdr, MU_HEADER_TO, str, 128, &str_len);
str[str_len] = '\0';
if (_mailer_rctp(ml, str) == -1)
return (-1);
header_get_value(hdr, MU_HEADER_CC, str, 128, &str_len);
str[str_len] = '\0';
if (_mailer_rctp(ml, str) == -1)
return (-1);
return (0);
break;
case MAILER_DATA:
nb_fprintf(ml->socket, "DATA\r\n");
success = "354";
break;
case MAILER_RSET:
nb_fprintf(ml->socket, "RSET\r\n");
break;
case MAILER_QUIT:
nb_fprintf(ml->socket, "QUIT\r\n");
success = "221";
break;
int status = observable_create (&(mailer->observable), mailer);
if (status != 0)
return status;
}
nb_fgets(ml->line_buf, sizeof(ml->line_buf), ml->socket);
if (strncmp(ml->line_buf, success, 3) == 0)
return (0);
else
return (-strtol(ml->line_buf, 0, 10));
return observable_attach (mailer->observable, observer);
}
char *
nb_fgets( char *buf, int size, int s )
int
mailer_detach (mailer_t mailer, observer_t observer)
{
static char *buffer[25];
char *p, *b, *d;
int bytes, i;
int flags;
/* FIXME: I should check for invalid types */
if (mailer == NULL || observer == NULL)
return EINVAL;
if (mailer->observable == NULL)
return 0;
return observable_detach (mailer->observable, observer);
}
if ( !buffer[s] && !( buffer[s] = calloc( BUFFSIZE+1, 1 ) ) )
int
mailer_set_debug (mailer_t mailer, debug_t debug)
{
if (mailer == NULL)
return EINVAL;
debug_destroy (&(mailer->debug), mailer);
mailer->debug = debug;
return 0;
bytes = i = strlen( p = b = buffer[s] );
*( d = buf ) = '\0';
for ( ; i-- > 0; p++ )
{
if ( *p == '\n' )
{
char c = *( p+1 );
}
*( p+1 ) = '\0';
strcat( d, b );
*( p+1 ) = c;
memmove( b, p+1, i+1 );
return buf;
}
}
flags = fcntl( s, F_GETFL );
fcntl( s, F_SETFL, O_NONBLOCK );
while ( bytes <= size )
int
mailer_get_debug (mailer_t mailer, debug_t *pdebug)
{
if (mailer == NULL || pdebug == NULL)
return EINVAL;
if (mailer->debug == NULL)
{
fd_set fds;
int status = debug_create (&(mailer->debug), mailer);
if (status != 0)
return status;
}
*pdebug = mailer->debug;
return 0;
}
FD_ZERO( &fds );
FD_SET( s, &fds );
select( s+1, &fds, 0, 0, 0 ); /* we really don't care what it returns */
if ( ( i = nb_read( s, p, BUFFSIZE - bytes ) ) == -1 )
{
*b = '\0';
/* Mailer Internal Locks. Put the name of the functions in parenteses To make
they will not be redefine by the macro. If the flags was non-blocking we
should not block on the lock, so we try with pthread_rwlock_try*lock(). */
int
(mailer_wrlock) (mailer_t mailer)
{
#ifdef WITH_PTHREAD
int err = (mailer->flags & MU_STREAM_NONBLOCK) ?
RWLOCK_TRYWRLOCK (&(mailer->rwlock)) :
RWLOCK_WRLOCK (&(mailer->rwlock)) ;
if (err != 0 && err != EDEADLK)
return err;
#endif
return 0;
}
int
(mailer_rdlock) (mailer_t mailer)
{
#ifdef WITH_PTHREAD
int err = (mailer->flags & MU_STREAM_NONBLOCK) ?
RWLOCK_TRYRDLOCK (&(mailer->rwlock)) :
RWLOCK_RDLOCK (&(mailer->rwlock)) ;
if (err != 0 && err != EDEADLK)
return err;
#endif
return 0;
}
else if ( i == 0 )
{
*( p+1 ) = '\0';
strcat( d, b );
*b = '\0';
fcntl( s, F_SETFL, flags );
return strlen( buf ) ? buf : 0;
}
*( p+i ) = '\0';
bytes += i;
for ( ; i-- > 0; p++ )
{
if ( *p == '\n' )
{
char c = *( p+1 );
*( p+1 ) = '\0';
strcat( d, b );
*( p+1 ) = c;
memmove( b, p+1, i+1 );
fcntl( s, F_SETFL, flags );
return buf;
}
}
if ( bytes == BUFFSIZE )
{
memcpy( d, b, BUFFSIZE );
d += BUFFSIZE;
size -= BUFFSIZE;
bytes = 0;
*( p = b ) = '\0';
}
}
memcpy( d, b, size );
memmove( b, b+size, strlen( b+size )+1 );
fcntl( s, F_SETFL, flags );
return buf;
}
const char *
nb_fprintf( int s, const char *format, ... )
int
(mailer_unlock) (mailer_t mailer)
{
char buf[MAILER_LINE_BUF_SIZE];
va_list vl;
int i;
va_start( vl, format );
vsprintf( buf, format, vl );
va_end( vl );
i = strlen( buf );
if ( nb_write( s, buf, i ) != i )
#ifdef WITH_PTHREAD
return RWLOCK_UNLOCK (&(mailer->rwlock));
#else
return 0;
return format;
#endif
}
......
......@@ -15,6 +15,9 @@
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 <stdio.h>
......@@ -26,12 +29,12 @@
#include <fcntl.h>
#include <unistd.h>
#include <stream0.h>
#include <mailutils/stream.h>
#ifdef _POSIX_MAPPED_FILES
#include <sys/mman.h>
struct _mapfile_stream
{
int fd;
......@@ -43,7 +46,7 @@ struct _mapfile_stream
static void
_mapfile_destroy (stream_t stream)
{
struct _mapfile_stream *mfs = stream->owner;
struct _mapfile_stream *mfs = stream_get_owner (stream);
if (mfs && mfs->ptr)
{
......@@ -57,7 +60,7 @@ static int
_mapfile_read (stream_t stream, char *optr, size_t osize,
off_t offset, size_t *nbytes)
{
struct _mapfile_stream *mfs = stream->owner;
struct _mapfile_stream *mfs = stream_get_owner (stream);
size_t n;
if (mfs == NULL || mfs->ptr == NULL)
......@@ -82,7 +85,7 @@ static int
_mapfile_readline (stream_t stream, char *optr, size_t osize,
off_t offset, size_t *nbytes)
{
struct _mapfile_stream *mfs = stream->owner;
struct _mapfile_stream *mfs = stream_get_owner (stream);
char *nl;
size_t n = 0;
......@@ -111,7 +114,7 @@ static int
_mapfile_write (stream_t stream, const char *iptr, size_t isize,
off_t offset, size_t *nbytes)
{
struct _mapfile_stream *mfs = stream->owner;
struct _mapfile_stream *mfs = stream_get_owner (stream);
if (mfs == NULL || mfs->ptr == NULL)
return EINVAL;
......@@ -151,7 +154,7 @@ _mapfile_write (stream_t stream, const char *iptr, size_t isize,
static int
_mapfile_truncate (stream_t stream, off_t len)
{
struct _mapfile_stream *mfs = stream->owner;
struct _mapfile_stream *mfs = stream_get_owner (stream);
if (mfs == NULL || mfs->ptr == NULL)
return EINVAL;
/* Remap. */
......@@ -178,7 +181,7 @@ _mapfile_truncate (stream_t stream, off_t len)
static int
_mapfile_size (stream_t stream, off_t *psize)
{
struct _mapfile_stream *mfs = stream->owner;
struct _mapfile_stream *mfs = stream_get_owner (stream);
struct stat stbuf;
if (mfs == NULL || mfs->ptr == NULL)
......@@ -194,7 +197,7 @@ _mapfile_size (stream_t stream, off_t *psize)
static int
_mapfile_flush (stream_t stream)
{
struct _mapfile_stream *mfs = stream->owner;
struct _mapfile_stream *mfs = stream_get_owner (stream);
if (mfs == NULL)
return EINVAL;
return msync (mfs->ptr, mfs->size, MS_SYNC);
......@@ -203,7 +206,7 @@ _mapfile_flush (stream_t stream)
static int
_mapfile_get_fd (stream_t stream, int *pfd)
{
struct _mapfile_stream *mfs = stream->owner;
struct _mapfile_stream *mfs = stream_get_owner (stream);
if (mfs == NULL)
return EINVAL;
if (pfd)
......@@ -214,7 +217,7 @@ _mapfile_get_fd (stream_t stream, int *pfd)
static int
_mapfile_close (stream_t stream)
{
struct _mapfile_stream *mfs = stream->owner;
struct _mapfile_stream *mfs = stream_get_owner (stream);
int err = 0;
if (mfs && mfs->ptr)
{
......@@ -231,7 +234,7 @@ _mapfile_close (stream_t stream)
static int
_mapfile_open (stream_t stream, const char *filename, int port, int flags)
{
struct _mapfile_stream *mfs = stream->owner;
struct _mapfile_stream *mfs = stream_get_owner (stream);
int mflag, flg;
struct stat st;
......@@ -277,7 +280,7 @@ _mapfile_open (stream_t stream, const char *filename, int port, int flags)
return err;
}
mfs->flags = mflag;
stream_set_flags (stream, flags |MU_STREAM_NO_CHECK, mfs);
stream_set_flags (stream, flags |MU_STREAM_NO_CHECK);
return 0;
}
......
/* 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 <string.h>
#include <stdlib.h>
#include <paths.h>
#include <errno.h>
#include <stdio.h>
#include <mailutils/mailbox.h>
#ifndef _PATH_MAILDIR
......
/* 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 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 <errno.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <mailbox0.h>
#include <registrar0.h>
static int mailbox_file_init (mailbox_t mbox);
/* Register variables. */
static struct mailbox_entry _file_entry =
{
url_file_init, mailbox_file_init
};
mailbox_entry_t file_entry = &_file_entry;
static struct _record _file_record =
{
MU_FILE_SCHEME,
&_file_entry, /* Mailbox entry. */
NULL, /* Mailer entry. */
0, /* Not malloc()ed. */
NULL, /* No need for an owner. */
NULL, /* is_scheme method. */
NULL, /* get_mailbox method. */
NULL /* get_mailer method. */
};
record_t file_record = &_file_record;
/* Register variables. */
static struct mailbox_entry _path_entry =
{
url_path_init, mailbox_file_init
};
mailbox_entry_t path_entry = &_path_entry;
static struct _record _path_record =
{
MU_PATH_SCHEME,
&_path_entry, /* Mailbox entry. */
NULL, /* Mailer entry. */
0, /* Not malloc()ed. */
NULL, /* No need for an owner. */
NULL, /* is_scheme method. */
NULL, /* get_mailbox method. */
NULL /* get_mailer method. */
};
record_t path_record = &_path_record;
/*
Caveat there is no specific URL for file mailbox or simple path name,
<path_name>
file:<path_name>
It would be preferrable to use :
maildir:<path>
unix:<path>
mmdf:<path>
This would eliminate heuristic discovery that would turn
out to be wrong.
*/
static int
mailbox_file_init (mailbox_t mbox)
{
struct stat st;
size_t len = 0;
char *path;
int status;
status = url_get_path (mbox->url, NULL, 0, &len);
if (status != 0)
return status;
path = calloc (len + 1, sizeof (char));
if (path == NULL)
return ENOMEM;
status = url_get_path (mbox->url, path, len + 1, NULL);
if (status != 0)
{
free (path);
return status;
}
/* Sigh, if they want to creat ??? they should know the type of ???
What is the best course of action ? For the default is mbox if the
file does not exist. */
if (stat (path, &st) < 0)
{
status = mbox_entry->_mailbox_init (mbox);
}
else if (S_ISREG (st.st_mode))
{
/*
FIXME: We should do an open() and try
to do a better reconnaissance of the type,
maybe MMDF. For now assume Unix MBox */
status = mbox_entry->_mailbox_init (mbox);
}
/* Is that true ? Are all directories Maildir ?? */
else if (S_ISDIR (st.st_mode))
{
/*status = maildir_entry._mailbox_init (mbox);*/
status = EINVAL;
}
free (path);
return status;
}
......@@ -2,7 +2,7 @@
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
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.
......@@ -14,122 +14,1381 @@
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. */
/* First draft by Alain Magloire */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <signal.h>
#include <time.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <errno.h>
#include <sys/stat.h>
#include <mailbox0.h>
#include <mailutils/message.h>
#include <mailutils/stream.h>
#include <mailutils/body.h>
#include <mailutils/header.h>
#include <mailutils/attribute.h>
#include <registrar0.h>
#include <mailbox0.h>
#define ATTRIBUTE_IS_DELETED(flag) (flag & MU_ATTRIBUTE_DELETED)
#define ATTRIBUTE_IS_EQUAL(flag1, flag2) (flag1 == flag2)
static int mbox_init (mailbox_t mailbox);
static int mailbox_mbox_create (mailbox_t *mbox, const char *name);
static void mailbox_mbox_destroy (mailbox_t *mbox);
/* Register variables. */
static struct mailbox_entry _mbox_entry =
{
url_mbox_init, mbox_init
};
mailbox_entry_t mbox_entry = &_mbox_entry;
struct mailbox_registrar _mailbox_mbox_registrar =
static struct _record _mbox_record =
{
"UNIX_MBOX/Maildir/MMDF",
mailbox_mbox_create, mailbox_mbox_destroy
MU_MBOX_SCHEME,
&_mbox_entry, /* Mailbox entry. */
NULL, /* Mailer entry. */
0, /* Not malloc()ed. */
NULL, /* No need for an owner. */
NULL, /* is_scheme method. */
NULL, /* get_mailbox method. */
NULL /* get_mailer method. */
};
record_t mbox_record = &_mbox_record;
static void mbox_destroy (mailbox_t);
struct _mbox_message;
struct _mbox_data;
typedef struct _mbox_data* mbox_data_t;
typedef struct _mbox_message* mbox_message_t;
/* Keep the position of where the header and body starts and ends.
old_flags is the "Status:" message. */
struct _mbox_message
{
/* Offset of the parts of the messages in the mailbox. */
off_t header_from;
off_t header_from_end;
/* Little hack to make things easier when updating the attribute. */
off_t header_status;
off_t header_status_end;
off_t body;
off_t body_end;
/* The old_flags contains the definition of Header. */
int old_flags;
/* The new_flags holds the attributes changes for the current session. We
use this so when expunging we can tell when an attribute been modified.
This is a big help so we can jump to the first modify email for speed
in expunging (see mark dirty). */
int new_flags;
size_t header_lines;
size_t body_lines;
stream_t stream;
/* A message attach to it. */
message_t message;
mbox_data_t mud; /* Back pointer. */
};
/* The umessages is an array of pointers that contains umessages_count of
mbox_message_t*; umessages[umessages_count]. We do it this way because
realloc() can move everything to a new memory region and invalidate all
the pointers. Thanks to <Dave Inglis> for pointing this out. The
messages_count is the count number of messages parsed so far. */
struct _mbox_data
{
mbox_message_t *umessages; /* Array. */
size_t umessages_count; /* How big is the umessages[]. */
size_t messages_count; /* How many valid entry in umessages[]. */
stream_t stream;
off_t size;
char *name;
/* The variables below are use to hold the state when appending messages. */
enum mbox_state
{
MBOX_NO_STATE=0, MBOX_STATE_FROM, MBOX_STATE_DATE, MBOX_STATE_APPEND
} state ;
char *from;
char *date;
off_t off;
mailbox_t mailbox; /* Back pointer. */
};
/*
Caveat there is no specific URL for file mailbox or simple path name,
<path_name>
file:<path_name>
/* Mailbox concrete implementation. */
static int mbox_open (mailbox_t, int);
static int mbox_close (mailbox_t);
static int mbox_get_message (mailbox_t, size_t, message_t *);
static int mbox_append_message (mailbox_t, message_t);
static int mbox_messages_count (mailbox_t, size_t *);
static int mbox_expunge (mailbox_t);
static int mbox_scan (mailbox_t, size_t, size_t *);
static int mbox_is_updated (mailbox_t);
static int mbox_size (mailbox_t, off_t *);
It would be preferrable to use :
maildir:<path>
unix:<path>
mmdf:<path>
This would eliminate heuristic discovery that would turn
out to be wrong.
*/
/* private stuff */
static int mbox_scan0 (mailbox_t, size_t, size_t *, int);
static int mbox_get_header_read (stream_t, char *, size_t, off_t, size_t *);
static int mbox_get_hdr_fd (stream_t, int *);
static int mbox_get_body_fd (stream_t, int *);
static int mbox_get_fd (mbox_message_t, int *);
static int mbox_get_attr_flags (attribute_t, int *);
static int mbox_set_attr_flags (attribute_t, int);
static int mbox_unset_attr_flags (attribute_t, int);
static int mbox_readstream (stream_t, char *, size_t, off_t, size_t *);
static int mbox_header_size (header_t, size_t *);
static int mbox_header_lines (header_t, size_t *);
static int mbox_body_size (body_t, size_t *);
static int mbox_body_lines (body_t, size_t *);
static int mbox_msg_from (message_t, char *, size_t, size_t *);
static int mbox_msg_received (message_t, char *, size_t, size_t *);
static int mbox_lock (mailbox_t, int);
static int mbox_touchlock (mailbox_t);
static int mbox_unlock (mailbox_t);
/* We allocate the mbox_data_t struct, but don't do any parsing on the name or
even test for existence. However we do strip any leading "mbox:" part of
the name, this is suppose to be the protocol/scheme name. */
static int
mailbox_mbox_create (mailbox_t *mbox, const char *name)
mbox_init (mailbox_t mailbox)
{
struct stat st;
size_t len;
mbox_data_t mud;
size_t name_len;
if (name == NULL || mbox == NULL)
if (mailbox == NULL)
return EINVAL;
len = strlen (name);
if (len >= 5 &&
(name[0] == 'f' || name[0] == 'F') &&
(name[1] == 'i' || name[1] == 'I') &&
(name[2] == 'l' || name[2] == 'L') &&
(name[3] == 'e' || name[3] == 'E') &&
name[4] == ':')
/* Allocate specific mbox data. */
mud = mailbox->data = calloc (1, sizeof (*mud));
if (mailbox->data == NULL)
return ENOMEM;
/* Back pointer. */
mud->mailbox = mailbox;
/* Copy the name.
We do not do any further interpretation after the scheme "mbox:"
Because for example on distributed system like QnX4 a file name is
//390/etc/passwd. So the best approach is to let the OS handle it
for example if we receive: "mbox:///var/mail/alain" the mailbox name
will be "///var/mail/alain", we let open() do the right thing.
So it will let things like this "mbox://390/var/mail/alain" where
"//390/var/mail/alain" _is_ the filename, pass correctely. */
url_get_path (mailbox->url, NULL, 0, &name_len);
mud->name = calloc (name_len + 1, sizeof (char));
if (mud->name == NULL)
{
name += 5;
mbox_destroy (mailbox);
return ENOMEM;
}
/*
* If they want to creat ?? should they know the type ???
* What is the best course of action ??
* For the default is unix if the file does not exist.
*/
if (stat (name, &st) < 0)
return _mailbox_unix_registrar._create (mbox, name);
url_get_path (mailbox->url, mud->name, name_len + 1, NULL);
mud->state = MBOX_NO_STATE;
/* Overloading the default. */
mailbox->_init = mbox_init;
mailbox->_destroy = mbox_destroy;
mailbox->_open = mbox_open;
mailbox->_close = mbox_close;
if (S_ISREG (st.st_mode))
/* Messages. */
mailbox->_get_message = mbox_get_message;
mailbox->_append_message = mbox_append_message;
mailbox->_messages_count = mbox_messages_count;
mailbox->_expunge = mbox_expunge;
mailbox->_scan = mbox_scan;
mailbox->_is_updated = mbox_is_updated;
mailbox->_size = mbox_size;
MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE, "mbox_init(%s)\n", mud->name);
return 0; /* okdoke */
}
/* Free all ressources associated with Unix mailbox. */
static void
mbox_destroy (mailbox_t mailbox)
{
mbox_close (mailbox);
if (mailbox->data)
{
size_t i;
mbox_data_t mud = mailbox->data;
MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE,
"mbox_destroy (%s/%s)\n", mud->name);
mailbox_wrlock (mailbox);
for (i = 0; i < mud->umessages_count; i++)
{
mbox_message_t mum = mud->umessages[i];
if (mum == NULL)
{
/*
FIXME: We should do an open() and try
to do a better reconnaissance of the type,
maybe MMDF. For now assume Unix MBox */
#if 0
char head[6];
ssize_t cout;
message_destroy (&(mum->message), mum);
free (mum);
}
}
if (mud->umessages)
free (mud->umessages);
if (mud->name)
free (mud->name);
free (mailbox->data);
mailbox->data = NULL;
mailbox_unlock (mailbox);
}
}
/* Open the file. */
static int
mbox_open (mailbox_t mailbox, int flags)
{
mbox_data_t mud = mailbox->data;
int status = 0;
if (mud == NULL)
return EINVAL;
mailbox->flags = flags | MU_STREAM_FILE;
mailbox_rdlock (mailbox);
/* Get a stream. */
if (mailbox->stream == NULL)
{
/* FIXME: for small mbox we should try to mmap (). */
status = (flags & MU_STREAM_CREAT) || (mailbox->flags & MU_STREAM_APPEND);
if (status == 0)
status = mapfile_stream_create (&(mailbox->stream));
if (status != 0)
{
status = file_stream_create (&(mailbox->stream));
if (status != 0)
{
mailbox_unlock (mailbox);
return status;
}
}
status = stream_open (mailbox->stream, mud->name, 0, mailbox->flags);
if (status != 0)
{
mailbox_unlock (mailbox);
return status;
}
}
else
{
status = stream_open (mailbox->stream, mud->name, 0, mailbox->flags);
if (status != 0)
{
mailbox_unlock (mailbox);
return status;
}
}
MAILBOX_DEBUG2 (mailbox, MU_DEBUG_TRACE, "mbox_open(%s, %d)\n",
mud->name, mailbox->flags);
/* Give an appopriate way to lock. */
if (mailbox->locker == NULL)
locker_create (&(mailbox->locker), mud->name, strlen (mud->name),
MU_LOCKER_PID | MU_LOCKER_FCNTL);
mailbox_unlock (mailbox);
return 0;
}
static int
mbox_close (mailbox_t mailbox)
{
mbox_data_t mud = mailbox->data;
size_t i;
if (mud == NULL)
return EINVAL;
/* Make sure we do not hold any lock for that file. */
mbox_unlock (mailbox);
MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE, "mbox_close(%s)\n", mud->name);
mailbox_wrlock (mailbox);
/* Before closing we need to remove all the messages
- to reclaim the memory
- to prepare for another scan. */
for (i = 0; i < mud->umessages_count; i++)
{
mbox_message_t mum = mud->umessages[i];
/* Destroy the attach messages. */
if (mum == NULL)
{
message_destroy (&(mum->message), mum);
free (mum);
}
}
free (mud->umessages);
mud->umessages = NULL;
mud->messages_count = mud->umessages_count = 0;
mud->size = 0;
mailbox_unlock (mailbox);
return stream_close (mailbox->stream);
}
/* Mailbox Parsing. */
#include "mbx_mboxscan.c"
static int
mbox_scan (mailbox_t mailbox, size_t msgno, size_t *pcount)
{
mbox_data_t mud = mailbox->data;
MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE, "mbox_scan(%s)\n", mud->name);
return mbox_scan0 (mailbox, msgno, pcount, 1);
}
/* FIXME: How to handle a shrink ? meaning, the &^$^@%#@^& user start two
browsers and delete files in one. My views is that we should scream
bloody murder and hunt them with a machette. But for now just play dumb,
but maybe the best approach is to pack our things and leave .i.e exit(). */
static int
mbox_is_updated (mailbox_t mailbox)
{
off_t size;
mbox_data_t mud = mailbox->data;
int status;
if (mud == NULL)
return EINVAL;
mailbox_rdlock (mailbox);
if (stream_size (mailbox->stream, &size) != 0)
{
mailbox_unlock (mailbox);
return 0;
}
status = (mud->size == size);
mailbox_unlock (mailbox);
return status;
}
/* FIXME: the use of tmpfile() on some system can lead to race condition, We
should use a safer approach. */
static FILE *
mbox_tmpfile (mailbox_t mailbox, char **pbox)
{
const char *tmpdir;
int fd;
FILE *fp;
const char *basename;
mbox_data_t mud = mailbox->data;
/* P_tmpdir should be define in <stdio.h>. */
#ifndef P_tmpdir
# define P_tmpdir "/tmp"
#endif
tmpdir = getenv ("TEMPDIR") ? getenv ("TEMPDIR") : P_tmpdir;
basename = strrchr (mud->name, '/');
if (basename)
basename++;
else
basename = mud->name;
*pbox = calloc (strlen (tmpdir) + strlen ("MBOX_") +
strlen (basename) + 1, sizeof (char));
if (*pbox == NULL)
return NULL;
sprintf (*pbox, "%s/%s%s", tmpdir, "MBOX_", basename);
fd = open (name, O_RDONLY);
if (fd == -1)
/* FIXME: I don't think this is the righ approach, creating an anonymous
file would be better ? no trace left behind. */
/* Create the file. It must not exist. If it does exist, fail. */
fd = open (*pbox, O_RDWR|O_CREAT|O_EXCL, 0600);
if (fd < 0)
{
/* Oops !! wrong permission ? file deleted ? */
return errno; /* errno set by open () */
fprintf (stderr,"Can't create %s\n", *pbox);
fprintf (stderr,"delete file <%s>, Please\n", *pbox);
fprintf (stderr, "It was likely due to an error when expunging\n");
return NULL;
}
fp = fdopen (fd, "w+");
if (fp == 0)
{
close(fd);
free (*pbox);
*pbox = NULL;
}
/* Read a small chunck */
count = read (fd, head, sizeof(head));
/* Really I should just remove the file here. */
/* remove(*pbox); */
return fp;
}
/* Try Unix Mbox */
/* For the expunge bits we took a very cautionnary approach, meaning
we create temporary file in the tmpdir copy all the file not mark deleted,
and skip the deleted ones, truncate the real mailbox to the desired size
and overwrite with the tmp mailbox. The approach to do everyting
in core is tempting but require to much memory, it is not rare now
a day to have 30 Megs mailbox, also there is danger for filesystems
with quotas, or some program may not respect the advisory lock and
decide to append a new message while your expunging etc ...
The real downside to the approach we take is that when things go wrong
the temporary file bay be left in /tmp, which is not all that bad
because at least have something to recuparate when failure. */
static int
mbox_expunge (mailbox_t mailbox)
{
mbox_data_t mud = mailbox->data;
mbox_message_t mum;
int status = 0;
sigset_t signalset;
FILE *tempfile;
size_t nread;
size_t i, j, dirty, first;
off_t marker = 0;
off_t total = 0;
char buffer [BUFSIZ];
char *tmpmbox = NULL;
if (mud == NULL)
return EINVAL;
/* FIXME:
What happen if the file is empty ???
Do we default to Unix ??
*/
if (count == 0) /*empty file*/
MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE, "mbox_expunge (%s)\n", mud->name);
/* Noop. */
if (mud->messages_count == 0)
return 0;
/* Do we have a consistent view of the mailbox. */
if (! mbox_is_updated (mailbox))
{
close (fd);
return _mailbox_unix_registrar._create (mbox, name);
fprintf (stderr, "mailbox is not updated, try again.\n");
return EAGAIN;
}
if (count >= 5)
mailbox_wrlock (mailbox);
/* Mark dirty the first mail with an attribute change. */
for (dirty = 0; dirty < mud->messages_count; dirty++)
{
if (strncmp (head, "From ", 5) == 0)
mum = mud->umessages[dirty];
if (mum->new_flags &&
! ATTRIBUTE_IS_EQUAL (mum->old_flags, mum->new_flags))
break;
}
/* Did something change ? */
if (dirty == mud->messages_count)
{
/* This is a Unix Mbox */
close (fd);
return _mailbox_unix_registrar._create (mbox, name);
mailbox_unlock (mailbox);
return 0; /* Nothing change, bail out. */
}
/* This is redundant, we go to the loop again. But it's more secure here
since we don't want to be disturb when expunging. */
for (j = 0; j < mud->messages_count; j++)
{
mum = mud->umessages[j];
if (mum && mum->new_flags && ATTRIBUTE_IS_DELETED (mum->new_flags))
message_destroy (&(mum->message), mum);
}
/* Try MMDF */
close (fd);
#endif
return _mailbox_unix_registrar._create (mbox, name);
/* Create a tempory file. */
tempfile = mbox_tmpfile (mailbox, &tmpmbox);
if (tempfile == NULL)
{
fprintf (stderr, "Failed to create temporary file when expunging.\n");
free (tmpmbox);
mailbox_unlock (mailbox);
return errno;
}
/* Get the lock. */
if (mbox_lock (mailbox, MU_LOCKER_WRLOCK) < 0)
{
fclose (tempfile);
remove (tmpmbox);
free (tmpmbox);
fprintf (stderr, "Failed to grab the lock\n");
mailbox_unlock (mailbox);
return ENOLCK;
}
/* Critical section, we can not allowed signal here. */
sigemptyset (&signalset);
sigaddset (&signalset, SIGTERM);
sigaddset (&signalset, SIGHUP);
sigaddset (&signalset, SIGTSTP);
sigaddset (&signalset, SIGINT);
sigaddset (&signalset, SIGWINCH);
sigprocmask (SIG_BLOCK, &signalset, 0);
/* Set the marker position. */
total = marker = mud->umessages[dirty]->header_from;
/* Copy to tempfile emails not mark deleted. */
for (first = 1, i = dirty; i < mud->messages_count; i++)
{
mum = mud->umessages[i];
/* Skip it, if mark for deletion. */
if (ATTRIBUTE_IS_DELETED (mum->new_flags))
continue;
/* Add a NL separator between messages. */
if (first)
first = 0;
else
{
fputc ('\n', tempfile);
total++;
}
/* Is that true ? Are all directories Maildir ?? */
else if (S_ISDIR (st.st_mode))
return _mailbox_maildir_registrar._create (mbox, name);
/* Why can't a mailbox be FIFO ? or a DOOR/Portal ??? */
/* Begining of header copy. */
{
off_t current;
/* This is done in two parts first we check if the attribute changed,
if yes then we have to update the "Status:" field. Unfortunately
there is no requirement for the "Status:" to be the last field, so
we take the long approach; Copy up to the Status, update the
Status and copy the rest. */
/* Attribute change ? */
if (mum->new_flags
&&! ATTRIBUTE_IS_EQUAL (mum->old_flags, mum->new_flags)
&& mum->header_status > mum->header_from)
{
size_t n = 0;
off_t offset = mum->header_from;
size_t len = mum->header_status - mum->header_from;
current = mum->header_status_end;
while (len > 0)
{
nread = (len < sizeof (buffer)) ? len : sizeof (buffer);
if ((status = stream_read (mailbox->stream, buffer,
nread, offset, &n) != 0)
|| fwrite(buffer, sizeof(*buffer), n, tempfile) != n)
{
if (status == 0)
status = errno;
fprintf (stderr, "Error expunge:%d: (%s)\n", __LINE__,
strerror (status));
goto bailout0;
}
len -= n;
total += n;
offset += n;
}
/* Put the new attributes. */
{
char abuf[64];
size_t na = 0;
abuf[0] = '\0';
flags_to_string (mum->new_flags, abuf, sizeof(abuf), &na);
fputs (abuf, tempfile);
total += na;
}
}
else /* Attribute did not change. */
current = mum->header_from;
/* Copy the rest of header without changes. */
{
size_t n = 0;
off_t offset = current;
size_t len = mum->body - current;
while (len > 0)
{
nread = (len < sizeof (buffer)) ? len : sizeof (buffer);
if ((status = stream_read (mailbox->stream, buffer, nread,
offset, &n) != 0)
|| fwrite(buffer, sizeof(*buffer), n, tempfile) != n)
{
if (status == 0)
status = errno;
fprintf (stderr, "Error expunge:%d: %s", __LINE__,
strerror (status));
goto bailout0;
}
len -= n;
total += n;
offset += n;
}
}
} /* End of header copy. */
/* Copy the body. */
{
size_t n = 0;
off_t offset = mum->body;
size_t len = mum->body_end - mum->body;
while (len > 0)
{
nread = (len < sizeof (buffer)) ? len : sizeof (buffer);
if ((status = stream_read (mailbox->stream, buffer, nread,
offset, &n) != 0)
|| fwrite(buffer, sizeof(*buffer), n, tempfile) != n)
{
if (status == 0)
status = errno;
fprintf (stderr, "Error expunge:%d: %s", __LINE__,
strerror (status));
goto bailout0;
}
len -= n;
total += n;
offset += n;
}
} /* End of body copy. */
} /* for (;;) */
/* Caution: before ftruncate()ing the file see if we've receiving new mail
Some program may not respect the lock, or the lock was held for too
long. */
{
off_t size = 0;
if (stream_size (mailbox->stream, &size) == 0)
{
size_t n = 0;
off_t offset = size;
size_t len = size - mud->size;
while (len > 0)
{
nread = (len < sizeof (buffer)) ? len : sizeof (buffer);
if ((status = stream_read (mailbox->stream, buffer, nread,
offset, &n) != 0)
|| fwrite(buffer, sizeof(*buffer), n, tempfile) != n)
{
if (status == 0)
status = errno;
fprintf (stderr, "Error expunge:%d: %s", __LINE__,
strerror (status));
goto bailout0;
}
len -= n;
total += n;
offset += n;
}
}
} /* End of precaution. */
/* Seek and rewrite it. */
rewind (tempfile);
if (total > 0)
{
size_t n = 0;
off_t offset = marker;
while ((nread = fread (buffer, sizeof (*buffer),
sizeof (buffer), tempfile)) != 0)
{
while (nread)
{
status = stream_write (mailbox->stream, buffer, nread, offset, &n);
if (status != 0)
{
fprintf (stderr, "Error expunge:%d: %s\n", __LINE__,
strerror (status));
goto bailout;
}
nread -= n;
offset += n;
}
}
}
/* How can I handle error here ?? */
clearerr (tempfile);
/* Flush/truncation. */
stream_flush (mailbox->stream);
status = stream_truncate (mailbox->stream, total);
if (status != 0)
{
fprintf (stderr, "Error expunging:%d: %s", __LINE__, strerror (status));
goto bailout;
}
bailout0:
/* Don't remove the tmp mbox in case of errors, when writing back. */
remove (tmpmbox);
bailout:
free (tmpmbox);
/* Release the locks. */
mbox_unlock (mailbox);
fclose (tempfile);
sigprocmask (SIG_UNBLOCK, &signalset, 0);
/* We need to readjust the pointers. */
if (status == 0)
{
size_t dlast;
for (j = dirty, dlast = mud->messages_count - 1;
j < mud->messages_count; j++)
{
/* Clear all the references, any attach messages been already
destroy above. */
mum = mud->umessages[j];
if (mum->new_flags && ATTRIBUTE_IS_DELETED (mum->new_flags))
{
memmove (mud->umessages + j, mud->umessages + j + 1,
(dlast - dirty) * sizeof (mum));
mum->header_from = mum->header_from_end = 0;
mum->header_status = mum->header_status_end = 0;
mum->body = mum->body_end = 0;
mum->header_lines = mum->body_lines = 0;
mud->umessages[dlast] = mum;
dlast--;
mum = mud->umessages[j];
}
mum->header_from = mum->header_from_end = 0;
mum->header_status = mum->header_status_end = 0;
mum->body = mum->body_end = 0;
mum->header_lines = mum->body_lines = 0;
}
/* This is should reset the messages_count, the last argument 0 means
not to send event notification. */
mailbox_unlock (mailbox);
mbox_scan0 (mailbox, dirty, NULL, 0);
}
else
mailbox_unlock (mailbox);
return status;
}
static int
mbox_get_body_fd (stream_t is, int *pfd)
{
body_t body = stream_get_owner (is);
message_t msg = body_get_owner (body);
mbox_message_t mum = message_get_owner (msg);
return mbox_get_fd (mum, pfd);
}
static int
mbox_get_hdr_fd (stream_t is, int *pfd)
{
header_t header = stream_get_owner (is);
message_t msg = header_get_owner (header);
mbox_message_t mum = message_get_owner (msg);
return mbox_get_fd (mum, pfd);
}
static int
mbox_get_fd (mbox_message_t mum, int *pfd)
{
int status;
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
status = stream_get_fd (mum->stream, pfd);
mailbox_unlock (mum->mud->mailbox);
return status;
}
static void
mailbox_mbox_destroy (mailbox_t *pmbox)
static int
mbox_get_attr_flags (attribute_t attr, int *pflags)
{
if (pmbox && *pmbox)
_mailbox_unix_registrar._destroy (pmbox);
message_t msg = attribute_get_owner (attr);
mbox_message_t mum = message_get_owner (msg);
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
if (pflags)
*pflags = mum->new_flags;
mailbox_unlock (mum->mud->mailbox);
return 0;
}
static int
mbox_set_attr_flags (attribute_t attr, int flags)
{
message_t msg = attribute_get_owner (attr);
mbox_message_t mum = message_get_owner (msg);
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
mum->new_flags |= flags;
mailbox_unlock (mum->mud->mailbox);
return 0;
}
static int
mbox_unset_attr_flags (attribute_t attr, int flags)
{
message_t msg = attribute_get_owner (attr);
mbox_message_t mum = message_get_owner (msg);
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
mum->new_flags &= ~flags;
mailbox_unlock (mum->mud->mailbox);
return 0;
}
static int
mbox_readstream (stream_t is, char *buffer, size_t buflen,
off_t off, size_t *pnread)
{
body_t body = stream_get_owner (is);
message_t msg = body_get_owner (body);
mbox_message_t mum = message_get_owner (msg);
size_t nread = 0;
if (mum == NULL)
return EINVAL;
if (buffer == NULL || buflen == 0)
{
if (pnread)
*pnread = nread;
return 0;
}
mailbox_rdlock (mum->mud->mailbox);
{
off_t ln = mum->body_end - (mum->body + off);
size_t n = 0;
int status;
if (ln > 0)
{
nread = ((size_t)ln < buflen) ? ln : buflen;
/* Position the file pointer and the buffer. */
status = stream_read (mum->stream, buffer, nread, mum->body + off, &n);
if (status != 0)
{
mailbox_unlock (mum->mud->mailbox);
return status;
}
}
}
mailbox_unlock (mum->mud->mailbox);
if (pnread)
*pnread = nread;
return 0;
}
static int
mbox_get_header_read (stream_t is, char *buffer, size_t len,
off_t off, size_t *pnread)
{
header_t header = stream_get_owner (is);
message_t msg = header_get_owner (header);
mbox_message_t mum = message_get_owner (msg);
size_t nread = 0;
int status = 0;
off_t ln;
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
ln = mum->body - (mum->header_from_end + off);
if (ln > 0)
{
nread = ((size_t)ln < len) ? ln : len;
/* Position the file pointer and the buffer. */
status = stream_read (mum->stream, buffer, nread,
mum->header_from_end + off, &nread);
}
if (pnread)
*pnread = nread;
mailbox_unlock (mum->mud->mailbox);
return status;
}
static int
mbox_header_size (header_t header, size_t *psize)
{
message_t msg = header_get_owner (header);
mbox_message_t mum = message_get_owner (msg);
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
if (psize)
*psize = mum->body - mum->header_from_end;
mailbox_unlock (mum->mud->mailbox);
return 0;
}
static int
mbox_header_lines (header_t header, size_t *plines)
{
message_t msg = header_get_owner (header);
mbox_message_t mum = message_get_owner (msg);
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
if (plines)
*plines = mum->header_lines;
mailbox_unlock (mum->mud->mailbox);
return 0;
}
static int
mbox_body_size (body_t body, size_t *psize)
{
message_t msg = body_get_owner (body);
mbox_message_t mum = message_get_owner (msg);
if (mum == NULL)
return EINVAL;
if (psize)
*psize = mum->body_end - mum->body + 1;
return 0;
}
static int
mbox_body_lines (body_t body, size_t *plines)
{
message_t msg = body_get_owner (body);
mbox_message_t mum = message_get_owner (msg);
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
if (plines)
*plines = mum->body_lines;
mailbox_unlock (mum->mud->mailbox);
return 0;
}
static int
mbox_msg_received (message_t msg, char *buf, size_t len,
size_t *pnwrite)
{
mbox_message_t mum = message_get_owner (msg);
size_t n = 0;
int status;
char buffer[512];
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
status = stream_readline (mum->stream, buffer, sizeof(buffer),
mum->header_from, &n);
mailbox_unlock (mum->mud->mailbox);
if (status != 0)
{
if (pnwrite)
*pnwrite = 0;
if (buf)
*buf = '\0';
return status;
}
if (n > 5)
{
char *s = strchr (buffer + 5, ' ');
if (s)
{
if (buf && len > 0)
{
strncpy (buf, s + 1, len);
buffer [len - 1] = '\0';
}
if (pnwrite)
*pnwrite = strlen (s + 1);
return 0;
}
}
if (pnwrite)
*pnwrite = 0;
if (buf)
*buf = '\0';
return 0;
}
static int
mbox_msg_from (message_t msg, char *buf, size_t len, size_t *pnwrite)
{
mbox_message_t mum = message_get_owner (msg);
size_t n = 0;
int status;
char buffer[512];
if (mum == NULL)
return EINVAL;
mailbox_rdlock (mum->mud->mailbox);
status = stream_readline (mum->stream, buffer, sizeof(buffer),
mum->header_from, &n);
mailbox_unlock (mum->mud->mailbox);
if (status != 0)
{
if (pnwrite)
*pnwrite = 0;
if (buf)
*buf = '\0';
return status;
}
if (n > 5)
{
char *s = strchr (buffer + 5, ' ');
if (s)
{
*s = '\0';
if (buf && len > 0)
{
strncpy (buf, buffer + 5, len);
buffer [len - 1] = '\0';
}
if (pnwrite)
*pnwrite = strlen (buffer + 5);
return 0;
}
}
if (pnwrite)
*pnwrite = 0;
if (buf)
*buf = '\0';
return 0;
}
static int
mbox_get_message (mailbox_t mailbox, size_t msgno, message_t *pmsg)
{
int status;
mbox_data_t mud = mailbox->data;
mbox_message_t mum;
message_t msg = NULL;
/* Sanity checks. */
if (pmsg == NULL || mud == NULL || (!(mud->messages_count > 0 && msgno > 0
&& msgno <= mud->messages_count)))
return EINVAL;
mum = mud->umessages[msgno - 1];
/* Check if we already have it. */
if (mum->message)
{
if (pmsg)
*pmsg = mum->message;
return 0;
}
MAILBOX_DEBUG2 (mailbox, MU_DEBUG_TRACE, "mbox_get_message(%s, %d)\n",
mud->name, msgno);
/* Get an empty message struct. */
status = message_create (&msg, mum);
if (status != 0)
return status;
/* Set the header. */
{
header_t header = NULL;
stream_t stream = NULL;
if ((status = header_create (&header, NULL, 0, msg)) != 0
|| (status = stream_create (&stream, mailbox->flags, header)) != 0)
{
stream_destroy (&stream, header);
header_destroy (&header, msg);
message_destroy (&msg, mum);
return status;
}
stream_set_read (stream, mbox_get_header_read, header);
stream_set_fd (stream, mbox_get_hdr_fd, header);
header_set_stream (header, stream, msg);
header_set_size (header, mbox_header_size, msg);
header_set_lines (header, mbox_header_lines, msg);
message_set_header (msg, header, mum);
}
/* Set the attribute. */
{
attribute_t attribute;
status = attribute_create (&attribute, msg);
if (status != 0)
{
message_destroy (&msg, mum);
return status;
}
mum->new_flags = mum->old_flags;
attribute_set_get_flags (attribute, mbox_get_attr_flags, msg);
attribute_set_set_flags (attribute, mbox_set_attr_flags, msg);
attribute_set_unset_flags (attribute, mbox_unset_attr_flags, msg);
message_set_attribute (msg, attribute, mum);
}
/* Prepare the body. */
{
body_t body = NULL;
stream_t stream = NULL;
if ((status = body_create (&body, msg)) != 0
|| (status = stream_create (&stream, mailbox->flags, body)) != 0)
{
body_destroy (&body, msg);
stream_destroy (&stream, body);
message_destroy (&msg, mum);
return status;
}
stream_set_read (stream, mbox_readstream, body);
stream_set_fd (stream, mbox_get_body_fd, body);
body_set_stream (body, stream, msg);
body_set_size (body, mbox_body_size, msg);
body_set_lines (body, mbox_body_lines, msg);
message_set_body (msg, body, mum);
}
/* Set the envelope. */
message_set_from (msg, mbox_msg_from, mum);
message_set_received (msg, mbox_msg_received, mum);
/* Attach the message to the mailbox mbox data. */
mum->message = msg;
if (pmsg)
*pmsg = msg;
return 0;
}
static int
mbox_append_message (mailbox_t mailbox, message_t msg)
{
mbox_data_t mud = mailbox->data;
if (msg == NULL || mud == NULL)
return EINVAL;
MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE, "mbox_append_message (%s)\n",
mud->name);
mailbox_wrlock (mailbox);
mbox_lock (mailbox, MU_LOCKER_WRLOCK);
{
off_t size;
int status;
size_t n = 0;
char nl = '\n';
/* Move to the end of the file, not necesary if _APPEND mode. */
status = stream_size (mailbox->stream, &size);
if (status != 0)
{
mailbox_unlock (mailbox);
mbox_unlock (mailbox);
return status;
}
switch (mud->state)
{
case MBOX_NO_STATE:
mud->from = calloc (128, sizeof (char));
if (mud->from == NULL)
{
mbox_unlock (mailbox);
mailbox_unlock (mailbox);
return ENOMEM;
}
mud->date = calloc (128, sizeof (char));
if (mud->date == NULL)
{
free (mud->from);
mud->from = NULL;
mud->state = MBOX_NO_STATE;
mbox_unlock (mailbox);
mailbox_unlock (mailbox);
return ENOMEM;
}
mud->off = 0;
mud->state = MBOX_STATE_FROM;
case MBOX_STATE_FROM:
/* Generate a "From " separator. */
{
char *s;
size_t len = 0;
status = message_from (msg, mud->from, 127, &len);
if (status != 0)
{
if (status != EAGAIN)
{
free (mud->from);
free (mud->date);
mud->date = mud->from = NULL;
mud->state = MBOX_NO_STATE;
mbox_unlock (mailbox);
}
mailbox_unlock (mailbox);
return status;
}
/* Nuke trailing newline. */
s = memchr (mud->from, nl, len);
if (s)
*s = '\0';
mud->state = MBOX_STATE_DATE;
}
case MBOX_STATE_DATE:
/* Generate a date for the "From " separator. */
{
char *s;
size_t len = 0;
status = message_received (msg, mud->date, 127, &len);
if (status != 0)
{
if (status != EAGAIN)
{
free (mud->from);
free (mud->date);
mud->date = mud->from = NULL;
mud->state = MBOX_NO_STATE;
mbox_unlock (mailbox);
}
mailbox_unlock (mailbox);
return status;
}
/* Nuke trailing newline. */
s = memchr (mud->date, nl, len);
if (s)
*s = '\0';
/* Write the separator to the mailbox. */
stream_write (mailbox->stream, "From ", 5, size, &n);
size += n;
stream_write (mailbox->stream, mud->from, strlen (mud->from), size, &n);
size += n;
stream_write (mailbox->stream, " ", 1, size, &n);
size += n;
stream_write (mailbox->stream, mud->date, strlen (mud->date), size, &n);
size += n;
stream_write (mailbox->stream, &nl , 1, size, &n);
size += n;
free (mud->from);
free (mud->date);
mud->from = mud->date = NULL;
mud->state = MBOX_STATE_APPEND;
}
case MBOX_STATE_APPEND:
/* Append the Message. */
{
char buffer[BUFSIZ];
size_t nread = 0;
stream_t is;
message_get_stream (msg, &is);
do
{
status = stream_read (is, buffer, sizeof (buffer), mud->off,
&nread);
if (status != 0)
{
if (status != EAGAIN)
{
free (mud->from);
free (mud->date);
mud->date = mud->from = NULL;
mud->state = MBOX_NO_STATE;
mbox_unlock (mailbox);
}
stream_flush (mailbox->stream);
mailbox_unlock (mailbox);
return status;
}
stream_write (mailbox->stream, buffer, nread, size, &n);
mud->off += nread;
size += n;
}
while (nread > 0);
stream_write (mailbox->stream, &nl, 1, size, &n);
}
default:
break;
}
}
stream_flush (mailbox->stream);
mud->state = MBOX_NO_STATE;
mbox_unlock (mailbox);
mailbox_unlock (mailbox);
return 0;
}
static int
mbox_size (mailbox_t mailbox, off_t *psize)
{
off_t size;
int status;
/* Maybe was not open yet ?? */
mailbox_rdlock (mailbox);
status = stream_size (mailbox->stream, &size);
mailbox_unlock (mailbox);
if (status != 0)
return status;
if (psize)
*psize = size;
return 0;
}
static int
mbox_messages_count (mailbox_t mailbox, size_t *pcount)
{
mbox_data_t mud = mailbox->data;
if (mud == NULL)
return EINVAL;
if (! mbox_is_updated (mailbox))
return mbox_scan0 (mailbox, 1, pcount, 1);
if (pcount)
*pcount = mud->messages_count;
return 0;
}
/* Locking. */
static int
mbox_lock (mailbox_t mailbox, int flag)
{
if (mailbox && mailbox->locker != NULL)
{
locker_t locker = mailbox->locker;
locker_lock (locker, flag);
}
return 0;
}
static int
mbox_touchlock (mailbox_t mailbox)
{
if (mailbox && mailbox->locker != NULL)
{
locker_t locker = mailbox->locker;
locker_touchlock (locker);
}
return 0;
}
static int
mbox_unlock (mailbox_t mailbox)
{
if (mailbox && mailbox->locker != NULL)
{
locker_t locker = mailbox->locker;
locker_unlock (locker);
}
return 0;
}
......
/* 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. */
/* Credits to the c-client and its Authors
* The notorius c-client VALID() macro, was written by Mark Crispin.
*/
/* Parsing.
* The approach is to detect the "From " as start of a
* new message, give the position of the header and scan
* until "\n" then set header_end, set body position,
* scan until we it another "From " and set body_end.
*
************************************
* This is a classic case of premature optimisation
* being the root of all Evil(Donald E. Knuth).
* But I'm under "pressure" ;-) to come with
* something "faster". I think it's wastefull
* to spend time to gain a few seconds on 30Megs mailboxes
* ... but then again ... in computer time, 60 seconds, is eternity.
*
* If they use the event notification stuff
* to get some headers/messages early ... it's like pissing
* in the wind(sorry don't have the english equivalent).
* The worst is progress_bar it should be ... &*($^ nuke.
* For the events, we have to remove the *.LCK file,
* release the locks, flush the stream save the pointers
* etc ... hurry and wait...
* I this point I'm pretty much ranting.
*
*/
/* From the C-Client, part of pine */
/* You are not expected to understand this macro, but read the next page if
* you are not faint of heart.
*
* Known formats to the VALID macro are:
* From user Wed Dec 2 05:53 1992
* BSD From user Wed Dec 2 05:53:22 1992
* SysV From user Wed Dec 2 05:53 PST 1992
* rn From user Wed Dec 2 05:53:22 PST 1992
* From user Wed Dec 2 05:53 -0700 1992
* From user Wed Dec 2 05:53:22 -0700 1992
* From user Wed Dec 2 05:53 1992 PST
* From user Wed Dec 2 05:53:22 1992 PST
* From user Wed Dec 2 05:53 1992 -0700
* Solaris From user Wed Dec 2 05:53:22 1992 -0700
*
* Plus all of the above with `` remote from xxx'' after it. Thank you very
* much, smail and Solaris, for making my life considerably more complicated.
*/
/*
* What? You want to understand the VALID macro anyway? Alright, since you
* insist. Actually, it isn't really all that difficult, provided that you
* take it step by step.
*
* Line 1 Initializes the return ti value to failure (0);
* Lines 2-3 Validates that the 1st-5th characters are ``From ''.
* Lines 4-6 Validates that there is an end of line and points x at it.
* Lines 7-14 First checks to see if the line is at least 41 characters long
.
* If so, it scans backwards to find the rightmost space. From
* that point, it scans backwards to see if the string matches
* `` remote from''. If so, it sets x to point to the space at
* the start of the string.
* Line 15 Makes sure that there are at least 27 characters in the line.
* Lines 16-21 Checks if the date/time ends with the year (there is a space
* five characters back). If there is a colon three characters
* further back, there is no timezone field, so zn is set to 0
* and ti is set in front of the year. Otherwise, there must
* either to be a space four characters back for a three-letter
* timezone, or a space six characters back followed by a + or -
* for a numeric timezone; in either case, zn and ti become the
* offset of the space immediately before it.
* Lines 22-24 Are the failure case for line 14. If there is a space four
* characters back, it is a three-letter timezone; there must be
a
* space for the year nine characters back. zn is the zone
* offset; ti is the offset of the space.
* Lines 25-28 Are the failure case for line 20. If there is a space six
* characters back, it is a numeric timezone; there must be a
* space eleven characters back and a + or - five characters back
.
* zn is the zone offset; ti is the offset of the space.
* Line 29-32 If ti is valid, make sure that the string before ti is of the
* form www mmm dd hh:mm or www mmm dd hh:mm:ss, otherwise
* invalidate ti. There must be a colon three characters back
* and a space six or nine characters back (depending upon
* whether or not the character six characters back is a colon).
* There must be a space three characters further back (in front
* of the day), one seven characters back (in front of the month)
,
* and one eleven characters back (in front of the day of week).
* ti is set to be the offset of the space before the time.
*
* Why a macro? It gets invoked a *lot* in a tight loop. On some of the
* newer pipelined machines it is faster being open-coded than it would be if
* subroutines are called.
*
* Why does it scan backwards from the end of the line, instead of doing the
* much easier forward scan? There is no deterministic way to parse the
* ``user'' field, because it may contain unquoted spaces! Yes, I tested it t
o
* see if unquoted spaces were possible. They are, and I've encountered enoug
h
* evil mail to be totally unwilling to trust that ``it will never happen''.
*/
#define VALID(s,x,ti,zn) { \
ti = 0; \
if ((*s == 'F') && (s[1] == 'r') && (s[2] == 'o') && (s[3] == 'm') && \
(s[4] == ' ')) { \
for (x = s + 5; *x && *x != '\n'; x++); \
if (x) { \
if (x - s >= 41) { \
for (zn = -1; x[zn] != ' '; zn--); \
if ((x[zn-1] == 'm') && (x[zn-2] == 'o') && (x[zn-3] == 'r') && \
(x[zn-4] == 'f') && (x[zn-5] == ' ') && (x[zn-6] == 'e') && \
(x[zn-7] == 't') && (x[zn-8] == 'o') && (x[zn-9] == 'm') && \
(x[zn-10] == 'e') && (x[zn-11] == 'r') && (x[zn-12] == ' '))\
x += zn - 12; \
} \
if (x - s >= 27) { \
if (x[-5] == ' ') { \
if (x[-8] == ':') zn = 0,ti = -5; \
else if (x[-9] == ' ') ti = zn = -9; \
else if ((x[-11] == ' ') && ((x[-10]=='+') || (x[-10]=='-'))) \
ti = zn = -11; \
} \
else if (x[-4] == ' ') { \
if (x[-9] == ' ') zn = -4,ti = -9; \
} \
else if (x[-6] == ' ') { \
if ((x[-11] == ' ') && ((x[-5] == '+') || (x[-5] == '-'))) \
zn = -6,ti = -11; \
} \
if (ti && !((x[ti - 3] == ':') && \
(x[ti -= ((x[ti - 6] == ':') ? 9 : 6)] == ' ') && \
(x[ti - 3] == ' ') && (x[ti - 7] == ' ') && \
(x[ti - 11] == ' '))) ti = 0; \
} \
} \
} \
}
#define STRLEN(s, i) \
do \
{ \
char *tmp = (s);\
while (*tmp) tmp++; \
i = tmp - s; \
} while (0)
#define ATTRIBUTE_SET(buf,mum,c0,c1,type) \
do \
{ \
char *s; \
for (s = (buf) + 7; *s; s++) \
{ \
if (*s == c0 || *s == c1) \
{ \
(mum)->old_flags |= (type); \
break; \
} \
} \
} while (0)
#define ISSTATUS(buf) (\
(buf[0] == 'S' || buf[0] == 's') && \
(buf[1] == 'T' || buf[1] == 't') && \
(buf[2] == 'A' || buf[2] == 'a') && \
(buf[3] == 'T' || buf[3] == 't') && \
(buf[4] == 'U' || buf[4] == 'u') && \
(buf[5] == 'S' || buf[5] == 's') && (buf[6] == ':'))
/* Notifications ADD_MESG. */
#define DISPATCH_ADD_MSG(mbox,mud) \
do \
{ \
int bailing = 0; \
mailbox_unlock (mbox); \
if (mbox->observable) \
bailing = observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD); \
if (bailing != 0) \
{ \
if (pcount) \
*pcount = (mud)->messages_count; \
mbox_unlock (mbox); \
return EINTR; \
} \
mailbox_wrlock (mbox); \
} while (0);
/* Notification MBX_PROGRESS
We do not want to fire up the progress notification every line, it will be
too expensive, so we do it arbitrarely every 10 000 Lines.
FIXME: maybe this should be configurable. */
/* This is more tricky we can not leave the mum struct incomplete. So we
only tell them about the complete messages. */
#define DISPATCH_PROGRESS(mbox,mud) \
do \
{ \
{ \
int bailing = 0; \
mailbox_unlock (mbox); \
mud->messages_count--; \
if (mbox->observable) \
bailing = observable_notify (mbox->observable, MU_EVT_MAILBOX_PROGRESS); \
if (bailing != 0) \
{ \
if (pcount) \
*pcount = (mud)->messages_count; \
mbox_unlock (mbox); \
return EINTR; \
} \
mud->messages_count++; \
mailbox_wrlock (mbox); \
} \
} while (0)
/* Allocate slots for the new messages. */
/* size_t num = 2 * ((mud)->messages_count) + 10; */
#define ALLOCATE_MSGS(mbox,mud) \
do \
{ \
if ((mud)->messages_count >= (mud)->umessages_count) \
{ \
mbox_message_t *m; \
size_t num = ((mud)->umessages_count) + 1; \
m = realloc ((mud)->umessages, num * sizeof (*m)); \
if (m == NULL) \
{ \
mbox_unlock (mbox); \
mailbox_unlock (mbox); \
return ENOMEM; \
} \
(mud)->umessages = m; \
(mud)->umessages[num - 1] = calloc (1, sizeof (*(mum))); \
if ((mud)->umessages[num - 1] == NULL) \
{ \
mbox_unlock (mbox); \
mailbox_unlock (mbox); \
return ENOMEM; \
} \
(mud)->umessages_count = num; \
} \
} while (0)
static int
mbox_scan0 (mailbox_t mailbox, size_t msgno, size_t *pcount, int do_notif)
{
#define MSGLINELEN 1024
char buf[MSGLINELEN];
int inheader;
int inbody;
off_t total = 0;
mbox_data_t mud = mailbox->data;
mbox_message_t mum = NULL;
int status = 0;
size_t lines;
int newline;
size_t n = 0;
int zn, isfrom = 0;
char *temp;
/* Sanity. */
if (mud == NULL)
return EINVAL;
/* Grab the lock. */
mailbox_wrlock (mailbox);
/* Save the timestamp and size. */
status = stream_size (mailbox->stream, &(mud->size));
if (status != 0)
{
mailbox_unlock (mailbox);
return status;
}
mbox_lock (mailbox, MU_LOCKER_RDLOCK);
/* Seek to the starting point. */
if (mud->umessages && msgno > 0 && mud->messages_count > 0
&& msgno <= mud->messages_count)
{
mum = mud->umessages[msgno - 1];
if (mum)
total = mum->header_from;
mud->messages_count = msgno - 1;
}
else
mud->messages_count = 0;
newline = 1;
errno = lines = inheader = inbody = 0;
while ((status = stream_readline (mailbox->stream, buf, sizeof (buf),
total, &n)) == 0 && n != 0)
{
int nl;
total += n;
nl = (*buf == '\n') ? 1 : 0;
VALID(buf, temp, isfrom, zn);
isfrom = (isfrom) ? 1 : 0;
/* Which part of the message are we in ? */
inheader = isfrom | ((!nl) & inheader);
inbody = (!isfrom) & (!inheader);
lines++;
if (inheader)
{
/* New message. */
if (isfrom)
{
/* Signal the end of the body. */
if (mum && !mum->body_end)
{
mum->body_end = total - n - newline;
mum->body_lines = --lines - newline;
if (do_notif)
DISPATCH_ADD_MSG(mailbox, mud);
}
/* Allocate_msgs will initialize mum. */
ALLOCATE_MSGS(mailbox, mud);
mud->messages_count++;
mum = mud->umessages[mud->messages_count - 1];
mum->stream = mailbox->stream;
mum->mud = mud;
mum->header_from = total - n;
mum->header_from_end = total;
lines = 0;
}
else if ((n > 7) && ISSTATUS(buf))
{
mum->header_status = total - n;
mum->header_status_end = total;
ATTRIBUTE_SET(buf, mum, 'r', 'R', MU_ATTRIBUTE_READ);
ATTRIBUTE_SET(buf, mum, 'o', 'O', MU_ATTRIBUTE_SEEN);
ATTRIBUTE_SET(buf, mum, 'a', 'A', MU_ATTRIBUTE_ANSWERED);
ATTRIBUTE_SET(buf, mum, 'd', 'D', MU_ATTRIBUTE_DELETED);
}
}
/* Body. */
if (inbody)
{
/* Set the body position. */
if (mum && !mum->body)
{
mum->body = total - n + nl;
mum->header_lines = lines;
lines = 0;
}
}
newline = nl;
/* Every 50 mesgs update the lock, it should be every minute. */
if ((mud->messages_count % 50) == 0)
mbox_touchlock (mailbox);
/* Ping them every 1000 lines. */
if (do_notif)
if (((lines +1) % 1000) == 0)
DISPATCH_PROGRESS(mailbox, mud);
} /* while */
if (mum)
{
mum->body_end = total - newline;
mum->body_lines = lines - newline;
if (do_notif)
DISPATCH_ADD_MSG(mailbox, mud);
}
mbox_unlock (mailbox);
if (pcount)
*pcount = mud->messages_count;
mailbox_unlock (mailbox);
return status;
}
......@@ -15,6 +15,10 @@
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 <termios.h>
#include <errno.h>
#include <stdlib.h>
......@@ -24,16 +28,40 @@
#include <fcntl.h>
#include <stdarg.h>
#include <mailutils/stream.h>
#include <mailutils/body.h>
#include <mailutils/message.h>
#include <mailutils/header.h>
#include <mailutils/attribute.h>
#include <mailutils/url.h>
#include <mailutils/auth.h>
#include <mailbox0.h>
#include <stream0.h>
#include <body0.h>
#include <message0.h>
#include <registrar0.h>
#include <auth0.h>
#include <header0.h>
#include <attribute0.h>
#include <bio.h>
static int pop_init (mailbox_t);
static struct mailbox_entry _pop_entry =
{
url_pop_init, pop_init
};
static struct _record _pop_record =
{
MU_POP_SCHEME,
&_pop_entry, /* Mailbox entry. */
NULL, /* Mailer entry. */
0, /* Not malloc()ed. */
NULL, /* No need for an owner. */
NULL, /* is_scheme method. */
NULL, /* get_mailbox method. */
NULL /* get_mailer method. */
};
/* We export two functions: url parsing and the initialisation of
the mailbox, via the register entry/record. */
record_t pop_record = &_pop_record;
mailbox_entry_t pop_entry = &_pop_entry;
/* Advance declarations. */
struct _pop_data;
struct _pop_message;
......@@ -45,34 +73,25 @@ typedef struct _pop_message * pop_message_t;
reentrant. It is only one channel. */
enum pop_state
{
POP_NO_STATE = 0, POP_STATE_DONE,
POP_NO_STATE, POP_STATE_DONE,
POP_OPEN_CONNECTION,
POP_GREETINGS,
POP_APOP_TX, POP_APOP_ACK,
POP_DELE_TX, POP_DELE_ACK,
POP_LIST_TX, POP_LIST_ACK, POP_LIST_RX,
POP_PASS_TX, POP_PASS_ACK,
POP_QUIT_TX, POP_QUIT_ACK,
POP_NOOP_TX, POP_NOOP_ACK,
POP_RETR_TX, POP_RETR_ACK, POP_RETR_RX_HDR, POP_RETR_RX_BODY,
POP_RSET_TX, POP_RSET_ACK,
POP_STAT_TX, POP_STAT_ACK,
POP_TOP_TX, POP_TOP_ACK, POP_TOP_RX,
POP_UIDL_TX, POP_UIDL_ACK,
POP_USER_TX, POP_USER_ACK,
POP_APOP, POP_APOP_ACK,
POP_DELE, POP_DELE_ACK,
POP_LIST, POP_LIST_ACK, POP_LIST_RX,
POP_QUIT, POP_QUIT_ACK,
POP_NOOP, POP_NOOP_ACK,
POP_RETR, POP_RETR_ACK, POP_RETR_RX_HDR, POP_RETR_RX_BODY,
POP_RSET, POP_RSET_ACK,
POP_STAT, POP_STAT_ACK,
POP_TOP, POP_TOP_ACK, POP_TOP_RX,
POP_UIDL, POP_UIDL_ACK,
POP_AUTH, POP_AUTH_DONE,
POP_AUTH_USER, POP_AUTH_USER_ACK,
POP_AUTH_PASS, POP_AUTH_PASS_ACK
};
/* Those two are exportable funtions i.e. they are visible/call when you
call a URL "pop://..." to mailbox_create. */
static int pop_create (mailbox_t *, const char *);
static void pop_destroy (mailbox_t *);
struct mailbox_registrar _mailbox_pop_registrar =
{
"POP3",
pop_create, pop_destroy
};
static void pop_destroy (mailbox_t);
/* Functions/Methods that implements the mailbox_t API. */
static int pop_open (mailbox_t, int);
......@@ -80,27 +99,31 @@ static int pop_close (mailbox_t);
static int pop_get_message (mailbox_t, size_t, message_t *);
static int pop_messages_count (mailbox_t, size_t *);
static int pop_expunge (mailbox_t);
static int pop_num_deleted (mailbox_t, size_t *);
static int pop_scan (mailbox_t, size_t, size_t *);
static int pop_is_updated (mailbox_t);
/* The implementation of message_t */
static int pop_user (authority_t);
static int pop_size (mailbox_t, off_t *);
static int pop_header_read (stream_t, char *, size_t, off_t, size_t *);
static int pop_header_fd (stream_t, int *);
static int pop_body_fd (stream_t, int *);
static int pop_body_size (body_t, size_t *);
static int pop_body_lines (body_t, size_t *);
static int pop_body_read (stream_t, char *, size_t, off_t, size_t *);
static int pop_message_read (stream_t, char *, size_t, off_t, size_t *);
static int pop_message_size (message_t, size_t *);
static int pop_message_fd (stream_t, int *);
static int pop_top (stream_t, char *, size_t, off_t, size_t *);
static int pop_read_header (stream_t, char *, size_t, off_t, size_t *);
static int pop_read_body (stream_t, char *, size_t, off_t, size_t *);
static int pop_read_message (stream_t, char *, size_t, off_t, size_t *);
static int pop_retr (pop_message_t, char *, size_t, off_t, size_t *);
static int pop_get_fd (stream_t, int *);
static int pop_get_flags (attribute_t, int *);
static int pop_body_size (body_t, size_t *);
static int pop_body_lines (body_t body, size_t *plines);
static int pop_get_fd (pop_message_t, int *);
static int pop_attr_flags (attribute_t, int *);
static int pop_uidl (message_t, char *, size_t, size_t *);
static int fill_buffer (pop_data_t mpd, char *buffer, size_t buflen);
static int pop_readline (pop_data_t mpd);
static int pop_read_ack (pop_data_t mpd);
static int pop_writeline (pop_data_t mpd, const char *format, ...);
static int pop_write (pop_data_t mpd);
static int fill_buffer (pop_data_t, char *, size_t);
static int pop_readline (pop_data_t);
static int pop_read_ack (pop_data_t);
static int pop_writeline (pop_data_t, const char *, ...);
static int pop_write (pop_data_t);
/* This structure holds the info for a pop_get_message(). The pop_message_t
type, will serve as the owner of the message_t and contains the command to
......@@ -116,7 +139,10 @@ struct _pop_message
int skip_header;
int skip_body;
size_t body_size;
size_t header_size;
size_t body_lines;
size_t header_lines;
size_t message_size;
size_t num;
message_t message;
pop_data_t mpd; /* Back pointer. */
......@@ -126,19 +152,13 @@ struct _pop_message
many messages we have so far etc ... */
struct _pop_data
{
/* Pop is a serial protocol, we need only one global mutex. */
#ifdef HAVE_PTHREAD_H
pthread_mutex_t mutex;
#else
void *func; /* Indicate a command is in operation, busy. */
#endif
size_t id; /* Use in pop_expunge to hold the message num, if EAGAIN. */
enum pop_state state;
pop_message_t *pmessages;
size_t pmessages_count;
size_t messages_count;
size_t size;
int flags; /* Flags of for the stream_t object. */
/* Working I/O buffers. */
bio_t bio;
......@@ -154,9 +174,46 @@ struct _pop_data
} ;
/* Usefull little Macros, since these are very repetitive. */
/* Check if we're busy ? */
/* POP is a one channel dowload protocol, so if someone
is trying to do another command while another is running
something is seriously incorrect, So the best course
of action is to close down the connection and start a new one.
For example mime_t only reads part of the message. If a client
wants to read different part of the message via mime it should
download it first. POP does not have the features of IMAP for
multipart messages. */
#define CHECK_BUSY(mbox, mpd, function, identity) \
do \
{ \
int err = mailbox_wrlock (mbox); \
if (err != 0) \
return err; \
if ((mpd->func && mpd->func != function) \
|| (mpd->id && mpd->id != (size_t)identity)) \
{ \
mpd->id = 0; \
mpd->func = pop_open; \
mpd->state = POP_NO_STATE; \
mailbox_unlock (mbox); \
err = pop_open (mbox, mbox->flags); \
if (err != 0) \
{ \
return err; \
} \
} \
else \
{ \
mpd->id = (size_t)identity; \
mpd->func = func; \
mailbox_unlock (mbox); \
} \
} \
while (0)
#define CLEAR_STATE(mpd) \
mpd->id = 0, mpd->func = NULL, \
mpd->state = POP_NO_STATE
mpd->id = 0, mpd->func = NULL, mpd->state = POP_NO_STATE
/* Clear the state and close the stream. */
#define CHECK_ERROR_CLOSE(mbox, mpd, status) \
......@@ -201,67 +258,21 @@ while (0)
/* Parse the url, allocate mailbox_t, allocate pop internal structures. */
static int
pop_create (mailbox_t *pmbox, const char *name)
pop_init (mailbox_t mbox)
{
mailbox_t mbox;
pop_data_t mpd;
size_t name_len;
/* Sanity check. */
if (name == NULL || *name == '\0')
return EINVAL;
name_len = strlen (name);
#define POP_SCHEME "pop://"
#define POP_SCHEME_LEN 6
#define SEPARATOR '/'
/* Skip the url scheme. */
if (name_len > POP_SCHEME_LEN
&& (name[0] == 'p' || name[0] == 'P')
&& (name[1] == 'o' || name[1] == 'O')
&& (name[2] == 'p' || name[2] == 'P')
&& (name[3] == ':' && name[4] == '/' && name[5] == '/'))
{
name += POP_SCHEME_LEN;
name_len -= POP_SCHEME_LEN;
}
/* Allocate memory for mbox. */
mbox = calloc (1, sizeof (*mbox));
if (mbox == NULL)
return ENOMEM;
/* Allocate specifics for pop data. */
mpd = mbox->data = calloc (1, sizeof (*mpd));
if (mbox->data == NULL)
{
pop_destroy (&mbox);
return ENOMEM;
}
mpd->state = POP_NO_STATE;
mpd->mbox = mbox;
/* Copy the name. */
mbox->name = calloc (name_len + 1, sizeof (char));
if (mbox->name == NULL)
{
pop_destroy (&mbox);
return ENOMEM;
}
memcpy (mbox->name, name, name_len);
mpd->mbox = mbox; /* Back pointer. */
#ifdef HAVE_PHTREAD_H
/* Mutex when accessing the structure fields. */
/* FIXME: should we use rdwr locks instead ?? */
/* XXXX: This is not use yet and the library is still not thread safe. This
is more a gentle remider that I got more work to do. */
pthread_mutex_init (&(mpd->mutex), NULL);
#endif
mpd->state = POP_NO_STATE; /* Init with no state. */
/* Initialize the structure. */
mbox->_create = pop_create;
mbox->_init = pop_init;
mbox->_destroy = pop_destroy;
mbox->_open = pop_open;
......@@ -271,29 +282,24 @@ pop_create (mailbox_t *pmbox, const char *name)
mbox->_get_message = pop_get_message;
mbox->_messages_count = pop_messages_count;
mbox->_expunge = pop_expunge;
mbox->_num_deleted = pop_num_deleted;
mbox->_scan = pop_scan;
mbox->_is_updated = pop_is_updated;
mbox->_size = pop_size;
(*pmbox) = mbox;
return 0; /* Okdoke. */
}
/* Cleaning up all the ressources associate with a pop mailbox. */
static void
pop_destroy (mailbox_t *pmbox)
pop_destroy (mailbox_t mbox)
{
if (pmbox && *pmbox)
{
mailbox_t mbox = *pmbox;
if (mbox->data)
{
pop_data_t mpd = mbox->data;
size_t i;
mailbox_wrlock (mbox);
/* Destroy the pop messages and ressources associated to them. */
for (i = 0; i < mpd->pmessages_count; i++)
{
......@@ -310,89 +316,89 @@ pop_destroy (mailbox_t *pmbox)
mpd->buffer = NULL;
free (mpd->pmessages);
mpd->pmessages = NULL;
#ifdef HAVE_PHTREAD_H
pthread_mutex_destroy (&(mpd->mutex));
#endif
free (mpd);
mbox->data = NULL;
mailbox_unlock (mbox);
}
/* Since the mailbox is destroy, close the stream but not via
pop_close () which can return EAGAIN, or other unpleasant side
effects, but rather the hard way. */
stream_close (mbox->stream);
stream_destroy (&(mbox->stream), mbox);
auth_destroy (&(mbox->auth), mbox);
if (mbox->name)
}
/* User/pass authentication for pop. */
int
pop_user (authority_t auth)
{
mailbox_t mbox = authority_get_owner (auth);
pop_data_t mpd = mbox->data;
ticket_t ticket;
int status;
switch (mpd->state)
{
free (mbox->name);
mbox->name = NULL;
}
if (mbox->event)
case POP_AUTH:
authority_get_ticket (auth, &ticket);
/* Fetch the user/passwd from them. */
ticket_pop (ticket, "Pop User: ", &mpd->user);
ticket_pop (ticket, "Pop Passwd: ", &mpd->passwd);
status = pop_writeline (mpd, "USER %s\r\n", mpd->user);
CHECK_ERROR_CLOSE(mbox, mpd, status);
MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer);
free (mpd->user);
mpd->user = NULL;
mpd->state = POP_AUTH_USER;
case POP_AUTH_USER:
/* Send username. */
status = pop_write (mpd);
CHECK_EAGAIN (mpd, status);
mpd->state = POP_AUTH_USER_ACK;
case POP_AUTH_USER_ACK:
/* Get the user ack. */
status = pop_read_ack (mpd);
CHECK_EAGAIN (mpd, status);
MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer);
if (strncasecmp (mpd->buffer, "+OK", 3) != 0)
{
free (mbox->event);
mbox->event = NULL;
}
if (mbox->url)
url_destroy (&(mbox->url));
free (mbox);
*pmbox = NULL;
observable_t observable = NULL;
mailbox_get_observable (mbox, &observable);
observable_notify (observable, MU_EVT_AUTHORITY_FAILED);
CHECK_ERROR_CLOSE (mbox, mpd, EACCES);
}
}
status = pop_writeline (mpd, "PASS %s\r\n", mpd->passwd);
CHECK_ERROR_CLOSE (mbox, mpd, status);
/* We have to nuke the passwd. */
memset (mpd->passwd, 0, strlen (mpd->passwd));
free (mpd->passwd);
mpd->passwd = NULL;
MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, "PASS *\n");
mpd->state = POP_AUTH_PASS;
static void
echo_off(struct termios *stored_settings)
{
struct termios new_settings;
tcgetattr (0, stored_settings);
new_settings = *stored_settings;
new_settings.c_lflag &= (~ECHO);
tcsetattr (0, TCSANOW, &new_settings);
}
case POP_AUTH_PASS:
/* Send passwd. */
status = pop_write (mpd);
CHECK_EAGAIN (mpd, status);
/* We have to nuke the passwd. */
memset (mpd->buffer, 0, mpd->buflen);
mpd->state = POP_AUTH_PASS_ACK;
static void
echo_on(struct termios *stored_settings)
{
tcsetattr (0, TCSANOW, stored_settings);
}
case POP_AUTH_PASS_ACK:
/* Get the ack from passwd. */
status = pop_read_ack (mpd);
CHECK_EAGAIN (mpd, status);
MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer);
if (strncasecmp (mpd->buffer, "+OK", 3) != 0)
{
observable_t observable = NULL;
mailbox_get_observable (mbox, &observable);
observable_notify (observable, MU_EVT_AUTHORITY_FAILED);
CHECK_ERROR_CLOSE (mbox, mpd, EACCES);
}
mpd->state = POP_AUTH_DONE;
break; /* We're outta here. */
/* User/pass authentication for pop. */
static int
pop_authenticate (auth_t auth, char **user, char **passwd)
{
/* FIXME: This incorrect and goes against GNU style: having a limitation on
the user/passwd length, it should be fix. */
char u[128];
char p[128];
mailbox_t mbox = auth->owner;
int status;
/* We should probably use getpass () or something similar. */
struct termios stored_settings;
*u = '\0';
*p = '\0';
memset (&stored_settings, 0, sizeof (stored_settings));
/* Prompt for the user/login name. */
status = url_get_user (mbox->url, u, sizeof (u), NULL);
if (status != 0 || *u == '\0')
{
printf ("Pop User: "); fflush (stdout);
fgets (u, sizeof (u), stdin);
u [strlen (u) - 1] = '\0'; /* nuke the trailing NL */
}
/* Prompt for the passwd. */
status = url_get_passwd (mbox->url, p, sizeof (p), NULL);
if (status != 0 || *p == '\0' || *p == '*')
{
printf ("Pop Passwd: ");
fflush (stdout);
echo_off (&stored_settings);
fgets (p, sizeof(p), stdin);
echo_on (&stored_settings);
p [strlen (p) - 1] = '\0';
}
*user = strdup (u);
*passwd = strdup (p);
default:
break;
}
CLEAR_STATE (mpd);
return 0;
}
......@@ -412,24 +418,14 @@ pop_open (mailbox_t mbox, int flags)
if (mbox->url == NULL || mpd == NULL)
return EINVAL;
mbox->flags = flags | MU_STREAM_POP;
/* Fetch the pop server name and the port in the url_t. */
if ((status = url_get_host (mbox->url, host, sizeof(host), NULL)) != 0
|| (status = url_get_port (mbox->url, &port)) != 0)
return status;
/* Dealing whith Authentication. So far only normal user/pass supported. */
if (mbox->auth == NULL)
{
status = auth_create (&(mbox->auth), mbox);
if (status != 0)
return status;
auth_set_authenticate (mbox->auth, pop_authenticate, mbox);
}
/* Flag busy. */
if (mpd->func && mpd->func != func)
return EBUSY;
mpd->func = func;
CHECK_BUSY (mbox, mpd, func, 0);
/* Enter the pop state machine, and boogy: AUTHORISATION State. */
switch (mpd->state)
......@@ -447,31 +443,21 @@ pop_open (mailbox_t mbox, int flags)
mpd->ptr = mpd->buffer;
}
/* Spawn auth prologue. */
auth_prologue (mbox->auth);
/* Create the networking stack. */
if (mbox->stream == NULL)
{
status = tcp_stream_create (&(mbox->stream));
CHECK_ERROR(mpd, status);
}
else
stream_close (mbox->stream);
mpd->state = POP_OPEN_CONNECTION;
case POP_OPEN_CONNECTION:
/* Establish the connection. */
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, "open (%s:%d)\n",
host, port);
status = stream_open (mbox->stream, host, port, flags);
if (status != 0)
{
/* Clear the state for non recoverable error. */
if (status != EAGAIN && status != EINPROGRESS && status != EINTR)
{
CLEAR_STATE (mpd);
}
return status;
}
MAILBOX_DEBUG2 (mbox, MU_DEBUG_PROT, "open (%s:%d)\n", host, port);
status = stream_open (mbox->stream, host, port, mbox->flags);
CHECK_EAGAIN (mpd, status);
/* Need to destroy the old bio maybe a different stream. */
bio_destroy (&(mpd->bio));
/* Allocate the struct for buffered I/O. */
......@@ -481,67 +467,42 @@ pop_open (mailbox_t mbox, int flags)
mpd->state = POP_GREETINGS;
case POP_GREETINGS:
{
char auth[64] = "";
size_t n = 0;
/* Swallow the greetings. */
status = pop_read_ack (mpd);
CHECK_EAGAIN (mpd, status);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer);
MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer);
if (strncasecmp (mpd->buffer, "+OK", 3) != 0)
{
CHECK_ERROR_CLOSE (mbox, mpd, EACCES);
}
/* Fetch the user/passwd from them. */
auth_authenticate (mbox->auth, &mpd->user, &mpd->passwd);
status = pop_writeline (mpd, "USER %s\r\n", mpd->user);
CHECK_ERROR_CLOSE(mbox, mpd, status);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer);
free (mpd->user);
mpd->user = NULL;
mpd->state = POP_USER_TX;
case POP_USER_TX:
/* Send username. */
status = pop_write (mpd);
CHECK_EAGAIN (mpd, status);
mpd->state = POP_USER_ACK;
case POP_USER_ACK:
/* Get the user ack. */
status = pop_read_ack (mpd);
CHECK_EAGAIN (mpd, status);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer);
if (strncasecmp (mpd->buffer, "+OK", 3) != 0)
url_get_auth (mbox->url, auth, 64, &n);
if (n == 0 || strcasecmp (auth, "*") == 0)
{
CHECK_ERROR_CLOSE (mbox, mpd, EACCES);
authority_create (&(mbox->authority), mbox->ticket, mbox);
authority_set_authenticate (mbox->authority, pop_user, mbox);
}
status = pop_writeline (mpd, "PASS %s\r\n", mpd->passwd);
CHECK_ERROR_CLOSE (mbox, mpd, status);
/* We have to nuke the passwd. */
memset (mpd->passwd, 0, strlen (mpd->passwd));
free (mpd->passwd);
mpd->passwd = NULL;
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, "PASS *\n");
mpd->state = POP_PASS_TX;
case POP_PASS_TX:
/* Send passwd. */
status = pop_write (mpd);
CHECK_EAGAIN (mpd, status);
/* We have to nuke the passwd. */
memset (mpd->buffer, 0, mpd->buflen);
mpd->state = POP_PASS_ACK;
case POP_PASS_ACK:
/* Get the ack from passwd. */
status = pop_read_ack (mpd);
CHECK_EAGAIN (mpd, status);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer);
if (strncasecmp (mpd->buffer, "+OK", 3) != 0)
else if (strcasecmp (auth, "+apop") == 0)
{
CHECK_ERROR_CLOSE (mbox, mpd, EACCES);
/* Not supported. */
}
else
{
/* What can do flag an error ? */
}
mpd->state = POP_AUTH;
}
break; /* We're outta here. */
case POP_AUTH:
status = authority_authenticate (mbox->authority);
if (status != 0)
return status;
case POP_AUTH_DONE:
break;
default:
/*
......@@ -550,9 +511,6 @@ pop_open (mailbox_t mbox, int flags)
break;
}/* End AUTHORISATION state. */
/* Spawn cleanup functions. */
auth_epilogue (mbox->auth);
/* Clear any state. */
CLEAR_STATE (mpd);
return 0;
......@@ -570,11 +528,13 @@ pop_close (mailbox_t mbox)
if (mpd == NULL)
return EINVAL;
/* Flag busy ? */
/* CHECK_BUSY (mbox, mpd, func, 0); */
mailbox_wrlock (mbox);
if (mpd->func && mpd->func != func)
return EBUSY;
mpd->state = POP_NO_STATE;
mpd->id = 0;
mpd->func = func;
mailbox_unlock (mbox);
/* Ok boys, it's a wrap: UPDATE State. */
switch (mpd->state)
......@@ -582,10 +542,10 @@ pop_close (mailbox_t mbox)
case POP_NO_STATE:
/* Initiate the close. */
status = pop_writeline (mpd, "QUIT\r\n");
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer);
mpd->state = POP_QUIT_TX;
MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer);
mpd->state = POP_QUIT;
case POP_QUIT_TX:
case POP_QUIT:
/* Send the quit. */
status = pop_write (mpd);
CHECK_EAGAIN (mpd, status);
......@@ -595,7 +555,7 @@ pop_close (mailbox_t mbox)
/* Glob the acknowledge. */
status = pop_read_ack (mpd);
CHECK_EAGAIN (mpd, status);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer);
MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer);
/* Now what ! and how can we tell them about errors ? So far now
lets just be verbose about the error but close the connection
anyway. */
......@@ -649,6 +609,7 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
if (pmsg == NULL || mpd == NULL)
return EINVAL;
mailbox_rdlock (mbox);
/* See if we have already this message. */
for (i = 0; i < mpd->pmessages_count; i++)
{
......@@ -657,10 +618,12 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
if (mpd->pmessages[i]->num == msgno)
{
*pmsg = mpd->pmessages[i]->message;
mailbox_unlock (mbox);
return 0;
}
}
}
mailbox_unlock (mbox);
mpm = calloc (1, sizeof (*mpm));
if (mpm == NULL)
......@@ -674,51 +637,49 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
{
stream_t stream = NULL;
if ((status = message_create (&msg, mpm)) != 0
|| (status = stream_create (&stream, MU_STREAM_READ, mpm)) != 0)
|| (status = stream_create (&stream, mbox->flags, msg)) != 0)
{
stream_destroy (&stream, msg);
message_destroy (&msg, mpm);
stream_destroy (&stream, mpm);
free (mpm);
return status;
}
stream_set_read (stream, pop_read_message, mpm);
stream_set_fd (stream, pop_get_fd, mpm);
stream_set_flags (stream, MU_STREAM_READ, mpm);
stream_set_read (stream, pop_message_read, msg);
stream_set_fd (stream, pop_message_fd, msg);
message_set_stream (msg, stream, mpm);
message_set_size (msg, pop_message_size, mpm);
}
/* Create the header. */
{
header_t header = NULL;
stream_t stream = NULL;
if ((status = header_create (&header, NULL, 0, mpm)) != 0
|| (status = stream_create (&stream, MU_STREAM_READ, mpm)) != 0)
if ((status = header_create (&header, NULL, 0, msg)) != 0
|| (status = stream_create (&stream, mbox->flags, header)) != 0)
{
header_destroy (&header, mpm);
stream_destroy (&stream, mpm);
stream_destroy (&stream, header);
header_destroy (&header, msg);
message_destroy (&msg, mpm);
free (mpm);
return status;
}
stream_set_read (stream, pop_top, mpm);
//stream_set_read (stream, pop_read_header, mpm);
stream_set_fd (stream, pop_get_fd, mpm);
stream_set_flags (stream, MU_STREAM_READ, mpm);
header_set_stream (header, stream, mpm);
stream_set_read (stream, pop_top, header);
stream_set_fd (stream, pop_header_fd, header);
header_set_stream (header, stream, msg);
message_set_header (msg, header, mpm);
}
/* Create the attribute. */
{
attribute_t attribute;
status = attribute_create (&attribute, mpm);
status = attribute_create (&attribute, msg);
if (status != 0)
{
message_destroy (&msg, mpm);
free (mpm);
return status;
}
attribute_set_get_flags (attribute, pop_get_flags, mpm);
attribute_set_get_flags (attribute, pop_attr_flags, msg);
message_set_attribute (msg, attribute, mpm);
}
......@@ -726,21 +687,20 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
{
body_t body = NULL;
stream_t stream = NULL;
if ((status = body_create (&body, mpm)) != 0
|| (status = stream_create (&stream, MU_STREAM_READ, mpm)) != 0)
if ((status = body_create (&body, msg)) != 0
|| (status = stream_create (&stream, mbox->flags, body)) != 0)
{
body_destroy (&body, mpm);
stream_destroy (&stream, mpm);
body_destroy (&body, msg);
stream_destroy (&stream, body);
message_destroy (&msg, mpm);
free (mpm);
return status;
}
stream_set_read (stream, pop_read_body, mpm);
stream_set_fd (stream, pop_get_fd, mpm);
stream_set_flags (stream, mpd->flags, mpm);
body_set_size (body, pop_body_size, mpm);
body_set_lines (body, pop_body_lines, mpm);
body_set_stream (body, stream, mpm);
stream_set_read (stream, pop_body_read, body);
stream_set_fd (stream, pop_body_fd, body);
body_set_size (body, pop_body_size, msg);
body_set_lines (body, pop_body_lines, msg);
body_set_stream (body, stream, msg);
message_set_body (msg, body, mpm);
}
......@@ -748,6 +708,7 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
message_set_uidl (msg, pop_uidl, mpm);
/* Add it to the list. */
mailbox_wrlock (mbox);
{
pop_message_t *m ;
m = realloc (mpd->pmessages, (mpd->pmessages_count + 1)*sizeof (*m));
......@@ -755,12 +716,14 @@ pop_get_message (mailbox_t mbox, size_t msgno, message_t *pmsg)
{
message_destroy (&msg, mpm);
free (mpm);
mailbox_unlock (mbox);
return ENOMEM;
}
mpd->pmessages = m;
mpd->pmessages[mpd->pmessages_count] = mpm;
mpd->pmessages_count++;
}
mailbox_unlock (mbox);
/* Save The message. */
*pmsg = mpm->message = msg;
......@@ -788,10 +751,7 @@ pop_messages_count (mailbox_t mbox, size_t *pcount)
}
/* Flag busy. */
if (mpd->func && mpd->func != func)
return EBUSY;
mpd->func = func;
CHECK_BUSY (mbox, mpd, func, 0);
/* TRANSACTION state. */
switch (mpd->state)
......@@ -799,10 +759,10 @@ pop_messages_count (mailbox_t mbox, size_t *pcount)
case POP_NO_STATE:
status = pop_writeline (mpd, "STAT\r\n");
CHECK_ERROR (mpd, status);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer);
mpd->state = POP_STAT_TX;
MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer);
mpd->state = POP_STAT;
case POP_STAT_TX:
case POP_STAT:
/* Send the STAT. */
status = pop_write (mpd);
CHECK_EAGAIN (mpd, status);
......@@ -812,7 +772,7 @@ pop_messages_count (mailbox_t mbox, size_t *pcount)
/* Get the ACK. */
status = pop_read_ack (mpd);
CHECK_EAGAIN (mpd, status);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer);
MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer);
break;
default:
......@@ -850,33 +810,6 @@ pop_is_updated (mailbox_t mbox)
return mpd->is_updated;
}
/* We do not send anything to the server since, no DELE command is sent but
the only the attribute flag is modified.
DELE is sent only when expunging. */
static int
pop_num_deleted (mailbox_t mbox, size_t *pnum)
{
pop_data_t mpd = mbox->data;
size_t i, total;
attribute_t attr;
if (mpd == NULL)
return EINVAL;
for (i = total = 0; i < mpd->messages_count; i++)
{
if (message_get_attribute (mpd->pmessages[i]->message, &attr) != 0)
{
if (attribute_is_deleted (attr))
total++;
}
}
if (pnum)
*pnum = total;
return 0;
}
/* We just simulated. By sending a notification for the total msgno. */
/* FIXME is message is set deleted should we sent a notif ? */
static int
......@@ -888,8 +821,10 @@ pop_scan (mailbox_t mbox, size_t msgno, size_t *pcount)
status = pop_messages_count (mbox, pcount);
if (status != 0)
return status;
if (mbox->observable == NULL)
return 0;
for (i = msgno; i <= *pcount; i++)
if (mailbox_notification (mbox, MU_EVT_MBX_MSG_ADD) != 0)
if (observable_notify (mbox->observable, MU_EVT_MESSAGE_ADD) != 0)
break;
return 0;
}
......@@ -908,10 +843,7 @@ pop_expunge (mailbox_t mbox)
return EINVAL;
/* Busy ? */
if (mpd->func && mpd->func != func)
return EBUSY;
mpd->func = func;
CHECK_BUSY (mbox, mpd, func, 0);
for (i = (int)mpd->id; i < mpd->pmessages_count; mpd->id = ++i)
{
......@@ -925,10 +857,10 @@ pop_expunge (mailbox_t mbox)
status = pop_writeline (mpd, "DELE %d\r\n",
mpd->pmessages[i]->num);
CHECK_ERROR (mpd, status);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer);
mpd->state = POP_DELE_TX;
MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer);
mpd->state = POP_DELE;
case POP_DELE_TX:
case POP_DELE:
/* Send DELETE. */
status = pop_write (mpd);
CHECK_EAGAIN (mpd, status);
......@@ -937,7 +869,7 @@ pop_expunge (mailbox_t mbox)
case POP_DELE_ACK:
status = pop_read_ack (mpd);
CHECK_EAGAIN (mpd, status);
mailbox_debug (mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer);
MAILBOX_DEBUG0 (mbox, MU_DEBUG_PROT, mpd->buffer);
if (strncasecmp (mpd->buffer, "+OK", 3) != 0)
{
CHECK_ERROR (mpd, ERANGE);
......@@ -952,9 +884,7 @@ pop_expunge (mailbox_t mbox)
} /* if attribute_is_deleted() */
} /* message_get_attribute() */
} /* for */
mpd->id = 0;
mpd->func = NULL;
mpd->state = POP_NO_STATE;
CLEAR_STATE (mpd);
/* Invalidate. But Really they should shutdown the channel POP protocol
is not meant for this like IMAP. */
mpd->is_updated = 0;
......@@ -978,21 +908,111 @@ pop_size (mailbox_t mbox, off_t *psize)
return status;
}
/* Form the RFC:
"It is important to note that the octet count for a message on the
server host may differ from the octet count assigned to that message
due to local conventions for designating end-of-line. Usually,
during the AUTHORIZATION state of the POP3 session, the POP3 server
can calculate the size of each message in octets when it opens the
maildrop. For example, if the POP3 server host internally represents
end-of-line as a single character, then the POP3 server simply counts
each occurrence of this character in a message as two octets."
This is not perfect if we do not know the number of lines in the message
then the octets returned will not be correct so we do our best.
*/
static int
pop_body_size (body_t body, size_t *psize)
pop_message_size (message_t msg, size_t *psize)
{
pop_message_t mpm = body->owner;
pop_message_t mpm = message_get_owner (msg);
pop_data_t mpd;
int status = 0;
void *func = (void *)pop_message_size;
size_t num;
if (mpm == NULL)
return EINVAL;
/* Did we have it already ? */
if (mpm->message_size != 0)
{
*psize = mpm->message_size;
return 0;
}
mpd = mpm->mpd;
/* Busy ? */
CHECK_BUSY (mpd->mbox, mpd, func, msg);
/* Get the size. */
switch (mpd->state)
{
case POP_NO_STATE:
status = pop_writeline (mpd, "LIST %d\r\n", mpm->num);
CHECK_ERROR (mpd, status);
MAILBOX_DEBUG0 (mpd->mbox, MU_DEBUG_PROT, mpd->buffer);
mpd->state = POP_LIST;
case POP_LIST:
/* Send the LIST. */
status = pop_write (mpd);
CHECK_EAGAIN (mpd, status);
mpd->state = POP_LIST_ACK;
case POP_LIST_ACK:
/* Resp from LIST. */
status = pop_read_ack (mpd);
CHECK_EAGAIN (mpd, status);
MAILBOX_DEBUG0 (mpd->mbox, MU_DEBUG_PROT, mpd->buffer);
break;
default:
/*
fprintf (stderr, "pop_uidl state\n");
*/
break;
}
status = sscanf (mpd->buffer, "+OK %d %d\n", &num, &mpm->message_size);
CLEAR_STATE (mpd);
if (status != 2)
status = EINVAL;
if (psize)
*psize = mpm->message_size;
return 0;
}
static int
pop_body_size (body_t body, size_t *psize)
{
message_t msg = body_get_owner (body);
pop_message_t mpm = message_get_owner (msg);
if (mpm == NULL)
return EINVAL;
/* Did we have it already ? */
if (mpm->body_size != 0)
{
*psize = mpm->body_size;
}
else if (mpm->message_size != 0)
{
*psize = mpm->message_size - mpm->header_size - mpm->body_lines;
}
else
*psize = 0;
return 0;
}
static int
pop_body_lines (body_t body, size_t *plines)
{
pop_message_t mpm = body->owner;
message_t msg = body_get_owner (body);
pop_message_t mpm = message_get_owner (msg);
if (mpm == NULL)
return EINVAL;
if (plines)
......@@ -1005,9 +1025,10 @@ pop_body_lines (body_t body, size_t *plines)
because we call header_get_value the function may return EAGAIN...
uncool. */
static int
pop_get_flags (attribute_t attr, int *pflags)
pop_attr_flags (attribute_t attr, int *pflags)
{
pop_message_t mpm = attr->owner;
message_t msg = attribute_get_owner (attr);
pop_message_t mpm = message_get_owner (msg);
char hdr_status[64];
header_t header = NULL;
int err;
......@@ -1023,10 +1044,38 @@ pop_get_flags (attribute_t attr, int *pflags)
return err;
}
/* stub to call from body object. */
static int
pop_body_fd (stream_t stream, int *pfd)
{
body_t body = stream_get_owner (stream);
message_t msg = body_get_owner (body);
pop_message_t mpm = message_get_owner (msg);
return pop_get_fd (mpm, pfd);
}
/* stub to call from header object. */
static int
pop_header_fd (stream_t stream, int *pfd)
{
header_t header = stream_get_owner (stream);
message_t msg = header_get_owner (header);
pop_message_t mpm = message_get_owner (msg);
return pop_get_fd (mpm, pfd);
}
/* stub to call from message object. */
static int
pop_message_fd (stream_t stream, int *pfd)
{
message_t msg = stream_get_owner (stream);
pop_message_t mpm = message_get_owner (msg);
return pop_get_fd (mpm, pfd);
}
static int
pop_get_fd (stream_t stream, int *pfd)
pop_get_fd (pop_message_t mpm, int *pfd)
{
pop_message_t mpm = stream->owner;
if (mpm && mpm->mpd && mpm->mpd->mbox)
return stream_get_fd (mpm->mpd->mbox->stream, pfd);
return EINVAL;
......@@ -1039,7 +1088,7 @@ pop_get_fd (stream_t stream, int *pfd)
static int
pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
{
pop_message_t mpm = msg->owner;
pop_message_t mpm = message_get_owner (msg);
pop_data_t mpd;
int status = 0;
void *func = (void *)pop_uidl;
......@@ -1053,10 +1102,7 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
mpd = mpm->mpd;
/* Busy ? */
if (mpd->func && mpd->func != func)
return EBUSY;
mpd->func = func;
CHECK_BUSY (mpd->mbox, mpd, func, 0);
/* Get the UIDL. */
switch (mpd->state)
......@@ -1064,10 +1110,10 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
case POP_NO_STATE:
status = pop_writeline (mpd, "UIDL %d\r\n", mpm->num);
CHECK_ERROR (mpd, status);
mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer);
mpd->state = POP_UIDL_TX;
MAILBOX_DEBUG0 (mpd->mbox, MU_DEBUG_PROT, mpd->buffer);
mpd->state = POP_UIDL;
case POP_UIDL_TX:
case POP_UIDL:
/* Send the UIDL. */
status = pop_write (mpd);
CHECK_EAGAIN (mpd, status);
......@@ -1077,7 +1123,7 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
/* Resp from UIDL. */
status = pop_read_ack (mpd);
CHECK_EAGAIN (mpd, status);
mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer);
MAILBOX_DEBUG0 (mpd->mbox, MU_DEBUG_PROT, mpd->buffer);
break;
default:
......@@ -1089,6 +1135,7 @@ pop_uidl (message_t msg, char *buffer, size_t buflen, size_t *pnwriten)
CLEAR_STATE (mpd);
/* FIXME: I should cache the result. */
*uniq = '\0';
status = sscanf (mpd->buffer, "+OK %d %127s\n", &num, uniq);
if (status != 2)
......@@ -1117,7 +1164,9 @@ static int
pop_top (stream_t is, char *buffer, size_t buflen,
off_t offset, size_t *pnread)
{
pop_message_t mpm = is->owner;
header_t header = stream_get_owner (is);
message_t msg = header_get_owner (header);
pop_message_t mpm = message_get_owner (msg);
pop_data_t mpd;
size_t nread = 0;
int status = 0;
......@@ -1126,15 +1175,14 @@ pop_top (stream_t is, char *buffer, size_t buflen,
if (mpm == NULL)
return EINVAL;
/* We do not carry the offset(for pop), should be doc somewhere. */
(void)offset;
mpd = mpm->mpd;
/* Busy ? */
if (mpd->func && mpd->func != func)
return EBUSY;
/* We do not carry the offset backward(for pop), should be doc somewhere. */
if ((size_t)offset < mpm->header_size)
return ESPIPE;
mpd->func = func;
/* Busy ? */
CHECK_BUSY (mpd->mbox, mpd, func, msg);
/* Get the header. */
switch (mpd->state)
......@@ -1145,10 +1193,10 @@ pop_top (stream_t is, char *buffer, size_t buflen,
fall to a second scheme. */
status = pop_writeline (mpd, "TOP %d 0\r\n", mpm->num);
CHECK_ERROR (mpd, status);
mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer);
mpd->state = POP_TOP_TX;
MAILBOX_DEBUG0 (mpd->mbox, MU_DEBUG_PROT, mpd->buffer);
mpd->state = POP_TOP;
case POP_TOP_TX:
case POP_TOP:
/* Send the TOP. */
status = pop_write (mpd);
CHECK_EAGAIN (mpd, status);
......@@ -1158,7 +1206,7 @@ pop_top (stream_t is, char *buffer, size_t buflen,
/* Ack from TOP. */
status = pop_read_ack (mpd);
CHECK_EAGAIN (mpd, status);
mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer);
MAILBOX_DEBUG0 (mpd->mbox, MU_DEBUG_PROT, mpd->buffer);
if (strncasecmp (mpd->buffer, "+OK", 3) != 0)
{
/* fprintf (stderr, "TOP not implemented\n"); */
......@@ -1172,13 +1220,25 @@ pop_top (stream_t is, char *buffer, size_t buflen,
case POP_TOP_RX:
/* Get the header. */
do
{
/* Seek in position. */
ssize_t pos = offset - mpm->header_size;
/* Do we need to fill up. */
if (mpd->nl == NULL || mpd->ptr == mpd->buffer)
{
status = pop_readline (mpd);
CHECK_EAGAIN (mpd, status);
mpm->header_lines++;
}
/* If we have to skip some data to get to the offet. */
if (pos > 0)
nread = fill_buffer (mpd, NULL, pos);
else
nread = fill_buffer (mpd, buffer, buflen);
mpm->header_size += nread;
}
while (nread > 0 && (size_t)offset > mpm->header_size);
break;
default:
......@@ -1199,67 +1259,65 @@ pop_top (stream_t is, char *buffer, size_t buflen,
/* Stub to call pop_retr (). */
static int
pop_read_header (stream_t is, char *buffer, size_t buflen, off_t offset,
pop_header_read (stream_t is, char *buffer, size_t buflen, off_t offset,
size_t *pnread)
{
pop_message_t mpm = is->owner;
message_t msg = stream_get_owner (is);
pop_message_t mpm = message_get_owner (msg);
pop_data_t mpd;
void *func = (void *)pop_read_header;
void *func = (void *)pop_header_read;
if (mpm == NULL)
return EINVAL;
mpd = mpm->mpd;
/* Busy ? */
if (mpd->func && mpd->func != func)
return EBUSY;
mpd->func = func;
CHECK_BUSY (mpd->mbox, mpd, func, msg);
mpm->skip_header = 0;
mpm->skip_body = 1;
return pop_retr (mpm, buffer, buflen, offset, pnread);
}
/* Stub to call pop_retr (). */
/* Stub to call pop_retr (). Call from the stream object of the body. */
static int
pop_read_body (stream_t is, char *buffer, size_t buflen, off_t offset,
pop_body_read (stream_t is, char *buffer, size_t buflen, off_t offset,
size_t *pnread)
{
pop_message_t mpm = is->owner;
body_t body = stream_get_owner (is);
message_t msg = body_get_owner (body);
pop_message_t mpm = message_get_owner (msg);
pop_data_t mpd;
void *func = (void *)pop_read_body;
void *func = (void *)pop_body_read;
if (mpm == NULL)
return EINVAL;
mpd = mpm->mpd;
/* Busy ? */
if (mpd->func && mpd->func != func)
return EBUSY;
mpd->func = func;
CHECK_BUSY (mpd->mbox, mpd, func, msg);
mpm->skip_header = 1;
mpm->skip_body = 0;
return pop_retr (mpm, buffer, buflen, offset, pnread);
}
/* Stub to call pop_retr (). */
/* Stub to call pop_retr (), calling from the stream object of a message. */
static int
pop_read_message (stream_t is, char *buffer, size_t buflen, off_t offset,
pop_message_read (stream_t is, char *buffer, size_t buflen, off_t offset,
size_t *pnread)
{
pop_message_t mpm = is->owner;
message_t msg = stream_get_owner (is);
pop_message_t mpm = message_get_owner (msg);
pop_data_t mpd;
void *func = (void *)pop_read_message;
void *func = (void *)pop_message_read;
if (mpm == NULL)
return EINVAL;
mpd = mpm->mpd;
/* Busy ? */
if (mpd->func && mpd->func != func)
return EBUSY;
mpd->func = func;
CHECK_BUSY (mpd->mbox, mpd, func, msg);
mpm->skip_header = mpm->skip_body = 0;
return pop_retr (mpm, buffer, buflen, offset, pnread);
......@@ -1281,6 +1339,7 @@ fill_buffer (pop_data_t mpd, char *buffer, size_t buflen)
size_t sentinel;
nread = buflen;
sentinel = mpd->ptr - (mpd->buffer + nread);
if (buffer)
memcpy (buffer, mpd->buffer, nread);
memmove (mpd->buffer, mpd->buffer + nread, sentinel);
mpd->ptr = mpd->buffer + sentinel;
......@@ -1289,6 +1348,7 @@ fill_buffer (pop_data_t mpd, char *buffer, size_t buflen)
{
/* Drain our buffer. */;
nread = n;
if (buffer)
memcpy (buffer, mpd->buffer, nread);
mpd->ptr = mpd->buffer;
}
......@@ -1308,24 +1368,35 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset,
(void)offset;
mpd = mpm->mpd;
if (pnread)
*pnread = nread;
/* Take care of the obvious. */
if (buffer == NULL || buflen == 0)
{
CLEAR_STATE (mpd);
return 0;
}
mpd = mpm->mpd;
/* We do not carry the offset backward(for pop), should be doc somewhere. */
/*if (offset < mpm->header_size)
return ESPIPE;
*/
/* pop_retr() is not call directly so we assume that the locks were set. */
switch (mpd->state)
{
case POP_NO_STATE:
mpm->body_lines = mpm->body_size = 0;
status = pop_writeline (mpd, "RETR %d\r\n", mpm->num);
mailbox_debug (mpd->mbox, MU_MAILBOX_DEBUG_PROT, mpd->buffer);
MAILBOX_DEBUG0 (mpd->mbox, MU_DEBUG_PROT, mpd->buffer);
CHECK_ERROR (mpd, status);
mpd->state = POP_RETR_TX;
mpd->state = POP_RETR;
case POP_RETR_TX:
case POP_RETR:
/* Send the RETR command. */
status = pop_write (mpd);
CHECK_EAGAIN (mpd, status);
......@@ -1347,6 +1418,7 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset,
{
/* Do we need to fill up. */
if (mpd->nl == NULL || mpd->ptr == mpd->buffer)
{
status = pop_readline (mpd);
if (status != 0)
......@@ -1356,11 +1428,17 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset,
return 0;
CHECK_EAGAIN (mpd, status);
}
mpm->header_lines++;
}
/* Oops !! Hello houston we have a major problem here. */
if (mpd->buffer[0] == '\0')
{
/* Still Do the right thing. */
if (buflen != oldbuflen)
{
CLEAR_STATE (mpd);
}
else
mpd->state = POP_STATE_DONE;
return 0;
}
......@@ -1372,9 +1450,18 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset,
hack below will suffice. */
if (mpd->buffer[0] == '\n' && mpd->buffer[1] == '\0')
mpm->inbody = 1; /* break out of the while. */
if (mpm->skip_header == 0)
if (!mpm->skip_header)
{
ssize_t pos = offset - mpm->header_size;
if (pos)
{
nread = fill_buffer (mpd, NULL, pos);
mpm->header_size += nread;
}
else
{
nread = fill_buffer (mpd, buffer, buflen);
mpm->header_size += nread;
if (pnread)
*pnread += nread;
buflen -= nread ;
......@@ -1383,6 +1470,7 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset,
else
return 0;
}
}
else
mpd->ptr = mpd->buffer;
}
......@@ -1409,7 +1497,15 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset,
if (mpd->buffer[0] == '\0')
mpm->inbody = 0; /* Breakout of the while. */
if (mpm->skip_body == 0)
if (!mpm->skip_body)
{
ssize_t pos = offset - mpm->body_size;
if (pos > 0)
{
nread = fill_buffer (mpd, NULL, pos);
mpm->body_size += nread;
}
else
{
nread = fill_buffer (mpd, buffer, buflen);
mpm->body_size += nread;
......@@ -1421,12 +1517,14 @@ pop_retr (pop_message_t mpm, char *buffer, size_t buflen, off_t offset,
else
return 0;
}
}
else
{
mpm->body_size += (mpd->ptr - mpd->buffer);
mpd->ptr = mpd->buffer;
}
}
mpm->message_size = mpm->body_size + mpm->header_size;
mpd->state = POP_STATE_DONE;
/* Return here earlier, because we want to return nread = 0 to notify
the callee that we've finish, since there is already data in the
......
......@@ -15,9 +15,9 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <stream0.h>
#include <message0.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <errno.h>
#include <stdio.h>
......@@ -28,9 +28,10 @@
#include <string.h>
#include <ctype.h>
/* FIXME: This should be part of the address_t object when implemented. */
static int extract_addr(const char *s, size_t n, char **presult,
size_t *pnwrite);
#include <mailutils/stream.h>
#include <misc.h>
#include <message0.h>
static int message_read (stream_t is, char *buf, size_t buflen,
off_t off, size_t *pnread );
static int message_write (stream_t os, const char *buf, size_t buflen,
......@@ -64,34 +65,26 @@ message_destroy (message_t *pmsg, void *owner)
{
/* Notify the listeners. */
/* FIXME: to be removed since we do not supoort this event. */
if (msg->event_num)
if (msg->observable)
{
message_notification (msg, MU_EVT_MSG_DESTROY);
free (msg->event);
observable_notify (msg->observable, MU_EVT_MESSAGE_DESTROY);
observable_destroy (&(msg->observable), msg);
}
/* Header. */
if (msg->header)
header_destroy (&(msg->header), owner);
if (msg->header)
header_destroy (&(msg->header), msg);
/* Attribute. */
if (msg->attribute)
attribute_destroy (&(msg->attribute), owner);
if (msg->attribute)
attribute_destroy (&(msg->attribute), msg);
/* Stream. */
if (msg->stream)
stream_destroy (&(msg->stream), owner);
if (msg->stream)
stream_destroy (&(msg->stream), msg);
/* Body. */
if (msg->body)
body_destroy (&(msg->body), owner);
if (msg->body)
body_destroy (&(msg->body), msg);
/* Mime. */
......@@ -105,6 +98,12 @@ message_destroy (message_t *pmsg, void *owner)
}
}
void *
message_get_owner (message_t msg)
{
return (msg == NULL) ? NULL : msg->owner;
}
int
message_get_header (message_t msg, header_t *phdr)
{
......@@ -198,7 +197,7 @@ message_get_stream (message_t msg, stream_t *pstream)
stream_set_read (stream, message_read, msg);
stream_set_write (stream, message_write, msg);
stream_set_fd (stream, message_get_fd, msg);
stream_set_flags (stream, MU_STREAM_RDWR, msg);
stream_set_flags (stream, MU_STREAM_RDWR);
msg->stream = stream;
}
......@@ -222,6 +221,8 @@ int
message_lines (message_t msg, size_t *plines)
{
size_t hlines, blines;
int ret = 0;
if (msg == NULL)
return EINVAL;
/* Overload. */
......@@ -230,11 +231,11 @@ message_lines (message_t msg, size_t *plines)
if (plines)
{
hlines = blines = 0;
header_lines (msg->header, &hlines);
body_lines (msg->body, &blines);
if ( ( ret = header_lines (msg->header, &hlines) ) == 0 )
ret = body_lines (msg->body, &blines);
*plines = hlines + blines;
}
return 0;
return ret;
}
int
......@@ -253,6 +254,8 @@ int
message_size (message_t msg, size_t *psize)
{
size_t hsize, bsize;
int ret = 0;
if (msg == NULL)
return EINVAL;
/* Overload ? */
......@@ -261,11 +264,11 @@ message_size (message_t msg, size_t *psize)
if (psize)
{
hsize = bsize = 0;
header_size (msg->header, &hsize);
body_size (msg->body, &bsize);
if ( ( ret = header_size (msg->header, &hsize) ) == 0 )
ret = body_size (msg->body, &bsize);
*psize = hsize + bsize;
}
return 0;
return ret;
}
int
......@@ -300,12 +303,22 @@ message_from (message_t msg, char *buf, size_t len, size_t *pnwrite)
status = header_get_value (header, MU_HEADER_FROM, NULL, 0, &n);
if (status == 0 && n != 0)
{
char *from = calloc (1, n + 1);
char *from;
char *addr;
from = calloc (1, n + 1);
if (from == NULL)
return ENOMEM;
addr = calloc (1, n + 1);
if (addr == NULL)
{
free (from);
return ENOMEM;
}
header_get_value (header, MU_HEADER_FROM, from, n + 1, NULL);
if (extract_addr (from, n, &addr, &n) == 0)
if (parseaddr (from, addr, n + 1) == 0)
{
n = (n > len) ? len : n;
size_t i = strlen (addr);
n = (i > len) ? len : i;
if (buf && len > 0)
{
memcpy (buf, addr, n);
......@@ -563,77 +576,26 @@ message_set_get_part (message_t msg, int (*_get_part)
}
int
message_register (message_t msg, size_t type,
int (*action) (size_t typ, void *arg), void *arg)
message_get_observable (message_t msg, observable_t *pobservable)
{
event_t event;
size_t i;
if (msg == NULL || action == NULL || type == 0)
if (msg == NULL || pobservable == NULL)
return EINVAL;
/* Find a free spot. */
for (i = 0; i < msg->event_num; i++)
if (msg->observable == NULL)
{
event = &(msg->event[i]);
if (event->_action == NULL)
{
event->type = type;
event->_action = action;
event->arg = arg;
return 0;
}
int status = observable_create (&(msg->observable), msg);
if (status != 0)
return status;
}
event = realloc (msg->event, (msg->event_num + 1)*sizeof (*event));
if (event == NULL)
return ENOMEM;
msg->event = event;
event[msg->event_num]._action = action;
event[msg->event_num].type = type;
event[msg->event_num].arg = arg;
msg->event_num++;
return 0;
}
int
message_deregister (message_t msg, void *action)
{
size_t i;
event_t event;
if (msg == NULL || action == NULL)
return EINVAL;
for (i = 0; i < msg->event_num; i++)
{
event = &(msg->event[i]);
if ((int)event->_action == (int)action)
{
event->type = 0;
event->_action = NULL;
event->arg = NULL;
*pobservable = msg->observable;
return 0;
}
}
return ENOENT;
}
void
message_notification (message_t msg, size_t type)
{
size_t i;
event_t event;
for (i = 0; i < msg->event_num; i++)
{
event = &(msg->event[i]);
if ((event->_action) && (event->type & type))
event->_action (type, event->arg);
}
}
static int
message_read (stream_t is, char *buf, size_t buflen,
off_t off, size_t *pnread )
{
message_t msg = is->owner;
message_t msg = stream_get_owner (is);
stream_t his, bis;
size_t hread, hsize, bread, bsize;
......@@ -670,11 +632,11 @@ static int
message_write (stream_t os, const char *buf, size_t buflen,
off_t off, size_t *pnwrite)
{
message_t msg;
message_t msg = stream_get_owner (os);
int status = 0;
size_t bufsize = buflen;
if (os == NULL || (msg = os->owner) == NULL)
if (msg == NULL)
return EINVAL;
/* Skip the obvious. */
......@@ -772,11 +734,11 @@ message_write (stream_t os, const char *buf, size_t buflen,
static int
message_get_fd (stream_t stream, int *pfd)
{
message_t msg;
message_t msg = stream_get_owner (stream);
body_t body;
stream_t is;
if (stream == NULL || (msg = stream->owner) == NULL)
if (msg == NULL)
return EINVAL;
/* Probably being lazy, then create a body for the stream. */
......@@ -794,72 +756,3 @@ message_get_fd (stream_t stream, int *pfd)
body_get_stream (body, &is);
return stream_get_fd (is, pfd);
}
static int
extract_addr (const char *s, size_t n, char **presult, size_t *pnwrite)
{
char *p, *p1, *p2;
if (s == NULL || n == 0 || presult == NULL)
return EINVAL;
/* Skip the double quotes. */
p = memchr (s, '\"', n);
if (p != NULL)
{
p1 = memchr (s, '<', p - s);
p2 = memchr (s, '@', p - s);
if (p1 == NULL && p2 == NULL)
{
p1 = memchr (p + 1, '\"', n - ((p + 1) - s));
if (p1 != NULL)
{
n -= (p1 + 1) - s;
s = p1 + 1;
}
}
}
/* <name@hostname> ?? */
p = memchr (s, '<', n);
if (p != NULL)
{
p1 = memchr (p, '>', n - (p - s));
if (p1 != NULL && (p1 - p) > 1)
{
p2 = memchr (p, ' ', p1 - p);
if (p2 == NULL)
{
/* The NULL is already accounted for. */
*presult = calloc (1, p1 - p);
if (*presult == NULL)
return ENOMEM;
memcpy (*presult, p + 1, (p1 - p) - 1);
if (pnwrite)
*pnwrite = (p1 - p) - 1;
return 0;
}
}
}
/* name@domain */
p = memchr (s, '@', n);
if (p != NULL)
{
p1 = p;
while (*p != ' ' && p != s)
p--;
while (*p1 != ' ' && p1 < (s + n))
p1++;
*presult = calloc (1, (p1 - p) + 1);
if (*presult == NULL)
return ENOMEM;
memcpy (*presult, p, p1 - p);
if (pnwrite)
*pnwrite = p1 - p;
return 0;
}
*presult = NULL;
return EINVAL;
}
......
......@@ -16,17 +16,18 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <message0.h>
#include <mime0.h>
#include <stream0.h>
#include <body0.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <mailutils/message.h>
#include <mailutils/stream.h>
#include <mailutils/body.h>
#include <mailutils/header.h>
#include <mime0.h>
#ifndef TRUE
#define TRUE (1)
#define FALSE (0)
......@@ -34,11 +35,8 @@
/* TODO:
* Need to prevent re-entry into mime lib, but allow non-blocking re-entry into lib.
* Define mbx i/f for protocols that support mime parsing (IMAP).
*/
#define DIGEST_TYPE "Content-Type: message/rfc822"
static int _mime_is_multipart_digest(mime_t mime)
{
if ( mime->content_type )
......@@ -46,16 +44,16 @@ static int _mime_is_multipart_digest(mime_t mime)
return 0;
}
static int _mime_append_part(mime_t mime, message_t msg, int body_offset, int body_len)
static int _mime_append_part(mime_t mime, message_t msg, int offset, int len, int lines)
{
struct _mime_part *mime_part, **part_arr;
int ret;
size_t size;
header_t hdr;
if ( ( mime_part = calloc(1, sizeof(*mime_part)) ) == NULL )
return ENOMEM;
memcpy(mime_part->sig,"MIME", 4);
if ( mime->nmtp_parts >= mime->tparts ) {
if ( ( part_arr = realloc(mime->mtp_parts, ( mime->tparts + 5 ) * sizeof(mime_part)) ) == NULL ) {
free(mime_part);
......@@ -66,21 +64,34 @@ static int _mime_append_part(mime_t mime, message_t msg, int body_offset, int bo
}
mime->mtp_parts[mime->nmtp_parts++] = mime_part;
if ( msg == NULL ) {
if ( ( ret = header_create(&mime_part->hdr, mime->header_buf, mime->header_length, mime_part) ) != 0 ) {
if ( ( ret = message_create(&(mime_part->msg), mime_part) ) == 0 ) {
if ( ( ret = header_create(&hdr, mime->header_buf, mime->header_length, mime_part->msg) ) != 0 ) {
message_destroy(&mime_part->msg, mime_part);
free(mime_part);
return ret;
}
message_set_header(mime_part->msg, hdr, mime_part);
} else {
free(mime_part);
return ret;
}
mime->header_length = 0;
if ( ( ret = header_get_value(mime_part->hdr, "Content-Type", NULL, 0, &size) ) != 0 || size == 0 ) {
if ( ( ret = header_get_value(hdr, "Content-Type", NULL, 0, &size) ) != 0 || size == 0 ) {
if ( _mime_is_multipart_digest(mime) )
header_set_value(mime_part->hdr, "Content-Type", "message/rfc822", 0);
header_set_value(hdr, "Content-Type", "message/rfc822", 0);
else
header_set_value(mime_part->hdr, "Content-Type", "text/plain", 0);
}
header_set_value(hdr, "Content-Type", "text/plain", 0);
}
mime_part->body_len = body_len;
mime_part->body_offset = body_offset;
mime_part->len = len;
mime_part->lines = lines;
mime_part->offset = offset;
} else {
message_size(msg, &mime_part->len);
message_lines(msg, &mime_part->lines);
if ( mime->nmtp_parts > 1 )
mime_part->offset = mime->mtp_parts[mime->nmtp_parts-2]->len;
mime_part->msg = msg;
}
mime_part->mime = mime;
return 0;
}
......@@ -170,7 +181,7 @@ static char *_mime_get_param(char *field_body, const char *param, int *len)
continue;
}
else
return was_quoted ? v + 1 : v; /* return unquted value */
return was_quoted ? v + 1 : v; /* return unquoted value */
}
return NULL;
}
......@@ -203,7 +214,7 @@ static void _mime_append_header_line(mime_t mime)
static int _mime_parse_mpart_message(mime_t mime)
{
char *cp, *cp2;
int blength, body_length, body_offset, ret;
int blength, body_length, body_offset, body_lines, ret;
size_t nbytes;
if ( !(mime->flags & MIME_PARSER_ACTIVE) ) {
......@@ -225,6 +236,7 @@ static int _mime_parse_mpart_message(mime_t mime)
}
body_length = mime->body_length;
body_offset = mime->body_offset;
body_lines = mime->body_lines;
while ( ( ret = stream_read(mime->stream, mime->cur_buf, mime->buf_size, mime->cur_offset, &nbytes) ) == 0 && nbytes ) {
cp = mime->cur_buf;
......@@ -240,6 +252,8 @@ static int _mime_parse_mpart_message(mime_t mime)
case MIME_STATE_SCAN_BOUNDARY:
cp2 = mime->cur_line[0] == '\n' ? mime->cur_line + 1 : mime->cur_line;
blength = strlen(mime->boundary);
if ( mime->header_length )
body_lines++;
if ( mime->line_ndx >= blength ) {
if ( ( !strncasecmp(cp2,"--", 2) && !strncasecmp(cp2+2, mime->boundary, blength) )
|| !strncasecmp(cp2, mime->boundary, blength) ) {
......@@ -247,7 +261,7 @@ static int _mime_parse_mpart_message(mime_t mime)
mime->flags &= ~MIME_PARSER_HAVE_CR;
body_length = mime->cur_offset - body_offset - mime->line_ndx + 1;
if ( mime->header_length ) /* this skips the preamble */
_mime_append_part(mime, NULL, body_offset, body_length);
_mime_append_part(mime, NULL, body_offset, body_length, body_lines);
if ( ( cp2 + blength + 2 < cp && !strncasecmp(cp2+2+blength, "--",2) ) ||
!strncasecmp(cp2+blength, "--",2) ) { /* very last boundary */
mime->parser_state = MIME_STATE_BEGIN_LINE;
......@@ -267,6 +281,7 @@ static int _mime_parse_mpart_message(mime_t mime)
if ( mime->line_ndx == 1 || mime->cur_line[0] == '\r' ) {
mime->parser_state = MIME_STATE_BEGIN_LINE;
body_offset = mime->cur_offset + 1;
body_lines = 0;
}
mime->line_ndx = -1;
break;
......@@ -281,59 +296,225 @@ static int _mime_parse_mpart_message(mime_t mime)
nbytes--;
cp++;
}
if ( mime->flags & MIME_INCREAMENTAL_PARSER ) {
/*
* can't really do this since returning EAGAIN will make the MUA think
* it should select on the messages stream fd. re-think this whole
* non-blocking thing.....
ret = EAGAIN;
break;
*/
}
}
mime->body_lines = body_lines;
mime->body_length = body_length;
mime->body_offset = body_offset;
if ( ret != EAGAIN ) { /* finished cleanup */
if ( mime->header_length ) /* this skips the preamble */
_mime_append_part(mime, NULL, body_offset, body_length);
_mime_append_part(mime, NULL, body_offset, body_length, body_lines);
mime->flags &= ~MIME_PARSER_ACTIVE;
mime->body_offset = mime->body_length = mime->header_length = 0;
mime->body_offset = mime->body_length = mime->header_length = mime->body_lines = 0;
}
return ret;
}
static int _mime_message_read(stream_t stream, char *buf, size_t buflen, off_t off, size_t *nbytes)
/*------ Mime message functions for READING a multipart message -----*/
static int _mimepart_body_read(stream_t stream, char *buf, size_t buflen, off_t off, size_t *nbytes)
{
struct _mime_part *mime_part = stream->owner;
body_t body = stream_get_owner(stream);
message_t msg = body_get_owner(body);
struct _mime_part *mime_part = message_get_owner(msg);
size_t read_len;
if ( nbytes == NULL )
return(EINVAL);
*nbytes = 0;
read_len = (int)mime_part->body_len - (int)off;
read_len = (int)mime_part->len - (int)off;
if ( read_len <= 0 )
return 0;
read_len = (buflen <= read_len)? buflen : read_len;
return stream_read(mime_part->mime->stream, buf, read_len, mime_part->body_offset + off, nbytes );
return stream_read(mime_part->mime->stream, buf, read_len, mime_part->offset + off, nbytes );
}
static int _mime_message_fd(stream_t stream, int *fd)
static int _mimepart_body_fd(stream_t stream, int *fd)
{
struct _mime_part *mime_part = stream->owner;
body_t body = stream_get_owner(stream);
message_t msg = body_get_owner(body);
struct _mime_part *mime_part = message_get_owner(msg);
return stream_get_fd(mime_part->mime->stream, fd);
}
static int _mime_body_size (body_t body, size_t *psize)
static int _mimepart_body_size (body_t body, size_t *psize)
{
struct _mime_part *mime_part = body->owner;
message_t msg = body_get_owner(body);
struct _mime_part *mime_part = message_get_owner(msg);
if (mime_part == NULL)
return EINVAL;
if (psize)
*psize = mime_part->body_len;
*psize = mime_part->len;
return 0;
}
static int _mimepart_body_lines (body_t body, size_t *plines)
{
message_t msg = body_get_owner(body);
struct _mime_part *mime_part = message_get_owner(msg);
if (mime_part == NULL)
return EINVAL;
if (plines)
*plines = mime_part->lines;
return 0;
}
/*------ Mime message/header functions for CREATING multipart message -----*/
static int _mime_set_content_type(mime_t mime)
{
char content_type[256];
char boundary[128];
if ( mime->nmtp_parts > 1 ) {
if ( mime->flags & MIME_ADDED_MULTIPART )
return 0;
if ( mime->flags & MIME_MULTIPART_MIXED )
strcpy(content_type, "multipart/mixed; boundary=");
else
strcpy(content_type, "multipart/alternative; boundary=");
if ( mime->boundary == NULL ) {
sprintf (boundary,"%ld-%ld=:%ld",random (),time (0), getpid ());
if ( ( mime->boundary = strdup(boundary) ) == NULL )
return ENOMEM;
}
strcat(content_type, "\"");
strcat(content_type, mime->boundary);
strcat(content_type, "\"");
mime->flags |= MIME_ADDED_MULTIPART;
} else {
if ( (mime->flags & (MIME_ADDED_CONTENT_TYPE|MIME_ADDED_MULTIPART)) == MIME_ADDED_CONTENT_TYPE )
return 0;
mime->flags &= ~MIME_ADDED_MULTIPART;
strcpy(content_type, "text/plain; charset=us-ascii");
}
mime->flags |= MIME_ADDED_CONTENT_TYPE;
return header_set_value(mime->hdrs, "Content-Type", content_type, 1);
}
static int _mime_body_read(stream_t stream, char *buf, size_t buflen, off_t off, size_t *nbytes)
{
body_t body = stream_get_owner(stream);
message_t msg = body_get_owner(body);
mime_t mime = message_get_owner(msg);
int ret = 0, len;
size_t part_nbytes = 0;
stream_t msg_stream = NULL;
if ( mime->nmtp_parts == 0 )
return EINVAL;
if ( off == 0 ) { /* reset message */
mime->cur_offset = 0;
mime->cur_part = 0;
}
if ( off != mime->cur_offset )
return ESPIPE;
if ( nbytes )
*nbytes = 0;
if ( mime->cur_part == mime->nmtp_parts )
return 0;
if ( ( ret = _mime_set_content_type(mime) ) == 0 ) {
do {
len = 0;
if ( mime->nmtp_parts > 1 && ( mime->flags & MIME_INSERT_BOUNDARY || mime->cur_offset == 0 ) ) {
mime->cur_part++;
len = 2;
buf[0] = buf[1] = '-';
buf+=2;
len += strlen(mime->boundary);
strcpy(buf, mime->boundary);
buf+= strlen(mime->boundary);
if ( mime->cur_part == mime->nmtp_parts ) {
len+=2;
buf[0] = buf[1] = '-';
buf+=2;
}
len++;
buf[0] = '\n';
buf++;
mime->flags &= ~MIME_INSERT_BOUNDARY;
buflen =- len;
mime->part_offset = 0;
if ( mime->cur_part == mime->nmtp_parts ) {
if ( nbytes )
*nbytes += len;
mime->cur_offset +=len;
break;
}
}
message_get_stream(mime->mtp_parts[mime->cur_part]->msg, &msg_stream);
ret = stream_read(msg_stream, buf, buflen, mime->part_offset, &part_nbytes );
len += part_nbytes;
mime->part_offset += part_nbytes;
if ( nbytes )
*nbytes += len;
mime->cur_offset += len;
if ( ret == 0 && part_nbytes == 0 )
mime->flags |= MIME_INSERT_BOUNDARY;
} while( ret == 0 && part_nbytes == 0 );
}
return ret;
}
static int _mime_body_fd(stream_t stream, int *fd)
{
body_t body = stream_get_owner(stream);
message_t msg = body_get_owner(body);
mime_t mime = message_get_owner(msg);
stream_t msg_stream = NULL;
if ( mime->nmtp_parts == 0 || mime->cur_offset == 0 )
return EINVAL;
message_get_stream(mime->mtp_parts[mime->cur_part]->msg, &msg_stream);
return stream_get_fd(msg_stream, fd);
}
static int _mime_body_size (body_t body, size_t *psize)
{
message_t msg = body_get_owner(body);
mime_t mime = message_get_owner(msg);
int i;
size_t size;
if ( mime->nmtp_parts == 0 )
return EINVAL;
for ( i=0;i<mime->nmtp_parts;i++ ) {
message_size(mime->mtp_parts[i]->msg, &size);
*psize+=size;
if ( mime->nmtp_parts > 1 ) /* boundary line */
*psize+= strlen(mime->boundary) + 3;
}
if ( mime->nmtp_parts > 1 ) /* ending boundary line */
*psize+= 2;
return 0;
}
static int _mime_body_lines (body_t body, size_t *plines)
{
message_t msg = body_get_owner(body);
mime_t mime = message_get_owner(msg);
int i;
size_t lines;
if ( mime->nmtp_parts == 0 )
return EINVAL;
for ( i = 0; i < mime->nmtp_parts; i++ ) {
message_lines(mime->mtp_parts[i]->msg, &lines);
plines+=lines;
if ( mime->nmtp_parts > 1 ) /* boundary line */
plines++;
}
return 0;
}
......@@ -342,11 +523,12 @@ int mime_create(mime_t *pmime, message_t msg, int flags)
mime_t mime = NULL;
int ret = 0;
size_t size;
body_t body;
if (pmime == NULL)
return EINVAL;
*pmime = NULL;
if ( ( mime = calloc (1, sizeof (*mime)) ) == NULL )
if ( ( mime = calloc(1, sizeof (*mime)) ) == NULL )
return ENOMEM;
if ( msg ) {
if ( ( ret = message_get_header(msg, &(mime->hdrs)) ) == 0 ) {
......@@ -363,22 +545,21 @@ int mime_create(mime_t *pmime, message_t msg, int flags)
if (ret == 0 ) {
mime->msg = msg;
mime->buf_size = MIME_DFLT_BUF_SIZE;
message_get_stream(msg, &(mime->stream));
message_get_body(msg, &body);
body_get_stream(body, &(mime->stream));
}
}
}
else {
if ( ( ret = message_create( &(mime->msg), mime ) ) == 0 ) {
mime->flags |= MIME_NEW_MESSAGE;
}
}
if ( ret != 0 ) {
if ( mime->content_type )
free(mime->content_type);
free(mime);
}
else {
mime->flags = (flags & MIME_FLAG_MASK);
mime->flags |= (flags & MIME_FLAG_MASK);
*pmime = mime;
}
return ret;
......@@ -397,8 +578,6 @@ void mime_destroy(mime_t *pmime)
mime_part = mime->mtp_parts[i];
if ( mime_part->msg )
message_destroy(&mime_part->msg, mime_part);
else if ( mime_part->hdr )
header_destroy(&mime_part->hdr, mime_part);
}
}
if ( mime->content_type )
......@@ -419,7 +598,6 @@ void mime_destroy(mime_t *pmime)
int mime_get_part(mime_t mime, int part, message_t *msg)
{
int nmtp_parts, ret = 0;
size_t hsize = 0;
stream_t stream;
body_t body;
struct _mime_part *mime_part;
......@@ -431,22 +609,18 @@ int mime_get_part(mime_t mime, int part, message_t *msg)
*msg = mime->msg;
else {
mime_part = mime->mtp_parts[part-1];
if ( ( ret = message_create(&(mime_part->msg), mime_part) ) == 0 ) {
message_set_header(mime_part->msg, mime_part->hdr, mime_part);
header_size(mime_part->hdr, &hsize);
if ( ( ret = body_create(&body, mime_part) ) == 0 ) {
if ( ( ret = stream_create(&stream, MU_STREAM_READ, mime_part) ) == 0 ) {
body_set_size (body, _mime_body_size, mime_part);
stream_set_read(stream, _mime_message_read, mime_part);
stream_set_fd(stream, _mime_message_fd, mime_part);
body_set_stream(body, stream, mime_part);
if ( ( ret = body_create(&body, mime_part->msg) ) == 0 ) {
body_set_size (body, _mimepart_body_size, mime_part->msg);
body_set_lines (body, _mimepart_body_lines, mime_part->msg);
if ( ( ret = stream_create(&stream, MU_STREAM_READ, body) ) == 0 ) {
stream_set_read(stream, _mimepart_body_read, body);
stream_set_fd(stream, _mimepart_body_fd, body);
body_set_stream(body, stream, mime_part->msg);
message_set_body(mime_part->msg, body, mime_part);
*msg = mime_part->msg;
return 0;
}
}
message_destroy(&mime_part->msg, mime_part);
}
}
}
return ret;
......@@ -472,15 +646,45 @@ int mime_add_part(mime_t mime, message_t msg)
{
if ( mime == NULL || msg == NULL || ( mime->flags & MIME_NEW_MESSAGE ) == 0 )
return EINVAL;
return _mime_append_part(mime, msg, 0, 0);
return _mime_append_part(mime, msg, 0, 0, 0);
}
int mime_get_message(mime_t mime, message_t *msg)
{
stream_t body_stream;
body_t body;
int ret = 0;
if ( mime == NULL || msg == NULL )
return EINVAL;
if ( mime->msg == NULL ) {
if ( ( mime->flags & MIME_NEW_MESSAGE ) == 0 )
return EINVAL;
if ( ( ret = message_create(&(mime->msg), mime) ) == 0 ) {
if ( ( ret = header_create(&(mime->hdrs), NULL, 0, mime->msg) ) == 0 ) {
message_set_header(mime->msg, mime->hdrs, mime);
header_set_value(mime->hdrs, "MIME-Version", "1.0", 0);
if ( ( ret = _mime_set_content_type(mime) ) == 0 ) {
if ( ( ret = body_create(&body, mime->msg) ) == 0 ) {
message_set_body(mime->msg, body, mime);
body_set_size (body, _mime_body_size, mime->msg);
body_set_lines (body, _mime_body_lines, mime->msg);
if ( ( ret = stream_create(&body_stream, MU_STREAM_READ, body) ) == 0 ) {
stream_set_read(body_stream, _mime_body_read, body);
stream_set_fd(body_stream, _mime_body_fd, body);
body_set_stream(body, body_stream, mime->msg);
*msg = mime->msg;
return 0;
}
}
}
}
message_destroy(&(mime->msg), mime);
}
}
if ( ret == 0 )
*msg = mime->msg;
return ret;
}
int mime_is_multipart(mime_t mime)
......
/* 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 <misc.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
size_t
_cpystr (char *dst, const char *src, size_t size)
{
size_t len = src ? strlen (src) : 0 ;
if (dst == NULL || size == 0)
return len;
if (len >= size)
len = size - 1;
memcpy (dst, src, len);
dst[len] = '\0';
return len;
}
/*
* parseaddr.c Read a valid RFC822 address with all the comments
* etc in it, and return _just_ the email address.
*
* Version: @(#)parseaddr.c 1.00 02-Apr-1999 miquels@cistron.nl
*
*/
struct token
{
struct token *next;
char word[1];
};
#define SKIPSPACE(p) do { while(*p && isspace(*p)) p++; } while(0)
/* Skip everything between quotes. */
static void
quotes (char **ptr)
{
char *p = *ptr;
p++;
while (*p && *p != '"')
{
if (*p == '\\' && p[1])
p++;
p++;
}
*ptr = p;
}
/* Return the next token. A token can be "<>()," or any "word". */
static struct token *
gettoken (char **ptr)
{
struct token *tok;
char *p = *ptr;
char *begin;
int l, quit = 0;
SKIPSPACE(p);
begin = p;
while (!quit)
{
switch (*p)
{
case 0:
case ' ':
case '\t':
case '\n':
quit = 1;
break;
case '(':
case ')':
case '<':
case '>':
case ',':
if (p == begin)
p++;
quit = 1;
break;
case '\\':
if (p[1])
p++;
break;
case '"':
quotes (&p);
break;
}
if (!quit)
p++;
}
l = p - begin;
if (l == 0)
return NULL;
tok = malloc (sizeof (struct token) + l);
if (tok == NULL)
return NULL;
tok->next = NULL;
strncpy (tok->word, begin, l);
tok->word[l] = 0;
SKIPSPACE (p);
*ptr = p;
return tok;
}
/* Get email address from rfc822 address. */
int
parseaddr (const char *addr, char *buf, size_t bufsz)
{
const char *p;
struct token *t, *tok, *last;
struct token *brace = NULL;
int comment = 0;
tok = last = NULL;
/* Read address, remove comments right away. */
p = addr;
while ((t = gettoken(&p)) != NULL && t->word[0] != ',')
{
if (t->word[0] == '(' || t->word[0] == ')' || comment)
{
free (t);
if (t->word[0] == '(')
comment++;
if (t->word[0] == ')')
comment--;
continue;
}
if (t->word[0] == '<')
brace = t;
if (tok)
last->next = t;
else
tok = t;
last = t;
}
/* Put extracted address into "buf" */
buf[0] = 0;
t = brace ? brace->next : tok;
for (; t && t->word[0] != ',' && t->word[0] != '>'; t = t->next)
{
if (strlen (t->word) >= bufsz)
return -1;
bufsz -= strlen (t->word);
strcat (buf, t->word);
}
/* Free list of tokens. */
for (t = tok; t; t = last)
{
last = t->next;
free (t);
}
return 0;
}
/* 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 <errno.h>
#include <stdlib.h>
#include <mailutils/iterator.h>
#include <observer0.h>
int
observer_create (observer_t *pobserver, void *owner)
{
observer_t observer;
observer = calloc (sizeof (*observer), 1);
if (observer == NULL)
return ENOMEM;
observer->owner = owner;
*pobserver = observer;
return 0;
}
void
observer_destroy (observer_t *pobserver, void *owner)
{
if (pobserver && *pobserver)
{
observer_t observer = *pobserver;
if (observer->owner == owner || observer->flags & MU_OBSERVER_NO_CHECK)
{
if (observer->_destroy)
observer->_destroy (observer);
free (observer);
}
*pobserver = NULL;
}
}
void *
observer_get_owner (observer_t observer)
{
return (observer) ? observer->owner : NULL;
}
int
observer_action (observer_t observer, size_t type)
{
if (observer == NULL)
return EINVAL;
if (observer->_action)
return observer->_action (observer, type);
return 0;
}
int
observer_set_action (observer_t observer, int (*_action)
__P ((observer_t, size_t)), void *owner)
{
if (observer == NULL)
return EINVAL;
if (observer->owner != owner)
return EACCES;
observer->_action = _action;
return 0;
}
int
observer_set_destroy (observer_t observer, int (*_destroy) __P((observer_t)),
void *owner)
{
if (observer == NULL)
return EINVAL;
if (observer->owner != owner)
return EACCES;
observer->_destroy = _destroy;
return 0;
}
int
observer_set_flags (observer_t observer, int flags)
{
if (observer == NULL)
return EINVAL;
observer->flags |= flags;
return 0;
}
int
observable_create (observable_t *pobservable, void *owner)
{
observable_t observable;
int status;
if (pobservable == NULL)
return EINVAL;
observable = calloc (sizeof (*observable), 1);
if (observable == NULL)
return ENOMEM;
status = list_create (&(observable->list));
if (status != 0 )
{
free (observable);
return status;
}
observable->owner = owner;
*pobservable = observable;
return 0;
}
void
observable_destroy (observable_t *pobservable, void *owner)
{
iterator_t iterator;
if (pobservable && *pobservable)
{
observable_t observable = *pobservable;
if (observable->owner == owner)
{
int status = iterator_create (&iterator, observable->list);
if (status == 0)
{
observer_t observer = NULL;
for (iterator_first (iterator); !iterator_is_done (iterator);
iterator_next (iterator))
{
iterator_current (iterator, (void **)&observer);
if (observer != NULL)
observer_destroy (&observer, NULL);
}
}
list_destroy (&((*pobservable)->list));
free (*pobservable);
}
*pobservable = NULL;
}
}
void *
observable_get_owner (observable_t observable)
{
return (observable) ? observable->owner : NULL;
}
int
observable_attach (observable_t observable, observer_t observer)
{
if (observable == NULL || observer == NULL)
return EINVAL;
return list_append (observable->list, observer);
}
int
observable_detach (observable_t observable, observer_t observer)
{
iterator_t iterator;
int status;
int found = 0;
observer_t current;
if (observable == NULL ||observer == NULL)
return EINVAL;
status = iterator_create (&iterator, observable->list);
if (status != 0)
return status;
for (iterator_first (iterator); !iterator_is_done (iterator);
iterator_next (iterator))
{
iterator_current (iterator, (void **)&current);
if ((int)(current) == (int)observer)
{
found = 1;
break;
}
}
iterator_destroy (&iterator);
return (found) ? list_remove (observable->list, observer) : ENOENT;
}
int
observable_notify (observable_t observable, int type)
{
iterator_t iterator;
observer_t observer = NULL;
int status = 0;
if (observable == NULL)
return EINVAL;
status = iterator_create (&iterator, observable->list);
if (status != 0)
return status;
for (iterator_first (iterator); !iterator_is_done (iterator);
iterator_next (iterator))
{
iterator_current (iterator, (void **)&observer);
if (observer)
{
status |= observer_action (observer, type);
observer = NULL;
}
}
iterator_destroy (&iterator);
return status;
}
......@@ -19,225 +19,73 @@
#include <config.h>
#endif
#include <registrar0.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
/* Builtin mailbox types. A circular list is use for the builtin.
Proper locking is not done when accessing the list.
FIXME: not thread-safe. */
#include <mailutils/iterator.h>
#include <registrar0.h>
static struct _registrar registrar [] =
{
{ NULL, NULL, 0, &registrar[1] }, /* sentinel, head list */
{ &_url_file_registrar, &_mailbox_mbox_registrar, 0, &registrar[2] },
{ &_url_mbox_registrar, &_mailbox_mbox_registrar, 0, &registrar[3] },
{ &_url_unix_registrar, &_mailbox_unix_registrar, 0, &registrar[4] },
{ &_url_maildir_registrar, &_mailbox_maildir_registrar, 0, &registrar[5] },
{ &_url_mmdf_registrar, &_mailbox_mmdf_registrar, 0, &registrar[6] },
{ &_url_pop_registrar, &_mailbox_pop_registrar, 0, &registrar[7] },
{ &_url_imap_registrar, &_mailbox_imap_registrar, 0, &registrar[0] },
};
static void
free_ureg (struct url_registrar *ureg)
{
if (ureg)
{
free ((char *)ureg->scheme);
free (ureg);
}
}
static list_t reg_list;
static void
free_mreg (struct mailbox_registrar *mreg)
int
registrar_get_list (list_t *plist)
{
if (mreg)
if (plist == NULL)
return EINVAL;
if (reg_list == NULL)
{
free ((char *)mreg->name);
free (mreg);
int status = list_create (&reg_list);
if (status != 0)
return status;
}
*plist = reg_list;
return 0;
}
int
registrar_add (struct url_registrar *new_ureg,
struct mailbox_registrar *new_mreg, int *id)
record_is_scheme (record_t record, const char *scheme)
{
struct _registrar *entry;
struct url_registrar *ureg = NULL;
struct mailbox_registrar *mreg;
/* Must registrar a mailbox */
if (new_mreg == NULL)
return EINVAL;
/* Mailbox */
mreg = calloc (1, sizeof (*mreg));
if (mreg == NULL)
return ENOMEM;
if (record == NULL)
return 0;
if (new_mreg->name)
{
mreg->name = strdup (new_mreg->name);
if (mreg->name == NULL)
{
free (mreg);
return ENOMEM;
}
}
mreg->_create = new_mreg->_create;
mreg->_destroy = new_mreg->_destroy;
/* Overload. */
if (record->_is_scheme)
return record->_is_scheme (record, scheme);
/* URL */
if (new_ureg)
{
ureg = calloc (1, sizeof (*ureg));
if (ureg == NULL)
{
free_mreg (mreg);
return ENOMEM;
}
if (new_ureg->scheme)
{
ureg->scheme = strdup (new_ureg->scheme);
if (ureg->scheme == NULL)
{
free_mreg (mreg);
free_ureg (ureg);
return ENOMEM;
}
}
ureg->_create = new_ureg->_create;
ureg->_destroy = new_ureg->_destroy;
}
if (record->scheme && strncasecmp (record->scheme, scheme,
strlen (record->scheme)) == 0)
return 1;
/* Register them to the list */
entry = calloc (1, sizeof (*entry));
if (entry == NULL)
{
free_mreg (mreg);
free_ureg (ureg);
return ENOMEM;
}
entry->ureg = ureg;
entry->mreg = mreg;
entry->is_allocated = 1;
entry->next = registrar->next;
registrar->next = entry;
if (id)
*id = (int)entry;
return 0;
}
int
registrar_remove (int id)
record_get_mailbox (record_t record, mailbox_entry_t *pmbox)
{
struct _registrar *current, *previous;
for (previous = registrar, current = registrar->next;
current != registrar;
previous = current, current = current->next)
{
if ((int)current == id)
{
previous->next = current->next;
if (current->is_allocated)
{
free_ureg (current->ureg);
free_mreg (current->mreg);
}
free (current);
return 0;;
}
}
if (record == NULL)
return EINVAL;
}
int
registrar_get (int id,
struct url_registrar **ureg, struct mailbox_registrar **mreg)
{
struct _registrar *current;
for (current = registrar->next; current != registrar;
current = current->next)
{
if ((int)current == id)
{
if (mreg)
*mreg = current->mreg;
if (ureg)
*ureg = current->ureg;
return 0;
}
}
return EINVAL;
}
/* Overload. */
if (record->_get_mailbox)
return record->_get_mailbox (record, pmbox);
int
registrar_entry_count (size_t *num)
{
struct _registrar *current;
size_t count;
for (count = 0, current = registrar->next; current != registrar;
current = current->next, count++)
;
if (num)
*num = count;
if (pmbox)
*pmbox = record->mailbox;
return 0;
}
int
registrar_entry (size_t num, struct url_registrar **ureg,
struct mailbox_registrar **mreg, int *id)
record_get_mailer (record_t record, mailer_entry_t *pml)
{
struct _registrar *current;
size_t count, status;
for (status = ENOENT, count = 0, current = registrar->next;
current != registrar; current = current->next, count++)
{
if (num == count)
{
if (ureg)
*ureg = current->ureg;
if (mreg)
*mreg = current->mreg;
if (id)
*id = (int)current;
status = 0;
break;
}
}
return status;
}
int
registrar_list (struct url_registrar **ureg, struct mailbox_registrar **mreg,
int *id, registrar_t *reg)
{
struct _registrar *current;
if (reg == NULL)
if (record == NULL)
return EINVAL;
current = *reg;
if (current == NULL)
current = registrar;
if (current->next == registrar)
return -1;
if (ureg)
*ureg = current->ureg;
if (mreg)
*mreg = current->mreg;
if (id)
*id = (int)current;
*reg = current->next;
/* Overload. */
if (record->_get_mailer)
return record->_get_mailer (record, pml);
if (pml)
*pml = record->mailer;
return 0;
}
......
/* 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 <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <mailutils/stream.h>
#include <mailer0.h>
#include <registrar0.h>
#include <misc.h>
static int sendmail_init (mailer_t);
static struct mailer_entry _sendmail_entry =
{
url_sendmail_init, sendmail_init
};
static struct _record _sendmail_record =
{
MU_SENDMAIL_SCHEME,
NULL, /* Mailbox entry. */
&_sendmail_entry, /* Mailer entry. */
0, /* Not malloc()ed. */
NULL, /* No need for an owner. */
NULL, /* is_scheme method. */
NULL, /* get_mailbox method. */
NULL /* get_mailer method. */
};
/* We export two functions: url parsing and the initialisation of
the mailbox, via the register entry/record. */
record_t sendmail_record = &_sendmail_record;
mailer_entry_t sendmail_entry = &_sendmail_entry;
struct _sendmail
{
int dsn;
char *path;
pid_t pid;
off_t offset;
int fd;
enum sendmail_state { SENDMAIL_NO_STATE, SENDMAIL_SEND } state;
};
typedef struct _sendmail * sendmail_t;
static void sendmail_destroy (mailer_t);
static int sendmail_open (mailer_t, int);
static int sendmail_close (mailer_t);
static int sendmail_send_message (mailer_t, const char *from, const char *rcpt,
int dsn, message_t);
int
sendmail_init (mailer_t mailer)
{
sendmail_t sendmail;
/* Allocate memory specific to sendmail mailer. */
sendmail = mailer->data = calloc (1, sizeof (*sendmail));
if (mailer->data == NULL)
return ENOMEM;
sendmail->state = SENDMAIL_NO_STATE;
mailer->_init = sendmail_init;
mailer->_destroy = sendmail_destroy;
mailer->_open = sendmail_open;
mailer->_close = sendmail_close;
mailer->_send_message = sendmail_send_message;
return 0;
}
static void
sendmail_destroy(mailer_t mailer)
{
sendmail_t sendmail = mailer->data;
if (sendmail)
{
if (sendmail->path)
free (sendmail->path);
free (sendmail);
mailer->data = NULL;
}
}
static int
sendmail_open (mailer_t mailer, int flags)
{
sendmail_t sendmail = mailer->data;
int status;
size_t pathlen = 0;
char *path;
/* Sanity checks. */
if (sendmail == NULL)
return EINVAL;
mailer->flags = flags | MU_STREAM_SENDMAIL;
/* Fetch the mailer server name and the port in the url_t. */
if ((status = url_get_path (mailer->url, NULL, 0, &pathlen)) != 0
|| pathlen == 0)
return status;
path = calloc (pathlen + 1, sizeof (char));
url_get_path (mailer->url, path, pathlen + 1, NULL);
if (access (path, X_OK) == -1)
{
free (path);
return errno;
}
sendmail->path = path;
return 0;
}
static int
sendmail_close (mailer_t mailer)
{
(void)mailer;
return 0;
}
static int
sendmail_send_message (mailer_t mailer, const char *from, const char *rcpt,
int dsn, message_t msg)
{
sendmail_t sendmail = mailer->data;
int status = 0;
if (sendmail == NULL || msg == NULL)
return EINVAL;
sendmail->dsn = dsn;
switch (sendmail->state)
{
case SENDMAIL_NO_STATE:
{
int tunnel[2];
int argc = 3;
char **argvec = NULL;
argvec = realloc (argvec, argc * (sizeof (*argvec)));
argvec[0] = sendmail->path;
/* do not treat '.' as message terminator*/
argvec[1] = strdup ("-oi");
argvec[2] = strdup ("-t");
if (from)
{
size_t len = strlen (from) + 1;
char *addr = calloc (len, sizeof (char));
if (parseaddr (from, addr, len) == 0)
{
argc++;
argvec = realloc (argvec, argc * (sizeof (*argvec)));
argvec[argc - 1] = strdup ("-f");
argc++;
argvec = realloc (argvec, argc * (sizeof (*argvec)));
argvec[argc - 1] = addr;
}
else
free (addr);
}
if (rcpt)
{
const char *p = rcpt;
do
{
size_t len = strlen (p) + 1;
char *addr = calloc (len, sizeof (char));
if (parseaddr (rcpt, addr, len) == 0)
{
argc++;
argvec = realloc (argvec, argc * (sizeof (*argvec)));
argvec[argc - 1] = addr;
}
else
free (addr);
p = strchr (p, ',');
if (p != NULL)
p++;
}
while (p != NULL && *p != '\0');
}
argc++;
argvec = realloc (argvec, argc * (sizeof (*argvec)));
argvec[argc - 1] = NULL;
if (pipe (tunnel) == 0)
{
sendmail->fd = tunnel [1];
sendmail->pid = fork ();
if (sendmail->pid == 0) /* Child. */
{
close (STDIN_FILENO);
close (STDOUT_FILENO);
close (STDERR_FILENO);
close (tunnel[1]);
dup2 (tunnel[0], STDIN_FILENO);
execv (sendmail->path, argvec);
exit (1);
}
else if (sendmail->pid == -1)
status = errno;
}
else
status = errno;
for (argc = 0; argvec[argc]; argc++)
free (argvec[argc]);
free (argvec);
close (tunnel[0]);
if (status != 0)
{
close (sendmail->fd);
break;
}
sendmail->state = SENDMAIL_SEND;
}
case SENDMAIL_SEND: /* Parent. */
{
stream_t stream = NULL;
char buffer[512];
size_t len = 0;
int rc;
message_get_stream (msg, &stream);
while ((status = stream_read (stream, buffer, sizeof (buffer),
sendmail->offset, &len)) == 0
&& len != 0)
{
if (write (sendmail->fd, buffer, len) == -1)
{
status = errno;
break;
}
sendmail->offset += len;
}
if (status == EAGAIN)
return status;
close (sendmail->fd);
rc = waitpid(sendmail->pid, &status, 0);
if (rc < 0)
status = errno;
else if (WIFEXITED(status))
status = WEXITSTATUS(status);
}
default:
break;
}
sendmail->state = SENDMAIL_NO_STATE;
return status;
}
/* 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 <sys/types.h>
#include <stdio.h>
#include <pwd.h>
#include <unistd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <mailutils/stream.h>
#include <mailer0.h>
#include <registrar0.h>
#include <bio.h>
#include <misc.h>
static int smtp_init (mailer_t);
static struct mailer_entry _smtp_entry =
{
url_smtp_init, smtp_init
};
static struct _record _smtp_record =
{
MU_SMTP_SCHEME,
NULL, /* Mailbox entry. */
&_smtp_entry, /* Mailer entry. */
0, /* Not malloc()ed. */
NULL, /* No need for an owner. */
NULL, /* is_scheme method. */
NULL, /* get_mailbox method. */
NULL /* get_mailer method. */
};
/* We export two functions: url parsing and the initialisation of
the mailbox, via the register entry/record. */
record_t smtp_record = &_smtp_record;
mailer_entry_t smtp_entry = &_smtp_entry;
struct _smtp
{
char *mailhost;
char *localhost;
bio_t bio;
char *ptr;
char *nl;
char *buffer;
size_t buflen;
enum smtp_state
{
SMTP_NO_STATE, SMTP_OPEN, SMTP_GREETINGS, SMTP_EHLO, SMTP_EHLO_ACK,
SMTP_HELO, SMTP_HELO_ACK, SMTP_QUIT, SMTP_QUIT_ACK, SMTP_ENV_FROM,
SMTP_ENV_RCPT, SMTP_MAIL_FROM, SMTP_MAIL_FROM_ACK, SMTP_RCPT_TO,
SMTP_RCPT_TO_ACK, SMTP_DATA, SMTP_DATA_ACK, SMTP_SEND, SMTP_SEND_ACK,
SMTP_SEND_DOT
} state;
int extended;
char *from;
char *to;
off_t offset;
int dsn;
message_t message;
};
typedef struct _smtp * smtp_t;
/* Usefull little Macros, since these are very repetitive. */
#define CLEAR_STATE(smtp) \
smtp->state = SMTP_NO_STATE
/* Clear the state and close the stream. */
#define CHECK_ERROR_CLOSE(mailer, smtp, status) \
do \
{ \
if (status != 0) \
{ \
stream_close (mailer->stream); \
CLEAR_STATE (smtp); \
return status; \
} \
} \
while (0)
/* Clear the state. */
#define CHECK_ERROR(smtp, status) \
do \
{ \
if (status != 0) \
{ \
CLEAR_STATE (smtp); \
return status; \
} \
} \
while (0)
/* Clear the state for non recoverable error. */
#define CHECK_EAGAIN(smtp, status) \
do \
{ \
if (status != 0) \
{ \
if (status != EAGAIN && status != EINPROGRESS && status != EINTR) \
{ \
CLEAR_STATE (smtp); \
} \
return status; \
} \
} \
while (0)
static void smtp_destroy (mailer_t);
static int smtp_open (mailer_t, int);
static int smtp_close (mailer_t);
static int smtp_send_message (mailer_t, const char *from, const char *rcpt,
int dsn, message_t);
static int smtp_writeline (smtp_t smtp, const char *format, ...);
static int smtp_readline (smtp_t);
static int smtp_read_ack (smtp_t);
static int smtp_write (smtp_t);
int
smtp_init (mailer_t mailer)
{
smtp_t smtp;
/* Allocate memory specific to smtp mailer. */
smtp = mailer->data = calloc (1, sizeof (*smtp));
if (mailer->data == NULL)
return ENOMEM;
mailer->_init = smtp_init;
mailer->_destroy = smtp_destroy;
mailer->_open = smtp_open;
mailer->_close = smtp_close;
mailer->_send_message = smtp_send_message;
return 0;
}
static void
smtp_destroy(mailer_t mailer)
{
smtp_t smtp = mailer->data;
smtp_close (mailer);
if (smtp->mailhost)
free (smtp->mailhost);
if (smtp->localhost)
free (smtp->localhost);
if (smtp->bio)
bio_destroy (&(smtp->bio));
if (smtp->buffer)
free (smtp->buffer);
if (smtp->from)
free (smtp->from);
if (smtp->to)
free (smtp->to);
free (smtp);
mailer->data = NULL;
}
static int
smtp_open (mailer_t mailer, int flags)
{
smtp_t smtp = mailer->data;
int status;
long port;
size_t buf_len = 0;
/* Sanity checks. */
if (smtp == NULL)
return EINVAL;
mailer->flags = flags | MU_STREAM_SMTP;
/* Fetch the mailer server name and the port in the url_t. */
if ((status = url_get_host (mailer->url, NULL, 0, &buf_len)) != 0
|| buf_len == 0 || (status = url_get_port (mailer->url, &port)) != 0)
return status;
switch (smtp->state)
{
case SMTP_NO_STATE:
/* Get the mailhost. */
if (smtp->mailhost)
{
free (smtp->mailhost);
smtp->mailhost = NULL;
}
smtp->mailhost = calloc (buf_len + 1, sizeof (char));
if (smtp->mailhost == NULL)
return ENOMEM;
url_get_host (mailer->url, smtp->mailhost, buf_len + 1, NULL);
if (smtp->localhost)
{
free (smtp->localhost);
smtp->localhost = NULL;
}
/* Fetch our localhost name. */
buf_len = 64;
do
{
char *tmp;
errno = 0;
buf_len *= 2; /* Initial guess */
tmp = realloc (smtp->localhost, buf_len);
if (tmp == NULL)
{
if (smtp->localhost)
free (smtp->localhost);
smtp->localhost = NULL;
free (smtp->mailhost);
smtp->mailhost = NULL;
return ENOMEM;
}
smtp->localhost = tmp;
}
while (((status = gethostname(smtp->localhost, buf_len)) == 0
&& !memchr (smtp->localhost, '\0', buf_len))
#ifdef ENAMETOOLONG
|| errno == ENAMETOOLONG
#endif
);
if (status != 0 && errno != 0)
{
/* gethostname failed, abort. */
free (smtp->localhost);
smtp->localhost = NULL;
free (smtp->mailhost);
smtp->mailhost = NULL;
return EINVAL;
}
/* Many SMTP servers prefer a FQDN. */
if (strchr (smtp->localhost, '.') == NULL)
{
struct hostent *hp = gethostbyname (smtp->localhost);
if (hp == NULL)
{
/* Don't flag it as an error some SMTP servers can get the FQDN
by themselves even if the client is lying, probably
with getpeername(). */
// return EINVAL;
}
else
{
free (smtp->localhost);
smtp->localhost = strdup (hp->h_name);
if (smtp->localhost == NULL)
{
free (smtp->mailhost);
smtp->mailhost = NULL;
return ENOMEM;
}
}
}
/* allocate a working io buffer. */
if (smtp->buffer == NULL)
{
smtp->buflen = 255; /* Initial guess. */
smtp->buffer = malloc (smtp->buflen + 1);
if (smtp->buffer == NULL)
{
CHECK_ERROR (smtp, ENOMEM);
}
smtp->ptr = smtp->buffer;
}
status = bio_create (&(smtp->bio), mailer->stream);
CHECK_ERROR (smtp, status);
/* Create a TCP stack if one is not given. */
if (mailer->stream == NULL)
{
status = tcp_stream_create (&(mailer->stream));
CHECK_ERROR (smtp, status);
}
smtp->state = SMTP_OPEN;
case SMTP_OPEN:
status = stream_open (mailer->stream, smtp->mailhost, port,
mailer->flags);
CHECK_EAGAIN (smtp, status);
smtp->state = SMTP_GREETINGS;
case SMTP_GREETINGS:
/* Swallow the greetings. */
status = smtp_read_ack (smtp);
CHECK_EAGAIN (smtp, status);
if (smtp->buffer[0] != '2')
{
stream_close (mailer->stream);
return EACCES;
}
status = smtp_writeline (smtp, "EHLO %s\r\n", smtp->localhost);
CHECK_ERROR (smtp, status);
smtp->state = SMTP_EHLO;
case SMTP_EHLO:
/* We first try Extended SMTP. */
status = smtp_write (smtp);
CHECK_EAGAIN (smtp, status);
smtp->state = SMTP_EHLO_ACK;
case SMTP_EHLO_ACK:
status = smtp_read_ack (smtp);
CHECK_EAGAIN (smtp, status);
if (smtp->buffer[0] != '2')
{
smtp->extended = 0;
status = smtp_writeline (smtp, "HELO %s\r\n", smtp->localhost);
CHECK_ERROR (smtp, status);
smtp->state = SMTP_HELO;
}
else
{
smtp->extended = 1;
break;
}
case SMTP_HELO:
if (!smtp->extended)
{
status = smtp_write (smtp);
CHECK_EAGAIN (smtp, status);
}
smtp->state = SMTP_HELO_ACK;
case SMTP_HELO_ACK:
if (!smtp->extended)
{
status = smtp_read_ack (smtp);
CHECK_EAGAIN (smtp, status);
if (smtp->buffer[0] != '2')
{
stream_close (mailer->stream);
CLEAR_STATE (smtp);
return EACCES;
}
}
default:
break;
}
smtp->state = SMTP_NO_STATE;
return 0;
}
static int
smtp_close (mailer_t mailer)
{
smtp_t smtp = mailer->data;
int status;
switch (smtp->state)
{
case SMTP_NO_STATE:
status = smtp_writeline (smtp, "Quit\r\n");
CHECK_ERROR (smtp, status);
smtp->state = SMTP_QUIT;
case SMTP_QUIT:
status = smtp_write (smtp);
CHECK_EAGAIN (smtp, status);
smtp->state = SMTP_QUIT_ACK;
case SMTP_QUIT_ACK:
status = smtp_read_ack (smtp);
CHECK_EAGAIN (smtp, status);
default:
break;
}
return stream_close (mailer->stream);
}
static int
smtp_send_message(mailer_t mailer, const char *from, const char *rcpt,
int dsn, message_t msg)
{
smtp_t smtp = mailer->data;
int status;
if (smtp == NULL || msg == NULL)
return EINVAL;
switch (smtp->state)
{
case SMTP_NO_STATE:
smtp->dsn = dsn;
smtp->state = SMTP_ENV_FROM;
case SMTP_ENV_FROM:
if (smtp->from)
{
free (smtp->from);
smtp->from = NULL;
}
/* Try to fetch it from the header. */
if (from == NULL)
{
header_t header;
size_t size;
message_get_header (msg, &header);
status = header_get_value (header, MU_HEADER_FROM, NULL, 0, &size);
if (status == EAGAIN)
return status;
/* If it's not in the header create one form the passwd. */
if (status != 0)
{
struct passwd *pwd = getpwuid (getuid ());
/* Not in the passwd ???? We have a problem. */
if (pwd == 0 || pwd->pw_name == NULL)
{
size_t len = 10 + strlen (smtp->localhost) + 1;
smtp->from = calloc (len, sizeof (char));
if (smtp->from == NULL)
{
CHECK_ERROR (smtp, ENOMEM);
}
snprintf (smtp->from, len, "%d@%s", getuid(),
smtp->localhost);
}
else
{
smtp->from = calloc (strlen (pwd->pw_name) + 1
+ strlen (smtp->localhost) + 1,
sizeof (char));
if (smtp->from == NULL)
{
CHECK_ERROR (smtp, ENOMEM);
}
sprintf(smtp->from, "%s@%s", pwd->pw_name, smtp->localhost);
}
}
else
{
smtp->from = calloc (size + 1, sizeof (char));
if (smtp->from == NULL)
{
CHECK_ERROR (smtp, ENOMEM);
}
status = header_get_value (header, MU_HEADER_FROM, smtp->from,
size + 1, NULL);
CHECK_EAGAIN (smtp, status);
}
}
else
{
smtp->from = strdup (from);
if (smtp->from == NULL)
{
CHECK_ERROR (smtp, ENOMEM);
}
}
/* Check if a Fully Qualified Name, some smtp servers
notably sendmail insists on it, for good reasons. */
if (strchr (smtp->from, '@') == NULL)
{
char *tmp;
tmp = malloc (strlen (smtp->from) + 1 +strlen (smtp->localhost) + 1);
if (tmp == NULL)
{
free (smtp->from);
smtp->from = NULL;
CHECK_ERROR (smtp, ENOMEM);
}
sprintf (tmp, "%s@%s", smtp->from, smtp->localhost);
free (smtp->from);
smtp->from = tmp;
}
smtp->state = SMTP_ENV_RCPT;
case SMTP_ENV_RCPT:
if (smtp->to)
{
free (smtp->to);
smtp->to = NULL;
}
if (rcpt == NULL)
{
header_t header;
size_t size;
message_get_header (msg, &header);
status = header_get_value (header, MU_HEADER_TO, NULL, 0, &size);
CHECK_EAGAIN (smtp, status);
smtp->to = calloc (size + 1, sizeof (char));
if (smtp->to == NULL)
{
CHECK_ERROR (smtp, ENOMEM);
}
status = header_get_value (header, MU_HEADER_TO, smtp->to,
size + 1, NULL);
CHECK_EAGAIN (smtp, status);
}
else
{
smtp->to = strdup (rcpt);
if (smtp->to == NULL)
{
CHECK_ERROR (smtp, ENOMEM);
}
}
status = smtp_writeline (smtp, "MAIL FROM: %s\r\n", smtp->from);
free (smtp->from);
smtp->from = NULL;
CHECK_ERROR (smtp, status);
smtp->state = SMTP_MAIL_FROM;
case SMTP_MAIL_FROM:
status = smtp_write (smtp);
CHECK_EAGAIN (smtp, status);
smtp->state = SMTP_MAIL_FROM_ACK;
case SMTP_MAIL_FROM_ACK:
status = smtp_read_ack (smtp);
CHECK_EAGAIN (smtp, status);
if (smtp->buffer[0] != '2')
{
stream_close (mailer->stream);
CLEAR_STATE (smtp);
return EACCES;
}
/* We use a goto, since we may have multiple recipients,
we come back here and doit all over again ... Not pretty. */
RCPT_TO:
{
char *buf;
size_t len = strlen (smtp->to) + 1;
buf = calloc (len, sizeof (char));
if (buf == NULL)
{
CHECK_ERROR (smtp, ENOMEM);
}
if (parseaddr (smtp->to, buf, len) != 0)
{
free (buf);
CHECK_ERROR (smtp, EINVAL);
}
status = smtp_writeline (smtp, "RCPT TO: %s\r\n", buf);
free (buf);
CHECK_ERROR (smtp, status);
smtp->state = SMTP_RCPT_TO;
}
case SMTP_RCPT_TO:
status = smtp_write (smtp);
CHECK_EAGAIN (smtp, status);
smtp->state = SMTP_RCPT_TO_ACK;
case SMTP_RCPT_TO_ACK:
{
char *p;
status = smtp_read_ack (smtp);
CHECK_EAGAIN (smtp, status);
if (smtp->buffer[0] != '2')
{
stream_close (mailer->stream);
CLEAR_STATE (smtp);
return EACCES;
}
/* Do we have multiple recipients ? */
p = strchr (smtp->to, ',');
if (p != NULL)
{
char *tmp = smtp->to;
smtp->to = strdup (p++);
if (smtp->to == NULL)
{
free (tmp);
CHECK_ERROR (smtp, ENOMEM);
}
free (tmp);
goto RCPT_TO;
}
/* We are done with the rcpt. */
free (smtp->to);
smtp->to = NULL;
status = smtp_writeline (smtp, "DATA\r\n");
CHECK_ERROR (smtp, status);
smtp->state = SMTP_DATA;
}
case SMTP_DATA:
status = smtp_write (smtp);
CHECK_EAGAIN (smtp, status);
smtp->state = SMTP_DATA_ACK;
case SMTP_DATA_ACK:
status = smtp_read_ack (smtp);
CHECK_EAGAIN (smtp, status);
if (smtp->buffer[0] != '3')
{
stream_close (mailer->stream);
CLEAR_STATE (smtp);
return EACCES;
}
smtp->offset = 0;
smtp->state = SMTP_SEND;
case SMTP_SEND:
{
stream_t stream;
size_t n = 0;
char data[256] = "";
/* We may be here after an EAGAIN so check if we have something
in the buffer and flush it. */
status = smtp_write (smtp);
CHECK_EAGAIN (smtp, status);
message_get_stream (msg, &stream);
while ((status = stream_readline (stream, data, sizeof (data) - 1,
smtp->offset, &n)) == 0 && n > 0)
{
if (data [n - 1] == '\n')
data [n -1] = '\0';
if (data[0] == '.')
{
status = smtp_writeline (smtp, ".%s\r\n", data);
CHECK_ERROR (smtp, status);
}
else
{
status = smtp_writeline (smtp, "%s\r\n", data);
CHECK_ERROR (smtp, status);
}
smtp->offset += n;
status = smtp_write (smtp);
CHECK_EAGAIN (smtp, status);
}
smtp->offset = 0;
status = smtp_writeline (smtp, ".\r\n");
CHECK_ERROR (smtp, status);
smtp->state = SMTP_SEND_DOT;
}
case SMTP_SEND_DOT:
status = smtp_write (smtp);
CHECK_EAGAIN (smtp, status);
smtp->state = SMTP_SEND_ACK;
case SMTP_SEND_ACK:
status = smtp_read_ack (smtp);
CHECK_EAGAIN (smtp, status);
if (smtp->buffer[0] != '2')
{
stream_close (mailer->stream);
CLEAR_STATE (smtp);
return EACCES;
}
default:
break;
}
CLEAR_STATE (smtp);
return 0;
}
static int
smtp_writeline (smtp_t smtp, const char *format, ...)
{
int len;
va_list ap;
va_start(ap, format);
do
{
len = vsnprintf (smtp->buffer, smtp->buflen - 1, format, ap);
if (len >= (int)smtp->buflen)
{
smtp->buflen *= 2;
smtp->buffer = realloc (smtp->buffer, smtp->buflen);
if (smtp->buffer == NULL)
return ENOMEM;
}
}
while (len > (int)smtp->buflen);
va_end(ap);
smtp->ptr = smtp->buffer + len;
return 0;
}
static int
smtp_write (smtp_t smtp)
{
int status = 0;
size_t len;
if (smtp->ptr > smtp->buffer)
{
len = smtp->ptr - smtp->buffer;
status = bio_write (smtp->bio, smtp->buffer, len, &len);
if (status == 0)
{
memmove (smtp->buffer, smtp->buffer + len, len);
smtp->ptr -= len;
}
}
else
{
smtp->ptr = smtp->buffer;
len = 0;
}
return status;
}
static int
smtp_read_ack (smtp_t smtp)
{
int status;
int multi;
do
{
multi = 0;
status = smtp_readline (smtp);
if ((smtp->ptr - smtp->buffer) > 4
&& smtp->buffer[3] == '-')
multi = 1;
if (status == 0)
smtp->ptr = smtp->buffer;
}
while (multi && status == 0);
if (status == 0)
smtp->ptr = smtp->buffer;
return status;
}
/* Read a complete line form the pop server. Transform CRLF to LF,
put a null in the buffer when done. */
static int
smtp_readline (smtp_t smtp)
{
size_t n = 0;
size_t total = smtp->ptr - smtp->buffer;
int status;
/* Must get a full line before bailing out. */
do
{
status = bio_readline (smtp->bio, smtp->buffer + total,
smtp->buflen - total, &n);
if (status != 0)
return status;
total += n;
smtp->nl = memchr (smtp->buffer, '\n', total);
if (smtp->nl == NULL) /* Do we have a full line. */
{
/* Allocate a bigger buffer ? */
if (total >= smtp->buflen -1)
{
smtp->buflen *= 2;
smtp->buffer = realloc (smtp->buffer, smtp->buflen + 1);
if (smtp->buffer == NULL)
return ENOMEM;
}
}
smtp->ptr = smtp->buffer + total;
}
while (smtp->nl == NULL);
/* \r\n --> \n\0 */
if (smtp->nl > smtp->buffer)
{
*(smtp->nl - 1) = '\n';
*(smtp->nl) = '\0';
smtp->ptr = smtp->nl;
}
return 0;
}
......@@ -15,6 +15,10 @@
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 <stdio.h>
......@@ -65,6 +69,13 @@ stream_set_destroy (stream_t stream, void (*_destroy) (stream_t), void *owner)
return 0;
}
void *
stream_get_owner (stream_t stream)
{
return (stream) ? stream->owner : NULL;
}
int
stream_open (stream_t stream, const char *name, int port, int flags)
{
......@@ -253,13 +264,11 @@ stream_get_flags (stream_t stream, int *pfl)
}
int
stream_set_flags (stream_t stream, int fl, void *owner)
stream_set_flags (stream_t stream, int fl)
{
if (stream == NULL)
return EINVAL;
if (stream->owner != owner)
return EACCES;
stream->flags = fl;
stream->flags |= fl;
return 0;
}
......
......@@ -15,6 +15,10 @@
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 <stdlib.h>
#include <stdio.h>
#include <errno.h>
......@@ -27,12 +31,12 @@
#include <arpa/inet.h>
#include <unistd.h>
#include <stream0.h>
#include <mailutils/stream.h>
#include <tcp0.h>
static int _tcp_close(stream_t stream)
{
struct _tcp_instance *tcp = stream->owner;
struct _tcp_instance *tcp = stream_get_owner(stream);
if ( tcp->fd != -1 )
close(tcp->fd);
......@@ -43,7 +47,7 @@ static int _tcp_close(stream_t stream)
static int _tcp_open(stream_t stream, const char *host, int port, int flags)
{
struct _tcp_instance *tcp = stream->owner;
struct _tcp_instance *tcp = stream_get_owner(stream);
int flgs, ret;
size_t namelen;
struct sockaddr_in peer_addr;
......@@ -66,7 +70,7 @@ static int _tcp_open(stream_t stream, const char *host, int port, int flags)
flgs = fcntl(tcp->fd, F_GETFL);
flgs |= O_NONBLOCK;
fcntl(tcp->fd, F_SETFL, flgs);
stream->flags |= MU_STREAM_NONBLOCK;
stream_set_flags (stream, MU_STREAM_NONBLOCK);
}
tcp->state = TCP_STATE_RESOLVING;
case TCP_STATE_RESOLVING:
......@@ -115,7 +119,7 @@ static int _tcp_open(stream_t stream, const char *host, int port, int flags)
static int _tcp_get_fd(stream_t stream, int *fd)
{
struct _tcp_instance *tcp = stream->owner;
struct _tcp_instance *tcp = stream_get_owner(stream);
if ( fd == NULL || tcp->fd == EINVAL )
return EINVAL;
......@@ -126,7 +130,7 @@ static int _tcp_get_fd(stream_t stream, int *fd)
static int _tcp_read(stream_t stream, char *buf, size_t buf_size, off_t offset, size_t *br)
{
struct _tcp_instance *tcp = stream->owner;
struct _tcp_instance *tcp = stream_get_owner(stream);
int bytes;
offset = offset;
......@@ -143,7 +147,7 @@ static int _tcp_read(stream_t stream, char *buf, size_t buf_size, off_t offset,
static int _tcp_write(stream_t stream, const char *buf, size_t buf_size, off_t offset, size_t *bw)
{
struct _tcp_instance *tcp = stream->owner;
struct _tcp_instance *tcp = stream_get_owner(stream);
int bytes;
offset = offset;
......@@ -160,7 +164,7 @@ static int _tcp_write(stream_t stream, const char *buf, size_t buf_size, off_t o
static void _tcp_destroy(stream_t stream)
{
struct _tcp_instance *tcp = stream->owner;
struct _tcp_instance *tcp = stream_get_owner(stream);
if ( tcp->host )
free(tcp->host);
......
......@@ -15,13 +15,16 @@
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stream0.h>
#include <mailutils/stream.h>
struct _ts_desc {
const char *encoding;
......@@ -54,7 +57,7 @@ struct _ts_desc tslist[NUM_TRANSCODERS] = { { "base64", _base64_decode,
static void _trans_destroy(stream_t stream)
{
struct _trans_stream *ts = stream->owner;
struct _trans_stream *ts = stream_get_owner(stream);
stream_destroy(&(ts->stream), NULL);
if ( ts->leftover )
......@@ -64,7 +67,7 @@ static void _trans_destroy(stream_t stream)
static int _trans_read(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nbytes)
{
struct _trans_stream *ts = stream->owner;
struct _trans_stream *ts = stream_get_owner(stream);
size_t isize = osize;
char *iptr;
int consumed, ret;
......@@ -100,7 +103,7 @@ static int _trans_read(stream_t stream, char *optr, size_t osize, off_t offset,
static int _trans_write(stream_t stream, const char *iptr, size_t isize, off_t offset, size_t *nbytes)
{
struct _trans_stream *ts = stream->owner;
struct _trans_stream *ts = stream_get_owner(stream);
size_t osize = isize;
char *optr;
int ret;
......
......@@ -15,13 +15,16 @@
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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <steam0.h>
#include <mailutils/sys/steam0.h>
#include <mailutils/transcode.h>
int _base64_decode(stream_t stream, char *optr, size_t osize, off_t offset, size_t *nbytes);
......
......@@ -19,98 +19,23 @@
# include <config.h>
#endif
#include <url0.h>
#include <registrar0.h>
#include <cpystr.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
/* Forward prototypes */
static int get_scheme (const url_t, char *, size_t, size_t *);
static int get_user (const url_t, char *, size_t, size_t *);
static int get_passwd (const url_t, char *, size_t, size_t *);
static int get_host (const url_t, char *, size_t, size_t *);
static int get_port (const url_t, long *);
static int get_path (const url_t, char *, size_t, size_t *);
static int get_query (const url_t, char *, size_t, size_t *);
static int get_id (const url_t, int *);
#include <mailutils/registrar.h>
#include <misc.h>
#include <url0.h>
int
url_create (url_t * purl, const char *name)
url_create (url_t *purl, const char *name)
{
int status = EINVAL;
struct url_registrar *ureg;
struct mailbox_registrar *mreg;
size_t name_len;
int id;
size_t i, entry_count = 0;
/* Sanity checks */
if (name == NULL || *name == '\0')
return status;
name_len = strlen (name);
/* Search for a known scheme */
registrar_entry_count (&entry_count);
for (i = 0; i < entry_count; i++)
{
if (registrar_entry (i, &ureg, &mreg, &id) == 0)
{
size_t scheme_len;
if (ureg && ureg->scheme &&
name_len > (scheme_len = strlen (ureg->scheme)) &&
memcmp (name, ureg->scheme, scheme_len) == 0)
{
status = 0;
break;
}
}
}
/*
while (registrar_list (&ureg, &mreg, &id, &reg) == 0)
{
size_t scheme_len;
if (ureg && ureg->scheme &&
name_len > (scheme_len = strlen (ureg->scheme)) &&
memcmp (name, ureg->scheme, scheme_len) == 0)
{
status = 0;
break;
}
}
*/
/* Found one initialize it */
if (status == 0)
{
status = ureg->_create (purl, name);
if (status == 0)
{
url_t url = *purl;
url->id = id;
if (url->_get_id == NULL)
url->_get_id = get_id;
if (url->_get_scheme == NULL)
url->_get_scheme = get_scheme;
if (url->_get_user == NULL)
url->_get_user = get_user;
if (url->_get_passwd == NULL)
url->_get_passwd = get_passwd;
if (url->_get_host == NULL)
url->_get_host = get_host;
if (url->_get_port == NULL)
url->_get_port = get_port;
if (url->_get_path == NULL)
url->_get_path = get_path;
if (url->_get_query == NULL)
url->_get_query = get_query;
}
}
return status;
url_t url = calloc(1, sizeof (*url));
if (url == NULL)
return ENOMEM;
url->name = strdup (name);
*purl = url;
return 0;
}
void
......@@ -118,142 +43,144 @@ url_destroy (url_t *purl)
{
if (purl && *purl)
{
struct url_registrar *ureg;
int id;
url_get_id (*purl, &id);
registrar_get (id, &ureg, NULL);
ureg->_destroy(purl);
(*purl) = NULL;
}
}
url_t url = (*purl);
if (url->_destroy)
url->_destroy (url);
int (url_get_scheme) (const url_t url, char *scheme, size_t len, size_t *n)
{
return (url) ? url->_get_scheme(url, scheme, len, n) : EINVAL;
}
int (url_get_user) (const url_t url, char *user, size_t len, size_t *n)
{
return (url) ? url->_get_user(url, user, len, n) : EINVAL;
}
if (url->name)
free (url->name);
int (url_get_passwd) (const url_t url, char *passwd, size_t len, size_t *n)
{
return (url) ? url->_get_passwd(url, passwd, len, n) : EINVAL;
}
if (url->scheme)
free (url->scheme);
int (url_get_host) (const url_t url, char *host, size_t len, size_t *n)
{
return (url) ? url->_get_host(url, host, len, n) : EINVAL;
}
if (url->user)
free (url->user);
int (url_get_port) (const url_t url, long *port)
{
return (url) ? url->_get_port(url, port) : EINVAL;
}
if (url->passwd)
free (url->passwd);
int (url_get_path) (const url_t url, char *path, size_t len, size_t *n)
{
return (url) ? url->_get_path(url, path, len, n) : EINVAL;
}
if (url->host)
free (url->host);
int (url_get_query) (const url_t url, char *query, size_t len, size_t *n)
{
return (url) ? url->_get_query(url, query, len, n) : EINVAL;
*purl = NULL;
}
}
int (url_get_id) (const url_t url, int *id)
int
url_get_scheme (const url_t url, char *scheme, size_t len, size_t *n)
{
return (url) ? url->_get_id (url, id) : EINVAL;
size_t i;
if (url == NULL)
return EINVAL;
if (url->_get_scheme)
return url->_get_scheme (url, scheme, len, n);
i = _cpystr (scheme, url->scheme, len);
if (n)
*n = i;
return 0;
}
/* Simple stub functions they all call _cpystr */
static int
get_scheme (const url_t u, char *s, size_t len, size_t *n)
int
url_get_user (const url_t url, char *user, size_t len, size_t *n)
{
size_t i;
if (u == NULL)
if (url == NULL)
return EINVAL;
i = _cpystr (s, u->scheme, len);
if (url->_get_user)
return url->_get_user (url, user, len, n);
i = _cpystr (user, url->user, len);
if (n)
*n = i;
return 0;
}
static int
get_user (const url_t u, char *s, size_t len, size_t *n)
/* FIXME: We should not store passwd in clear, but rather
have a simple encoding, and decoding mechanism */
int
url_get_passwd (const url_t url, char *passwd, size_t len, size_t *n)
{
size_t i;
if (u == NULL)
if (url == NULL)
return EINVAL;
i = _cpystr (s, u->user, len);
if (url->_get_passwd)
return url->_get_passwd (url, passwd, len, n);
i = _cpystr (passwd, url->passwd, len);
if (n)
*n = i;
return 0;
}
/* FIXME: We should not store passwd in clear, but rather
have a simple encoding, and decoding mechanism */
static int
get_passwd (const url_t u, char *s, size_t len, size_t *n)
int
url_get_auth (const url_t url, char *auth, size_t len, size_t *n)
{
size_t i;
if (u == NULL)
if (url == NULL)
return EINVAL;
i = _cpystr (s, u->passwd, len);
if (url->_get_auth)
return url->_get_auth (url, auth, len, n);
i = _cpystr (auth, url->auth, len);
if (n)
*n = i;
return 0;
}
static int
get_host (const url_t u, char *s, size_t len, size_t *n)
int
url_get_host (const url_t url, char *host, size_t len, size_t *n)
{
size_t i;
if (u == NULL)
if (url == NULL)
return EINVAL;
i = _cpystr (s, u->host, len);
if (url->_get_host)
return url->_get_host (url, host, len, n);
i = _cpystr (host, url->host, len);
if (n)
*n = i;
return 0;
}
static int
get_port (const url_t u, long * p)
int
url_get_port (const url_t url, long *pport)
{
*p = u->port;
if (url == NULL)
return EINVAL;
if (url->_get_port)
return url->_get_port (url, pport);
*pport = url->port;
return 0;
}
static int
get_path (const url_t u, char *s, size_t len, size_t *n)
int
url_get_path (const url_t url, char *path, size_t len, size_t *n)
{
size_t i;
if (u == NULL)
if (url == NULL)
return EINVAL;
i = _cpystr(s, u->path, len);
if (url->_get_path)
return url->_get_path (url, path, len, n);
i = _cpystr(path, url->path, len);
if (n)
*n = i;
return 0;
}
static int
get_query (const url_t u, char *s, size_t len, size_t *n)
int
url_get_query (const url_t url, char *query, size_t len, size_t *n)
{
size_t i;
if (u == NULL)
if (url == NULL)
return EINVAL;
i = _cpystr(s, u->query, len);
if (url->_get_query)
return url->_get_query (url, query, len, n);
i = _cpystr(query, url->query, len);
if (n)
*n = i;
return 0;
}
static int
get_id (const url_t u, int *id)
const char *
url_to_string (const url_t url)
{
if (id)
*id = u->id;
return 0;
if (url == NULL || url->name == NULL)
return "";
return url->name;
}
......
......@@ -15,74 +15,63 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <url0.h>
#include <registrar0.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
static void url_file_destroy (url_t *purl);
static int url_file_create (url_t *purl, const char *name);
#include <mailutils/registrar.h>
#include <url0.h>
struct url_registrar _url_file_registrar =
{
"file:",
url_file_create, url_file_destroy
};
int url_file_init (url_t purl);
static void url_file_destroy (url_t purl);
static void
url_file_destroy (url_t *purl)
url_file_destroy (url_t url)
{
if (purl && *purl)
{
url_t url = *purl;
free (url->scheme);
free (url->path);
free (url);
*purl = NULL;
}
(void) url;
}
/*
UNIX box
UNIX File
file:path
*/
static int
url_file_create (url_t *purl, const char *name)
int
url_file_init (url_t url)
{
url_t url;
struct url_registrar *ureg = &_url_mbox_registrar;
const char *name = url_to_string (url);
size_t len = strlen (name);
/* reject the obvious */
if (name == NULL || *name == '\0')
if (name == NULL || strncmp (MU_FILE_SCHEME, name, MU_FILE_SCHEME_LEN) != 0
|| len < (MU_FILE_SCHEME_LEN + 1) /* (scheme)+1(path)*/)
return EINVAL;
/* FIXME: do I need to decode url encoding '% hex hex' ? */
url = calloc(1, sizeof (*url));
if (url == NULL)
return ENOMEM;
/* do I need to decode url encoding '% hex hex' ? */
/* TYPE */
url->_create = ureg->_create;
url->_destroy = ureg->_destroy;
url->_init = url_file_init;
url->_destroy = url_file_destroy;
/* SCHEME */
url->scheme = strdup (ureg->scheme);
url->scheme = strdup (MU_FILE_SCHEME);
if (url->scheme == NULL)
{
ureg->_destroy (&url);
url_file_destroy (url);
return ENOMEM;
}
/* PATH */
name += MU_FILE_SCHEME_LEN; /* pass the scheme */
url->path = strdup (name);
if (url->path == NULL)
{
ureg->_destroy (&url);
url_file_destroy (url);
return ENOMEM;
}
*purl = url;
return 0;
}
......
......@@ -15,74 +15,63 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <url0.h>
#include <mailutils/registrar.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
static void url_mbox_destroy (url_t *purl);
static int url_mbox_create (url_t *purl, const char *name);
#include <mailutils/registrar.h>
#include <url0.h>
struct url_registrar _url_mbox_registrar =
{
"/",
url_mbox_create, url_mbox_destroy
};
int url_mbox_init (url_t purl);
static void url_mbox_destroy (url_t purl);
static void
url_mbox_destroy (url_t *purl)
url_mbox_destroy (url_t url)
{
if (purl && *purl)
{
url_t url = *purl;
free (url->scheme);
free (url->path);
free (url);
*purl = NULL;
}
(void) url;
}
/*
UNIX box
UNIX Mbox
mbox:path
*/
static int
url_mbox_create (url_t *purl, const char *name)
int
url_mbox_init (url_t url)
{
url_t url;
struct url_registrar *ureg = &_url_mbox_registrar;
const char *name = url_to_string (url);
size_t len = strlen (name);
/* reject the obvious */
if (name == NULL || *name == '\0')
if (name == NULL || strncmp (MU_MBOX_SCHEME, name, MU_MBOX_SCHEME_LEN) != 0
|| len < (MU_MBOX_SCHEME_LEN + 1) /* (scheme)+1(path)*/)
return EINVAL;
/* FIXME: do I need to decode url encoding '% hex hex' ? */
url = calloc(1, sizeof (*url));
if (url == NULL)
return ENOMEM;
/* do I need to decode url encoding '% hex hex' ? */
/* TYPE */
url->_create = ureg->_create;
url->_destroy = ureg->_destroy;
url->_init = url_mbox_init;
url->_destroy = url_mbox_destroy;
/* SCHEME */
url->scheme = strdup (ureg->scheme);
url->scheme = strdup (MU_MBOX_SCHEME);
if (url->scheme == NULL)
{
ureg->_destroy (&url);
url_mbox_destroy (url);
return ENOMEM;
}
/* PATH */
name += MU_MBOX_SCHEME_LEN; /* pass the scheme */
url->path = strdup (name);
if (url->path == NULL)
{
ureg->_destroy (&url);
url_mbox_destroy (url);
return ENOMEM;
}
*purl = url;
return 0;
}
......
/* 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 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 <string.h>
#include <mailutils/registrar.h>
#include <url0.h>
static void url_path_destroy (url_t);
int url_path_init (url_t);
static void
url_path_destroy (url_t url)
{
(void)url;
}
int
url_path_init (url_t url)
{
const char *name = url_to_string (url);
/* reject the obvious */
if (name == NULL || *name == '\0')
return EINVAL;
/* FIXME: do I need to decode url encoding '% hex hex' ? */
/* TYPE */
url->_init = url_path_init;
url->_destroy = url_path_destroy;
/* SCHEME */
url->scheme = strdup (MU_PATH_SCHEME);
if (url->scheme == NULL)
{
url_path_destroy (url);
return ENOMEM;
}
/* PATH */
url->path = strdup (name);
if (url->path == NULL)
{
url_path_destroy (url);
return ENOMEM;
}
return 0;
}
......@@ -15,73 +15,55 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <url0.h>
#include <mailutils/registrar.h>
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
static void url_pop_destroy (url_t *purl);
static int url_pop_create (url_t *purl, const char *name);
#include <mailutils/registrar.h>
#include <url0.h>
struct url_registrar _url_pop_registrar =
{
"pop://",
url_pop_create, url_pop_destroy
};
static void url_pop_destroy (url_t url);
static void
url_pop_destroy (url_t *purl)
url_pop_destroy (url_t url)
{
if (purl && *purl)
{
url_t url = *purl;
free (url->scheme);
free (url->user);
free (url->passwd);
free (url->host);
free (url);
*purl = NULL;
}
(void)url;
}
/*
POP URL
pop://[<user>;AUTH=<auth>@]<host>[:<port>]
*/
static int
url_pop_create (url_t *purl, const char *name)
int
url_pop_init (url_t url)
{
const char *host_port, *indexe;
struct url_registrar *ureg = &_url_pop_registrar;
size_t scheme_len = strlen (ureg->scheme);
url_t url;
char *name = url->name;
/* reject the obvious */
if (name == NULL || strncmp (ureg->scheme, name, scheme_len) != 0)
if (name == NULL || strncmp (MU_POP_SCHEME, name, MU_POP_SCHEME_LEN) != 0)
return EINVAL;
/* do I need to decode url encoding '% hex hex' ? */
url = calloc(1, sizeof (*url));
if (url == NULL)
return ENOMEM;
/* TYPE */
url->_create = _url_pop_registrar._create;
url->_destroy = _url_pop_registrar._destroy;
url->_init = url_pop_init;
url->_destroy = url_pop_destroy;
/* SCHEME */
url->scheme = strdup ("pop://");
url->scheme = strdup (MU_POP_SCHEME);
if (url->scheme == NULL)
{
url_pop_destroy (&url);
url_pop_destroy (url);
return ENOMEM;
}
name += scheme_len; /* pass the scheme */
name += MU_POP_SCHEME_LEN; /* pass the scheme */
host_port = strchr (name, '@');
if (host_port == NULL)
......@@ -103,7 +85,7 @@ url_pop_create (url_t *purl, const char *name)
url->user = malloc(indexe - name + 1);
if (url->user == NULL)
{
url_pop_destroy (&url);
url_pop_destroy (url);
return -1;
}
((char *)memcpy(url->user, name, indexe - name))[indexe - name] = '\0';
......@@ -112,28 +94,28 @@ url_pop_create (url_t *purl, const char *name)
if (indexe == host_port)
{
/* Use default AUTH '*' */
url->passwd = malloc (1 + 1);
if (url->passwd)
url->auth = malloc (1 + 1);
if (url->auth)
{
url->passwd[0] = '*';
url->passwd[1] = '\0';
url->auth[0] = '*';
url->auth[1] = '\0';
}
}
else
{
/* move pass AUTH= */
indexe += 6;
url->passwd = malloc (host_port - indexe + 1);
if (url->passwd)
url->auth = malloc (host_port - indexe + 1);
if (url->auth)
{
((char *)memcpy (url->passwd, indexe, host_port - indexe))
((char *)memcpy (url->auth, indexe, host_port - indexe))
[host_port - indexe] = '\0';
}
}
if (url->passwd == NULL)
if (url->auth == NULL)
{
url_pop_destroy (&url);
url_pop_destroy (url);
return -1;
}
......@@ -161,7 +143,7 @@ url_pop_create (url_t *purl, const char *name)
if (url->host == NULL)
{
url_pop_destroy (&url);
url_pop_destroy (url);
return ENOMEM;
}
else
......@@ -172,6 +154,5 @@ url_pop_create (url_t *purl, const char *name)
url->host[len - 1] = '\0'; /* leak a bit */
}
*purl = url;
return 0;
}
......
/* 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 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 <string.h>
#include <mailutils/registrar.h>
#include <url0.h>
int url_sendmail_init (url_t purl);
static void url_sendmail_destroy (url_t purl);
static void
url_sendmail_destroy (url_t url)
{
(void) url;
}
/*
UNIX Sendmail
sendmail:path
*/
int
url_sendmail_init (url_t url)
{
const char *name = url_to_string (url);
size_t len = strlen (name);
/* reject the obvious */
if (name == NULL || strncmp (MU_SENDMAIL_SCHEME, name, MU_SENDMAIL_SCHEME_LEN) != 0
|| len < (MU_SENDMAIL_SCHEME_LEN + 1) /* (scheme)+1(path)*/)
return EINVAL;
/* do I need to decode url encoding '% hex hex' ? */
/* TYPE */
url->_init = url_sendmail_init;
url->_destroy = url_sendmail_destroy;
/* SCHEME */
url->scheme = strdup (MU_SENDMAIL_SCHEME);
if (url->scheme == NULL)
{
url_sendmail_destroy (url);
return ENOMEM;
}
/* PATH */
name += MU_SENDMAIL_SCHEME_LEN; /* pass the scheme */
url->path = strdup (name);
if (url->path == NULL)
{
url_sendmail_destroy (url);
return ENOMEM;
}
return 0;
}
/* 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 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 <string.h>
#include <mailutils/registrar.h>
#include <url0.h>
int url_smtp_init (url_t purl);
static void url_smtp_destroy (url_t purl);
static void
url_smtp_destroy (url_t url)
{
(void) url;
}
/*
UNIX File
file:path
*/
int
url_smtp_init (url_t url)
{
const char *name = url_to_string (url);
size_t len = strlen (name);
/* reject the obvious */
if (name == NULL || strncmp (MU_SMTP_SCHEME, name, MU_SMTP_SCHEME_LEN) != 0
|| len < (MU_SMTP_SCHEME_LEN + 1) /* (scheme)+1(path)*/)
return EINVAL;
/* do I need to decode url encoding '% hex hex' ? */
/* TYPE */
url->_init = url_smtp_init;
url->_destroy = url_smtp_destroy;
/* SCHEME */
url->scheme = strdup (MU_SMTP_SCHEME);
if (url->scheme == NULL)
{
url_smtp_destroy (url);
return ENOMEM;
}
/* PATH */
name += MU_SMTP_SCHEME_LEN; /* pass the scheme */
url->host = strdup (name);
if (url->host == NULL)
{
url_smtp_destroy (url);
return ENOMEM;
}
url->port = MU_SMTP_PORT;
return 0;
}