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