/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2003,
2004, 2005 Free Software Foundation, Inc.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301 USA */
/* Mailutils Abstract Mail Directory Layer
First draft by Sergey Poznyakoff.
Thanks Tang Yong Ping <yongping.tang@radixs.com> for initial
patch (although not used here).
This module provides basic support for "MH" and "Maildir" formats. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <ctype.h>
#include <dirent.h>
#ifdef WITH_PTHREAD
# ifdef HAVE_PTHREAD_H
# define _XOPEN_SOURCE 500
# include <pthread.h>
# endif
#endif
#include <string.h>
#ifdef HAVE_STRINGS_H
# include <strings.h>
#endif
#include <mailutils/attribute.h>
#include <mailutils/body.h>
#include <mailutils/debug.h>
#include <mailutils/envelope.h>
#include <mailutils/error.h>
#include <mailutils/errno.h>
#include <mailutils/header.h>
#include <mailutils/locker.h>
#include <mailutils/message.h>
#include <mailutils/mutil.h>
#include <mailutils/property.h>
#include <mailutils/stream.h>
#include <mailutils/url.h>
#include <mailutils/observer.h>
#include <mailbox0.h>
#include <registrar0.h>
#include <url0.h>
#include <amd.h>
static void amd_destroy __P((mailbox_t mailbox));
static int amd_open __P ((mailbox_t, int));
static int amd_close __P ((mailbox_t));
static int amd_get_message __P ((mailbox_t, size_t, message_t *));
static int amd_append_message __P ((mailbox_t, message_t));
static int amd_messages_count __P ((mailbox_t, size_t *));
static int amd_messages_recent __P ((mailbox_t, size_t *));
static int amd_message_unseen __P ((mailbox_t, size_t *));
static int amd_expunge __P ((mailbox_t));
static int amd_save_attributes __P ((mailbox_t));
static int amd_uidnext __P((mailbox_t mailbox, size_t *puidnext));
static int amd_uidvalidity __P ((mailbox_t, unsigned long *));
static int amd_scan __P ((mailbox_t, size_t, size_t *));
static int amd_is_updated __P ((mailbox_t));
static int amd_get_size __P ((mailbox_t, off_t *));
static int amd_body_read __P ((stream_t, char *, size_t, off_t, size_t *));
static int amd_body_readline __P ((stream_t, char *, size_t, off_t, size_t *));
static int amd_stream_size __P ((stream_t stream, off_t *psize));
static int amd_body_size __P ((body_t body, size_t *psize));
static int amd_body_lines __P ((body_t body, size_t *plines));
static int amd_header_fill __P((header_t header, char *buffer, size_t len,
off_t off, size_t *pnread));
static int amd_header_size __P((header_t header, size_t *psize));
static int amd_header_lines __P((header_t header, size_t *plines));
static int amd_get_attr_flags __P((attribute_t attr, int *pflags));
static int amd_set_attr_flags __P((attribute_t attr, int flags));
static int amd_unset_attr_flags __P((attribute_t attr, int flags));
static void _amd_message_delete __P((struct _amd_data *amd,
struct _amd_message *msg));
static int amd_pool_open __P((struct _amd_message *mhm));
static int amd_pool_open_count __P((struct _amd_data *amd));
static void amd_pool_flush (struct _amd_data *amd);
static struct _amd_message **amd_pool_lookup __P((struct _amd_message *mhm));
static int amd_envelope_date __P((envelope_t envelope, char *buf, size_t len,
size_t *psize));
static int amd_envelope_sender __P((envelope_t envelope, char *buf, size_t len,
size_t *psize));
/* Operations on message array */
/* Perform binary search for message MSG on a segment of message array
of AMD between the indexes FIRST and LAST inclusively.
If found, return 0 and store index of the located entry in the
variable PRET. Otherwise, return 1 and place into PRET index of
the nearest array element that is less than MSG (in the sense of
amd->msg_cmp)
Indexes are zero-based. */
static int
amd_msg_bsearch (struct _amd_data *amd, off_t first, off_t last,
struct _amd_message *msg,
off_t *pret)
{
off_t mid;
int rc;
if (last < first)
return 1;
mid = (first + last) / 2;
rc = amd->msg_cmp (amd->msg_array[mid], msg);
if (rc > 0)
return amd_msg_bsearch (amd, first, mid-1, msg, pret);
*pret = mid;
if (rc < 0)
return amd_msg_bsearch (amd, mid+1, last, msg, pret);
/* else */
return 0;
}
/* Search for message MSG in the message array of AMD.
If found, return 0 and store index of the located entry in the
variable PRET. Otherwise, return 1 and place into PRET index of
the array element that is less than MSG (in the sense of
amd->msg_cmp)
Index returned in PRET is 1-based, so *PRET == 0 means that MSG
is less than the very first element of the message array.
In other words, when amd_msg_lookup() returns 1, the value in *PRET
can be regarded as a 0-based index of the array slot where MSG can
be inserted */
int
amd_msg_lookup (struct _amd_data *amd, struct _amd_message *msg,
size_t *pret)
{
int rc;
off_t i;
if (!amd->msg_array)
{
*pret = 0;
return 1;
}
rc = amd->msg_cmp (msg, amd->msg_array[0]);
if (rc < 0)
{
*pret = 0;
return 1;
}
else if (rc == 0)
{
*pret = 1;
return 0;
}
rc = amd->msg_cmp (msg, amd->msg_array[amd->msg_count - 1]);
if (rc > 0)
{
*pret = amd->msg_count;
return 1;
}
else if (rc == 0)
{
*pret = amd->msg_count;
return 0;
}
rc = amd_msg_bsearch (amd, 0, amd->msg_count - 1, msg, &i);
*pret = i + 1;
return rc;
}
#define AMD_MSG_INC 64
/* Prepare the message array for insertion of a new message
at position INDEX (zero based), by moving its contents
one slot to the right. If necessary, expand the array by
AMD_MSG_INC */
int
amd_array_expand (struct _amd_data *amd, size_t index)
{
if (amd->msg_count == amd->msg_max)
{
struct _amd_message **p;
amd->msg_max += AMD_MSG_INC; /* FIXME: configurable? */
p = realloc (amd->msg_array, amd->msg_max * amd->msg_size);
if (!p)
{
amd->msg_max -= AMD_MSG_INC;
return ENOMEM;
}
amd->msg_array = p;
}
memmove (&amd->msg_array[index+1], &amd->msg_array[index],
(amd->msg_count-index) * amd->msg_size);
amd->msg_count++;
return 0;
}
/* Shrink the message array by removing element at INDEX-1 and
shifting left by one position all the elements on the right of
it. */
int
amd_array_shrink (struct _amd_data *amd, size_t index)
{
memmove (&amd->msg_array[index-1], &amd->msg_array[index],
(amd->msg_count-index) * amd->msg_size);
amd->msg_count--;
return 0;
}
int
amd_init_mailbox (mailbox_t mailbox, size_t amd_size, struct _amd_data **pamd)
{
struct _amd_data *amd;
size_t name_len;
if (mailbox == NULL)
return MU_ERR_MBX_NULL;
if (amd_size < sizeof (*amd))
return EINVAL;
amd = mailbox->data = calloc (1, amd_size);
if (mailbox->data == NULL)
return ENOMEM;
/* Back pointer. */
amd->mailbox = mailbox;
url_get_path (mailbox->url, NULL, 0, &name_len);
amd->name = calloc (name_len + 1, sizeof (char));
if (amd->name == NULL)
{
free (amd);
mailbox->data = NULL;
return ENOMEM;
}
url_get_path (mailbox->url, amd->name, name_len + 1, NULL);
/* Overloading the defaults. */
mailbox->_destroy = amd_destroy;
mail
|