#include "config.h"
#include <stdio.h>
#include "bashtypes.h"
#include "posixstat.h"
#ifndef _MINIX
# include <sys/param.h>
#endif
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "posixtime.h"
#include "bashansi.h"
#include "shell.h"
#include "execute_cmd.h"
#include "mailcheck.h"
#include <tilde/tilde.h>
extern int mailstat __P((const char *, struct stat *));
typedef struct {
char *name;
char *msg;
time_t access_time;
time_t mod_time;
off_t file_size;
} FILEINFO;
static FILEINFO **mailfiles = (FILEINFO **)NULL;
static int mailfiles_count;
static time_t last_time_mail_checked;
int mail_warning;
static int find_mail_file __P((char *));
static void update_mail_file __P((int));
static int add_mail_file __P((char *, char *));
static int file_mod_date_changed __P((int));
static int file_access_date_changed __P((int));
static int file_has_grown __P((int));
static char *parse_mailpath_spec __P((char *));
int
time_to_check_mail ()
{
char *temp;
time_t now;
intmax_t seconds;
temp = get_string_value ("MAILCHECK");
if (temp == 0 || legal_number (temp, &seconds) == 0 || seconds < 0)
return (0);
now = NOW;
return (seconds == 0 || ((now - last_time_mail_checked) >= seconds));
}
void
reset_mail_timer ()
{
last_time_mail_checked = NOW;
}
static int
find_mail_file (file)
char *file;
{
register int i;
for (i = 0; i < mailfiles_count; i++)
if (STREQ (mailfiles[i]->name, file))
return i;
return -1;
}
#define RESET_MAIL_FILE(i) \
do \
{ \
mailfiles[i]->access_time = mailfiles[i]->mod_time = 0; \
mailfiles[i]->file_size = 0; \
} \
while (0)
static void
update_mail_file (i)
int i;
{
char *file;
struct stat finfo;
file = mailfiles[i]->name;
if (mailstat (file, &finfo) == 0)
{
mailfiles[i]->access_time = finfo.st_atime;
mailfiles[i]->mod_time = finfo.st_mtime;
mailfiles[i]->file_size = finfo.st_size;
}
else
RESET_MAIL_FILE (i);
}
static int
add_mail_file (file, msg)
char *file, *msg;
{
struct stat finfo;
char *filename;
int i;
filename = full_pathname (file);
i = find_mail_file (filename);
if (i >= 0)
{
if (mailstat (filename, &finfo) == 0)
{
mailfiles[i]->mod_time = finfo.st_mtime;
mailfiles[i]->access_time = finfo.st_atime;
mailfiles[i]->file_size = finfo.st_size;
}
free (filename);
return i;
}
i = mailfiles_count++;
mailfiles = (FILEINFO **)xrealloc
(mailfiles, mailfiles_count * sizeof (FILEINFO *));
mailfiles[i] = (FILEINFO *)xmalloc (sizeof (FILEINFO));
mailfiles[i]->name = filename;
mailfiles[i]->msg = msg ? savestring (msg) : (char *)NULL;
update_mail_file (i);
return i;
}
void
reset_mail_files ()
{
register int i;
for (i = 0; i < mailfiles_count; i++)
{
RESET_MAIL_FILE (i);
}
}
void
free_mail_files ()
{
register int i;
for (i = 0; i < mailfiles_count; i++)
{
free (mailfiles[i]->name);
FREE (mailfiles[i]->msg);
free (mailfiles[i]);
}
if (mailfiles)
free (mailfiles);
mailfiles_count = 0;
mailfiles = (FILEINFO **)NULL;
}
static int
file_mod_date_changed (i)
int i;
{
time_t mtime;
struct stat finfo;
char *file;
file = mailfiles[i]->name;
mtime = mailfiles[i]->mod_time;
if ((mailstat (file, &finfo) == 0) && (finfo.st_size > 0))
return (mtime != finfo.st_mtime);
return (0);
}
static int
file_access_date_changed (i)
int i;
{
time_t atime;
struct stat finfo;
char *file;
file = mailfiles[i]->name;
atime = mailfiles[i]->access_time;
if ((mailstat (file, &finfo) == 0) && (finfo.st_size > 0))
return (atime != finfo.st_atime);
return (0);
}
static int
file_has_grown (i)
int i;
{
off_t size;
struct stat finfo;
char *file;
file = mailfiles[i]->name;
size = mailfiles[i]->file_size;
return ((mailstat (file, &finfo) == 0) && (finfo.st_size > size));
}
static char *
parse_mailpath_spec (str)
char *str;
{
char *s;
int pass_next;
for (s = str, pass_next = 0; s && *s; s++)
{
if (pass_next)
{
pass_next = 0;
continue;
}
if (*s == '\\')
{
pass_next++;
continue;
}
if (*s == '?' || *s == '%')
return s;
}
return ((char *)NULL);
}
char *
make_default_mailpath ()
{
char *mp;
get_current_user_info ();
mp = (char *)xmalloc (2 + sizeof (DEFAULT_MAIL_DIRECTORY) + strlen (current_user.user_name));
strcpy (mp, DEFAULT_MAIL_DIRECTORY);
mp[sizeof(DEFAULT_MAIL_DIRECTORY) - 1] = '/';
strcpy (mp + sizeof (DEFAULT_MAIL_DIRECTORY), current_user.user_name);
return (mp);
}
void
remember_mail_dates ()
{
char *mailpaths;
char *mailfile, *mp;
int i = 0;
mailpaths = get_string_value ("MAILPATH");
if (mailpaths == 0 && (mailpaths = get_string_value ("MAIL")))
{
add_mail_file (mailpaths, (char *)NULL);
return;
}
if (mailpaths == 0)
{
mailpaths = make_default_mailpath ();
add_mail_file (mailpaths, (char *)NULL);
free (mailpaths);
return;
}
while (mailfile = extract_colon_unit (mailpaths, &i))
{
mp = parse_mailpath_spec (mailfile);
if (mp && *mp)
*mp++ = '\0';
add_mail_file (mailfile, mp);
free (mailfile);
}
}
void
check_mail ()
{
char *current_mail_file, *message;
int i, use_user_notification;
char *dollar_underscore, *temp;
dollar_underscore = get_string_value ("_");
if (dollar_underscore)
dollar_underscore = savestring (dollar_underscore);
for (i = 0; i < mailfiles_count; i++)
{
current_mail_file = mailfiles[i]->name;
if (*current_mail_file == '\0')
continue;
if (file_mod_date_changed (i))
{
int file_is_bigger;
use_user_notification = mailfiles[i]->msg != (char *)NULL;
message = mailfiles[i]->msg ? mailfiles[i]->msg : "You have mail in $_";
bind_variable ("_", current_mail_file);
#define atime mailfiles[i]->access_time
#define mtime mailfiles[i]->mod_time
file_is_bigger = file_has_grown (i);
update_mail_file (i);
if ((atime >= mtime) || !file_is_bigger)
continue;
if (use_user_notification == 0 && (atime < mtime) && file_is_bigger)
message = "You have new mail in $_";
#undef atime
#undef mtime
if (temp = expand_string_to_string (message, Q_DOUBLE_QUOTES))
{
puts (temp);
free (temp);
}
else
putchar ('\n');
}
if (mail_warning && file_access_date_changed (i))
{
update_mail_file (i);
printf ("The mail in %s has been read\n", current_mail_file);
}
}
if (dollar_underscore)
{
bind_variable ("_", dollar_underscore);
free (dollar_underscore);
}
else
unbind_variable ("_");
}