Commit 1b691c26 1b691c267b818bab719f32fb3fc134c30d02ff04 by Alain Magloire

* mailbox/mbx_mbox.c (mbox_expunge0): New function.

	Move all the previous mbox_expunge() to mbox_expunge0()
	with a new argument deciding whether or not to remove
	messages set deleted.
	(mbox_save_attributes): Stub calling mbox_expunge0().
	(mbox_expunge): Stub calling mbox_expunge0()

	* mailbox/mbx_mh.c: Provide a prototype for mh_message_number()
	there is no provision for it in the current Mailbox API.
1 parent 45be40f7
2001-10-08 Alain Magloire
* mailbox/mbx_mbox.c (mbox_expunge0): New function.
Move all the previous mbox_expunge() to mbox_expunge0()
with a new argument deciding whether or not to remove
messages set deleted.
(mbox_save_attributes): Stub calling mbox_expunge0().
(mbox_expunge): Stub calling mbox_expunge0()
* mailbox/mbx_mh.c: Provide a prototype for mh_message_number()
there is no provision for it in the current Mailbox API.
2001-10-08 Sergey Poznyakoff
* mail/z.c: Bugfix: Did not display the last message when the
number of lines in last page was less than pagelines.
* mailbox/mbx_pop.c: Use ENOSYS instead of ENOTSUP.
* mh/mh_format.c: Fixed memory leak in strobj_free().
2001-10-05 Alain Magloire
* mailbox/folder_imap.c (imap_flags): Bailout at the matching
......
......@@ -171,6 +171,7 @@ static int mbox_append_message __P ((mailbox_t, message_t));
static int mbox_messages_count __P ((mailbox_t, size_t *));
static int mbox_messages_recent __P ((mailbox_t, size_t *));
static int mbox_message_unseen __P ((mailbox_t, size_t *));
static int mbox_expunge0 __P ((mailbox_t, int));
static int mbox_expunge __P ((mailbox_t));
static int mbox_save_attributes __P ((mailbox_t));
static int mbox_uidvalidity __P ((mailbox_t, unsigned long *));
......@@ -540,305 +541,6 @@ mbox_tmpfile (mailbox_t mailbox, char **pbox)
return fd;
}
/* FIXME: This is the code of _expunge(), duplicating code like this is really
not elegant ... but since we are moving with a new API of the mailbox,
this hack will suffice, for now.
- Check if messages/attributeds are modified
- create a temporary mailbox
- copy the messages to the temporay mailbox
- copy the temporary mailbox back to the original
- truncate ()
- re-scan ()
*/
static int
mbox_save_attributes (mailbox_t mailbox)
{
mbox_data_t mud = mailbox->data;
mbox_message_t mum;
int status = 0;
sigset_t signalset;
int tempfile;
size_t i, dirty; /* dirty will indicate the first modified message. */
off_t marker = 0; /* marker will be the position to truncate. */
off_t total = 0;
char *tmpmboxname = NULL;
mailbox_t tmpmailbox = NULL;
size_t save_imapbase = 0; /* uidvalidity is save in the first message. */
#ifdef WITH_PTHREAD
int state;
#endif
if (mud == NULL)
return EINVAL;
MAILBOX_DEBUG1 (mailbox, MU_DEBUG_TRACE, "mbox_save_attribute (%s)\n",
mud->name);
/* Noop. */
if (mud->messages_count == 0)
return 0;
/* Find the first dirty(modified) message. */
for (dirty = 0; dirty < mud->messages_count; dirty++)
{
mum = mud->umessages[dirty];
/* Attribute may have been tampered, break here. */
if ((mum->attr_flags & MU_ATTRIBUTE_MODIFIED)
|| (mum->message && message_is_modified (mum->message)))
break;
}
/* Did something change ? */
if (dirty == mud->messages_count)
return 0; /* Noop. Nothing change, bail out. */
/* Create a temporary file, for our temp mailbox. */
tempfile = mbox_tmpfile (mailbox, &tmpmboxname);
if (tempfile == -1)
{
if (tmpmboxname)
free (tmpmboxname);
mu_error ("Failed to create temporary file when saving attributes.\n");
return errno;
}
/* Create the temporary mailbox_t. */
{
mbox_data_t tmp_mud;
char *m = alloca (5 + strlen (tmpmboxname) + 1);
/* Try via the mbox: protocol. */
sprintf (m, "mbox:%s", tmpmboxname);
status = mailbox_create (&tmpmailbox, m);
if (status != 0)
{
/* Do not give up just yet, maybe they register the path_record. */
sprintf (m, "%s", tmpmboxname);
status = mailbox_create (&tmpmailbox, m);
if (status != 0)
{
/* Ok give up now. */
close (tempfile);
remove (tmpmboxname);
free (tmpmboxname);
return status;
}
}
/* Caution:Must be flag CREATE if not the mailbox_open will try to mmap()
the file. */
status = mailbox_open (tmpmailbox, MU_STREAM_CREAT | MU_STREAM_RDWR);
if (status != 0)
{
close (tempfile);
remove (tmpmboxname);
free (tmpmboxname);
return status;
}
close (tempfile); /* This one is useless the mailbox have its own. */
tmp_mud = tmpmailbox->data;
/* May need when appending. */
tmp_mud->uidvalidity = mud->uidvalidity;
tmp_mud->uidnext = mud->uidnext;
}
/* Get the File lock. */
if (locker_lock (mailbox->locker, MU_LOCKER_WRLOCK) != 0)
{
mailbox_close (tmpmailbox);
mailbox_destroy (&tmpmailbox);
remove (tmpmboxname);
free (tmpmboxname);
mu_error ("Failed to grab the lock\n");
return ENOLCK;
}
/* Critical section, we can not allowed signal here. */
#ifdef WITH_PTHREAD
pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state);
#endif
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. */
marker = mud->umessages[dirty]->header_from;
total = 0;
/* Copy to the temporary mailbox all messages starting from the dirty. */
for (i = dirty; i < mud->messages_count; i++)
{
mum = mud->umessages[i];
/* Do the expensive mbox_append_message0() only if mark dirty. */
if ((mum->attr_flags & MU_ATTRIBUTE_MODIFIED)
|| (mum->message && message_is_modified (mum->message)))
{
/* The message was not instanciated, probably the dirty attribute
flag was set by mbox_scan(), create one here. */
if (mum->message == 0)
{
message_t msg;
status = mbox_get_message (mailbox, i + 1, &msg);
if (status != 0)
{
mu_error ("Error expunge:%d: %s", __LINE__,
strerror (status));
goto bailout0;
}
}
status = mbox_append_message0 (tmpmailbox, mum->message,
&total, 1, (i == save_imapbase));
if (status != 0)
{
mu_error ("Error expunge:%d: %s", __LINE__,
strerror (status));
goto bailout0;
}
/* Clear the dirty bits. */
mum->attr_flags &= ~MU_ATTRIBUTE_MODIFIED;
message_clear_modified (mum->message);
}
else
{
/* Nothing changed, copy the message straight. */
char buffer [1024];
size_t n;
off_t offset = mum->header_from;
size_t len = mum->body_end - mum->header_from;
while (len > 0)
{
n = (len < sizeof (buffer)) ? len : sizeof (buffer);
if ((status = stream_read (mailbox->stream, buffer, n, offset,
&n) != 0)
|| (status = stream_write (tmpmailbox->stream, buffer, n,
total, &n) != 0))
{
mu_error ("Error expunge:%d: %s", __LINE__,
strerror (status));
goto bailout0;
}
len -= n;
total += n;
offset += n;
}
/* Add the newline separator. */
status = stream_write (tmpmailbox->stream, "\n", 1, total, &n);
if (status != 0)
{
mu_error ("Error expunge:%d: %s", __LINE__,
strerror (status));
goto bailout0;
}
total++;
}
} /* for (;;) */
/* Caution: before ftruncate()ing the file see
- if we've receive new mails. Some programs may not respect the lock,
- or the lock was held for too long.
- The mailbox may not have been properly updated before expunging. */
{
off_t size = 0;
if (stream_size (mailbox->stream, &size) == 0)
{
off_t len = size - mud->size;
off_t offset = mud->size;
char buffer [1024];
size_t n = 0;
if (len > 0 )
{
while ((status = stream_read (mailbox->stream, buffer,
sizeof (buffer), offset, &n)) == 0
&& n > 0)
{
status = stream_write (tmpmailbox->stream, buffer, n,
total, &n);
if (status != 0)
{
mu_error ("Error expunge:%d: %s", __LINE__,
strerror (status));
goto bailout0;
}
total += n;
offset += n;
}
}
else if (len < 0)
{
/* Corrupted mailbox. */
mu_error ("Error expunge:%d: %s", __LINE__,
strerror (status));
goto bailout0;
}
}
} /* End of precaution. */
/* Seek and rewrite it. */
if (total > 0)
{
char buffer [1024];
size_t n = 0;
off_t off = 0;
off_t offset = marker;
while ((status = stream_read (tmpmailbox->stream, buffer,
sizeof (buffer), off, &n)) == 0
&& n > 0)
{
status = stream_write (mailbox->stream, buffer, n, offset, &n);
if (status != 0)
{
mu_error ("Error expunge:%d: %s\n", __LINE__,
strerror (status));
goto bailout;
}
off += n;
offset += n;
}
}
/* Flush/truncation. Need to flush before truncate. */
stream_flush (mailbox->stream);
status = stream_truncate (mailbox->stream, total + marker);
if (status != 0)
{
mu_error ("Error expunging:%d: %s\n", __LINE__,
strerror (status));
goto bailout;
}
/* Don't remove the tmp mbox in case of errors, when writing back. */
bailout0:
remove (tmpmboxname);
bailout:
free (tmpmboxname);
/* Release the File lock. */
locker_unlock (mailbox->locker);
mailbox_close (tmpmailbox);
mailbox_destroy (&tmpmailbox);
/* Reenable interruption. */
#ifdef WITH_PTHREAD
pthread_setcancelstate (state, &state);
#endif
sigprocmask (SIG_UNBLOCK, &signalset, 0);
/* We need to readjust the pointers i.e the offsets of the msg structures. */
if (status == 0)
{
/* This should reset the messages_count, the last argument 0 means
not to send event notification. */
status = mbox_scan0 (mailbox, dirty, NULL, 0);
}
return status;
}
/* For the expunge bits we took a very cautionnary approach, meaning
we create a temporary mailbox in the tmpdir copy all the message not mark
deleted(Actually we copy all the message that may have been modified
......@@ -855,7 +557,7 @@ mbox_save_attributes (mailbox_t mailbox)
the temporary file may be left in /tmp, which is not all that bad
because at least, we have something to recuperate when failure. */
static int
mbox_expunge (mailbox_t mailbox)
mbox_expunge0 (mailbox_t mailbox, int remove_deleted)
{
mbox_data_t mud = mailbox->data;
mbox_message_t mum;
......@@ -909,11 +611,14 @@ mbox_expunge (mailbox_t mailbox)
/* 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. Destroy all the
messages mark for deletion. */
for (j = 0; j < mud->messages_count; j++)
if (remove_deleted)
{
mum = mud->umessages[j];
if (mum && mum->message && ATTRIBUTE_IS_DELETED (mum->attr_flags))
message_destroy (&(mum->message), mum);
for (j = 0; j < mud->messages_count; j++)
{
mum = mud->umessages[j];
if (mum && mum->message && ATTRIBUTE_IS_DELETED (mum->attr_flags))
message_destroy (&(mum->message), mum);
}
}
/* Create temporary mailbox_t. */
......@@ -988,7 +693,7 @@ mbox_expunge (mailbox_t mailbox)
mum = mud->umessages[i];
/* Skip it, if mark for deletion. */
if (ATTRIBUTE_IS_DELETED (mum->attr_flags))
if (remove_deleted && ATTRIBUTE_IS_DELETED (mum->attr_flags))
{
/* We save the uidvalidity in the first message, if it is being
deleted we need to move the uidvalidity to the first available
......@@ -1172,7 +877,7 @@ mbox_expunge (mailbox_t mailbox)
/* Clear all the references, any attach messages been already
destroy above. */
mum = mud->umessages[j];
if (ATTRIBUTE_IS_DELETED (mum->attr_flags))
if (remove_deleted && ATTRIBUTE_IS_DELETED (mum->attr_flags))
{
if ((j + 1) <= dlast)
{
......@@ -1230,6 +935,18 @@ mbox_expunge (mailbox_t mailbox)
}
static int
mbox_expunge (mailbox_t mailbox)
{
return mbox_expunge0 (mailbox, 1);
}
static int
mbox_save_attributes (mailbox_t mailbox)
{
return mbox_expunge0 (mailbox, 0);
}
static int
mbox_message_uid (message_t msg, size_t *puid)
{
mbox_message_t mum = message_get_owner (msg);
......
......@@ -72,9 +72,9 @@ struct _mh_message
int deleted; /* Was the message originally deleted */
time_t mtime; /* Time of last modification */
size_t header_lines; /* Number of lines in the header part */
size_t header_lines; /* Number of lines in the header part */
size_t body_lines; /* Number of lines in the body */
message_t message; /* Corresponding message_t */
struct _mh_data *mhd; /* Back pointer. */
};
......@@ -150,6 +150,9 @@ static int mh_envelope_date __P((envelope_t envelope, char *buf, size_t len,
static int mh_envelope_sender __P((envelope_t envelope, char *buf, size_t len,
size_t *psize));
/* Should be in an other header file. */
extern int mh_message_number __P ((message_t msg, size_t *pnum));
/* Return filename for the message.
NOTE: Allocates memory. */
static char *
......@@ -490,7 +493,7 @@ _mh_message_save (struct _mh_data *mhd, struct _mh_message *mhm, int expunge)
int status;
attribute_t attr;
body_t body;
if (expunge)
fp = _mh_tempfile (mhm->mhd, &name);
else
......@@ -499,7 +502,7 @@ _mh_message_save (struct _mh_data *mhd, struct _mh_message *mhm, int expunge)
fp = fopen (msg_name, "w");
free (msg_name);
}
if (!fp)
{
free (mhm);
......@@ -531,7 +534,7 @@ _mh_message_save (struct _mh_data *mhd, struct _mh_message *mhm, int expunge)
break;
nlines++;
if (!(strncasecmp (buf, "status:", 7) == 0
|| strncasecmp (buf, "x-imapbase:", 11) == 0
|| strncasecmp (buf, "x-iud:", 6) == 0))
......@@ -556,7 +559,7 @@ _mh_message_save (struct _mh_data *mhd, struct _mh_message *mhm, int expunge)
fprintf (fp, "\n");
/* Copy message body */
message_get_body (msg, &body);
body_get_stream (body, &stream);
off = 0;
......@@ -584,7 +587,7 @@ _mh_message_save (struct _mh_data *mhd, struct _mh_message *mhm, int expunge)
free (name);
free (msg_name);
}
return 0;
}
......@@ -597,11 +600,11 @@ mh_append_message (mailbox_t mailbox, message_t msg)
if (!mailbox || !msg)
return EINVAL;
mhm = calloc (1, sizeof(*mhm));
if (!mhm)
return ENOMEM;
mhm->mhd = mhd;
mhm->seq_number = _mh_next_seq (mhd);
mhm->uid = mhd->uidnext++;
......@@ -902,8 +905,8 @@ mh_scan_message (struct _mh_message *mhm)
return 0;
}
free (msg_name);
}
}
while ((status = stream_readline (stream, buf, sizeof (buf), off, &n) == 0)
&& n != 0)
{
......@@ -1220,7 +1223,7 @@ mh_readstream (struct _mh_message *mhm, char *buffer, size_t buflen,
if (ln > 0)
{
/* Position the file pointer and the buffer. */
nread = ((size_t)ln < buflen) ? ln : buflen;
nread = ((size_t)ln < buflen) ? (size_t)ln : buflen;
if (isreadline)
status = stream_readline (mhm->stream, buffer, buflen,
start + off, &nread);
......@@ -1482,5 +1485,3 @@ mh_message_number (message_t msg, size_t *pnum)
*pnum = mhm->seq_number;
return 0;
}
......