xref: /csrg-svn/libexec/comsat/comsat.c (revision 37257)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  */
17 
18 #ifndef lint
19 char copyright[] =
20 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
21  All rights reserved.\n";
22 #endif /* not lint */
23 
24 #ifndef lint
25 static char sccsid[] = "@(#)comsat.c	5.14 (Berkeley) 04/02/89";
26 #endif /* not lint */
27 
28 #include <sys/param.h>
29 #include <sys/socket.h>
30 #include <sys/stat.h>
31 #include <sys/file.h>
32 #include <sys/wait.h>
33 
34 #include <netinet/in.h>
35 
36 #include <stdio.h>
37 #include <sgtty.h>
38 #include <utmp.h>
39 #include <signal.h>
40 #include <errno.h>
41 #include <netdb.h>
42 #include <syslog.h>
43 #include <strings.h>
44 
45 #include "pathnames.h"
46 
47 /*
48  * comsat
49  */
50 int	debug = 0;
51 #define	dsyslog	if (debug) syslog
52 
53 #define MAXIDLE	120
54 
55 char	hostname[MAXHOSTNAMELEN];
56 struct	utmp *utmp = NULL;
57 time_t	lastmsgtime, time();
58 int	nutmp, uf;
59 
60 main(argc, argv)
61 	int argc;
62 	char **argv;
63 {
64 	extern int errno;
65 	register int cc;
66 	char msgbuf[100];
67 	struct sockaddr_in from;
68 	int fromlen, reapchildren(), onalrm();
69 
70 	/* verify proper invocation */
71 	fromlen = sizeof (from);
72 	if (getsockname(0, &from, &fromlen) < 0) {
73 		fprintf(stderr, "%s: ", argv[0]);
74 		perror("getsockname");
75 		exit(1);
76 	}
77 	openlog("comsat", LOG_PID, LOG_DAEMON);
78 	if (chdir(_PATH_MAIL)) {
79 		syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAIL);
80 		exit(1);
81 	}
82 	if ((uf = open(_PATH_UTMP, O_RDONLY, 0)) < 0) {
83 		syslog(LOG_ERR, ".main: %s: %m", _PATH_UTMP);
84 		(void) recv(0, msgbuf, sizeof (msgbuf) - 1, 0);
85 		exit(1);
86 	}
87 	(void)time(&lastmsgtime);
88 	(void)gethostname(hostname, sizeof (hostname));
89 	onalrm();
90 	(void)signal(SIGALRM, onalrm);
91 	(void)signal(SIGTTOU, SIG_IGN);
92 	(void)signal(SIGCHLD, reapchildren);
93 	for (;;) {
94 		cc = recv(0, msgbuf, sizeof (msgbuf) - 1, 0);
95 		if (cc <= 0) {
96 			if (errno != EINTR)
97 				sleep(1);
98 			errno = 0;
99 			continue;
100 		}
101 		if (!nutmp)		/* no one has logged in yet */
102 			continue;
103 		sigblock(sigmask(SIGALRM));
104 		msgbuf[cc] = 0;
105 		(void)time(&lastmsgtime);
106 		mailfor(msgbuf);
107 		sigsetmask(0L);
108 	}
109 }
110 
111 reapchildren()
112 {
113 	while (wait3((union wait *)NULL, WNOHANG, (struct rusage *)NULL) > 0);
114 }
115 
116 onalrm()
117 {
118 	static u_int utmpsize;		/* last malloced size for utmp */
119 	static u_int utmpmtime;		/* last modification time for utmp */
120 	struct stat statbf;
121 	off_t lseek();
122 	char *malloc(), *realloc();
123 
124 	if (time((time_t *)NULL) - lastmsgtime >= MAXIDLE)
125 		exit(0);
126 	(void)alarm((u_int)15);
127 	(void)fstat(uf, &statbf);
128 	if (statbf.st_mtime > utmpmtime) {
129 		utmpmtime = statbf.st_mtime;
130 		if (statbf.st_size > utmpsize) {
131 			utmpsize = statbf.st_size + 10 * sizeof(struct utmp);
132 			if (utmp)
133 				utmp = (struct utmp *)realloc((char *)utmp, utmpsize);
134 			else
135 				utmp = (struct utmp *)malloc(utmpsize);
136 			if (!utmp) {
137 				syslog(LOG_ERR, "malloc failed");
138 				exit(1);
139 			}
140 		}
141 		(void)lseek(uf, 0L, L_SET);
142 		nutmp = read(uf, utmp, (int)statbf.st_size)/sizeof(struct utmp);
143 	}
144 }
145 
146 mailfor(name)
147 	char *name;
148 {
149 	register struct utmp *utp = &utmp[nutmp];
150 	register char *cp;
151 	off_t offset, atol();
152 
153 	if (!(cp = index(name, '@')))
154 		return;
155 	*cp = '\0';
156 	offset = atoi(cp + 1);
157 	while (--utp >= utmp)
158 		if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name)))
159 			notify(utp, offset);
160 }
161 
162 static char	*cr;
163 
164 notify(utp, offset)
165 	register struct utmp *utp;
166 	off_t offset;
167 {
168 	static char tty[20] = "/dev/";
169 	struct sgttyb gttybuf;
170 	FILE *tp;
171 	char name[sizeof (utmp[0].ut_name) + 1];
172 	struct stat stb;
173 
174 	(void)strncpy(tty + 5, utp->ut_line, sizeof(utp->ut_line));
175 	if (stat(tty, &stb) || !(stb.st_mode & S_IEXEC)) {
176 		dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_name, tty);
177 		return;
178 	}
179 	dsyslog(LOG_DEBUG, "notify %s on %s\n", utp->ut_name, tty);
180 	if (fork())
181 		return;
182 	(void)signal(SIGALRM, SIG_DFL);
183 	(void)alarm((u_int)30);
184 	if ((tp = fopen(tty, "w")) == NULL) {
185 		dsyslog(LOG_ERR, "fopen of tty %s failed", tty);
186 		_exit(-1);
187 	}
188 	(void)ioctl(fileno(tp), TIOCGETP, &gttybuf);
189 	cr = (gttybuf.sg_flags&CRMOD) && !(gttybuf.sg_flags&RAW) ? "" : "\r";
190 	(void)strncpy(name, utp->ut_name, sizeof (utp->ut_name));
191 	name[sizeof (name) - 1] = '\0';
192 	fprintf(tp, "%s\n\007New mail for %s@%.*s\007 has arrived:%s\n----%s\n",
193 	    cr, name, sizeof (hostname), hostname, cr, cr);
194 	jkfprintf(tp, name, offset);
195 	fclose(tp);
196 	_exit(0);
197 }
198 
199 jkfprintf(tp, name, offset)
200 	register FILE *tp;
201 	char name[];
202 	off_t offset;
203 {
204 	register char *cp;
205 	register FILE *fi;
206 	register int linecnt, charcnt, inheader;
207 	char line[BUFSIZ];
208 	off_t fseek();
209 
210 	if ((fi = fopen(name, "r")) == NULL)
211 		return;
212 	(void)fseek(fi, offset, L_SET);
213 	/*
214 	 * Print the first 7 lines or 560 characters of the new mail
215 	 * (whichever comes first).  Skip header crap other than
216 	 * From, Subject, To, and Date.
217 	 */
218 	linecnt = 7;
219 	charcnt = 560;
220 	inheader = 1;
221 	while (fgets(line, sizeof (line), fi) != NULL) {
222 		if (inheader) {
223 			if (line[0] == '\n') {
224 				inheader = 0;
225 				continue;
226 			}
227 			if (line[0] == ' ' || line[0] == '\t' ||
228 			    strncmp(line, "From:", 5) &&
229 			    strncmp(line, "Subject:", 8))
230 				continue;
231 		}
232 		if (linecnt <= 0 || charcnt <= 0) {
233 			fprintf(tp, "...more...%s\n", cr);
234 			return;
235 		}
236 		if (cp = index(line, '\n'))
237 			*cp = '\0';
238 		fprintf(tp, "%s%s\n", line, cr);
239 		charcnt -= strlen(line);
240 		linecnt--;
241 	}
242 	fprintf(tp, "----%s\n", cr);
243 }
244