3 * Command line oriented SMS List tool.
5 * by Mark Rosenstein, September 1988.
7 * Copyright 1989 by the Massachusetts Institute of Technology.
9 * (c) Copyright 1988 by the Massachusetts Institute of Technology.
10 * For copying and distribution information, please see the file
14 /* ### Aren't there a lot of sq abstraction barrier violations here?
15 Do we need to improve the support for queue operations? */
17 #include <mit-copyright.h>
24 static char smslist_rcsid[] = "$Header$";
33 /* It is important to membercmp that M_USER < M_LIST < M_STRING */
40 /* argument parsing macro */
41 #define argis(a,b) ((strcmp(*arg+1, a) == 0) || (strcmp(*arg+1, b) == 0))
43 /* flags from command line */
44 int infoflg, verbose, syncflg, memberflg, recursflg, debugflg, noauth;
45 int showusers, showstrings, showkerberos, showlists;
47 /* various member lists */
48 struct save_queue *addlist, *dellist, *memberlist, *synclist;
50 char *listname, *whoami;
55 int show_list_info(), show_list_count(), get_list_members(), scream();
56 int show_list_members();
57 struct member *parse_member();
67 char *membervec[3], *motd;
68 struct member *memberstruct;
69 char *server = SMS_SERVER;
71 /* clear all flags & lists */
72 infoflg = verbose = syncflg = memberflg = debugflg = recursflg = 0;
73 noauth = showusers = showstrings = showkerberos = showlists = 0;
75 addlist = sq_create();
76 dellist = sq_create();
77 memberlist = sq_create();
78 synclist = sq_create();
81 /* parse args, building addlist, dellist, & synclist */
82 while (++arg - argv < argc) {
85 if (argis("m", "members"))
87 else if (argis("u", "users"))
89 else if (argis("s", "strings"))
91 else if (argis("l", "lists"))
93 else if (argis("k", "kerberos"))
95 else if (argis("D", "debug"))
97 else if (argis("i","info"))
99 else if (argis("n","noauth"))
101 else if (argis("v","verbose"))
103 else if (argis("r","recursive"))
105 else if (argis("S","server"))
106 if (arg - argv < argc - 1) {
111 else if (argis("a","add"))
112 if (arg - argv < argc - 1) {
114 if (memberstruct = parse_member(*arg))
115 sq_save_data(addlist, memberstruct);
118 else if (argis("d","delete"))
119 if (arg - argv < argc - 1) {
121 if (memberstruct = parse_member(*arg))
122 sq_save_data(dellist, memberstruct);
125 else if (argis("f","file"))
126 if (arg - argv < argc - 1) {
132 if (!strcmp(*arg, "-"))
135 in = fopen(*arg, "r");
137 com_err(whoami, errno,
138 " while opening %s for input", *arg);
142 while (fgets(buf, BUFSIZ, in))
143 if (memberstruct = parse_member(buf))
144 sq_save_data(synclist, memberstruct);
146 com_err(whoami, errno, " while reading from %s", *arg);
152 else if (listname == NULL)
157 if (listname == NULL)
160 /* if no other options specified, turn on list members flag */
161 if (!(infoflg || syncflg ||
162 addlist->q_next != addlist || dellist->q_next != dellist))
165 /* If none of {users,strings,lists,kerberos} specified, turn them all on */
166 if (!(showusers || showstrings || showlists || showkerberos))
167 showusers = showstrings = showlists = showkerberos = 1;
170 if (status = sms_connect(server)) {
171 com_err(whoami, status, " unable to connect to the Moira server");
174 if ( status = sms_motd(&motd) ) {
175 com_err(whoami, status, " unable to check server status");
179 fprintf(stderr, "The Moira server is currently unavailable:\n%s\n", motd);
184 if (!noauth && (status = sms_auth("blanche"))) {
185 com_err(whoami, status, " unable to authenticate to Moira");
187 "Try the -noauth flag if you don't need authentication");
191 /* display list info if requested to */
193 status = sms_query("get_list_info", 1, &listname, show_list_info,NULL);
195 com_err(whoami, status, " while getting list information");
196 if (verbose && !memberflg) {
197 status = sms_query("count_members_of_list", 1, &listname,
198 show_list_count, NULL);
200 com_err(whoami, status, " while getting list count");
204 /* if we're synchronizing to a file, we need to:
205 * get the current members of the list
206 * for each member of the sync file
207 * if they are on the list, remove them from the in-memory copy
208 * if they're not on the list, add them to add-list
209 * if anyone is left on the in-memory copy, put them on the delete-list
210 * lastly, reset memberlist so we can use it again later
213 status = sms_query("get_members_of_list", 1, &listname,
214 get_list_members, (char *)memberlist);
216 com_err(whoami, status, " getting members of list %s", listname);
217 while (sq_get_data(synclist, &memberstruct)) {
218 struct save_queue *q;
221 for (q = memberlist->q_next; q != memberlist; q = q->q_next) {
222 if (membercmp(q->q_data, memberstruct) == 0) {
223 q->q_prev->q_next = q->q_next;
224 q->q_next->q_prev = q->q_prev;
230 sq_save_data(addlist, memberstruct);
232 while (sq_get_data(memberlist, &memberstruct))
233 sq_save_data(dellist, memberstruct);
234 sq_destroy(memberlist);
235 memberlist = sq_create();
238 /* Process the add list */
239 while (sq_get_data(addlist, &memberstruct)) {
240 membervec[0] = listname;
241 membervec[2] = memberstruct->name;
243 printf("Adding member ");
244 show_list_member(memberstruct);
246 switch (memberstruct->type) {
249 membervec[1] = "USER";
250 status = sms_query("add_member_to_list", 3, membervec, scream, NULL);
251 if (status == SMS_SUCCESS)
253 else if (status != SMS_USER || memberstruct->type != M_ANY) {
254 com_err(whoami, status, " while adding member %s to %s",
255 memberstruct->name, listname);
259 membervec[1] = "LIST";
260 status = sms_query("add_member_to_list", 3, membervec,
262 if (status == SMS_SUCCESS)
264 else if (status != SMS_LIST || memberstruct->type != M_ANY) {
265 com_err(whoami, status, " while adding member %s to %s",
266 memberstruct->name, listname);
270 membervec[1] = "STRING";
271 status = sms_query("add_member_to_list", 3, membervec,
273 if (status != SMS_SUCCESS)
274 com_err(whoami, status, " while adding member %s to %s",
275 memberstruct->name, listname);
278 membervec[1] = "KERBEROS";
279 status = sms_query("add_member_to_list", 3, membervec,
281 if (status != SMS_SUCCESS)
282 com_err(whoami, status, " while adding member %s to %s",
283 memberstruct->name, listname);
287 /* Process the delete list */
288 while (sq_get_data(dellist, &memberstruct)) {
289 membervec[0] = listname;
290 membervec[2] = memberstruct->name;
292 printf("Deleting member ");
293 show_list_member(memberstruct);
295 switch (memberstruct->type) {
298 membervec[1] = "USER";
299 status = sms_query("delete_member_from_list", 3, membervec,
301 if (status == SMS_SUCCESS)
303 else if ((status != SMS_USER && status != SMS_NO_MATCH) ||
304 memberstruct->type != M_ANY) {
305 com_err(whoami, status, " while deleteing member %s from %s",
306 memberstruct->name, listname);
310 membervec[1] = "LIST";
311 status = sms_query("delete_member_from_list", 3, membervec,
313 if (status == SMS_SUCCESS)
315 else if ((status != SMS_LIST && status != SMS_NO_MATCH) ||
316 memberstruct->type != M_ANY) {
317 com_err(whoami, status, " while deleteing member %s from %s",
318 memberstruct->name, listname);
322 membervec[1] = "STRING";
323 status = sms_query("delete_member_from_list", 3, membervec,
325 if (status == SMS_STRING && memberstruct->type == M_ANY)
326 com_err(whoami, 0, "Unable to find member %s to delete from %s",
327 memberstruct->name, listname);
328 else if (status != SMS_SUCCESS)
329 com_err(whoami, status, " while deleteing member %s from %s",
330 memberstruct->name, listname);
333 membervec[1] = "KERBEROS";
334 status = sms_query("delete_member_from_list", 3, membervec,
336 if (status != SMS_SUCCESS)
337 com_err(whoami, status, " while deleteing member %s from %s",
338 memberstruct->name, listname);
342 /* Display the members of the list now, if requested */
345 recursive_display_list_members();
347 status = sms_query("get_members_of_list", 1, &listname,
348 get_list_members, (char *)memberlist);
350 com_err(whoami, status, " while getting members of list %s",
352 while (sq_get_data(memberlist, &memberstruct))
353 show_list_member(memberstruct);
365 fprintf(stderr, "Usage: %s [options] listname [options]\n",argv[0]);
366 fprintf(stderr, "Options are\n");
367 fprintf(stderr, " -v | -verbose\n");
368 fprintf(stderr, " -m | -members\n");
369 fprintf(stderr, " -u | -users\n");
370 fprintf(stderr, " -l | -lists\n");
371 fprintf(stderr, " -s | -strings\n");
372 fprintf(stderr, " -k | -kerberos\n");
373 fprintf(stderr, " -i | -info\n");
374 fprintf(stderr, " -r | -recursive\n");
375 fprintf(stderr, " -a | -add member\n");
376 fprintf(stderr, " -d | -delete member\n");
377 fprintf(stderr, " -f | -file filename\n");
378 fprintf(stderr, " -n | -noauth\n");
379 fprintf(stderr, " -S | -server host:port\n");
380 fprintf(stderr, " -D | -debug\n");
385 /* Display the members stored in the queue */
387 show_list_member(memberstruct)
388 struct member *memberstruct;
392 switch (memberstruct->type) {
414 printf("%s\n", memberstruct->name);
419 printf("%s:%s\n", s, memberstruct->name);
421 if (memberstruct->type == M_LIST)
422 printf("LIST:%s\n", memberstruct->name);
423 else if (memberstruct->type == M_KERBEROS)
424 printf("KERBEROS:%s\n", memberstruct->name);
425 else if (memberstruct->type == M_STRING &&
426 !index(memberstruct->name, '@'))
427 printf("STRING:%s\n", memberstruct->name);
429 printf("%s\n", memberstruct->name);
434 /* Show the retrieved information about a list */
436 show_list_info(argc, argv, hint)
441 printf("List: %s\n", argv[0]);
442 printf("Description: %s\n", argv[9]);
443 printf("Flags: %s, %s, and %s\n",
444 atoi(argv[1]) ? "active" : "inactive",
445 atoi(argv[2]) ? "public" : "private",
446 atoi(argv[3]) ? "hidden" : "visible");
447 printf("%s is %sa maillist and is %sa group", argv[0],
448 atoi(argv[4]) ? "" : "not ",
449 atoi(argv[5]) ? "" : "not ");
451 printf(" with GID %d\n", atoi(argv[6]));
454 printf("Owner: %s %s\n", argv[7], argv[8]);
455 printf("Last modified by %s with %s on %s\n", argv[11], argv[12], argv[10]);
460 /* Show the retrieve list member count */
462 show_list_count(argc, argv, hint)
467 printf("Members: %s\n", argv[0]);
471 /* Recursively find all of the members of listname, and then display them */
473 recursive_display_list_members()
475 int status, count, savecount;
476 struct save_queue *lists, *members;
477 struct member *m, *m1, *data;
480 members = sq_create();
481 m = (struct member *) malloc(sizeof(struct member));
484 sq_save_data(lists, m);
486 while (sq_get_data(lists, &m)) {
487 sq_destroy(memberlist);
488 memberlist = sq_create();
490 fprintf(stderr, "Fetching members of %s\n", m->name);
491 status = sms_query("get_members_of_list", 1, &(m->name),
492 get_list_members, (char *)memberlist);
494 com_err(whoami, status, " while getting members of list %s", m->name);
495 while (sq_get_data(memberlist, &m1)) {
496 if (m1->type == M_LIST)
497 unique_add_member(lists, m1);
499 unique_add_member(members, m1);
502 savecount = count = sq_count_elts(members);
503 data = (struct member *) malloc(count * sizeof(struct member));
505 while (sq_get_data(members, &m))
506 bcopy(m, &data[count++], sizeof(struct member));
507 qsort(data, count, sizeof(struct member), membercmp);
508 for (count = 0; count < savecount; count++) {
509 show_list_member(&data[count]);
514 /* add a struct member to a queue if that member isn't already there. */
516 unique_add_member(q, m)
517 struct save_queue *q;
520 struct save_queue *qp;
522 for (qp = q->q_next; qp != q; qp = qp->q_next) {
523 if (!membercmp(qp->q_data, m))
530 /* Collect the retrieved members of the list */
532 get_list_members(argc, argv, q)
535 struct save_queue *q;
539 m = (struct member *) malloc(sizeof(struct member));
540 switch (argv[0][0]) {
551 m->type = M_KERBEROS;
554 m->name = strsave(argv[1]);
560 /* Called only if a query returns a value that we weren't expecting */
564 fprintf(stderr, "Programmer botch\n");
569 /* Parse a line of input, fetching a member. NULL is returned if a member
570 * is not found. Only the first token on the line is parsed. ';' is a
574 struct member *parse_member(s)
577 register struct member *m;
580 while (*s && isspace(*s))
583 while (*p && isprint(*p) && !isspace(*p) && *p != ';')
586 if (p == s || strlen(s) == 0)
589 if ((m = (struct member *) malloc(sizeof(struct member))) == NULL)
592 if (p = index(s, ':')) {
595 if (!strcasecmp("user", s))
597 else if (!strcasecmp("list", s))
599 else if (!strcasecmp("string", s))
601 else if (!strcasecmp("kerberos", s))
602 m->type = M_KERBEROS;
608 m->name = strsave(m->name);
611 m->name = strsave(s);
612 if (index(s, '@') || index(s, '!') || index(s, '%'))
621 * This routine two compares members by the following rules:
622 * 1. A USER is less than a LIST
623 * 2. A LIST is less than a STRING
624 * 3. If two members are of the same type, the one alphabetically first
625 * is less than the other
626 * It returs < 0 if the first member is less, 0 if they are identical, and
627 * > 0 if the second member is less (the first member is greater).
630 int membercmp(m1, m2)
631 struct member *m1, *m2;
633 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
634 return(strcmp(m1->name, m2->name));
636 return(m1->type - m2->type);
641 struct save_queue *q;
647 while (sq_get_data(q, &foo))