1 #ifndef lint 2 static char sccsid[] = "@(#)comsat.c 4.12 (Berkeley) 08/01/84"; 3 #endif 4 5 #include <sys/types.h> 6 #include <sys/socket.h> 7 #include <sys/stat.h> 8 #include <sys/wait.h> 9 #include <sys/file.h> 10 11 #include <netinet/in.h> 12 13 #include <stdio.h> 14 #include <sgtty.h> 15 #include <utmp.h> 16 #include <signal.h> 17 #include <errno.h> 18 #include <netdb.h> 19 #include <syslog.h> 20 21 /* 22 * comsat 23 */ 24 int debug = 0; 25 #define dprintf if (debug) printf 26 27 #define MAXUTMP 100 /* down from init */ 28 29 struct sockaddr_in sin = { AF_INET }; 30 extern errno; 31 32 char hostname[32]; 33 struct utmp utmp[100]; 34 int nutmp; 35 int uf; 36 unsigned utmpmtime; /* last modification time for utmp */ 37 int onalrm(); 38 int reapchildren(); 39 long lastmsgtime; 40 41 #define MAXIDLE 120 42 #define NAMLEN (sizeof (uts[0].ut_name) + 1) 43 44 main(argc, argv) 45 int argc; 46 char *argv[]; 47 { 48 register int cc; 49 char buf[BUFSIZ]; 50 char msgbuf[100]; 51 struct sockaddr_in from; 52 int fromlen; 53 54 /* verify proper invocation */ 55 fromlen = sizeof (from); 56 if (getsockname(0, &from, &fromlen) < 0) { 57 fprintf(stderr, "%s: ", argv[0]); 58 perror("getsockname"); 59 _exit(1); 60 } 61 chdir("/usr/spool/mail"); 62 if ((uf = open("/etc/utmp",0)) < 0) { 63 openlog("comsat", 0, 0); 64 syslog(LOG_ERR, "/etc/utmp: %m"); 65 (void) recv(0, msgbuf, sizeof (msgbuf) - 1, 0); 66 exit(1); 67 } 68 lastmsgtime = time(0); 69 gethostname(hostname, sizeof (hostname)); 70 onalrm(); 71 signal(SIGALRM, onalrm); 72 signal(SIGTTOU, SIG_IGN); 73 signal(SIGCHLD, reapchildren); 74 for (;;) { 75 cc = recv(0, msgbuf, sizeof (msgbuf) - 1, 0); 76 if (cc <= 0) { 77 if (errno != EINTR) 78 sleep(1); 79 errno = 0; 80 continue; 81 } 82 sigblock(1<<SIGALRM); 83 msgbuf[cc] = 0; 84 lastmsgtime = time(0); 85 mailfor(msgbuf); 86 sigsetmask(0); 87 } 88 } 89 90 reapchildren() 91 { 92 93 while (wait3((struct wait *)0, WNOHANG, (struct rusage *)0) > 0) 94 ; 95 } 96 97 onalrm() 98 { 99 struct stat statbf; 100 struct utmp *utp; 101 102 if (time(0) - lastmsgtime >= MAXIDLE) 103 exit(0); 104 dprintf("alarm\n"); 105 alarm(15); 106 fstat(uf, &statbf); 107 if (statbf.st_mtime > utmpmtime) { 108 dprintf(" changed\n"); 109 utmpmtime = statbf.st_mtime; 110 lseek(uf, 0, 0); 111 nutmp = read(uf,utmp,sizeof(utmp))/sizeof(struct utmp); 112 } else 113 dprintf(" ok\n"); 114 } 115 116 mailfor(name) 117 char *name; 118 { 119 register struct utmp *utp = &utmp[nutmp]; 120 register char *cp; 121 char *rindex(); 122 int offset; 123 124 dprintf("mailfor %s\n", name); 125 cp = name; 126 while (*cp && *cp != '@') 127 cp++; 128 if (*cp == 0) { 129 dprintf("bad format\n"); 130 return; 131 } 132 *cp = 0; 133 offset = atoi(cp+1); 134 while (--utp >= utmp) 135 if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name))) 136 notify(utp, offset); 137 } 138 139 char *cr; 140 141 notify(utp, offset) 142 register struct utmp *utp; 143 { 144 int fd, flags, n, err, msglen; 145 struct sgttyb gttybuf; 146 char tty[20], msgbuf[BUFSIZ]; 147 char name[sizeof (utmp[0].ut_name) + 1]; 148 struct stat stb; 149 150 strcpy(tty, "/dev/"); 151 strncat(tty, utp->ut_line, sizeof(utp->ut_line)); 152 dprintf("notify %s on %s\n", utp->ut_name, tty); 153 if (stat(tty, &stb) == 0 && (stb.st_mode & 0100) == 0) { 154 dprintf("wrong mode\n"); 155 return; 156 } 157 if ((fd = open(tty, O_WRONLY|O_NDELAY)) < 0) { 158 dprintf("%s: open failed\n", tty); 159 return; 160 } 161 if ((flags = fcntl(fd, F_GETFL, 0)) == -1) { 162 dprintf("fcntl(F_GETFL) failed %d\n", errno); 163 return; 164 } 165 ioctl(fd, TIOCGETP, >tybuf); 166 cr = (gttybuf.sg_flags & CRMOD) ? "" : "\r"; 167 strncpy(name, utp->ut_name, sizeof (utp->ut_name)); 168 name[sizeof (name) - 1] = '\0'; 169 sprintf(msgbuf, "%s\n\007New mail for %s@%s\007 has arrived:%s\n", 170 cr, name, hostname, cr); 171 jkfprintf(msgbuf+strlen(msgbuf), name, offset); 172 if (fcntl(fd, F_SETFL, flags | FNDELAY) == -1) 173 goto oldway; 174 msglen = strlen(msgbuf); 175 n = write(fd, msgbuf, msglen); 176 err = errno; 177 (void) fcntl(fd, F_SETFL, flags); 178 (void) close(fd); 179 if (n == msglen) 180 return; 181 if (err != EWOULDBLOCK) { 182 dprintf("write failed %d\n", errno); 183 return; 184 } 185 oldway: 186 if (fork()) { 187 (void) close(fd); 188 return; 189 } 190 signal(SIGALRM, SIG_DFL); 191 alarm(30); 192 (void) write(fd, msgbuf, msglen); 193 exit(0); 194 } 195 196 jkfprintf(mp, name, offset) 197 register char *mp; 198 { 199 register FILE *fi; 200 register int linecnt, charcnt; 201 char line[BUFSIZ]; 202 int inheader; 203 204 dprintf("HERE %s's mail starting at %d\n", name, offset); 205 206 if ((fi = fopen(name, "r")) == NULL) { 207 dprintf("Cant read the mail\n"); 208 return; 209 } 210 fseek(fi, offset, L_SET); 211 /* 212 * Print the first 7 lines or 560 characters of the new mail 213 * (whichever comes first). Skip header crap other than 214 * From, Subject, To, and Date. 215 */ 216 linecnt = 7; 217 charcnt = 560; 218 inheader = 1; 219 while (fgets(line, sizeof (line), fi) != NULL) { 220 register char *cp; 221 char *index(); 222 int cnt; 223 224 if (linecnt <= 0 || charcnt <= 0) { 225 sprintf(mp, "...more...%s\n", cr); 226 mp += strlen(mp); 227 return; 228 } 229 if (strncmp(line, "From ", 5) == 0) 230 continue; 231 if (inheader && (line[0] == ' ' || line[0] == '\t')) 232 continue; 233 cp = index(line, ':'); 234 if (cp == 0 || (index(line, ' ') && index(line, ' ') < cp)) 235 inheader = 0; 236 else 237 cnt = cp - line; 238 if (inheader && 239 strncmp(line, "Date", cnt) && 240 strncmp(line, "From", cnt) && 241 strncmp(line, "Subject", cnt) && 242 strncmp(line, "To", cnt)) 243 continue; 244 cp = index(line, '\n'); 245 if (cp) 246 *cp = '\0'; 247 sprintf(mp, "%s%s\n", line, cr); 248 mp += strlen(mp); 249 linecnt--, charcnt -= strlen(line); 250 } 251 sprintf(mp, "----%s\n", cr); 252 mp += strlen(mp); 253 } 254