/* $Id: mboxClient.c,v 1.17 2004/03/28 00:28:58 bluehal Exp $ */ /* Author: Yong-iL Joh Modified: Jorge García Rob Funk Neil Spring * * MBOX checker. * * Last Updated : $Date: 2004/03/28 00:28:58 $ * */ #ifdef HAVE_CONFIG_H #include #endif #include "Client.h" #include #include #include #ifdef USE_DMALLOC #include #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: */