source: trunk/third/nmh/uip/rcvtty.c @ 12455

Revision 12455, 6.4 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12454, which included commits to RCS files with non-trunk default branches.
Line 
1
2/*
3 * rcvtty.c -- a rcvmail program (a lot like rcvalert) handling IPC ttys
4 *
5 * $Id: rcvtty.c,v 1.1.1.1 1999-02-07 18:14:16 danw Exp $
6 */
7
8#include <h/mh.h>
9#include <h/signals.h>
10#include <h/rcvmail.h>
11#include <h/scansbr.h>
12#include <zotnet/tws/tws.h>
13#include <signal.h>
14#include <fcntl.h>
15
16#include <utmp.h>
17#ifndef UTMP_FILE
18# ifdef _PATH_UTMP
19#  define UTMP_FILE _PATH_UTMP
20# else
21#  define UTMP_FILE "/etc/utmp"
22# endif
23#endif
24
25#define SCANFMT \
26"%2(hour{dtimenow}):%02(min{dtimenow}): %<(size)%5(size) %>%<{encrypted}E%>\
27%<(mymbox{from})%<{to}To:%14(friendly{to})%>%>%<(zero)%17(friendly{from})%>  \
28%{subject}%<{body}<<%{body}>>%>"
29
30static struct swit switches[] = {
31#define BIFFSW  0
32    { "biff", 0 },
33#define FORMSW  1
34    { "form formatfile", 0 },
35#define FMTSW   2
36    { "format string", 5 },
37#define WIDTHSW 3
38    { "width columns", 0 },
39#define NLSW    4
40    { "newline", 0 },
41#define NNLSW   5
42    { "nonewline", 0 },
43#define BELSW   6
44    { "bell", 0 },
45#define NBELSW  7
46    { "nobell", 0 },
47#define VERSIONSW 8
48    { "version", 0 },
49#define HELPSW  9
50    { "help", 4 },
51    { NULL, 0 }
52};
53
54static jmp_buf myctx;
55static int bell = 1;
56static int newline = 1;
57static int biff = 0;
58static int width = 0;
59static char *form = NULL;
60static char *format = NULL;
61
62/*
63 * external prototypes
64 */
65char *getusername(void);
66
67/*
68 * static prototypes
69 */
70static RETSIGTYPE alrmser (int);
71static int message_fd (char **);
72static int header_fd (void);
73static void alert (char *, int);
74
75
76int
77main (int argc, char **argv)
78{
79    int md, vecp = 0;
80    char *cp, *user, buf[BUFSIZ], tty[BUFSIZ];
81    char **argp, **arguments, *vec[MAXARGS];
82    struct utmp ut;
83    register FILE *uf;
84
85#ifdef LOCALE
86    setlocale(LC_ALL, "");
87#endif
88    invo_name = r1bindex (argv[0], '/');
89
90    /* read user profile/context */
91    context_read();
92
93    mts_init (invo_name);
94    arguments = getarguments (invo_name, argc, argv, 1);
95    argp = arguments;
96
97    while ((cp = *argp++)) {
98        if (*cp == '-') {
99            switch (smatch (++cp, switches)) {
100                case AMBIGSW:
101                    ambigsw (cp, switches);
102                    done (1);
103                case UNKWNSW:
104                    vec[vecp++] = --cp;
105                    continue;
106
107                case HELPSW:
108                    snprintf (buf, sizeof(buf), "%s [command ...]", invo_name);
109                    print_help (buf, switches, 1);
110                    done (1);
111                case VERSIONSW:
112                    print_version(invo_name);
113                    done (1);
114
115                case BIFFSW:
116                    biff = 1;
117                    continue;
118
119                case FORMSW:
120                    if (!(form = *argp++) || *form == '-')
121                        adios (NULL, "missing argument to %s", argp[-2]);
122                    format = NULL;
123                    continue;
124                case FMTSW:
125                    if (!(format = *argp++) || *format == '-')
126                        adios (NULL, "missing argument to %s", argp[-2]);
127                    form = NULL;
128                    continue;
129
130                case WIDTHSW:
131                    if (!(cp = *argp++) || *cp == '-')
132                        adios(NULL, "missing argument to %s", argp[-2]);
133                    width = atoi(cp);
134                    continue;
135                case NLSW:
136                    newline = 1;
137                    continue;
138                case NNLSW:
139                    newline = 0;
140                    continue;
141                case BELSW:
142                    bell = 1;
143                    continue;
144                case NBELSW:
145                    bell = 0;
146                    continue;
147
148            }
149        }
150        vec[vecp++] = cp;
151    }
152    vec[vecp] = 0;
153
154    if ((md = vecp ? message_fd (vec) : header_fd ()) == NOTOK)
155        exit (RCV_MBX);
156
157    user = getusername();
158    if ((uf = fopen (UTMP_FILE, "r")) == NULL)
159        exit (RCV_MBX);
160
161    while (fread ((char *) &ut, sizeof(ut), 1, uf) == 1)
162        if (ut.ut_name[0] != 0
163                && strncmp (user, ut.ut_name, sizeof(ut.ut_name)) == 0) {
164            strncpy (tty, ut.ut_line, sizeof(ut.ut_line));
165            alert (tty, md);
166        }
167
168    fclose (uf);
169    exit (RCV_MOK);
170}
171
172
173static RETSIGTYPE
174alrmser (int i)
175{
176#ifndef RELIABLE_SIGNALS
177    SIGNAL (SIGALRM, alrmser);
178#endif
179
180    longjmp (myctx, 1);
181}
182
183
184static int
185message_fd (char **vec)
186{
187    pid_t child_id;
188    int bytes, fd, seconds;
189    char tmpfil[BUFSIZ];
190    struct stat st;
191
192    unlink (mktemp (strncpy (tmpfil, "/tmp/rcvttyXXXXX", sizeof(tmpfil))));
193    if ((fd = open (tmpfil, O_RDWR | O_CREAT | O_TRUNC, 0600)) == NOTOK)
194        return header_fd ();
195    unlink (tmpfil);
196
197    if ((child_id = vfork()) == NOTOK) {
198        /* fork error */
199        close (fd);
200        return header_fd ();
201    } else if (child_id) {
202        /* parent process */
203        if (!setjmp (myctx)) {
204            SIGNAL (SIGALRM, alrmser);
205            bytes = fstat(fileno (stdin), &st) != NOTOK ? (int) st.st_size : 100;
206
207            /* amount of time to wait depends on message size */
208            if (bytes <= 100) {
209                /* give at least 5 minutes */
210                seconds = 300;
211            } else if (bytes >= 90000) {
212                /* but 30 minutes should be long enough */
213                seconds = 1800;
214            } else {
215                seconds = (bytes / 60) + 300;
216            }
217            alarm ((unsigned int) seconds);
218            pidwait(child_id, OK);
219            alarm (0);
220
221            if (fstat (fd, &st) != NOTOK && st.st_size > (off_t) 0)
222                return fd;
223        } else {
224            /*
225             * Ruthlessly kill the child and anything
226             * else in its process group.
227             */
228            KILLPG(child_id, SIGKILL);
229        }
230        close (fd);
231        return header_fd ();
232    }
233
234    /* child process */
235    rewind (stdin);
236    if (dup2 (fd, 1) == NOTOK || dup2 (fd, 2) == NOTOK)
237        _exit (-1);
238    closefds (3);
239    setpgid ((pid_t) 0, getpid ());     /* put in own process group */
240    execvp (vec[0], vec);
241    _exit (-1);
242}
243
244
245static int
246header_fd (void)
247{
248    int fd;
249    char *nfs, tmpfil[BUFSIZ];
250
251    strncpy (tmpfil, m_tmpfil (invo_name), sizeof(tmpfil));
252    if ((fd = open (tmpfil, O_RDWR | O_CREAT | O_TRUNC, 0600)) == NOTOK)
253        return NOTOK;
254    unlink (tmpfil);
255
256    rewind (stdin);
257
258    /* get new format string */
259    nfs = new_fs (form, format, SCANFMT);
260    scan (stdin, 0, 0, nfs, width, 0, 0, NULL, 0L, 0);
261    if (newline)
262        write (fd, "\n\r", 2);
263    write (fd, scanl, strlen (scanl));
264    if (bell)
265        write (fd, "\007", 1);
266
267    return fd;
268}
269
270
271static void
272alert (char *tty, int md)
273{
274    int i, td, mask;
275    char buffer[BUFSIZ], ttyspec[BUFSIZ];
276    struct stat st;
277
278    snprintf (ttyspec, sizeof(ttyspec), "/dev/%s", tty);
279
280    /*
281     * The mask depends on whether we are checking for
282     * write permission based on `biff' or `mesg'.
283     */
284    mask = biff ? S_IEXEC : (S_IWRITE >> 3);
285    if (stat (ttyspec, &st) == NOTOK || (st.st_mode & mask) == 0)
286        return;
287
288    if (!setjmp (myctx)) {
289        SIGNAL (SIGALRM, alrmser);
290        alarm (2);
291        td = open (ttyspec, O_WRONLY);
292        alarm (0);
293        if (td == NOTOK)
294            return;
295    } else {
296        alarm (0);
297        return;
298    }
299
300    lseek (md, (off_t) 0, SEEK_SET);
301
302    while ((i = read (md, buffer, sizeof(buffer))) > 0)
303        if (write (td, buffer, i) != i)
304            break;
305
306    close (td);
307}
308
Note: See TracBrowser for help on using the repository browser.