3 * Command line oriented Moira List tool.
5 * by Mark Rosenstein, September 1988.
7 * Copyright (C) 1988-1998 by the Massachusetts Institute of Technology.
8 * For copying and distribution information, please see the file
12 #include <mit-copyright.h>
14 #include <moira_site.h>
30 /* It is important to membercmp that M_USER < M_LIST < M_STRING */
39 char *typename[] = { "ANY", "USER", "LIST", "STRING", "KERBEROS", "MACHINE",
42 /* argument parsing macro */
43 #define argis(a, b) (!strcmp(*arg + 1, a) || !strcmp(*arg + 1, b))
45 /* flags from command line */
46 int infoflg, verbose, syncflg, memberflg, recursflg, noauth;
47 int showusers, showstrings, showkerberos, showlists, showtags, showmachines;
48 int createflag, setinfo, active, public, hidden, maillist, grouplist;
49 int nfsgroup, mailman;
50 struct member *owner, *memacl;
51 char *desc, *newname, *mailman_server;
53 /* various member lists */
54 struct save_queue *addlist, *dellist, *memberlist, *synclist, *taglist;
56 char *listname, *whoami;
58 void usage(char **argv);
59 void show_list_member(struct member *memberstruct);
60 int show_list_info(int argc, char **argv, void *hint);
61 int save_list_info(int argc, char **argv, void *hint);
62 int show_list_count(int argc, char **argv, void *hint);
63 void recursive_display_list_members(void);
64 void unique_add_member(struct save_queue *q, struct member *m);
65 int get_list_members(int argc, char **argv, void *sq);
66 void get_members_from_file(char *filename, struct save_queue *queue);
67 int collect(int argc, char **argv, void *l);
68 struct member *parse_member(char *s);
69 int membercmp(const void *mem1, const void *mem2);
70 int sq_count_elts(struct save_queue *q);
71 char *get_username(void);
73 int main(int argc, char **argv)
78 struct member *memberstruct;
79 char *server = NULL, *p;
81 /* clear all flags & lists */
82 infoflg = verbose = syncflg = memberflg = recursflg = 0;
83 noauth = showusers = showstrings = showkerberos = showlists = 0;
84 showtags = showmachines = createflag = setinfo = 0;
85 active = public = hidden = maillist = grouplist = nfsgroup = mailman = -1;
86 listname = newname = desc = NULL;
89 addlist = sq_create();
90 dellist = sq_create();
91 memberlist = sq_create();
92 synclist = sq_create();
93 taglist = sq_create();
98 /* parse args, building addlist, dellist, & synclist */
99 while (++arg - argv < argc)
103 if (argis("m", "members"))
105 else if (argis("u", "users"))
107 else if (argis("s", "strings"))
109 else if (argis("l", "lists"))
111 else if (argis("k", "kerberos"))
113 else if (argis("t", "tags"))
115 else if (argis("i", "info"))
117 else if (argis("n", "noauth"))
119 else if (argis("v", "verbose"))
121 else if (argis("r", "recursive"))
123 else if (argis("S", "server") || argis("db", "database"))
125 if (arg - argv < argc - 1)
133 else if (argis("a", "add"))
135 if (arg - argv < argc - 1)
138 if ((memberstruct = parse_member(*arg)))
139 sq_save_data(addlist, memberstruct);
144 else if (argis("at", "addtagged"))
146 if (arg - argv < argc - 2)
149 if ((memberstruct = parse_member(*arg)))
150 sq_save_data(addlist, memberstruct);
151 memberstruct->tag = *++arg;
156 else if (argis("al", "addlist"))
158 if (arg - argv < argc - 1)
161 get_members_from_file(*arg, addlist);
166 else if (argis("d", "delete"))
168 if (arg - argv < argc - 1)
171 if ((memberstruct = parse_member(*arg)))
172 sq_save_data(dellist, memberstruct);
177 else if (argis("dl", "deletelist"))
179 if (arg - argv < argc - 1)
182 get_members_from_file(*arg, dellist);
187 else if (argis("f", "file"))
189 if (arg - argv < argc - 1)
193 get_members_from_file(*arg, synclist);
198 else if (argis("ct", "changetag"))
200 if (arg - argv < argc - 2)
203 if ((memberstruct = parse_member(*arg)))
204 sq_save_data(taglist, memberstruct);
205 memberstruct->tag = *++arg;
210 else if (argis("C", "create"))
212 else if (argis("P", "public"))
217 else if (argis("NP", "private"))
222 else if (argis("A", "active"))
227 else if (argis("I", "inactive"))
232 else if (argis("V", "visible"))
237 else if (argis("H", "hidden"))
242 else if (argis("M", "mail"))
247 else if (argis("NM", "notmail"))
252 else if (argis("G", "group"))
257 else if (argis("NG", "notgroup"))
262 else if (argis("N", "nfs"))
267 else if (argis("NN", "notnfs"))
272 else if (argis("mm", "mailman"))
277 else if (argis("nmm", "notmailman"))
282 else if (argis("ms", "mailman_server"))
284 if (arg - argv < argc - 1)
288 mailman_server = canonicalize_hostname(strdup(*arg));
293 else if (argis("D", "desc"))
295 if (arg - argv < argc - 1)
304 else if (argis("O", "owner"))
306 if (arg - argv < argc - 1)
310 owner = parse_member(*arg);
315 else if (argis("MA", "memacl"))
317 if (arg - argv < argc -1)
321 memacl = parse_member(*arg);
326 else if (argis("R", "rename"))
328 if (arg - argv < argc - 1)
340 else if (listname == NULL)
345 if (listname == NULL)
348 /* if no other options specified, turn on list members flag */
349 if (!(infoflg || syncflg || createflag || setinfo ||
350 addlist->q_next != addlist || dellist->q_next != dellist ||
351 taglist->q_next != taglist))
354 /* If none of {users,strings,lists,kerberos,machines} specified,
356 if (!(showusers || showstrings || showlists || showkerberos))
357 showusers = showstrings = showlists = showkerberos = showmachines = 1;
360 status = mrcl_connect(server, "blanche", 10, !noauth);
361 if (status == MRCL_AUTH_ERROR)
363 com_err(whoami, 0, "Authentication error while working on list %s",
365 com_err(whoami, 0, "Try the -noauth flag if you don't "
366 "need authentication.");
371 /* check for username/listname clash */
372 if (createflag || (setinfo && newname && strcmp(newname, listname)))
374 status = mr_query("get_user_account_by_login", 1,
375 createflag ? &listname : &newname,
377 if (status != MR_NO_MATCH)
378 fprintf(stderr, "WARNING: A user by that name already exists.\n");
381 /* create if needed */
386 argv[L_NAME] = listname;
387 argv[L_ACTIVE] = (active == 0) ? "0" : "1";
388 argv[L_PUBLIC] = (public == 1) ? "1" : "0";
389 argv[L_HIDDEN] = (hidden == 1) ? "1" : "0";
390 argv[L_MAILLIST] = (maillist == 0) ? "0" : "1";
391 argv[L_GROUP] = (grouplist == 1) ? "1" : "0";
392 argv[L_GID] = UNIQUE_GID;
393 argv[L_NFSGROUP] = (nfsgroup == 1) ? "1" : "0";
394 argv[L_MAILMAN] = (mailman == 1) ? "1" : "0";
395 argv[L_DESC] = desc ? desc : "none";
398 argv[L_MAILMAN_SERVER] = mailman_server ? mailman_server : "[ANY]";
400 argv[L_MAILMAN_SERVER] = "[NONE]";
404 if (memacl->type == M_ANY)
406 status = mr_query("get_user_account_by_login", 1,
407 &memacl->name, NULL, NULL);
408 if (status == MR_NO_MATCH)
409 memacl->type = M_LIST;
411 memacl->type = M_USER;
413 argv[L_MEMACE_TYPE] = typename[memacl->type];
414 argv[L_MEMACE_NAME] = memacl->name;
415 if (memacl->type == M_KERBEROS)
417 status = mrcl_validate_kerberos_member(argv[L_MEMACE_NAME],
418 &argv[L_MEMACE_NAME]);
419 if (mrcl_get_message())
420 mrcl_com_err(whoami);
421 if (status == MRCL_REJECT)
426 argv[L_MEMACE_TYPE] = argv[L_MEMACE_NAME] = "NONE";
430 argv[L_ACE_NAME] = owner->name;
435 argv[L_ACE_TYPE] = "USER";
436 status = mr_query("add_list", 15, argv, NULL, NULL);
437 if (owner->type != M_ANY || status != MR_USER)
441 argv[L_ACE_TYPE] = "LIST";
442 status = mr_query("add_list", 15, argv, NULL, NULL);
446 argv[L_ACE_TYPE] = "KERBEROS";
447 status = mrcl_validate_kerberos_member(argv[L_ACE_NAME],
449 if (mrcl_get_message())
450 mrcl_com_err(whoami);
451 if (status == MRCL_REJECT)
453 status = mr_query("add_list", 15, argv, NULL, NULL);
456 argv[L_ACE_TYPE] = argv[L_ACE_NAME] = "NONE";
457 status = mr_query("add_list", 15, argv, NULL, NULL);
463 argv[L_ACE_TYPE] = "USER";
464 argv[L_ACE_NAME] = get_username();
466 status = mr_query("add_list", 15, argv, NULL, NULL);
471 com_err(whoami, status, "while creating list.");
479 status = mr_query("get_list_info", 1, &listname,
480 save_list_info, argv);
483 com_err(whoami, status, "while getting list information");
489 argv[L_NAME + 1] = newname;
491 argv[L_ACTIVE + 1] = active ? "1" : "0";
493 argv[L_PUBLIC + 1] = public ? "1" : "0";
495 argv[L_HIDDEN + 1] = hidden ? "1" : "0";
497 argv[L_MAILLIST + 1] = maillist ? "1" : "0";
499 argv[L_GROUP + 1] = grouplist ? "1" : "0";
501 argv[L_NFSGROUP + 1] = nfsgroup ? "1" : "0";
503 argv[L_MAILMAN + 1] = mailman ? "1" : "0";
505 /* If someone toggled the mailman bit, but didn't specify a server,
509 argv[L_MAILMAN_SERVER + 1] = mailman_server;
510 else if ((mailman == 1) && !strcmp(argv[L_MAILMAN_SERVER + 1], "[NONE]"))
511 argv[L_MAILMAN_SERVER + 1] = "[ANY]";
514 argv[L_DESC + 1] = desc;
518 if (memacl->type == M_ANY)
520 status = mr_query("get_user_account_by_login", 1,
521 &memacl->name, NULL, NULL);
522 if (status == MR_NO_MATCH)
523 memacl->type = M_LIST;
525 memacl->type = M_USER;
527 argv[L_MEMACE_TYPE + 1] = typename[memacl->type];
528 argv[L_MEMACE_NAME + 1] = memacl->name;
529 if (memacl->type == M_KERBEROS)
531 status = mrcl_validate_kerberos_member(argv[L_MEMACE_NAME + 1],
532 &argv[L_MEMACE_NAME + 1]);
533 if (mrcl_get_message())
534 mrcl_com_err(whoami);
535 if (status == MRCL_REJECT)
542 argv[L_ACE_NAME + 1] = owner->name;
547 argv[L_ACE_TYPE + 1] = "USER";
548 status = mr_query("update_list", 16, argv, NULL, NULL);
549 if (owner->type != M_ANY || status != MR_USER)
553 argv[L_ACE_TYPE + 1] = "LIST";
554 status = mr_query("update_list", 16, argv, NULL, NULL);
558 argv[L_ACE_TYPE + 1] = "KERBEROS";
559 status = mrcl_validate_kerberos_member(argv[L_ACE_NAME + 1],
560 &argv[L_ACE_NAME + 1]);
561 if (mrcl_get_message())
562 mrcl_com_err(whoami);
563 if (status == MRCL_REJECT)
565 status = mr_query("update_list", 16, argv, NULL, NULL);
568 argv[L_ACE_TYPE + 1] = argv[L_ACE_NAME + 1] = "NONE";
569 status = mr_query("update_list", 16, argv, NULL, NULL);
574 status = mr_query("update_list", 16, argv, NULL, NULL);
578 com_err(whoami, status, "while updating list.");
585 /* display list info if requested to */
588 status = mr_query("get_list_info", 1, &listname, show_list_info, NULL);
591 com_err(whoami, status, "while getting list information");
594 if (verbose && !memberflg)
596 status = mr_query("count_members_of_list", 1, &listname,
597 show_list_count, NULL);
600 com_err(whoami, status, "while getting list count");
606 /* if we're synchronizing to a file, we need to:
607 * get the current members of the list
608 * for each member of the sync file
609 * if they are on the list, remove them from the in-memory copy
610 * if they're not on the list, add them to add-list
611 * if anyone is left on the in-memory copy, put them on the delete-list
612 * lastly, reset memberlist so we can use it again later
616 status = mr_query("get_members_of_list", 1, &listname,
617 get_list_members, memberlist);
620 com_err(whoami, status, "getting members of list %s", listname);
623 while (sq_get_data(synclist, &memberstruct))
625 struct save_queue *q;
628 for (q = memberlist->q_next; q != memberlist; q = q->q_next)
630 if (membercmp(q->q_data, memberstruct) == 0)
632 q->q_prev->q_next = q->q_next;
633 q->q_next->q_prev = q->q_prev;
639 sq_save_data(addlist, memberstruct);
641 while (sq_get_data(memberlist, &memberstruct))
642 sq_save_data(dellist, memberstruct);
643 sq_destroy(memberlist);
644 memberlist = sq_create();
647 /* Process the add list */
648 while (sq_get_data(addlist, &memberstruct))
650 /* canonicalize string if necessary */
651 if (memberstruct->type != M_KERBEROS &&
652 (p = strchr(memberstruct->name, '@')))
654 char *host = canonicalize_hostname(strdup(++p));
655 static char **mailhubs = NULL;
664 mailhubs = malloc(sizeof(char *));
666 status = mr_query("get_alias", 3, argv, collect,
668 if (status != MR_SUCCESS && status != MR_NO_MATCH)
670 com_err(whoami, status,
671 " while reading list of MAILHUB servers");
675 for (i = 0; (p = mailhubs[i]); i++)
677 if (!strcasecmp(p, host))
679 host = strdup(memberstruct->name);
680 *(strchr(memberstruct->name, '@')) = 0;
681 if (memberstruct->type == M_STRING)
682 memberstruct->type = M_ANY;
683 fprintf(stderr, "Warning: \"%s\" converted to "
684 "\"%s\" because it is a local name.\n",
685 host, memberstruct->name);
691 /* now continue adding member */
692 membervec[0] = listname;
693 membervec[2] = memberstruct->name;
694 membervec[3] = memberstruct->tag;
697 printf("Adding member ");
698 show_list_member(memberstruct);
700 switch (memberstruct->type)
704 membervec[1] = "USER";
705 status = mr_query("add_tagged_member_to_list", 4, membervec,
707 if (status == MR_SUCCESS)
709 else if (status != MR_USER || memberstruct->type != M_ANY)
711 com_err(whoami, status, "while adding member %s to %s",
712 memberstruct->name, listname);
717 membervec[1] = "LIST";
718 status = mr_query("add_tagged_member_to_list", 4, membervec,
720 if (status == MR_SUCCESS)
722 if (!strcmp(membervec[0], get_username()))
724 fprintf(stderr, "\nWARNING: \"LIST:%s\" was just added "
725 "to list \"%s\".\n", membervec[2], membervec[0]);
726 fprintf(stderr, "If you meant to add yourself to the list "
727 "\"%s\", type:\n", membervec[2]);
728 fprintf(stderr, "\tblanche %s -d %s\t(to undo this)\n",
729 membervec[0], membervec[2]);
730 fprintf(stderr, "\tblanche %s -a %s\t(to add yourself to "
731 "that list)\n", membervec[2], membervec[0]);
735 else if (status != MR_LIST || memberstruct->type != M_ANY)
737 com_err(whoami, status, "while adding member %s to %s",
738 memberstruct->name, listname);
743 status = mrcl_validate_string_member(memberstruct->name);
744 if (memberstruct->type == M_ANY && status == MRCL_WARN)
746 /* if user is trying to add something which isn't a
747 remote string, or a list, or a user, and didn't
748 explicitly specify `STRING:', it's probably a typo */
749 com_err(whoami, MR_NO_MATCH, "while adding member %s to %s",
750 memberstruct->name, listname);
755 mrcl_com_err(whoami);
757 if (status == MRCL_REJECT)
763 membervec[1] = "STRING";
764 status = mr_query("add_tagged_member_to_list", 4, membervec,
766 if (status != MR_SUCCESS)
768 com_err(whoami, status, "while adding member %s to %s",
769 memberstruct->name, listname);
774 membervec[1] = "KERBEROS";
775 status = mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
776 if (mrcl_get_message())
777 mrcl_com_err(whoami);
778 if (status == MRCL_REJECT)
783 status = mr_query("add_tagged_member_to_list", 4, membervec,
785 if (status != MR_SUCCESS)
787 com_err(whoami, status, "while adding member %s to %s",
788 memberstruct->name, listname);
794 membervec[1] = "MACHINE";
795 membervec[2] = canonicalize_hostname(strdup(memberstruct->name));
796 status = mr_query("add_tagged_member_to_list", 4, membervec,
798 if (status != MR_SUCCESS)
800 com_err(whoami, status, "while adding member %s to %s",
801 memberstruct->name, listname);
808 /* Process the delete list */
809 while (sq_get_data(dellist, &memberstruct))
811 membervec[0] = listname;
812 membervec[2] = memberstruct->name;
815 printf("Deleting member ");
816 show_list_member(memberstruct);
818 switch (memberstruct->type)
822 membervec[1] = "USER";
823 status = mr_query("delete_member_from_list", 3, membervec,
825 if (status == MR_SUCCESS)
827 else if ((status != MR_USER && status != MR_NO_MATCH) ||
828 memberstruct->type != M_ANY)
830 com_err(whoami, status, "while deleting member %s from %s",
831 memberstruct->name, listname);
836 membervec[1] = "LIST";
837 status = mr_query("delete_member_from_list", 3, membervec,
839 if (status == MR_SUCCESS)
841 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
842 memberstruct->type != M_ANY)
844 if (status == MR_PERM && memberstruct->type == M_ANY &&
845 !strcmp(membervec[2], get_username()))
847 /* M_ANY means we've fallen through from the user
848 * case. The user is trying to remove himself from
849 * a list, but we got MR_USER or MR_NO_MATCH above,
850 * meaning he's not really on it, and we got MR_PERM
851 * when trying to remove LIST:$USER because he's not
852 * on the acl. That error is useless, so return
853 * MR_NO_MATCH instead. However, this will generate the
854 * wrong error if the user was trying to remove the list
855 * with his username from a list he doesn't administrate
856 * without explicitly specifying "list:".
858 status = MR_NO_MATCH;
860 com_err(whoami, status, "while deleting member %s from %s",
861 memberstruct->name, listname);
866 membervec[1] = "STRING";
867 status = mr_query("delete_member_from_list", 3, membervec,
869 if (status == MR_STRING && memberstruct->type == M_ANY)
871 com_err(whoami, 0, " Unable to find member %s to delete from %s",
872 memberstruct->name, listname);
874 if (!strcmp(membervec[0], get_username()))
876 fprintf(stderr, "(If you were trying to remove yourself "
877 "from the list \"%s\",\n", membervec[2]);
878 fprintf(stderr, "the correct command is \"blanche %s -d "
879 "%s\".)\n", membervec[2], membervec[0]);
882 else if (status != MR_SUCCESS)
884 com_err(whoami, status, "while deleting member %s from %s",
885 memberstruct->name, listname);
890 membervec[1] = "KERBEROS";
891 status = mr_query("delete_member_from_list", 3, membervec,
893 if (status == MR_STRING || status == MR_NO_MATCH)
895 /* Try canonicalizing the Kerberos principal and trying
896 * again. If we succeed, print the message from mrcl.
897 * Otherwise, just pretend we never did this and print
898 * the original error message.
900 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
901 if (mrcl_get_message())
903 if (mr_query("delete_member_from_list", 3, membervec,
904 NULL, NULL) == MR_SUCCESS)
905 mrcl_com_err(whoami);
909 if (status != MR_SUCCESS)
911 com_err(whoami, status, "while deleting member %s from %s",
912 memberstruct->name, listname);
917 membervec[1] = "MACHINE";
918 membervec[2] = canonicalize_hostname(memberstruct->name);
919 status = mr_query("delete_member_from_list", 3, membervec,
921 if (status != MR_SUCCESS)
923 com_err(whoami, status, "while deleting member %s from %s",
924 memberstruct->name, listname);
931 /* Process the tag list */
932 while (sq_get_data(taglist, &memberstruct))
934 membervec[0] = listname;
935 membervec[2] = memberstruct->name;
936 membervec[3] = memberstruct->tag;
939 printf("Tagging member ");
940 show_list_member(memberstruct);
942 switch (memberstruct->type)
946 membervec[1] = "USER";
947 status = mr_query("tag_member_of_list", 4, membervec,
949 if (status == MR_SUCCESS)
951 else if ((status != MR_USER && status != MR_NO_MATCH) ||
952 memberstruct->type != M_ANY)
954 com_err(whoami, status, "while changing tag on member %s of %s",
955 memberstruct->name, listname);
960 membervec[1] = "LIST";
961 status = mr_query("tag_member_of_list", 4, membervec,
963 if (status == MR_SUCCESS)
965 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
966 memberstruct->type != M_ANY)
968 com_err(whoami, status, "while changing tag on member %s of %s",
969 memberstruct->name, listname);
974 membervec[1] = "STRING";
975 status = mr_query("tag_member_of_list", 4, membervec,
977 if (status == MR_STRING && memberstruct->type == M_ANY)
979 com_err(whoami, 0, " Unable to find member %s on list %s",
980 memberstruct->name, listname);
983 else if (status != MR_SUCCESS)
985 com_err(whoami, status, "while retagging member %s on %s",
986 memberstruct->name, listname);
991 membervec[1] = "KERBEROS";
992 status = mr_query("tag_member_of_list", 4, membervec,
994 if (status == MR_STRING || status == MR_NO_MATCH)
996 /* Try canonicalizing the Kerberos principal and trying
997 * again. If we succeed, print the message from mrcl.
998 * Otherwise, just pretend we never did this and print
999 * the original error message.
1001 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
1002 if (mrcl_get_message())
1004 if (mr_query("tag_member_of_list", 4, membervec,
1005 NULL, NULL) == MR_SUCCESS)
1006 mrcl_com_err(whoami);
1007 status = MR_SUCCESS;
1010 if (status != MR_SUCCESS)
1012 com_err(whoami, status, "while changing tag on member %s of %s",
1013 memberstruct->name, listname);
1019 /* Display the members of the list now, if requested */
1023 recursive_display_list_members();
1026 status = mr_query(showtags ? "get_tagged_members_of_list" :
1027 "get_members_of_list", 1, &listname,
1028 get_list_members, memberlist);
1030 com_err(whoami, status, "while getting members of list %s",
1032 while (sq_get_data(memberlist, &memberstruct))
1033 show_list_member(memberstruct);
1039 exit(success ? 0 : 1);
1042 void usage(char **argv)
1044 #define USAGE_OPTIONS_FORMAT " %-39s%s\n"
1045 fprintf(stderr, "Usage: %s listname [options]\n", argv[0]);
1046 fprintf(stderr, "Options are\n");
1047 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-v | -verbose",
1049 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-m | -members",
1050 "-R | -rename newname");
1051 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-u | -users",
1053 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-l | -lists",
1055 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-s | -strings",
1057 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-k | -kerberos",
1059 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-i | -info",
1061 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-r | -recursive",
1063 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-a | -add member",
1065 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-d | -delete member",
1067 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-al | -addlist filename",
1069 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-dl | -deletelist filename",
1071 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-f | -file filename",
1073 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-at | -addtagged member tag",
1075 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-ct | -changetag member tag",
1077 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-t | -tags",
1078 "-nmm | -notmailman");
1079 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-D | -desc description",
1080 "-ms | -mailman_server server");
1081 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-O | -owner owner",
1082 "-MA | -memacl membership_acl");
1083 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-n | -noauth",
1084 "-db | -database host[:port]");
1089 /* Display the members stored in the queue */
1091 void show_list_member(struct member *memberstruct)
1095 switch (memberstruct->type)
1123 printf("%s\n", memberstruct->name);
1128 printf("%s:%s", s, memberstruct->name);
1131 if (memberstruct->type == M_LIST)
1132 printf("LIST:%s", memberstruct->name);
1133 else if (memberstruct->type == M_KERBEROS)
1134 printf("KERBEROS:%s", memberstruct->name);
1135 else if (memberstruct->type == M_STRING &&
1136 !strchr(memberstruct->name, '@'))
1137 printf("STRING:%s", memberstruct->name);
1138 else if (memberstruct->type == M_MACHINE)
1139 printf("MACHINE:%s", memberstruct->name);
1141 printf("%s", memberstruct->name);
1143 if (showtags && *(memberstruct->tag))
1144 printf(" (%s)\n", memberstruct->tag);
1150 /* Show the retrieved information about a list */
1152 int show_list_info(int argc, char **argv, void *hint)
1154 printf("List: %s\n", argv[L_NAME]);
1155 printf("Description: %s\n", argv[L_DESC]);
1156 printf("Flags: %s, %s, and %s\n",
1157 atoi(argv[L_ACTIVE]) ? "active" : "inactive",
1158 atoi(argv[L_PUBLIC]) ? "public" : "private",
1159 atoi(argv[L_HIDDEN]) ? "hidden" : "visible");
1160 printf("%s is %sa maillist and is %sa group", argv[L_NAME],
1161 atoi(argv[L_MAILLIST]) ? "" : "not ",
1162 atoi(argv[L_GROUP]) ? "" : "not ");
1163 if (atoi(argv[L_GROUP]))
1165 if (atoi(argv[L_NFSGROUP]))
1166 printf(" (and an NFS group)");
1167 printf(" with GID %d\n", atoi(argv[L_GID]));
1171 if (atoi(argv[L_MAILMAN]))
1172 printf("%s is a Mailman list on server %s\n", argv[L_NAME],
1173 argv[L_MAILMAN_SERVER]);
1174 printf("Owner: %s %s\n", argv[L_ACE_TYPE], argv[L_ACE_NAME]);
1175 if (strcmp(argv[L_MEMACE_TYPE], "NONE"))
1176 printf("Membership ACL: %s %s\n", argv[L_MEMACE_TYPE],
1177 argv[L_MEMACE_NAME]);
1178 printf("Last modified by %s with %s on %s\n",
1179 argv[L_MODBY], argv[L_MODWITH], argv[L_MODTIME]);
1184 /* Copy retrieved information about a list into a new argv */
1186 int save_list_info(int argc, char **argv, void *hint)
1188 char **nargv = hint;
1190 for (argc = 0; argc < 16; argc++)
1191 nargv[argc + 1] = strdup(argv[argc]);
1195 /* Show the retrieve list member count */
1197 int show_list_count(int argc, char **argv, void *hint)
1199 printf("Members: %s\n", argv[0]);
1204 /* Recursively find all of the members of listname, and then display them */
1206 void recursive_display_list_members(void)
1208 int status, count, savecount;
1209 struct save_queue *lists, *members;
1210 struct member *m, *m1, *data;
1212 lists = sq_create();
1213 members = sq_create();
1214 m = malloc(sizeof(struct member));
1217 sq_save_data(lists, m);
1219 while (sq_get_data(lists, &m))
1221 sq_destroy(memberlist);
1222 memberlist = sq_create();
1223 status = mr_query("get_members_of_list", 1, &(m->name),
1224 get_list_members, memberlist);
1226 com_err(whoami, status, "while getting members of list %s", m->name);
1227 while (sq_get_data(memberlist, &m1))
1229 if (m1->type == M_LIST)
1230 unique_add_member(lists, m1);
1232 unique_add_member(members, m1);
1235 savecount = count = sq_count_elts(members);
1236 data = malloc(count * sizeof(struct member));
1238 while (sq_get_data(members, &m))
1239 memcpy(&data[count++], m, sizeof(struct member));
1240 qsort(data, count, sizeof(struct member), membercmp);
1241 for (count = 0; count < savecount; count++)
1242 show_list_member(&data[count]);
1246 /* add a struct member to a queue if that member isn't already there. */
1248 void unique_add_member(struct save_queue *q, struct member *m)
1250 struct save_queue *qp;
1252 for (qp = q->q_next; qp != q; qp = qp->q_next)
1254 if (!membercmp(qp->q_data, m))
1261 /* Collect the retrieved members of the list */
1263 int get_list_members(int argc, char **argv, void *sq)
1265 struct save_queue *q = sq;
1268 m = malloc(sizeof(struct member));
1281 m->type = M_KERBEROS;
1284 m->type = M_MACHINE;
1287 m->name = strdup(argv[1]);
1289 m->tag = strdup(argv[2]);
1291 m->tag = strdup("");
1297 /* Open file, parse members from file, and put them on the specified queue */
1298 void get_members_from_file(char *filename, struct save_queue *queue)
1302 struct member *memberstruct;
1304 if (!strcmp(filename, "-"))
1308 in = fopen(filename, "r");
1311 com_err(whoami, errno, "while opening %s for input", filename);
1316 while (fgets(buf, BUFSIZ, in))
1318 if ((memberstruct = parse_member(buf)))
1319 sq_save_data(queue, memberstruct);
1323 com_err(whoami, errno, "while reading from %s", filename);
1329 /* Collect the possible expansions of the alias MAILHUB */
1331 int collect(int argc, char **argv, void *l)
1336 for (i = 0; (*list)[i]; i++)
1338 *list = realloc(*list, (i + 2) * sizeof(char *));
1339 (*list)[i] = strdup(argv[2]);
1340 (*list)[i + 1] = NULL;
1345 /* Parse a line of input, fetching a member. NULL is returned if a member
1346 * is not found. ';' is a comment character.
1349 struct member *parse_member(char *s)
1354 while (*s && isspace(*s))
1357 while (*p && *p != '\n' && *p != ';')
1359 if (isprint(*p) && !isspace(*p))
1366 if (p == s || strlen(s) == 0)
1369 if (!(m = malloc(sizeof(struct member))))
1371 m->tag = strdup("");
1373 if ((p = strchr(s, ':')))
1377 if (!strcasecmp("user", s))
1379 else if (!strcasecmp("list", s))
1381 else if (!strcasecmp("string", s))
1383 else if (!strcasecmp("kerberos", s))
1384 m->type = M_KERBEROS;
1385 else if (!strcasecmp("machine", s))
1386 m->type = M_MACHINE;
1387 else if (!strcasecmp("none", s))
1395 m->name = strdup(m->name);
1399 m->name = strdup(s);
1400 m->type = strcasecmp(s, "none") ? M_ANY : M_NONE;
1407 * This routine two compares members by the following rules:
1408 * 1. A USER is less than a LIST
1409 * 2. A LIST is less than a STRING
1410 * 3. If two members are of the same type, the one alphabetically first
1411 * is less than the other
1412 * It returs < 0 if the first member is less, 0 if they are identical, and
1413 * > 0 if the second member is less (the first member is greater).
1416 int membercmp(const void *mem1, const void *mem2)
1418 const struct member *m1 = mem1, *m2 = mem2;
1420 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
1421 return strcmp(m1->name, m2->name);
1423 return m1->type - m2->type;
1427 int sq_count_elts(struct save_queue *q)
1433 while (sq_get_data(q, &foo))
1438 char *get_username(void)
1442 username = getenv("USER");
1445 username = mrcl_krb_user();
1448 com_err(whoami, 0, "Could not determine username");