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>
23 #include <moira_site.h>
26 static char blanche_rcsid[] = "$Header$";
35 /* It is important to membercmp that M_USER < M_LIST < M_STRING */
42 /* argument parsing macro */
43 #define argis(a,b) ((strcmp(*arg+1, a) == 0) || (strcmp(*arg+1, b) == 0))
45 /* flags from command line */
46 int infoflg, verbose, syncflg, memberflg, recursflg, debugflg, noauth;
47 int showusers, showstrings, showkerberos, showlists;
49 /* various member lists */
50 struct save_queue *addlist, *dellist, *memberlist, *synclist;
52 char *listname, *whoami;
59 int show_list_info(), show_list_count(), get_list_members(), scream();
60 int show_list_members(), membercmp();
61 struct member *parse_member();
71 char *membervec[3], *motd;
72 struct member *memberstruct;
73 char *server = NULL, *p;
75 /* clear all flags & lists */
76 infoflg = verbose = syncflg = memberflg = debugflg = recursflg = 0;
77 noauth = showusers = showstrings = showkerberos = showlists = 0;
79 addlist = sq_create();
80 dellist = sq_create();
81 memberlist = sq_create();
82 synclist = sq_create();
85 /* parse args, building addlist, dellist, & synclist */
86 while (++arg - argv < argc) {
89 if (argis("m", "members"))
91 else if (argis("u", "users"))
93 else if (argis("s", "strings"))
95 else if (argis("l", "lists"))
97 else if (argis("k", "kerberos"))
99 else if (argis("D", "debug"))
101 else if (argis("i","info"))
103 else if (argis("n","noauth"))
105 else if (argis("v","verbose"))
107 else if (argis("r","recursive"))
109 else if (argis("S","server"))
110 if (arg - argv < argc - 1) {
115 else if (argis("a","add"))
116 if (arg - argv < argc - 1) {
118 if (memberstruct = parse_member(*arg))
119 sq_save_data(addlist, memberstruct);
122 else if (argis("al","addlist"))
123 if (arg - argv < argc - 1) {
125 get_members_from_file(*arg, addlist);
128 else if (argis("d","delete"))
129 if (arg - argv < argc - 1) {
131 if (memberstruct = parse_member(*arg))
132 sq_save_data(dellist, memberstruct);
135 else if (argis("dl","deletelist"))
136 if (arg - argv < argc - 1) {
138 get_members_from_file(*arg, dellist);
141 else if (argis("f","file"))
142 if (arg - argv < argc - 1) {
145 get_members_from_file(*arg, synclist);
151 else if (listname == NULL)
156 if (listname == NULL)
159 /* if no other options specified, turn on list members flag */
160 if (!(infoflg || syncflg ||
161 addlist->q_next != addlist || dellist->q_next != dellist))
164 /* If none of {users,strings,lists,kerberos} specified, turn them all on */
165 if (!(showusers || showstrings || showlists || showkerberos))
166 showusers = showstrings = showlists = showkerberos = 1;
169 if (status = mr_connect(server)) {
170 com_err(whoami, status, "unable to connect to the Moira server");
173 if ( status = mr_motd(&motd) ) {
174 com_err(whoami, status, "unable to check server status");
178 fprintf(stderr, "The Moira server is currently unavailable:\n%s\n", motd);
183 if (!noauth && (status = mr_auth("blanche"))) {
184 if (status == MR_USER_AUTH)
185 com_err(whoami, status, "");
187 com_err(whoami, status, "unable to authenticate to Moira");
189 " Try the -noauth flag if you don't need authentication");
194 /* display list info if requested to */
196 status = mr_query("get_list_info", 1, &listname, show_list_info,NULL);
198 com_err(whoami, status, "while getting list information");
199 if (verbose && !memberflg) {
200 status = mr_query("count_members_of_list", 1, &listname,
201 show_list_count, NULL);
203 com_err(whoami, status, "while getting list count");
207 /* if we're synchronizing to a file, we need to:
208 * get the current members of the list
209 * for each member of the sync file
210 * if they are on the list, remove them from the in-memory copy
211 * if they're not on the list, add them to add-list
212 * if anyone is left on the in-memory copy, put them on the delete-list
213 * lastly, reset memberlist so we can use it again later
216 status = mr_query("get_members_of_list", 1, &listname,
217 get_list_members, (char *)memberlist);
219 com_err(whoami, status, "getting members of list %s", listname);
220 while (sq_get_data(synclist, &memberstruct)) {
221 struct save_queue *q;
224 for (q = memberlist->q_next; q != memberlist; q = q->q_next) {
225 if (membercmp(q->q_data, memberstruct) == 0) {
226 q->q_prev->q_next = q->q_next;
227 q->q_next->q_prev = q->q_prev;
233 sq_save_data(addlist, memberstruct);
235 while (sq_get_data(memberlist, &memberstruct))
236 sq_save_data(dellist, memberstruct);
237 sq_destroy(memberlist);
238 memberlist = sq_create();
241 /* Process the add list */
242 while (sq_get_data(addlist, &memberstruct)) {
243 /* canonicalize string if necessary */
244 if (memberstruct->type == M_STRING &&
245 (p = strchr(memberstruct->name, '@'))) {
246 char *host = canonicalize_hostname(strsave(++p));
247 static char **mailhubs = NULL;
255 mailhubs = (char **)malloc(sizeof(char *));
257 status = mr_query("get_alias", 3, argv, collect,
259 if (status != MR_SUCCESS && status != MR_NO_MATCH) {
260 com_err(whoami, status,
261 " while reading list of MAILHUB servers");
265 for (i = 0; p = mailhubs[i]; i++) {
266 if (!strcasecmp(p, host)) {
267 host = strsave(memberstruct->name);
268 *(strchr(memberstruct->name, '@')) = 0;
269 memberstruct->type = M_ANY;
270 fprintf(stderr, "Warning: \"STRING:%s\" converted to \"%s\" because it is a local name.\n",
271 host, memberstruct->name);
277 /* now continue adding member */
278 membervec[0] = listname;
279 membervec[2] = memberstruct->name;
281 printf("Adding member ");
282 show_list_member(memberstruct);
284 switch (memberstruct->type) {
287 membervec[1] = "USER";
288 status = mr_query("add_member_to_list", 3, membervec, scream, NULL);
289 if (status == MR_SUCCESS)
291 else if (status != MR_USER || memberstruct->type != M_ANY) {
292 com_err(whoami, status, "while adding member %s to %s",
293 memberstruct->name, listname);
297 membervec[1] = "LIST";
298 status = mr_query("add_member_to_list", 3, membervec,
300 if (status == MR_SUCCESS)
302 else if (status != MR_LIST || memberstruct->type != M_ANY) {
303 com_err(whoami, status, "while adding member %s to %s",
304 memberstruct->name, listname);
308 membervec[1] = "STRING";
309 status = mr_query("add_member_to_list", 3, membervec,
311 if (status != MR_SUCCESS)
312 com_err(whoami, status, "while adding member %s to %s",
313 memberstruct->name, listname);
316 membervec[1] = "KERBEROS";
317 status = mr_query("add_member_to_list", 3, membervec,
319 if (status != MR_SUCCESS)
320 com_err(whoami, status, "while adding member %s to %s",
321 memberstruct->name, listname);
325 /* Process the delete list */
326 while (sq_get_data(dellist, &memberstruct)) {
327 membervec[0] = listname;
328 membervec[2] = memberstruct->name;
330 printf("Deleting member ");
331 show_list_member(memberstruct);
333 switch (memberstruct->type) {
336 membervec[1] = "USER";
337 status = mr_query("delete_member_from_list", 3, membervec,
339 if (status == MR_SUCCESS)
341 else if ((status != MR_USER && status != MR_NO_MATCH) ||
342 memberstruct->type != M_ANY) {
343 com_err(whoami, status, "while deleting member %s from %s",
344 memberstruct->name, listname);
348 membervec[1] = "LIST";
349 status = mr_query("delete_member_from_list", 3, membervec,
351 if (status == MR_SUCCESS)
353 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
354 memberstruct->type != M_ANY) {
355 com_err(whoami, status, "while deleting member %s from %s",
356 memberstruct->name, listname);
360 membervec[1] = "STRING";
361 status = mr_query("delete_member_from_list", 3, membervec,
363 if (status == MR_STRING && memberstruct->type == M_ANY)
364 com_err(whoami, 0, " Unable to find member %s to delete from %s",
365 memberstruct->name, listname);
366 else if (status != MR_SUCCESS)
367 com_err(whoami, status, "while deleting member %s from %s",
368 memberstruct->name, listname);
371 membervec[1] = "KERBEROS";
372 status = mr_query("delete_member_from_list", 3, membervec,
374 if (status != MR_SUCCESS)
375 com_err(whoami, status, "while deleting member %s from %s",
376 memberstruct->name, listname);
380 /* Display the members of the list now, if requested */
383 recursive_display_list_members();
385 status = mr_query("get_members_of_list", 1, &listname,
386 get_list_members, (char *)memberlist);
388 com_err(whoami, status, "while getting members of list %s",
390 while (sq_get_data(memberlist, &memberstruct))
391 show_list_member(memberstruct);
403 fprintf(stderr, "Usage: %s listname [options]\n",argv[0]);
404 fprintf(stderr, "Options are\n");
405 fprintf(stderr, " -v | -verbose\n");
406 fprintf(stderr, " -m | -members\n");
407 fprintf(stderr, " -u | -users\n");
408 fprintf(stderr, " -l | -lists\n");
409 fprintf(stderr, " -s | -strings\n");
410 fprintf(stderr, " -k | -kerberos\n");
411 fprintf(stderr, " -i | -info\n");
412 fprintf(stderr, " -r | -recursive\n");
413 fprintf(stderr, " -a | -add member\n");
414 fprintf(stderr, " -d | -delete member\n");
415 fprintf(stderr, " -al | -addlist filename\n");
416 fprintf(stderr, " -dl | -deletelist filename\n");
417 fprintf(stderr, " -f | -file filename\n");
418 fprintf(stderr, " -n | -noauth\n");
419 fprintf(stderr, " -S | -server host[:port]\n");
420 fprintf(stderr, " -D | -debug\n");
425 /* Display the members stored in the queue */
427 show_list_member(memberstruct)
428 struct member *memberstruct;
432 switch (memberstruct->type) {
454 printf("%s\n", memberstruct->name);
459 printf("%s:%s\n", s, memberstruct->name);
461 if (memberstruct->type == M_LIST)
462 printf("LIST:%s\n", memberstruct->name);
463 else if (memberstruct->type == M_KERBEROS)
464 printf("KERBEROS:%s\n", memberstruct->name);
465 else if (memberstruct->type == M_STRING &&
466 !strchr(memberstruct->name, '@'))
467 printf("STRING:%s\n", memberstruct->name);
469 printf("%s\n", memberstruct->name);
474 /* Show the retrieved information about a list */
476 show_list_info(argc, argv, hint)
481 printf("List: %s\n", argv[0]);
482 printf("Description: %s\n", argv[9]);
483 printf("Flags: %s, %s, and %s\n",
484 atoi(argv[1]) ? "active" : "inactive",
485 atoi(argv[2]) ? "public" : "private",
486 atoi(argv[3]) ? "hidden" : "visible");
487 printf("%s is %sa maillist and is %sa group", argv[0],
488 atoi(argv[4]) ? "" : "not ",
489 atoi(argv[5]) ? "" : "not ");
491 printf(" with GID %d\n", atoi(argv[6]));
494 printf("Owner: %s %s\n", argv[7], argv[8]);
495 printf("Last modified by %s with %s on %s\n", argv[11], argv[12], argv[10]);
500 /* Show the retrieve list member count */
502 show_list_count(argc, argv, hint)
507 printf("Members: %s\n", argv[0]);
511 /* Recursively find all of the members of listname, and then display them */
513 recursive_display_list_members()
515 int status, count, savecount;
516 struct save_queue *lists, *members;
517 struct member *m, *m1, *data;
520 members = sq_create();
521 m = (struct member *) malloc(sizeof(struct member));
524 sq_save_data(lists, m);
526 while (sq_get_data(lists, &m)) {
527 sq_destroy(memberlist);
528 memberlist = sq_create();
530 fprintf(stderr, "Fetching members of %s\n", m->name);
531 status = mr_query("get_members_of_list", 1, &(m->name),
532 get_list_members, (char *)memberlist);
534 com_err(whoami, status, "while getting members of list %s", m->name);
535 while (sq_get_data(memberlist, &m1)) {
536 if (m1->type == M_LIST)
537 unique_add_member(lists, m1);
539 unique_add_member(members, m1);
542 savecount = count = sq_count_elts(members);
543 data = (struct member *) malloc(count * sizeof(struct member));
545 while (sq_get_data(members, &m))
546 memcpy(&data[count++], m, sizeof(struct member));
547 qsort(data, count, sizeof(struct member), membercmp);
548 for (count = 0; count < savecount; count++) {
549 show_list_member(&data[count]);
554 /* add a struct member to a queue if that member isn't already there. */
556 unique_add_member(q, m)
557 struct save_queue *q;
560 struct save_queue *qp;
562 for (qp = q->q_next; qp != q; qp = qp->q_next) {
563 if (!membercmp(qp->q_data, m))
570 /* Collect the retrieved members of the list */
572 get_list_members(argc, argv, q)
575 struct save_queue *q;
579 m = (struct member *) malloc(sizeof(struct member));
580 switch (argv[0][0]) {
591 m->type = M_KERBEROS;
594 m->name = strsave(argv[1]);
600 /* Called only if a query returns a value that we weren't expecting */
604 fprintf(stderr, "Programmer botch\n");
609 /* Open file, parse members from file, and put them on the specified queue */
610 get_members_from_file(filename, queue)
612 struct save_queue *queue;
616 struct member *memberstruct;
618 if (!strcmp(filename, "-"))
621 in = fopen(filename, "r");
623 com_err(whoami, errno, "while opening %s for input", filename);
628 while (fgets(buf, BUFSIZ, in))
629 if (memberstruct = parse_member(buf))
630 sq_save_data(queue, memberstruct);
632 com_err(whoami, errno, "while reading from %s", filename);
636 /* Collect the possible expansions of the alias MAILHUB */
638 int collect(argc, argv, list)
645 for (i = 0; (*list)[i]; i++);
646 *list = (char **)realloc(*list, (i + 2) * sizeof(char *));
647 (*list)[i] = strsave(argv[2]);
653 /* Parse a line of input, fetching a member. NULL is returned if a member
654 * is not found. ';' is a comment character.
657 struct member *parse_member(s)
660 register struct member *m;
663 while (*s && isspace(*s))
666 while (*p && *p != '\n' && *p != ';')
667 if (isprint(*p) && !isspace(*p))
673 if (p == s || strlen(s) == 0)
676 if ((m = (struct member *) malloc(sizeof(struct member))) == NULL)
679 if (p = strchr(s, ':')) {
682 if (!strcasecmp("user", s))
684 else if (!strcasecmp("list", s))
686 else if (!strcasecmp("string", s))
688 else if (!strcasecmp("kerberos", s))
689 m->type = M_KERBEROS;
695 m->name = strsave(m->name);
697 m->name = strsave(s);
698 if (strchr(s, '@') || strchr(s, '!') || strchr(s, '%') || strchr(s, ' '))
708 * This routine two compares members by the following rules:
709 * 1. A USER is less than a LIST
710 * 2. A LIST is less than a STRING
711 * 3. If two members are of the same type, the one alphabetically first
712 * is less than the other
713 * It returs < 0 if the first member is less, 0 if they are identical, and
714 * > 0 if the second member is less (the first member is greater).
717 int membercmp(m1, m2)
718 struct member *m1, *m2;
720 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
721 return(strcmp(m1->name, m2->name));
723 return(m1->type - m2->type);
728 struct save_queue *q;
734 while (sq_get_data(q, &foo))