]> asedeno.scripts.mit.edu Git - 1ts-debian.git/blob - zephyr/clients/zctl/zctl.c
unpack of new upstream
[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,v 1.32 2003/11/04 19:21:49 ghudson 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/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,v 1.32 2003/11/04 19:21:49 ghudson Exp $";
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 int purge_subs();
44
45 int sci_idx;
46 char subsname[BUFSIZ];
47 char ourhost[MAXHOSTNAMELEN],ourhostcanon[MAXHOSTNAMELEN];
48
49 extern ss_request_table zctl_cmds;
50
51 void add_file(), del_file(), fix_macros(), fix_macros2();
52
53 main(argc,argv)
54         int argc;
55         char *argv[];
56 {
57         struct passwd *pwd;
58         struct hostent *hent;
59         char ssline[BUFSIZ],oldsubsname[BUFSIZ],*envptr,*tty = NULL;
60         int retval,code,i;
61 #ifdef HAVE_SYS_UTSNAME
62         struct utsname name;
63 #endif
64
65         if ((retval = ZInitialize()) != ZERR_NONE) {
66                 com_err(argv[0],retval,"while initializing");
67                 exit (1);
68         }
69
70         /* Set hostname and tty for locations.  If we support X, use the
71          * DISPLAY environment variable for the tty name. */
72 #ifndef X_DISPLAY_MISSING
73         tty = getenv("DISPLAY");
74 #endif  
75         if ((retval = ZInitLocationInfo(NULL, tty)) != ZERR_NONE)
76             com_err(argv[0], retval, "initializing location information");
77
78         envptr = getenv("ZEPHYR_SUBS");
79         if (envptr)
80                 strcpy(subsname,envptr);
81         else {
82                 envptr = getenv("HOME");
83                 if (envptr)
84                         strcpy(subsname,envptr);
85                 else {
86                         if (!(pwd = getpwuid((int) getuid()))) {
87                                 fprintf(stderr,"Who are you?\n");
88                                 exit (1);
89                         }
90
91                         strcpy(subsname,pwd->pw_dir);
92                 }
93                 strcpy(oldsubsname,subsname);
94                 strcat(oldsubsname,OLD_SUBS);
95                 strcat(subsname,USERS_SUBS);
96                 if (!access(oldsubsname,F_OK) && access(subsname, F_OK)) {
97                         /* only if old one exists and new one does not exist */
98                         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");
99                         if (rename(oldsubsname,subsname))
100                                 com_err(argv[0], errno, "renaming .subscriptions");
101                 }
102         }
103
104 #ifdef HAVE_SYS_UTSNAME
105         uname(&name);
106         strcpy(ourhost, name.nodename);
107 #else
108         if (gethostname(ourhost,MAXHOSTNAMELEN) == -1) {
109                 com_err(argv[0],errno,"while getting host name");
110                 exit (1);
111         }
112 #endif
113
114         if (!(hent = gethostbyname(ourhost))) {
115                 fprintf(stderr,"%s: Can't resolve hostname %s; %s may be "
116                         "wrong in subscriptions",argv[0],ourhost,
117                         TOKEN_CANONNAME);
118                 strncpy(ourhostcanon,ourhost,sizeof(ourhostcanon)-1);
119         } else
120                 strncpy(ourhostcanon,hent->h_name,sizeof(ourhostcanon)-1);
121
122         sci_idx = ss_create_invocation("zctl","",0,&zctl_cmds,&code);
123         if (code) {
124                 ss_perror(sci_idx,code,"while creating invocation");
125                 exit(1);
126         }
127
128         if (argc > 1) {
129                 *ssline = '\0';
130                 for (i=1;i<argc;i++)
131                         (void) sprintf(ssline+strlen(ssline),"%s ",argv[i]);
132                 ssline[strlen(ssline)-1] = '\0';
133                 code = ss_execute_line(sci_idx,ssline);
134                 if (code)
135                     fprintf (stderr, "%s: %s: %s\n",
136                              argv[0], error_message (code), ssline);
137                 exit((code != 0));
138         } 
139
140         printf("ZCTL $Revision: 1.32 $ (Protocol %s%d.%d) - Type '?' for a list of commands.\n\n",
141                ZVERSIONHDR,
142                ZVERSIONMAJOR,ZVERSIONMINOR);
143         
144         ss_listen(sci_idx);
145         exit(0);
146 }
147
148 void
149 set_file(argc,argv)
150         int argc;
151         char *argv[];
152 {
153         if (argc > 2) {
154                 fprintf(stderr,"Usage: %s filename\n",argv[0]);
155                 return;
156         }
157
158         if (argc == 1)
159                 printf("Current file: %s\n",subsname);
160         else
161                 (void) strcpy(subsname,argv[1]);
162 }
163
164 void
165 flush_locations(argc,argv)
166         int argc;
167         char *argv[];
168 {
169         int retval;
170         
171         if (argc > 1) {
172                 fprintf(stderr,"Usage: %s\n",argv[0]);
173                 return;
174         }
175
176         if ((retval = ZFlushMyLocations()) != ZERR_NONE)
177                 ss_perror(sci_idx,retval,"while flushing locations");
178 }
179
180 void
181 wgc_control(argc,argv)
182         int argc;
183         register char **argv;
184 {
185         int retval;
186         short newport;
187         struct sockaddr_in newsin;
188         ZNotice_t notice;
189
190         newsin = ZGetDestAddr();
191
192         if (argc > 1) {
193                 fprintf(stderr,"Usage: %s\n",argv[0]);
194                 return;
195         }
196         
197         if ((newport = ZGetWGPort()) == -1) {
198                 ss_perror(sci_idx,errno,"while getting WindowGram port");
199                 return;
200         }
201
202         newsin.sin_port = (u_short) newport;
203         if ((retval = ZSetDestAddr(&newsin)) != ZERR_NONE) {
204                 ss_perror(sci_idx,retval,"while setting destination address");
205                 return;
206         }
207
208         (void) memset((char *)&notice, 0, sizeof(notice));
209         notice.z_kind = UNSAFE;
210         notice.z_port = 0;
211         notice.z_class = WG_CTL_CLASS;
212         notice.z_class_inst = WG_CTL_USER;
213
214         if (!strcmp(argv[0],"wg_read"))
215                 notice.z_opcode = USER_REREAD;
216         if (!strcmp(argv[0],"wg_shutdown"))
217                 notice.z_opcode = USER_SHUTDOWN;
218         if (!strcmp(argv[0],"wg_startup"))
219                 notice.z_opcode = USER_STARTUP;
220         if (!strcmp(argv[0],"wg_exit"))
221                 notice.z_opcode = USER_EXIT;
222         if (!notice.z_opcode) {
223                 fprintf(stderr,
224                         "unknown WindowGram client control command %s\n",
225                         argv[0]);
226                 return;
227         }
228         notice.z_sender = 0;
229         notice.z_recipient = "";
230         notice.z_default_format = "";
231         notice.z_message_len = 0;
232
233         if ((retval = ZSendNotice(&notice,ZNOAUTH)) != ZERR_NONE)
234                 ss_perror(sci_idx,retval,"while sending notice");
235
236         if ((retval = ZInitialize()) != ZERR_NONE)
237                 ss_perror(sci_idx,retval,
238                           "while reinitializing");
239
240
241 void
242 hm_control(argc,argv)
243         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(argc,argv)
280         int argc;
281         char *argv[];
282 {
283         int i;
284         char *value;
285         
286         if (argc < 2) {
287                 fprintf(stderr,"Usage: %s <varname> <varname> ...\n",argv[0]);
288                 return;
289         }
290
291         for (i=1;i<argc;i++) {
292                 value = ZGetVariable(argv[i]);
293                 if (value)
294                         printf("%s: %s\n",argv[i],value);
295                 else
296                         printf("%s: not defined\n",argv[i]);
297         }
298 }
299
300 void
301 set_var(argc,argv)
302         int argc;
303         register char **argv;
304 {
305         int retval,setting_exp,i;
306         char *exp_level,*newargv[1];
307         char varcat[BUFSIZ];
308         
309         if (argc < 2) {
310                 fprintf(stderr,"Usage: %s <varname> [value]\n",
311                         argv[0]);
312                 return;
313         }
314
315         setting_exp = 0;
316
317         if (!strcasecmp(argv[1],"exposure")) {
318                 setting_exp = 1;
319                 if (argc != 3) {
320                         fprintf(stderr,"An exposure setting must be specified.\n");
321                         return;
322                 }
323                 exp_level = (char *)0;
324                 if (!strcasecmp(argv[2],EXPOSE_NONE))
325                         exp_level = EXPOSE_NONE;
326                 if (!strcasecmp(argv[2],EXPOSE_OPSTAFF))
327                         exp_level = EXPOSE_OPSTAFF;
328                 if (!strcasecmp(argv[2],EXPOSE_REALMVIS))
329                         exp_level = EXPOSE_REALMVIS;
330                 if (!strcasecmp(argv[2],EXPOSE_REALMANN))
331                         exp_level = EXPOSE_REALMANN;
332                 if (!strcasecmp(argv[2],EXPOSE_NETVIS))
333                         exp_level = EXPOSE_NETVIS;
334                 if (!strcasecmp(argv[2],EXPOSE_NETANN))
335                         exp_level = EXPOSE_NETANN;
336                 if (!exp_level) {
337                         fprintf(stderr,"The exposure setting must be one of:\n");
338                         fprintf(stderr,"%s, %s, %s, %s, %s, %s.\n",
339                                 EXPOSE_NONE,
340                                 EXPOSE_OPSTAFF,
341                                 EXPOSE_REALMVIS,
342                                 EXPOSE_REALMANN,
343                                 EXPOSE_NETVIS,
344                                 EXPOSE_NETANN);
345                         return;
346                 }
347         } 
348         if (argc == 2)
349                 retval = ZSetVariable(argv[1],"");
350         else {
351                 (void) strcpy(varcat,argv[2]);
352                 for (i=3;i<argc;i++) {
353                         (void) strcat(varcat," ");
354                         (void) strcat(varcat,argv[i]);
355                 } 
356                 retval = ZSetVariable(argv[1],varcat);
357         } 
358
359         if (retval != ZERR_NONE) {
360                 ss_perror(sci_idx,retval,"while setting variable value");
361                 return;
362         }
363
364         /* Side-effects?  Naw, us? */
365         
366         if (setting_exp) {
367                 if ((retval = ZSetLocation(exp_level)) != ZERR_NONE)
368                         ss_perror(sci_idx,retval,"while changing exposure status");
369                 if (!strcmp(exp_level,EXPOSE_NONE)) {
370                         newargv[0] = "wg_shutdown";
371                         wgc_control(1,newargv);
372                 } else {
373                         newargv[0] = "wg_startup";
374                         wgc_control(1,newargv);
375                 }
376                 return;
377         } 
378 }
379
380 void
381 do_hide(argc,argv)
382         int argc;
383         char *argv[];
384 {
385         char *exp_level = NULL;
386         Code_t retval;
387
388         if (argc != 1) {
389                 fprintf(stderr, "Usage: %s\n",argv[0]);
390                 return;
391         }
392         if (!strcmp(argv[0],"unhide"))
393                 exp_level = EXPOSE_REALMVIS;
394         else
395                 exp_level = EXPOSE_OPSTAFF;
396         if ((retval = ZSetLocation(exp_level)) != ZERR_NONE)
397                 ss_perror(sci_idx,retval,"while changing exposure status");
398         return;
399 }
400
401 void
402 unset_var(argc,argv)
403         int argc;
404         char *argv[];
405 {
406         int retval,i;
407         
408         if (argc < 2) {
409                 fprintf(stderr,"Usage: %s <varname> [<varname> ... ]\n",
410                         argv[0]);
411                 return;
412         }
413
414         for (i=1;i<argc;i++)
415                 if ((retval = ZUnsetVariable(argv[i])) != ZERR_NONE)
416                         ss_perror(sci_idx,retval,
417                                   "while unsetting variable value");
418 }
419
420 void
421 cancel_subs(argc,argv)
422         int argc;
423         char *argv[];
424 {
425         int retval;
426         short wgport;
427
428         if (argc != 1) {
429                 fprintf(stderr,"Usage: %s\n",argv[0]);
430                 return;
431         } 
432
433         if ((wgport = ZGetWGPort()) == -1) {
434                 ss_perror(sci_idx,errno,"while finding WindowGram port");
435                 return;
436         } 
437         if ((retval = ZCancelSubscriptions((u_short)wgport)) != ZERR_NONE)
438                 ss_perror(sci_idx,retval,"while cancelling subscriptions");
439 }
440
441 void
442 subscribe(argc,argv)
443         int argc;
444         char *argv[];
445 {
446         int retval;
447         short wgport;
448         ZSubscription_t sub,sub2;
449         
450         if (argc > 4 || argc < 3) {
451                 fprintf(stderr,"Usage: %s class instance [*]\n",argv[0]);
452                 return;
453         }
454         
455         sub.zsub_class = argv[1];
456         sub.zsub_classinst = argv[2];
457         sub.zsub_recipient = (argc == 3)?ZGetSender():argv[3];
458
459         fix_macros(&sub,&sub2,1);
460         
461         if ((wgport = ZGetWGPort()) == -1) {
462                 ss_perror(sci_idx,errno,"while finding WindowGram port");
463                 return;
464         } 
465
466         retval = (*argv[0] == 's') ?
467                 ZSubscribeToSansDefaults(&sub2,1,(u_short)wgport) :
468                 ZUnsubscribeTo(&sub2,1,(u_short)wgport);
469         
470         if (retval != ZERR_NONE)
471                 ss_perror(sci_idx,retval,"while subscribing");
472
473
474 void
475 sub_file(argc,argv)
476         int argc;
477         char *argv[];
478 {
479         ZSubscription_t sub;
480         short wgport;
481
482         if (argc > 4 || argc < 3) {
483                 fprintf(stderr,"Usage: %s class instance [*]\n",argv[0]);
484                 return;
485         }
486
487         if (argv[1][0] == '!') {
488                 ss_perror(sci_idx,0,
489                           (!strcmp(argv[0],"add_unsubscription") ||
490                            !strcmp(argv[0],"add_un") ||
491                            !strcmp(argv[0],"delete_unsubscription") ||
492                            !strcmp(argv[0],"del_un")) ?
493                           "Do not use `!' as the first character of a class.\n\tIt is automatically added before modifying the subscription file." :
494                           "Do not use `!' as the first character of a class.\n\tIt is reserved for internal use with un-subscriptions.");
495                 return;
496         }
497         sub.zsub_class = argv[1];
498         sub.zsub_classinst = argv[2];
499         sub.zsub_recipient = (argc == 3)?TOKEN_ME:argv[3];
500
501         if (make_exist(subsname))
502                 return;
503         if ((wgport = ZGetWGPort()) == -1) {
504                 ss_perror(sci_idx,errno,"while finding WindowGram port");
505                 return;
506         } 
507
508         if (!strcmp(argv[0],"add"))
509                 add_file(wgport,&sub,0);
510         else if (!strcmp(argv[0],"add_unsubscription") ||
511                  !strcmp(argv[0],"add_un"))
512                 add_file(wgport,&sub,1);
513         else if (!strcmp(argv[0],"delete") ||
514                  !strcmp(argv[0],"del") ||
515                  !strcmp(argv[0],"dl"))
516                 del_file(wgport,&sub,0);
517         else if (!strcmp(argv[0],"delete_unsubscription") ||
518                  !strcmp(argv[0],"del_un")) {
519                 del_file(wgport,&sub,1);
520         } else
521                 ss_perror(sci_idx,0,"unknown command name");
522         return;
523 }
524
525 void
526 add_file(wgport,subs,unsub)
527 short wgport;
528 ZSubscription_t *subs;
529 int unsub;
530 {
531         FILE *fp;
532         char errbuf[BUFSIZ];
533         ZSubscription_t sub2;
534         Code_t retval;
535
536         (void) purge_subs(subs,ALL);    /* remove copies in the subs file */
537         if (!(fp = fopen(subsname,"a"))) {
538                 (void) sprintf(errbuf,"while opening %s for append",subsname);
539                 ss_perror(sci_idx,errno,errbuf);
540                 return;
541         } 
542         fprintf(fp,"%s%s,%s,%s\n",
543                 unsub ? "!" : "",
544                 subs->zsub_class, subs->zsub_classinst, subs->zsub_recipient);
545         if (fclose(fp) == EOF) {
546                 (void) sprintf(errbuf, "while closing %s", subsname);
547                 ss_perror(sci_idx, errno, errbuf);
548                 return;
549         }
550         fix_macros(subs,&sub2,1);
551         if (retval = (unsub ? ZUnsubscribeTo(&sub2,1,(u_short)wgport) :
552                        ZSubscribeToSansDefaults(&sub2,1,(u_short)wgport)))
553                 ss_perror(sci_idx,retval,
554                           unsub ? "while unsubscribing" :
555                           "while subscribing");
556         return;
557 }
558
559 void
560 del_file(wgport,subs,unsub)
561 short wgport;
562 register ZSubscription_t *subs;
563 int unsub;
564 {
565         ZSubscription_t sub2;
566         int retval;
567         
568         retval = purge_subs(subs, unsub ? UNSUBONLY : SUBONLY);
569         if (retval == ERR)
570                 return;
571         if (retval == NOT_REMOVED)
572                 fprintf(stderr,
573                         "Couldn't find %sclass %s instance %s recipient %s in\n\tfile %s\n",
574                         unsub ? "un-subscription " : "",
575                         subs->zsub_class, subs->zsub_classinst,
576                         subs->zsub_recipient, subsname);
577         fix_macros(subs,&sub2,1);
578         if ((retval = ZUnsubscribeTo(&sub2,1,(u_short)wgport)) !=
579             ZERR_NONE)
580                 ss_perror(sci_idx,retval,"while unsubscribing");
581         return;
582 }
583
584 int
585 purge_subs(subs,which)
586 register ZSubscription_t *subs;
587 int which;
588 {
589         FILE *fp,*fpout;
590         char errbuf[BUFSIZ],subline[BUFSIZ];
591         char backup[BUFSIZ],ourline[BUFSIZ];
592         int delflag = NOT_REMOVED;
593         int keep;
594
595         switch (which) {
596         case SUBONLY:
597         case UNSUBONLY:
598         case ALL:
599                 break;
600         default:
601                 ss_perror(sci_idx,0,"internal error in purge_subs");
602                 return(ERR);
603         }
604
605         (void) sprintf(ourline,"%s,%s,%s",
606                        subs->zsub_class,
607                        subs->zsub_classinst,
608                        subs->zsub_recipient);
609
610         if (!(fp = fopen(subsname,"r"))) {
611                 (void) sprintf(errbuf,"while opening %s for read",subsname);
612                 ss_perror(sci_idx,errno,errbuf);
613                 return(ERR);
614         } 
615         (void) strcpy(backup, subsname);
616         (void) strcat(backup, ".temp");
617         (void) unlink(backup);
618         if (!(fpout = fopen(backup,"w"))) {
619                 (void) sprintf(errbuf,"while opening %s for writing",backup);
620                 ss_perror(sci_idx,errno,errbuf);
621                 (void) fclose(fp);
622                 return(ERR);
623         } 
624         for (;;) {
625                 if (!fgets(subline,sizeof subline,fp))
626                         break;
627                 if (*subline)
628                         subline[strlen(subline)-1] = '\0'; /* nuke newline */
629                 switch (which) {
630                 case SUBONLY:
631                         keep = strcmp(subline,ourline);
632                         break;
633                 case UNSUBONLY:
634                         keep = (*subline != '!' || strcmp(subline+1,ourline));
635                         break;
636                 case ALL:
637                         keep = (strcmp(subline,ourline) &&
638                                 (*subline != '!' || strcmp(subline+1,
639                                                            ourline)));
640                         break;
641                 }
642                 if (keep) {
643                         fputs(subline, fpout);
644                         if (ferror(fpout) || (fputc('\n', fpout) == EOF)) {
645                                 (void) sprintf(errbuf, "while writing to %s",
646                                                backup);
647                                 ss_perror(sci_idx, errno, errbuf);
648                         }
649                 } else
650                         delflag = REMOVED;
651         }
652         (void) fclose(fp);              /* open read-only, ignore errs */
653         if (fclose(fpout) == EOF) {
654                 (void) sprintf(errbuf, "while closing %s",backup);
655                 ss_perror(sci_idx, errno, errbuf);
656                 return(ERR);
657         }
658         if (rename(backup,subsname) == -1) {
659                 (void) sprintf(errbuf,"while renaming %s to %s\n",
660                                backup,subsname);
661                 ss_perror(sci_idx,errno,errbuf);
662                 return(ERR);
663         }
664         return(delflag);
665 }
666
667 void
668 load_subs(argc,argv)
669         int argc;
670         char *argv[];
671 {
672         ZSubscription_t subs[SUBSATONCE],subs2[SUBSATONCE],unsubs[SUBSATONCE];
673         FILE *fp;
674         int ind,unind,lineno,i,retval,type;
675         short wgport;
676         char *comma,*comma2,*file,subline[BUFSIZ];
677
678         if (argc > 2) {
679                 fprintf(stderr,"Usage: %s [file]\n",argv[0]);
680                 return;
681         }
682
683         if (*argv[0] == 'u')
684                 type = UNSUB;
685         else
686                 if (!strcmp(argv[0],"list") || !strcmp(argv[0],"ls"))
687                         type = LIST;
688                 else
689                         type = SUB;
690
691         if (type != LIST) 
692                 if ((wgport = ZGetWGPort()) == -1) {
693                         ss_perror(sci_idx,errno,
694                                   "while finding WindowGram port");
695                         return;
696                 } 
697
698         file = (argc == 1) ? subsname : argv[1];
699         
700         fp = fopen(file,"r");
701
702         if (fp == NULL) {
703                 ss_perror(sci_idx,errno,
704                           "while loading subscription file");
705                 return;
706         }
707         
708         ind = unind = 0;
709         lineno = 1;
710         
711         for (;;lineno++) {
712                 if (!fgets(subline,sizeof subline,fp))
713                         break;
714                 if (*subline == '#' || !*subline)
715                         continue;
716                 subline[strlen(subline)-1] = '\0'; /* nuke newline */
717                 comma = strchr(subline,',');
718                 if (comma)
719                         comma2 = strchr(comma+1,',');
720                 else
721                         comma2 = 0;
722                 if (!comma || !comma2) {
723                         fprintf(stderr,
724                                 "Malformed subscription at line %d of %s:\n%s\n",
725                                 lineno,file,subline);
726                         continue;
727                 }
728                 *comma = '\0';
729                 *comma2 = '\0';
730                 if (type == LIST) {
731                         if (*subline == '!') 
732                                 printf("(Un-subscription) Class %s instance %s recipient %s\n",
733                                        subline+1, comma+1, comma2+1);
734                         else
735                                 printf("Class %s instance %s recipient %s\n",
736                                        subline, comma+1, comma2+1);
737                         continue;
738                 }
739                 if (*subline == '!') {  /* an un-subscription */
740                         /* if we are explicitly un-subscribing to
741                            the contents of a subscription file, ignore
742                            any un-subscriptions in that file */
743                         if (type == UNSUB)
744                                 continue;
745                         unsubs[unind].zsub_class =
746                             (char *)malloc((unsigned)(strlen(subline)));
747                         /* XXX check malloc return */
748                         /* skip the leading '!' */
749                         (void) strcpy(unsubs[unind].zsub_class,subline+1);
750                         unsubs[unind].zsub_classinst =
751                             (char *)malloc((unsigned)(strlen(comma+1)+1));
752                         /* XXX check malloc return */
753                         (void) strcpy(unsubs[unind].zsub_classinst,comma+1);
754                         unsubs[unind].zsub_recipient =
755                             (char *)malloc((unsigned)(strlen(comma2+1)+1));
756                         /* XXX check malloc return */
757                         (void) strcpy(unsubs[unind].zsub_recipient,comma2+1);
758                         unind++;
759                 } else {
760                         subs[ind].zsub_class =
761                             (char *)malloc((unsigned)(strlen(subline)+1));
762                         /* XXX check malloc return */
763                         (void) strcpy(subs[ind].zsub_class,subline);
764                         subs[ind].zsub_classinst =
765                             (char *)malloc((unsigned)(strlen(comma+1)+1));
766                         /* XXX check malloc return */
767                         (void) strcpy(subs[ind].zsub_classinst,comma+1);
768                         subs[ind].zsub_recipient =
769                             (char *)malloc((unsigned)(strlen(comma2+1)+1));
770                         /* XXX check malloc return */
771                         (void) strcpy(subs[ind].zsub_recipient,comma2+1);
772                         ind++;
773                 }
774                 if (ind == SUBSATONCE) {
775                         fix_macros(subs,subs2,ind);
776                         if ((retval = (type == SUB)?
777                              ZSubscribeTo(subs2,ind,(u_short)wgport):
778                              ZUnsubscribeTo(subs2,ind,(u_short)wgport)) !=
779                             ZERR_NONE) {
780                                 ss_perror(sci_idx,retval,(type == SUB)?
781                                           "while subscribing":
782                                           "while unsubscribing");
783                                 goto cleanup;
784                         }
785                         for (i=0;i<ind;i++) {
786                                 free(subs[i].zsub_class);
787                                 free(subs[i].zsub_classinst);
788                                 free(subs[i].zsub_recipient);
789                         } 
790                         ind = 0;
791                 }
792                 if (unind == SUBSATONCE) {
793                         fix_macros(unsubs,subs2,unind);
794                         if ((retval = ZUnsubscribeTo(subs2,unind,(u_short)wgport)) != ZERR_NONE) {
795                                 ss_perror(sci_idx,retval,
796                                           "while unsubscribing to un-subscriptions");
797                                 goto cleanup;
798                         }
799                         for (i=0;i<unind;i++) {
800                                 free(unsubs[i].zsub_class);
801                                 free(unsubs[i].zsub_classinst);
802                                 free(unsubs[i].zsub_recipient);
803                         } 
804                         unind = 0;
805                 }
806         }
807         
808         if (type != LIST) {
809                 /* even if we have no subscriptions, be sure to send
810                    an empty packet to trigger the default subscriptions */
811                 fix_macros(subs,subs2,ind);
812                 if ((retval = (type == SUB)?ZSubscribeTo(subs2,ind,(u_short)wgport):
813                      ZUnsubscribeTo(subs2,ind,(u_short)wgport)) != ZERR_NONE) {
814                         ss_perror(sci_idx,retval,(type == SUB)?
815                                   "while subscribing":
816                                   "while unsubscribing");
817                         goto cleanup;
818                 }
819                 if (unind) {
820                         fix_macros(unsubs,subs2,unind);
821                         if ((retval =
822                              ZUnsubscribeTo(subs2,unind,(u_short)wgport)) != ZERR_NONE) {
823                                 ss_perror(sci_idx,retval,
824                                           "while unsubscribing to un-subscriptions");
825                                 goto cleanup;
826                         }
827                 }
828         }
829 cleanup:
830         for (i=0;i<ind;i++) {
831           free(subs[i].zsub_class);
832           free(subs[i].zsub_classinst);
833           free(subs[i].zsub_recipient);
834         } 
835         for (i=0;i<unind;i++) {
836           free(unsubs[i].zsub_class);
837           free(unsubs[i].zsub_classinst);
838           free(unsubs[i].zsub_recipient);
839         } 
840
841         (void) fclose(fp);      /* ignore errs--file is read-only */
842         return;
843 }
844
845 void
846 current(argc,argv)
847         int argc;
848         char *argv[];
849 {
850         FILE *fp;
851         char errbuf[BUFSIZ];
852         ZSubscription_t subs;
853         int i,nsubs,retval,save,one,defs;
854         short wgport;
855         char *file,backup[BUFSIZ];
856         
857         save = 0;
858         defs = 0;
859
860         if (!strcmp(argv[0],"save"))
861                 save = 1;
862         else if (!strcmp(argv[0], "defaults") || !strcmp(argv[0], "defs"))
863                 defs = 1;
864
865         if (argc != 1 && !(save && argc == 2)) {
866                 fprintf(stderr,"Usage: %s%s\n",argv[0],save?" [filename]":"");
867                 return;
868         }
869
870         if (!defs)
871                 if ((wgport = ZGetWGPort()) == -1) {
872                         ss_perror(sci_idx,errno,
873                                   "while finding WindowGram port");
874                         return;
875                 } 
876
877         if (defs)
878                 retval = ZRetrieveDefaultSubscriptions(&nsubs);
879         else
880                 retval = ZRetrieveSubscriptions((u_short)wgport,&nsubs);
881
882         if (retval == ZERR_TOOMANYSUBS) {
883                 fprintf(stderr,"Too many subscriptions -- some have not been returned.\n");
884                 if (save) {
885                         fprintf(stderr,"Save aborted.\n");
886                         return;
887                 }
888         }
889         else
890                 if (retval != ZERR_NONE) {
891                         ss_perror(sci_idx,retval,"retrieving subscriptions");
892                         return;
893                 }
894
895         if (save) {
896                 file = (argc == 1)?subsname:argv[1];
897                 (void) strcpy(backup,file);
898                 (void) strcat(backup,".temp");
899                 if (!(fp = fopen(backup,"w"))) {
900                         (void) sprintf(errbuf,"while opening %s for write",
901                                        backup);
902                         ss_perror(sci_idx,errno,errbuf);
903                         return;
904                 }
905         }
906         
907         for (i=0;i<nsubs;i++) {
908                 one = 1;
909                 if ((retval = ZGetSubscriptions(&subs,&one)) != ZERR_NONE) {
910                         ss_perror(sci_idx,retval,"while getting subscription");
911                         if (save) {
912                                 fprintf(stderr,"Subscriptions file not modified\n");
913                                 (void) fclose(fp);
914                                 (void) unlink(backup);
915                         }
916                         return;
917                 } 
918                 if (save)
919                         fprintf(fp,"%s,%s,%s\n",subs.zsub_class,
920                                 subs.zsub_classinst, subs.zsub_recipient);
921                 else
922                         printf("Class %s Instance %s Recipient %s\n",
923                                subs.zsub_class, subs.zsub_classinst,
924                                subs.zsub_recipient);
925         }
926
927         if (save) {
928                 if (fclose(fp) == EOF) {
929                         (void) sprintf(errbuf, "while closing %s", backup);
930                         ss_perror(sci_idx, errno, errbuf);
931                         return;
932                 }
933                 if (rename(backup,file) == -1) {
934                         (void) sprintf(errbuf,"while renaming %s to %s",
935                                        backup,file);
936                         ss_perror(sci_idx,retval,errbuf);
937                         (void) unlink(backup);
938                 }
939         }
940 }
941
942 int
943 make_exist(filename)
944         char *filename;
945 {
946         char errbuf[BUFSIZ];
947         FILE *fpout;
948         
949         if (!access(filename,F_OK))
950                 return (0);
951
952         if (!(fpout = fopen(filename,"w"))) {
953                 (void) sprintf(errbuf,"while opening %s for write",filename);
954                 ss_perror(sci_idx,errno,errbuf);
955                 return (1);
956         }
957
958         if (fclose(fpout) == EOF) {
959                 (void) sprintf(errbuf, "while closing %s", filename);
960                 ss_perror(sci_idx, errno, errbuf);
961                 return(1);
962         }
963         return (0);
964 }
965
966 void
967 fix_macros(subs,subs2,num)
968         ZSubscription_t *subs,*subs2;
969         int num;
970 {
971         int i;
972
973         for (i=0;i<num;i++) {
974                 subs2[i] = subs[i];
975                 fix_macros2(subs[i].zsub_class,&subs2[i].zsub_class);
976                 fix_macros2(subs[i].zsub_classinst,&subs2[i].zsub_classinst);
977                 fix_macros2(subs[i].zsub_recipient,&subs2[i].zsub_recipient);
978         }
979 }
980
981 void
982 fix_macros2(src,dest)
983         register char *src;
984         char **dest;
985 {
986         if (!strcmp(src,TOKEN_HOSTNAME)) {
987                 *dest = ourhost;
988                 return;
989         }
990         if (!strcmp(src,TOKEN_CANONNAME)) {
991                 *dest = ourhostcanon;
992                 return;
993         }
994         if (!strcmp(src,TOKEN_ME))
995                 *dest = ZGetSender();
996 }