2008-02-01 21:36:15 +03:00
|
|
|
/* GKrellM
|
2010-09-15 19:32:14 +04:00
|
|
|
| Copyright (C) 1999-2010 Bill Wilson
|
2008-02-01 21:36:15 +03:00
|
|
|
|
|
|
|
|
| Author: Bill Wilson billw@gkrellm.net
|
|
|
|
| Latest versions might be found at: http://gkrellm.net
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| GKrellM 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 3 of the License, or
|
|
|
|
| (at your option) any later version.
|
|
|
|
|
|
|
|
|
| GKrellM 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, see http://www.gnu.org/licenses/
|
2009-12-26 20:08:15 +03:00
|
|
|
|
|
|
|
|
|
|
|
|
|
| Additional permission under GNU GPL version 3 section 7
|
|
|
|
|
|
|
|
|
| If you modify this program, or any covered work, by linking or
|
|
|
|
| combining it with the OpenSSL project's OpenSSL library (or a
|
|
|
|
| modified version of that library), containing parts covered by
|
|
|
|
| the terms of the OpenSSL or SSLeay licenses, you are granted
|
|
|
|
| additional permission to convey the resulting work.
|
|
|
|
| Corresponding Source for a non-source form of such a combination
|
|
|
|
| shall include the source code for the parts of OpenSSL used as well
|
|
|
|
| as that of the covered work.
|
2008-02-01 21:36:15 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "gkrellmd.h"
|
|
|
|
#include "gkrellmd-private.h"
|
|
|
|
|
|
|
|
|
|
|
|
#if !defined(WIN32)
|
|
|
|
|
|
|
|
#define MBOX_MBOX 0
|
|
|
|
#define MBOX_MAILDIR 1
|
|
|
|
#define MBOX_MH_DIR 2
|
|
|
|
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
gchar *path;
|
|
|
|
gchar *homedir_path;
|
|
|
|
gint mboxtype;
|
|
|
|
gboolean (*check_func)();
|
|
|
|
gint mail_count;
|
|
|
|
gint new_mail_count;
|
|
|
|
gint old_mail_count;
|
|
|
|
gint prev_mail_count,
|
|
|
|
prev_new_mail_count;
|
|
|
|
time_t last_mtime;
|
|
|
|
off_t last_size;
|
|
|
|
gboolean is_internal; /* Internal mail message (ie: localmachine) */
|
|
|
|
gboolean changed;
|
|
|
|
}
|
|
|
|
Mailbox;
|
|
|
|
|
|
|
|
static GList *mailbox_list;
|
|
|
|
|
|
|
|
static gint mail_check_timeout = 5; /* Seconds */
|
|
|
|
|
|
|
|
static gboolean unseen_is_new = TRUE; /* Accessed but unread */
|
|
|
|
|
|
|
|
static gboolean mail_need_serve;
|
|
|
|
|
|
|
|
|
|
|
|
/* Look at a From line to see if it is valid, lines look like:
|
|
|
|
| From sending_address dayofweek month dayofmonth timeofday year
|
|
|
|
| eg: From billw@gkrellm.net Fri Oct 22 13:52:49 2010
|
|
|
|
*/
|
|
|
|
static gint
|
|
|
|
is_From_line(Mailbox *mbox, gchar *buf)
|
|
|
|
{
|
|
|
|
gchar sender[512];
|
|
|
|
gint dayofmonth = 0;
|
|
|
|
|
|
|
|
if (strncmp(buf, "From ", 5))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* In case sending address missing, look for a day of month
|
|
|
|
| number in field 3 or 4 (0 based).
|
|
|
|
*/
|
|
|
|
sender[0] = '\0';
|
|
|
|
if (sscanf(buf, "%*s %*s %*s %d", &dayofmonth) != 1)
|
|
|
|
{
|
|
|
|
if (sscanf(buf, "%*s %511s %*s %*s %d", sender, &dayofmonth) != 2)
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
if (dayofmonth < 1 || dayofmonth > 31)
|
|
|
|
return FALSE;
|
|
|
|
if (strcmp(sender, "MAILER-DAEMON") == 0)
|
|
|
|
mbox->is_internal = TRUE;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Check if this is a Content-Type-line. If it contains a boundary
|
|
|
|
| field, copy boundary string to buffer (including two leading and
|
|
|
|
| trailing dashes marking the end of a multipart mail) and return
|
|
|
|
| true. Otherwise, return false.
|
|
|
|
*/
|
|
|
|
static gint
|
|
|
|
is_multipart_mail(gchar *buf, gchar *separator)
|
|
|
|
{
|
|
|
|
gchar *fieldstart;
|
|
|
|
gchar *sepstart;
|
|
|
|
gint seplen;
|
|
|
|
|
|
|
|
if (strncmp(buf, "Content-Type: ", 14) != 0)
|
|
|
|
return FALSE;
|
|
|
|
if (strncmp(&buf[14], "multipart/", 10) != 0)
|
|
|
|
return FALSE;
|
|
|
|
fieldstart = &buf[14];
|
|
|
|
while (*fieldstart!=0)
|
|
|
|
{
|
|
|
|
while (*fieldstart!=0 && *fieldstart!=';')
|
|
|
|
fieldstart++;
|
|
|
|
if (*fieldstart==';') fieldstart++;
|
|
|
|
while (*fieldstart!=0 && *fieldstart==' ')
|
|
|
|
fieldstart++;
|
|
|
|
if (strncmp(fieldstart, "boundary=", 9) == 0)
|
|
|
|
{
|
|
|
|
sepstart = fieldstart + 9;
|
|
|
|
if (sepstart[0]=='"')
|
|
|
|
{
|
|
|
|
sepstart++;
|
|
|
|
seplen = 0;
|
|
|
|
while (sepstart[seplen]!='"' && sepstart[seplen]>=32)
|
|
|
|
seplen++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
seplen = 0;
|
|
|
|
while (sepstart[seplen]!=';' && sepstart[seplen]>32)
|
|
|
|
seplen++;
|
|
|
|
}
|
|
|
|
strcpy(separator,"--");
|
|
|
|
strncpy(&separator[2],sepstart,seplen);
|
|
|
|
strcpy(&separator[seplen+2],"--");
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
mh_sequences_new_count(Mailbox *mbox)
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
gchar buf[1024];
|
|
|
|
gchar *path, *tok;
|
|
|
|
gint n0, n1;
|
|
|
|
|
|
|
|
path = g_strconcat(mbox->path, G_DIR_SEPARATOR_S,
|
|
|
|
".mh_sequences", NULL);
|
|
|
|
f = fopen(path, "r");
|
|
|
|
g_free(path);
|
|
|
|
if (!f)
|
|
|
|
return FALSE;
|
|
|
|
while (fgets(buf, sizeof(buf), f))
|
|
|
|
{
|
|
|
|
/* Look for unseen sequence like "unseen: 4 7-9 23"
|
|
|
|
*/
|
|
|
|
if (strncmp(buf, "unseen:", 7))
|
|
|
|
continue;
|
|
|
|
tok = strtok(buf, " \t\n");
|
|
|
|
while ((tok = strtok(NULL, " \t\n")) != NULL)
|
|
|
|
{
|
|
|
|
if (sscanf(tok, "%d-%d", &n0, &n1) == 2)
|
|
|
|
mbox->new_mail_count += n1 - n0 + 1;
|
|
|
|
else
|
|
|
|
mbox->new_mail_count++;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Sylpheed procmsg.h enums MSG_NEW as (1 << 0) and MSG_UNREAD as (1 << 1)
|
|
|
|
| And procmsg_write_flags() in Sylpheeds procmsg.c writes a mail record as
|
|
|
|
| a pair of ints with msgnum first followed by flags.
|
|
|
|
*/
|
|
|
|
#define SYLPHEED_MSG_NEW 1
|
|
|
|
#define SYLPHEED_MSG_UNREAD 2
|
|
|
|
#define SYLPHEED_MARK_VERSION 2
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
sylpheed_mark_new_count(Mailbox *mbox)
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
gchar *path;
|
|
|
|
gint msgnum, flags, ver, mark_files = 0;
|
|
|
|
|
|
|
|
path = g_strconcat(mbox->path, G_DIR_SEPARATOR_S,
|
|
|
|
".sylpheed_mark", NULL);
|
|
|
|
f = fopen(path, "rb");
|
|
|
|
g_free(path);
|
|
|
|
if (!f)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if ( fread(&ver, sizeof(ver), 1, f) == 1
|
|
|
|
&& SYLPHEED_MARK_VERSION == ver
|
|
|
|
)
|
|
|
|
{
|
|
|
|
while ( fread(&msgnum, sizeof(msgnum), 1, f) == 1
|
|
|
|
&& fread(&flags, sizeof(flags), 1, f) == 1
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if ( (flags & SYLPHEED_MSG_NEW)
|
|
|
|
|| ((flags & SYLPHEED_MSG_UNREAD) && unseen_is_new)
|
|
|
|
)
|
|
|
|
mbox->new_mail_count += 1;
|
|
|
|
++mark_files;
|
|
|
|
}
|
|
|
|
if (mark_files < mbox->mail_count)
|
|
|
|
mbox->new_mail_count += mbox->mail_count - mark_files;
|
|
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Check a mh directory for mail. The way that messages are marked as new
|
|
|
|
| depends on the MUA being using. Only .mh_sequences and .sylpheed_mark
|
|
|
|
| are currently checked, otherwise all mail found is considered new mail.
|
|
|
|
*/
|
|
|
|
static gboolean
|
|
|
|
check_mh_dir(Mailbox *mbox)
|
|
|
|
{
|
|
|
|
GDir *dir;
|
|
|
|
gchar *name;
|
|
|
|
|
|
|
|
mbox->mail_count = mbox->new_mail_count = 0;
|
|
|
|
|
|
|
|
if ((dir = g_dir_open(mbox->path, 0, NULL)) == NULL)
|
|
|
|
return FALSE;
|
|
|
|
while ((name = (gchar *) g_dir_read_name(dir)) != NULL)
|
|
|
|
{
|
|
|
|
/* Files starting with a digit are messages. */
|
|
|
|
if (isdigit((unsigned char)name[0]))
|
|
|
|
mbox->mail_count++;
|
|
|
|
}
|
|
|
|
g_dir_close(dir);
|
|
|
|
|
|
|
|
/* Some MH dir clients use .mh_sequences, others such as mutt or gnus
|
|
|
|
| do not. For mixed cases, it's a user option to ignore .mh_sequences.
|
|
|
|
| Sylpheed uses .sylpheed_mark.
|
|
|
|
*/
|
|
|
|
if ( !mh_sequences_new_count(mbox)
|
|
|
|
&& !sylpheed_mark_new_count(mbox)
|
|
|
|
)
|
|
|
|
mbox->new_mail_count = mbox->mail_count;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* A maildir has new, cur, and tmp subdirectories. Any file in new
|
|
|
|
| or cur that does not begin with a '.' is a mail message. It is
|
|
|
|
| suggested that messages begin with the output of time() (9 digits)
|
|
|
|
| but while mutt and qmail use this standard, procmail does not.
|
|
|
|
| maildir(5) says:
|
|
|
|
| It is a good idea for readers to skip all filenames in
|
|
|
|
| new and cur starting with a dot. Other than this,
|
|
|
|
| readers should not attempt to parse filenames.
|
|
|
|
| So check_maildir() simply looks for files in new and cur.
|
|
|
|
| But if unseen_is_new flag is set, look for ":2,*S" file suffix where
|
|
|
|
| the 'S' indicates the mail is seen.
|
|
|
|
| See http://cr.yp.to/proto/maildir.html
|
|
|
|
*/
|
|
|
|
static gboolean
|
|
|
|
check_maildir(Mailbox *mbox)
|
|
|
|
{
|
|
|
|
gchar path[256], *s;
|
|
|
|
gchar *name;
|
|
|
|
GDir *dir;
|
|
|
|
|
|
|
|
mbox->new_mail_count = 0;
|
|
|
|
snprintf(path, sizeof(path), "%s%cnew", mbox->path,
|
|
|
|
G_DIR_SEPARATOR);
|
|
|
|
if ((dir = g_dir_open(path, 0, NULL)) != NULL)
|
|
|
|
{
|
|
|
|
while ((name = (gchar *) g_dir_read_name(dir)) != NULL)
|
|
|
|
mbox->new_mail_count++;
|
|
|
|
g_dir_close(dir);
|
|
|
|
}
|
|
|
|
mbox->mail_count = mbox->new_mail_count;
|
|
|
|
snprintf(path, sizeof(path), "%s%ccur", mbox->path,
|
|
|
|
G_DIR_SEPARATOR);
|
|
|
|
if ((dir = g_dir_open(path, 0, NULL)) != NULL)
|
|
|
|
{
|
|
|
|
while ((name = (gchar *) g_dir_read_name(dir)) != NULL)
|
|
|
|
{
|
|
|
|
mbox->mail_count++;
|
|
|
|
if ( unseen_is_new
|
|
|
|
&& ( (s = strchr(name, ':')) == NULL
|
|
|
|
|| !strchr(s, 'S')
|
|
|
|
)
|
|
|
|
)
|
|
|
|
mbox->new_mail_count++;
|
|
|
|
}
|
|
|
|
g_dir_close(dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_GK.debug_level & DEBUG_MAIL)
|
|
|
|
g_print(_("mdir %s total=%d old=%d new=%d\n"), mbox->path,
|
|
|
|
mbox->mail_count, mbox->old_mail_count, mbox->new_mail_count);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Count total mail and old mail in a mailbox. Old mail can be read
|
|
|
|
| with a Status: R0, or can be accessed and not read with Status: O
|
|
|
|
| So, new mail will be the diff - note that unread mail is not
|
|
|
|
| necessarily new mail. According to stat() man page:
|
|
|
|
| st_atime is changed by mknod(), utime(), read(), write(), truncate()
|
|
|
|
| st_mtime is changed by mknod(), utime(), write()
|
|
|
|
| But, new mail arriving (writing mailbox) sets st_mtime while reading
|
|
|
|
| the mailbox (mail program reading) sets st_atime. So the test
|
|
|
|
| st_atime > st_mtime is testing if mbox has been read since last new mail.
|
|
|
|
| Mail readers may restore st_mtime after writting status.
|
|
|
|
| And Netscape mail does status with X-Mozilla-Status: xxxS
|
|
|
|
| where S is bitwise or of status flags:
|
|
|
|
| 1: read 2: replied 4: marked 8: deleted
|
|
|
|
|
|
|
|
|
| Evolution uses status with X-Evolution: 00000000-xxxx where xxxx status is
|
|
|
|
| a bitfield in hexadecimal (see enum _CamelMessageFlags in evolution/camel
|
|
|
|
| source) and most importantly CAMEL_MESSAGE_SEEN = 1<<4.
|
|
|
|
*/
|
|
|
|
/* test if buf is a status for standard mail, mozilla or evolution
|
|
|
|
*/
|
|
|
|
static gboolean
|
|
|
|
is_status(gchar *buf)
|
|
|
|
{
|
|
|
|
if (buf[0] != 'S' && buf[0] != 'X')
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if ( !strncmp(buf, "Status:", 7) /* Standard mail clients */
|
|
|
|
|| !strncmp(buf, "X-Mozilla-Status:", 17) /* Netscape */
|
|
|
|
|| !strncmp(buf, "X-Evolution:", 12) /* Mozilla */
|
|
|
|
)
|
|
|
|
return TRUE;
|
|
|
|
else
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
status_is_old(gchar *buf)
|
|
|
|
{
|
|
|
|
gchar c;
|
|
|
|
int tmp;
|
|
|
|
|
|
|
|
/* Standard mail clients
|
|
|
|
*/
|
|
|
|
if ( !strncmp(buf, "Status:", 7)
|
|
|
|
&& (strchr(buf, 'R') || (!unseen_is_new && strchr(buf, 'O')))
|
|
|
|
)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
/* Netscape
|
|
|
|
*/
|
|
|
|
if (!strncmp(buf, "X-Mozilla-Status:", 17))
|
|
|
|
{
|
|
|
|
c = buf[21];
|
|
|
|
if (c < '8') /* Not deleted */
|
|
|
|
c -= '0';
|
|
|
|
if (c >= '8' || (c & 0x1))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Evolution
|
|
|
|
*/
|
|
|
|
if (!strncmp(buf, "X-Evolution:", 12))
|
|
|
|
{
|
|
|
|
sscanf(buf+22, "%04x", &tmp);
|
|
|
|
if (tmp & (1<<4))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* test if a mail is marked as deleted
|
|
|
|
| Evolution uses status with X-Evolution: 00000000-xxxx where xxxx status is
|
|
|
|
| a bitfield in hexadecimal (see enum _CamelMessageFlags in evolution/camel source)
|
|
|
|
| and most importantly CAMEL_MESSAGE_DELETED = 1<<1.
|
|
|
|
*/
|
|
|
|
static gboolean
|
|
|
|
status_is_deleted(gchar *buf)
|
|
|
|
{
|
|
|
|
gint tmp;
|
|
|
|
|
|
|
|
/* Standard mail clients
|
|
|
|
if ( !strncmp(buf, "Status:", 7) )
|
|
|
|
*/
|
|
|
|
/* Netscape
|
|
|
|
if (!strncmp(buf, "X-Mozilla-Status:", 17))
|
|
|
|
*/
|
|
|
|
/* Evolution
|
|
|
|
*/
|
|
|
|
if (!strncmp(buf, "X-Evolution:", 12))
|
|
|
|
{
|
|
|
|
sscanf(buf+22, "%04x", &tmp);
|
|
|
|
if (tmp & (1<<1))
|
|
|
|
return TRUE;
|
|
|
|
/* Junk is not explicitly marked as deleted but is shown as if
|
|
|
|
| where in evolution
|
|
|
|
*/
|
|
|
|
if (tmp & (1<<7))
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
check_mbox(Mailbox *mbox)
|
|
|
|
{
|
|
|
|
FILE *f;
|
|
|
|
struct utimbuf ut;
|
|
|
|
struct stat s;
|
|
|
|
gchar buf[1024];
|
|
|
|
gchar mpart_sep[1024];
|
|
|
|
gint in_header = FALSE;
|
|
|
|
gint marked_read = FALSE;
|
|
|
|
gint is_multipart = FALSE;
|
|
|
|
|
|
|
|
if (stat(mbox->path, &s) != 0)
|
|
|
|
{
|
|
|
|
mbox->mail_count = mbox->old_mail_count = mbox->new_mail_count = 0;
|
|
|
|
mbox->last_mtime = 0;
|
|
|
|
mbox->last_size = 0;
|
2010-06-12 23:41:22 +04:00
|
|
|
gkrellm_debug(DEBUG_MAIL, "check_mbox can't stat(%s): %s\n",
|
|
|
|
mbox->path, g_strerror(errno));
|
2008-02-01 21:36:15 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If the mailboxes have been modified since last check, count
|
|
|
|
| the new/total messages.
|
|
|
|
*/
|
|
|
|
if ( s.st_mtime != mbox->last_mtime
|
|
|
|
|| s.st_size != mbox->last_size
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if ((f = fopen(mbox->path, "r")) == NULL)
|
|
|
|
{
|
2010-06-12 23:41:22 +04:00
|
|
|
gkrellm_debug(DEBUG_MAIL, "check_mbox can't fopen(%s): %s\n",
|
|
|
|
mbox->path, g_strerror(errno));
|
2008-02-01 21:36:15 +03:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
mbox->mail_count = 0;
|
|
|
|
mbox->old_mail_count = 0;
|
|
|
|
while(fgets(buf, sizeof(buf), f))
|
|
|
|
{
|
|
|
|
if (is_multipart && !in_header)
|
|
|
|
{
|
|
|
|
/* Skip to last line of multipart mail */
|
|
|
|
if (strncmp(buf,mpart_sep,strlen(mpart_sep))==0)
|
|
|
|
is_multipart = FALSE;
|
|
|
|
}
|
|
|
|
else if (buf[0] == '\n')
|
|
|
|
{
|
|
|
|
in_header = FALSE;
|
|
|
|
mbox->is_internal = FALSE;
|
|
|
|
}
|
|
|
|
else if (is_From_line(mbox, buf))
|
|
|
|
{
|
|
|
|
mbox->mail_count += 1;
|
|
|
|
in_header = TRUE;
|
|
|
|
marked_read = FALSE;
|
|
|
|
}
|
|
|
|
else if (in_header && is_status(buf))
|
|
|
|
{
|
|
|
|
if (status_is_old(buf) && !marked_read)
|
|
|
|
{
|
|
|
|
mbox->old_mail_count += 1;
|
|
|
|
marked_read = TRUE;
|
|
|
|
}
|
|
|
|
if (status_is_deleted(buf))
|
|
|
|
{
|
|
|
|
if (marked_read)
|
|
|
|
mbox->old_mail_count -= 1;
|
|
|
|
mbox->mail_count -= 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (in_header && mbox->is_internal)
|
|
|
|
{
|
|
|
|
if (strncmp(buf, "From: Mail System Internal Data", 31) == 0)
|
|
|
|
{
|
|
|
|
in_header = FALSE;
|
|
|
|
mbox->mail_count -= 1;
|
|
|
|
mbox->is_internal = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (in_header && is_multipart_mail(buf,mpart_sep))
|
|
|
|
{
|
|
|
|
is_multipart = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
/* Restore the mbox stat times for other mail checking programs and
|
|
|
|
| so the (st_atime > st_mtime) animation override below will work.
|
|
|
|
*/
|
|
|
|
ut.actime = s.st_atime;
|
|
|
|
ut.modtime = s.st_mtime;
|
|
|
|
utime(mbox->path, &ut);
|
|
|
|
|
|
|
|
mbox->last_mtime = s.st_mtime;
|
|
|
|
mbox->last_size = s.st_size;
|
|
|
|
if (_GK.debug_level & DEBUG_MAIL)
|
|
|
|
g_print("mbox read <%s> total=%d old=%d\n",
|
|
|
|
mbox->path,
|
|
|
|
mbox->mail_count, mbox->old_mail_count);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If mbox has been accessed since last modify a MUA has probably read
|
|
|
|
| the mbox.
|
|
|
|
*/
|
|
|
|
mbox->new_mail_count = mbox->mail_count - mbox->old_mail_count;
|
|
|
|
if (s.st_atime > s.st_mtime)
|
|
|
|
{
|
|
|
|
mbox->prev_new_mail_count = mbox->new_mail_count;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
update_mail(GkrellmdMonitor *mon, gboolean force)
|
|
|
|
{
|
|
|
|
Mailbox *mbox;
|
|
|
|
GList *list;
|
|
|
|
static gint second_count;
|
|
|
|
|
|
|
|
if ( (!GK.second_tick || (++second_count % mail_check_timeout) != 0)
|
|
|
|
&& !force
|
|
|
|
)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (list = mailbox_list; list; list = list->next)
|
|
|
|
{
|
|
|
|
mbox = (Mailbox *) list->data;
|
|
|
|
if (mbox->check_func)
|
|
|
|
(*mbox->check_func)(mbox);
|
|
|
|
|
|
|
|
if ( mbox->prev_mail_count != mbox->mail_count
|
|
|
|
|| mbox->prev_new_mail_count != mbox->new_mail_count
|
|
|
|
)
|
|
|
|
{
|
|
|
|
mbox->changed = TRUE;
|
|
|
|
mail_need_serve = TRUE;
|
|
|
|
gkrellmd_need_serve(mon);
|
|
|
|
}
|
|
|
|
mbox->prev_mail_count = mbox->mail_count;
|
|
|
|
mbox->prev_new_mail_count = mbox->new_mail_count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
get_local_mboxtype(Mailbox *mbox)
|
|
|
|
{
|
|
|
|
gchar *path;
|
|
|
|
|
|
|
|
if (*(mbox->path) == '~')
|
|
|
|
{
|
|
|
|
mbox->homedir_path = mbox->path;
|
|
|
|
mbox->path = g_strdup_printf("%s%s", g_get_home_dir(),
|
|
|
|
mbox->homedir_path + 1);
|
|
|
|
}
|
|
|
|
if (g_file_test(mbox->path, G_FILE_TEST_IS_DIR))
|
|
|
|
{
|
|
|
|
path = g_build_path(G_DIR_SEPARATOR_S, mbox->path, "new", NULL);
|
|
|
|
if (g_file_test(path, G_FILE_TEST_IS_DIR))
|
|
|
|
mbox->mboxtype = MBOX_MAILDIR;
|
|
|
|
else
|
|
|
|
mbox->mboxtype = MBOX_MH_DIR;
|
|
|
|
g_free(path);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
mbox->mboxtype = MBOX_MBOX;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gkrellmd_add_mailbox(gchar *path)
|
|
|
|
{
|
|
|
|
Mailbox *mbox;
|
|
|
|
|
|
|
|
if (!path || !*path)
|
|
|
|
return;
|
|
|
|
mbox = g_new0(Mailbox, 1);
|
|
|
|
mbox->path = g_strdup(path);
|
|
|
|
get_local_mboxtype(mbox);
|
|
|
|
|
|
|
|
if (mbox->mboxtype == MBOX_MAILDIR)
|
|
|
|
mbox->check_func = check_maildir;
|
|
|
|
else if (mbox->mboxtype == MBOX_MH_DIR)
|
|
|
|
mbox->check_func = check_mh_dir;
|
|
|
|
else
|
|
|
|
mbox->check_func = check_mbox;
|
|
|
|
|
|
|
|
mailbox_list = g_list_append(mailbox_list, mbox);
|
|
|
|
gkrellmd_add_serveflag_done(&mbox->changed);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ============================================================= */
|
|
|
|
|
|
|
|
static void
|
|
|
|
serve_mail_data(GkrellmdMonitor *mon, gboolean first_serve)
|
|
|
|
{
|
|
|
|
Mailbox *mbox;
|
|
|
|
GList *list;
|
|
|
|
gchar *line;
|
|
|
|
|
|
|
|
if ((!mail_need_serve && !first_serve) || !mailbox_list)
|
|
|
|
return;
|
|
|
|
gkrellmd_set_serve_name(mon, "mail");
|
|
|
|
for (list = mailbox_list; list; list = list->next)
|
|
|
|
{
|
|
|
|
mbox = (Mailbox *) list->data;
|
|
|
|
if (mbox->changed || first_serve)
|
|
|
|
{
|
|
|
|
line = g_strdup_printf("%s %d %d\n", mbox->homedir_path ?
|
|
|
|
mbox->homedir_path : mbox->path,
|
|
|
|
mbox->mail_count, mbox->new_mail_count);
|
|
|
|
gkrellmd_serve_data(mon, line);
|
|
|
|
g_free(line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
serve_mail_setup(GkrellmdMonitor *mon)
|
|
|
|
{
|
|
|
|
GkrellmdClient *client = mon->privat->client;
|
|
|
|
GList *list;
|
|
|
|
Mailbox *mbox;
|
|
|
|
gchar *line;
|
|
|
|
|
|
|
|
gkrellmd_send_to_client(client, "<mail_setup>\n");
|
|
|
|
for (list = mailbox_list; list; list = list->next)
|
|
|
|
{
|
|
|
|
mbox = (Mailbox *) list->data;
|
|
|
|
line = g_strdup_printf("%s\n", mbox->homedir_path ?
|
|
|
|
mbox->homedir_path : mbox->path);
|
|
|
|
gkrellmd_send_to_client(client, line);
|
|
|
|
g_free(line);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static GkrellmdMonitor mail_monitor =
|
|
|
|
{
|
|
|
|
"mail",
|
|
|
|
update_mail,
|
|
|
|
serve_mail_data,
|
|
|
|
serve_mail_setup
|
|
|
|
};
|
|
|
|
|
|
|
|
GkrellmdMonitor *
|
|
|
|
gkrellmd_init_mail_monitor(void)
|
|
|
|
{
|
|
|
|
gkrellmd_add_serveflag_done(&mail_need_serve);
|
|
|
|
return &mail_monitor;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* defined(WIN32) */
|
|
|
|
|
|
|
|
GkrellmdMonitor *
|
|
|
|
gkrellmd_init_mail_monitor(void)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gkrellmd_add_mailbox(gchar *path)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
gkrellm_mail_local_unsupported(void)
|
|
|
|
{
|
|
|
|
/* WIN32 only calls this and it is taken care of by above #if */
|
|
|
|
}
|
|
|
|
|
|
|
|
GThread *
|
|
|
|
gkrellm_mail_get_active_thread(void)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|