xref: /original-bsd/libexec/comsat/comsat.c (revision 0b685140)
1 static	char *sccsid = "@(#)comsat.c	4.2 (Berkeley) 10/20/80";
2 #include <stdio.h>
3 #include <sys/mx.h>
4 #include <sgtty.h>
5 #include <utmp.h>
6 #include <sys/types.h>
7 #include <stat.h>
8 #include <wait.h>
9 #include <signal.h>
10 
11 /*
12  * comsat
13  */
14 #define	dprintf	if (0) printf
15 int	xd;
16 
17 struct  ctp {
18 	short   ctrl;
19 	short   ctrlarg;
20 	struct  sgttyb ctrlv;
21 } ctp;
22 
23 #define MAXUTMP 100		/* down from init */
24 
25 struct	utmp utmp[100];
26 int	nutmp;
27 int	uf;
28 unsigned utmpmtime;			/* last modification time for utmp */
29 int	onalrm();
30 
31 #define NAMLEN (sizeof (uts[0].ut_name) + 1)
32 
33 main(argc, argv)
34 char **argv;
35 {
36 	register cc;
37 	char buf[BUFSIZ];
38 
39 	if (fork())
40 		exit();
41 	chdir("/usr/spool/mail");
42 	if((uf = open("/etc/utmp",0)) < 0)
43 		perror("/etc/utmp"), exit(1);
44 	while (fork())
45 		wait(0);
46 	sleep(10);
47 	onalrm();
48 	sigset(SIGALRM, onalrm);
49 	sigignore(SIGTTOU);
50 	unlink("/dev/mail");
51 	xd = mpx("/dev/mail", 0666);
52 	if (xd < 0) {
53 		close(2);
54 		open("/dev/console", 1);
55 		perror("/dev/mail");
56 		exit(1);
57 	}
58 	while((cc=read(xd, buf, BUFSIZ)) >= 0) {
59 		dprintf("0: got %d bytes\n", cc);
60 		unpack(buf, cc);
61 	}
62 	_exit(1);
63 }
64 
65 #define	skip(rp, c)	((struct rh *)(((char *)rp)+c))
66 
67 unpack(rp, cc)
68 	register struct rh *rp;
69 {
70 	register struct rh *end;
71 	int i;
72 
73 	i = 0;
74 	end = skip(rp, cc);
75 	while (rp < end) {
76 		dprintf("%d: ", ++i);
77 		if (rp->count==0) {
78 			dprintf("%d byte control message\n", rp->ccount);
79 			control(rp->index, rp+1, rp->ccount);
80 		} else {
81 			dprintf("%*.*s\n", rp->count, rp->count, rp+1);
82 			sighold(SIGALRM);
83 			mailfor(rp+1);
84 			sigrelse(SIGALRM);
85 		}
86 		rp->count += rp->ccount;
87 		if (rp->count & 1)
88 			rp->count++;
89 		rp = skip(rp, rp->count);
90 		rp++;
91 	}
92 }
93 
94 control(x, cb, cc)
95 	register char *cb;
96 {
97 	register char *end;
98 	int cmd;
99 	short *sp;
100 	struct wh or;
101 
102 	end = cb + cc;
103 	cmd = *cb++;
104 	sp = (short *)cb+1;
105 	switch (cmd) {
106 
107 	case M_WATCH:
108 		dprintf("attach %x, uid %d\n", x, *sp);
109 		attach(x, xd);
110 		break;
111 
112 	case M_CLOSE:
113 		sp = (short *)cb;
114 		dprintf("detach %x, uid %d\n", x, *sp);
115 		detach(x, xd);
116 		break;
117 
118 	case M_IOCTL:
119 		dprintf("ioctl %x\n", x);
120 		or.index = x;
121 		or.count = 0;
122 		or.ccount = sizeof ctp;
123 		or.data = (char *) &ctp.ctrlarg;
124 		ctp.ctrlarg = M_IOANS;
125 		write(xd, &or, sizeof or);
126 		break;
127 
128 	default:
129 		dprintf("unknown command %d\n", cmd);
130 		return;
131 	}
132 }
133 
134 onalrm()
135 {
136 	struct stat statbf;
137 	struct utmp *utp;
138 
139 	dprintf("alarm\n");
140 	alarm(15);
141 	fstat(uf,&statbf);
142 	if (statbf.st_mtime > utmpmtime) {
143 		dprintf(" changed\n");
144 		utmpmtime = statbf.st_mtime;
145 		lseek(uf, 0, 0);
146 		nutmp = read(uf,utmp,sizeof(utmp))/sizeof(struct utmp);
147 	} else
148 		dprintf(" ok\n");
149 }
150 
151 mailfor(name)
152 	char *name;
153 {
154 	register struct utmp *utp = &utmp[nutmp];
155 	register char *cp;
156 	char *rindex();
157 	int offset;
158 
159 	dprintf("mailfor %s\n", name);
160 	cp = name;
161 	while (*cp && *cp != '@')
162 		cp++;
163 	if (*cp == 0) {
164 		dprintf("bad format\n");
165 		return;
166 	}
167 	*cp = 0;
168 	offset = atoi(cp+1);
169 	while (--utp >= utmp)
170 		if (!strncmp(utp->ut_name, name, sizeof(utmp[0].ut_name)))
171 			if (fork() == 0) {
172 				signal(SIGALRM, SIG_DFL);
173 				alarm(30);
174 				notify(utp, offset), exit(0);
175 			} else
176 				while (wait3(0, WNOHANG, 0) > 0)
177 					continue;
178 }
179 
180 char *cr;
181 
182 notify(utp, offset)
183 	register struct utmp *utp;
184 {
185 	FILE *tp;
186 	struct sgttyb gttybuf;
187 	char tty[20];
188 	char name[sizeof (utmp[0].ut_name) + 1];
189 	struct stat stb;
190 
191 	strcpy(tty, "/dev/");
192 	strncat(tty, utp->ut_line, sizeof(utp->ut_line));
193 	dprintf("notify %s on %s\n", utp->ut_name, tty);
194 	if (stat(tty, &stb) == 0 && (stb.st_mode & 0100) == 0) {
195 		dprintf("wrong mode\n");
196 		return;
197 	}
198 	if ((tp = fopen(tty,"w")) == 0) {
199 		dprintf("fopen failed\n");
200 		return;
201 	}
202 	gtty(fileno(tp),&gttybuf);
203 	cr = (gttybuf.sg_flags & CRMOD) ? "" : "\r";
204 	strncpy(name, utp->ut_name, sizeof (utp->ut_name));
205 	name[sizeof (name) - 1] = 0;
206 	fprintf(tp,"%s\n\007New mail for %s\007 has arrived:%s\n",
207 	    cr, name, cr);
208 	fprintf(tp,"----%s\n", cr);
209 	jkfprintf(tp, name, offset);
210 	 fclose(tp);
211 }
212 
213 jkfprintf(tp, name, offset)
214 	register FILE *tp;
215 {
216 	register FILE *fi;
217 	register int linecnt, charcnt;
218 
219 	dprintf("HERE %s's mail starting at %d\n",
220 	    name, offset);
221 	if ((fi = fopen(name,"r")) == NULL) {
222 		dprintf("Cant read the mail\n");
223 		return;
224 	}
225 	fseek(fi, offset, 0);
226 	linecnt = 7;
227 	charcnt = 560;
228 	/*
229 	 * print the first 7 lines or 560 characters of the new mail
230 	 * (whichever comes first)
231 	 */
232 	for (;;) {
233 		register ch;
234 
235 	 	if ((ch = getc(fi)) == EOF) {
236 			fprintf(tp,"----%s\n", cr);
237 			break;
238 		}
239 		if (ch == '\n') {
240 			fprintf(tp,"%s\n", cr);
241 		 	if (linecnt-- < 0) {
242 				fprintf(tp,"...more...%s\n", cr);
243 				break;
244 			}
245 		} else if(linecnt <= 0) {
246 			fprintf(tp,"...more...%s\n", cr);
247 			break;
248 		} else
249 			putc(ch, tp);
250 		if (charcnt-- == 0) {
251 			fprintf(tp, "%s\n", cr);
252 			break;
253 		}
254 	}
255 }
256