Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / uip / rcvtty.c
1 /* rcvtty.c - a rcvmail program (a lot like rcvalert) handling IPC ttys */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: rcvtty.c,v 1.13 1994/04/21 18:20:50 jromine Exp $";
4 #endif  /* lint */
5
6 #ifndef BSD42
7 #undef  TTYD
8 #endif
9 #include "../h/mh.h"
10 #include "../h/rcvmail.h"
11 #include "../h/scansbr.h"
12 #include "../zotnet/tws.h"
13 #include <signal.h>
14 #include <sys/stat.h>
15 #ifndef TTYD
16 #include <utmp.h>
17 #endif  /* not TTYD */
18 #ifdef LOCALE
19 #include        <locale.h>
20 #endif
21
22 /* \f */
23 #define SCANFMT \
24 "%2(hour{dtimenow}):%02(min{dtimenow}): %<(size)%5(size) %>%<{encrypted}E%>\
25 %<(mymbox{from})%<{to}To:%14(friendly{to})%>%>%<(zero)%17(friendly{from})%>  \
26 %{subject}%<{body}<<%{body}>>%>"
27
28 static struct swit switches[] = {
29 #define HELPSW  0
30     "help", 4,
31
32 #define BIFFSW  1
33     "biff", 0,
34
35 #define FORMSW  2
36     "form formatfile", 0,
37 #define FMTSW   3
38     "format string", 5,
39
40 #define NLSW    4
41     "newline", 0,
42 #define NNLSW   5
43     "nonewline", 0,
44 #define BELSW   6
45     "bell", 0,
46 #define NBELSW  7
47     "nobell", 0,
48
49     NULL, 0
50 };
51
52 /* \f */
53
54 static  jmp_buf myctx;
55
56 off_t   lseek ();
57 char   *getusr ();
58
59 static int      message_fd(), header_fd();
60 static          alert();
61
62 static int bell = 1;
63 static int newline = 1;
64 static int biff = 0;
65 static char *form = NULL;
66 static char *format = NULL;
67
68 /* \f */
69
70 /* ARGSUSED */
71
72 main (argc, argv)
73 int     argc;
74 char   **argv;
75 {
76     int     md,
77             vecp = 0;
78     char   *cp,
79            *user,
80             buf[100],
81           **ap,
82           **argp,
83            *arguments[MAXARGS],
84            *vec[MAXARGS];
85 #ifndef TTYD
86     char    tty[BUFSIZ];
87     struct utmp ut;
88     register FILE  *uf;
89 #endif  /* not TTYD */
90
91 #ifdef LOCALE
92         setlocale(LC_ALL, "");
93 #endif
94     invo_name = r1bindex (argv[0], '/');
95     mts_init (invo_name);
96     if ((cp = m_find (invo_name)) != NULL) {
97         ap = brkstring (cp = getcpy (cp), " ", "\n");
98         ap = copyip (ap, arguments);
99     }
100     else
101         ap = arguments;
102     (void) copyip (argv + 1, ap);
103     argp = arguments;
104
105 /* \f */
106
107     while (cp = *argp++) {
108         if (*cp == '-')
109             switch (smatch (++cp, switches)) {
110                 case AMBIGSW: 
111                     ambigsw (cp, switches);
112                     done (1);
113                 case UNKWNSW: 
114                     vec[vecp++] = --cp;
115                     continue;
116                 case HELPSW: 
117                     (void) sprintf (buf, "%s [command ...]", invo_name);
118                     help (buf, switches);
119                     done (1);
120
121                 case BIFFSW:
122                     biff = 1;
123                     continue;
124
125                 case FORMSW: 
126                     if (!(form = *argp++) || *form == '-')
127                         adios (NULLCP, "missing argument to %s", argp[-2]);
128                     format = NULL;
129                     continue;
130                 case FMTSW: 
131                     if (!(format = *argp++) || *format == '-')
132                         adios (NULLCP, "missing argument to %s", argp[-2]);
133                     form = NULL;
134                     continue;
135
136                 case NLSW:
137                     newline = 1;
138                     continue;
139                 case NNLSW:
140                     newline = 0;
141                     continue;
142                 case BELSW:
143                     bell = 1;
144                     continue;
145                 case NBELSW:
146                     bell = 0;
147                     continue;
148
149             }
150         vec[vecp++] = cp;
151     }
152     vec[vecp] = 0;
153
154 /* \f */
155
156     if ((md = vecp ? message_fd (vec) : header_fd ()) == NOTOK)
157         exit (RCV_MBX);
158
159     user = getusr ();
160 #ifndef TTYD
161     if ((uf = fopen ("/etc/utmp", "r")) == NULL)
162         exit (RCV_MBX);
163     while (fread ((char *) &ut, sizeof ut, 1, uf) == 1)
164         if (ut.ut_name[0] != 0
165                 && strncmp (user, ut.ut_name, sizeof ut.ut_name) == 0) {
166             (void) strncpy (tty, ut.ut_line, sizeof ut.ut_line);
167             alert (tty, md);
168         }
169     (void) fclose (uf);
170 #else   /* TTYD */
171     alert (user, md);
172 #endif  /* TTYD */
173
174     exit (RCV_MOK);
175 }
176
177 /* \f */
178
179 /* ARGSUSED */
180
181 static  TYPESIG alrmser (i)
182 int     i;
183 {
184     longjmp (myctx, DONE);
185 }
186
187
188 static int  message_fd (vec)
189 char   *vec[];
190 {
191     int     bytes,
192             child_id,
193             fd;
194     char    tmpfil[BUFSIZ];
195     struct stat st;
196
197     (void) unlink (mktemp (strcpy (tmpfil, "/tmp/rcvttyXXXXX")));
198     if ((fd = creat (tmpfil, 0600)) == NOTOK)
199         return header_fd ();
200     (void) close (fd);
201
202     if ((fd = open (tmpfil, 2)) == NOTOK)
203         return header_fd ();
204     (void) unlink (tmpfil);
205
206 /* \f */
207
208     switch (child_id = vfork ()) {
209         case NOTOK: 
210             (void) close (fd);
211             return header_fd ();
212
213         case OK: 
214             rewind (stdin);
215             if (dup2 (fd, 1) == NOTOK || dup2 (fd, 2) == NOTOK)
216                 _exit (-1);
217             closefds (3);
218 #ifdef  BSD42
219             (void) setpgrp (0, getpid ());
220 #endif  /* BSD42 */
221             execvp (vec[0], vec);
222             _exit (-1);
223
224         default: 
225             switch (setjmp (myctx)) {
226                 case OK: 
227                     (void) signal (SIGALRM, alrmser);
228                     bytes = fstat (fileno (stdin), &st) != NOTOK
229                         ? (int) st.st_size : 100;
230                     if (bytes <= 0)
231                         bytes = 100;
232                     (void) alarm ((unsigned) (bytes * 60 + 300));
233
234                     (void) pidwait (child_id, OK);
235
236                     (void) alarm (0);
237                     if (fstat (fd, &st) != NOTOK && st.st_size > (off_t)0)
238                         return fd;
239                     (void) close (fd);
240                     return header_fd ();
241
242                 default: 
243 #ifndef BSD42
244                     (void) kill (child_id, SIGKILL);
245 #else   /* BSD42 */
246                     (void) killpg (child_id, SIGKILL);
247 #endif  /* BSD42 */
248                     (void) close (fd);
249                     return header_fd ();
250             }
251     }
252 }
253
254 /* \f */
255
256 static int  header_fd () {
257     int     fd;
258     char    tmpfil[BUFSIZ];
259
260     (void) strcpy (tmpfil, m_tmpfil (invo_name));
261     if ((fd = creat (tmpfil, 0600)) == NOTOK)
262         return NOTOK;
263     (void) close (fd);
264
265     if ((fd = open (tmpfil, 2)) == NOTOK)
266         return NOTOK;
267     (void) unlink (tmpfil);
268
269     rewind (stdin);
270     (void) scan (stdin, 0, 0, new_fs (form, format, SCANFMT), 0, 0, 0,
271             0, 0, 0L, 0);
272     if ( newline )
273         (void) write (fd, "\n\r", 2);
274     (void) write (fd, scanl, strlen (scanl));
275     if ( bell )
276         (void) write (fd, "\007", 1);
277
278     return fd;
279 }
280
281 /* \f */
282
283 #ifndef TTYD
284 static  alert (tty, md)
285 char   *tty;
286 int     md;
287 {
288     int     i,
289             td;
290     char    buffer[BUFSIZ],
291             ttyspec[BUFSIZ];
292     struct stat st;
293
294     (void) sprintf (ttyspec, "/dev/%s", tty);
295     if (stat (ttyspec, &st) == NOTOK ||
296         (st.st_mode & (biff ? S_IEXEC :
297 #ifdef  BSD43
298                        (S_IWRITE >> 3)
299 #else   /* BSD43 */
300                        02
301 #endif  /* BSD43 */
302                        )) == 0)
303         return;
304
305     switch (setjmp (myctx)) {
306         case OK: 
307             (void) signal (SIGALRM, alrmser);
308             (void) alarm (2);
309             td = open (ttyspec, 1);
310             (void) alarm (0);
311             if (td == NOTOK)
312                 return;
313             break;
314
315         default: 
316             (void) alarm (0);
317             return;
318     }
319
320     (void) lseek (md, (off_t)0, 0);
321
322     while ((i = read (md, buffer, sizeof buffer)) > 0)
323         if (write (td, buffer, i) != i)
324             break;
325
326     (void) close (td);
327 }
328 #else   /* TTYD */
329
330 /* \f */
331
332 static  alert (user, md)
333 register char   *user;
334 int     md;
335 {
336     int     i,
337             td;
338     char    buffer[BUFSIZ];
339
340     if ((td = ttyw ("notify", NULLCP, NULLCP, user)) == NOTOK)
341         return;
342     (void) signal (SIGPIPE, SIG_IGN);
343
344     (void) lseek (md, (off_t), 0);
345     while ((i = read (md, buffer, sizeof buffer)) > 0)
346         if (write (td, buffer, i) != i)
347             break;
348
349     (void) close (td);
350 }
351 #endif  /* TTYD */