]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/clients/zctl/zctl.c
r4275@bucket (orig r265): kcr | 2008-01-21 02:57:32 -0500
[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$
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$";
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$ (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,*newargv[1];
304         char varcat[BUFSIZ];
305         
306         if (argc < 2) {
307                 fprintf(stderr,"Usage: %s <varname> [value]\n",
308                         argv[0]);
309                 return;
310         }
311
312         setting_exp = 0;
313
314         if (!strcasecmp(argv[1],"exposure")) {
315                 setting_exp = 1;
316                 if (argc != 3) {
317                         fprintf(stderr,"An exposure setting must be specified.\n");
318                         return;
319                 }
320                 exp_level = (char *)0;
321                 if (!strcasecmp(argv[2],EXPOSE_NONE))
322                         exp_level = EXPOSE_NONE;
323                 if (!strcasecmp(argv[2],EXPOSE_OPSTAFF))
324                         exp_level = EXPOSE_OPSTAFF;
325                 if (!strcasecmp(argv[2],EXPOSE_REALMVIS))
326                         exp_level = EXPOSE_REALMVIS;
327                 if (!strcasecmp(argv[2],EXPOSE_REALMANN))
328                         exp_level = EXPOSE_REALMANN;
329                 if (!strcasecmp(argv[2],EXPOSE_NETVIS))
330                         exp_level = EXPOSE_NETVIS;
331                 if (!strcasecmp(argv[2],EXPOSE_NETANN))
332                         exp_level = EXPOSE_NETANN;
333                 if (!exp_level) {
334                         fprintf(stderr,"The exposure setting must be one of:\n");
335                         fprintf(stderr,"%s, %s, %s, %s, %s, %s.\n",
336                                 EXPOSE_NONE,
337                                 EXPOSE_OPSTAFF,
338                                 EXPOSE_REALMVIS,
339                                 EXPOSE_REALMANN,
340                                 EXPOSE_NETVIS,
341                                 EXPOSE_NETANN);
342                         return;
343                 }
344         } 
345         if (argc == 2)
346                 retval = ZSetVariable(argv[1],"");
347         else {
348                 (void) strcpy(varcat,argv[2]);
349                 for (i=3;i<argc;i++) {
350                         (void) strcat(varcat," ");
351                         (void) strcat(varcat,argv[i]);
352                 } 
353                 retval = ZSetVariable(argv[1],varcat);
354         } 
355
356         if (retval != ZERR_NONE) {
357                 ss_perror(sci_idx,retval,"while setting variable value");
358                 return;
359         }
360
361         /* Side-effects?  Naw, us? */
362         
363         if (setting_exp) {
364                 if ((retval = ZSetLocation(exp_level)) != ZERR_NONE)
365                         ss_perror(sci_idx,retval,"while changing exposure status");
366                 if (!strcmp(exp_level,EXPOSE_NONE)) {
367                         newargv[0] = "wg_shutdown";
368                         wgc_control(1,newargv);
369                 } else {
370                         newargv[0] = "wg_startup";
371                         wgc_control(1,newargv);
372                 }
373                 return;
374         } 
375 }
376
377 void
378 do_hide(int argc,
379         char *argv[])
380 {
381         char *exp_level = NULL;
382         Code_t retval;
383
384         if (argc != 1) {
385                 fprintf(stderr, "Usage: %s\n",argv[0]);
386                 return;
387         }
388         if (!strcmp(argv[0],"unhide"))
389                 exp_level = EXPOSE_REALMVIS;
390         else
391                 exp_level = EXPOSE_OPSTAFF;
392         if ((retval = ZSetLocation(exp_level)) != ZERR_NONE)
393                 ss_perror(sci_idx,retval,"while changing exposure status");
394         return;
395 }
396
397 void
398 unset_var(int argc,
399           char *argv[])
400 {
401         int retval,i;
402         
403         if (argc < 2) {
404                 fprintf(stderr,"Usage: %s <varname> [<varname> ... ]\n",
405                         argv[0]);
406                 return;
407         }
408
409         for (i=1;i<argc;i++)
410                 if ((retval = ZUnsetVariable(argv[i])) != ZERR_NONE)
411                         ss_perror(sci_idx,retval,
412                                   "while unsetting variable value");
413 }
414
415 void
416 cancel_subs(int argc,
417             char *argv[])
418 {
419         int retval;
420         short wgport;
421
422         if (argc != 1) {
423                 fprintf(stderr,"Usage: %s\n",argv[0]);
424                 return;
425         } 
426
427         if ((wgport = ZGetWGPort()) == -1) {
428                 ss_perror(sci_idx,errno,"while finding WindowGram port");
429                 return;
430         } 
431         if ((retval = ZCancelSubscriptions((u_short)wgport)) != ZERR_NONE)
432                 ss_perror(sci_idx,retval,"while cancelling subscriptions");
433 }
434
435 void
436 subscribe(int argc,
437           char *argv[])
438 {
439         int retval;
440         short wgport;
441         ZSubscription_t sub,sub2;
442         
443         if (argc > 4 || argc < 3) {
444                 fprintf(stderr,"Usage: %s class instance [*]\n",argv[0]);
445                 return;
446         }
447         
448         sub.zsub_class = argv[1];
449         sub.zsub_classinst = argv[2];
450         sub.zsub_recipient = (argc == 3)?ZGetSender():argv[3];
451
452         fix_macros(&sub,&sub2,1);
453         
454         if ((wgport = ZGetWGPort()) == -1) {
455                 ss_perror(sci_idx,errno,"while finding WindowGram port");
456                 return;
457         } 
458
459         retval = (*argv[0] == 's') ?
460                 ZSubscribeToSansDefaults(&sub2,1,(u_short)wgport) :
461                 ZUnsubscribeTo(&sub2,1,(u_short)wgport);
462         
463         if (retval != ZERR_NONE)
464                 ss_perror(sci_idx,retval,"while subscribing");
465
466
467 void
468 sub_file(int argc,
469          char *argv[])
470 {
471         ZSubscription_t sub;
472         short wgport;
473
474         if (argc > 4 || argc < 3) {
475                 fprintf(stderr,"Usage: %s class instance [*]\n",argv[0]);
476                 return;
477         }
478
479         if (argv[1][0] == '!') {
480                 ss_perror(sci_idx,0,
481                           (!strcmp(argv[0],"add_unsubscription") ||
482                            !strcmp(argv[0],"add_un") ||
483                            !strcmp(argv[0],"delete_unsubscription") ||
484                            !strcmp(argv[0],"del_un")) ?
485                           "Do not use `!' as the first character of a class.\n\tIt is automatically added before modifying the subscription file." :
486                           "Do not use `!' as the first character of a class.\n\tIt is reserved for internal use with un-subscriptions.");
487                 return;
488         }
489         sub.zsub_class = argv[1];
490         sub.zsub_classinst = argv[2];
491         sub.zsub_recipient = (argc == 3)?TOKEN_ME:argv[3];
492
493         if (make_exist(subsname))
494                 return;
495         if ((wgport = ZGetWGPort()) == -1) {
496                 ss_perror(sci_idx,errno,"while finding WindowGram port");
497                 return;
498         } 
499
500         if (!strcmp(argv[0],"add"))
501                 add_file(wgport,&sub,0);
502         else if (!strcmp(argv[0],"add_unsubscription") ||
503                  !strcmp(argv[0],"add_un"))
504                 add_file(wgport,&sub,1);
505         else if (!strcmp(argv[0],"delete") ||
506                  !strcmp(argv[0],"del") ||
507                  !strcmp(argv[0],"dl"))
508                 del_file(wgport,&sub,0);
509         else if (!strcmp(argv[0],"delete_unsubscription") ||
510                  !strcmp(argv[0],"del_un")) {
511                 del_file(wgport,&sub,1);
512         } else
513                 ss_perror(sci_idx,0,"unknown command name");
514         return;
515 }
516
517 void
518 add_file(short wgport,
519          ZSubscription_t *subs,
520          int unsub)
521 {
522         FILE *fp;
523         char errbuf[BUFSIZ];
524         ZSubscription_t sub2;
525         Code_t retval;
526
527         (void) purge_subs(subs,ALL);    /* remove copies in the subs file */
528         if (!(fp = fopen(subsname,"a"))) {
529                 (void) sprintf(errbuf,"while opening %s for append",subsname);
530                 ss_perror(sci_idx,errno,errbuf);
531                 return;
532         } 
533         fprintf(fp,"%s%s,%s,%s\n",
534                 unsub ? "!" : "",
535                 subs->zsub_class, subs->zsub_classinst, subs->zsub_recipient);
536         if (fclose(fp) == EOF) {
537                 (void) sprintf(errbuf, "while closing %s", subsname);
538                 ss_perror(sci_idx, errno, errbuf);
539                 return;
540         }
541         fix_macros(subs,&sub2,1);
542         retval = (unsub
543                   ? ZUnsubscribeTo(&sub2,1,(u_short)wgport)
544                   : ZSubscribeToSansDefaults(&sub2,1,(u_short)wgport));
545         if (retval)
546                 ss_perror(sci_idx,retval,
547                           unsub ? "while unsubscribing" :
548                           "while subscribing");
549         return;
550 }
551
552 void
553 del_file(short wgport,
554          register ZSubscription_t *subs,
555          int unsub)
556 {
557         ZSubscription_t sub2;
558         int retval;
559         
560         retval = purge_subs(subs, unsub ? UNSUBONLY : SUBONLY);
561         if (retval == ERR)
562                 return;
563         if (retval == NOT_REMOVED)
564                 fprintf(stderr,
565                         "Couldn't find %sclass %s instance %s recipient %s in\n\tfile %s\n",
566                         unsub ? "un-subscription " : "",
567                         subs->zsub_class, subs->zsub_classinst,
568                         subs->zsub_recipient, subsname);
569         fix_macros(subs,&sub2,1);
570         if ((retval = ZUnsubscribeTo(&sub2,1,(u_short)wgport)) !=
571             ZERR_NONE)
572                 ss_perror(sci_idx,retval,"while unsubscribing");
573         return;
574 }
575
576 int
577 purge_subs(register ZSubscription_t *subs,
578            int which)
579 {
580         FILE *fp,*fpout;
581         char errbuf[BUFSIZ],subline[BUFSIZ];
582         char backup[BUFSIZ],ourline[BUFSIZ];
583         int delflag = NOT_REMOVED;
584         int keep;
585
586         switch (which) {
587         case SUBONLY:
588         case UNSUBONLY:
589         case ALL:
590                 break;
591         default:
592                 ss_perror(sci_idx,0,"internal error in purge_subs");
593                 return(ERR);
594         }
595
596         (void) sprintf(ourline,"%s,%s,%s",
597                        subs->zsub_class,
598                        subs->zsub_classinst,
599                        subs->zsub_recipient);
600
601         if (!(fp = fopen(subsname,"r"))) {
602                 (void) sprintf(errbuf,"while opening %s for read",subsname);
603                 ss_perror(sci_idx,errno,errbuf);
604                 return(ERR);
605         } 
606         (void) strcpy(backup, subsname);
607         (void) strcat(backup, ".temp");
608         (void) unlink(backup);
609         if (!(fpout = fopen(backup,"w"))) {
610                 (void) sprintf(errbuf,"while opening %s for writing",backup);
611                 ss_perror(sci_idx,errno,errbuf);
612                 (void) fclose(fp);
613                 return(ERR);
614         } 
615         for (;;) {
616                 if (!fgets(subline,sizeof subline,fp))
617                         break;
618                 if (*subline)
619                         subline[strlen(subline)-1] = '\0'; /* nuke newline */
620                 switch (which) {
621                 case SUBONLY:
622                         keep = strcmp(subline,ourline);
623                         break;
624                 case UNSUBONLY:
625                         keep = (*subline != '!' || strcmp(subline+1,ourline));
626                         break;
627                 case ALL:
628                         keep = (strcmp(subline,ourline) &&
629                                 (*subline != '!' || strcmp(subline+1,
630                                                            ourline)));
631                         break;
632                 }
633                 if (keep) {
634                         fputs(subline, fpout);
635                         if (ferror(fpout) || (fputc('\n', fpout) == EOF)) {
636                                 (void) sprintf(errbuf, "while writing to %s",
637                                                backup);
638                                 ss_perror(sci_idx, errno, errbuf);
639                         }
640                 } else
641                         delflag = REMOVED;
642         }
643         (void) fclose(fp);              /* open read-only, ignore errs */
644         if (fclose(fpout) == EOF) {
645                 (void) sprintf(errbuf, "while closing %s",backup);
646                 ss_perror(sci_idx, errno, errbuf);
647                 return(ERR);
648         }
649         if (rename(backup,subsname) == -1) {
650                 (void) sprintf(errbuf,"while renaming %s to %s\n",
651                                backup,subsname);
652                 ss_perror(sci_idx,errno,errbuf);
653                 return(ERR);
654         }
655         return(delflag);
656 }
657
658 void
659 load_subs(int argc,
660           char *argv[])
661 {
662         ZSubscription_t subs[SUBSATONCE],subs2[SUBSATONCE],unsubs[SUBSATONCE];
663         FILE *fp;
664         int ind,unind,lineno,i,retval,type;
665         short wgport;
666         char *comma,*comma2,*file,subline[BUFSIZ];
667
668         if (argc > 2) {
669                 fprintf(stderr,"Usage: %s [file]\n",argv[0]);
670                 return;
671         }
672
673         if (*argv[0] == 'u')
674                 type = UNSUB;
675         else
676                 if (!strcmp(argv[0],"list") || !strcmp(argv[0],"ls"))
677                         type = LIST;
678                 else
679                         type = SUB;
680
681         if (type != LIST) 
682                 if ((wgport = ZGetWGPort()) == -1) {
683                         ss_perror(sci_idx,errno,
684                                   "while finding WindowGram port");
685                         return;
686                 } 
687
688         file = (argc == 1) ? subsname : argv[1];
689         
690         fp = fopen(file,"r");
691
692         if (fp == NULL) {
693                 ss_perror(sci_idx,errno,
694                           "while loading subscription file");
695                 return;
696         }
697         
698         ind = unind = 0;
699         lineno = 1;
700         
701         for (;;lineno++) {
702                 if (!fgets(subline,sizeof subline,fp))
703                         break;
704                 if (*subline == '#' || !*subline)
705                         continue;
706                 subline[strlen(subline)-1] = '\0'; /* nuke newline */
707                 comma = strchr(subline,',');
708                 if (comma)
709                         comma2 = strchr(comma+1,',');
710                 else
711                         comma2 = 0;
712                 if (!comma || !comma2) {
713                         fprintf(stderr,
714                                 "Malformed subscription at line %d of %s:\n%s\n",
715                                 lineno,file,subline);
716                         continue;
717                 }
718                 *comma = '\0';
719                 *comma2 = '\0';
720                 if (type == LIST) {
721                         if (*subline == '!') 
722                                 printf("(Un-subscription) Class %s instance %s recipient %s\n",
723                                        subline+1, comma+1, comma2+1);
724                         else
725                                 printf("Class %s instance %s recipient %s\n",
726                                        subline, comma+1, comma2+1);
727                         continue;
728                 }
729                 if (*subline == '!') {  /* an un-subscription */
730                         /* if we are explicitly un-subscribing to
731                            the contents of a subscription file, ignore
732                            any un-subscriptions in that file */
733                         if (type == UNSUB)
734                                 continue;
735                         unsubs[unind].zsub_class =
736                             (char *)malloc((unsigned)(strlen(subline)));
737                         /* XXX check malloc return */
738                         /* skip the leading '!' */
739                         (void) strcpy(unsubs[unind].zsub_class,subline+1);
740                         unsubs[unind].zsub_classinst =
741                             (char *)malloc((unsigned)(strlen(comma+1)+1));
742                         /* XXX check malloc return */
743                         (void) strcpy(unsubs[unind].zsub_classinst,comma+1);
744                         unsubs[unind].zsub_recipient =
745                             (char *)malloc((unsigned)(strlen(comma2+1)+1));
746                         /* XXX check malloc return */
747                         (void) strcpy(unsubs[unind].zsub_recipient,comma2+1);
748                         unind++;
749                 } else {
750                         subs[ind].zsub_class =
751                             (char *)malloc((unsigned)(strlen(subline)+1));
752                         /* XXX check malloc return */
753                         (void) strcpy(subs[ind].zsub_class,subline);
754                         subs[ind].zsub_classinst =
755                             (char *)malloc((unsigned)(strlen(comma+1)+1));
756                         /* XXX check malloc return */
757                         (void) strcpy(subs[ind].zsub_classinst,comma+1);
758                         subs[ind].zsub_recipient =
759                             (char *)malloc((unsigned)(strlen(comma2+1)+1));
760                         /* XXX check malloc return */
761                         (void) strcpy(subs[ind].zsub_recipient,comma2+1);
762                         ind++;
763                 }
764                 if (ind == SUBSATONCE) {
765                         fix_macros(subs,subs2,ind);
766                         if ((retval = (type == SUB)?
767                              ZSubscribeTo(subs2,ind,(u_short)wgport):
768                              ZUnsubscribeTo(subs2,ind,(u_short)wgport)) !=
769                             ZERR_NONE) {
770                                 ss_perror(sci_idx,retval,(type == SUB)?
771                                           "while subscribing":
772                                           "while unsubscribing");
773                                 goto cleanup;
774                         }
775                         for (i=0;i<ind;i++) {
776                                 free(subs[i].zsub_class);
777                                 free(subs[i].zsub_classinst);
778                                 free(subs[i].zsub_recipient);
779                         } 
780                         ind = 0;
781                 }
782                 if (unind == SUBSATONCE) {
783                         fix_macros(unsubs,subs2,unind);
784                         if ((retval = ZUnsubscribeTo(subs2,unind,(u_short)wgport)) != ZERR_NONE) {
785                                 ss_perror(sci_idx,retval,
786                                           "while unsubscribing to un-subscriptions");
787                                 goto cleanup;
788                         }
789                         for (i=0;i<unind;i++) {
790                                 free(unsubs[i].zsub_class);
791                                 free(unsubs[i].zsub_classinst);
792                                 free(unsubs[i].zsub_recipient);
793                         } 
794                         unind = 0;
795                 }
796         }
797         
798         if (type != LIST) {
799                 /* even if we have no subscriptions, be sure to send
800                    an empty packet to trigger the default subscriptions */
801                 fix_macros(subs,subs2,ind);
802                 if ((retval = (type == SUB)?ZSubscribeTo(subs2,ind,(u_short)wgport):
803                      ZUnsubscribeTo(subs2,ind,(u_short)wgport)) != ZERR_NONE) {
804                         ss_perror(sci_idx,retval,(type == SUB)?
805                                   "while subscribing":
806                                   "while unsubscribing");
807                         goto cleanup;
808                 }
809                 if (unind) {
810                         fix_macros(unsubs,subs2,unind);
811                         if ((retval =
812                              ZUnsubscribeTo(subs2,unind,(u_short)wgport)) != ZERR_NONE) {
813                                 ss_perror(sci_idx,retval,
814                                           "while unsubscribing to un-subscriptions");
815                                 goto cleanup;
816                         }
817                 }
818         }
819 cleanup:
820         for (i=0;i<ind;i++) {
821           free(subs[i].zsub_class);
822           free(subs[i].zsub_classinst);
823           free(subs[i].zsub_recipient);
824         } 
825         for (i=0;i<unind;i++) {
826           free(unsubs[i].zsub_class);
827           free(unsubs[i].zsub_classinst);
828           free(unsubs[i].zsub_recipient);
829         } 
830
831         (void) fclose(fp);      /* ignore errs--file is read-only */
832         return;
833 }
834
835 void
836 current(int argc,
837         char *argv[])
838 {
839         FILE *fp;
840         char errbuf[BUFSIZ];
841         ZSubscription_t subs;
842         int i,nsubs,retval,save,one,defs;
843         short wgport;
844         char *file,backup[BUFSIZ];
845         
846         save = 0;
847         defs = 0;
848
849         if (!strcmp(argv[0],"save"))
850                 save = 1;
851         else if (!strcmp(argv[0], "defaults") || !strcmp(argv[0], "defs"))
852                 defs = 1;
853
854         if (argc != 1 && !(save && argc == 2)) {
855                 fprintf(stderr,"Usage: %s%s\n",argv[0],save?" [filename]":"");
856                 return;
857         }
858
859         if (!defs)
860                 if ((wgport = ZGetWGPort()) == -1) {
861                         ss_perror(sci_idx,errno,
862                                   "while finding WindowGram port");
863                         return;
864                 } 
865
866         if (defs)
867                 retval = ZRetrieveDefaultSubscriptions(&nsubs);
868         else
869                 retval = ZRetrieveSubscriptions((u_short)wgport,&nsubs);
870
871         if (retval == ZERR_TOOMANYSUBS) {
872                 fprintf(stderr,"Too many subscriptions -- some have not been returned.\n");
873                 if (save) {
874                         fprintf(stderr,"Save aborted.\n");
875                         return;
876                 }
877         }
878         else
879                 if (retval != ZERR_NONE) {
880                         ss_perror(sci_idx,retval,"retrieving subscriptions");
881                         return;
882                 }
883
884         if (save) {
885                 file = (argc == 1)?subsname:argv[1];
886                 (void) strcpy(backup,file);
887                 (void) strcat(backup,".temp");
888                 if (!(fp = fopen(backup,"w"))) {
889                         (void) sprintf(errbuf,"while opening %s for write",
890                                        backup);
891                         ss_perror(sci_idx,errno,errbuf);
892                         return;
893                 }
894         }
895         
896         for (i=0;i<nsubs;i++) {
897                 one = 1;
898                 if ((retval = ZGetSubscriptions(&subs,&one)) != ZERR_NONE) {
899                         ss_perror(sci_idx,retval,"while getting subscription");
900                         if (save) {
901                                 fprintf(stderr,"Subscriptions file not modified\n");
902                                 (void) fclose(fp);
903                                 (void) unlink(backup);
904                         }
905                         return;
906                 } 
907                 if (save)
908                         fprintf(fp,"%s,%s,%s\n",subs.zsub_class,
909                                 subs.zsub_classinst, subs.zsub_recipient);
910                 else
911                         printf("Class %s Instance %s Recipient %s\n",
912                                subs.zsub_class, subs.zsub_classinst,
913                                subs.zsub_recipient);
914         }
915
916         if (save) {
917                 if (fclose(fp) == EOF) {
918                         (void) sprintf(errbuf, "while closing %s", backup);
919                         ss_perror(sci_idx, errno, errbuf);
920                         return;
921                 }
922                 if (rename(backup,file) == -1) {
923                         (void) sprintf(errbuf,"while renaming %s to %s",
924                                        backup,file);
925                         ss_perror(sci_idx,retval,errbuf);
926                         (void) unlink(backup);
927                 }
928         }
929 }
930
931 int
932 make_exist(char *filename)
933 {
934         char errbuf[BUFSIZ];
935         FILE *fpout;
936         
937         if (!access(filename,F_OK))
938                 return (0);
939
940         if (!(fpout = fopen(filename,"w"))) {
941                 (void) sprintf(errbuf,"while opening %s for write",filename);
942                 ss_perror(sci_idx,errno,errbuf);
943                 return (1);
944         }
945
946         if (fclose(fpout) == EOF) {
947                 (void) sprintf(errbuf, "while closing %s", filename);
948                 ss_perror(sci_idx, errno, errbuf);
949                 return(1);
950         }
951         return (0);
952 }
953
954 void
955 fix_macros(ZSubscription_t *subs,
956            ZSubscription_t *subs2,
957            int num)
958 {
959         int i;
960
961         for (i=0;i<num;i++) {
962                 subs2[i] = subs[i];
963                 fix_macros2(subs[i].zsub_class,&subs2[i].zsub_class);
964                 fix_macros2(subs[i].zsub_classinst,&subs2[i].zsub_classinst);
965                 fix_macros2(subs[i].zsub_recipient,&subs2[i].zsub_recipient);
966         }
967 }
968
969 void
970 fix_macros2(char *src, char **dest)
971 {
972         if (!strcmp(src,TOKEN_HOSTNAME)) {
973                 *dest = ourhost;
974                 return;
975         }
976         if (!strcmp(src,TOKEN_CANONNAME)) {
977                 *dest = ourhostcanon;
978                 return;
979         }
980         if (!strcmp(src,TOKEN_ME))
981                 *dest = ZGetSender();
982 }