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 delete list */
666 while (sq_get_data(dellist, &memberstruct))
668 membervec[0] = listname;
669 membervec[2] = memberstruct->name;
672 printf("Deleting member ");
673 show_list_member(memberstruct);
675 switch (memberstruct->type)
679 membervec[1] = "USER";
680 status = mr_query("delete_member_from_list", 3, membervec,
682 if (status == MR_SUCCESS)
684 else if ((status != MR_USER && status != MR_NO_MATCH) ||
685 memberstruct->type != M_ANY)
687 com_err(whoami, status, "while deleting member %s from %s",
688 memberstruct->name, listname);
693 membervec[1] = "LIST";
694 status = mr_query("delete_member_from_list", 3, membervec,
696 if (status == MR_SUCCESS)
698 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
699 memberstruct->type != M_ANY)
701 if (status == MR_PERM && memberstruct->type == M_ANY &&
702 !strcmp(membervec[2], get_username()))
704 /* M_ANY means we've fallen through from the user
705 * case. The user is trying to remove himself from a
706 * list, but we got MR_USER or MR_NO_MATCH above,
707 * meaning he's not really on it, and we got MR_PERM
708 * when trying to remove LIST:$USER because he's not
709 * on the acl. That error is useless, so return
710 * MR_NO_MATCH instead. However, this will generate
711 * the wrong error if the user was trying to remove
712 * the list with his username from a list he doesn't
713 * administrate without explicitly specifying
716 status = MR_NO_MATCH;
718 com_err(whoami, status, "while deleting member %s from %s",
719 memberstruct->name, listname);
724 membervec[1] = "STRING";
725 status = mr_query("delete_member_from_list", 3, membervec,
727 if (status == MR_STRING && memberstruct->type == M_ANY)
729 com_err(whoami, 0, " Unable to find member %s to delete from %s",
730 memberstruct->name, listname);
732 if (!strcmp(membervec[0], get_username()))
734 fprintf(stderr, "(If you were trying to remove yourself "
735 "from the list \"%s\",\n", membervec[2]);
736 fprintf(stderr, "the correct command is \"blanche %s -d "
737 "%s\".)\n", membervec[2], membervec[0]);
740 else if (status != MR_SUCCESS)
742 com_err(whoami, status, "while deleting member %s from %s",
743 memberstruct->name, listname);
748 membervec[1] = "KERBEROS";
749 status = mr_query("delete_member_from_list", 3, membervec,
751 if (status == MR_STRING || status == MR_NO_MATCH)
753 /* Try canonicalizing the Kerberos principal and trying
754 * again. If we succeed, print the message from mrcl.
755 * Otherwise, just pretend we never did this and print
756 * the original error message.
758 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
759 if (mrcl_get_message())
761 if (mr_query("delete_member_from_list", 3, membervec,
762 NULL, NULL) == MR_SUCCESS)
763 mrcl_com_err(whoami);
767 if (status != MR_SUCCESS)
769 com_err(whoami, status, "while deleting member %s from %s",
770 memberstruct->name, listname);
775 membervec[1] = "MACHINE";
776 membervec[2] = canonicalize_hostname(memberstruct->name);
777 status = mr_query("delete_member_from_list", 3, membervec,
779 if (status != MR_SUCCESS)
781 com_err(whoami, status, "while deleting member %s from %s",
782 memberstruct->name, listname);
789 /* Process the add list */
790 while (sq_get_data(addlist, &memberstruct))
792 /* canonicalize string if necessary */
793 if (memberstruct->type != M_KERBEROS &&
794 (p = strchr(memberstruct->name, '@')))
796 char *host = canonicalize_hostname(strdup(++p));
797 static char **mailhubs = NULL;
806 mailhubs = malloc(sizeof(char *));
808 status = mr_query("get_alias", 3, argv, collect,
810 if (status != MR_SUCCESS && status != MR_NO_MATCH)
812 com_err(whoami, status,
813 " while reading list of MAILHUB servers");
817 for (i = 0; (p = mailhubs[i]); i++)
819 if (!strcasecmp(p, host))
821 host = strdup(memberstruct->name);
822 *(strchr(memberstruct->name, '@')) = 0;
823 if (memberstruct->type == M_STRING)
824 memberstruct->type = M_ANY;
825 fprintf(stderr, "Warning: \"%s\" converted to "
826 "\"%s\" because it is a local name.\n",
827 host, memberstruct->name);
833 /* now continue adding member */
834 membervec[0] = listname;
835 membervec[2] = memberstruct->name;
836 membervec[3] = memberstruct->tag;
839 printf("Adding member ");
840 show_list_member(memberstruct);
842 switch (memberstruct->type)
846 membervec[1] = "USER";
847 status = mr_query("add_tagged_member_to_list", 4, membervec,
849 if (status == MR_SUCCESS)
851 else if (status != MR_USER || memberstruct->type != M_ANY)
853 com_err(whoami, status, "while adding member %s to %s",
854 memberstruct->name, listname);
859 membervec[1] = "LIST";
860 status = mr_query("add_tagged_member_to_list", 4, membervec,
862 if (status == MR_SUCCESS)
864 if (!strcmp(membervec[0], get_username()))
866 fprintf(stderr, "\nWARNING: \"LIST:%s\" was just added "
867 "to list \"%s\".\n", membervec[2], membervec[0]);
868 fprintf(stderr, "If you meant to add yourself to the list "
869 "\"%s\", type:\n", membervec[2]);
870 fprintf(stderr, "\tblanche %s -d %s\t(to undo this)\n",
871 membervec[0], membervec[2]);
872 fprintf(stderr, "\tblanche %s -a %s\t(to add yourself to "
873 "that list)\n", membervec[2], membervec[0]);
877 else if (status != MR_LIST || memberstruct->type != M_ANY)
879 com_err(whoami, status, "while adding member %s to %s",
880 memberstruct->name, listname);
885 status = mrcl_validate_string_member(memberstruct->name);
886 if (memberstruct->type == M_ANY && status == MRCL_WARN)
888 /* if user is trying to add something which isn't a
889 remote string, or a list, or a user, and didn't
890 explicitly specify `STRING:', it's probably a typo */
891 com_err(whoami, MR_NO_MATCH, "while adding member %s to %s",
892 memberstruct->name, listname);
897 mrcl_com_err(whoami);
899 if (status == MRCL_REJECT)
905 membervec[1] = "STRING";
906 status = mr_query("add_tagged_member_to_list", 4, membervec,
908 if (status != MR_SUCCESS)
910 com_err(whoami, status, "while adding member %s to %s",
911 memberstruct->name, listname);
916 membervec[1] = "KERBEROS";
917 status = mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
918 if (mrcl_get_message())
919 mrcl_com_err(whoami);
920 if (status == MRCL_REJECT)
925 status = mr_query("add_tagged_member_to_list", 4, membervec,
927 if (status != MR_SUCCESS)
929 com_err(whoami, status, "while adding member %s to %s",
930 memberstruct->name, listname);
936 membervec[1] = "MACHINE";
937 membervec[2] = canonicalize_hostname(strdup(memberstruct->name));
938 status = mr_query("add_tagged_member_to_list", 4, membervec,
940 if (status != MR_SUCCESS)
942 com_err(whoami, status, "while adding member %s to %s",
943 memberstruct->name, listname);
950 /* Process the tag list */
951 while (sq_get_data(taglist, &memberstruct))
953 membervec[0] = listname;
954 membervec[2] = memberstruct->name;
955 membervec[3] = memberstruct->tag;
958 printf("Tagging member ");
959 show_list_member(memberstruct);
961 switch (memberstruct->type)
965 membervec[1] = "USER";
966 status = mr_query("tag_member_of_list", 4, membervec,
968 if (status == MR_SUCCESS)
970 else if ((status != MR_USER && status != MR_NO_MATCH) ||
971 memberstruct->type != M_ANY)
973 com_err(whoami, status, "while changing tag on member %s of %s",
974 memberstruct->name, listname);
979 membervec[1] = "LIST";
980 status = mr_query("tag_member_of_list", 4, membervec,
982 if (status == MR_SUCCESS)
984 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
985 memberstruct->type != M_ANY)
987 com_err(whoami, status, "while changing tag on member %s of %s",
988 memberstruct->name, listname);
993 membervec[1] = "STRING";
994 status = mr_query("tag_member_of_list", 4, membervec,
996 if (status == MR_STRING && memberstruct->type == M_ANY)
998 com_err(whoami, 0, " Unable to find member %s on list %s",
999 memberstruct->name, listname);
1002 else if (status != MR_SUCCESS)
1004 com_err(whoami, status, "while retagging member %s on %s",
1005 memberstruct->name, listname);
1010 membervec[1] = "KERBEROS";
1011 status = mr_query("tag_member_of_list", 4, membervec,
1013 if (status == MR_STRING || status == MR_NO_MATCH)
1015 /* Try canonicalizing the Kerberos principal and trying
1016 * again. If we succeed, print the message from mrcl.
1017 * Otherwise, just pretend we never did this and print
1018 * the original error message.
1020 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
1021 if (mrcl_get_message())
1023 if (mr_query("tag_member_of_list", 4, membervec,
1024 NULL, NULL) == MR_SUCCESS)
1025 mrcl_com_err(whoami);
1026 status = MR_SUCCESS;
1029 if (status != MR_SUCCESS)
1031 com_err(whoami, status, "while changing tag on member %s of %s",
1032 memberstruct->name, listname);
1036 membervec[1] = "MACHINE";
1037 status = mr_query("tag_member_of_list", 4, membervec,
1039 if (status != MR_SUCCESS)
1041 com_err(whoami, status, "while adding member %s to %s",
1042 memberstruct->name, listname);
1048 /* Display the members of the list now, if requested */
1052 recursive_display_list_members();
1055 status = mr_query(showtags ? "get_tagged_members_of_list" :
1056 "get_members_of_list", 1, &listname,
1057 get_list_members, memberlist);
1059 com_err(whoami, status, "while getting members of list %s",
1061 while (sq_get_data(memberlist, &memberstruct))
1062 show_list_member(memberstruct);
1068 exit(success ? 0 : 1);
1071 void usage(char **argv)
1073 #define USAGE_OPTIONS_FORMAT " %-39s%s\n"
1074 fprintf(stderr, "Usage: %s listname [options]\n", argv[0]);
1075 fprintf(stderr, "Options are\n");
1076 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-v | -verbose",
1078 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-m | -members",
1079 "-R | -rename newname");
1080 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-u | -users",
1082 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-l | -lists",
1084 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-s | -strings",
1086 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-k | -kerberos",
1088 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-i | -info",
1090 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-r | -recursive",
1092 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-a | -add member",
1094 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-d | -delete member",
1096 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-al | -addlist filename",
1098 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-dl | -deletelist filename",
1100 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-f | -file filename",
1102 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-at | -addtagged member tag",
1104 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-ct | -changetag member tag",
1106 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-t | -tags",
1107 "-nmm | -notmailman");
1108 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-D | -desc description",
1109 "-ms | -mailman_server server");
1110 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-O | -owner owner",
1111 "-MA | -memacl membership_acl");
1112 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-n | -noauth",
1113 "-db | -database host[:port]");
1118 /* Display the members stored in the queue */
1120 void show_list_member(struct member *memberstruct)
1124 switch (memberstruct->type)
1152 printf("%s\n", memberstruct->name);
1157 printf("%s:%s", s, memberstruct->name);
1160 if (memberstruct->type == M_LIST)
1161 printf("LIST:%s", memberstruct->name);
1162 else if (memberstruct->type == M_KERBEROS)
1163 printf("KERBEROS:%s", memberstruct->name);
1164 else if (memberstruct->type == M_STRING &&
1165 !strchr(memberstruct->name, '@'))
1166 printf("STRING:%s", memberstruct->name);
1167 else if (memberstruct->type == M_MACHINE)
1168 printf("MACHINE:%s", memberstruct->name);
1170 printf("%s", memberstruct->name);
1172 if (showtags && *(memberstruct->tag))
1173 printf(" (%s)\n", memberstruct->tag);
1179 /* Show the retrieved information about a list */
1181 int show_list_info(int argc, char **argv, void *hint)
1183 printf("List: %s\n", argv[L_NAME]);
1184 printf("Description: %s\n", argv[L_DESC]);
1185 printf("Flags: %s, %s, and %s\n",
1186 atoi(argv[L_ACTIVE]) ? "active" : "inactive",
1187 atoi(argv[L_PUBLIC]) ? "public" : "private",
1188 atoi(argv[L_HIDDEN]) ? "hidden" : "visible");
1189 printf("%s is %sa maillist and is %sa group", argv[L_NAME],
1190 atoi(argv[L_MAILLIST]) ? "" : "not ",
1191 atoi(argv[L_GROUP]) ? "" : "not ");
1192 if (atoi(argv[L_GROUP]))
1194 if (atoi(argv[L_NFSGROUP]))
1195 printf(" (and an NFS group)");
1196 printf(" with GID %d\n", atoi(argv[L_GID]));
1200 if (atoi(argv[L_MAILMAN]))
1201 printf("%s is a Mailman list on server %s\n", argv[L_NAME],
1202 argv[L_MAILMAN_SERVER]);
1203 printf("Owner: %s %s\n", argv[L_ACE_TYPE], argv[L_ACE_NAME]);
1204 if (strcmp(argv[L_MEMACE_TYPE], "NONE"))
1205 printf("Membership ACL: %s %s\n", argv[L_MEMACE_TYPE],
1206 argv[L_MEMACE_NAME]);
1207 printf("Last modified by %s with %s on %s\n",
1208 argv[L_MODBY], argv[L_MODWITH], argv[L_MODTIME]);
1213 /* Copy retrieved information about a list into a new argv */
1215 int save_list_info(int argc, char **argv, void *hint)
1217 char **nargv = hint;
1219 for (argc = 0; argc < 16; argc++)
1220 nargv[argc + 1] = strdup(argv[argc]);
1224 /* Show the retrieve list member count */
1226 int show_list_count(int argc, char **argv, void *hint)
1228 printf("Members: %s\n", argv[0]);
1233 /* Recursively find all of the members of listname, and then display them */
1235 void recursive_display_list_members(void)
1237 int status, count, savecount;
1238 struct save_queue *lists, *members;
1239 struct member *m, *m1, *data;
1241 lists = sq_create();
1242 members = sq_create();
1243 m = malloc(sizeof(struct member));
1246 sq_save_data(lists, m);
1248 while (sq_get_data(lists, &m))
1250 sq_destroy(memberlist);
1251 memberlist = sq_create();
1252 status = mr_query("get_members_of_list", 1, &(m->name),
1253 get_list_members, memberlist);
1255 com_err(whoami, status, "while getting members of list %s", m->name);
1256 while (sq_get_data(memberlist, &m1))
1258 if (m1->type == M_LIST)
1259 unique_add_member(lists, m1);
1261 unique_add_member(members, m1);
1264 savecount = count = sq_count_elts(members);
1265 data = malloc(count * sizeof(struct member));
1267 while (sq_get_data(members, &m))
1268 memcpy(&data[count++], m, sizeof(struct member));
1269 qsort(data, count, sizeof(struct member), membercmp);
1270 for (count = 0; count < savecount; count++)
1271 show_list_member(&data[count]);
1275 /* add a struct member to a queue if that member isn't already there. */
1277 void unique_add_member(struct save_queue *q, struct member *m)
1279 struct save_queue *qp;
1281 for (qp = q->q_next; qp != q; qp = qp->q_next)
1283 if (!membercmp(qp->q_data, m))
1290 /* Collect the retrieved members of the list */
1292 int get_list_members(int argc, char **argv, void *sq)
1294 struct save_queue *q = sq;
1297 m = malloc(sizeof(struct member));
1310 m->type = M_KERBEROS;
1313 m->type = M_MACHINE;
1316 m->name = strdup(argv[1]);
1318 m->tag = strdup(argv[2]);
1320 m->tag = strdup("");
1326 /* Open file, parse members from file, and put them on the specified queue */
1327 void get_members_from_file(char *filename, struct save_queue *queue)
1331 struct member *memberstruct;
1333 if (!strcmp(filename, "-"))
1337 in = fopen(filename, "r");
1340 com_err(whoami, errno, "while opening %s for input", filename);
1345 while (fgets(buf, BUFSIZ, in))
1347 if ((memberstruct = parse_member(buf)))
1348 sq_save_data(queue, memberstruct);
1352 com_err(whoami, errno, "while reading from %s", filename);
1358 /* Collect the possible expansions of the alias MAILHUB */
1360 int collect(int argc, char **argv, void *l)
1365 for (i = 0; (*list)[i]; i++)
1367 *list = realloc(*list, (i + 2) * sizeof(char *));
1368 (*list)[i] = strdup(argv[2]);
1369 (*list)[i + 1] = NULL;
1374 /* Parse a line of input, fetching a member. NULL is returned if a member
1375 * is not found. ';' is a comment character.
1378 struct member *parse_member(char *s)
1383 while (*s && isspace(*s))
1386 while (*p && *p != '\n' && *p != ';')
1388 if (isprint(*p) && !isspace(*p))
1395 if (p == s || strlen(s) == 0)
1398 if (!(m = malloc(sizeof(struct member))))
1400 m->tag = strdup("");
1402 if ((p = strchr(s, ':')))
1406 if (!strcasecmp("user", s))
1408 else if (!strcasecmp("list", s))
1410 else if (!strcasecmp("string", s))
1412 else if (!strcasecmp("kerberos", s))
1413 m->type = M_KERBEROS;
1414 else if (!strcasecmp("machine", s))
1415 m->type = M_MACHINE;
1416 else if (!strcasecmp("none", s))
1424 m->name = strdup(m->name);
1428 m->name = strdup(s);
1429 m->type = strcasecmp(s, "none") ? M_ANY : M_NONE;
1436 * This routine two compares members by the following rules:
1437 * 1. A USER is less than a LIST
1438 * 2. A LIST is less than a STRING
1439 * 3. If two members are of the same type, the one alphabetically first
1440 * is less than the other
1441 * It returs < 0 if the first member is less, 0 if they are identical, and
1442 * > 0 if the second member is less (the first member is greater).
1445 int membercmp(const void *mem1, const void *mem2)
1447 const struct member *m1 = mem1, *m2 = mem2;
1449 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
1450 return strcmp(m1->name, m2->name);
1452 return m1->type - m2->type;
1456 int sq_count_elts(struct save_queue *q)
1462 while (sq_get_data(q, &foo))
1467 char *get_username(void)
1471 username = getenv("USER");
1474 username = mrcl_krb_user();
1477 com_err(whoami, 0, "Could not determine username");