1 /* mailcheck.c -- The check is in the mail... */
3 /* Copyright (C) 1987,1989 Free Software Foundation, Inc.
5 This file is part of GNU Bash, the Bourne Again SHell.
7 Bash is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 1, or (at your option) any later
12 Bash is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with Bash; see the file COPYING. If not, write to the Free Software
19 Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
22 #include "bashtypes.h"
23 #include "posixstat.h"
24 #include <sys/param.h>
28 #include "execute_cmd.h"
29 #include <tilde/tilde.h>
32 #define NOW ((time_t)time ((time_t *)0))
42 /* The list of remembered mail files. */
43 FILEINFO **mailfiles = (FILEINFO **)NULL;
45 /* Number of mail files that we have. */
46 int mailfiles_count = 0;
48 /* The last known time that mail was checked. */
49 int last_time_mail_checked = 0;
51 /* Returns non-zero if it is time to check mail. */
55 char *temp = get_string_value ("MAILCHECK");
59 /* Skip leading whitespace in MAILCHECK. */
62 while (whitespace (*temp))
65 seconds = atoi (temp);
68 /* Negative number, or non-numbers (such as empty string) cause no
69 checking to take place. */
73 /* Time to check if MAILCHECK is explicitly set to zero, or if enough
74 time has passed since the last check. */
75 return (!seconds || ((now - last_time_mail_checked) >= seconds));
78 /* Okay, we have checked the mail. Perhaps I should make this function
83 last_time_mail_checked = NOW;
86 /* Locate a file in the list. Return index of
87 entry, or -1 if not found. */
94 for (i = 0; i < mailfiles_count; i++)
95 if (STREQ ((mailfiles[i])->name, file))
101 /* Add this file to the list of remembered files and return its index
102 in the list of mail files. */
111 filename = full_pathname (file);
112 i = find_mail_file (file);
115 if (stat (filename, &finfo) == 0)
117 mailfiles[i]->mod_time = finfo.st_mtime;
118 mailfiles[i]->access_time = finfo.st_atime;
119 mailfiles[i]->file_size = (long)finfo.st_size;
125 i = mailfiles_count++;
126 mailfiles = (FILEINFO **)xrealloc
127 (mailfiles, mailfiles_count * sizeof (FILEINFO *));
129 mailfiles[i] = (FILEINFO *)xmalloc (sizeof (FILEINFO));
130 mailfiles[i]->name = filename;
131 if (stat (filename, &finfo) == 0)
133 mailfiles[i]->access_time = finfo.st_atime;
134 mailfiles[i]->mod_time = finfo.st_mtime;
135 mailfiles[i]->file_size = finfo.st_size;
139 mailfiles[i]->access_time = mailfiles[i]->mod_time = (time_t)-1;
140 mailfiles[i]->file_size = -1L;
145 /* Reset the existing mail files access and modification times to zero. */
151 for (i = 0; i < mailfiles_count; i++)
153 mailfiles[i]->access_time = mailfiles[i]->mod_time = 0;
154 mailfiles[i]->file_size = 0L;
158 /* Free the information that we have about the remembered mail files. */
164 for (i = 0; i < mailfiles_count; i++)
166 free (mailfiles[i]->name);
174 mailfiles = (FILEINFO **)NULL;
177 /* Return non-zero if FILE's mod date has changed and it has not been
178 accessed since modified. */
180 file_mod_date_changed (file)
183 time_t time = (time_t)0;
187 i = find_mail_file (file);
189 time = mailfiles[i]->mod_time;
191 if ((stat (file, &finfo) == 0) && (finfo.st_size > 0))
192 return (time != finfo.st_mtime);
197 /* Return non-zero if FILE's access date has changed. */
199 file_access_date_changed (file)
202 time_t time = (time_t)0;
206 i = find_mail_file (file);
208 time = mailfiles[i]->access_time;
210 if ((stat (file, &finfo) == 0) && (finfo.st_size > 0))
211 return (time != finfo.st_atime);
216 /* Return non-zero if FILE's size has increased. */
218 file_has_grown (file)
225 i = find_mail_file (file);
227 size = mailfiles[i]->file_size;
229 return ((stat (file, &finfo) == 0) && (finfo.st_size > size));
233 make_default_mailpath ()
237 mp = xmalloc (1 + sizeof (DEFAULT_MAIL_PATH) + strlen (current_user.user_name));
238 strcpy (mp, DEFAULT_MAIL_PATH);
239 strcpy (mp + sizeof (DEFAULT_MAIL_PATH) - 1, current_user.user_name);
243 /* Return the colon separated list of pathnames to check for mail. */
249 mailpaths = get_string_value ("MAILPATH");
252 mailpaths = get_string_value ("MAIL");
255 return (savestring (mailpaths));
257 return (make_default_mailpath ());
260 /* Take an element from $MAILPATH and return the portion from
261 the first unquoted `?' or `%' to the end of the string. This is the
262 message to be printed when the file contents change. */
264 parse_mailpath_spec (str)
270 for (s = str, pass_next = 0; s && *s; s++)
282 if (*s == '?' || *s == '%')
285 return ((char *)NULL);
288 /* Remember the dates of the files specified by MAILPATH, or if there is
289 no MAILPATH, by the file specified in MAIL. If neither exists, use a
290 default value, which we randomly concoct from using Unix. */
292 remember_mail_dates ()
298 mailpaths = get_mailpaths ();
299 while (mailfile = extract_colon_unit (mailpaths, &i))
301 mp = parse_mailpath_spec (mailfile);
304 add_mail_file (mailfile);
310 /* check_mail () is useful for more than just checking mail. Since it has
311 the paranoids dream ability of telling you when someone has read your
312 mail, it can just as easily be used to tell you when someones .profile
313 file has been read, thus letting one know when someone else has logged
314 in. Pretty good, huh? */
316 /* Check for mail in some files. If the modification date of any
317 of the files in MAILPATH has changed since we last did a
318 remember_mail_dates () then mention that the user has mail.
319 Special hack: If the shell variable MAIL_WARNING is on and the
320 mail file has been accessed since the last time we remembered, then
321 the message "The mail in <mailfile> has been read" is printed. */
325 char *current_mail_file, *you_have_mail_message;
326 char *mailpaths, *mp;
328 char *dollar_underscore;
330 dollar_underscore = get_string_value ("_");
332 if (dollar_underscore)
333 dollar_underscore = savestring (dollar_underscore);
335 mailpaths = get_mailpaths ();
336 while ((current_mail_file = extract_colon_unit (mailpaths, &file_index)))
339 int use_user_notification;
341 if (!*current_mail_file)
343 free (current_mail_file);
347 t = full_pathname (current_mail_file);
348 free (current_mail_file);
349 current_mail_file = t;
351 use_user_notification = 0;
352 you_have_mail_message = "You have mail in $_";
354 mp = parse_mailpath_spec (current_mail_file);
358 you_have_mail_message = ++mp;
359 use_user_notification++;
362 if (file_mod_date_changed (current_mail_file))
365 int i, file_is_bigger;
366 bind_variable ("_", current_mail_file);
367 #define atime mailfiles[i]->access_time
368 #define mtime mailfiles[i]->mod_time
370 /* Have to compute this before the call to add_mail_file, which
371 resets all the information. */
372 file_is_bigger = file_has_grown (current_mail_file);
374 i = add_mail_file (current_mail_file);
377 continue; /* if this returns -1 , it is a bug */
379 /* If the user has just run a program which manipulates the
380 mail file, then don't bother explaining that the mail
381 file has been manipulated. Since some systems don't change
382 the access time to be equal to the modification time when
383 the mail in the file is manipulated, check the size also. If
384 the file has not grown, continue. */
385 if ((atime >= mtime) && !file_is_bigger)
387 free (current_mail_file);
391 /* If the mod time is later than the access time and the file
392 has grown, note the fact that this is *new* mail. */
393 if (!use_user_notification && (atime < mtime) && file_is_bigger)
394 you_have_mail_message = "You have new mail in $_";
398 if ((tlist = expand_string (you_have_mail_message, 1)))
400 char *tem = string_list (tlist);
401 printf ("%s\n", tem);
403 dispose_words (tlist);
409 if (find_variable ("MAIL_WARNING") &&
410 file_access_date_changed (current_mail_file))
412 add_mail_file (current_mail_file);
413 printf ("The mail in %s has been read!\n", current_mail_file);
416 free (current_mail_file);
420 if (dollar_underscore)
422 bind_variable ("_", dollar_underscore);
423 free (dollar_underscore);
426 unbind_variable ("_");