xref: /original-bsd/libexec/comsat/comsat.c (revision f1656be1)
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 this notice is preserved and that due credit is given
7  * to the University of California at Berkeley. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific written prior permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  */
12 
13 #ifndef lint
14 char copyright[] =
15 "@(#) Copyright (c) 1980 Regents of the University of California.\n\
16  All rights reserved.\n";
17 #endif /* not lint */
18 
19 #ifndef lint
20 static char sccsid[] = "@(#)comsat.c	5.11 (Berkeley) 03/29/88";
21 #endif /* not lint */
22 
23 #include <sys/param.h>
24 #include <sys/socket.h>
25 #include <sys/stat.h>
26 #include <sys/file.h>
27 #include <sys/wait.h>
28 
29 #include <netinet/in.h>
30 
31 #include <stdio.h>
32 #include <sgtty.h>
33 #include <utmp.h>
34 #include <signal.h>
35 #include <errno.h>
36 #include <netdb.h>
37 #include <syslog.h>
38 #include <strings.h>
39 
40 /*
41  * comsat
42  */
43 int	debug = 0;
44 #define	dsyslog	if (debug) syslog
45 
46 #define MAXIDLE	120
47 
48 char	hostname[MAXHOSTNAMELEN];
49 struct	utmp *utmp = NULL;
50 time_t	lastmsgtime, time();
51 int	nutmp, uf;
52 
53 main(argc, argv)
54 	int argc;
55 	char **argv;
56 {
57 	extern int errno;
58 	register int cc;
59 	char msgbuf[100];
60 	struct sockaddr_in from;
61 	int fromlen, reapchildren(), onalrm();
62 
63 	/* verify proper invocation */
64 	fromlen = sizeof (from);
65 	if (getsockname(0, &from, &fromlen) < 0) {
66 		fprintf(stderr, "%s: ", argv[0]);
67 		perror("getsockname");
68 		exit(1);
69 	}
70 	openlog("comsat", LOG_PID, LOG_DAEMON);
71 	if (chdir("/usr/spool/mail")) {
72 		syslog(LOG_ERR, "chdir: /usr/spool/mail");
73 		exit(1);
74 	}
75 	if ((uf = open("/etc/utmp", O_RDONLY, 0)) < 0) {
76 		syslog(LOG_ERR, ".main: /etc/utmp: %m");
77 		(void) recv(0, msgbuf, sizeof (msgbuf) - 1, 0);
78 		exit(1);
79 	}
80 	(void)time(&lastmsgtime);
81 	(void)gethostname(hostname, sizeof (hostname));
82 	onalrm();
83 	(void)signal(SIGALRM, onalrm);
84 	(void)signal(SIGTTOU, SIG_IGN);
85 	(void)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 		if (!nutmp)		/* no one has logged in yet */
95 			continue;
96 		sigblock(sigmask(SIGALRM));
97 		msgbuf[cc] = 0;
98 		(void)time(&lastmsgtime);
99 		mailfor(msgbuf);
100 		sigsetmask(0L);
101 	}
102 }
103 
104 reapchildren()
105 {
106 	while (wait3((union wait *)NULL, WNOHANG, (struct rusage *)NULL) > 0);
107 }
108 
109 onalrm()
110 {
111 	static u_int utmpsize;		/* last malloced size for utmp */
112 	static u_int utmpmtime;		/* last modification time for utmp */
113 	struct stat statbf;
114 	off_t lseek();
115 	char *malloc(), *realloc();
116 
117 	if (time((time_t *)NULL) - lastmsgtime >= MAXIDLE)
118 		exit(0);
119 	(void)alarm((u_int)15);
120 	(void)fstat(uf, &statbf);
121 	if (statbf.st_mtime > utmpmtime) {
122 		utmpmtime = statbf.st_mtime;
123 		if (statbf.st_size > utmpsize) {
124 			utmpsize = statbf.st_size + 10 * sizeof(struct utmp);
125 			if (utmp)
126 				utmp = (struct utmp *)realloc((char *)utmp, utmpsize);
127 			else
128 				utmp = (struct utmp *)malloc(utmpsize);
129 			if (!utmp) {
130 				syslog(LOG_ERR, "malloc failed");
131 				exit(1);
132 			}
133 		}
134 		(void)lseek(uf, 0L, L_SET);
135 		nutmp = read(uf, utmp, (int)statbf.st_size)/sizeof(struct utmp);
136 	}
137 }
138 
139 mailfor(name)
140 	char *name;
141 {
142 	register struct utmp *utp = &utmp[nutmp];
143 	register char *cp;
144 	off_t offset, atol();
145 
146 	if (!(cp = index(name, '@')))
147 		return;
148 	*cp = '\0';
149 	offset = atoi(cp + 1);
150 	while (--utp >= utmp)
151 		if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name)))
152 			notify(utp, offset);
153 }
154 
155 static char	*cr;
156 
157 notify(utp, offset)
158 	register struct utmp *utp;
159 	off_t offset;
160 {
161 	static char tty[20] = "/dev/";
162 	struct sgttyb gttybuf;
163 	FILE *tp;
164 	char name[sizeof (utmp[0].ut_name) + 1];
165 	struct stat stb;
166 
167 	(void)strncpy(tty + 5, utp->ut_line, sizeof(utp->ut_line));
168 	if (stat(tty, &stb) || !(stb.st_mode & S_IEXEC)) {
169 		dsyslog(LOG_DEBUG, "%s: wrong mode on %s", utp->ut_name, tty);
170 		return;
171 	}
172 	dsyslog(LOG_DEBUG, "notify %s on %s\n", utp->ut_name, tty);
173 	if (fork())
174 		return;
175 	(void)signal(SIGALRM, SIG_DFL);
176 	(void)alarm((u_int)30);
177 	if ((tp = fopen(tty, "w")) == NULL) {
178 		dsyslog(LOG_ERR, "fopen of tty %s failed", tty);
179 		_exit(-1);
180 	}
181 	(void)ioctl(fileno(tp), TIOCGETP, &gttybuf);
182 	cr = (gttybuf.sg_flags&CRMOD) && !(gttybuf.sg_flags&RAW) ? "" : "\r";
183 	(void)strncpy(name, utp->ut_name, sizeof (utp->ut_name));
184 	name[sizeof (name) - 1] = '\0';
185 	fprintf(tp, "%s\n\007New mail for %s@%.*s\007 has arrived:%s\n----%s\n",
186 	    cr, name, sizeof (hostname), hostname, cr, cr);
187 	jkfprintf(tp, name, offset);
188 	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;
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 (cp = index(line, '\n'))
226 			*cp = '\0';
227 		fprintf(tp, "%s%s\n", line, cr);
228 		charcnt -= strlen(line);
229 		if (--linecnt <= 0 || charcnt <= 0) {
230 			fprintf(tp, "...more...%s\n", cr);
231 			return;
232 		}
233 	}
234 	fprintf(tp, "----%s\n", cr);
235 }
236