xref: /original-bsd/libexec/comsat/comsat.c (revision 81287ac5)
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, &gttybuf);
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