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>
22 #include <moira_site.h>
25 static char blanche_rcsid[] = "$Header$";
34 /* It is important to membercmp that M_USER < M_LIST < M_STRING */
41 /* argument parsing macro */
42 #define argis(a,b) ((strcmp(*arg+1, a) == 0) || (strcmp(*arg+1, b) == 0))
44 /* flags from command line */
45 int infoflg, verbose, syncflg, memberflg, recursflg, debugflg, noauth;
46 int showusers, showstrings, showkerberos, showlists;
48 /* various member lists */
49 struct save_queue *addlist, *dellist, *memberlist, *synclist;
51 char *listname, *whoami;
58 int show_list_info(), show_list_count(), get_list_members(), scream();
59 int show_list_members(), membercmp();
60 struct member *parse_member();
70 char *membervec[3], *motd;
71 struct member *memberstruct;
72 char *server = NULL, *p;
74 /* clear all flags & lists */
75 infoflg = verbose = syncflg = memberflg = debugflg = recursflg = 0;
76 noauth = showusers = showstrings = showkerberos = showlists = 0;
78 addlist = sq_create();
79 dellist = sq_create();
80 memberlist = sq_create();
81 synclist = sq_create();
84 /* parse args, building addlist, dellist, & synclist */
85 while (++arg - argv < argc) {
88 if (argis("m", "members"))
90 else if (argis("u", "users"))
92 else if (argis("s", "strings"))
94 else if (argis("l", "lists"))
96 else if (argis("k", "kerberos"))
98 else if (argis("D", "debug"))
100 else if (argis("i","info"))
102 else if (argis("n","noauth"))
104 else if (argis("v","verbose"))
106 else if (argis("r","recursive"))
108 else if (argis("S","server"))
109 if (arg - argv < argc - 1) {
114 else if (argis("a","add"))
115 if (arg - argv < argc - 1) {
117 if (memberstruct = parse_member(*arg))
118 sq_save_data(addlist, memberstruct);
121 else if (argis("al","addlist"))
122 if (arg - argv < argc - 1) {
124 get_members_from_file(*arg, addlist);
127 else if (argis("d","delete"))
128 if (arg - argv < argc - 1) {
130 if (memberstruct = parse_member(*arg))
131 sq_save_data(dellist, memberstruct);
134 else if (argis("dl","deletelist"))
135 if (arg - argv < argc - 1) {
137 get_members_from_file(*arg, dellist);
140 else if (argis("f","file"))
141 if (arg - argv < argc - 1) {
144 get_members_from_file(*arg, synclist);
150 else if (listname == NULL)
155 if (listname == NULL)
158 /* if no other options specified, turn on list members flag */
159 if (!(infoflg || syncflg ||
160 addlist->q_next != addlist || dellist->q_next != dellist))
163 /* If none of {users,strings,lists,kerberos} specified, turn them all on */
164 if (!(showusers || showstrings || showlists || showkerberos))
165 showusers = showstrings = showlists = showkerberos = 1;
168 if (status = mr_connect(server)) {
169 com_err(whoami, status, "unable to connect to the Moira server");
172 if ( status = mr_motd(&motd) ) {
173 com_err(whoami, status, "unable to check server status");
177 fprintf(stderr, "The Moira server is currently unavailable:\n%s\n", motd);
182 if (!noauth && (status = mr_auth("blanche"))) {
183 if (status == MR_USER_AUTH)
184 com_err(whoami, status, "");
186 com_err(whoami, status, "unable to authenticate to Moira");
188 " Try the -noauth flag if you don't need authentication");
193 /* display list info if requested to */
195 status = mr_query("get_list_info", 1, &listname, show_list_info,NULL);
197 com_err(whoami, status, "while getting list information");
198 if (verbose && !memberflg) {
199 status = mr_query("count_members_of_list", 1, &listname,
200 show_list_count, NULL);
202 com_err(whoami, status, "while getting list count");
206 /* if we're synchronizing to a file, we need to:
207 * get the current members of the list
208 * for each member of the sync file
209 * if they are on the list, remove them from the in-memory copy
210 * if they're not on the list, add them to add-list
211 * if anyone is left on the in-memory copy, put them on the delete-list
212 * lastly, reset memberlist so we can use it again later
215 status = mr_query("get_members_of_list", 1, &listname,
216 get_list_members, (char *)memberlist);
218 com_err(whoami, status, "getting members of list %s", listname);
219 while (sq_get_data(synclist, &memberstruct)) {
220 struct save_queue *q;
223 for (q = memberlist->q_next; q != memberlist; q = q->q_next) {
224 if (membercmp(q->q_data, memberstruct) == 0) {
225 q->q_prev->q_next = q->q_next;
226 q->q_next->q_prev = q->q_prev;
232 sq_save_data(addlist, memberstruct);
234 while (sq_get_data(memberlist, &memberstruct))
235 sq_save_data(dellist, memberstruct);
236 sq_destroy(memberlist);
237 memberlist = sq_create();
240 /* Process the add list */
241 while (sq_get_data(addlist, &memberstruct)) {
242 /* canonicalize string if necessary */
243 if (memberstruct->type == M_STRING &&
244 (p = strchr(memberstruct->name, '@'))) {
245 char *host = canonicalize_hostname(strsave(++p));
246 static char **mailhubs = NULL;
254 mailhubs = (char **)malloc(sizeof(char *));
256 status = mr_query("get_alias", 3, argv, collect,
258 if (status != MR_SUCCESS && status != MR_NO_MATCH) {
259 com_err(whoami, status,
260 " while reading list of MAILHUB servers");
264 for (i = 0; p = mailhubs[i]; i++) {
265 if (!strcasecmp(p, host)) {
266 host = strsave(memberstruct->name);
267 *(strchr(memberstruct->name, '@')) = 0;
268 memberstruct->type = M_ANY;
269 fprintf(stderr, "Warning: \"STRING:%s\" converted to \"%s\" because it is a local name.\n",
270 host, memberstruct->name);
276 /* now continue adding member */
277 membervec[0] = listname;
278 membervec[2] = memberstruct->name;
280 printf("Adding member ");
281 show_list_member(memberstruct);
283 switch (memberstruct->type) {
286 membervec[1] = "USER";
287 status = mr_query("add_member_to_list", 3, membervec, scream, NULL);
288 if (status == MR_SUCCESS)
290 else if (status != MR_USER || memberstruct->type != M_ANY) {
291 com_err(whoami, status, "while adding member %s to %s",
292 memberstruct->name, listname);
296 membervec[1] = "LIST";
297 status = mr_query("add_member_to_list", 3, membervec,
299 if (status == MR_SUCCESS)
301 else if (status != MR_LIST || memberstruct->type != M_ANY) {
302 com_err(whoami, status, "while adding member %s to %s",
303 memberstruct->name, listname);
307 membervec[1] = "STRING";
308 status = mr_query("add_member_to_list", 3, membervec,
310 if (status != MR_SUCCESS)
311 com_err(whoami, status, "while adding member %s to %s",
312 memberstruct->name, listname);
315 membervec[1] = "KERBEROS";
316 status = mr_query("add_member_to_list", 3, membervec,
318 if (status != MR_SUCCESS)
319 com_err(whoami, status, "while adding member %s to %s",
320 memberstruct->name, listname);
324 /* Process the delete list */
325 while (sq_get_data(dellist, &memberstruct)) {
326 membervec[0] = listname;
327 membervec[2] = memberstruct->name;
329 printf("Deleting member ");
330 show_list_member(memberstruct);
332 switch (memberstruct->type) {
335 membervec[1] = "USER";
336 status = mr_query("delete_member_from_list", 3, membervec,
338 if (status == MR_SUCCESS)
340 else if ((status != MR_USER && status != MR_NO_MATCH) ||
341 memberstruct->type != M_ANY) {
342 com_err(whoami, status, "while deleting member %s from %s",
343 memberstruct->name, listname);
347 membervec[1] = "LIST";
348 status = mr_query("delete_member_from_list", 3, membervec,
350 if (status == MR_SUCCESS)
352 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
353 memberstruct->type != M_ANY) {
354 com_err(whoami, status, "while deleting member %s from %s",
355 memberstruct->name, listname);
359 membervec[1] = "STRING";
360 status = mr_query("delete_member_from_list", 3, membervec,
362 if (status == MR_STRING && memberstruct->type == M_ANY)
363 com_err(whoami, 0, " Unable to find member %s to delete from %s",
364 memberstruct->name, listname);
365 else if (status != MR_SUCCESS)
366 com_err(whoami, status, "while deleting member %s from %s",
367 memberstruct->name, listname);
370 membervec[1] = "KERBEROS";
371 status = mr_query("delete_member_from_list", 3, membervec,
373 if (status != MR_SUCCESS)
374 com_err(whoami, status, "while deleting member %s from %s",
375 memberstruct->name, listname);
379 /* Display the members of the list now, if requested */
382 recursive_display_list_members();
384 status = mr_query("get_members_of_list", 1, &listname,
385 get_list_members, (char *)memberlist);
387 com_err(whoami, status, "while getting members of list %s",
389 while (sq_get_data(memberlist, &memberstruct))
390 show_list_member(memberstruct);
402 fprintf(stderr, "Usage: %s listname [options]\n",argv[0]);
403 fprintf(stderr, "Options are\n");
404 fprintf(stderr, " -v | -verbose\n");
405 fprintf(stderr, " -m | -members\n");
406 fprintf(stderr, " -u | -users\n");
407 fprintf(stderr, " -l | -lists\n");
408 fprintf(stderr, " -s | -strings\n");
409 fprintf(stderr, " -k | -kerberos\n");
410 fprintf(stderr, " -i | -info\n");
411 fprintf(stderr, " -r | -recursive\n");
412 fprintf(stderr, " -a | -add member\n");
413 fprintf(stderr, " -d | -delete member\n");
414 fprintf(stderr, " -al | -addlist filename\n");
415 fprintf(stderr, " -dl | -deletelist filename\n");
416 fprintf(stderr, " -f | -file filename\n");
417 fprintf(stderr, " -n | -noauth\n");
418 fprintf(stderr, " -S | -server host[:port]\n");
419 fprintf(stderr, " -D | -debug\n");
424 /* Display the members stored in the queue */
426 show_list_member(memberstruct)
427 struct member *memberstruct;
431 switch (memberstruct->type) {
453 printf("%s\n", memberstruct->name);
458 printf("%s:%s\n", s, memberstruct->name);
460 if (memberstruct->type == M_LIST)
461 printf("LIST:%s\n", memberstruct->name);
462 else if (memberstruct->type == M_KERBEROS)
463 printf("KERBEROS:%s\n", memberstruct->name);
464 else if (memberstruct->type == M_STRING &&
465 !strchr(memberstruct->name, '@'))
466 printf("STRING:%s\n", memberstruct->name);
468 printf("%s\n", memberstruct->name);
473 /* Show the retrieved information about a list */
475 show_list_info(argc, argv, hint)
480 printf("List: %s\n", argv[0]);
481 printf("Description: %s\n", argv[9]);
482 printf("Flags: %s, %s, and %s\n",
483 atoi(argv[1]) ? "active" : "inactive",
484 atoi(argv[2]) ? "public" : "private",
485 atoi(argv[3]) ? "hidden" : "visible");
486 printf("%s is %sa maillist and is %sa group", argv[0],
487 atoi(argv[4]) ? "" : "not ",
488 atoi(argv[5]) ? "" : "not ");
490 printf(" with GID %d\n", atoi(argv[6]));
493 printf("Owner: %s %s\n", argv[7], argv[8]);
494 printf("Last modified by %s with %s on %s\n", argv[11], argv[12], argv[10]);
499 /* Show the retrieve list member count */
501 show_list_count(argc, argv, hint)
506 printf("Members: %s\n", argv[0]);
510 /* Recursively find all of the members of listname, and then display them */
512 recursive_display_list_members()
514 int status, count, savecount;
515 struct save_queue *lists, *members;
516 struct member *m, *m1, *data;
519 members = sq_create();
520 m = (struct member *) malloc(sizeof(struct member));
523 sq_save_data(lists, m);
525 while (sq_get_data(lists, &m)) {
526 sq_destroy(memberlist);
527 memberlist = sq_create();
529 fprintf(stderr, "Fetching members of %s\n", m->name);
530 status = mr_query("get_members_of_list", 1, &(m->name),
531 get_list_members, (char *)memberlist);
533 com_err(whoami, status, "while getting members of list %s", m->name);
534 while (sq_get_data(memberlist, &m1)) {
535 if (m1->type == M_LIST)
536 unique_add_member(lists, m1);
538 unique_add_member(members, m1);
541 savecount = count = sq_count_elts(members);
542 data = (struct member *) malloc(count * sizeof(struct member));
544 while (sq_get_data(members, &m))
545 memcpy(&data[count++], m, sizeof(struct member));
546 qsort(data, count, sizeof(struct member), membercmp);
547 for (count = 0; count < savecount; count++) {
548 show_list_member(&data[count]);
553 /* add a struct member to a queue if that member isn't already there. */
555 unique_add_member(q, m)
556 struct save_queue *q;
559 struct save_queue *qp;
561 for (qp = q->q_next; qp != q; qp = qp->q_next) {
562 if (!membercmp(qp->q_data, m))
569 /* Collect the retrieved members of the list */
571 get_list_members(argc, argv, q)
574 struct save_queue *q;
578 m = (struct member *) malloc(sizeof(struct member));
579 switch (argv[0][0]) {
590 m->type = M_KERBEROS;
593 m->name = strsave(argv[1]);
599 /* Called only if a query returns a value that we weren't expecting */
603 fprintf(stderr, "Programmer botch\n");
608 /* Open file, parse members from file, and put them on the specified queue */
609 get_members_from_file(filename, queue)
611 struct save_queue *queue;
615 struct member *memberstruct;
617 if (!strcmp(filename, "-"))
620 in = fopen(filename, "r");
622 com_err(whoami, errno, "while opening %s for input", filename);
627 while (fgets(buf, BUFSIZ, in))
628 if (memberstruct = parse_member(buf))
629 sq_save_data(queue, memberstruct);
631 com_err(whoami, errno, "while reading from %s", filename);
635 /* Collect the possible expansions of the alias MAILHUB */
637 int collect(argc, argv, list)
644 for (i = 0; (*list)[i]; i++);
645 *list = (char **)realloc(*list, (i + 2) * sizeof(char *));
646 (*list)[i] = strsave(argv[2]);
652 /* Parse a line of input, fetching a member. NULL is returned if a member
653 * is not found. ';' is a comment character.
656 struct member *parse_member(s)
659 register struct member *m;
662 while (*s && isspace(*s))
665 while (*p && *p != '\n' && *p != ';')
666 if (isprint(*p) && !isspace(*p))
672 if (p == s || strlen(s) == 0)
675 if ((m = (struct member *) malloc(sizeof(struct member))) == NULL)
678 if (p = strchr(s, ':')) {
681 if (!strcasecmp("user", s))
683 else if (!strcasecmp("list", s))
685 else if (!strcasecmp("string", s))
687 else if (!strcasecmp("kerberos", s))
688 m->type = M_KERBEROS;
694 m->name = strsave(m->name);
696 m->name = strsave(s);
697 if (strchr(s, '@') || strchr(s, '!') || strchr(s, '%') || strchr(s, ' '))
707 * This routine two compares members by the following rules:
708 * 1. A USER is less than a LIST
709 * 2. A LIST is less than a STRING
710 * 3. If two members are of the same type, the one alphabetically first
711 * is less than the other
712 * It returs < 0 if the first member is less, 0 if they are identical, and
713 * > 0 if the second member is less (the first member is greater).
716 int membercmp(m1, m2)
717 struct member *m1, *m2;
719 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
720 return(strcmp(m1->name, m2->name));
722 return(m1->type - m2->type);
727 struct save_queue *q;
733 while (sq_get_data(q, &foo))