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