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))
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);
1037 /* Display the members of the list now, if requested */
1041 recursive_display_list_members();
1044 status = mr_query(showtags ? "get_tagged_members_of_list" :
1045 "get_members_of_list", 1, &listname,
1046 get_list_members, memberlist);
1048 com_err(whoami, status, "while getting members of list %s",
1050 while (sq_get_data(memberlist, &memberstruct))
1051 show_list_member(memberstruct);
1057 exit(success ? 0 : 1);
1060 void usage(char **argv)
1062 #define USAGE_OPTIONS_FORMAT " %-39s%s\n"
1063 fprintf(stderr, "Usage: %s listname [options]\n", argv[0]);
1064 fprintf(stderr, "Options are\n");
1065 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-v | -verbose",
1067 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-m | -members",
1068 "-R | -rename newname");
1069 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-u | -users",
1071 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-l | -lists",
1073 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-s | -strings",
1075 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-k | -kerberos",
1077 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-i | -info",
1079 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-r | -recursive",
1081 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-a | -add member",
1083 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-d | -delete member",
1085 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-al | -addlist filename",
1087 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-dl | -deletelist filename",
1089 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-f | -file filename",
1091 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-at | -addtagged member tag",
1093 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-ct | -changetag member tag",
1095 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-t | -tags",
1096 "-nmm | -notmailman");
1097 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-D | -desc description",
1098 "-ms | -mailman_server server");
1099 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-O | -owner owner",
1100 "-MA | -memacl membership_acl");
1101 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-n | -noauth",
1102 "-db | -database host[:port]");
1107 /* Display the members stored in the queue */
1109 void show_list_member(struct member *memberstruct)
1113 switch (memberstruct->type)
1141 printf("%s\n", memberstruct->name);
1146 printf("%s:%s", s, memberstruct->name);
1149 if (memberstruct->type == M_LIST)
1150 printf("LIST:%s", memberstruct->name);
1151 else if (memberstruct->type == M_KERBEROS)
1152 printf("KERBEROS:%s", memberstruct->name);
1153 else if (memberstruct->type == M_STRING &&
1154 !strchr(memberstruct->name, '@'))
1155 printf("STRING:%s", memberstruct->name);
1156 else if (memberstruct->type == M_MACHINE)
1157 printf("MACHINE:%s", memberstruct->name);
1159 printf("%s", memberstruct->name);
1161 if (showtags && *(memberstruct->tag))
1162 printf(" (%s)\n", memberstruct->tag);
1168 /* Show the retrieved information about a list */
1170 int show_list_info(int argc, char **argv, void *hint)
1172 printf("List: %s\n", argv[L_NAME]);
1173 printf("Description: %s\n", argv[L_DESC]);
1174 printf("Flags: %s, %s, and %s\n",
1175 atoi(argv[L_ACTIVE]) ? "active" : "inactive",
1176 atoi(argv[L_PUBLIC]) ? "public" : "private",
1177 atoi(argv[L_HIDDEN]) ? "hidden" : "visible");
1178 printf("%s is %sa maillist and is %sa group", argv[L_NAME],
1179 atoi(argv[L_MAILLIST]) ? "" : "not ",
1180 atoi(argv[L_GROUP]) ? "" : "not ");
1181 if (atoi(argv[L_GROUP]))
1183 if (atoi(argv[L_NFSGROUP]))
1184 printf(" (and an NFS group)");
1185 printf(" with GID %d\n", atoi(argv[L_GID]));
1189 if (atoi(argv[L_MAILMAN]))
1190 printf("%s is a Mailman list on server %s\n", argv[L_NAME],
1191 argv[L_MAILMAN_SERVER]);
1192 printf("Owner: %s %s\n", argv[L_ACE_TYPE], argv[L_ACE_NAME]);
1193 if (strcmp(argv[L_MEMACE_TYPE], "NONE"))
1194 printf("Membership ACL: %s %s\n", argv[L_MEMACE_TYPE],
1195 argv[L_MEMACE_NAME]);
1196 printf("Last modified by %s with %s on %s\n",
1197 argv[L_MODBY], argv[L_MODWITH], argv[L_MODTIME]);
1202 /* Copy retrieved information about a list into a new argv */
1204 int save_list_info(int argc, char **argv, void *hint)
1206 char **nargv = hint;
1208 for (argc = 0; argc < 16; argc++)
1209 nargv[argc + 1] = strdup(argv[argc]);
1213 /* Show the retrieve list member count */
1215 int show_list_count(int argc, char **argv, void *hint)
1217 printf("Members: %s\n", argv[0]);
1222 /* Recursively find all of the members of listname, and then display them */
1224 void recursive_display_list_members(void)
1226 int status, count, savecount;
1227 struct save_queue *lists, *members;
1228 struct member *m, *m1, *data;
1230 lists = sq_create();
1231 members = sq_create();
1232 m = malloc(sizeof(struct member));
1235 sq_save_data(lists, m);
1237 while (sq_get_data(lists, &m))
1239 sq_destroy(memberlist);
1240 memberlist = sq_create();
1241 status = mr_query("get_members_of_list", 1, &(m->name),
1242 get_list_members, memberlist);
1244 com_err(whoami, status, "while getting members of list %s", m->name);
1245 while (sq_get_data(memberlist, &m1))
1247 if (m1->type == M_LIST)
1248 unique_add_member(lists, m1);
1250 unique_add_member(members, m1);
1253 savecount = count = sq_count_elts(members);
1254 data = malloc(count * sizeof(struct member));
1256 while (sq_get_data(members, &m))
1257 memcpy(&data[count++], m, sizeof(struct member));
1258 qsort(data, count, sizeof(struct member), membercmp);
1259 for (count = 0; count < savecount; count++)
1260 show_list_member(&data[count]);
1264 /* add a struct member to a queue if that member isn't already there. */
1266 void unique_add_member(struct save_queue *q, struct member *m)
1268 struct save_queue *qp;
1270 for (qp = q->q_next; qp != q; qp = qp->q_next)
1272 if (!membercmp(qp->q_data, m))
1279 /* Collect the retrieved members of the list */
1281 int get_list_members(int argc, char **argv, void *sq)
1283 struct save_queue *q = sq;
1286 m = malloc(sizeof(struct member));
1299 m->type = M_KERBEROS;
1302 m->type = M_MACHINE;
1305 m->name = strdup(argv[1]);
1307 m->tag = strdup(argv[2]);
1309 m->tag = strdup("");
1315 /* Open file, parse members from file, and put them on the specified queue */
1316 void get_members_from_file(char *filename, struct save_queue *queue)
1320 struct member *memberstruct;
1322 if (!strcmp(filename, "-"))
1326 in = fopen(filename, "r");
1329 com_err(whoami, errno, "while opening %s for input", filename);
1334 while (fgets(buf, BUFSIZ, in))
1336 if ((memberstruct = parse_member(buf)))
1337 sq_save_data(queue, memberstruct);
1341 com_err(whoami, errno, "while reading from %s", filename);
1347 /* Collect the possible expansions of the alias MAILHUB */
1349 int collect(int argc, char **argv, void *l)
1354 for (i = 0; (*list)[i]; i++)
1356 *list = realloc(*list, (i + 2) * sizeof(char *));
1357 (*list)[i] = strdup(argv[2]);
1358 (*list)[i + 1] = NULL;
1363 /* Parse a line of input, fetching a member. NULL is returned if a member
1364 * is not found. ';' is a comment character.
1367 struct member *parse_member(char *s)
1372 while (*s && isspace(*s))
1375 while (*p && *p != '\n' && *p != ';')
1377 if (isprint(*p) && !isspace(*p))
1384 if (p == s || strlen(s) == 0)
1387 if (!(m = malloc(sizeof(struct member))))
1389 m->tag = strdup("");
1391 if ((p = strchr(s, ':')))
1395 if (!strcasecmp("user", s))
1397 else if (!strcasecmp("list", s))
1399 else if (!strcasecmp("string", s))
1401 else if (!strcasecmp("kerberos", s))
1402 m->type = M_KERBEROS;
1403 else if (!strcasecmp("machine", s))
1404 m->type = M_MACHINE;
1405 else if (!strcasecmp("none", s))
1413 m->name = strdup(m->name);
1417 m->name = strdup(s);
1418 m->type = strcasecmp(s, "none") ? M_ANY : M_NONE;
1425 * This routine two compares members by the following rules:
1426 * 1. A USER is less than a LIST
1427 * 2. A LIST is less than a STRING
1428 * 3. If two members are of the same type, the one alphabetically first
1429 * is less than the other
1430 * It returs < 0 if the first member is less, 0 if they are identical, and
1431 * > 0 if the second member is less (the first member is greater).
1434 int membercmp(const void *mem1, const void *mem2)
1436 const struct member *m1 = mem1, *m2 = mem2;
1438 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
1439 return strcmp(m1->name, m2->name);
1441 return m1->type - m2->type;
1445 int sq_count_elts(struct save_queue *q)
1451 while (sq_get_data(q, &foo))
1456 char *get_username(void)
1460 username = getenv("USER");
1463 username = mrcl_krb_user();
1466 com_err(whoami, 0, "Could not determine username");