/* $Header$ * * Command line oriented SMS List tool. * * by Mark Rosenstein, September 1988. * * Copyright 1989 by the Massachusetts Institute of Technology. */ #include #include #include #include #include #ifndef LINT static char smslist_rcsid[] = "$Header$"; #endif struct member { int type; char *name; }; /* member types */ #define M_ANY 0 #define M_USER 1 #define M_LIST 2 #define M_STRING 3 /* flags from command line */ int infoflg, verbose, syncflg, memberflg, debugflg; /* various member lists */ struct save_queue *addlist, *dellist, *memberlist, *synclist; char *listname, *whoami; extern char *index(); extern int errno; int show_list_info(), show_list_count(), get_list_members(), scream(); struct member *parse_member(); main(argc, argv) int argc; char **argv; { int status; char **arg = argv; char *membervec[3]; struct member *memberstruct; /* clear all flags & lists */ infoflg = verbose = syncflg = memberflg = debugflg = 0; listname = NULL; addlist = sq_create(); dellist = sq_create(); memberlist = sq_create(); synclist = sq_create(); whoami = argv[0]; /* parse args, building addlist, dellist, & synclist */ while (++arg - argv < argc) { if (**arg == '-') switch((*arg)[1]) { case 'm': memberflg++; break; case 'D': debugflg++; break; case 'i': infoflg++; break; case 'v': verbose++; break; case 'a': if (arg - argv < argc - 1) { ++arg; if (memberstruct = parse_member(*arg)) sq_save_data(addlist, memberstruct); } else usage(argv); break; case 'd': if (arg - argv < argc - 1) { ++arg; if (memberstruct = parse_member(*arg)) sq_save_data(dellist, memberstruct); } else usage(argv); break; case 'f': if (arg - argv < argc - 1) { FILE *in; char buf[BUFSIZ]; syncflg++; ++arg; if (!strcmp(*arg, "-")) in = stdin; else { in = fopen(*arg, "r"); if (!in) { com_err(whoami, errno, " while opening %s for input", *arg); exit(2); } } while (fgets(buf, BUFSIZ, in)) if (memberstruct = parse_member(buf)) sq_save_data(synclist, memberstruct); if (!feof(in)) com_err(whoami, errno, " while reading from %s", *arg); } else usage(argv); break; default: usage(argv); } else if (listname == NULL) listname = *arg; else usage(argv); } if (listname == NULL) usage(argv); /* if no other options specified, turn on list members flag */ if (!(infoflg || syncflg || addlist->q_next != addlist || dellist->q_next != dellist)) memberflg++; /* fire up SMS */ if (status = sms_connect()) { com_err(whoami, status, " unable to connect to SMS"); exit(2); } if (status = sms_auth("blanche")) { com_err(whoami, status, " unable to authenticate to SMS"); exit(2); } /* display list info if requested to */ if (infoflg) { status = sms_query("get_list_info", 1, &listname, show_list_info,NULL); if (status) com_err(whoami, status, " while getting list information"); if (verbose && !memberflg) { status = sms_query("count_members_of_list", 1, &listname, show_list_count, NULL); if (status) com_err(whoami, status, " while getting list count"); } } /* if we're synchronizing to a file, we need to: * get the current members of the list * for each member of the sync file * if they are on the list, remove them from the in-memory copy * if they're not on the list, add them to add-list * if anyone is left on the in-memory copy, put them on the delete-list * lastly, reset memberlist so we can use it again later */ if (syncflg) { status = sms_query("get_members_of_list", 1, &listname, get_list_members, memberlist); if (status) com_err(whoami, status, " while getting members of list"); while (sq_get_data(synclist, &memberstruct)) { struct save_queue *q; int removed = 0; for (q = memberlist->q_next; q != memberlist; q = q->q_next) { if (membermatch(q->q_data, memberstruct)) { q->q_prev->q_next = q->q_next; q->q_next->q_prev = q->q_prev; removed++; break; } } if (!removed) sq_save_data(addlist, memberstruct); } while (sq_get_data(memberlist, &memberstruct)) sq_save_data(dellist, memberstruct); sq_destroy(memberlist); memberlist = sq_create(); } /* Process the add list */ while (sq_get_data(addlist, &memberstruct)) { membervec[0] = listname; membervec[2] = memberstruct->name; switch (memberstruct->type) { case M_ANY: case M_USER: membervec[1] = "USER"; status = sms_query("add_member_to_list", 3, membervec, scream, NULL); if (status == SMS_SUCCESS) break; else if (status != SMS_USER || memberstruct->type != M_ANY) { com_err(whoami, status, " while adding member %s to %s", memberstruct->name, listname); break; } case M_LIST: membervec[1] = "LIST"; status = sms_query("add_member_to_list", 3, membervec, scream, NULL); if (status == SMS_SUCCESS) break; else if (status != SMS_LIST || memberstruct->type != M_ANY) { com_err(whoami, status, " while adding member %s to %s", memberstruct->name, listname); break; } case M_STRING: membervec[1] = "STRING"; status = sms_query("add_member_to_list", 3, membervec, scream, NULL); if (status != SMS_SUCCESS) com_err(whoami, status, " while adding member %s to %s", memberstruct->name, listname); } } /* Process the delete list */ while (sq_get_data(dellist, &memberstruct)) { membervec[0] = listname; membervec[2] = memberstruct->name; switch (memberstruct->type) { case M_ANY: case M_USER: membervec[1] = "USER"; status = sms_query("delete_member_from_list", 3, membervec, scream, NULL); if (status == SMS_SUCCESS) break; else if ((status != SMS_USER && status != SMS_NO_MATCH) || memberstruct->type != M_ANY) { com_err(whoami, status, " while deleteing member %s from %s", memberstruct->name, listname); break; } case M_LIST: membervec[1] = "LIST"; status = sms_query("delete_member_from_list", 3, membervec, scream, NULL); if (status == SMS_SUCCESS) break; else if ((status != SMS_LIST && status != SMS_NO_MATCH) || memberstruct->type != M_ANY) { com_err(whoami, status, " while deleteing member %s from %s", memberstruct->name, listname); break; } case M_STRING: membervec[1] = "STRING"; status = sms_query("delete_member_from_list", 3, membervec, scream, NULL); if (status == SMS_STRING && memberstruct->type == M_ANY) com_err(whoami, 0, "Unable to find member %s to delete from %s", memberstruct->name, listname); else if (status != SMS_SUCCESS) com_err(whoami, status, " while deleteing member %s from %s", memberstruct->name, listname); } } /* Display the members of the list now, if requested */ if (memberflg) { status = sms_query("get_members_of_list", 1, &listname, get_list_members, memberlist); if (status) com_err(whoami, status, " while getting members of list"); while (sq_get_data(memberlist, &memberstruct)) { if (verbose) { char *s; switch (memberstruct->type) { case M_USER: s = "USER"; break; case M_LIST: s = "LIST"; break; case M_STRING: s = "STRING"; break; } printf("%s: %s\n", s, memberstruct->name); } else { if (memberstruct->type == M_LIST) printf("LIST:%s\n", memberstruct->name); else if (memberstruct->type == M_STRING && !index(memberstruct->name, '@')) printf("STRING:%s\n", memberstruct->name); else printf("%s\n", memberstruct->name); } } } /* We're done! */ sms_disconnect(); exit(0); } usage(argv) char **argv; { printf("Usage: %s [-i] [-v] [-m] listname [-a member] [-d member] [-f file]\n", argv[0]); exit(1); } show_list_info(argc, argv, hint) int argc; char **argv; int hint; { printf("List: %s\n", argv[0]); printf("Description: %s\n", argv[9]); printf("Flags: %s, %s, and %s\n", atoi(argv[1]) ? "active" : "inactive", atoi(argv[2]) ? "public" : "private", atoi(argv[3]) ? "hidden" : "visible"); printf("%s is %sa maillist, and is %sa group", argv[0], atoi(argv[4]) ? "" : "not ", atoi(argv[5]) ? "" : "not "); if (atoi(argv[5])) printf(" with GID %d\n", atoi(argv[6])); else printf("\n"); printf("Owner: %s %s\n", argv[7], argv[8]); printf("Last modified by %s with %s on %s\n", argv[11], argv[12], argv[10]); return(SMS_CONT); } show_list_count(argc, argv, hint) int argc; char **argv; int hint; { printf("Members: %s\n", argv[0]); } get_list_members(argc, argv, q) int argc; char **argv; struct save_queue *q; { struct member *m; m = (struct member *) malloc(sizeof(struct member)); switch (argv[0][0]) { case 'U': m->type = M_USER; break; case 'L': m->type = M_LIST; break; case 'S': m->type = M_STRING; break; } m->name = strsave(argv[1]); sq_save_data(q, m); return(SMS_CONT); } scream() { fprintf(stderr, "Programmer botch\n"); exit(3); } struct member *parse_member(s) register char *s; { register struct member *m; char *p; while (*s && isspace(*s)) s++; p = s; while (*p && isprint(*p) && !isspace(*p) && *p != ';') p++; *p = 0; if (p == s || strlen(s) == 0) return(NULL); if ((m = (struct member *) malloc(sizeof(struct member))) == NULL) return(NULL); if (p = index(s, ':')) { *p = 0; m->name = ++p; if (!strcasecmp("user", s)) m->type = M_USER; else if (!strcasecmp("list", s)) m->type = M_LIST; else if (!strcasecmp("string", s)) m->type = M_STRING; else { m->type = M_STRING; *(--p) = ':'; m->name = s; } m->name = strsave(m->name); return(m); } m->name = strsave(s); if (index(s, '@') || index(s, '!') || index(s, '%')) m->type = M_STRING; else m->type = M_ANY; return(m); } int membermatch(m1, m2) struct member *m1, *m2; { if (strcmp(m1->name, m2->name)) return(0); if (m1->type == M_ANY || m2->type == M_ANY) return(1); if (m1->type == m2->type) return(1); else return(0); }