Home | History | Annotate | Line # | Download | only in ksh
mail.c revision 1.5
      1 /*	$NetBSD: mail.c,v 1.5 2006/01/15 18:16:30 jschauma Exp $	*/
      2 
      3 /*
      4  * Mailbox checking code by Robert J. Gibson, adapted for PD ksh by
      5  * John R. MacMillan
      6  */
      7 #include <sys/cdefs.h>
      8 
      9 #ifndef lint
     10 __RCSID("$NetBSD: mail.c,v 1.5 2006/01/15 18:16:30 jschauma Exp $");
     11 #endif
     12 
     13 
     14 #include "config.h"
     15 
     16 #ifdef KSH
     17 #include "sh.h"
     18 #include "ksh_stat.h"
     19 #include "ksh_time.h"
     20 
     21 #define MBMESSAGE	"You have mail in $_"
     22 
     23 typedef struct mbox {
     24 	struct mbox    *mb_next;	/* next mbox in list */
     25 	char	       *mb_path;	/* path to mail file */
     26 	char	       *mb_msg;		/* to announce arrival of new mail */
     27 	time_t		mb_mtime;	/* mtime of mail file */
     28 } mbox_t;
     29 
     30 /*
     31  * $MAILPATH is a linked list of mboxes.  $MAIL is a treated as a
     32  * special case of $MAILPATH, where the list has only one node.  The
     33  * same list is used for both since they are exclusive.
     34  */
     35 
     36 static mbox_t	*mplist;
     37 static mbox_t	mbox;
     38 static time_t	mlastchkd;	/* when mail was last checked */
     39 static time_t	mailcheck_interval;
     40 
     41 static void     munset      ARGS((mbox_t *mlist)); /* free mlist and mval */
     42 static mbox_t * mballoc     ARGS((char *p, char *m)); /* allocate a new mbox */
     43 static void     mprintit    ARGS((mbox_t *mbp));
     44 
     45 void
     46 mcheck()
     47 {
     48 	register mbox_t	*mbp;
     49 	time_t		 now;
     50 	struct tbl	*vp;
     51 	struct stat	 stbuf;
     52 
     53 	now = time((time_t *) 0);
     54 	if (mlastchkd == 0)
     55 		mlastchkd = now;
     56 	if (now - mlastchkd >= mailcheck_interval) {
     57 		mlastchkd = now;
     58 
     59 		if (mplist)
     60 			mbp = mplist;
     61 		else if ((vp = global("MAIL")) && (vp->flag & ISSET))
     62 			mbp = &mbox;
     63 		else
     64 			mbp = NULL;
     65 
     66 		while (mbp) {
     67 			if (mbp->mb_path && stat(mbp->mb_path, &stbuf) == 0
     68 			    && S_ISREG(stbuf.st_mode))
     69 			{
     70 				if (stbuf.st_size
     71 				    && mbp->mb_mtime != stbuf.st_mtime
     72 				    && stbuf.st_atime <= stbuf.st_mtime)
     73 					mprintit(mbp);
     74 				mbp->mb_mtime = stbuf.st_mtime;
     75 			} else {
     76 				/*
     77 				 * Some mail readers remove the mail
     78 				 * file if all mail is read.  If file
     79 				 * does not exist, assume this is the
     80 				 * case and set mtime to zero.
     81 				 */
     82 				mbp->mb_mtime = 0;
     83 			}
     84 			mbp = mbp->mb_next;
     85 		}
     86 	}
     87 }
     88 
     89 void
     90 mcset(interval)
     91 	long interval;
     92 {
     93 	mailcheck_interval = interval;
     94 }
     95 
     96 void
     97 mbset(p)
     98 	register char	*p;
     99 {
    100 	struct stat	stbuf;
    101 
    102 	if (mbox.mb_msg)
    103 		afree((void *)mbox.mb_msg, APERM);
    104 	if (mbox.mb_path)
    105 		afree((void *)mbox.mb_path, APERM);
    106 	/* Save a copy to protect from export (which munges the string) */
    107 	mbox.mb_path = str_save(p, APERM);
    108 	mbox.mb_msg = NULL;
    109 	if (p && stat(p, &stbuf) == 0 && S_ISREG(stbuf.st_mode))
    110 		mbox.mb_mtime = stbuf.st_mtime;
    111 	else
    112 		mbox.mb_mtime = 0;
    113 }
    114 
    115 void
    116 mpset(mptoparse)
    117 	register char	*mptoparse;
    118 {
    119 	register mbox_t	*mbp;
    120 	register char	*mpath, *mmsg, *mval;
    121 	char *p;
    122 
    123 	munset( mplist );
    124 	mplist = NULL;
    125 	mval = str_save(mptoparse, APERM);
    126 	while (mval) {
    127 		mpath = mval;
    128 		if ((mval = strchr(mval, PATHSEP)) != NULL) {
    129 			*mval = '\0', mval++;
    130 		}
    131 		/* POSIX/bourne-shell say file%message */
    132 		for (p = mpath; (mmsg = strchr(p, '%')); ) {
    133 			/* a literal percent? (POSIXism) */
    134 			if (mmsg[-1] == '\\') {
    135 				/* use memmove() to avoid overlap problems */
    136 				memmove(mmsg - 1, mmsg, strlen(mmsg) + 1);
    137 				p = mmsg + 1;
    138 				continue;
    139 			}
    140 			break;
    141 		}
    142 		/* at&t ksh says file?message */
    143 		if (!mmsg && !Flag(FPOSIX))
    144 			mmsg = strchr(mpath, '?');
    145 		if (mmsg) {
    146 			*mmsg = '\0';
    147 			mmsg++;
    148 		}
    149 		mbp = mballoc(mpath, mmsg);
    150 		mbp->mb_next = mplist;
    151 		mplist = mbp;
    152 	}
    153 }
    154 
    155 static void
    156 munset(mlist)
    157 register mbox_t	*mlist;
    158 {
    159 	register mbox_t	*mbp;
    160 
    161 	while (mlist != NULL) {
    162 		mbp = mlist;
    163 		mlist = mbp->mb_next;
    164 		if (!mlist)
    165 			afree((void *)mbp->mb_path, APERM);
    166 		afree((void *)mbp, APERM);
    167 	}
    168 }
    169 
    170 static mbox_t *
    171 mballoc(p, m)
    172 	char	*p;
    173 	char	*m;
    174 {
    175 	struct stat	stbuf;
    176 	register mbox_t	*mbp;
    177 
    178 	mbp = (mbox_t *)alloc(sizeof(mbox_t), APERM);
    179 	mbp->mb_next = NULL;
    180 	mbp->mb_path = p;
    181 	mbp->mb_msg = m;
    182 	if (stat(mbp->mb_path, &stbuf) == 0 && S_ISREG(stbuf.st_mode))
    183 		mbp->mb_mtime = stbuf.st_mtime;
    184 	else
    185 		mbp->mb_mtime = 0;
    186 	return(mbp);
    187 }
    188 
    189 static void
    190 mprintit( mbp )
    191 mbox_t	*mbp;
    192 {
    193 	struct tbl	*vp;
    194 
    195 	/* Ignore setstr errors here (arbitrary) */
    196 	setstr((vp = local("_", FALSE)), mbp->mb_path, KSH_RETURN_ERROR);
    197 
    198 	shellf("%s\n", substitute(mbp->mb_msg ? mbp->mb_msg : MBMESSAGE, 0));
    199 
    200 	unset(vp, 0);
    201 }
    202 #endif /* KSH */
    203