/* This file is part of the Project Athena Zephyr Notification System. * It contains code for the "zctl" command. * * Created by: Robert French * * $Id$ * * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. * For copying and distribution information, see the file * "mit-copyright.h". */ #include #include #include #include #include #include #ifndef lint static const char *rcsid_zctl_c = "$Id$"; #endif #define SUBSATONCE 7 #define SUB 0 #define UNSUB 1 #define LIST 2 #define USERS_SUBS "/.zephyr.subs" #define OLD_SUBS "/.subscriptions" #define TOKEN_HOSTNAME "%host%" #define TOKEN_CANONNAME "%canon%" #define TOKEN_ME "%me%" #define TOKEN_WILD "*" #define ALL 0 #define UNSUBONLY 1 #define SUBONLY 2 #define ERR (-1) #define NOT_REMOVED 0 #define REMOVED 1 int purge_subs(); int sci_idx; char subsname[BUFSIZ]; char ourhost[MAXHOSTNAMELEN],ourhostcanon[MAXHOSTNAMELEN]; extern ss_request_table zctl_cmds; main(argc,argv) int argc; char *argv[]; { struct passwd *pwd; struct hostent *hent; char ssline[BUFSIZ],oldsubsname[BUFSIZ],*envptr,*tty = NULL; int retval,code,i; #ifdef HAVE_SYS_UTSNAME struct utsname name; #endif if ((retval = ZInitialize()) != ZERR_NONE) { com_err(argv[0],retval,"while initializing"); exit (1); } /* Set hostname and tty for locations. If we support X, use the * DISPLAY environment variable for the tty name. */ #ifndef X_DISPLAY_MISSING tty = getenv("DISPLAY"); #endif if ((retval = ZInitLocationInfo(NULL, tty)) != ZERR_NONE) com_err(argv[0], retval, "initializing location information"); envptr = getenv("HOME"); if (envptr) strcpy(subsname,envptr); else { if (!(pwd = getpwuid((int) getuid()))) { fprintf(stderr,"Who are you?\n"); exit (1); } strcpy(subsname,pwd->pw_dir); } strcpy(oldsubsname,subsname); strcat(oldsubsname,OLD_SUBS); strcat(subsname,USERS_SUBS); if (!access(oldsubsname,F_OK) && access(subsname, F_OK)) { /* only if old one exists and new one does not exist */ 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"); if (rename(oldsubsname,subsname)) com_err(argv[0], errno, "renaming .subscriptions"); } #ifdef HAVE_SYS_UTSNAME uname(&name); strcpy(ourhost, name.nodename); #else if (gethostname(ourhost,MAXHOSTNAMELEN) == -1) { com_err(argv[0],errno,"while getting host name"); exit (1); } #endif if (!(hent = gethostbyname(ourhost))) { fprintf(stderr,"%s: Can't get canonical name for host %s", argv[0], ourhost); exit (1); } (void) strcpy(ourhostcanon,hent->h_name); sci_idx = ss_create_invocation("zctl","",0,&zctl_cmds,&code); if (code) { ss_perror(sci_idx,code,"while creating invocation"); exit(1); } if (argc > 1) { *ssline = '\0'; for (i=1;i 2) { fprintf(stderr,"Usage: %s filename\n",argv[0]); return; } if (argc == 1) printf("Current file: %s\n",subsname); else (void) strcpy(subsname,argv[1]); } flush_locations(argc,argv) int argc; char *argv[]; { int retval; if (argc > 1) { fprintf(stderr,"Usage: %s\n",argv[0]); return; } if ((retval = ZFlushMyLocations()) != ZERR_NONE) ss_perror(sci_idx,retval,"while flushing locations"); } wgc_control(argc,argv) int argc; register char **argv; { int retval; short newport; struct sockaddr_in newsin; ZNotice_t notice; newsin = ZGetDestAddr(); if (argc > 1) { fprintf(stderr,"Usage: %s\n",argv[0]); return; } if ((newport = ZGetWGPort()) == -1) { ss_perror(sci_idx,errno,"while getting WindowGram port"); return; } newsin.sin_port = (u_short) newport; if ((retval = ZSetDestAddr(&newsin)) != ZERR_NONE) { ss_perror(sci_idx,retval,"while setting destination address"); return; } (void) memset((char *)¬ice, 0, sizeof(notice)); notice.z_kind = UNSAFE; notice.z_port = 0; notice.z_class = WG_CTL_CLASS; notice.z_class_inst = WG_CTL_USER; if (!strcmp(argv[0],"wg_read")) notice.z_opcode = USER_REREAD; if (!strcmp(argv[0],"wg_shutdown")) notice.z_opcode = USER_SHUTDOWN; if (!strcmp(argv[0],"wg_startup")) notice.z_opcode = USER_STARTUP; if (!strcmp(argv[0],"wg_exit")) notice.z_opcode = USER_EXIT; if (!notice.z_opcode) { fprintf(stderr, "unknown WindowGram client control command %s\n", argv[0]); return; } notice.z_sender = 0; notice.z_recipient = ""; notice.z_default_format = ""; notice.z_message_len = 0; if ((retval = ZSendNotice(¬ice,ZNOAUTH)) != ZERR_NONE) ss_perror(sci_idx,retval,"while sending notice"); if ((retval = ZInitialize()) != ZERR_NONE) ss_perror(sci_idx,retval, "while reinitializing"); } hm_control(argc,argv) int argc; char *argv[]; { int retval; ZNotice_t notice; if (argc > 1) { fprintf(stderr,"Usage: %s\n",argv[0]); return; } (void) memset((char *)¬ice, 0, sizeof(notice)); notice.z_kind = HMCTL; notice.z_port = 0; notice.z_class = HM_CTL_CLASS; notice.z_class_inst = HM_CTL_CLIENT; if (!strcmp(argv[0],"hm_flush")) notice.z_opcode = CLIENT_FLUSH; if (!strcmp(argv[0],"new_server")) notice.z_opcode = CLIENT_NEW_SERVER; if (!notice.z_opcode) { fprintf(stderr, "unknown HostManager control command %s\n", argv[0]); return; } notice.z_sender = 0; notice.z_recipient = ""; notice.z_default_format = ""; notice.z_message_len = 0; if ((retval = ZSendNotice(¬ice,ZNOAUTH)) != ZERR_NONE) ss_perror(sci_idx,retval,"while sending notice"); } show_var(argc,argv) int argc; char *argv[]; { int i; char *value; if (argc < 2) { fprintf(stderr,"Usage: %s ...\n",argv[0]); return; } for (i=1;i [value]\n", argv[0]); return; } setting_exp = 0; if (!strcasecmp(argv[1],"exposure")) { setting_exp = 1; if (argc != 3) { fprintf(stderr,"An exposure setting must be specified.\n"); return; } exp_level = (char *)0; if (!strcasecmp(argv[2],EXPOSE_NONE)) exp_level = EXPOSE_NONE; if (!strcasecmp(argv[2],EXPOSE_OPSTAFF)) exp_level = EXPOSE_OPSTAFF; if (!strcasecmp(argv[2],EXPOSE_REALMVIS)) exp_level = EXPOSE_REALMVIS; if (!strcasecmp(argv[2],EXPOSE_REALMANN)) exp_level = EXPOSE_REALMANN; if (!strcasecmp(argv[2],EXPOSE_NETVIS)) exp_level = EXPOSE_NETVIS; if (!strcasecmp(argv[2],EXPOSE_NETANN)) exp_level = EXPOSE_NETANN; if (!exp_level) { fprintf(stderr,"The exposure setting must be one of:\n"); fprintf(stderr,"%s, %s, %s, %s, %s, %s.\n", EXPOSE_NONE, EXPOSE_OPSTAFF, EXPOSE_REALMVIS, EXPOSE_REALMANN, EXPOSE_NETVIS, EXPOSE_NETANN); return; } } if (argc == 2) retval = ZSetVariable(argv[1],""); else { (void) strcpy(varcat,argv[2]); for (i=3;i [ ... ]\n", argv[0]); return; } for (i=1;i 4 || argc < 3) { fprintf(stderr,"Usage: %s class instance [*]\n",argv[0]); return; } sub.zsub_class = argv[1]; sub.zsub_classinst = argv[2]; sub.zsub_recipient = (argc == 3)?ZGetSender():argv[3]; fix_macros(&sub,&sub2,1); if ((wgport = ZGetWGPort()) == -1) { ss_perror(sci_idx,errno,"while finding WindowGram port"); return; } retval = (*argv[0] == 's') ? ZSubscribeTo(&sub2,1,(u_short)wgport) : ZUnsubscribeTo(&sub2,1,(u_short)wgport); if (retval != ZERR_NONE) ss_perror(sci_idx,retval,"while subscribing"); } sub_file(argc,argv) int argc; char *argv[]; { ZSubscription_t sub; short wgport; if (argc > 4 || argc < 3) { fprintf(stderr,"Usage: %s class instance [*]\n",argv[0]); return; } if (argv[1][0] == '!') { ss_perror(sci_idx,0, (!strcmp(argv[0],"add_unsubscription") || !strcmp(argv[0],"add_un") || !strcmp(argv[0],"delete_unsubscription") || !strcmp(argv[0],"del_un")) ? "Do not use `!' as the first character of a class.\n\tIt is automatically added before modifying the subscription file." : "Do not use `!' as the first character of a class.\n\tIt is reserved for internal use with un-subscriptions."); return; } sub.zsub_class = argv[1]; sub.zsub_classinst = argv[2]; sub.zsub_recipient = (argc == 3)?TOKEN_ME:argv[3]; if (make_exist(subsname)) return; if ((wgport = ZGetWGPort()) == -1) { ss_perror(sci_idx,errno,"while finding WindowGram port"); return; } if (!strcmp(argv[0],"add")) add_file(wgport,&sub,0); else if (!strcmp(argv[0],"add_unsubscription") || !strcmp(argv[0],"add_un")) add_file(wgport,&sub,1); else if (!strcmp(argv[0],"delete") || !strcmp(argv[0],"del") || !strcmp(argv[0],"dl")) del_file(wgport,&sub,0); else if (!strcmp(argv[0],"delete_unsubscription") || !strcmp(argv[0],"del_un")) { del_file(wgport,&sub,1); } else ss_perror(sci_idx,0,"unknown command name"); return; } add_file(wgport,subs,unsub) short wgport; ZSubscription_t *subs; int unsub; { FILE *fp; char errbuf[BUFSIZ]; ZSubscription_t sub2; Code_t retval; (void) purge_subs(subs,ALL); /* remove copies in the subs file */ if (!(fp = fopen(subsname,"a"))) { (void) sprintf(errbuf,"while opening %s for append",subsname); ss_perror(sci_idx,errno,errbuf); return; } fprintf(fp,"%s%s,%s,%s\n", unsub ? "!" : "", subs->zsub_class, subs->zsub_classinst, subs->zsub_recipient); if (fclose(fp) == EOF) { (void) sprintf(errbuf, "while closing %s", subsname); ss_perror(sci_idx, errno, errbuf); return; } fix_macros(subs,&sub2,1); if (retval = (unsub ? ZUnsubscribeTo(&sub2,1,(u_short)wgport) : ZSubscribeTo(&sub2,1,(u_short)wgport))) ss_perror(sci_idx,retval, unsub ? "while unsubscribing" : "while subscribing"); return; } del_file(wgport,subs,unsub) short wgport; register ZSubscription_t *subs; int unsub; { ZSubscription_t sub2; int retval; retval = purge_subs(subs, unsub ? UNSUBONLY : SUBONLY); if (retval == ERR) return; if (retval == NOT_REMOVED) fprintf(stderr, "Couldn't find %sclass %s instance %s recipient %s in\n\tfile %s\n", unsub ? "un-subscription " : "", subs->zsub_class, subs->zsub_classinst, subs->zsub_recipient, subsname); fix_macros(subs,&sub2,1); if ((retval = ZUnsubscribeTo(&sub2,1,(u_short)wgport)) != ZERR_NONE) ss_perror(sci_idx,retval,"while unsubscribing"); return; } int purge_subs(subs,which) register ZSubscription_t *subs; int which; { FILE *fp,*fpout; char errbuf[BUFSIZ],subline[BUFSIZ]; char backup[BUFSIZ],ourline[BUFSIZ]; int delflag = NOT_REMOVED; int keep; switch (which) { case SUBONLY: case UNSUBONLY: case ALL: break; default: ss_perror(sci_idx,0,"internal error in purge_subs"); return(ERR); } (void) sprintf(ourline,"%s,%s,%s", subs->zsub_class, subs->zsub_classinst, subs->zsub_recipient); if (!(fp = fopen(subsname,"r"))) { (void) sprintf(errbuf,"while opening %s for read",subsname); ss_perror(sci_idx,errno,errbuf); return(ERR); } (void) strcpy(backup, subsname); (void) strcat(backup, ".temp"); (void) unlink(backup); if (!(fpout = fopen(backup,"w"))) { (void) sprintf(errbuf,"while opening %s for writing",backup); ss_perror(sci_idx,errno,errbuf); (void) fclose(fp); return(ERR); } for (;;) { if (!fgets(subline,sizeof subline,fp)) break; if (*subline) subline[strlen(subline)-1] = '\0'; /* nuke newline */ switch (which) { case SUBONLY: keep = strcmp(subline,ourline); break; case UNSUBONLY: keep = (*subline != '!' || strcmp(subline+1,ourline)); break; case ALL: keep = (strcmp(subline,ourline) && (*subline != '!' || strcmp(subline+1, ourline))); break; } if (keep) { fputs(subline, fpout); if (ferror(fpout) || (fputc('\n', fpout) == EOF)) { (void) sprintf(errbuf, "while writing to %s", backup); ss_perror(sci_idx, errno, errbuf); } } else delflag = REMOVED; } (void) fclose(fp); /* open read-only, ignore errs */ if (fclose(fpout) == EOF) { (void) sprintf(errbuf, "while closing %s",backup); ss_perror(sci_idx, errno, errbuf); return(ERR); } if (rename(backup,subsname) == -1) { (void) sprintf(errbuf,"while renaming %s to %s\n", backup,subsname); ss_perror(sci_idx,errno,errbuf); return(ERR); } return(delflag); } load_subs(argc,argv) int argc; char *argv[]; { ZSubscription_t subs[SUBSATONCE],subs2[SUBSATONCE],unsubs[SUBSATONCE]; FILE *fp; int ind,unind,lineno,i,retval,type; short wgport; char *comma,*comma2,*file,subline[BUFSIZ]; if (argc > 2) { fprintf(stderr,"Usage: %s [file]\n",argv[0]); return; } if (*argv[0] == 'u') type = UNSUB; else if (!strcmp(argv[0],"list") || !strcmp(argv[0],"ls")) type = LIST; else type = SUB; if (type != LIST) if ((wgport = ZGetWGPort()) == -1) { ss_perror(sci_idx,errno, "while finding WindowGram port"); return; } file = (argc == 1) ? subsname : argv[1]; fp = fopen(file,"r"); if (fp == NULL) { ss_perror(sci_idx,errno, "while loading subscription file"); return; } ind = unind = 0; lineno = 1; for (;;lineno++) { if (!fgets(subline,sizeof subline,fp)) break; if (*subline == '#' || !*subline) continue; subline[strlen(subline)-1] = '\0'; /* nuke newline */ comma = strchr(subline,','); if (comma) comma2 = strchr(comma+1,','); else comma2 = 0; if (!comma || !comma2) { fprintf(stderr, "Malformed subscription at line %d of %s:\n%s\n", lineno,file,subline); continue; } *comma = '\0'; *comma2 = '\0'; if (type == LIST) { if (*subline == '!') printf("(Un-subscription) Class %s instance %s recipient %s\n", subline+1, comma+1, comma2+1); else printf("Class %s instance %s recipient %s\n", subline, comma+1, comma2+1); continue; } if (*subline == '!') { /* an un-subscription */ /* if we are explicitly un-subscribing to the contents of a subscription file, ignore any un-subscriptions in that file */ if (type == UNSUB) continue; unsubs[unind].zsub_class = (char *)malloc((unsigned)(strlen(subline))); /* XXX check malloc return */ /* skip the leading '!' */ (void) strcpy(unsubs[unind].zsub_class,subline+1); unsubs[unind].zsub_classinst = (char *)malloc((unsigned)(strlen(comma+1)+1)); /* XXX check malloc return */ (void) strcpy(unsubs[unind].zsub_classinst,comma+1); unsubs[unind].zsub_recipient = (char *)malloc((unsigned)(strlen(comma2+1)+1)); /* XXX check malloc return */ (void) strcpy(unsubs[unind].zsub_recipient,comma2+1); unind++; } else { subs[ind].zsub_class = (char *)malloc((unsigned)(strlen(subline)+1)); /* XXX check malloc return */ (void) strcpy(subs[ind].zsub_class,subline); subs[ind].zsub_classinst = (char *)malloc((unsigned)(strlen(comma+1)+1)); /* XXX check malloc return */ (void) strcpy(subs[ind].zsub_classinst,comma+1); subs[ind].zsub_recipient = (char *)malloc((unsigned)(strlen(comma2+1)+1)); /* XXX check malloc return */ (void) strcpy(subs[ind].zsub_recipient,comma2+1); ind++; } if (ind == SUBSATONCE) { fix_macros(subs,subs2,ind); if ((retval = (type == SUB)? ZSubscribeTo(subs2,ind,(u_short)wgport): ZUnsubscribeTo(subs2,ind,(u_short)wgport)) != ZERR_NONE) { ss_perror(sci_idx,retval,(type == SUB)? "while subscribing": "while unsubscribing"); goto cleanup; } for (i=0;i