Commit 3770cdc7 3770cdc780567a2d6a37a8d1b45ea96c7a5d6938 by Alain Magloire

Support for IMAP, buffering internal scheme for stream_t

1 parent b40ad529
......@@ -21,6 +21,7 @@ debug.c \
envelope.c \
file_stream.c \
folder.c \
folder_imap.c \
folder_mbox.c \
folder_pop.c \
header.c \
......@@ -32,6 +33,7 @@ mailer.c \
mapfile_stream.c \
mbx_default.c \
mbx_file.c \
mbx_imap.c \
mbx_mbox.c \
mbx_pop.c \
message.c \
......
......@@ -16,12 +16,14 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#include <config.h>
#endif
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <mailutils/message.h>
#include <mailutils/stream.h>
......@@ -39,38 +41,43 @@ struct _msg_info {
message_t msg;
int ioffset;
int ooffset;
char line[MAX_HDR_LEN];
int line_ndx;
stream_t ostream; // output file/decoding stream for saving attachment
};
#define MSG_HDR "Content-Type: %s\nContent-Transfer-Encoding: %s\n\n"
#define MSG_HDR "Content-Type: %s; name=%s\nContent-Transfer-Encoding: %s\nContent-Disposition: attachment; filename=%s\n\n"
int message_create_attachment(const char *content_type, const char *encoding, const char *filename, message_t *newmsg)
{
header_t hdr;
body_t body;
stream_t fstream = NULL, tstream = NULL;
char *header;
char *header, *name = NULL, *fname = NULL;
int ret;
if ( filename == NULL || newmsg == NULL )
return EINVAL;
if ( ( ret = message_create(newmsg, NULL) ) == 0 ) {
if ( content_type == NULL )
content_type = "text/plain";
if ( encoding == NULL )
encoding = "7bit";
if ( ( header = alloca(strlen(MSG_HDR) + strlen(content_type) + strlen(encoding)) ) == NULL )
ret = ENOMEM;
else {
sprintf(header, MSG_HDR, content_type, encoding);
if ( ( ret = header_create( &hdr, header, strlen(header), *newmsg ) ) == 0 ) {
message_get_body(*newmsg, &body);
if ( ( ret = file_stream_create(&fstream) ) == 0 ) {
if ( ( ret = stream_open(fstream, filename, 0, MU_STREAM_READ) ) == 0 ) {
if ( ( ret = encoder_stream_create(&tstream, fstream, encoding) ) == 0 ) {
body_set_stream(body, tstream, *newmsg);
message_set_header(*newmsg, hdr, NULL);
if ( ( fname = strdup(filename) ) != NULL ) {
name = basename(fname);
if ( ( header = alloca(strlen(MSG_HDR) + strlen(content_type) + strlen(name) * 2 + strlen(encoding) + 1) ) == NULL )
ret = ENOMEM;
else {
sprintf(header, MSG_HDR, content_type, name, encoding, name);
if ( ( ret = header_create( &hdr, header, strlen(header), *newmsg ) ) == 0 ) {
message_get_body(*newmsg, &body);
if ( ( ret = file_stream_create(&fstream) ) == 0 ) {
if ( ( ret = stream_open(fstream, filename, 0, MU_STREAM_READ) ) == 0 ) {
if ( ( ret = encoder_stream_create(&tstream, fstream, encoding) ) == 0 ) {
body_set_stream(body, tstream, *newmsg);
message_set_header(*newmsg, hdr, NULL);
}
}
}
}
}
}
}
......@@ -82,6 +89,8 @@ int message_create_attachment(const char *content_type, const char *encoding, co
header_destroy(&hdr, NULL);
if ( fstream )
stream_destroy(&fstream, NULL);
if ( fname )
free(fname);
}
return ret;
}
......@@ -125,32 +134,135 @@ static void _attachment_free(struct _msg_info *info, int free_message) {
free(info);
}
#define _ISSPECIAL(c) ( \
((c) == '(') || ((c) == ')') || ((c) == '<') || ((c) == '>') \
|| ((c) == '@') || ((c) == ',') || ((c) == ';') || ((c) == ':') \
|| ((c) == '\\') || ((c) == '.') || ((c) == '[') \
|| ((c) == ']') )
static char *_header_get_param(char *field_body, const char *param, size_t *len)
{
char *str, *p, *v, *e;
int quoted = 0, was_quoted = 0;
if ( len == NULL || ( str = field_body ) == NULL )
return NULL;
p = strchr(str, ';' );
while ( p ) {
p++;
while( isspace(*p) ) /* walk upto start of param */
p++;
if ( ( v = strchr(p, '=' ) ) == NULL )
break;
*len = 0;
v = e = v + 1;
while ( *e && (quoted || ( !_ISSPECIAL(*e) && !isspace(*e) ) ) ) { /* skip pass value and calc len */
if ( *e == '\"' )
quoted = ~quoted, was_quoted = 1;
else
(*len)++;
e++;
}
if ( strncasecmp(p, param, strlen(param)) ) { /* no match jump to next */
p = strchr(e, ';' );
continue;
}
else
return was_quoted ? v + 1 : v; /* return unquoted value */
}
return NULL;
}
int message_attachment_filename(message_t msg, char **filename)
{
char *pTmp, *fname = NULL;
header_t hdr;
int ret = EINVAL;
size_t size = 0;
if ( filename != NULL && ( ret = message_get_header(msg, &hdr) ) == 0 ) {
*filename = NULL;
header_get_value(hdr, "Content-Dispostion", NULL, 0, &size);
if ( size ) {
if ( ( pTmp = alloca(size+1) ) == NULL )
ret = ENOMEM;
header_get_value(hdr, "Content-Dispostion", pTmp, size+1, 0);
if ( strstr( pTmp, "attachment" ) != NULL )
fname = _header_get_param(pTmp, "filename", &size);
}
if ( fname == NULL ) {
size = 0;
header_get_value(hdr, "Content-Type", NULL, 0, &size);
if ( size ) {
if ( ( pTmp = alloca(size+1) ) == NULL )
ret = ENOMEM;
header_get_value(hdr, "Content-Type", pTmp, size+1, 0);
fname = _header_get_param(pTmp, "name", &size);
}
}
if ( fname ) {
fname[size] = '\0';
if ( ( *filename = strdup(fname) ) == NULL )
ret = ENOMEM;
} else
ret = ENOENT;
}
return ret;
}
int message_save_attachment(message_t msg, const char *filename, void **data)
{
stream_t stream;
header_t hdr;
stream_t istream, fstream;
struct _msg_info *info = NULL;
int ret = 0;
int ret;
size_t size;
char *content_encoding;
size_t nbytes;
header_t hdr;
const char *content_encoding, *fname = NULL;
if ( msg == NULL || filename == NULL)
return EINVAL;
if ( ( data == NULL || *data == NULL) && ( ret = message_get_header(msg, &hdr) ) == 0 ) {
header_get_value(hdr, "Content-Transfer-Encoding", NULL, 0, &size);
if ( size ) {
if ( ( content_encoding = alloca(size+1) ) == NULL )
ret = ENOMEM;
header_get_value(hdr, "Content-Transfer-Encoding", content_encoding, size+1, 0);
}
}
if ( ret == 0 && ( ret = _attachment_setup( &info, msg, &stream, data) ) != 0 )
if ( ( ret = _attachment_setup( &info, msg, &istream, data) ) != 0 )
return ret;
if ( ret != EAGAIN && info )
if ( ret == 0 && ( ret = message_get_header(msg, &hdr) ) == 0 ) {
if ( filename == NULL )
ret = message_attachment_filename(msg, &fname);
else
fname = filename;
if ( fname && ( ret = file_stream_create(&fstream) ) == 0 ) {
if ( ( ret = stream_open(fstream, fname, 0, MU_STREAM_WRITE|MU_STREAM_CREAT) ) == 0 ) {
header_get_value(hdr, "Content-Transfer-Encoding", NULL, 0, &size);
if ( size ) {
if ( ( content_encoding = alloca(size+1) ) == NULL )
ret = ENOMEM;
header_get_value(hdr, "Content-Transfer-Encoding", content_encoding, size+1, 0);
} else
content_encoding = "7bit";
ret = decoder_stream_create(&info->ostream, fstream, content_encoding);
}
}
}
if ( info->ostream && istream ) {
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(info->ostream, info->buf, info->nbytes, info->ooffset, &nbytes ) ) != 0 )
break;
info->nbytes -= nbytes;
info->ooffset += nbytes;
}
}
}
if ( ret != EAGAIN && info ) {
stream_close(info->ostream);
stream_destroy(&info->ostream, NULL);
_attachment_free(info, ret);
}
return ret;
}
......@@ -244,4 +356,3 @@ int message_unencapsulate(message_t msg, message_t *newmsg, void **data)
_attachment_free(info, ret);
return ret;
}
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Library Public License as published by
......@@ -344,5 +344,7 @@ file_stream_create (stream_t *stream)
stream_set_size (*stream, _file_size, fs);
stream_set_flush (*stream, _file_flush, fs);
stream_set_destroy (*stream, _file_destroy, fs);
/* Make sure we do not use the stream internal buffering. */
stream_setbufsiz (*stream, 0);
return 0;
}
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Library Public License as published by
......@@ -31,18 +31,19 @@
#include <misc.h>
#include <folder0.h>
static struct _monitor folder_lock = MU_MONITOR_INITIALIZER;
/* Internal folder list. */
static list_t known_folder_list;
static int is_known_folder (url_t, folder_t *);
static int is_same_scheme (url_t, url_t);
static int is_same_user (url_t, url_t);
static int is_same_path (url_t, url_t);
static int is_same_host (url_t, url_t);
static int is_same_port (url_t, url_t);
/* A folder could be remote(IMAP), or local(a spool directory) like $HOME/Mail
static int is_known_folder __P ((url_t, folder_t *));
static int is_same_scheme __P ((url_t, url_t));
static int is_same_user __P ((url_t, url_t));
static int is_same_path __P ((url_t, url_t));
static int is_same_host __P ((url_t, url_t));
static int is_same_port __P ((url_t, url_t));
/* Static folder lock. */
static struct _monitor folder_lock = MU_MONITOR_INITIALIZER;
/* A folder could be remote (IMAP), or local(a spool directory) like $HOME/Mail
etc .. We maintain a known list of folder to not generate multiple folder
of the same URL. Meaning when folder_create () is call we'll check if we
already have a folder for that URL and return the same, if not we create a
......@@ -63,7 +64,8 @@ folder_create (folder_t *pfolder, const char *name)
if (pfolder == NULL)
return EINVAL;
/* Look in the registrar list(iterator), for a match */
/* Look in the registrar list(iterator), for a possible concrete mailbox
implementatio that could match the URL. */
registrar_get_list (&list);
status = iterator_create (&iterator, list);
if (status != 0)
......@@ -117,8 +119,8 @@ folder_create (folder_t *pfolder, const char *name)
if (folder != NULL)
{
folder->url = url;
/* Initialize the internal lock, now so the concrete folder could
use it. */
/* Initialize the internal foilder lock, now so the concrete folder
could use it. */
status = monitor_create (&(folder->monitor), 0, folder);
if (status == 0)
{
......@@ -151,6 +153,7 @@ folder_create (folder_t *pfolder, const char *name)
return status;
}
/* The folder is destroy if it is the last reference. */
void
folder_destroy (folder_t *pfolder)
{
......@@ -161,17 +164,22 @@ folder_destroy (folder_t *pfolder)
monitor_t monitor = folder->monitor;
monitor_wrlock (monitor);
/* Check if this the last reference for this folder. If yes removed
it from the list. */
monitor_wrlock (&folder_lock);
folder->ref--;
/* Remove the folder from the list of known folder. */
if (folder->ref <= 0)
list_remove (known_folder_list, folder);
/* If the list is empty we can safely remove it. */
if (list_is_empty)
{
list_destroy (&known_folder_list);
known_folder_list = NULL;
}
monitor_unlock (&folder_lock);
if (folder->ref <= 0)
{
monitor_unlock (monitor);
......@@ -202,6 +210,8 @@ folder_destroy (folder_t *pfolder)
}
}
/* Cover functions. */
int
folder_open (folder_t folder, int flags)
{
......@@ -320,11 +330,12 @@ folder_get_debug (folder_t folder, debug_t *pdebug)
}
int
folder_list (folder_t folder, const char *dirname, struct folder_list *pflist)
folder_list (folder_t folder, const char *dirname, const char *basename,
struct folder_list *pflist)
{
if (folder == NULL || folder->_list == NULL)
return ENOSYS;
return folder->_list (folder, dirname, pflist);
return folder->_list (folder, dirname, basename, pflist);
}
int
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as published by
......@@ -83,14 +83,15 @@ static struct _record _path_record =
record_t path_record = &_path_record;
/* lsub/subscribe/unsubscribe are not needed. */
static void folder_mbox_destroy (folder_t);
static int folder_mbox_open (folder_t, int);
static int folder_mbox_close (folder_t);
static int folder_mbox_delete (folder_t, const char *);
static int folder_mbox_rename (folder_t , const char *, const char *);
static int folder_mbox_list (folder_t, const char *, struct folder_list *);
static void folder_mbox_destroy __P ((folder_t));
static int folder_mbox_open __P ((folder_t, int));
static int folder_mbox_close __P ((folder_t));
static int folder_mbox_delete __P ((folder_t, const char *));
static int folder_mbox_rename __P ((folder_t , const char *, const char *));
static int folder_mbox_list __P ((folder_t, const char *, const char *,
struct folder_list *));
static char *get_pathname (const char *, const char *);
static char *get_pathname __P ((const char *, const char *));
struct _fmbox
{
......@@ -215,7 +216,7 @@ folder_mbox_rename (folder_t folder, const char *oldpath, const char *newpath)
Unfortunately glov() does not expand the '~'. We also return
The full pathname so it can be use to create other folders. */
static int
folder_mbox_list (folder_t folder, const char *pattern,
folder_mbox_list (folder_t folder, const char *dirname, const char *pattern,
struct folder_list *pflist)
{
fmbox_t fmbox = folder->data;
......@@ -224,7 +225,10 @@ folder_mbox_list (folder_t folder, const char *pattern,
size_t num = 0;
glob_t gl;
pathname = get_pathname (fmbox->dirname, pattern);
if (dirname == NULL || dirname[0] == '\0')
dirname = (const char *)fmbox->dirname;
pathname = get_pathname (dirname, pattern);
if (pathname)
{
memset(&gl, 0, sizeof(gl));
......
......@@ -8,6 +8,7 @@ envelope0.h \
folder0.h \
header0.h \
iterator0.h \
imap0.h \
list0.h \
mailbox0.h \
mailer0.h \
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU Library General Public License as published by
......@@ -63,8 +63,10 @@ struct _folder
int (*_open) __P ((folder_t, int flag));
int (*_close) __P ((folder_t));
int (*_list) __P ((folder_t, const char *, struct folder_list *));
int (*_lsub) __P ((folder_t, const char *, struct folder_list *));
int (*_list) __P ((folder_t, const char *, const char *,
struct folder_list *));
int (*_lsub) __P ((folder_t, const char *, const char *,
struct folder_list *));
int (*_delete) __P ((folder_t, const char *));
int (*_rename) __P ((folder_t, const char *, const char *));
int (*_subscribe) __P ((folder_t, const char *));
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU 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 _IMAP0_H
#define _IMAP0_H
#ifdef DMALLOC
# include <dmalloc.h>
#endif
#include <folder0.h>
#include <mailbox0.h>
#include <registrar0.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __P
# ifdef __STDC__
# define __P(args) args
# else
# define __P(args) ()
# endif
#endif /*__P */
#define CLEAR_STATE(f_imap) \
f_imap->id = 0, f_imap->func = NULL, f_imap->state = IMAP_NO_STATE
/* Clear the state and close the stream. */
#define CHECK_ERROR_CLOSE(folder, f_imap, status) \
do \
{ \
if (status != 0) \
{ \
stream_close (folder->stream); \
CLEAR_STATE (f_imap); \
return status; \
} \
} \
while (0)
/* Clear the state. */
#define CHECK_ERROR(f_imap, status) \
do \
{ \
if (status != 0) \
{ \
CLEAR_STATE (f_imap); \
return status; \
} \
} \
while (0)
/* Clear the state for non recoverable error. */
#define CHECK_EAGAIN(f_imap, status) \
do \
{ \
if (status != 0) \
{ \
if (status != EAGAIN && status != EINPROGRESS && status != EINTR) \
{ \
CLEAR_STATE (f_imap); \
} \
return status; \
} \
} \
while (0)
struct _f_imap;
struct _m_imap;
struct _msg_imap;
typedef struct _f_imap *f_imap_t;
typedef struct _m_imap *m_imap_t;
typedef struct _msg_imap *msg_imap_t;
enum imap_state
{
IMAP_NO_STATE=0,
IMAP_AUTH, IMAP_AUTH_DONE,
IMAP_BODY,
IMAP_CLOSE, IMAP_CLOSE_ACK,
IMAP_DELETE, IMAP_DELETE_ACK,
IMAP_FETCH, IMAP_FETCH_ACK,
IMAP_GREETINGS,
IMAP_HEADER,
IMAP_HEADER_FIELD,
IMAP_LIST, IMAP_LIST_PARSE, IMAP_LIST_ACK,
IMAP_LOGIN, IMAP_LOGIN_ACK,
IMAP_LOGOUT, IMAP_LOGOUT_ACK,
IMAP_LSUB, IMAP_LSUB_ACK,
IMAP_MESSAGE,
IMAP_NOOP, IMAP_NOOP_ACK,
IMAP_OPEN_CONNECTION,
IMAP_RENAME, IMAP_RENAME_ACK,
IMAP_SELECT, IMAP_SELECT_ACK,
IMAP_STORE, IMAP_STORE_ACK,
IMAP_SUBSCRIBE, IMAP_SUBSCRIBE_ACK,
IMAP_UNSUBSCRIBE, IMAP_UNSUBSCRIBE_ACK
};
struct literal_string
{
char *buffer;
size_t buflen;
size_t total;
msg_imap_t msg_imap;
enum imap_state type;
size_t nleft; /* nleft to read in the literal. */
};
struct _f_imap
{
/* Back pointer. */
folder_t folder;
m_imap_t selected;
enum imap_state state;
void *func;
size_t id;
size_t seq; /* Sequence number to build a tag. */
char *capa; /* Cabilities of the server. */
size_t flags;
struct literal_string callback;
int isopen;
/* Buffer I/O */
size_t buflen;
char *buffer;
char *ptr;
char *nl;
off_t offset; /* Dummy, this is use because of the stream buffering.
The stream_t maintains and offset and the offset we use must
be in sync. */
/* Login */
char *user;
char *passwd;
};
struct _m_imap
{
/* Back pointers. */
mailbox_t mailbox;
f_imap_t f_imap;
size_t messages_count;
size_t imessages_count;
msg_imap_t *imessages;
size_t recent;
size_t unseen;
size_t uidvalidity;
char *name;
};
struct _msg_imap
{
/* Back pointers. */
message_t message;
m_imap_t m_imap;
size_t num;
size_t part;
size_t num_parts;
msg_imap_t *parts;
msg_imap_t parent;
int flags;
char *uid;
size_t message_size;
size_t message_lines;
size_t body_size;
size_t body_lines;
size_t header_size;
size_t header_lines;
};
int folder_imap_open __P ((folder_t, int));
int folder_imap_close __P ((folder_t));
int imap_writeline __P ((f_imap_t, const char *format, ...));
int imap_write __P ((f_imap_t));
int imap_send __P ((f_imap_t));
int imap_parse __P ((f_imap_t));
int imap_readline __P ((f_imap_t));
char *section_name __P ((msg_imap_t));
#ifdef __cplusplus
}
#endif
#endif /* _IMAP0_H */
......@@ -114,35 +114,35 @@ struct _mbox_data
};
/* 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 *);
static int mbox_open __P ((mailbox_t, int));
static int mbox_close __P ((mailbox_t));
static int mbox_get_message __P ((mailbox_t, size_t, message_t *));
static int mbox_append_message __P ((mailbox_t, message_t));
static int mbox_messages_count __P ((mailbox_t, size_t *));
static int mbox_expunge __P ((mailbox_t));
static int mbox_scan __P ((mailbox_t, size_t, size_t *));
static int mbox_is_updated __P ((mailbox_t));
static int mbox_size __P ((mailbox_t, off_t *));
/* 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_envelope_sender (envelope_t, char *, size_t, size_t *);
static int mbox_envelope_date (envelope_t, char *, size_t, size_t *);
static int mbox_scan0 __P ((mailbox_t, size_t, size_t *, int));
static int mbox_get_header_read __P ((stream_t, char *, size_t, off_t, size_t *));
static int mbox_get_hdr_fd __P ((stream_t, int *));
static int mbox_get_body_fd __P ((stream_t, int *));
static int mbox_get_fd __P ((mbox_message_t, int *));
static int mbox_get_attr_flags __P ((attribute_t, int *));
static int mbox_set_attr_flags __P ((attribute_t, int));
static int mbox_unset_attr_flags __P ((attribute_t, int));
static int mbox_readstream __P ((stream_t, char *, size_t, off_t, size_t *));
static int mbox_header_size __P ((header_t, size_t *));
static int mbox_header_lines __P ((header_t, size_t *));
static int mbox_body_size __P ((body_t, size_t *));
static int mbox_body_lines __P ((body_t, size_t *));
static int mbox_envelope_sender __P ((envelope_t, char *, size_t, size_t *));
static int mbox_envelope_date __P ((envelope_t, char *, size_t, size_t *));
#ifdef WITH_PTHREAD
static void mbox_cleanup (void *);
static void mbox_cleanup __P ((void *));
#endif
/* We allocate the mbox_data_t struct, but don't do any parsing on the name or
......
......@@ -70,40 +70,40 @@ enum pop_state
POP_AUTH_PASS, POP_AUTH_PASS_ACK
};
static void pop_destroy (mailbox_t);
static void pop_destroy __P ((mailbox_t));
/* Functions/Methods that implements the mailbox_t API. */
static int pop_open (mailbox_t, int);
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_scan (mailbox_t, size_t, size_t *);
static int pop_is_updated (mailbox_t);
static int pop_open __P ((mailbox_t, int));
static int pop_close __P ((mailbox_t));
static int pop_get_message __P ((mailbox_t, size_t, message_t *));
static int pop_messages_count __P ((mailbox_t, size_t *));
static int pop_expunge __P ((mailbox_t));
static int pop_scan __P ((mailbox_t, size_t, size_t *));
static int pop_is_updated __P ((mailbox_t));
/* The implementation of message_t */
static int pop_user (authority_t);
static int pop_size (mailbox_t, off_t *);
static int pop_user __P ((authority_t));
static int pop_size __P ((mailbox_t, off_t *));
/* We use pop_top for retreiving headers. */
/* 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_retr (pop_message_t, char *, size_t, off_t, size_t *);
static int pop_get_fd (pop_message_t, int *);
static int pop_attr_flags (attribute_t, int *);
static int pop_uid (message_t, char *, size_t, size_t *);
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);
static int pop_header_fd __P ((stream_t, int *));
static int pop_body_fd __P ((stream_t, int *));
static int pop_body_size __P ((body_t, size_t *));
static int pop_body_lines __P ((body_t, size_t *));
static int pop_body_read __P ((stream_t, char *, size_t, off_t, size_t *));
static int pop_message_read __P ((stream_t, char *, size_t, off_t, size_t *));
static int pop_message_size __P ((message_t, size_t *));
static int pop_message_fd __P ((stream_t, int *));
static int pop_top __P ((stream_t, char *, size_t, off_t, size_t *));
static int pop_retr __P ((pop_message_t, char *, size_t, off_t, size_t *));
static int pop_get_fd __P ((pop_message_t, int *));
static int pop_attr_flags __P ((attribute_t, int *));
static int pop_uid __P ((message_t, char *, size_t, size_t *));
static int fill_buffer __P ((pop_data_t, char *, size_t));
static int pop_readline __P ((pop_data_t));
static int pop_read_ack __P ((pop_data_t));
static int pop_writeline __P ((pop_data_t, const char *, ...));
static int pop_write __P ((pop_data_t));
/* This structure holds the info for a message. The pop_message_t
type, will serve as the owner of the message_t and contains the command to
......@@ -146,6 +146,9 @@ struct _pop_data
size_t buflen; /* Len of buffer. */
char *ptr; /* Points to the end of the buffer i.e the non consume chars. */
char *nl; /* Points to the '\n' char in te string. */
off_t offset; /* Dummy, this is use because of the stream buffering.
The stream_t maintains and offset and the offset we use must
be in sync. */
int is_updated;
char *user; /* Temporary holders for user and passwd. */
......@@ -334,11 +337,12 @@ pop_user (authority_t auth)
{
case POP_AUTH:
{
/* Fetch the user from them. */
size_t n = 0;
authority_get_ticket (auth, &ticket);
if (mpd->user)
free (mpd->user);
/* Fetch the user from them. */
/* Was it in the URL? */
status = url_get_user (mbox->url, NULL, 0, &n);
if (status != 0 || n == 0)
ticket_pop (ticket, "Pop User: ", &mpd->user);
......@@ -388,7 +392,7 @@ pop_user (authority_t auth)
}
status = pop_writeline (mpd, "PASS %s\r\n", mpd->passwd);
/* We have to nuke the passwd. */
memset (mpd->passwd, 0, strlen (mpd->passwd));
memset (mpd->passwd, '\0', strlen (mpd->passwd));
free (mpd->passwd);
mpd->passwd = NULL;
CHECK_ERROR_CLOSE (mbox, mpd, status);
......@@ -400,7 +404,7 @@ pop_user (authority_t auth)
status = pop_write (mpd);
CHECK_EAGAIN (mpd, status);
/* Clear the buffer it contains the passwd. */
memset (mpd->buffer, 0, mpd->buflen);
memset (mpd->buffer, '\0', mpd->buflen);
mpd->state = POP_AUTH_PASS_ACK;
case POP_AUTH_PASS_ACK:
......@@ -1762,11 +1766,12 @@ pop_readline (pop_data_t mpd)
do
{
status = stream_readline (mpd->mbox->stream, mpd->buffer + total,
mpd->buflen - total, 0, &n);
mpd->buflen - total, mpd->offset, &n);
if (status != 0)
return status;
total += n;
mpd->offset += n;
mpd->nl = memchr (mpd->buffer, '\n', total);
if (mpd->nl == NULL) /* Do we have a full line. */
{
......
/* GNU mailutils - a suite of utilities for electronic mail
Copyright (C) 1999, 2000 Free Software Foundation, Inc.
Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Library Public License as published by
......@@ -31,15 +31,15 @@
#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,
off_t off, size_t *pnwrite);
static int message_get_fd (stream_t stream, int *pfd);
static int message_sender (envelope_t envelope, char *buf, size_t len,
size_t *pnwrite);
static int message_date (envelope_t envelope, char *buf, size_t len,
size_t *pnwrite);
static int message_read __P ((stream_t is, char *buf, size_t buflen,
off_t off, size_t *pnread ));
static int message_write __P ((stream_t os, const char *buf, size_t buflen,
off_t off, size_t *pnwrite));
static int message_get_fd __P ((stream_t stream, int *pfd));
static int message_sender __P ((envelope_t envelope, char *buf, size_t len,
size_t *pnwrite));
static int message_date __P ((envelope_t envelope, char *buf, size_t len,
size_t *pnwrite));
/* Allocate ressources for the message_t. */
int
......
......@@ -15,9 +15,7 @@
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>
......@@ -41,14 +39,16 @@
* Need to prevent re-entry into mime lib, but allow non-blocking re-entry into lib.
*/
static int _mime_is_multipart_digest(mime_t mime)
static int
_mime_is_multipart_digest(mime_t mime)
{
if ( mime->content_type )
return(strncasecmp("multipart/digest", mime->content_type, strlen("multipart/digest")) ? 0: 1);
return 0;
}
static int _mime_append_part(mime_t mime, message_t msg, int offset, int len, int lines)
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;
......@@ -80,11 +80,11 @@ static int _mime_append_part(mime_t mime, message_t msg, int offset, int len, in
return ret;
}
mime->header_length = 0;
if ( ( ret = header_get_value(hdr, "Content-Type", NULL, 0, &size) ) != 0 || size == 0 ) {
if ( ( ret = header_get_value(hdr, MU_HEADER_CONTENT_TYPE, NULL, 0, &size) ) != 0 || size == 0 ) {
if ( _mime_is_multipart_digest(mime) )
header_set_value(hdr, "Content-Type", "message/rfc822", 0);
header_set_value(hdr, MU_HEADER_CONTENT_TYPE, "message/rfc822", 0);
else
header_set_value(hdr, "Content-Type", "text/plain", 0);
header_set_value(hdr, MU_HEADER_CONTENT_TYPE, "text/plain", 0);
}
mime_part->len = len;
mime_part->lines = lines;
......@@ -101,7 +101,8 @@ static int _mime_append_part(mime_t mime, message_t msg, int offset, int len, in
return 0;
}
static char *_strltrim(char *str)
static char *
_strltrim(char *str)
{
char *p;
......@@ -110,7 +111,8 @@ static char *_strltrim(char *str)
return((p != str) ? memmove(str, p, strlen(p)+1) : str);
}
static char *_strttrim(char *str)
static char *
_strttrim(char *str)
{
char *p;
......@@ -129,7 +131,8 @@ char *_strtrim(char *str);
|| ((c) == '\\') || ((c) == '.') || ((c) == '[') \
|| ((c) == ']') )
static void _mime_munge_content_header(char *field_body )
static void
_mime_munge_content_header(char *field_body )
{
char *p, *e, *str = field_body;
int quoted = 0;
......@@ -159,7 +162,8 @@ static void _mime_munge_content_header(char *field_body )
}
}
static char *_mime_get_param(char *field_body, const char *param, int *len)
static char *
_mime_get_param(char *field_body, const char *param, int *len)
{
char *str, *p, *v, *e;
int quoted = 0, was_quoted = 0;
......@@ -191,7 +195,8 @@ static char *_mime_get_param(char *field_body, const char *param, int *len)
return NULL;
}
static int _mime_setup_buffers(mime_t mime)
static int
_mime_setup_buffers(mime_t mime)
{
if ( mime->cur_buf == NULL && ( mime->cur_buf = malloc( mime->buf_size ) ) == NULL ) {
return ENOMEM;
......@@ -203,7 +208,8 @@ static int _mime_setup_buffers(mime_t mime)
return 0;
}
static void _mime_append_header_line(mime_t mime)
static void
_mime_append_header_line(mime_t mime)
{
if ( mime->header_length + mime->line_ndx > mime->header_buf_size) {
char *nhb;
......@@ -216,7 +222,8 @@ static void _mime_append_header_line(mime_t mime)
mime->header_length += mime->line_ndx;
}
static int _mime_parse_mpart_message(mime_t mime)
static int
_mime_parse_mpart_message(mime_t mime)
{
char *cp, *cp2;
int blength, mb_length, mb_offset, mb_lines, ret;
......@@ -316,7 +323,8 @@ static int _mime_parse_mpart_message(mime_t mime)
/*------ 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)
static int
_mimepart_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);
......@@ -335,7 +343,8 @@ static int _mimepart_body_read(stream_t stream, char *buf, size_t buflen, off_t
return stream_read(mime_part->mime->stream, buf, read_len, mime_part->offset + off, nbytes );
}
static int _mimepart_body_fd(stream_t stream, int *fd)
static int
_mimepart_body_fd(stream_t stream, int *fd)
{
body_t body = stream_get_owner(stream);
message_t msg = body_get_owner(body);
......@@ -344,7 +353,8 @@ static int _mimepart_body_fd(stream_t stream, int *fd)
return stream_get_fd(mime_part->mime->stream, fd);
}
static int _mimepart_body_size (body_t body, size_t *psize)
static int
_mimepart_body_size (body_t body, size_t *psize)
{
message_t msg = body_get_owner(body);
struct _mime_part *mime_part = message_get_owner(msg);
......@@ -356,7 +366,8 @@ static int _mimepart_body_size (body_t body, size_t *psize)
return 0;
}
static int _mimepart_body_lines (body_t body, size_t *plines)
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);
......@@ -369,13 +380,14 @@ static int _mimepart_body_lines (body_t body, size_t *plines)
}
/*------ Mime message/header functions for CREATING multipart message -----*/
static int _mime_set_content_type(mime_t mime)
static int
_mime_set_content_type(mime_t mime)
{
char content_type[256];
char boundary[128];
header_t hdr = NULL;
size_t size;
if ( mime->nmtp_parts > 1 ) {
if ( mime->flags & MIME_ADDED_MULTIPART_CT )
return 0;
......@@ -398,18 +410,19 @@ static int _mime_set_content_type(mime_t mime)
mime->flags &= ~MIME_ADDED_MULTIPART_CT;
if ( mime->nmtp_parts )
message_get_header(mime->mtp_parts[0]->msg, &hdr);
if ( hdr == NULL || header_get_value(hdr, "Content-Type", NULL, 0, &size) != 0 || size == 0 )
if ( hdr == NULL || header_get_value(hdr, MU_HEADER_CONTENT_TYPE, NULL, 0, &size) != 0 || size == 0 )
strcpy(content_type, "text/plain; charset=us-ascii");
else
header_get_value(hdr, "Content-Type", content_type, sizeof(content_type), &size);
header_get_value(hdr, MU_HEADER_CONTENT_TYPE, content_type, sizeof(content_type), &size);
}
mime->flags |= MIME_ADDED_CT;
return header_set_value(mime->hdrs, "Content-Type", content_type, 1);
return header_set_value(mime->hdrs, MU_HEADER_CONTENT_TYPE, content_type, 1);
}
#define ADD_CHAR(buf, c, offset, buflen, nbytes) {*(buf)++ = c; (offset)++; (nbytes)++;if (--(buflen) == 0) return 0;}
static int _mime_body_read(stream_t stream, char *buf, size_t buflen, off_t off, size_t *nbytes)
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);
......@@ -457,7 +470,7 @@ static int _mime_body_read(stream_t stream, char *buf, size_t buflen, off_t off,
}
while(mime->postamble) {
mime->postamble--;
ADD_CHAR(buf, '-', mime->cur_offset, buflen, *nbytes);
ADD_CHAR(buf, '-', mime->cur_offset, buflen, *nbytes);
}
mime->flags &= ~(MIME_INSERT_BOUNDARY|MIME_ADDING_BOUNDARY);
mime->part_offset = 0;
......@@ -489,7 +502,8 @@ static int _mime_body_read(stream_t stream, char *buf, size_t buflen, off_t off,
return ret;
}
static int _mime_body_fd(stream_t stream, int *fd)
static int
_mime_body_fd(stream_t stream, int *fd)
{
body_t body = stream_get_owner(stream);
message_t msg = body_get_owner(body);
......@@ -502,7 +516,8 @@ static int _mime_body_fd(stream_t stream, int *fd)
return stream_get_fd(msg_stream, fd);
}
static int _mime_body_size (body_t body, size_t *psize)
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);
......@@ -526,7 +541,8 @@ static int _mime_body_size (body_t body, size_t *psize)
return 0;
}
static int _mime_body_lines (body_t body, size_t *plines)
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);
......@@ -547,7 +563,8 @@ static int _mime_body_lines (body_t body, size_t *plines)
return 0;
}
int mime_create(mime_t *pmime, message_t msg, int flags)
int
mime_create(mime_t *pmime, message_t msg, int flags)
{
mime_t mime = NULL;
int ret = 0;
......@@ -561,10 +578,10 @@ int mime_create(mime_t *pmime, message_t msg, int flags)
return ENOMEM;
if ( msg ) {
if ( ( ret = message_get_header(msg, &(mime->hdrs)) ) == 0 ) {
if ( ( ret = header_get_value(mime->hdrs, "Content-Type", NULL, 0, &size) ) == 0 && size ) {
if ( ( ret = header_get_value(mime->hdrs, MU_HEADER_CONTENT_TYPE, NULL, 0, &size) ) == 0 && size ) {
if ( ( mime->content_type = malloc(size+1) ) == NULL )
ret = ENOMEM;
else if ( ( ret = header_get_value(mime->hdrs, "Content-Type", mime->content_type, size+1, 0) ) == 0 )
else if ( ( ret = header_get_value(mime->hdrs, MU_HEADER_CONTENT_TYPE, mime->content_type, size+1, 0) ) == 0 )
_mime_munge_content_header(mime->content_type);
} else {
ret = 0;
......@@ -594,7 +611,8 @@ int mime_create(mime_t *pmime, message_t msg, int flags)
return ret;
}
void mime_destroy(mime_t *pmime)
void
mime_destroy(mime_t *pmime)
{
mime_t mime;
struct _mime_part *mime_part;
......@@ -630,9 +648,11 @@ void mime_destroy(mime_t *pmime)
}
}
int mime_get_part(mime_t mime, int part, message_t *msg)
int
mime_get_part(mime_t mime, int part, message_t *msg)
{
int nmtp_parts, ret = 0;
size_t nmtp_parts;
int ret = 0;
stream_t stream;
body_t body;
struct _mime_part *mime_part;
......@@ -661,7 +681,8 @@ int mime_get_part(mime_t mime, int part, message_t *msg)
return ret;
}
int mime_get_num_parts(mime_t mime, int *nmtp_parts)
int
mime_get_num_parts(mime_t mime, size_t *nmtp_parts)
{
int ret = 0;
......@@ -677,10 +698,11 @@ int mime_get_num_parts(mime_t mime, int *nmtp_parts)
}
int mime_add_part(mime_t mime, message_t msg)
int
mime_add_part(mime_t mime, message_t msg)
{
int ret;
if ( mime == NULL || msg == NULL || ( mime->flags & MIME_NEW_MESSAGE ) == 0 )
return EINVAL;
if ( ( ret = _mime_append_part(mime, msg, 0, 0, 0) ) == 0 )
......@@ -688,7 +710,8 @@ int mime_add_part(mime_t mime, message_t msg)
return ret;
}
int mime_get_message(mime_t mime, message_t *msg)
int
mime_get_message(mime_t mime, message_t *msg)
{
stream_t body_stream;
body_t body;
......@@ -702,7 +725,7 @@ int mime_get_message(mime_t mime, message_t *msg)
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);
header_set_value(mime->hdrs, MU_HEADER_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);
......@@ -726,7 +749,8 @@ int mime_get_message(mime_t mime, message_t *msg)
return ret;
}
int mime_is_multipart(mime_t mime)
int
mime_is_multipart(mime_t mime)
{
if ( mime->content_type )
return(strncasecmp("multipart", mime->content_type, strlen("multipart")) ? 0: 1);
......
......@@ -161,7 +161,8 @@ stream_read (stream_t is, char *buf, size_t count,
int r;
/* Fill the buffer, do not want to start empty hand. */
if (is->rbuffer.count <= 0)
if (is->rbuffer.count <= 0 || offset < is->rbuffer.offset
|| offset > (is->rbuffer.offset + is->rbuffer.count))
{
status = refill (is, offset);
if (status != 0)
......@@ -184,7 +185,7 @@ stream_read (stream_t is, char *buf, size_t count,
is->rbuffer.offset += r;
buf += r;
residue -= r;
status = refill (is, is->rbuffer.offset + r);
status = refill (is, is->rbuffer.offset);
if (status != 0)
{
/* We have something in the buffer return the error on the
......@@ -246,7 +247,7 @@ stream_readline (stream_t is, char *buf, size_t count,
/* Grossly inefficient hopefully they override this */
for (n = 1; n < count; n++)
{
status = stream_read (is, &c, 1, offset, &nr);
status = is->_read (is, &c, 1, offset, &nr);
if (status != 0) /* Error. */
return status;
else if (nr == 1)
......@@ -273,14 +274,32 @@ stream_readline (stream_t is, char *buf, size_t count,
char *p, *nl;
size_t len;
size_t total = 0;
count--; /* Leave space for the null. */
//fprintf (stderr, "OFFSET %d %d\n", offset, is->rbuffer.offset);
/* If out of range refill. */
if ((offset < is->rbuffer.offset
|| offset > (is->rbuffer.offset + is->rbuffer.count)))
{
status = refill (is, offset);
if (status != 0)
return status;
if (is->rbuffer.count == 0)
{
if (pnread)
*pnread = 0;
return 0;
}
}
while (count != 0)
{
/* If the buffer is empty refill it. */
len = is->rbuffer.count;
if (len <= 0)
{
status = refill (is, offset);
status = refill (is, is->rbuffer.offset);
if (status != 0)
{
if (s != buf)
......@@ -304,21 +323,26 @@ stream_readline (stream_t is, char *buf, size_t count,
len = ++nl - p;
is->rbuffer.count -= len;
is->rbuffer.ptr = nl;
is->rbuffer.offset += len;
(void)memcpy ((void *)s, (void *)p, len);
total += len;
s[len] = 0;
//fprintf (stderr, ":%d %d:%s", len, total, s);
if (pnread)
*pnread = total;
return 0;
}
is->rbuffer.count -= len;
is->rbuffer.ptr += len;
is->rbuffer.offset += len;
(void)memcpy((void *)s, (void *)p, len);
//fprintf (stderr, "!:%d %d\n", len, total);
total += len;
s += len;
count -= len;
}
*s = 0;
//fprintf (stderr, "1:%s", s);
if (pnread)
*pnread = s - buf;
}
......@@ -554,6 +578,7 @@ refill (stream_t stream, off_t offset)
{
if (stream->_read)
{
int status;
if (stream->rbuffer.base == NULL)
{
stream->rbuffer.base = calloc (1, stream->rbuffer.bufsiz);
......@@ -563,9 +588,13 @@ refill (stream_t stream, off_t offset)
stream->rbuffer.ptr = stream->rbuffer.base;
stream->rbuffer.offset = offset;
stream->rbuffer.count = 0;
return stream->_read (stream, stream->rbuffer.ptr,
stream->rbuffer.bufsiz, offset,
(size_t *)&(stream->rbuffer.count));
status = stream->_read (stream, stream->rbuffer.ptr,
stream->rbuffer.bufsiz, offset,
(size_t *)&(stream->rbuffer.count));
//fprintf (stderr, "COUNT%d\n", stream->rbuffer.count);
//stream->rbuffer.ptr[stream->rbuffer.count] = 0;
//fprintf (stderr, "%s\n", stream->rbuffer.ptr);
return status;
}
return ENOTSUP;
}
......