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