3 * Command line oriented Moira 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>
21 #include <moira_site.h>
24 static char blanche_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(), membercmp();
57 struct member *parse_member();
67 char *membervec[3], *motd;
68 struct member *memberstruct;
69 char *server = NULL, *p;
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("al","addlist"))
119 if (arg - argv < argc - 1) {
121 get_members_from_file(*arg, addlist);
124 else if (argis("d","delete"))
125 if (arg - argv < argc - 1) {
127 if (memberstruct = parse_member(*arg))
128 sq_save_data(dellist, memberstruct);
131 else if (argis("dl","deletelist"))
132 if (arg - argv < argc - 1) {
134 get_members_from_file(*arg, dellist);
137 else if (argis("f","file"))
138 if (arg - argv < argc - 1) {
141 get_members_from_file(*arg, synclist);
147 else if (listname == NULL)
152 if (listname == NULL)
155 /* if no other options specified, turn on list members flag */
156 if (!(infoflg || syncflg ||
157 addlist->q_next != addlist || dellist->q_next != dellist))
160 /* If none of {users,strings,lists,kerberos} specified, turn them all on */
161 if (!(showusers || showstrings || showlists || showkerberos))
162 showusers = showstrings = showlists = showkerberos = 1;
165 if (status = mr_connect(server)) {
166 com_err(whoami, status, "unable to connect to the Moira server");
169 if ( status = mr_motd(&motd) ) {
170 com_err(whoami, status, "unable to check server status");
174 fprintf(stderr, "The Moira server is currently unavailable:\n%s\n", motd);
179 if (!noauth && (status = mr_auth("blanche"))) {
180 if (status == MR_USER_AUTH)
181 com_err(whoami, status, "");
183 com_err(whoami, status, "unable to authenticate to Moira");
185 " Try the -noauth flag if you don't need authentication");
190 /* display list info if requested to */
192 status = mr_query("get_list_info", 1, &listname, show_list_info,NULL);
194 com_err(whoami, status, "while getting list information");
195 if (verbose && !memberflg) {
196 status = mr_query("count_members_of_list", 1, &listname,
197 show_list_count, NULL);
199 com_err(whoami, status, "while getting list count");
203 /* if we're synchronizing to a file, we need to:
204 * get the current members of the list
205 * for each member of the sync file
206 * if they are on the list, remove them from the in-memory copy
207 * if they're not on the list, add them to add-list
208 * if anyone is left on the in-memory copy, put them on the delete-list
209 * lastly, reset memberlist so we can use it again later
212 status = mr_query("get_members_of_list", 1, &listname,
213 get_list_members, (char *)memberlist);
215 com_err(whoami, status, "getting members of list %s", listname);
216 while (sq_get_data(synclist, &memberstruct)) {
217 struct save_queue *q;
220 for (q = memberlist->q_next; q != memberlist; q = q->q_next) {
221 if (membercmp(q->q_data, memberstruct) == 0) {
222 q->q_prev->q_next = q->q_next;
223 q->q_next->q_prev = q->q_prev;
229 sq_save_data(addlist, memberstruct);
231 while (sq_get_data(memberlist, &memberstruct))
232 sq_save_data(dellist, memberstruct);
233 sq_destroy(memberlist);
234 memberlist = sq_create();
237 /* Process the add list */
238 while (sq_get_data(addlist, &memberstruct)) {
239 /* canonicalize string if necessary */
240 if (memberstruct->type == M_STRING &&
241 (p = index(memberstruct->name, '@'))) {
242 char *host = canonicalize_hostname(strsave(++p));
243 static char **mailhubs = NULL;
251 mailhubs = (char **)malloc(sizeof(char *));
253 status = mr_query("get_alias", 3, argv, collect, &mailhubs);
254 if (status != MR_SUCCESS && status != MR_NO_MATCH) {
255 com_err(whoami, status,
256 " while reading list of MAILHUB servers");
260 for (i = 0; p = mailhubs[i]; i++) {
261 if (!strcasecmp(p, host)) {
262 host = strsave(memberstruct->name);
263 *(index(memberstruct->name, '@')) = 0;
264 memberstruct->type = M_ANY;
265 fprintf(stderr, "Warning: \"STRING:%s\" converted to \"%s\" because it is a local name.\n",
266 host, memberstruct->name);
272 /* now continue adding member */
273 membervec[0] = listname;
274 membervec[2] = memberstruct->name;
276 printf("Adding member ");
277 show_list_member(memberstruct);
279 switch (memberstruct->type) {
282 membervec[1] = "USER";
283 status = mr_query("add_member_to_list", 3, membervec, scream, NULL);
284 if (status == MR_SUCCESS)
286 else if (status != MR_USER || memberstruct->type != M_ANY) {
287 com_err(whoami, status, "while adding member %s to %s",
288 memberstruct->name, listname);
292 membervec[1] = "LIST";
293 status = mr_query("add_member_to_list", 3, membervec,
295 if (status == MR_SUCCESS)
297 else if (status != MR_LIST || memberstruct->type != M_ANY) {
298 com_err(whoami, status, "while adding member %s to %s",
299 memberstruct->name, listname);
303 membervec[1] = "STRING";
304 status = mr_query("add_member_to_list", 3, membervec,
306 if (status != MR_SUCCESS)
307 com_err(whoami, status, "while adding member %s to %s",
308 memberstruct->name, listname);
311 membervec[1] = "KERBEROS";
312 status = mr_query("add_member_to_list", 3, membervec,
314 if (status != MR_SUCCESS)
315 com_err(whoami, status, "while adding member %s to %s",
316 memberstruct->name, listname);
320 /* Process the delete list */
321 while (sq_get_data(dellist, &memberstruct)) {
322 membervec[0] = listname;
323 membervec[2] = memberstruct->name;
325 printf("Deleting member ");
326 show_list_member(memberstruct);
328 switch (memberstruct->type) {
331 membervec[1] = "USER";
332 status = mr_query("delete_member_from_list", 3, membervec,
334 if (status == MR_SUCCESS)
336 else if ((status != MR_USER && status != MR_NO_MATCH) ||
337 memberstruct->type != M_ANY) {
338 com_err(whoami, status, "while deleting member %s from %s",
339 memberstruct->name, listname);
343 membervec[1] = "LIST";
344 status = mr_query("delete_member_from_list", 3, membervec,
346 if (status == MR_SUCCESS)
348 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
349 memberstruct->type != M_ANY) {
350 com_err(whoami, status, "while deleting member %s from %s",
351 memberstruct->name, listname);
355 membervec[1] = "STRING";
356 status = mr_query("delete_member_from_list", 3, membervec,
358 if (status == MR_STRING && memberstruct->type == M_ANY)
359 com_err(whoami, 0, " Unable to find member %s to delete from %s",
360 memberstruct->name, listname);
361 else if (status != MR_SUCCESS)
362 com_err(whoami, status, "while deleting member %s from %s",
363 memberstruct->name, listname);
366 membervec[1] = "KERBEROS";
367 status = mr_query("delete_member_from_list", 3, membervec,
369 if (status != MR_SUCCESS)
370 com_err(whoami, status, "while deleting member %s from %s",
371 memberstruct->name, listname);
375 /* Display the members of the list now, if requested */
378 recursive_display_list_members();
380 status = mr_query("get_members_of_list", 1, &listname,
381 get_list_members, (char *)memberlist);
383 com_err(whoami, status, "while getting members of list %s",
385 while (sq_get_data(memberlist, &memberstruct))
386 show_list_member(memberstruct);
398 fprintf(stderr, "Usage: %s listname [options]\n",argv[0]);
399 fprintf(stderr, "Options are\n");
400 fprintf(stderr, " -v | -verbose\n");
401 fprintf(stderr, " -m | -members\n");
402 fprintf(stderr, " -u | -users\n");
403 fprintf(stderr, " -l | -lists\n");
404 fprintf(stderr, " -s | -strings\n");
405 fprintf(stderr, " -k | -kerberos\n");
406 fprintf(stderr, " -i | -info\n");
407 fprintf(stderr, " -r | -recursive\n");
408 fprintf(stderr, " -a | -add member\n");
409 fprintf(stderr, " -d | -delete member\n");
410 fprintf(stderr, " -al | -addlist filename\n");
411 fprintf(stderr, " -dl | -deletelist filename\n");
412 fprintf(stderr, " -f | -file filename\n");
413 fprintf(stderr, " -n | -noauth\n");
414 fprintf(stderr, " -S | -server host[:port]\n");
415 fprintf(stderr, " -D | -debug\n");
420 /* Display the members stored in the queue */
422 show_list_member(memberstruct)
423 struct member *memberstruct;
427 switch (memberstruct->type) {
449 printf("%s\n", memberstruct->name);
454 printf("%s:%s\n", s, memberstruct->name);
456 if (memberstruct->type == M_LIST)
457 printf("LIST:%s\n", memberstruct->name);
458 else if (memberstruct->type == M_KERBEROS)
459 printf("KERBEROS:%s\n", memberstruct->name);
460 else if (memberstruct->type == M_STRING &&
461 !index(memberstruct->name, '@'))
462 printf("STRING:%s\n", memberstruct->name);
464 printf("%s\n", memberstruct->name);
469 /* Show the retrieved information about a list */
471 show_list_info(argc, argv, hint)
476 printf("List: %s\n", argv[0]);
477 printf("Description: %s\n", argv[9]);
478 printf("Flags: %s, %s, and %s\n",
479 atoi(argv[1]) ? "active" : "inactive",
480 atoi(argv[2]) ? "public" : "private",
481 atoi(argv[3]) ? "hidden" : "visible");
482 printf("%s is %sa maillist and is %sa group", argv[0],
483 atoi(argv[4]) ? "" : "not ",
484 atoi(argv[5]) ? "" : "not ");
486 printf(" with GID %d\n", atoi(argv[6]));
489 printf("Owner: %s %s\n", argv[7], argv[8]);
490 printf("Last modified by %s with %s on %s\n", argv[11], argv[12], argv[10]);
495 /* Show the retrieve list member count */
497 show_list_count(argc, argv, hint)
502 printf("Members: %s\n", argv[0]);
506 /* Recursively find all of the members of listname, and then display them */
508 recursive_display_list_members()
510 int status, count, savecount;
511 struct save_queue *lists, *members;
512 struct member *m, *m1, *data;
515 members = sq_create();
516 m = (struct member *) malloc(sizeof(struct member));
519 sq_save_data(lists, m);
521 while (sq_get_data(lists, &m)) {
522 sq_destroy(memberlist);
523 memberlist = sq_create();
525 fprintf(stderr, "Fetching members of %s\n", m->name);
526 status = mr_query("get_members_of_list", 1, &(m->name),
527 get_list_members, (char *)memberlist);
529 com_err(whoami, status, "while getting members of list %s", m->name);
530 while (sq_get_data(memberlist, &m1)) {
531 if (m1->type == M_LIST)
532 unique_add_member(lists, m1);
534 unique_add_member(members, m1);
537 savecount = count = sq_count_elts(members);
538 data = (struct member *) malloc(count * sizeof(struct member));
540 while (sq_get_data(members, &m))
541 bcopy(m, &data[count++], sizeof(struct member));
542 qsort(data, count, sizeof(struct member), membercmp);
543 for (count = 0; count < savecount; count++) {
544 show_list_member(&data[count]);
549 /* add a struct member to a queue if that member isn't already there. */
551 unique_add_member(q, m)
552 struct save_queue *q;
555 struct save_queue *qp;
557 for (qp = q->q_next; qp != q; qp = qp->q_next) {
558 if (!membercmp(qp->q_data, m))
565 /* Collect the retrieved members of the list */
567 get_list_members(argc, argv, q)
570 struct save_queue *q;
574 m = (struct member *) malloc(sizeof(struct member));
575 switch (argv[0][0]) {
586 m->type = M_KERBEROS;
589 m->name = strsave(argv[1]);
595 /* Called only if a query returns a value that we weren't expecting */
599 fprintf(stderr, "Programmer botch\n");
604 /* Open file, parse members from file, and put them on the specified queue */
605 get_members_from_file(filename, queue)
607 struct save_queue *queue;
611 struct member *memberstruct;
613 if (!strcmp(filename, "-"))
616 in = fopen(filename, "r");
618 com_err(whoami, errno, "while opening %s for input", filename);
623 while (fgets(buf, BUFSIZ, in))
624 if (memberstruct = parse_member(buf))
625 sq_save_data(queue, memberstruct);
627 com_err(whoami, errno, "while reading from %s", filename);
631 /* Collect the possible expansions of the alias MAILHUB */
633 int collect(argc, argv, list)
640 for (i = 0; (*list)[i]; i++);
641 *list = (char **)realloc(*list, (i + 2) * sizeof(char *));
642 (*list)[i] = strsave(argv[2]);
648 /* Parse a line of input, fetching a member. NULL is returned if a member
649 * is not found. ';' is a comment character.
652 struct member *parse_member(s)
655 register struct member *m;
658 while (*s && isspace(*s))
661 while (*p && *p != '\n' && *p != ';')
662 if (isprint(*p) && !isspace(*p))
668 if (p == s || strlen(s) == 0)
671 if ((m = (struct member *) malloc(sizeof(struct member))) == NULL)
674 if (p = index(s, ':')) {
677 if (!strcasecmp("user", s))
679 else if (!strcasecmp("list", s))
681 else if (!strcasecmp("string", s))
683 else if (!strcasecmp("kerberos", s))
684 m->type = M_KERBEROS;
690 m->name = strsave(m->name);
692 m->name = strsave(s);
693 if (index(s, '@') || index(s, '!') || index(s, '%') || index(s, ' '))
703 * This routine two compares members by the following rules:
704 * 1. A USER is less than a LIST
705 * 2. A LIST is less than a STRING
706 * 3. If two members are of the same type, the one alphabetically first
707 * is less than the other
708 * It returs < 0 if the first member is less, 0 if they are identical, and
709 * > 0 if the second member is less (the first member is greater).
712 int membercmp(m1, m2)
713 struct member *m1, *m2;
715 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
716 return(strcmp(m1->name, m2->name));
718 return(m1->type - m2->type);
723 struct save_queue *q;
729 while (sq_get_data(q, &foo))