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