/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 1999, 2000, 2001, 2002, 2003,
2004, 2005, 2006, 2007 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 3 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
# ifndef _XOPEN_SOURCE
# define _XOPEN_SOURCE 500
# endif
# 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 (mu_mailbox_t mailbox);
static int amd_open (mu_mailbox_t, int);
static int amd_close (mu_mailbox_t);
static int amd_get_message (mu_mailbox_t, size_t, mu_message_t *);
static int amd_quick_get_message (mu_mailbox_t mailbox, mu_message_qid_t qid,
mu_message_t *pmsg);
static int amd_append_message (mu_mailbox_t, mu_message_t);
static int amd_messages_count (mu_mailbox_t, size_t *);
static int amd_messages_recent (mu_mailbox_t, size_t *);
static int amd_message_unseen (mu_mailbox_t, size_t *);
static int amd_expunge (mu_mailbox_t);
static int amd_sync (mu_mailbox_t);
static int amd_uidnext (mu_mailbox_t mailbox, size_t *puidnext);
static int amd_uidvalidity (mu_mailbox_t, unsigned long *);
static int amd_scan (mu_mailbox_t, size_t, size_t *);
static int amd_is_updated (mu_mailbox_t);
static int amd_get_size (mu_mailbox_t, mu_off_t *);
static int amd_body_read (mu_stream_t, char *, size_t, mu_off_t, size_t *);
static int amd_body_readline (mu_stream_t, char *, size_t, mu_off_t, size_t *);
static int amd_stream_size (mu_stream_t stream, mu_off_t *psize);
static int amd_body_size (mu_body_t body, size_t *psize);
static int amd_body_lines (mu_body_t body, size_t *plines);
static int amd_header_fill (mu_header_t header, char *buffer, size_t len,
mu_off_t off, size_t *pnread);
static int amd_get_attr_flags (mu_attribute_t attr, int *pflags);
static int amd_set_attr_flags (mu_attribute_t attr, int flags);
static int amd_unset_attr_flags (mu_attribute_t attr, int flags);
static void _amd_message_delete (struct _amd_data *amd,
struct _amd_message *msg);
static int amd_pool_open (struct _amd_message *mhm);
static int amd_pool_open_count (struct _amd_data *amd);
static void amd_pool_flush (struct _amd_data *amd);
static struct _amd_message **amd_pool_lookup (struct _amd_message *mhm);
static int amd_envelope_date (mu_envelope_t envelope, char *buf, size_t len,
size_t *psize);
static int amd_envelope_sender (mu_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, mu_off_t first, mu_off_t last,
struct _amd_message *msg,
mu_off_t *pret)
{
mu_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;
mu_off_t i;
if (amd->msg_count == 0)
{
*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 slo
|