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