184 lines
4.3 KiB
C
184 lines
4.3 KiB
C
/* $Id: mboxClient.c,v 1.17 2004/03/28 00:28:58 bluehal Exp $ */
|
|
/* Author: Yong-iL Joh <tolkien@mizi.com>
|
|
Modified: Jorge García <Jorge.Garcia@uv.es>
|
|
Rob Funk <rfunk@funknet.net>
|
|
Neil Spring <nspring@cs.washington.edu>
|
|
*
|
|
* MBOX checker.
|
|
*
|
|
* Last Updated : $Date: 2004/03/28 00:28:58 $
|
|
*
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include "Client.h"
|
|
#include <sys/stat.h>
|
|
#include <errno.h>
|
|
#include <utime.h>
|
|
#ifdef USE_DMALLOC
|
|
#include <dmalloc.h>
|
|
#endif
|
|
|
|
#define PCM (pc->u).mbox
|
|
#define FROM_STR "From "
|
|
#define STATUS_STR "Status: "
|
|
|
|
FILE *openMailbox(Pop3 pc, const char *mbox_filename)
|
|
{
|
|
FILE *mailbox;
|
|
|
|
if ((mailbox = fopen(mbox_filename, "r")) == NULL) {
|
|
DM(pc, DEBUG_ERROR, "Error opening mailbox '%s': %s\n",
|
|
mbox_filename, strerror(errno));
|
|
pc->TotalMsgs = -1;
|
|
pc->UnreadMsgs = -1;
|
|
}
|
|
return (mailbox);
|
|
}
|
|
|
|
/* count the messages in a mailbox */
|
|
static void countMessages(Pop3 pc, const char *mbox_filename)
|
|
{
|
|
FILE *F;
|
|
char buf[BUF_SIZE];
|
|
int is_header = 0;
|
|
int next_from_is_start_of_header = 1;
|
|
int count_from = 0, count_status = 0;
|
|
int len_from = strlen(FROM_STR), len_status = strlen(STATUS_STR);
|
|
int pseudo_mail = 0;
|
|
|
|
F = openMailbox(pc, mbox_filename);
|
|
if (F == NULL)
|
|
return;
|
|
|
|
/* count message */
|
|
while (fgets(buf, BUF_SIZE, F)) {
|
|
// The first message usually is automatically created by POP3/IMAP
|
|
// clients for internal record keeping and is ignored
|
|
// (not displayed) by most email clients.
|
|
if (is_header && !strncmp(buf, "X-IMAP: ", 8))
|
|
{
|
|
pseudo_mail = 1;
|
|
}
|
|
if (buf[0] == '\n') {
|
|
/* a newline by itself terminates the header */
|
|
if (is_header)
|
|
is_header = 0;
|
|
else
|
|
next_from_is_start_of_header = 1;
|
|
} else if (!strncmp(buf, FROM_STR, len_from)) {
|
|
/* A line starting with "From" is the beginning of a new header.
|
|
"From" in the text of the mail should get escaped by the MDA.
|
|
If your MDA doesn't do that, it is broken.
|
|
*/
|
|
if (next_from_is_start_of_header)
|
|
is_header = 1;
|
|
if (is_header)
|
|
count_from++;
|
|
} else {
|
|
next_from_is_start_of_header = 0;
|
|
if (is_header && !strncmp(buf, STATUS_STR, len_status)
|
|
&& strrchr(buf, 'R')) {
|
|
count_status++;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (count_from && pseudo_mail) {
|
|
count_from--;
|
|
if (count_status)
|
|
count_status--;
|
|
}
|
|
|
|
DM(pc, DEBUG_INFO, "from: %d status: %d\n", count_from, count_status);
|
|
pc->TotalMsgs = count_from;
|
|
pc->UnreadMsgs = count_from - count_status;
|
|
fclose(F);
|
|
}
|
|
|
|
/* check file status; hold on to file information used
|
|
to restore access time */
|
|
int
|
|
fileHasChanged(const char *mbox_filename, time_t * atime,
|
|
time_t * mtime, off_t * size)
|
|
{
|
|
struct stat st;
|
|
|
|
/* mbox file */
|
|
if (stat(mbox_filename, &st)) {
|
|
DMA(DEBUG_ERROR, "Can't stat '%s': %s\n",
|
|
mbox_filename, strerror(errno));
|
|
} else if (st.st_mtime != *mtime || st.st_size != *size) {
|
|
/* file was changed OR initially read */
|
|
DMA(DEBUG_INFO, " %s was changed,"
|
|
" mTIME: %lu -> %lu; SIZE: %lu -> %lu\n",
|
|
mbox_filename, *mtime, st.st_mtime,
|
|
(unsigned long) *size, (unsigned long) st.st_size);
|
|
|
|
*atime = st.st_atime;
|
|
*mtime = st.st_mtime;
|
|
*size = st.st_size;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int mboxCheckHistory(Pop3 pc)
|
|
{
|
|
char *mbox_filename = backtickExpand(pc, pc->path);
|
|
struct utimbuf ut;
|
|
|
|
DM(pc, DEBUG_INFO, ">Mailbox: '%s'\n", mbox_filename);
|
|
|
|
if (fileHasChanged(mbox_filename, &ut.actime, &PCM.mtime, &PCM.size)
|
|
|| pc->OldMsgs < 0) {
|
|
|
|
countMessages(pc, mbox_filename);
|
|
|
|
/* Reset atime for (at least) MUTT to work */
|
|
/* ut.actime is set above */
|
|
ut.modtime = PCM.mtime;
|
|
utime(mbox_filename, &ut);
|
|
}
|
|
free(mbox_filename);
|
|
return 0;
|
|
}
|
|
|
|
int mboxCreate(Pop3 pc, const char *str)
|
|
{
|
|
/* MBOX format: mbox:fullpathname */
|
|
|
|
pc->TotalMsgs = 0;
|
|
pc->UnreadMsgs = 0;
|
|
pc->OldMsgs = -1;
|
|
pc->OldUnreadMsgs = -1;
|
|
pc->checkMail = mboxCheckHistory;
|
|
|
|
/* default boxes are mbox... cut mbox: if it exists */
|
|
if (!strncasecmp(pc->path, "mbox:", 5)) {
|
|
if (strlen(str + 5) + 1 > BUF_BIG) {
|
|
DM(pc, DEBUG_ERROR, "mbox '%s' is too long.\n", str + 5);
|
|
memset(pc->path, 0, BUF_BIG);
|
|
} else {
|
|
strncpy(pc->path, str + 5, BUF_BIG - 1); /* cut off ``mbox:'' */
|
|
}
|
|
}
|
|
|
|
DM(pc, DEBUG_INFO, "mbox: str = '%s'\n", str);
|
|
DM(pc, DEBUG_INFO, "mbox: path= '%s'\n", pc->path);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* vim:set ts=4: */
|
|
/*
|
|
* Local Variables:
|
|
* tab-width: 4
|
|
* c-indent-level: 4
|
|
* c-basic-offset: 4
|
|
* End:
|
|
*/
|