]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/clients/zctl/zctl.c
new upstream version
[1ts-debian.git] / zephyr / clients / zctl / zctl.c
1 /* This file is part of the Project Athena Zephyr Notification System.
2  * It contains code for the "zctl" command.
3  *
4  *      Created by:     Robert French
5  *
6  *      $Id: zctl.c 2333 2009-03-22 18:30:19Z kcr $
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/zephyr.h>
15 #include <ss/ss.h>
16 #include <com_err.h>
17 #include <pwd.h>
18 #include <netdb.h>
19 #ifndef lint
20 static const char rcsid_zctl_c[] = "$Id: zctl.c 2333 2009-03-22 18:30:19Z kcr $";
21 #endif
22
23 #define SUBSATONCE 7
24 #define SUB 0
25 #define UNSUB 1
26 #define LIST 2
27
28 #define USERS_SUBS "/.zephyr.subs"
29 #define OLD_SUBS "/.subscriptions"
30
31 #define TOKEN_HOSTNAME  "%host%"
32 #define TOKEN_CANONNAME "%canon%"
33 #define TOKEN_ME        "%me%"
34 #define TOKEN_WILD      "*"
35
36 #define ALL             0
37 #define UNSUBONLY       1
38 #define SUBONLY         2
39
40 #define ERR             (-1)
41 #define NOT_REMOVED     0
42 #define REMOVED         1
43
44 int sci_idx;
45 char subsname[BUFSIZ];
46 char ourhost[MAXHOSTNAMELEN],ourhostcanon[MAXHOSTNAMELEN];
47
48 extern ss_request_table zctl_cmds;
49
50 int purge_subs(register ZSubscription_t *, int);
51 void add_file(short, ZSubscription_t *, int);
52 void del_file(short, ZSubscription_t *, int);
53 void fix_macros(ZSubscription_t *, ZSubscription_t *, int);
54 void fix_macros2(char *, char **);
55 int make_exist(char *);
56
57 int
58 main(int argc,
59      char *argv[])
60 {
61         struct passwd *pwd;
62         struct hostent *hent;
63         char ssline[BUFSIZ],oldsubsname[BUFSIZ],*envptr,*tty = NULL;
64         int retval,code,i;
65 #ifdef HAVE_SYS_UTSNAME
66         struct utsname name;
67 #endif
68
69         if ((retval = ZInitialize()) != ZERR_NONE) {
70                 com_err(argv[0],retval,"while initializing");
71                 exit (1);
72         }
73
74         /* Set hostname and tty for locations.  If we support X, use the
75          * DISPLAY environment variable for the tty name. */
76 #ifndef X_DISPLAY_MISSING
77         tty = getenv("DISPLAY");
78 #endif  
79         if ((retval = ZInitLocationInfo(NULL, tty)) != ZERR_NONE)
80             com_err(argv[0], retval, "initializing location information");
81
82         envptr = getenv("ZEPHYR_SUBS");
83         if (envptr)
84                 strcpy(subsname,envptr);
85         else {
86                 envptr = getenv("HOME");
87                 if (envptr)
88                         strcpy(subsname,envptr);
89                 else {
90                         if (!(pwd = getpwuid((int) getuid()))) {
91                                 fprintf(stderr,"Who are you?\n");
92                                 exit (1);
93                         }
94
95                         strcpy(subsname,pwd->pw_dir);
96                 }
97                 strcpy(oldsubsname,subsname);
98                 strcat(oldsubsname,OLD_SUBS);
99                 strcat(subsname,USERS_SUBS);
100                 if (!access(oldsubsname,F_OK) && access(subsname, F_OK)) {
101                         /* only if old one exists and new one does not exist */
102                         printf("The .subscriptions file in your home directory is now being used as\n.zephyr.subs . I will rename it to .zephyr.subs for you.\n");
103                         if (rename(oldsubsname,subsname))
104                                 com_err(argv[0], errno, "renaming .subscriptions");
105                 }
106         }
107
108 #ifdef HAVE_SYS_UTSNAME
109         uname(&name);
110         strcpy(ourhost, name.nodename);
111 #else
112         if (gethostname(ourhost,MAXHOSTNAMELEN) == -1) {
113                 com_err(argv[0],errno,"while getting host name");
114                 exit (1);
115         }
116 #endif
117
118         if (!(hent = gethostbyname(ourhost))) {
119                 fprintf(stderr,"%s: Can't resolve hostname %s; %s may be "
120                         "wrong in subscriptions\n",argv[0],ourhost,
121                         TOKEN_CANONNAME);
122                 strncpy(ourhostcanon,ourhost,sizeof(ourhostcanon)-1);
123         } else
124                 strncpy(ourhostcanon,hent->h_name,sizeof(ourhostcanon)-1);
125
126         sci_idx = ss_create_invocation("zctl","",0,&zctl_cmds,&code);
127         if (code) {
128                 ss_perror(sci_idx,code,"while creating invocation");
129                 exit(1);
130         }
131
132         if (argc > 1) {
133                 *ssline = '\0';
134                 for (i=1;i<argc;i++)
135                         (void) sprintf(ssline+strlen(ssline),"%s ",argv[i]);
136                 ssline[strlen(ssline)-1] = '\0';
137                 code = ss_execute_line(sci_idx,ssline);
138                 if (code)
139                     fprintf (stderr, "%s: %s: %s\n",
140                              argv[0], error_message (code), ssline);
141                 exit((code != 0));
142         } 
143
144         printf("ZCTL $Revision: 2333 $ (Protocol %s%d.%d) - Type '?' for a list of commands.\n\n",
145                ZVERSIONHDR,
146                ZVERSIONMAJOR,ZVERSIONMINOR);
147         
148         ss_listen(sci_idx);
149         exit(0);
150 }
151
152 void
153 set_file(int argc,
154          char *argv[])
155 {
156         if (argc > 2) {
157                 fprintf(stderr,"Usage: %s filename\n",argv[0]);
158                 return;
159         }
160
161         if (argc == 1)
162                 printf("Current file: %s\n",subsname);
163         else
164                 (void) strcpy(subsname,argv[1]);
165 }
166
167 void
168 flush_locations(int argc,
169                 char *argv[])
170 {
171         int retval;
172         
173         if (argc > 1) {
174                 fprintf(stderr,"Usage: %s\n",argv[0]);
175                 return;
176         }
177
178         if ((retval = ZFlushMyLocations()) != ZERR_NONE)
179                 ss_perror(sci_idx,retval,"while flushing locations");
180 }
181
182 void
183 wgc_control(int argc,
184             char *argv[])
185 {
186         int retval;
187         short newport;
188         struct sockaddr_in newsin;
189         ZNotice_t notice;
190
191         newsin = ZGetDestAddr();
192
193         if (argc > 1) {
194                 fprintf(stderr,"Usage: %s\n",argv[0]);
195                 return;
196         }
197         
198         if ((newport = ZGetWGPort()) == -1) {
199                 ss_perror(sci_idx,errno,"while getting WindowGram port");
200                 return;
201         }
202
203         newsin.sin_port = (u_short) newport;
204         if ((retval = ZSetDestAddr(&newsin)) != ZERR_NONE) {
205                 ss_perror(sci_idx,retval,"while setting destination address");
206                 return;
207         }
208
209         (void) memset((char *)&notice, 0, sizeof(notice));
210         notice.z_kind = UNSAFE;
211         notice.z_port = 0;
212         notice.z_class = WG_CTL_CLASS;
213         notice.z_class_inst = WG_CTL_USER;
214
215         if (!strcmp(argv[0],"wg_read"))
216                 notice.z_opcode = USER_REREAD;
217         if (!strcmp(argv[0],"wg_shutdown"))
218                 notice.z_opcode = USER_SHUTDOWN;
219         if (!strcmp(argv[0],"wg_startup"))
220                 notice.z_opcode = USER_STARTUP;
221         if (!strcmp(argv[0],"wg_exit"))
222                 notice.z_opcode = USER_EXIT;
223         if (!notice.z_opcode) {
224                 fprintf(stderr,
225                         "unknown WindowGram client control command %s\n",
226                         argv[0]);
227                 return;
228         }
229         notice.z_sender = 0;
230         notice.z_recipient = "";
231         notice.z_default_format = "";
232         notice.z_message_len = 0;
233
234         if ((retval = ZSendNotice(&notice,ZNOAUTH)) != ZERR_NONE)
235                 ss_perror(sci_idx,retval,"while sending notice");
236
237         if ((retval = ZInitialize()) != ZERR_NONE)
238                 ss_perror(sci_idx,retval,
239                           "while reinitializing");
240
241
242 void
243 hm_control(int argc,
244            char *argv[])
245 {
246         int retval;
247         ZNotice_t notice;
248
249         if (argc > 1) {
250                 fprintf(stderr,"Usage: %s\n",argv[0]);
251                 return;
252         }
253         
254         (void) memset((char *)&notice, 0, sizeof(notice));
255         notice.z_kind = HMCTL;
256         notice.z_port = 0;
257         notice.z_class = HM_CTL_CLASS;
258         notice.z_class_inst = HM_CTL_CLIENT;
259
260         if (!strcmp(argv[0],"hm_flush"))
261                 notice.z_opcode = CLIENT_FLUSH;
262         if (!strcmp(argv[0],"new_server"))
263                 notice.z_opcode = CLIENT_NEW_SERVER;
264         if (!notice.z_opcode) {
265                 fprintf(stderr, "unknown HostManager control command %s\n",
266                         argv[0]);
267                 return;
268         }
269         notice.z_sender = 0;
270         notice.z_recipient = "";
271         notice.z_default_format = "";
272         notice.z_message_len = 0;
273
274         if ((retval = ZSendNotice(&notice,ZNOAUTH)) != ZERR_NONE)
275                 ss_perror(sci_idx,retval,"while sending notice");
276
277
278 void
279 show_var(int argc,
280          char *argv[])
281 {
282         int i;
283         char *value;
284         
285         if (argc < 2) {
286                 fprintf(stderr,"Usage: %s <varname> <varname> ...\n",argv[0]);
287                 return;
288         }
289
290         for (i=1;i<argc;i++) {
291                 value = ZGetVariable(argv[i]);
292                 if (value)
293                         printf("%s: %s\n",argv[i],value);
294                 else
295                         printf("%s: not defined\n",argv[i]);
296         }
297 }
298
299 void
300 set_var(int argc, char *argv[])
301 {
302         int retval,setting_exp,i;
303         char *exp_level = NULL;
304         char *newargv[1];
305         char varcat[BUFSIZ];
306         
307         if (argc < 2) {
308                 fprintf(stderr,"Usage: %s <varname> [value]\n",
309                         argv[0]);
310                 return;
311         }
312
313         setting_exp = 0;
314
315         if (!strcasecmp(argv[1],"exposure")) {
316                 setting_exp = 1;
317                 if (argc != 3) {
318                         fprintf(stderr,"An exposure setting must be specified.\n");
319                         return;
320                 }
321                 exp_level = (char *)0;
322                 if (!strcasecmp(argv[2],EXPOSE_NONE))
323                         exp_level = EXPOSE_NONE;
324                 if (!strcasecmp(argv[2],EXPOSE_OPSTAFF))
325                         exp_level = EXPOSE_OPSTAFF;
326                 if (!strcasecmp(argv[2],EXPOSE_REALMVIS))
327                         exp_level = EXPOSE_REALMVIS;
328                 if (!strcasecmp(argv[2],EXPOSE_REALMANN))
329                         exp_level = EXPOSE_REALMANN;
330                 if (!strcasecmp(argv[2],EXPOSE_NETVIS))
331                         exp_level = EXPOSE_NETVIS;
332                 if (!strcasecmp(argv[2],EXPOSE_NETANN))
333                         exp_level = EXPOSE_NETANN;
334                 if (!exp_level) {
335                         fprintf(stderr,"The exposure setting must be one of:\n");
336                         fprintf(stderr,"%s, %s, %s, %s, %s, %s.\n",
337                                 EXPOSE_NONE,
338                                 EXPOSE_OPSTAFF,
339                                 EXPOSE_REALMVIS,
340                                 EXPOSE_REALMANN,
341                                 EXPOSE_NETVIS,
342                                 EXPOSE_NETANN);
343                         return;
344                 }
345         } 
346         if (argc == 2)
347                 retval = ZSetVariable(argv[1],"");
348         else {
349                 (void) strcpy(varcat,argv[2]);
350                 for (i=3;i<argc;i++) {
351                         (void) strcat(varcat," ");
352                         (void) strcat(varcat,argv[i]);
353                 } 
354                 retval = ZSetVariable(argv[1],varcat);
355         } 
356
357         if (retval != ZERR_NONE) {
358                 ss_perror(sci_idx,retval,"while setting variable value");
359                 return;
360         }
361
362         /* Side-effects?  Naw, us? */
363         
364         if (setting_exp) {
365                 if ((retval = ZSetLocation(exp_level)) != ZERR_NONE)
366                         ss_perror(sci_idx,retval,"while changing exposure status");
367                 if (!strcmp(exp_level,EXPOSE_NONE)) {
368                         newargv[0] = "wg_shutdown";
369                         wgc_control(1,newargv);
370                 } else {
371                         newargv[0] = "wg_startup";
372                         wgc_control(1,newargv);
373                 }
374                 return;
375         } 
376 }
377
378 void
379 do_hide(int argc,
380         char *argv[])
381 {
382         char *exp_level = NULL;
383         Code_t retval;
384
385         if (argc != 1) {
386                 fprintf(stderr, "Usage: %s\n",argv[0]);
387                 return;
388         }
389         if (!strcmp(argv[0],"unhide"))
390                 exp_level = EXPOSE_REALMVIS;
391         else
392                 exp_level = EXPOSE_OPSTAFF;
393         if ((retval = ZSetLocation(exp_level)) != ZERR_NONE)
394                 ss_perror(sci_idx,retval,"while changing exposure status");
395         return;
396 }
397
398 void
399 unset_var(int argc,
400           char *argv[])
401 {
402         int retval,i;
403         
404         if (argc < 2) {
405                 fprintf(stderr,"Usage: %s <varname> [<varname> ... ]\n",
406                         argv[0]);
407                 return;
408         }
409
410         for (i=1;i<argc;i++)
411                 if ((retval = ZUnsetVariable(argv[i])) != ZERR_NONE)
412                         ss_perror(sci_idx,retval,
413                                   "while unsetting variable value");
414 }
415
416 void
417 cancel_subs(int argc,
418             char *argv[])
419 {
420         int retval;
421         short wgport;
422
423         if (argc != 1) {
424                 fprintf(stderr,"Usage: %s\n",argv[0]);
425                 return;
426         } 
427
428         if ((wgport = ZGetWGPort()) == -1) {
429                 ss_perror(sci_idx,errno,"while finding WindowGram port");
430                 return;
431         } 
432         if ((retval = ZCancelSubscriptions((u_short)wgport)) != ZERR_NONE)
433                 ss_perror(sci_idx,retval,"while cancelling subscriptions");
434 }
435
436 void
437 subscribe(int argc,
438           char *argv[])
439 {
440         int retval;
441         short wgport;
442         ZSubscription_t sub,sub2;
443         
444         if (argc > 4 || argc < 3) {
445                 fprintf(stderr,"Usage: %s class instance [*]\n",argv[0]);
446                 return;
447         }
448         
449         sub.zsub_class = argv[1];
450         sub.zsub_classinst = argv[2];
451         sub.zsub_recipient = (argc == 3)?ZGetSender():argv[3];
452
453         fix_macros(&sub,&sub2,1);
454         
455         if ((wgport = ZGetWGPort()) == -1) {
456                 ss_perror(sci_idx,errno,"while finding WindowGram port");
457                 return;
458         } 
459
460         retval = (*argv[0] == 's') ?
461                 ZSubscribeToSansDefaults(&sub2,1,(u_short)wgport) :
462                 ZUnsubscribeTo(&sub2,1,(u_short)wgport);
463         
464         if (retval != ZERR_NONE)
465                 ss_perror(sci_idx,retval,"while subscribing");
466
467
468 void
469 sub_file(int argc,
470          char *argv[])
471 {
472         ZSubscription_t sub;
473         short wgport;
474
475         if (argc > 4 || argc < 3) {
476                 fprintf(stderr,"Usage: %s class instance [*]\n",argv[0]);
477                 return;
478         }
479
480         if (argv[1][0] == '!') {
481                 ss_perror(sci_idx,0,
482                           (!strcmp(argv[0],"add_unsubscription") ||
483                            !strcmp(argv[0],"add_un") ||
484                            !strcmp(argv[0],"delete_unsubscription") ||
485                            !strcmp(argv[0],"del_un")) ?
486                           "Do not use `!' as the first character of a class.\n\tIt is automatically added before modifying the subscription file." :
487                           "Do not use `!' as the first character of a class.\n\tIt is reserved for internal use with un-subscriptions.");
488                 return;
489         }
490         sub.zsub_class = argv[1];
491         sub.zsub_classinst = argv[2];
492         sub.zsub_recipient = (argc == 3)?TOKEN_ME:argv[3];
493
494         if (make_exist(subsname))
495                 return;
496         if ((wgport = ZGetWGPort()) == -1) {
497                 ss_perror(sci_idx,errno,"while finding WindowGram port");
498                 return;
499         } 
500
501         if (!strcmp(argv[0],"add"))
502                 add_file(wgport,&sub,0);
503         else if (!strcmp(argv[0],"add_unsubscription") ||
504                  !strcmp(argv[0],"add_un"))
505                 add_file(wgport,&sub,1);
506         else if (!strcmp(argv[0],"delete") ||
507                  !strcmp(argv[0],"del") ||
508                  !strcmp(argv[0],"dl"))
509                 del_file(wgport,&sub,0);
510         else if (!strcmp(argv[0],"delete_unsubscription") ||
511                  !strcmp(argv[0],"del_un")) {
512                 del_file(wgport,&sub,1);
513         } else
514                 ss_perror(sci_idx,0,"unknown command name");
515         return;
516 }
517
518 void
519 add_file(short wgport,
520          ZSubscription_t *subs,
521          int unsub)
522 {
523         FILE *fp;
524         char errbuf[BUFSIZ];
525         ZSubscription_t sub2;
526         Code_t retval;
527
528         (void) purge_subs(subs,ALL);    /* remove copies in the subs file */
529         if (!(fp = fopen(subsname,"a"))) {
530                 (void) sprintf(errbuf,"while opening %s for append",subsname);
531                 ss_perror(sci_idx,errno,errbuf);
532                 return;
533         } 
534         fprintf(fp,"%s%s,%s,%s\n",
535                 unsub ? "!" : "",
536                 subs->zsub_class, subs->zsub_classinst, subs->zsub_recipient);
537         if (fclose(fp) == EOF) {
538                 (void) sprintf(errbuf, "while closing %s", subsname);
539                 ss_perror(sci_idx, errno, errbuf);
540                 return;
541         }
542         fix_macros(subs,&sub2,1);
543         retval = (unsub
544                   ? ZUnsubscribeTo(&sub2,1,(u_short)wgport)
545                   : ZSubscribeToSansDefaults(&sub2,1,(u_short)wgport));
546         if (retval)
547                 ss_perror(sci_idx,retval,
548                           unsub ? "while unsubscribing" :
549                           "while subscribing");
550         return;
551 }
552
553 void
554 del_file(short wgport,
555          register ZSubscription_t *subs,
556          int unsub)
557 {
558         ZSubscription_t sub2;
559         int retval;
560         
561         retval = purge_subs(subs, unsub ? UNSUBONLY : SUBONLY);
562         if (retval == ERR)
563                 return;
564         if (retval == NOT_REMOVED)
565                 fprintf(stderr,
566                         "Couldn't find %sclass %s instance %s recipient %s in\n\tfile %s\n",
567                         unsub ? "un-subscription " : "",
568                         subs->zsub_class, subs->zsub_classinst,
569                         subs->zsub_recipient, subsname);
570         fix_macros(subs,&sub2,1);
571         if ((retval = ZUnsubscribeTo(&sub2,1,(u_short)wgport)) !=
572             ZERR_NONE)
573                 ss_perror(sci_idx,retval,"while unsubscribing");
574         return;
575 }
576
577 int
578 purge_subs(register ZSubscription_t *subs,
579            int which)
580 {
581         FILE *fp,*fpout;
582         char errbuf[BUFSIZ],subline[BUFSIZ];
583         char backup[BUFSIZ],ourline[BUFSIZ];
584         int delflag = NOT_REMOVED;
585         int keep = 0;
586
587         switch (which) {
588         case SUBONLY:
589         case UNSUBONLY:
590         case ALL:
591                 break;
592         default:
593                 ss_perror(sci_idx,0,"internal error in purge_subs");
594                 return(ERR);
595         }
596
597         (void) sprintf(ourline,"%s,%s,%s",
598                        subs->zsub_class,
599                        subs->zsub_classinst,
600                        subs->zsub_recipient);
601
602         if (!(fp = fopen(subsname,"r"))) {
603                 (void) sprintf(errbuf,"while opening %s for read",subsname);
604                 ss_perror(sci_idx,errno,errbuf);
605                 return(ERR);
606         } 
607         (void) strcpy(backup, subsname);
608         (void) strcat(backup, ".temp");
609         (void) unlink(backup);
610         if (!(fpout = fopen(backup,"w"))) {
611                 (void) sprintf(errbuf,"while opening %s for writing",backup);
612                 ss_perror(sci_idx,errno,errbuf);
613                 (void) fclose(fp);
614                 return(ERR);
615         } 
616         for (;;) {
617                 if (!fgets(subline,sizeof subline,fp))
618                         break;
619                 if (*subline)
620                         subline[strlen(subline)-1] = '\0'; /* nuke newline */
621                 switch (which) {
622                 case SUBONLY:
623                         keep = strcmp(subline,ourline);
624                         break;
625                 case UNSUBONLY:
626                         keep = (*subline != '!' || strcmp(subline+1,ourline));
627                         break;
628                 case ALL:
629                         keep = (strcmp(subline,ourline) &&
630                                 (*subline != '!' || strcmp(subline+1,
631                                                            ourline)));
632                         break;
633                 }
634                 if (keep) {
635                         fputs(subline, fpout);
636                         if (ferror(fpout) || (fputc('\n', fpout) == EOF)) {
637                                 (void) sprintf(errbuf, "while writing to %s",
638                                                backup);
639                                 ss_perror(sci_idx, errno, errbuf);
640                         }
641                 } else
642                         delflag = REMOVED;
643         }
644         (void) fclose(fp);              /* open read-only, ignore errs */
645         if (fclose(fpout) == EOF) {
646                 (void) sprintf(errbuf, "while closing %s",backup);
647                 ss_perror(sci_idx, errno, errbuf);
648                 return(ERR);
649         }
650         if (rename(backup,subsname) == -1) {
651                 (void) sprintf(errbuf,"while renaming %s to %s\n",
652                                backup,subsname);
653                 ss_perror(sci_idx,errno,errbuf);
654                 return(ERR);
655         }
656         return(delflag);
657 }
658
659 void
660 load_subs(int argc,
661           char *argv[])
662 {
663         ZSubscription_t subs[SUBSATONCE],subs2[SUBSATONCE],unsubs[SUBSATONCE];
664 #ifdef CMU_ZCTL_PUNT
665         ZSubscription_t punts[SUBSATONCE];
666         int pind;
667 #endif
668         FILE *fp;
669         int ind,unind,lineno,i,retval,type;
670         short wgport = 0;
671         char *comma,*comma2,*file,subline[BUFSIZ];
672
673         if (argc > 2) {
674                 fprintf(stderr,"Usage: %s [file]\n",argv[0]);
675                 return;
676         }
677
678         if (*argv[0] == 'u')
679                 type = UNSUB;
680         else
681                 if (!strcmp(argv[0],"list") || !strcmp(argv[0],"ls"))
682                         type = LIST;
683                 else
684                         type = SUB;
685
686         if (type != LIST) 
687                 if ((wgport = ZGetWGPort()) == -1) {
688                         ss_perror(sci_idx,errno,
689                                   "while finding WindowGram port");
690                         return;
691                 } 
692
693         file = (argc == 1) ? subsname : argv[1];
694         
695         fp = fopen(file,"r");
696
697         if (fp == NULL) {
698                 ss_perror(sci_idx,errno,
699                           "while loading subscription file");
700                 return;
701         }
702         
703 #ifdef CMU_ZCTL_PUNT
704         pind =
705 #endif
706           ind = unind = 0;
707         lineno = 1;
708         
709         for (;;lineno++) {
710                 if (!fgets(subline,sizeof subline,fp))
711                         break;
712                 if (*subline == '#' || !*subline)
713                         continue;
714                 subline[strlen(subline)-1] = '\0'; /* nuke newline */
715                 comma = strchr(subline,',');
716                 if (comma)
717                         comma2 = strchr(comma+1,',');
718                 else
719                         comma2 = 0;
720                 if (!comma || !comma2) {
721                         fprintf(stderr,
722                                 "Malformed subscription at line %d of %s:\n%s\n",
723                                 lineno,file,subline);
724                         continue;
725                 }
726                 *comma = '\0';
727                 *comma2 = '\0';
728                 if (type == LIST) {
729                         if (*subline == '!') 
730                                 printf("(Un-subscription) Class %s instance %s recipient %s\n",
731                                        subline+1, comma+1, comma2+1);
732 #ifdef CMU_ZCTL_PUNT
733                         else if(*subline == '-')
734                                 printf("(Punted) Class %s instance %s recipient %s\n",
735                                        subline+1, comma+1, comma2+1);
736 #endif
737                         else
738                                 printf("Class %s instance %s recipient %s\n",
739                                        subline, comma+1, comma2+1);
740                         continue;
741                 }
742                 if (*subline == '!') {  /* an un-subscription */
743                         /* if we are explicitly un-subscribing to
744                            the contents of a subscription file, ignore
745                            any un-subscriptions in that file */
746                         if (type == UNSUB)
747                                 continue;
748                         unsubs[unind].zsub_class =
749                             (char *)malloc((unsigned)(strlen(subline)));
750                         /* XXX check malloc return */
751                         /* skip the leading '!' */
752                         (void) strcpy(unsubs[unind].zsub_class,subline+1);
753                         unsubs[unind].zsub_classinst =
754                             (char *)malloc((unsigned)(strlen(comma+1)+1));
755                         /* XXX check malloc return */
756                         (void) strcpy(unsubs[unind].zsub_classinst,comma+1);
757                         unsubs[unind].zsub_recipient =
758                             (char *)malloc((unsigned)(strlen(comma2+1)+1));
759                         /* XXX check malloc return */
760                         (void) strcpy(unsubs[unind].zsub_recipient,comma2+1);
761                         unind++;
762                 } else
763 #ifdef CMU_ZCTL_PUNT
764                 if (*subline == '-') {  /* a punt */
765                         if (type == UNSUB)
766                                 continue;
767                         punts[pind].zsub_class =
768                             (char *)malloc((unsigned)(strlen(subline)+1));
769                         /* XXX check malloc return */
770                         (void) strcpy(punts[pind].zsub_class,subline+1);
771                         punts[pind].zsub_classinst =
772                             (char *)malloc((unsigned)(strlen(comma+1)+1));
773                         /* XXX check malloc return */
774                         (void) strcpy(punts[pind].zsub_classinst,comma+1);
775                         punts[pind].zsub_recipient =
776                             (char *)malloc((unsigned)(strlen(comma2+1)+1));
777                         /* XXX check malloc return */
778                         (void) strcpy(punts[pind].zsub_recipient,comma2+1);
779                         pind++;
780                 } else
781 #endif
782                 { 
783                         subs[ind].zsub_class =
784                             (char *)malloc((unsigned)(strlen(subline)+1));
785                         /* XXX check malloc return */
786                         (void) strcpy(subs[ind].zsub_class,subline);
787                         subs[ind].zsub_classinst =
788                             (char *)malloc((unsigned)(strlen(comma+1)+1));
789                         /* XXX check malloc return */
790                         (void) strcpy(subs[ind].zsub_classinst,comma+1);
791                         subs[ind].zsub_recipient =
792                             (char *)malloc((unsigned)(strlen(comma2+1)+1));
793                         /* XXX check malloc return */
794                         (void) strcpy(subs[ind].zsub_recipient,comma2+1);
795                         ind++;
796                 }
797 #ifdef CMU_ZCTL_PUNT
798                 if (pind == SUBSATONCE) {
799                          fix_macros(punts,subs2,pind);
800                          if (retval = ZPunt(subs2,pind,(u_short)wgport) !=
801                              ZERR_NONE)
802                            {
803                              ss_perror(sci_idx,retval,
804                                        "while punting");
805                              goto cleanup;
806                            }
807                          for (i=0;i<pind;i++) {
808                                  free(punts[i].zsub_class);
809                                  free(punts[i].zsub_classinst);
810                                  free(punts[i].zsub_recipient);
811                          }
812                          pind = 0;
813                 }
814 #endif
815                 if (ind == SUBSATONCE) {
816                         fix_macros(subs,subs2,ind);
817                         if ((retval = (type == SUB)?
818                              ZSubscribeTo(subs2,ind,(u_short)wgport):
819                              ZUnsubscribeTo(subs2,ind,(u_short)wgport)) !=
820                             ZERR_NONE) {
821                                 ss_perror(sci_idx,retval,(type == SUB)?
822                                           "while subscribing":
823                                           "while unsubscribing");
824                                 goto cleanup;
825                         }
826                         for (i=0;i<ind;i++) {
827                                 free(subs[i].zsub_class);
828                                 free(subs[i].zsub_classinst);
829                                 free(subs[i].zsub_recipient);
830                         } 
831                         ind = 0;
832                 }
833                 if (unind == SUBSATONCE) {
834                         fix_macros(unsubs,subs2,unind);
835                         if ((retval = ZUnsubscribeTo(subs2,unind,(u_short)wgport)) != ZERR_NONE) {
836                                 ss_perror(sci_idx,retval,
837                                           "while unsubscribing to un-subscriptions");
838                                 goto cleanup;
839                         }
840                         for (i=0;i<unind;i++) {
841                                 free(unsubs[i].zsub_class);
842                                 free(unsubs[i].zsub_classinst);
843                                 free(unsubs[i].zsub_recipient);
844                         } 
845                         unind = 0;
846                 }
847         }
848         
849         if (type != LIST) {
850                 /* even if we have no subscriptions, be sure to send
851                    an empty packet to trigger the default subscriptions */
852                 fix_macros(subs,subs2,ind);
853                 if ((retval = (type == SUB)?ZSubscribeTo(subs2,ind,(u_short)wgport):
854                      ZUnsubscribeTo(subs2,ind,(u_short)wgport)) != ZERR_NONE) {
855                         ss_perror(sci_idx,retval,(type == SUB)?
856                                   "while subscribing":
857                                   "while unsubscribing");
858                         goto cleanup;
859                 }
860                 if (unind) {
861                         fix_macros(unsubs,subs2,unind);
862                         if ((retval =
863                              ZUnsubscribeTo(subs2,unind,(u_short)wgport)) != ZERR_NONE) {
864                                 ss_perror(sci_idx,retval,
865                                           "while unsubscribing to un-subscriptions");
866                                 goto cleanup;
867                         }
868                 }
869 #ifdef CMU_ZCTL_PUNT
870                 if (pind) {
871                         fix_macros(punts,subs2,pind);
872                         if (retval = ZPunt(subs2,pind,(u_short)wgport) !=
873                             ZERR_NONE)
874                         {
875                           ss_perror(sci_idx,retval,
876                                     "while punting");
877                           goto cleanup;
878                         }
879                 }
880 #endif
881         }
882 cleanup:
883         for (i=0;i<ind;i++) {
884           free(subs[i].zsub_class);
885           free(subs[i].zsub_classinst);
886           free(subs[i].zsub_recipient);
887         } 
888         for (i=0;i<unind;i++) {
889           free(unsubs[i].zsub_class);
890           free(unsubs[i].zsub_classinst);
891           free(unsubs[i].zsub_recipient);
892         } 
893 #ifdef CMU_ZCTL_PUNT
894         for (i=0;i<pind;i++) {
895           free(punts[i].zsub_class);
896           free(punts[i].zsub_classinst);
897           free(punts[i].zsub_recipient);
898         }
899 #endif
900
901         (void) fclose(fp);      /* ignore errs--file is read-only */
902         return;
903 }
904
905 void
906 current(int argc,
907         char *argv[])
908 {
909         FILE *fp = NULL;
910         char errbuf[BUFSIZ];
911         ZSubscription_t subs;
912         int i,nsubs,retval,save,one,defs;
913         short wgport;
914         char backup[BUFSIZ];
915         char *file = NULL;
916         
917         save = 0;
918         defs = 0;
919
920         if (!strcmp(argv[0],"save"))
921                 save = 1;
922         else if (!strcmp(argv[0], "defaults") || !strcmp(argv[0], "defs"))
923                 defs = 1;
924
925         if (argc != 1 && !(save && argc == 2)) {
926                 fprintf(stderr,"Usage: %s%s\n",argv[0],save?" [filename]":"");
927                 return;
928         }
929
930         if (!defs)
931                 if ((wgport = ZGetWGPort()) == -1) {
932                         ss_perror(sci_idx,errno,
933                                   "while finding WindowGram port");
934                         return;
935                 } 
936
937         if (defs)
938                 retval = ZRetrieveDefaultSubscriptions(&nsubs);
939         else
940                 retval = ZRetrieveSubscriptions((u_short)wgport,&nsubs);
941
942         if (retval == ZERR_TOOMANYSUBS) {
943                 fprintf(stderr,"Too many subscriptions -- some have not been returned.\n");
944                 if (save) {
945                         fprintf(stderr,"Save aborted.\n");
946                         return;
947                 }
948         }
949         else
950                 if (retval != ZERR_NONE) {
951                         ss_perror(sci_idx,retval,"retrieving subscriptions");
952                         return;
953                 }
954
955         if (save) {
956                 file = (argc == 1)?subsname:argv[1];
957                 (void) strcpy(backup,file);
958                 (void) strcat(backup,".temp");
959                 if (!(fp = fopen(backup,"w"))) {
960                         (void) sprintf(errbuf,"while opening %s for write",
961                                        backup);
962                         ss_perror(sci_idx,errno,errbuf);
963                         return;
964                 }
965         }
966         
967         for (i=0;i<nsubs;i++) {
968                 one = 1;
969                 if ((retval = ZGetSubscriptions(&subs,&one)) != ZERR_NONE) {
970                         ss_perror(sci_idx,retval,"while getting subscription");
971                         if (save) {
972                                 fprintf(stderr,"Subscriptions file not modified\n");
973                                 (void) fclose(fp);
974                                 (void) unlink(backup);
975                         }
976                         return;
977                 } 
978                 if (save)
979                         fprintf(fp,"%s,%s,%s\n",subs.zsub_class,
980                                 subs.zsub_classinst, subs.zsub_recipient);
981                 else
982                         printf("Class %s Instance %s Recipient %s\n",
983                                subs.zsub_class, subs.zsub_classinst,
984                                subs.zsub_recipient);
985         }
986
987         if (save) {
988                 if (fclose(fp) == EOF) {
989                         (void) sprintf(errbuf, "while closing %s", backup);
990                         ss_perror(sci_idx, errno, errbuf);
991                         return;
992                 }
993                 if (rename(backup,file) == -1) {
994                         (void) sprintf(errbuf,"while renaming %s to %s",
995                                        backup,file);
996                         ss_perror(sci_idx,retval,errbuf);
997                         (void) unlink(backup);
998                 }
999         }
1000 }
1001
1002 int
1003 make_exist(char *filename)
1004 {
1005         char errbuf[BUFSIZ];
1006         FILE *fpout;
1007         
1008         if (!access(filename,F_OK))
1009                 return (0);
1010
1011         if (!(fpout = fopen(filename,"w"))) {
1012                 (void) sprintf(errbuf,"while opening %s for write",filename);
1013                 ss_perror(sci_idx,errno,errbuf);
1014                 return (1);
1015         }
1016
1017         if (fclose(fpout) == EOF) {
1018                 (void) sprintf(errbuf, "while closing %s", filename);
1019                 ss_perror(sci_idx, errno, errbuf);
1020                 return(1);
1021         }
1022         return (0);
1023 }
1024
1025 void
1026 fix_macros(ZSubscription_t *subs,
1027            ZSubscription_t *subs2,
1028            int num)
1029 {
1030         int i;
1031
1032         for (i=0;i<num;i++) {
1033                 subs2[i] = subs[i];
1034                 fix_macros2(subs[i].zsub_class,&subs2[i].zsub_class);
1035                 fix_macros2(subs[i].zsub_classinst,&subs2[i].zsub_classinst);
1036                 fix_macros2(subs[i].zsub_recipient,&subs2[i].zsub_recipient);
1037         }
1038 }
1039
1040 void
1041 fix_macros2(char *src, char **dest)
1042 {
1043         if (!strcmp(src,TOKEN_HOSTNAME)) {
1044                 *dest = ourhost;
1045                 return;
1046         }
1047         if (!strcmp(src,TOKEN_CANONNAME)) {
1048                 *dest = ourhostcanon;
1049                 return;
1050         }
1051         if (!strcmp(src,TOKEN_ME))
1052                 *dest = ZGetSender();
1053 }
1054
1055 int
1056 do_punt(int argc, char **argv)
1057 {
1058 #ifdef CMU_ZCTL_PUNT
1059   char *class, *inst, *recip, *msg, *whoami = argv[0];
1060   int retval, punt;
1061   short newport;
1062   struct sockaddr_in newsin;
1063   ZNotice_t notice;
1064   
1065   if (! strcmp(whoami, "punt")) punt = 1;
1066   else punt = 0;
1067   
1068   switch (argc) {
1069   case 2:
1070     class = "message";
1071     inst = argv[1];
1072     recip = "";
1073     break;
1074   case 3:
1075     class = argv[1];
1076     inst = argv[2];
1077     recip = "";
1078     break;
1079   case 4:
1080     class = argv[1];
1081     inst = argv[2];
1082     recip = argv[3];
1083     if (*argv[3] == '*') /* fixed so realm punts would work (vs0r) */
1084       if (*(argv[3]+1) == '@')
1085       if (!strcmp((char *)ZGetRealm(), (char *)ZExpandRealm(argv[3]+2))) 
1086         /*check local*/
1087         recip = "";
1088     break;
1089   default:
1090     fprintf(stderr, "Usages:\n");
1091     fprintf(stderr, "\t%s instance\n", whoami);
1092     fprintf(stderr, "\t%s class instance\n", whoami);
1093     fprintf(stderr, "\t%s class instance recipient\n", whoami);
1094     return 1;
1095   }
1096   
1097   retval = ZOpenPort((u_short *) 0);
1098   if(retval != ZERR_NONE) {
1099     com_err(whoami, retval, "while opening Zephyr port.");
1100     return 1;
1101   }
1102   
1103   newsin = ZGetDestAddr();
1104   if ((newport = ZGetWGPort()) == -1) {
1105     fprintf(stderr, "%s: Can't find windowgram port\n", whoami);
1106     return 1;
1107   }
1108     
1109   newsin.sin_port = (unsigned short) newport;
1110   if ((retval = ZSetDestAddr(&newsin)) != ZERR_NONE) {
1111     com_err(whoami,retval,"while setting destination address");
1112     return 1;
1113   }
1114   
1115   msg = (char *) malloc(strlen(class) + strlen(inst) + strlen(recip) + 4);
1116   sprintf(msg, "%s%c%s%c%s", class, '\0', inst, '\0', recip);
1117
1118   if (*recip == '*') 
1119     if (*(recip+1) == '@')
1120       if (strcmp(recip+2, (char *)ZExpandRealm(recip+2))) 
1121         sprintf(msg, "%s%c%s%c%s", class, '\0', inst, '\0', 
1122                 (char *)ZExpandRealm(recip+2));
1123   printf("%s <%s,%s,%s>\n", punt ? "Punting" : "Unpunting",
1124        class, inst, *recip ? recip : "*");
1125   
1126   memset((char *) &notice, 0, sizeof(ZNotice_t));
1127   notice.z_kind = UNSAFE;
1128   notice.z_class = WG_CTL_CLASS;
1129   notice.z_class_inst = WG_CTL_USER;
1130   notice.z_recipient = "";
1131   notice.z_default_format = "";
1132   notice.z_opcode = (punt) ? "SUPPRESS" : "UNSUPPRESS";
1133   notice.z_port = 0;
1134   notice.z_message = msg;
1135   notice.z_message_len = strlen(class)+strlen(inst)+strlen(recip)+3;
1136   
1137   if ((retval = ZSendNotice(&notice,ZNOAUTH)) != ZERR_NONE)
1138     fprintf(stderr,"%s: while sending notice\n",whoami);
1139   
1140   free(msg);
1141   
1142   ZClosePort();
1143 #endif
1144   return 0;
1145 }
1146
1147 int
1148 list_punts(int argc, char **argv)
1149 {
1150 #ifdef CMU_ZCTL_PUNT
1151   ZNotice_t notice;
1152   int retval, lensofar;
1153   struct sockaddr_in old, to, from;
1154   u_short ourport, zwgcport;
1155   char *msg;
1156
1157   ourport=0; 
1158   retval = ZOpenPort(&ourport);
1159   if(retval != ZERR_NONE) {
1160     com_err("zctl", retval, "while opening Zephyr port.");
1161     return 1;
1162   }
1163   
1164   old = ZGetDestAddr();
1165   to = old;
1166   if ((zwgcport = ZGetWGPort()) == (u_short)-1) {
1167     fprintf(stderr, "zctl: Can't find windowgram port\n");
1168     return 1;
1169   }
1170   
1171   to.sin_port = (u_short) zwgcport;
1172   if ((retval = ZSetDestAddr(&to)) != ZERR_NONE) {
1173     com_err("zctl",retval,"while setting destination address");
1174     return 1;
1175   }
1176   
1177   memset((char *) &notice, 0, sizeof(ZNotice_t));
1178   notice.z_kind = UNSAFE;
1179   notice.z_class = WG_CTL_CLASS;
1180   notice.z_class_inst = WG_CTL_USER;
1181   notice.z_recipient = "";
1182   notice.z_default_format = "";
1183   notice.z_opcode = "LIST-SUPPRESSED" /*USER_LIST_SUPPRESSED*/;
1184   notice.z_port = ourport;
1185   notice.z_message = NULL;
1186   notice.z_message_len = 0;
1187   
1188   if ((retval = ZSendNotice(&notice,ZNOAUTH)) != ZERR_NONE)
1189     com_err("zctl",retval,"while sending notice");
1190   
1191   if ((retval = ZReceiveNotice(&notice,&from)) != ZERR_NONE)
1192     com_err("zctl",retval,"while receiving ack");
1193   
1194   (void) ZFreeNotice(&notice);
1195   
1196   if ((retval = ZReceiveNotice(&notice,&from)) != ZERR_NONE)
1197     com_err("zctl",retval,"while receiving notice");
1198   
1199   notice.z_auth = ZCheckAuthentication(&notice, &from);
1200   
1201   if ((retval = ZSetDestAddr(&old)) != ZERR_NONE) {
1202     com_err("zctl",retval,"while resetting destination address");
1203     return 1;
1204   }
1205   
1206   msg = (char *) malloc((notice.z_message_len+1) * sizeof(char));
1207   (void) strncpy(msg,notice.z_message, notice.z_message_len);
1208   msg[notice.z_message_len]=(char)0;
1209   printf("%s", msg);
1210   (void) free(msg);
1211   (void) ZFreeNotice(&notice);
1212   (void) ZClosePort();
1213   
1214 #endif /* CMU_ZCTL_PUNT */
1215   return 0;
1216 }