source: trunk/athena/lib/zephyr/clients/zwrite/zwrite.c @ 13498

Revision 13498, 13.9 KB checked in by danw, 26 years ago (diff)
fix things Irix n32 cc complains about
Line 
1/* This file is part of the Project Athena Zephyr Notification System.
2 * It contains code for the "zwrite" command.
3 *
4 *      Created by:     Robert French
5 *
6 *      $Id: zwrite.c,v 1.49 1999-08-13 00:19:42 danw Exp $
7 *
8 *      Copyright (c) 1987,1988 by the Massachusetts Institute of Technology.
9 *      For copying and distribution information, see the file
10 *      "mit-copyright.h".
11 */
12
13#include <sysdep.h>
14#include <zephyr/mit-copyright.h>
15#include <zephyr/zephyr.h>
16#include <netdb.h>
17#include <pwd.h>
18
19#ifndef lint
20static const char rcsid_zwrite_c[] = "$Id: zwrite.c,v 1.49 1999-08-13 00:19:42 danw Exp $";
21#endif /* lint */
22
23#define DEFAULT_CLASS "MESSAGE"
24#define DEFAULT_INSTANCE "PERSONAL"
25#define URGENT_INSTANCE "URGENT"
26#define DEFAULT_OPCODE ""
27#define FILSRV_CLASS "FILSRV"
28
29#define MAXRECIPS 100
30
31int nrecips, msgarg, verbose, quiet, nodot, cc;
32char *whoami, *inst, *class, *opcode, *realm, *recips[MAXRECIPS];
33Z_AuthProc auth;
34void un_tabify();
35
36char *fix_filsrv_inst();
37void usage(), send_off();
38
39main(argc, argv)
40    int argc;
41    char *argv[];
42{
43    int retval, arg, nocheck, nchars, msgsize, filsys, tabexpand;
44    char *message, *signature = NULL, *format = NULL;
45    static char bfr[BUFSIZ], classbfr[BUFSIZ], instbfr[BUFSIZ], sigbfr[BUFSIZ];
46    static char opbfr[BUFSIZ];
47    static ZNotice_t notice;
48
49    whoami = argv[0];
50
51    if ((retval = ZInitialize()) != ZERR_NONE) {
52        com_err(whoami, retval, "while initializing");
53        exit(1);
54    }
55
56    if (argc < 2)
57        usage(whoami);
58
59    auth = ZAUTH;
60    verbose = quiet = msgarg = nrecips = nocheck = filsys = nodot = 0;
61    tabexpand = 1;
62
63    if (class = ZGetVariable("zwrite-class")) {
64        (void) strcpy(classbfr, class);
65        class = classbfr;
66    }
67    else
68        class = DEFAULT_CLASS;
69    if (inst = ZGetVariable("zwrite-inst")) {
70        (void) strcpy(instbfr, inst);
71        inst = instbfr;
72    }
73    else
74        inst = DEFAULT_INSTANCE;
75
76    if (opcode = ZGetVariable("zwrite-opcode"))
77      opcode = strcpy(opbfr, opcode);
78    else
79      opcode = DEFAULT_OPCODE;
80
81      signature = ZGetVariable("zwrite-signature");
82    if (signature) {
83        (void) strcpy(sigbfr, signature);
84        signature = sigbfr;
85    }
86       
87    arg = 1;
88       
89    for (;arg<argc&&!msgarg;arg++) {
90        if (*argv[arg] != '-') {
91            recips[nrecips++] = argv[arg];
92            continue;
93        }
94        if (strlen(argv[arg]) > 2)
95            usage(whoami);
96        switch (argv[arg][1]) {
97        case 'a':               /* Backwards compatibility */
98            auth = ZAUTH;
99            break;
100        case 'o':
101            class = DEFAULT_CLASS;
102            inst = DEFAULT_INSTANCE;
103            opcode = DEFAULT_OPCODE;
104            break;
105        case 'd':
106            auth = ZNOAUTH;
107            break;
108        case 'v':
109            verbose = 1;
110            break;
111        case 'q':
112            quiet = 1;
113            break;
114        case 'n':
115            nocheck = 1;
116            break;
117        case 't':
118            tabexpand = 0;
119            break;
120        case 'u':
121            inst = URGENT_INSTANCE;
122            break;
123        case 'O':
124            if (arg == argc-1)
125              usage(whoami);
126            arg++;
127            opcode = argv[arg];
128            break;
129        case 'i':
130            if (arg == argc-1 || filsys == 1)
131                usage(whoami);
132            arg++;
133            inst = argv[arg];
134            filsys = -1;
135            break;
136        case 'c':
137            if (arg == argc-1 || filsys == 1)
138                usage(whoami);
139            arg++;
140            class = argv[arg];
141            filsys = -1;
142            break;
143        case 'f':
144            if (arg == argc-1 || filsys == -1)
145                usage(whoami);
146            arg++;
147            class = FILSRV_CLASS;
148            inst = fix_filsrv_inst(argv[arg]);
149            filsys = 1;
150            nocheck = 1;                /* implied -n (no ping) */
151            break;
152        case 's':
153            if (arg == argc-1)
154                usage(whoami);
155            arg++;
156            signature = argv[arg];
157            break;
158        case 'm':
159            if (arg == argc-1)
160                usage(whoami);
161            nocheck = 1;                /* implied -n (no ping) */
162            msgarg = arg+1;
163            break;
164        case 'l':                       /* literal */
165            nodot = 1;
166            break;
167        case 'F':
168            if (arg == argc-1)
169                usage(whoami);
170            arg++;
171            format = argv[arg];
172            break;
173        case 'r':
174            if (arg == argc-1)
175                usage(whoami);
176            arg++;
177            realm = argv[arg];
178            break;
179        case 'C':
180            cc = 1;
181            break;
182        default:
183            usage(whoami);
184        }
185    }
186
187    if (!nrecips && !(strcmp(class, DEFAULT_CLASS) ||
188                      (strcmp(inst, DEFAULT_INSTANCE) &&
189                       strcmp(inst, URGENT_INSTANCE)))) {
190        /* must specify recipient if using default class and
191           (default instance or urgent instance) */
192        fprintf(stderr, "No recipients specified.\n");
193        usage(whoami);
194    }
195
196    if (!signature) {
197        /* try to find name in the password file */
198        register struct passwd *pwd;
199        register char *cp = sigbfr;
200        register char *cp2, *pp;
201
202        pwd = getpwuid(getuid());
203        if (pwd) {
204            cp2 = pwd->pw_gecos;
205            for (; *cp2 && *cp2 != ',' ; cp2++) {
206                if (*cp2 == '&') {
207                    pp = pwd->pw_name;
208                    *cp++ = islower(*pp) ? toupper(*pp) : *pp;
209                    pp++;
210                    while (*pp)
211                        *cp++ = *pp++;
212                } else
213                    *cp++ = *cp2;
214            }
215            signature = sigbfr;
216        }
217    }   
218
219    notice.z_kind = ACKED;
220    notice.z_port = 0;
221    notice.z_class = class;
222    notice.z_class_inst = inst;
223    notice.z_opcode = "PING";
224    notice.z_sender = 0;
225    notice.z_message_len = 0;
226    notice.z_recipient = "";
227    if (format)
228            notice.z_default_format = format;
229    else if (filsys == 1)
230            notice.z_default_format = "@bold(Filesystem Operation Message for $instance:)\nFrom: @bold($sender) at $time $date\n$message";
231    else if (auth == ZAUTH) {
232        if (signature)
233            notice.z_default_format = "Class $class, Instance $instance:\nTo: @bold($recipient) at $time $date\nFrom: @bold($1) <$sender>\n\n$2";
234        else
235            notice.z_default_format = "Class $class, Instance $instance:\nTo: @bold($recipient) at $time $date\n$message";
236    } else {
237        if (signature)
238            notice.z_default_format = "@bold(UNAUTHENTIC) Class $class, Instance $instance at $time $date:\nFrom: @bold($1) <$sender>\n\n$2";
239        else
240            notice.z_default_format = "@bold(UNAUTHENTIC) Class $class, Instance $instance at $time $date:\n$message";
241    }
242    if (!nocheck && nrecips)
243        send_off(&notice, 0);
244       
245    if (!msgarg && isatty(0))
246        if (nodot)
247            printf("Type your message now.  End with the end-of-file character.\n");
248        else
249            printf("Type your message now.  End with control-D or a dot on a line by itself.\n");
250       
251    message = NULL;
252    msgsize = 0;
253    if (signature) {
254        message = malloc((unsigned)(strlen(signature)+2));
255        (void) strcpy(message, signature);
256        msgsize = strlen(message);
257        message[msgsize++] = '\0';
258    } else {
259        message = malloc(1);
260        message[msgsize++] = '\0';
261    }
262
263    if (cc && nrecips > 1) {
264        int size = msgsize;
265        for (arg=0;arg<nrecips;arg++)
266            size += (strlen(recips[arg]) + 2);
267        size += 6;                      /* for the newlines and "cc: " */
268        message = realloc(message, (unsigned) size);
269        (void) strcpy(message+msgsize, "CC: ");
270        msgsize += 4;
271        for (arg=0;arg<nrecips;arg++) {
272            (void) strcpy(message+msgsize, recips[arg]);
273            msgsize += strlen(recips[arg]);
274            if (arg != nrecips-1) {
275                message[msgsize] = ' ';
276                msgsize++;
277            }
278        }
279        message[msgsize] = '\n';
280        msgsize += 1;
281    }
282
283    if (msgarg) {
284        int size = msgsize;
285        for (arg=msgarg;arg<argc;arg++)
286                size += (strlen(argv[arg]) + 1);
287        size++;                         /* for the newline */
288        message = realloc(message, (unsigned) size);
289        for (arg=msgarg;arg<argc;arg++) {
290            (void) strcpy(message+msgsize, argv[arg]);
291            msgsize += strlen(argv[arg]);
292            if (arg != argc-1) {
293                message[msgsize] = ' ';
294                msgsize++;
295            }
296        }
297        message[msgsize] = '\n';
298        msgsize += 1;
299    } else {
300        if (isatty(0)) {
301            for (;;) {
302                unsigned int l;
303                if (!fgets(bfr, sizeof bfr, stdin))
304                    break;
305                if (!nodot && bfr[0] == '.' &&
306                    (bfr[1] == '\n' || bfr[1] == '\0'))
307                    break;
308                l = strlen(bfr);
309                message = realloc(message, msgsize+l+1);
310                (void) strcpy(message+msgsize, bfr);
311                msgsize += l;
312            }
313            message = realloc(message, (unsigned)(msgsize+1));
314        }
315        else {  /* Use read so you can send binary messages... */
316            while (nchars = read(fileno(stdin), bfr, sizeof bfr)) {
317                if (nchars == -1) {
318                    fprintf(stderr, "Read error from stdin!  Can't continue!\n");
319                    exit(1);
320                }
321                message = realloc(message, (unsigned)(msgsize+nchars));
322                (void) memcpy(message+msgsize, bfr, nchars);
323                msgsize += nchars;
324            }
325            /* end of msg */
326            message = realloc(message, (unsigned)(msgsize+1));
327        }
328    }
329
330    notice.z_opcode = opcode;
331    if (tabexpand)
332        un_tabify(&message, &msgsize);
333    notice.z_message = message;
334    notice.z_message_len = msgsize;
335
336    send_off(&notice, 1);
337    exit(0);
338}
339
340void
341send_off(notice, real)
342    ZNotice_t *notice;
343    int real;
344{
345    int i, success, retval;
346    char bfr[BUFSIZ], realm_recip[BUFSIZ], dest[3 * BUFSIZ], *cp;
347    ZNotice_t retnotice;
348
349    success = 0;
350       
351    for (i=0;i<nrecips || !nrecips;i++) {
352        if (realm) {
353            sprintf(realm_recip, "%s@%s", (nrecips) ? recips[i] : "", realm);
354            notice->z_recipient = realm_recip;
355        } else {
356            notice->z_recipient = (nrecips) ? recips[i] : "";
357        }
358        if (nrecips)
359            strcpy(dest, recips[i]);
360        else if (!strcmp(class, DEFAULT_CLASS))
361            sprintf(dest, "instance \"%s\"", inst);
362        else if (!strcmp(inst, DEFAULT_INSTANCE))
363            sprintf(dest, "class \"%s\"", class);
364        else
365            sprintf(dest, "class \"%s\", instance \"%s\"", class, inst);
366        if (verbose && real)
367            printf("Sending %smessage, class %s, instance %s, to %s\n",
368                   auth?"authenticated ":"",
369                   class, inst,
370                   nrecips?notice->z_recipient:"everyone");
371        if ((retval = ZSendNotice(notice, auth)) != ZERR_NONE) {
372            (void) sprintf(bfr, "while sending notice to %s", dest);
373            com_err(whoami, retval, bfr);
374            break;
375        }
376        if (real && !quiet) {
377            if (verbose)
378                printf("Queued... ");
379            else
380                printf("Message queued for %s... ", dest);
381            fflush(stdout);
382        }
383        if ((retval = ZIfNotice(&retnotice, (struct sockaddr_in *) 0,
384                                ZCompareUIDPred,
385                                (char *)&notice->z_uid)) !=
386            ZERR_NONE) {
387            ZFreeNotice(&retnotice);
388            (void) sprintf(bfr, "while waiting for acknowledgement for %s",
389                    dest);
390            com_err(whoami, retval, bfr);
391            continue;
392        }
393        if (retnotice.z_kind == SERVNAK) {
394            if (!quiet) {
395                printf("Received authorization failure while sending to %s\n",
396                       dest);
397            }
398            ZFreeNotice(&retnotice);
399            break;                      /* if auth fails, punt */
400        }
401        if (retnotice.z_kind != SERVACK || !retnotice.z_message_len) {
402            if (!quiet) {
403                printf("Detected server failure while receiving acknowledgement for %s\n",
404                       dest);
405            }
406            ZFreeNotice(&retnotice);
407            continue;
408        }
409        if (!strcmp(retnotice.z_message, ZSRVACK_SENT)) {
410            success = 1;
411            if (real && !quiet)
412                printf("sent\n");
413        } else if (!strcmp(retnotice.z_message, ZSRVACK_NOTSENT)) {
414            if (verbose && real && !quiet) {
415                if (strcmp(class, DEFAULT_CLASS)) {
416                    fprintf(stderr, "Not logged in or not subscribing to class %s, instance %s\n",
417                           class, inst);
418                } else {
419                    fprintf(stderr,
420                            "Not logged in or not subscribing to messages\n");
421                }
422            }
423            else if (!quiet) {
424                if (!nrecips) {
425                    fprintf(stderr,
426                            "No one subscribing to class %s, instance %s\n",
427                            class, inst);
428                } else {
429                    if (strcmp(class, DEFAULT_CLASS)) {
430                        fprintf(stderr, "%s: Not logged in or not subscribing to class %s, instance %s\n",
431                               notice->z_recipient, class, inst);
432                    } else {
433                        fprintf(stderr, "%s: Not logged in or not subscribing to messages\n",
434                               notice->z_recipient);
435                    }
436                }
437            }
438        }
439        else
440            printf("Internal failure - illegal message field in server response\n");
441        ZFreeNotice(&retnotice);
442        if (!nrecips)
443            break;
444    }
445    if (!success)
446        exit(1);
447}
448
449void
450usage(s)
451    char *s;
452{
453    fprintf(stderr,
454            "Usage: %s [-a] [-o] [-d] [-v] [-q] [-n] [-t] [-u] [-l]\n\
455\t[-c class] [-i inst] [-O opcode] [-f fsname] [-s signature] [-C]\n\
456\t[user ...] [-F format] [-r realm] [-m message]\n", s);
457    fprintf(stderr,"\t-f and -c are mutually exclusive\n\
458\t-f and -i are mutually exclusive\n\
459\trecipients must be specified unless -c or -f specifies a class\n\
460\tother than the default class or -i or -f specifies an instance\n\
461\tother than the default or urgent instance\n");
462    exit(1);
463}
464
465/*
466  if the -f option is specified, this routine is called to canonicalize
467  an instance of the form hostname[:pack].  It turns the hostname into the
468  name returned by gethostbyname(hostname)
469 */
470
471char *fix_filsrv_inst(str)
472char *str;
473{
474        static char fsinst[BUFSIZ];
475        char *ptr;
476        struct hostent *hp;
477
478        ptr = strchr(str,':');
479        if (ptr)
480                *ptr = '\0';
481       
482        hp = gethostbyname(str);
483        if (!hp) {
484                if (ptr)
485                        *ptr = ':';
486                return(str);
487        }
488        (void) strcpy(fsinst, hp->h_name);
489        if (ptr) {
490                (void) strcat(fsinst, ":");
491                ptr++;
492                (void) strcat(fsinst, ptr);
493        }
494        return(fsinst);
495}
496
497/* convert tabs in the buffer into appropriate # of spaces.
498   slightly tricky since the buffer can have NUL's in it. */
499
500#ifndef TABSTOP
501#define TABSTOP 8                       /* #chars between tabstops */
502#endif /* ! TABSTOP */
503
504void
505un_tabify(bufp, sizep)
506char **bufp;
507register int *sizep;
508{
509    register char *cp, *cp2;
510    char *cp3;
511    register int i;
512    register int column;                /* column of next character */
513    register int size = *sizep;
514
515    for (cp = *bufp, i = 0; size; size--, cp++)
516        if (*cp == '\t')
517            i++;                        /* count tabs in buffer */
518
519    if (!i)
520        return;                         /* no tabs == no work */
521
522    /* To avoid allocation churning, allocate enough extra space to convert
523       every tab into TABSTOP spaces */
524    /* only add (TABSTOP-1)x because we re-use the cell holding the
525       tab itself */
526    cp = malloc((unsigned)(*sizep + (i * (TABSTOP-1))));
527    if (!cp)                            /* XXX */
528        return;                         /* punt expanding if memory fails */
529    cp3 = cp;
530    /* Copy buffer, converting tabs to spaces as we go */
531    for (cp2 = *bufp, column = 1, size = *sizep; size; cp2++, size--) {
532        switch (*cp2) {
533        case '\n':
534        case '\0':
535            /* newline or null: reset column */
536            column = 1;
537            *cp++ = *cp2;               /* copy the newline */
538            break;
539        default:
540            /* copy the character */
541            *cp = *cp2;
542            cp++;
543            column++;
544            break;
545        case '\t':
546            /* it's a tab, compute how many spaces to expand into. */
547            i = TABSTOP - ((column - 1) % TABSTOP);
548            for (; i > 0; i--) {
549                *cp++ = ' ';            /* fill in the spaces */
550                column++;
551                (*sizep)++;             /* increment the size */
552            }
553            (*sizep)--;                 /* remove one (we replaced the tab) */
554            break;
555        }
556    }
557    free(*bufp);                        /* free the old buf */
558    *bufp = cp3;
559    return;
560}
Note: See TracBrowser for help on using the repository browser.