]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/clients/zwrite/zwrite.c
This commit was generated by cvs2svn to compensate for changes in r127,
[1ts-debian.git] / zephyr / clients / zwrite / zwrite.c
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
20 static 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
31 int nrecips, msgarg, verbose, quiet, nodot, cc;
32 char *whoami, *inst, *class, *opcode, *rhs, *galaxy, *recips[MAXRECIPS];
33 Z_AuthProc auth;
34 void un_tabify();
35
36 char *fix_filsrv_inst();
37 void usage(), send_off();
38
39 main(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             rhs = argv[arg];
178             break;
179         case 'G':
180             if (arg == argc-1)
181                 usage(whoami);
182             arg++;
183             galaxy = argv[arg];
184             break;
185         case 'C':
186             cc = 1;
187             break;
188         default:
189             usage(whoami);
190         }
191     }
192
193     if (!nrecips && !(strcmp(class, DEFAULT_CLASS) ||
194                       (strcmp(inst, DEFAULT_INSTANCE) &&
195                        strcmp(inst, URGENT_INSTANCE)))) {
196         /* must specify recipient if using default class and
197            (default instance or urgent instance) */
198         fprintf(stderr, "No recipients specified.\n");
199         usage(whoami);
200     }
201
202     if (!signature) {
203         /* try to find name in the password file */
204         register struct passwd *pwd;
205         register char *cp = sigbfr;
206         register char *cp2, *pp;
207
208         pwd = getpwuid(getuid());
209         if (pwd) {
210             cp2 = pwd->pw_gecos;
211             for (; *cp2 && *cp2 != ',' ; cp2++) {
212                 if (*cp2 == '&') {
213                     pp = pwd->pw_name;
214                     *cp++ = islower(*pp) ? toupper(*pp) : *pp;
215                     pp++;
216                     while (*pp)
217                         *cp++ = *pp++;
218                 } else
219                     *cp++ = *cp2;
220             }
221             signature = sigbfr;
222         }
223     }   
224
225     notice.z_kind = ACKED;
226     notice.z_port = 0;
227     notice.z_class = class;
228     notice.z_class_inst = inst;
229     notice.z_opcode = "PING";
230     notice.z_sender = 0;
231     notice.z_message_len = 0;
232     notice.z_recipient = "";
233     notice.z_dest_galaxy = galaxy;
234     if (format)
235             notice.z_default_format = format;
236     else if (filsys == 1)
237             notice.z_default_format = "@bold(Filesystem Operation Message for $instance:)\nFrom: @bold($sender) at $time $date\n$message";
238     else if (auth == ZAUTH) {
239         if (signature)
240             notice.z_default_format = "Class $class, Instance $instance:\nTo: @bold($recipient) at $time $date\nFrom: @bold($1) <$sender>\n\n$2";
241         else
242             notice.z_default_format = "Class $class, Instance $instance:\nTo: @bold($recipient) at $time $date\n$message";
243     } else {
244         if (signature)
245             notice.z_default_format = "@bold(UNAUTHENTIC) Class $class, Instance $instance at $time $date:\nFrom: @bold($1) <$sender>\n\n$2";
246         else
247             notice.z_default_format = "@bold(UNAUTHENTIC) Class $class, Instance $instance at $time $date:\n$message";
248     }
249     if (!nocheck && nrecips)
250         send_off(&notice, 0);
251         
252     if (!msgarg && isatty(0))
253         if (nodot)
254             printf("Type your message now.  End with the end-of-file character.\n");
255         else
256             printf("Type your message now.  End with control-D or a dot on a line by itself.\n");
257         
258     message = NULL;
259     msgsize = 0;
260     if (signature) {
261         message = malloc((unsigned)(strlen(signature)+2));
262         (void) strcpy(message, signature);
263         msgsize = strlen(message);
264         message[msgsize++] = '\0';
265     } else {
266         message = malloc(1);
267         message[msgsize++] = '\0';
268     }
269
270     if (cc && nrecips > 1) {
271         int size = msgsize;
272         for (arg=0;arg<nrecips;arg++)
273             size += (strlen(recips[arg]) + 2);
274         size += 6;                      /* for the newlines and "cc: " */
275         message = realloc(message, (unsigned) size);
276         (void) strcpy(message+msgsize, "CC: ");
277         msgsize += 4;
278         for (arg=0;arg<nrecips;arg++) {
279             (void) strcpy(message+msgsize, recips[arg]);
280             msgsize += strlen(recips[arg]);
281             if (arg != nrecips-1) {
282                 message[msgsize] = ' ';
283                 msgsize++;
284             }
285         }
286         message[msgsize] = '\n';
287         msgsize += 1;
288     }
289
290     if (msgarg) {
291         int size = msgsize;
292         for (arg=msgarg;arg<argc;arg++)
293                 size += (strlen(argv[arg]) + 1);
294         size++;                         /* for the newline */
295         message = realloc(message, (unsigned) size);
296         for (arg=msgarg;arg<argc;arg++) {
297             (void) strcpy(message+msgsize, argv[arg]);
298             msgsize += strlen(argv[arg]);
299             if (arg != argc-1) {
300                 message[msgsize] = ' ';
301                 msgsize++;
302             } 
303         }
304         message[msgsize] = '\n';
305         msgsize += 1;
306     } else {
307         if (isatty(0)) {
308             for (;;) {
309                 unsigned int l;
310                 if (!fgets(bfr, sizeof bfr, stdin))
311                     break;
312                 if (!nodot && bfr[0] == '.' &&
313                     (bfr[1] == '\n' || bfr[1] == '\0'))
314                     break;
315                 l = strlen(bfr);
316                 message = realloc(message, msgsize+l+1);
317                 (void) strcpy(message+msgsize, bfr);
318                 msgsize += l;
319             }
320             message = realloc(message, (unsigned)(msgsize+1));
321         }
322         else {  /* Use read so you can send binary messages... */
323             while (nchars = read(fileno(stdin), bfr, sizeof bfr)) {
324                 if (nchars == -1) {
325                     fprintf(stderr, "Read error from stdin!  Can't continue!\n");
326                     exit(1);
327                 }
328                 message = realloc(message, (unsigned)(msgsize+nchars));
329                 (void) memcpy(message+msgsize, bfr, nchars);
330                 msgsize += nchars;
331             }
332             /* end of msg */
333             message = realloc(message, (unsigned)(msgsize+1));
334         } 
335     }
336
337     notice.z_opcode = opcode;
338     if (tabexpand)
339         un_tabify(&message, &msgsize);
340     notice.z_message = message;
341     notice.z_message_len = msgsize;
342
343     send_off(&notice, 1);
344     exit(0);
345 }
346
347 void
348 send_off(notice, real)
349     ZNotice_t *notice;
350     int real;
351 {
352     int i, success, retval;
353     char bfr[BUFSIZ], rhs_recip[BUFSIZ], dest[3 * BUFSIZ], *cp;
354     ZNotice_t retnotice;
355
356     success = 0;
357         
358     for (i=0;i<nrecips || !nrecips;i++) {
359         if (rhs) {
360             sprintf(rhs_recip, "%s@%s", (nrecips) ? recips[i] : "", rhs);
361             notice->z_recipient = rhs_recip;
362         } else {
363             notice->z_recipient = (nrecips) ? recips[i] : "";
364         }
365         if (nrecips)
366             strcpy(dest, recips[i]);
367         else if (!strcmp(class, DEFAULT_CLASS))
368             sprintf(dest, "instance \"%s\"", inst);
369         else if (!strcmp(inst, DEFAULT_INSTANCE))
370             sprintf(dest, "class \"%s\"", class);
371         else
372             sprintf(dest, "class \"%s\", instance \"%s\"", class, inst);
373         if (verbose && real)
374             printf("Sending %smessage, class %s, instance %s, to %s\n", 
375                    auth?"authenticated ":"", 
376                    class, inst, 
377                    nrecips?notice->z_recipient:"everyone");
378         if ((retval = ZSendNotice(notice, auth)) != ZERR_NONE) {
379             (void) sprintf(bfr, "while sending notice to %s", dest);
380             com_err(whoami, retval, bfr);
381             break;
382         }
383         if (real && !quiet) {
384             if (verbose)
385                 printf("Queued... ");
386             else
387                 printf("Message queued for %s... ", dest);
388             fflush(stdout);
389         }
390         if ((retval = ZIfNotice(&retnotice, (struct sockaddr_in *) 0,
391                                 ZCompareUIDPred, 
392                                 (char *)&notice->z_uid)) !=
393             ZERR_NONE) {
394             ZFreeNotice(&retnotice);
395             (void) sprintf(bfr, "while waiting for acknowledgement for %s", 
396                     dest);
397             com_err(whoami, retval, bfr);
398             continue;
399         }
400         if (retnotice.z_kind == SERVNAK) {
401             if (!quiet) {
402                 printf("Received authorization failure while sending to %s\n", 
403                        dest);
404             }
405             ZFreeNotice(&retnotice);
406             break;                      /* if auth fails, punt */
407         } 
408         if (retnotice.z_kind != SERVACK || !retnotice.z_message_len) {
409             if (!quiet) {
410                 printf("Detected server failure while receiving acknowledgement for %s\n", 
411                        dest);
412             }
413             ZFreeNotice(&retnotice);
414             continue;
415         }
416         if (!strcmp(retnotice.z_message, ZSRVACK_SENT)) {
417             success = 1;
418             if (real && !quiet)
419                 printf("sent\n");
420         } else if (!strcmp(retnotice.z_message, ZSRVACK_NOTSENT)) {
421             if (verbose && real && !quiet) {
422                 if (strcmp(class, DEFAULT_CLASS)) {
423                     fprintf(stderr, "Not logged in or not subscribing to class %s, instance %s\n", 
424                            class, inst);
425                 } else {
426                     fprintf(stderr,
427                             "Not logged in or not subscribing to messages\n");
428                 }
429             } 
430             else if (!quiet) {
431                 if (!nrecips) {
432                     fprintf(stderr,
433                             "No one subscribing to class %s, instance %s\n", 
434                             class, inst);
435                 } else {
436                     if (strcmp(class, DEFAULT_CLASS)) {
437                         fprintf(stderr, "%s: Not logged in or not subscribing to class %s, instance %s\n", 
438                                notice->z_recipient, class, inst);
439                     } else {
440                         fprintf(stderr, "%s: Not logged in or not subscribing to messages\n", 
441                                notice->z_recipient);
442                     }
443                 }
444             }
445         } 
446         else
447             printf("Internal failure - illegal message field in server response\n");
448         ZFreeNotice(&retnotice);
449         if (!nrecips)
450             break;
451     }
452     if (!success)
453         exit(1);
454
455
456 void
457 usage(s)
458     char *s;
459 {
460     fprintf(stderr,
461             "Usage: %s [-a] [-o] [-d] [-v] [-q] [-n] [-t] [-u] [-l]\n\
462 \t[-c class] [-i inst] [-O opcode] [-f fsname] [-s signature] \n\
463 \t[-G galaxy] [-C]\n\
464 \t[user ...] [-F format] [-r rhs] [-m message]\n", s);
465     fprintf(stderr,"\t-f and -c are mutually exclusive\n\
466 \t-f and -i are mutually exclusive\n\
467 \trecipients must be specified unless -c or -f specifies a class\n\
468 \tother than the default class or -i or -f specifies an instance\n\
469 \tother than the default or urgent instance\n");
470     exit(1);
471
472
473 /*
474   if the -f option is specified, this routine is called to canonicalize
475   an instance of the form hostname[:pack].  It turns the hostname into the
476   name returned by gethostbyname(hostname)
477  */
478
479 char *fix_filsrv_inst(str)
480 char *str;
481 {
482         static char fsinst[BUFSIZ];
483         char *ptr;
484         struct hostent *hp;
485
486         ptr = strchr(str,':');
487         if (ptr)
488                 *ptr = '\0';
489         
490         hp = gethostbyname(str);
491         if (!hp) {
492                 if (ptr)
493                         *ptr = ':';
494                 return(str);
495         }
496         (void) strcpy(fsinst, hp->h_name);
497         if (ptr) {
498                 (void) strcat(fsinst, ":");
499                 ptr++;
500                 (void) strcat(fsinst, ptr);
501         }
502         return(fsinst);
503 }
504
505 /* convert tabs in the buffer into appropriate # of spaces.
506    slightly tricky since the buffer can have NUL's in it. */
507
508 #ifndef TABSTOP
509 #define TABSTOP 8                       /* #chars between tabstops */
510 #endif /* ! TABSTOP */
511
512 void
513 un_tabify(bufp, sizep)
514 char **bufp;
515 register int *sizep;
516 {
517     register char *cp, *cp2;
518     char *cp3;
519     register int i;
520     register int column;                /* column of next character */
521     register int size = *sizep;
522
523     for (cp = *bufp, i = 0; size; size--, cp++)
524         if (*cp == '\t')
525             i++;                        /* count tabs in buffer */
526
527     if (!i)
528         return;                         /* no tabs == no work */
529
530     /* To avoid allocation churning, allocate enough extra space to convert
531        every tab into TABSTOP spaces */
532     /* only add (TABSTOP-1)x because we re-use the cell holding the
533        tab itself */
534     cp = malloc((unsigned)(*sizep + (i * (TABSTOP-1))));
535     if (!cp)                            /* XXX */
536         return;                         /* punt expanding if memory fails */
537     cp3 = cp;
538     /* Copy buffer, converting tabs to spaces as we go */
539     for (cp2 = *bufp, column = 1, size = *sizep; size; cp2++, size--) {
540         switch (*cp2) {
541         case '\n':
542         case '\0':
543             /* newline or null: reset column */
544             column = 1;
545             *cp++ = *cp2;               /* copy the newline */
546             break;
547         default:
548             /* copy the character */
549             *cp = *cp2;
550             cp++;
551             column++;
552             break;
553         case '\t':
554             /* it's a tab, compute how many spaces to expand into. */
555             i = TABSTOP - ((column - 1) % TABSTOP);
556             for (; i > 0; i--) {
557                 *cp++ = ' ';            /* fill in the spaces */
558                 column++;
559                 (*sizep)++;             /* increment the size */
560             }
561             (*sizep)--;                 /* remove one (we replaced the tab) */
562             break;
563         }
564     }
565     free(*bufp);                        /* free the old buf */
566     *bufp = cp3;
567     return;
568 }