xref: /original-bsd/libexec/comsat/comsat.c (revision f5cc5b3e)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)comsat.c	5.22 (Berkeley) 06/24/90";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/socket.h>
20 #include <sys/stat.h>
21 #include <sys/file.h>
22 #include <sys/wait.h>
23 
24 #include <netinet/in.h>
25 
26 #include <stdio.h>
27 #include <sgtty.h>
28 #include <utmp.h>
29 #include <signal.h>
30 #include <errno.h>
31 #include <netdb.h>
32 #include <syslog.h>
33 #include <ctype.h>
34 #include <string.h>
35 #include <paths.h>
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 /* ARGSUSED */
48 main(argc, argv)
49 	int argc;
50 	char **argv;
51 {
52 	extern int errno;
53 	register int cc;
54 	char msgbuf[100];
55 	struct sockaddr_in from;
56 	int fromlen;
57 	void onalrm(), reapchildren();
58 
59 	/* verify proper invocation */
60 	fromlen = sizeof(from);
61 	if (getsockname(0, &from, &fromlen) < 0) {
62 		(void)fprintf(stderr,
63 		    "comsat: getsockname: %s.\n", strerror(errno));
64 		exit(1);
65 	}
66 	openlog("comsat", LOG_PID, LOG_DAEMON);
67 	if (chdir(_PATH_MAILDIR)) {
68 		syslog(LOG_ERR, "chdir: %s: %m", _PATH_MAILDIR);
69 		exit(1);
70 	}
71 	if ((uf = open(_PATH_UTMP, O_RDONLY, 0)) < 0) {
72 		syslog(LOG_ERR, ".main: %s: %m", _PATH_UTMP);
73 		(void) recv(0, msgbuf, sizeof(msgbuf) - 1, 0);
74 		exit(1);
75 	}
76 	(void)time(&lastmsgtime);
77 	(void)gethostname(hostname, sizeof(hostname));
78 	onalrm();
79 	(void)signal(SIGALRM, onalrm);
80 	(void)signal(SIGTTOU, SIG_IGN);
81 	(void)signal(SIGCHLD, reapchildren);
82 	for (;;) {
83 		cc = recv(0, msgbuf, sizeof(msgbuf) - 1, 0);
84 		if (cc <= 0) {
85 			if (errno != EINTR)
86 				sleep(1);
87 			errno = 0;
88 			continue;
89 		}
90 		if (!nutmp)		/* no one has logged in yet */
91 			continue;
92 		sigblock(sigmask(SIGALRM));
93 		msgbuf[cc] = 0;
94 		(void)time(&lastmsgtime);
95 		mailfor(msgbuf);
96 		sigsetmask(0L);
97 	}
98 }
99 
100 void
101 reapchildren()
102 {
103 	while (wait3((union wait *)NULL, WNOHANG, (struct rusage *)NULL) > 0);
104 }
105 
106 void
107 onalrm()
108 {
109 	static u_int utmpsize;		/* last malloced size for utmp */
110 	static u_int utmpmtime;		/* last modification time for utmp */
111 	struct stat statbf;
112 	off_t lseek();
113 	char *malloc(), *realloc();
114 
115 	if (time((time_t *)NULL) - lastmsgtime >= MAXIDLE)
116 		exit(0);
117 	(void)alarm((u_int)15);
118 	(void)fstat(uf, &statbf);
119 	if (statbf.st_mtime > utmpmtime) {
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((char *)utmp, utmpsize);
125 			else
126 				utmp = (struct utmp *)malloc(utmpsize);
127 			if (!utmp) {
128 				syslog(LOG_ERR, "malloc failed");
129 				exit(1);
130 			}
131 		}
132 		(void)lseek(uf, 0L, L_SET);
133 		nutmp = read(uf, utmp, (int)statbf.st_size)/sizeof(struct utmp);
134 	}
135 }
136 
137 mailfor(name)
138 	char *name;
139 {
140 	register struct utmp *utp = &utmp[nutmp];
141 	register char *cp;
142 	off_t offset;
143 
144 	if (!(cp = index(name, '@')))
145 		return;
146 	*cp = '\0';
147 	offset = atoi(cp + 1);
148 	while (--utp >= utmp)
149 		if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name)))
150 			notify(utp, offset);
151 }
152 
153 static char *cr;
154 
155 notify(utp, offset)
156 	register struct utmp *utp;
157 	off_t offset;
158 {
159 	static char tty[20] = _PATH_DEV;
160 	struct sgttyb gttybuf;
161 	struct stat stb;
162 	FILE *tp;
163 	char name[sizeof(utmp[0].ut_name) + 1];
164 
165 	(void)strncpy(tty + sizeof(_PATH_DEV) - 1, utp->ut_line,
166 	    sizeof(utp->ut_line));
167 	if (stat(tty, &stb) || !(stb.st_mode & S_IEXEC)) {
168 		dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_name, tty);
169 		return;
170 	}
171 	dsyslog(LOG_DEBUG, "notify %s on %s\n", utp->ut_name, tty);
172 	if (fork())
173 		return;
174 	(void)signal(SIGALRM, SIG_DFL);
175 	(void)alarm((u_int)30);
176 	if ((tp = fopen(tty, "w")) == NULL) {
177 		dsyslog(LOG_ERR, "fopen of tty %s failed", tty);
178 		_exit(-1);
179 	}
180 	(void)ioctl(fileno(tp), TIOCGETP, &gttybuf);
181 	cr = (gttybuf.sg_flags&CRMOD) && !(gttybuf.sg_flags&RAW) ?
182 	    "\n" : "\n\r";
183 	(void)strncpy(name, utp->ut_name, sizeof(utp->ut_name));
184 	name[sizeof(name) - 1] = '\0';
185 	(void)fprintf(tp, "%s\007New mail for %s@%.*s\007 has arrived:%s----%s",
186 	    cr, name, sizeof(hostname), hostname, cr, cr);
187 	jkfprintf(tp, name, offset);
188 	(void)fclose(tp);
189 	_exit(0);
190 }
191 
192 jkfprintf(tp, name, offset)
193 	register FILE *tp;
194 	char name[];
195 	off_t offset;
196 {
197 	register char *cp, ch;
198 	register FILE *fi;
199 	register int linecnt, charcnt, inheader;
200 	char line[BUFSIZ];
201 	off_t fseek();
202 
203 	if ((fi = fopen(name, "r")) == NULL)
204 		return;
205 	(void)fseek(fi, offset, L_SET);
206 	/*
207 	 * Print the first 7 lines or 560 characters of the new mail
208 	 * (whichever comes first).  Skip header crap other than
209 	 * From, Subject, To, and Date.
210 	 */
211 	linecnt = 7;
212 	charcnt = 560;
213 	inheader = 1;
214 	while (fgets(line, sizeof(line), fi) != NULL) {
215 		if (inheader) {
216 			if (line[0] == '\n') {
217 				inheader = 0;
218 				continue;
219 			}
220 			if (line[0] == ' ' || line[0] == '\t' ||
221 			    strncmp(line, "From:", 5) &&
222 			    strncmp(line, "Subject:", 8))
223 				continue;
224 		}
225 		if (linecnt <= 0 || charcnt <= 0) {
226 			(void)fprintf(tp, "...more...%s", cr);
227 			return;
228 		}
229 		/* strip weird stuff so can't trojan horse stupid terminals */
230 		for (cp = line; (ch = *cp) && ch != '\n'; ++cp, --charcnt) {
231 			ch = toascii(ch);
232 			if (!isprint(ch) && !isspace(ch))
233 				ch |= 0x40;
234 			(void)fputc(ch, tp);
235 		}
236 		(void)fputs(cr, tp);
237 		--linecnt;
238 	}
239 	(void)fprintf(tp, "----%s\n", cr);
240 }
241