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