xref: /csrg-svn/libexec/comsat/comsat.c (revision 22545)
1 #ifndef lint
2 static	char sccsid[] = "@(#)comsat.c	4.14 (Berkeley) 06/06/85";
3 #endif
4 
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <sys/stat.h>
8 #include <sys/wait.h>
9 #include <sys/file.h>
10 
11 #include <netinet/in.h>
12 
13 #include <stdio.h>
14 #include <sgtty.h>
15 #include <utmp.h>
16 #include <signal.h>
17 #include <errno.h>
18 #include <netdb.h>
19 #include <syslog.h>
20 
21 /*
22  * comsat
23  */
24 int	debug = 0;
25 #define	dprintf	if (debug) printf
26 
27 struct	sockaddr_in sin = { AF_INET };
28 extern	errno;
29 
30 char	hostname[32];
31 struct	utmp *utmp = NULL;
32 int	nutmp;
33 int	uf;
34 unsigned utmpmtime = 0;			/* last modification time for utmp */
35 unsigned utmpsize = 0;			/* last malloced size for utmp */
36 int	onalrm();
37 int	reapchildren();
38 long	lastmsgtime;
39 char 	*malloc(), *realloc();
40 
41 #define	MAXIDLE	120
42 #define NAMLEN (sizeof (uts[0].ut_name) + 1)
43 
44 main(argc, argv)
45 	int argc;
46 	char *argv[];
47 {
48 	register int cc;
49 	char buf[BUFSIZ];
50 	char msgbuf[100];
51 	struct sockaddr_in from;
52 	int fromlen;
53 
54 	/* verify proper invocation */
55 	fromlen = sizeof (from);
56 	if (getsockname(0, &from, &fromlen) < 0) {
57 		fprintf(stderr, "%s: ", argv[0]);
58 		perror("getsockname");
59 		_exit(1);
60 	}
61 	chdir("/usr/spool/mail");
62 	if ((uf = open("/etc/utmp",0)) < 0) {
63 		openlog("comsat", 0, 0);
64 		syslog(LOG_ERR, "/etc/utmp: %m");
65 		(void) recv(0, msgbuf, sizeof (msgbuf) - 1, 0);
66 		exit(1);
67 	}
68 	lastmsgtime = time(0);
69 	gethostname(hostname, sizeof (hostname));
70 	onalrm();
71 	signal(SIGALRM, onalrm);
72 	signal(SIGTTOU, SIG_IGN);
73 	signal(SIGCHLD, reapchildren);
74 	for (;;) {
75 		cc = recv(0, msgbuf, sizeof (msgbuf) - 1, 0);
76 		if (cc <= 0) {
77 			if (errno != EINTR)
78 				sleep(1);
79 			errno = 0;
80 			continue;
81 		}
82 		sigblock(1<<SIGALRM);
83 		msgbuf[cc] = 0;
84 		lastmsgtime = time(0);
85 		mailfor(msgbuf);
86 		sigsetmask(0);
87 	}
88 }
89 
90 reapchildren()
91 {
92 
93 	while (wait3((struct wait *)0, WNOHANG, (struct rusage *)0) > 0)
94 		;
95 }
96 
97 onalrm()
98 {
99 	struct stat statbf;
100 
101 	if (time(0) - lastmsgtime >= MAXIDLE)
102 		exit(0);
103 	dprintf("alarm\n");
104 	alarm(15);
105 	fstat(uf, &statbf);
106 	if (statbf.st_mtime > utmpmtime) {
107 		dprintf(" changed\n");
108 		utmpmtime = statbf.st_mtime;
109 		if (statbf.st_size > utmpsize) {
110 			utmpsize = statbf.st_size + 10 * sizeof(struct utmp);
111 			if (utmp)
112 				utmp = (struct utmp *)realloc(utmp, utmpsize);
113 			else
114 				utmp = (struct utmp *)malloc(utmpsize);
115 			if (! utmp) {
116 				dprintf("malloc failed\n");
117 				exit(1);
118 			}
119 		}
120 		lseek(uf, 0, 0);
121 		nutmp = read(uf,utmp,statbf.st_size)/sizeof(struct utmp);
122 	} else
123 		dprintf(" ok\n");
124 }
125 
126 mailfor(name)
127 	char *name;
128 {
129 	register struct utmp *utp = &utmp[nutmp];
130 	register char *cp;
131 	char *rindex();
132 	int offset;
133 
134 	dprintf("mailfor %s\n", name);
135 	cp = name;
136 	while (*cp && *cp != '@')
137 		cp++;
138 	if (*cp == 0) {
139 		dprintf("bad format\n");
140 		return;
141 	}
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 char	*cr;
150 
151 notify(utp, offset)
152 	register struct utmp *utp;
153 {
154 	FILE *tp;
155 	struct sgttyb gttybuf;
156 	char tty[20], name[sizeof (utmp[0].ut_name) + 1];
157 	struct stat stb;
158 
159 	strcpy(tty, "/dev/");
160 	strncat(tty, utp->ut_line, sizeof(utp->ut_line));
161 	dprintf("notify %s on %s\n", utp->ut_name, tty);
162 	if (stat(tty, &stb) == 0 && (stb.st_mode & 0100) == 0) {
163 		dprintf("wrong mode\n");
164 		return;
165 	}
166 	if (fork())
167 		return;
168 	signal(SIGALRM, SIG_DFL);
169 	alarm(30);
170 	if ((tp = fopen(tty,"w")) == 0) {
171 		dprintf("fopen failed\n");
172 		exit(-1);
173 	}
174 	ioctl(fileno(tp), TIOCGETP, &gttybuf);
175 	cr = (gttybuf.sg_flags & CRMOD) ? "" : "\r";
176 	strncpy(name, utp->ut_name, sizeof (utp->ut_name));
177 	name[sizeof (name) - 1] = '\0';
178 	fprintf(tp,"%s\n\007New mail for %s@%s\007 has arrived:%s\n",
179 	    cr, name, hostname, cr);
180 	fprintf(tp,"----%s\n", cr);
181 	jkfprintf(tp, name, offset);
182 	exit(0);
183 }
184 
185 jkfprintf(tp, name, offset)
186 	register FILE *tp;
187 {
188 	register FILE *fi;
189 	register int linecnt, charcnt;
190 	char line[BUFSIZ];
191 	int inheader;
192 
193 	dprintf("HERE %s's mail starting at %d\n",
194 	    name, offset);
195 	if ((fi = fopen(name,"r")) == NULL) {
196 		dprintf("Cant read the mail\n");
197 		return;
198 	}
199 	fseek(fi, 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 		register char *cp;
210 		char *index();
211 		int cnt;
212 
213 		if (linecnt <= 0 || charcnt <= 0) {
214 			fprintf(tp,"...more...%s\n", cr);
215 			return;
216 		}
217 		if (strncmp(line, "From ", 5) == 0)
218 			continue;
219 		if (inheader && (line[0] == ' ' || line[0] == '\t'))
220 			continue;
221 		cp = index(line, ':');
222 		if (cp == 0 || (index(line, ' ') && index(line, ' ') < cp))
223 			inheader = 0;
224 		else
225 			cnt = cp - line;
226 		if (inheader &&
227 		    strncmp(line, "Date", cnt) &&
228 		    strncmp(line, "From", cnt) &&
229 		    strncmp(line, "Subject", cnt) &&
230 		    strncmp(line, "To", cnt))
231 			continue;
232 		cp = index(line, '\n');
233 		if (cp)
234 			*cp = '\0';
235 		fprintf(tp,"%s%s\n", line, cr);
236 		linecnt--, charcnt -= strlen(line);
237 	}
238 	fprintf(tp,"----%s\n", cr);
239 }
240