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 argv[L_MAILMAN_SERVER + 1] = mailman_server;
507 argv[L_DESC + 1] = desc;
511 if (memacl->type == M_ANY)
513 status = mr_query("get_user_account_by_login", 1,
514 &memacl->name, NULL, NULL);
515 if (status == MR_NO_MATCH)
516 memacl->type = M_LIST;
518 memacl->type = M_USER;
520 argv[L_MEMACE_TYPE + 1] = typename[memacl->type];
521 argv[L_MEMACE_NAME + 1] = memacl->name;
522 if (memacl->type == M_KERBEROS)
524 status = mrcl_validate_kerberos_member(argv[L_MEMACE_NAME + 1],
525 &argv[L_MEMACE_NAME + 1]);
526 if (mrcl_get_message())
527 mrcl_com_err(whoami);
528 if (status == MRCL_REJECT)
535 argv[L_ACE_NAME + 1] = owner->name;
540 argv[L_ACE_TYPE + 1] = "USER";
541 status = mr_query("update_list", 16, argv, NULL, NULL);
542 if (owner->type != M_ANY || status != MR_USER)
546 argv[L_ACE_TYPE + 1] = "LIST";
547 status = mr_query("update_list", 16, argv, NULL, NULL);
551 argv[L_ACE_TYPE + 1] = "KERBEROS";
552 status = mrcl_validate_kerberos_member(argv[L_ACE_NAME + 1],
553 &argv[L_ACE_NAME + 1]);
554 if (mrcl_get_message())
555 mrcl_com_err(whoami);
556 if (status == MRCL_REJECT)
558 status = mr_query("update_list", 16, argv, NULL, NULL);
561 argv[L_ACE_TYPE + 1] = argv[L_ACE_NAME + 1] = "NONE";
562 status = mr_query("update_list", 16, argv, NULL, NULL);
567 status = mr_query("update_list", 16, argv, NULL, NULL);
571 com_err(whoami, status, "while updating list.");
578 /* display list info if requested to */
581 status = mr_query("get_list_info", 1, &listname, show_list_info, NULL);
584 com_err(whoami, status, "while getting list information");
587 if (verbose && !memberflg)
589 status = mr_query("count_members_of_list", 1, &listname,
590 show_list_count, NULL);
593 com_err(whoami, status, "while getting list count");
599 /* if we're synchronizing to a file, we need to:
600 * get the current members of the list
601 * for each member of the sync file
602 * if they are on the list, remove them from the in-memory copy
603 * if they're not on the list, add them to add-list
604 * if anyone is left on the in-memory copy, put them on the delete-list
605 * lastly, reset memberlist so we can use it again later
609 status = mr_query("get_members_of_list", 1, &listname,
610 get_list_members, memberlist);
613 com_err(whoami, status, "getting members of list %s", listname);
616 while (sq_get_data(synclist, &memberstruct))
618 struct save_queue *q;
621 for (q = memberlist->q_next; q != memberlist; q = q->q_next)
623 if (membercmp(q->q_data, memberstruct) == 0)
625 q->q_prev->q_next = q->q_next;
626 q->q_next->q_prev = q->q_prev;
632 sq_save_data(addlist, memberstruct);
634 while (sq_get_data(memberlist, &memberstruct))
635 sq_save_data(dellist, memberstruct);
636 sq_destroy(memberlist);
637 memberlist = sq_create();
640 /* Process the add list */
641 while (sq_get_data(addlist, &memberstruct))
643 /* canonicalize string if necessary */
644 if (memberstruct->type != M_KERBEROS &&
645 (p = strchr(memberstruct->name, '@')))
647 char *host = canonicalize_hostname(strdup(++p));
648 static char **mailhubs = NULL;
657 mailhubs = malloc(sizeof(char *));
659 status = mr_query("get_alias", 3, argv, collect,
661 if (status != MR_SUCCESS && status != MR_NO_MATCH)
663 com_err(whoami, status,
664 " while reading list of MAILHUB servers");
668 for (i = 0; (p = mailhubs[i]); i++)
670 if (!strcasecmp(p, host))
672 host = strdup(memberstruct->name);
673 *(strchr(memberstruct->name, '@')) = 0;
674 if (memberstruct->type == M_STRING)
675 memberstruct->type = M_ANY;
676 fprintf(stderr, "Warning: \"%s\" converted to "
677 "\"%s\" because it is a local name.\n",
678 host, memberstruct->name);
684 /* now continue adding member */
685 membervec[0] = listname;
686 membervec[2] = memberstruct->name;
687 membervec[3] = memberstruct->tag;
690 printf("Adding member ");
691 show_list_member(memberstruct);
693 switch (memberstruct->type)
697 membervec[1] = "USER";
698 status = mr_query("add_tagged_member_to_list", 4, membervec,
700 if (status == MR_SUCCESS)
702 else if (status != MR_USER || memberstruct->type != M_ANY)
704 com_err(whoami, status, "while adding member %s to %s",
705 memberstruct->name, listname);
710 membervec[1] = "LIST";
711 status = mr_query("add_tagged_member_to_list", 4, membervec,
713 if (status == MR_SUCCESS)
715 if (!strcmp(membervec[0], get_username()))
717 fprintf(stderr, "\nWARNING: \"LIST:%s\" was just added "
718 "to list \"%s\".\n", membervec[2], membervec[0]);
719 fprintf(stderr, "If you meant to add yourself to the list "
720 "\"%s\", type:\n", membervec[2]);
721 fprintf(stderr, "\tblanche %s -d %s\t(to undo this)\n",
722 membervec[0], membervec[2]);
723 fprintf(stderr, "\tblanche %s -a %s\t(to add yourself to "
724 "that list)\n", membervec[2], membervec[0]);
728 else if (status != MR_LIST || memberstruct->type != M_ANY)
730 com_err(whoami, status, "while adding member %s to %s",
731 memberstruct->name, listname);
736 status = mrcl_validate_string_member(memberstruct->name);
737 if (memberstruct->type == M_ANY && status == MRCL_WARN)
739 /* if user is trying to add something which isn't a
740 remote string, or a list, or a user, and didn't
741 explicitly specify `STRING:', it's probably a typo */
742 com_err(whoami, MR_NO_MATCH, "while adding member %s to %s",
743 memberstruct->name, listname);
748 mrcl_com_err(whoami);
750 if (status == MRCL_REJECT)
756 membervec[1] = "STRING";
757 status = mr_query("add_tagged_member_to_list", 4, membervec,
759 if (status != MR_SUCCESS)
761 com_err(whoami, status, "while adding member %s to %s",
762 memberstruct->name, listname);
767 membervec[1] = "KERBEROS";
768 status = mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
769 if (mrcl_get_message())
770 mrcl_com_err(whoami);
771 if (status == MRCL_REJECT)
776 status = mr_query("add_tagged_member_to_list", 4, membervec,
778 if (status != MR_SUCCESS)
780 com_err(whoami, status, "while adding member %s to %s",
781 memberstruct->name, listname);
787 membervec[1] = "MACHINE";
788 membervec[2] = canonicalize_hostname(strdup(memberstruct->name));
789 status = mr_query("add_tagged_member_to_list", 4, membervec,
791 if (status != MR_SUCCESS)
793 com_err(whoami, status, "while adding member %s to %s",
794 memberstruct->name, listname);
801 /* Process the delete list */
802 while (sq_get_data(dellist, &memberstruct))
804 membervec[0] = listname;
805 membervec[2] = memberstruct->name;
808 printf("Deleting member ");
809 show_list_member(memberstruct);
811 switch (memberstruct->type)
815 membervec[1] = "USER";
816 status = mr_query("delete_member_from_list", 3, membervec,
818 if (status == MR_SUCCESS)
820 else if ((status != MR_USER && status != MR_NO_MATCH) ||
821 memberstruct->type != M_ANY)
823 com_err(whoami, status, "while deleting member %s from %s",
824 memberstruct->name, listname);
829 membervec[1] = "LIST";
830 status = mr_query("delete_member_from_list", 3, membervec,
832 if (status == MR_SUCCESS)
834 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
835 memberstruct->type != M_ANY)
837 if (status == MR_PERM && memberstruct->type == M_ANY &&
838 !strcmp(membervec[2], get_username()))
840 /* M_ANY means we've fallen through from the user
841 * case. The user is trying to remove himself from
842 * a list, but we got MR_USER or MR_NO_MATCH above,
843 * meaning he's not really on it, and we got MR_PERM
844 * when trying to remove LIST:$USER because he's not
845 * on the acl. That error is useless, so return
846 * MR_NO_MATCH instead. However, this will generate the
847 * wrong error if the user was trying to remove the list
848 * with his username from a list he doesn't administrate
849 * without explicitly specifying "list:".
851 status = MR_NO_MATCH;
853 com_err(whoami, status, "while deleting member %s from %s",
854 memberstruct->name, listname);
859 membervec[1] = "STRING";
860 status = mr_query("delete_member_from_list", 3, membervec,
862 if (status == MR_STRING && memberstruct->type == M_ANY)
864 com_err(whoami, 0, " Unable to find member %s to delete from %s",
865 memberstruct->name, listname);
867 if (!strcmp(membervec[0], get_username()))
869 fprintf(stderr, "(If you were trying to remove yourself "
870 "from the list \"%s\",\n", membervec[2]);
871 fprintf(stderr, "the correct command is \"blanche %s -d "
872 "%s\".)\n", membervec[2], membervec[0]);
875 else if (status != MR_SUCCESS)
877 com_err(whoami, status, "while deleting member %s from %s",
878 memberstruct->name, listname);
883 membervec[1] = "KERBEROS";
884 status = mr_query("delete_member_from_list", 3, membervec,
886 if (status == MR_STRING || status == MR_NO_MATCH)
888 /* Try canonicalizing the Kerberos principal and trying
889 * again. If we succeed, print the message from mrcl.
890 * Otherwise, just pretend we never did this and print
891 * the original error message.
893 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
894 if (mrcl_get_message())
896 if (mr_query("delete_member_from_list", 3, membervec,
897 NULL, NULL) == MR_SUCCESS)
898 mrcl_com_err(whoami);
902 if (status != MR_SUCCESS)
904 com_err(whoami, status, "while deleting member %s from %s",
905 memberstruct->name, listname);
910 membervec[1] = "MACHINE";
911 membervec[2] = canonicalize_hostname(memberstruct->name);
912 status = mr_query("delete_member_from_list", 3, membervec,
914 if (status != MR_SUCCESS)
916 com_err(whoami, status, "while deleting member %s from %s",
917 memberstruct->name, listname);
924 /* Process the tag list */
925 while (sq_get_data(taglist, &memberstruct))
927 membervec[0] = listname;
928 membervec[2] = memberstruct->name;
929 membervec[3] = memberstruct->tag;
932 printf("Tagging member ");
933 show_list_member(memberstruct);
935 switch (memberstruct->type)
939 membervec[1] = "USER";
940 status = mr_query("tag_member_of_list", 4, membervec,
942 if (status == MR_SUCCESS)
944 else if ((status != MR_USER && status != MR_NO_MATCH) ||
945 memberstruct->type != M_ANY)
947 com_err(whoami, status, "while changing tag on member %s of %s",
948 memberstruct->name, listname);
953 membervec[1] = "LIST";
954 status = mr_query("tag_member_of_list", 4, membervec,
956 if (status == MR_SUCCESS)
958 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
959 memberstruct->type != M_ANY)
961 com_err(whoami, status, "while changing tag on member %s of %s",
962 memberstruct->name, listname);
967 membervec[1] = "STRING";
968 status = mr_query("tag_member_of_list", 4, membervec,
970 if (status == MR_STRING && memberstruct->type == M_ANY)
972 com_err(whoami, 0, " Unable to find member %s on list %s",
973 memberstruct->name, listname);
976 else if (status != MR_SUCCESS)
978 com_err(whoami, status, "while retagging member %s on %s",
979 memberstruct->name, listname);
984 membervec[1] = "KERBEROS";
985 status = mr_query("tag_member_of_list", 4, membervec,
987 if (status == MR_STRING || status == MR_NO_MATCH)
989 /* Try canonicalizing the Kerberos principal and trying
990 * again. If we succeed, print the message from mrcl.
991 * Otherwise, just pretend we never did this and print
992 * the original error message.
994 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
995 if (mrcl_get_message())
997 if (mr_query("tag_member_of_list", 4, membervec,
998 NULL, NULL) == MR_SUCCESS)
999 mrcl_com_err(whoami);
1000 status = MR_SUCCESS;
1003 if (status != MR_SUCCESS)
1005 com_err(whoami, status, "while changing tag on member %s of %s",
1006 memberstruct->name, listname);
1012 /* Display the members of the list now, if requested */
1016 recursive_display_list_members();
1019 status = mr_query(showtags ? "get_tagged_members_of_list" :
1020 "get_members_of_list", 1, &listname,
1021 get_list_members, memberlist);
1023 com_err(whoami, status, "while getting members of list %s",
1025 while (sq_get_data(memberlist, &memberstruct))
1026 show_list_member(memberstruct);
1032 exit(success ? 0 : 1);
1035 void usage(char **argv)
1037 #define USAGE_OPTIONS_FORMAT " %-39s%s\n"
1038 fprintf(stderr, "Usage: %s listname [options]\n", argv[0]);
1039 fprintf(stderr, "Options are\n");
1040 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-v | -verbose",
1042 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-m | -members",
1043 "-R | -rename newname");
1044 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-u | -users",
1046 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-l | -lists",
1048 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-s | -strings",
1050 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-k | -kerberos",
1052 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-i | -info",
1054 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-r | -recursive",
1056 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-a | -add member",
1058 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-d | -delete member",
1060 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-al | -addlist filename",
1062 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-dl | -deletelist filename",
1064 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-f | -file filename",
1066 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-at | -addtagged member tag",
1068 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-ct | -changetag member tag",
1070 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-t | -tags",
1071 "-nmm | -notmailman");
1072 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-D | -desc description",
1073 "-ms | -mailman_server server");
1074 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-O | -owner owner",
1075 "-MA | -memacl membership_acl");
1076 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-n | -noauth",
1077 "-db | -database host[:port]");
1082 /* Display the members stored in the queue */
1084 void show_list_member(struct member *memberstruct)
1088 switch (memberstruct->type)
1116 printf("%s\n", memberstruct->name);
1121 printf("%s:%s", s, memberstruct->name);
1124 if (memberstruct->type == M_LIST)
1125 printf("LIST:%s", memberstruct->name);
1126 else if (memberstruct->type == M_KERBEROS)
1127 printf("KERBEROS:%s", memberstruct->name);
1128 else if (memberstruct->type == M_STRING &&
1129 !strchr(memberstruct->name, '@'))
1130 printf("STRING:%s", memberstruct->name);
1131 else if (memberstruct->type == M_MACHINE)
1132 printf("MACHINE:%s", memberstruct->name);
1134 printf("%s", memberstruct->name);
1136 if (showtags && *(memberstruct->tag))
1137 printf(" (%s)\n", memberstruct->tag);
1143 /* Show the retrieved information about a list */
1145 int show_list_info(int argc, char **argv, void *hint)
1147 printf("List: %s\n", argv[L_NAME]);
1148 printf("Description: %s\n", argv[L_DESC]);
1149 printf("Flags: %s, %s, and %s\n",
1150 atoi(argv[L_ACTIVE]) ? "active" : "inactive",
1151 atoi(argv[L_PUBLIC]) ? "public" : "private",
1152 atoi(argv[L_HIDDEN]) ? "hidden" : "visible");
1153 printf("%s is %sa maillist and is %sa group", argv[L_NAME],
1154 atoi(argv[L_MAILLIST]) ? "" : "not ",
1155 atoi(argv[L_GROUP]) ? "" : "not ");
1156 if (atoi(argv[L_GROUP]))
1158 if (atoi(argv[L_NFSGROUP]))
1159 printf(" (and an NFS group)");
1160 printf(" with GID %d\n", atoi(argv[L_GID]));
1164 if (atoi(argv[L_MAILMAN]))
1165 printf("%s is a Mailman list on server %s\n", argv[L_NAME],
1166 argv[L_MAILMAN_SERVER]);
1167 printf("Owner: %s %s\n", argv[L_ACE_TYPE], argv[L_ACE_NAME]);
1168 if (strcmp(argv[L_MEMACE_TYPE], "NONE"))
1169 printf("Membership ACL: %s %s\n", argv[L_MEMACE_TYPE],
1170 argv[L_MEMACE_NAME]);
1171 printf("Last modified by %s with %s on %s\n",
1172 argv[L_MODBY], argv[L_MODWITH], argv[L_MODTIME]);
1177 /* Copy retrieved information about a list into a new argv */
1179 int save_list_info(int argc, char **argv, void *hint)
1181 char **nargv = hint;
1183 for (argc = 0; argc < 16; argc++)
1184 nargv[argc + 1] = strdup(argv[argc]);
1188 /* Show the retrieve list member count */
1190 int show_list_count(int argc, char **argv, void *hint)
1192 printf("Members: %s\n", argv[0]);
1197 /* Recursively find all of the members of listname, and then display them */
1199 void recursive_display_list_members(void)
1201 int status, count, savecount;
1202 struct save_queue *lists, *members;
1203 struct member *m, *m1, *data;
1205 lists = sq_create();
1206 members = sq_create();
1207 m = malloc(sizeof(struct member));
1210 sq_save_data(lists, m);
1212 while (sq_get_data(lists, &m))
1214 sq_destroy(memberlist);
1215 memberlist = sq_create();
1216 status = mr_query("get_members_of_list", 1, &(m->name),
1217 get_list_members, memberlist);
1219 com_err(whoami, status, "while getting members of list %s", m->name);
1220 while (sq_get_data(memberlist, &m1))
1222 if (m1->type == M_LIST)
1223 unique_add_member(lists, m1);
1225 unique_add_member(members, m1);
1228 savecount = count = sq_count_elts(members);
1229 data = malloc(count * sizeof(struct member));
1231 while (sq_get_data(members, &m))
1232 memcpy(&data[count++], m, sizeof(struct member));
1233 qsort(data, count, sizeof(struct member), membercmp);
1234 for (count = 0; count < savecount; count++)
1235 show_list_member(&data[count]);
1239 /* add a struct member to a queue if that member isn't already there. */
1241 void unique_add_member(struct save_queue *q, struct member *m)
1243 struct save_queue *qp;
1245 for (qp = q->q_next; qp != q; qp = qp->q_next)
1247 if (!membercmp(qp->q_data, m))
1254 /* Collect the retrieved members of the list */
1256 int get_list_members(int argc, char **argv, void *sq)
1258 struct save_queue *q = sq;
1261 m = malloc(sizeof(struct member));
1274 m->type = M_KERBEROS;
1277 m->type = M_MACHINE;
1280 m->name = strdup(argv[1]);
1282 m->tag = strdup(argv[2]);
1284 m->tag = strdup("");
1290 /* Open file, parse members from file, and put them on the specified queue */
1291 void get_members_from_file(char *filename, struct save_queue *queue)
1295 struct member *memberstruct;
1297 if (!strcmp(filename, "-"))
1301 in = fopen(filename, "r");
1304 com_err(whoami, errno, "while opening %s for input", filename);
1309 while (fgets(buf, BUFSIZ, in))
1311 if ((memberstruct = parse_member(buf)))
1312 sq_save_data(queue, memberstruct);
1316 com_err(whoami, errno, "while reading from %s", filename);
1322 /* Collect the possible expansions of the alias MAILHUB */
1324 int collect(int argc, char **argv, void *l)
1329 for (i = 0; (*list)[i]; i++)
1331 *list = realloc(*list, (i + 2) * sizeof(char *));
1332 (*list)[i] = strdup(argv[2]);
1333 (*list)[i + 1] = NULL;
1338 /* Parse a line of input, fetching a member. NULL is returned if a member
1339 * is not found. ';' is a comment character.
1342 struct member *parse_member(char *s)
1347 while (*s && isspace(*s))
1350 while (*p && *p != '\n' && *p != ';')
1352 if (isprint(*p) && !isspace(*p))
1359 if (p == s || strlen(s) == 0)
1362 if (!(m = malloc(sizeof(struct member))))
1364 m->tag = strdup("");
1366 if ((p = strchr(s, ':')))
1370 if (!strcasecmp("user", s))
1372 else if (!strcasecmp("list", s))
1374 else if (!strcasecmp("string", s))
1376 else if (!strcasecmp("kerberos", s))
1377 m->type = M_KERBEROS;
1378 else if (!strcasecmp("machine", s))
1379 m->type = M_MACHINE;
1380 else if (!strcasecmp("none", s))
1388 m->name = strdup(m->name);
1392 m->name = strdup(s);
1393 m->type = strcasecmp(s, "none") ? M_ANY : M_NONE;
1400 * This routine two compares members by the following rules:
1401 * 1. A USER is less than a LIST
1402 * 2. A LIST is less than a STRING
1403 * 3. If two members are of the same type, the one alphabetically first
1404 * is less than the other
1405 * It returs < 0 if the first member is less, 0 if they are identical, and
1406 * > 0 if the second member is less (the first member is greater).
1409 int membercmp(const void *mem1, const void *mem2)
1411 const struct member *m1 = mem1, *m2 = mem2;
1413 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
1414 return strcmp(m1->name, m2->name);
1416 return m1->type - m2->type;
1420 int sq_count_elts(struct save_queue *q)
1426 while (sq_get_data(q, &foo))
1431 char *get_username(void)
1435 username = getenv("USER");
1438 username = mrcl_krb_user();
1441 com_err(whoami, 0, "Could not determine username");