/*
* Copyright (C) 1996-2000,2010,2013 Michael R. Elkins <me@mutt.org>
* Copyright (C) 2016-2017,2020-2022 Kevin J. McCarthy <kevin@8t8.us>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#if HAVE_CONFIG_H
# include "config.h"
#endif
#include "mutt.h"
#include "buffy.h"
#include "mailbox.h"
#include "mx.h"
#include "mutt_curses.h"
#include "mutt_menu.h"
#ifdef USE_SIDEBAR
#include "sidebar.h"
#endif
#ifdef USE_IMAP
#include "imap.h"
#endif
#ifdef USE_INOTIFY
#include "monitor.h"
#endif
#include <string.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <dirent.h>
#include <utime.h>
#include <ctype.h>
#include <unistd.h>
#include <stdio.h>
static time_t BuffyTime = 0; /* last time we started checking for mail */
static time_t BuffyStatsTime = 0; /* last time we check performed mail_check_stats */
time_t BuffyDoneTime = 0; /* last time we knew for sure how much mail there was. */
static short BuffyCount = 0; /* how many boxes with new mail */
static short BuffyNotify = 0; /* # of unnotified new boxes */
static BUFFY* buffy_get (const char *path);
/* Find the last message in the file.
* upon success return 0. If no message found - return -1 */
static int fseek_last_message (FILE * f)
{
LOFF_T pos;
char buffer[BUFSIZ + 7]; /* 7 for "\n\nFrom " */
int bytes_read;
int i; /* Index into `buffer' for scanning. */
memset (buffer, 0, sizeof(buffer));
fseek (f, 0, SEEK_END);
pos = ftello (f);
/* Set `bytes_read' to the size of the last, probably partial, buffer; 0 <
* `bytes_read' <= `BUFSIZ'. */
bytes_read = pos % BUFSIZ;
if (bytes_read == 0)
bytes_read = BUFSIZ;
/* Make `pos' a multiple of `BUFSIZ' (0 if the file is short), so that all
* reads will be on block boundaries, which might increase efficiency. */
while ((pos -= bytes_read) >= 0)
{
/* we save in the buffer at the end the first 7 chars from the last read */
memcpy (buffer + BUFSIZ, buffer, 7);
fseeko (f, pos, SEEK_SET);
bytes_read = fread (buffer, sizeof (char), bytes_read, f);
if (bytes_read == -1)
return -1;
for (i = bytes_read; --i >= 0;)
if (!mutt_strncmp (buffer + i, "\n\nFrom ", 7))
{ /* found it - go to the beginning of the From */
fseeko (f, pos + i + 2, SEEK_SET);
return 0;
}
bytes_read = BUFSIZ;
}
/* here we are at the beginning of the file */
if (!mutt_strncmp ("From ", buffer, 5))
{
fseek (f, 0, SEEK_SET);
return (0);
}
return (-1);
}
/* Return 1 if the last message is new */
static int test_last_status_new (FILE * f)
{
HEADER *hdr;
ENVELOPE* tmp_envelope;
int result = 0;
if (fseek_last_message (f) == -1)
return (0);
hdr = mutt_new_header ();
tmp_envelope = mutt_read_rfc822_header (f, hdr, 0, 0);
if (!(hdr->read || hdr->old))
result = 1;
mutt_free_envelope(&tmp_envelope);
mutt_free_header (&hdr);
return result;
}
static int test_new_folder (const char *path)
{
FILE *f;
int rc = 0;
int typ;
typ = mx_get_magic (path);
if (typ != MUTT_MBOX && typ != MUTT_MMDF)
return 0;
if ((f = fopen (path, "rb")))
{
rc = test_last_status_new (f);
safe_fclose (&f);
}
return rc;
}
void mutt_buffy_cleanup (const char *buf, struct stat *st)
{
#ifdef HAVE_UTIMENSAT
struct timespec ts[2];
#else
struct utimbuf ut;
#endif
BUFFY *tmp;
if (option(OPTCHECKMBOXSIZE))
{
tmp = mutt_find_mailbox (buf);
if (tmp && !tmp->new)
mutt_update_mailbox (tmp);
}
else
{
/* fix up the times so buffy won't get confused */
if (st->st_mtime > st->st_atime)
{
#ifdef HAVE_UTIMENSAT
ts[0].tv_sec = 0;
ts[0].tv_nsec = UTIME_OMIT;
ts[1].tv_sec = 0;
ts[1].tv_nsec = UTIME_NOW;
utimensat (AT_FDCWD,