1 /* $OpenBSD: mail.c,v 1.9 1999/06/15 01:18:35 millert 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 #if 0 190 /* 191 * I doubt this $_ overloading is bad in /bin/sh mode. Anyhow, we 192 * crash as the code looks now if we do not set vp. Now, this is 193 * easy to fix too, but I'd like to see what POSIX says before doing 194 * a change like that. 195 */ 196 if (!Flag(FSH)) 197 #endif 198 /* Ignore setstr errors here (arbitrary) */ 199 setstr((vp = local("_", FALSE)), mbp->mb_path, KSH_RETURN_ERROR); 200 201 shellf("%s\n", substitute(mbp->mb_msg ? mbp->mb_msg : MBMESSAGE, 0)); 202 203 unset(vp, 0); 204 } 205 #endif /* KSH */ 206