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, *gid;
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 = gid = 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)
337 else if (argis("g", "gid"))
339 if (arg - argv < argc - 1)
351 else if (listname == NULL)
356 if (listname == NULL)
359 /* if no other options specified, turn on list members flag */
360 if (!(infoflg || syncflg || createflag || setinfo ||
361 addlist->q_next != addlist || dellist->q_next != dellist ||
362 taglist->q_next != taglist))
365 /* If none of {users,strings,lists,kerberos,machines} specified,
367 if (!(showusers || showstrings || showlists || showkerberos || showmachines))
368 showusers = showstrings = showlists = showkerberos = showmachines = 1;
371 status = mrcl_connect(server, "blanche", 10, !noauth);
372 if (status == MRCL_AUTH_ERROR)
374 com_err(whoami, 0, "Authentication error while working on list %s",
376 com_err(whoami, 0, "Try the -noauth flag if you don't "
377 "need authentication.");
382 /* check for username/listname clash */
383 if (createflag || (setinfo && newname && strcmp(newname, listname)))
385 status = mr_query("get_user_account_by_login", 1,
386 createflag ? &listname : &newname,
388 if (status != MR_NO_MATCH)
389 fprintf(stderr, "WARNING: A user by that name already exists.\n");
392 /* create if needed */
397 argv[L_NAME] = listname;
398 argv[L_ACTIVE] = (active == 0) ? "0" : "1";
399 argv[L_PUBLIC] = (public == 1) ? "1" : "0";
400 argv[L_HIDDEN] = (hidden == 1) ? "1" : "0";
401 argv[L_MAILLIST] = (maillist == 0) ? "0" : "1";
402 argv[L_GROUP] = (grouplist == 1) ? "1" : "0";
407 argv[L_GID] = UNIQUE_GID;
409 argv[L_NFSGROUP] = (nfsgroup == 1) ? "1" : "0";
410 argv[L_MAILMAN] = (mailman == 1) ? "1" : "0";
411 argv[L_DESC] = desc ? desc : "none";
414 argv[L_MAILMAN_SERVER] = mailman_server ? mailman_server : "[ANY]";
416 argv[L_MAILMAN_SERVER] = "[NONE]";
420 if (memacl->type == M_ANY)
422 status = mr_query("get_user_account_by_login", 1,
423 &memacl->name, NULL, NULL);
424 if (status == MR_NO_MATCH)
425 memacl->type = M_LIST;
427 memacl->type = M_USER;
429 argv[L_MEMACE_TYPE] = typename[memacl->type];
430 argv[L_MEMACE_NAME] = memacl->name;
431 if (memacl->type == M_KERBEROS)
433 status = mrcl_validate_kerberos_member(argv[L_MEMACE_NAME],
434 &argv[L_MEMACE_NAME]);
435 if (mrcl_get_message())
436 mrcl_com_err(whoami);
437 if (status == MRCL_REJECT)
442 argv[L_MEMACE_TYPE] = argv[L_MEMACE_NAME] = "NONE";
446 argv[L_ACE_NAME] = owner->name;
451 argv[L_ACE_TYPE] = "USER";
452 status = mr_query("add_list", 15, argv, NULL, NULL);
453 if (owner->type != M_ANY || status != MR_USER)
457 argv[L_ACE_TYPE] = "LIST";
458 status = mr_query("add_list", 15, argv, NULL, NULL);
462 argv[L_ACE_TYPE] = "KERBEROS";
463 status = mrcl_validate_kerberos_member(argv[L_ACE_NAME],
465 if (mrcl_get_message())
466 mrcl_com_err(whoami);
467 if (status == MRCL_REJECT)
469 status = mr_query("add_list", 15, argv, NULL, NULL);
472 argv[L_ACE_TYPE] = argv[L_ACE_NAME] = "NONE";
473 status = mr_query("add_list", 15, argv, NULL, NULL);
479 argv[L_ACE_TYPE] = "USER";
480 argv[L_ACE_NAME] = get_username();
482 status = mr_query("add_list", 15, argv, NULL, NULL);
487 com_err(whoami, status, "while creating list.");
495 status = mr_query("get_list_info", 1, &listname,
496 save_list_info, argv);
499 com_err(whoami, status, "while getting list information");
505 argv[L_NAME + 1] = newname;
507 argv[L_ACTIVE + 1] = active ? "1" : "0";
509 argv[L_PUBLIC + 1] = public ? "1" : "0";
511 argv[L_HIDDEN + 1] = hidden ? "1" : "0";
513 argv[L_MAILLIST + 1] = maillist ? "1" : "0";
515 argv[L_GROUP + 1] = grouplist ? "1" : "0";
517 argv[L_GID + 1] = gid;
519 argv[L_NFSGROUP + 1] = nfsgroup ? "1" : "0";
521 argv[L_MAILMAN + 1] = mailman ? "1" : "0";
523 /* If someone toggled the mailman bit, but didn't specify a server,
527 argv[L_MAILMAN_SERVER + 1] = mailman_server;
528 else if ((mailman == 1) && !strcmp(argv[L_MAILMAN_SERVER + 1], "[NONE]"))
529 argv[L_MAILMAN_SERVER + 1] = "[ANY]";
532 argv[L_DESC + 1] = desc;
536 if (memacl->type == M_ANY)
538 status = mr_query("get_user_account_by_login", 1,
539 &memacl->name, NULL, NULL);
540 if (status == MR_NO_MATCH)
541 memacl->type = M_LIST;
543 memacl->type = M_USER;
545 argv[L_MEMACE_TYPE + 1] = typename[memacl->type];
546 argv[L_MEMACE_NAME + 1] = memacl->name;
547 if (memacl->type == M_KERBEROS)
549 status = mrcl_validate_kerberos_member(argv[L_MEMACE_NAME + 1],
550 &argv[L_MEMACE_NAME + 1]);
551 if (mrcl_get_message())
552 mrcl_com_err(whoami);
553 if (status == MRCL_REJECT)
560 argv[L_ACE_NAME + 1] = owner->name;
565 argv[L_ACE_TYPE + 1] = "USER";
566 status = mr_query("update_list", 16, argv, NULL, NULL);
567 if (owner->type != M_ANY || status != MR_USER)
571 argv[L_ACE_TYPE + 1] = "LIST";
572 status = mr_query("update_list", 16, argv, NULL, NULL);
576 argv[L_ACE_TYPE + 1] = "KERBEROS";
577 status = mrcl_validate_kerberos_member(argv[L_ACE_NAME + 1],
578 &argv[L_ACE_NAME + 1]);
579 if (mrcl_get_message())
580 mrcl_com_err(whoami);
581 if (status == MRCL_REJECT)
583 status = mr_query("update_list", 16, argv, NULL, NULL);
586 argv[L_ACE_TYPE + 1] = argv[L_ACE_NAME + 1] = "NONE";
587 status = mr_query("update_list", 16, argv, NULL, NULL);
592 status = mr_query("update_list", 16, argv, NULL, NULL);
596 com_err(whoami, status, "while updating list.");
603 /* display list info if requested to */
606 status = mr_query("get_list_info", 1, &listname, show_list_info, NULL);
609 com_err(whoami, status, "while getting list information");
612 if (verbose && !memberflg)
614 status = mr_query("count_members_of_list", 1, &listname,
615 show_list_count, NULL);
618 com_err(whoami, status, "while getting list count");
624 /* if we're synchronizing to a file, we need to:
625 * get the current members of the list
626 * for each member of the sync file
627 * if they are on the list, remove them from the in-memory copy
628 * if they're not on the list, add them to add-list
629 * if anyone is left on the in-memory copy, put them on the delete-list
630 * lastly, reset memberlist so we can use it again later
634 status = mr_query("get_members_of_list", 1, &listname,
635 get_list_members, memberlist);
638 com_err(whoami, status, "getting members of list %s", listname);
641 while (sq_get_data(synclist, &memberstruct))
643 struct save_queue *q;
646 for (q = memberlist->q_next; q != memberlist; q = q->q_next)
648 if (membercmp(q->q_data, memberstruct) == 0)
650 q->q_prev->q_next = q->q_next;
651 q->q_next->q_prev = q->q_prev;
657 sq_save_data(addlist, memberstruct);
659 while (sq_get_data(memberlist, &memberstruct))
660 sq_save_data(dellist, memberstruct);
661 sq_destroy(memberlist);
662 memberlist = sq_create();
665 /* Process the add list */
666 while (sq_get_data(addlist, &memberstruct))
668 /* canonicalize string if necessary */
669 if (memberstruct->type != M_KERBEROS &&
670 (p = strchr(memberstruct->name, '@')))
672 char *host = canonicalize_hostname(strdup(++p));
673 static char **mailhubs = NULL;
682 mailhubs = malloc(sizeof(char *));
684 status = mr_query("get_alias", 3, argv, collect,
686 if (status != MR_SUCCESS && status != MR_NO_MATCH)
688 com_err(whoami, status,
689 " while reading list of MAILHUB servers");
693 for (i = 0; (p = mailhubs[i]); i++)
695 if (!strcasecmp(p, host))
697 host = strdup(memberstruct->name);
698 *(strchr(memberstruct->name, '@')) = 0;
699 if (memberstruct->type == M_STRING)
700 memberstruct->type = M_ANY;
701 fprintf(stderr, "Warning: \"%s\" converted to "
702 "\"%s\" because it is a local name.\n",
703 host, memberstruct->name);
709 /* now continue adding member */
710 membervec[0] = listname;
711 membervec[2] = memberstruct->name;
712 membervec[3] = memberstruct->tag;
715 printf("Adding member ");
716 show_list_member(memberstruct);
718 switch (memberstruct->type)
722 membervec[1] = "USER";
723 status = mr_query("add_tagged_member_to_list", 4, membervec,
725 if (status == MR_SUCCESS)
727 else if (status != MR_USER || memberstruct->type != M_ANY)
729 com_err(whoami, status, "while adding member %s to %s",
730 memberstruct->name, listname);
735 membervec[1] = "LIST";
736 status = mr_query("add_tagged_member_to_list", 4, membervec,
738 if (status == MR_SUCCESS)
740 if (!strcmp(membervec[0], get_username()))
742 fprintf(stderr, "\nWARNING: \"LIST:%s\" was just added "
743 "to list \"%s\".\n", membervec[2], membervec[0]);
744 fprintf(stderr, "If you meant to add yourself to the list "
745 "\"%s\", type:\n", membervec[2]);
746 fprintf(stderr, "\tblanche %s -d %s\t(to undo this)\n",
747 membervec[0], membervec[2]);
748 fprintf(stderr, "\tblanche %s -a %s\t(to add yourself to "
749 "that list)\n", membervec[2], membervec[0]);
753 else if (status != MR_LIST || memberstruct->type != M_ANY)
755 com_err(whoami, status, "while adding member %s to %s",
756 memberstruct->name, listname);
761 status = mrcl_validate_string_member(memberstruct->name);
762 if (memberstruct->type == M_ANY && status == MRCL_WARN)
764 /* if user is trying to add something which isn't a
765 remote string, or a list, or a user, and didn't
766 explicitly specify `STRING:', it's probably a typo */
767 com_err(whoami, MR_NO_MATCH, "while adding member %s to %s",
768 memberstruct->name, listname);
773 mrcl_com_err(whoami);
775 if (status == MRCL_REJECT)
781 membervec[1] = "STRING";
782 status = mr_query("add_tagged_member_to_list", 4, membervec,
784 if (status != MR_SUCCESS)
786 com_err(whoami, status, "while adding member %s to %s",
787 memberstruct->name, listname);
792 membervec[1] = "KERBEROS";
793 status = mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
794 if (mrcl_get_message())
795 mrcl_com_err(whoami);
796 if (status == MRCL_REJECT)
801 status = mr_query("add_tagged_member_to_list", 4, membervec,
803 if (status != MR_SUCCESS)
805 com_err(whoami, status, "while adding member %s to %s",
806 memberstruct->name, listname);
812 membervec[1] = "MACHINE";
813 membervec[2] = canonicalize_hostname(strdup(memberstruct->name));
814 status = mr_query("add_tagged_member_to_list", 4, membervec,
816 if (status != MR_SUCCESS)
818 com_err(whoami, status, "while adding member %s to %s",
819 memberstruct->name, listname);
826 /* Process the delete list */
827 while (sq_get_data(dellist, &memberstruct))
829 membervec[0] = listname;
830 membervec[2] = memberstruct->name;
833 printf("Deleting member ");
834 show_list_member(memberstruct);
836 switch (memberstruct->type)
840 membervec[1] = "USER";
841 status = mr_query("delete_member_from_list", 3, membervec,
843 if (status == MR_SUCCESS)
845 else if ((status != MR_USER && status != MR_NO_MATCH) ||
846 memberstruct->type != M_ANY)
848 com_err(whoami, status, "while deleting member %s from %s",
849 memberstruct->name, listname);
854 membervec[1] = "LIST";
855 status = mr_query("delete_member_from_list", 3, membervec,
857 if (status == MR_SUCCESS)
859 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
860 memberstruct->type != M_ANY)
862 if (status == MR_PERM && memberstruct->type == M_ANY &&
863 !strcmp(membervec[2], get_username()))
865 /* M_ANY means we've fallen through from the user
866 * case. The user is trying to remove himself from
867 * a list, but we got MR_USER or MR_NO_MATCH above,
868 * meaning he's not really on it, and we got MR_PERM
869 * when trying to remove LIST:$USER because he's not
870 * on the acl. That error is useless, so return
871 * MR_NO_MATCH instead. However, this will generate the
872 * wrong error if the user was trying to remove the list
873 * with his username from a list he doesn't administrate
874 * without explicitly specifying "list:".
876 status = MR_NO_MATCH;
878 com_err(whoami, status, "while deleting member %s from %s",
879 memberstruct->name, listname);
884 membervec[1] = "STRING";
885 status = mr_query("delete_member_from_list", 3, membervec,
887 if (status == MR_STRING && memberstruct->type == M_ANY)
889 com_err(whoami, 0, " Unable to find member %s to delete from %s",
890 memberstruct->name, listname);
892 if (!strcmp(membervec[0], get_username()))
894 fprintf(stderr, "(If you were trying to remove yourself "
895 "from the list \"%s\",\n", membervec[2]);
896 fprintf(stderr, "the correct command is \"blanche %s -d "
897 "%s\".)\n", membervec[2], membervec[0]);
900 else if (status != MR_SUCCESS)
902 com_err(whoami, status, "while deleting member %s from %s",
903 memberstruct->name, listname);
908 membervec[1] = "KERBEROS";
909 status = mr_query("delete_member_from_list", 3, membervec,
911 if (status == MR_STRING || status == MR_NO_MATCH)
913 /* Try canonicalizing the Kerberos principal and trying
914 * again. If we succeed, print the message from mrcl.
915 * Otherwise, just pretend we never did this and print
916 * the original error message.
918 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
919 if (mrcl_get_message())
921 if (mr_query("delete_member_from_list", 3, membervec,
922 NULL, NULL) == MR_SUCCESS)
923 mrcl_com_err(whoami);
927 if (status != MR_SUCCESS)
929 com_err(whoami, status, "while deleting member %s from %s",
930 memberstruct->name, listname);
935 membervec[1] = "MACHINE";
936 membervec[2] = canonicalize_hostname(memberstruct->name);
937 status = mr_query("delete_member_from_list", 3, membervec,
939 if (status != MR_SUCCESS)
941 com_err(whoami, status, "while deleting member %s from %s",
942 memberstruct->name, listname);
949 /* Process the tag list */
950 while (sq_get_data(taglist, &memberstruct))
952 membervec[0] = listname;
953 membervec[2] = memberstruct->name;
954 membervec[3] = memberstruct->tag;
957 printf("Tagging member ");
958 show_list_member(memberstruct);
960 switch (memberstruct->type)
964 membervec[1] = "USER";
965 status = mr_query("tag_member_of_list", 4, membervec,
967 if (status == MR_SUCCESS)
969 else if ((status != MR_USER && status != MR_NO_MATCH) ||
970 memberstruct->type != M_ANY)
972 com_err(whoami, status, "while changing tag on member %s of %s",
973 memberstruct->name, listname);
978 membervec[1] = "LIST";
979 status = mr_query("tag_member_of_list", 4, membervec,
981 if (status == MR_SUCCESS)
983 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
984 memberstruct->type != M_ANY)
986 com_err(whoami, status, "while changing tag on member %s of %s",
987 memberstruct->name, listname);
992 membervec[1] = "STRING";
993 status = mr_query("tag_member_of_list", 4, membervec,
995 if (status == MR_STRING && memberstruct->type == M_ANY)
997 com_err(whoami, 0, " Unable to find member %s on list %s",
998 memberstruct->name, listname);
1001 else if (status != MR_SUCCESS)
1003 com_err(whoami, status, "while retagging member %s on %s",
1004 memberstruct->name, listname);
1009 membervec[1] = "KERBEROS";
1010 status = mr_query("tag_member_of_list", 4, membervec,
1012 if (status == MR_STRING || status == MR_NO_MATCH)
1014 /* Try canonicalizing the Kerberos principal and trying
1015 * again. If we succeed, print the message from mrcl.
1016 * Otherwise, just pretend we never did this and print
1017 * the original error message.
1019 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
1020 if (mrcl_get_message())
1022 if (mr_query("tag_member_of_list", 4, membervec,
1023 NULL, NULL) == MR_SUCCESS)
1024 mrcl_com_err(whoami);
1025 status = MR_SUCCESS;
1028 if (status != MR_SUCCESS)
1030 com_err(whoami, status, "while changing tag on member %s of %s",
1031 memberstruct->name, listname);
1035 membervec[1] = "MACHINE";
1036 status = mr_query("tag_member_of_list", 4, membervec,
1038 if (status != MR_SUCCESS)
1040 com_err(whoami, status, "while adding member %s to %s",
1041 memberstruct->name, listname);
1047 /* Display the members of the list now, if requested */
1051 recursive_display_list_members();
1054 status = mr_query(showtags ? "get_tagged_members_of_list" :
1055 "get_members_of_list", 1, &listname,
1056 get_list_members, memberlist);
1058 com_err(whoami, status, "while getting members of list %s",
1060 while (sq_get_data(memberlist, &memberstruct))
1061 show_list_member(memberstruct);
1067 exit(success ? 0 : 1);
1070 void usage(char **argv)
1072 #define USAGE_OPTIONS_FORMAT " %-39s%s\n"
1073 fprintf(stderr, "Usage: %s listname [options]\n", argv[0]);
1074 fprintf(stderr, "Options are\n");
1075 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-v | -verbose",
1077 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-m | -members",
1078 "-R | -rename newname");
1079 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-u | -users",
1081 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-l | -lists",
1083 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-s | -strings",
1085 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-k | -kerberos",
1087 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-i | -info",
1089 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-r | -recursive",
1091 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-a | -add member",
1093 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-d | -delete member",
1095 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-al | -addlist filename",
1097 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-dl | -deletelist filename",
1099 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-f | -file filename",
1101 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-at | -addtagged member tag",
1103 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-ct | -changetag member tag",
1105 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-t | -tags",
1106 "-nmm | -notmailman");
1107 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-D | -desc description",
1108 "-ms | -mailman_server server");
1109 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-O | -owner owner",
1110 "-MA | -memacl membership_acl");
1111 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-n | -noauth",
1112 "-db | -database host[:port]");
1117 /* Display the members stored in the queue */
1119 void show_list_member(struct member *memberstruct)
1123 switch (memberstruct->type)
1151 printf("%s\n", memberstruct->name);
1156 printf("%s:%s", s, memberstruct->name);
1159 if (memberstruct->type == M_LIST)
1160 printf("LIST:%s", memberstruct->name);
1161 else if (memberstruct->type == M_KERBEROS)
1162 printf("KERBEROS:%s", memberstruct->name);
1163 else if (memberstruct->type == M_STRING &&
1164 !strchr(memberstruct->name, '@'))
1165 printf("STRING:%s", memberstruct->name);
1166 else if (memberstruct->type == M_MACHINE)
1167 printf("MACHINE:%s", memberstruct->name);
1169 printf("%s", memberstruct->name);
1171 if (showtags && *(memberstruct->tag))
1172 printf(" (%s)\n", memberstruct->tag);
1178 /* Show the retrieved information about a list */
1180 int show_list_info(int argc, char **argv, void *hint)
1182 printf("List: %s\n", argv[L_NAME]);
1183 printf("Description: %s\n", argv[L_DESC]);
1184 printf("Flags: %s, %s, and %s\n",
1185 atoi(argv[L_ACTIVE]) ? "active" : "inactive",
1186 atoi(argv[L_PUBLIC]) ? "public" : "private",
1187 atoi(argv[L_HIDDEN]) ? "hidden" : "visible");
1188 printf("%s is %sa maillist and is %sa group", argv[L_NAME],
1189 atoi(argv[L_MAILLIST]) ? "" : "not ",
1190 atoi(argv[L_GROUP]) ? "" : "not ");
1191 if (atoi(argv[L_GROUP]))
1193 if (atoi(argv[L_NFSGROUP]))
1194 printf(" (and an NFS group)");
1195 printf(" with GID %d\n", atoi(argv[L_GID]));
1199 if (atoi(argv[L_MAILMAN]))
1200 printf("%s is a Mailman list on server %s\n", argv[L_NAME],
1201 argv[L_MAILMAN_SERVER]);
1202 printf("Owner: %s %s\n", argv[L_ACE_TYPE], argv[L_ACE_NAME]);
1203 if (strcmp(argv[L_MEMACE_TYPE], "NONE"))
1204 printf("Membership ACL: %s %s\n", argv[L_MEMACE_TYPE],
1205 argv[L_MEMACE_NAME]);
1206 printf("Last modified by %s with %s on %s\n",
1207 argv[L_MODBY], argv[L_MODWITH], argv[L_MODTIME]);
1212 /* Copy retrieved information about a list into a new argv */
1214 int save_list_info(int argc, char **argv, void *hint)
1216 char **nargv = hint;
1218 for (argc = 0; argc < 16; argc++)
1219 nargv[argc + 1] = strdup(argv[argc]);
1223 /* Show the retrieve list member count */
1225 int show_list_count(int argc, char **argv, void *hint)
1227 printf("Members: %s\n", argv[0]);
1232 /* Recursively find all of the members of listname, and then display them */
1234 void recursive_display_list_members(void)
1236 int status, count, savecount;
1237 struct save_queue *lists, *members;
1238 struct member *m, *m1, *data;
1240 lists = sq_create();
1241 members = sq_create();
1242 m = malloc(sizeof(struct member));
1245 sq_save_data(lists, m);
1247 while (sq_get_data(lists, &m))
1249 sq_destroy(memberlist);
1250 memberlist = sq_create();
1251 status = mr_query("get_members_of_list", 1, &(m->name),
1252 get_list_members, memberlist);
1254 com_err(whoami, status, "while getting members of list %s", m->name);
1255 while (sq_get_data(memberlist, &m1))
1257 if (m1->type == M_LIST)
1258 unique_add_member(lists, m1);
1260 unique_add_member(members, m1);
1263 savecount = count = sq_count_elts(members);
1264 data = malloc(count * sizeof(struct member));
1266 while (sq_get_data(members, &m))
1267 memcpy(&data[count++], m, sizeof(struct member));
1268 qsort(data, count, sizeof(struct member), membercmp);
1269 for (count = 0; count < savecount; count++)
1270 show_list_member(&data[count]);
1274 /* add a struct member to a queue if that member isn't already there. */
1276 void unique_add_member(struct save_queue *q, struct member *m)
1278 struct save_queue *qp;
1280 for (qp = q->q_next; qp != q; qp = qp->q_next)
1282 if (!membercmp(qp->q_data, m))
1289 /* Collect the retrieved members of the list */
1291 int get_list_members(int argc, char **argv, void *sq)
1293 struct save_queue *q = sq;
1296 m = malloc(sizeof(struct member));
1309 m->type = M_KERBEROS;
1312 m->type = M_MACHINE;
1315 m->name = strdup(argv[1]);
1317 m->tag = strdup(argv[2]);
1319 m->tag = strdup("");
1325 /* Open file, parse members from file, and put them on the specified queue */
1326 void get_members_from_file(char *filename, struct save_queue *queue)
1330 struct member *memberstruct;
1332 if (!strcmp(filename, "-"))
1336 in = fopen(filename, "r");
1339 com_err(whoami, errno, "while opening %s for input", filename);
1344 while (fgets(buf, BUFSIZ, in))
1346 if ((memberstruct = parse_member(buf)))
1347 sq_save_data(queue, memberstruct);
1351 com_err(whoami, errno, "while reading from %s", filename);
1357 /* Collect the possible expansions of the alias MAILHUB */
1359 int collect(int argc, char **argv, void *l)
1364 for (i = 0; (*list)[i]; i++)
1366 *list = realloc(*list, (i + 2) * sizeof(char *));
1367 (*list)[i] = strdup(argv[2]);
1368 (*list)[i + 1] = NULL;
1373 /* Parse a line of input, fetching a member. NULL is returned if a member
1374 * is not found. ';' is a comment character.
1377 struct member *parse_member(char *s)
1382 while (*s && isspace(*s))
1385 while (*p && *p != '\n' && *p != ';')
1387 if (isprint(*p) && !isspace(*p))
1394 if (p == s || strlen(s) == 0)
1397 if (!(m = malloc(sizeof(struct member))))
1399 m->tag = strdup("");
1401 if ((p = strchr(s, ':')))
1405 if (!strcasecmp("user", s))
1407 else if (!strcasecmp("list", s))
1409 else if (!strcasecmp("string", s))
1411 else if (!strcasecmp("kerberos", s))
1412 m->type = M_KERBEROS;
1413 else if (!strcasecmp("machine", s))
1414 m->type = M_MACHINE;
1415 else if (!strcasecmp("none", s))
1423 m->name = strdup(m->name);
1427 m->name = strdup(s);
1428 m->type = strcasecmp(s, "none") ? M_ANY : M_NONE;
1435 * This routine two compares members by the following rules:
1436 * 1. A USER is less than a LIST
1437 * 2. A LIST is less than a STRING
1438 * 3. If two members are of the same type, the one alphabetically first
1439 * is less than the other
1440 * It returs < 0 if the first member is less, 0 if they are identical, and
1441 * > 0 if the second member is less (the first member is greater).
1444 int membercmp(const void *mem1, const void *mem2)
1446 const struct member *m1 = mem1, *m2 = mem2;
1448 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
1449 return strcmp(m1->name, m2->name);
1451 return m1->type - m2->type;
1455 int sq_count_elts(struct save_queue *q)
1461 while (sq_get_data(q, &foo))
1466 char *get_username(void)
1470 username = getenv("USER");
1473 username = mrcl_krb_user();
1476 com_err(whoami, 0, "Could not determine username");