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 */
38 char *typename[] = { "ANY", "USER", "LIST", "STRING", "KERBEROS", "NONE" };
40 /* argument parsing macro */
41 #define argis(a, b) (!strcmp(*arg + 1, a) || !strcmp(*arg + 1, b))
43 /* flags from command line */
44 int infoflg, verbose, syncflg, memberflg, recursflg, noauth;
45 int showusers, showstrings, showkerberos, showlists, showtags;
46 int createflag, setinfo, active, public, hidden, maillist, grouplist;
48 struct member *owner, *memacl;
51 /* various member lists */
52 struct save_queue *addlist, *dellist, *memberlist, *synclist, *taglist;
54 char *listname, *whoami;
56 void usage(char **argv);
57 void show_list_member(struct member *memberstruct);
58 int show_list_info(int argc, char **argv, void *hint);
59 int save_list_info(int argc, char **argv, void *hint);
60 int show_list_count(int argc, char **argv, void *hint);
61 void recursive_display_list_members(void);
62 void unique_add_member(struct save_queue *q, struct member *m);
63 int get_list_members(int argc, char **argv, void *sq);
64 void get_members_from_file(char *filename, struct save_queue *queue);
65 int collect(int argc, char **argv, void *l);
66 struct member *parse_member(char *s);
67 int membercmp(const void *mem1, const void *mem2);
68 int sq_count_elts(struct save_queue *q);
69 char *get_username(void);
71 int main(int argc, char **argv)
76 struct member *memberstruct;
77 char *server = NULL, *p;
79 /* clear all flags & lists */
80 infoflg = verbose = syncflg = memberflg = recursflg = 0;
81 noauth = showusers = showstrings = showkerberos = showlists = 0;
82 createflag = setinfo = 0;
83 active = public = hidden = maillist = grouplist = nfsgroup = -1;
84 listname = newname = desc = NULL;
87 addlist = sq_create();
88 dellist = sq_create();
89 memberlist = sq_create();
90 synclist = sq_create();
91 taglist = sq_create();
96 /* parse args, building addlist, dellist, & synclist */
97 while (++arg - argv < argc)
101 if (argis("m", "members"))
103 else if (argis("u", "users"))
105 else if (argis("s", "strings"))
107 else if (argis("l", "lists"))
109 else if (argis("k", "kerberos"))
111 else if (argis("t", "tags"))
113 else if (argis("i", "info"))
115 else if (argis("n", "noauth"))
117 else if (argis("v", "verbose"))
119 else if (argis("r", "recursive"))
121 else if (argis("S", "server") || argis("db", "database"))
123 if (arg - argv < argc - 1)
131 else if (argis("a", "add"))
133 if (arg - argv < argc - 1)
136 if ((memberstruct = parse_member(*arg)))
137 sq_save_data(addlist, memberstruct);
142 else if (argis("at", "addtagged"))
144 if (arg - argv < argc - 2)
147 if ((memberstruct = parse_member(*arg)))
148 sq_save_data(addlist, memberstruct);
149 memberstruct->tag = *++arg;
154 else if (argis("al", "addlist"))
156 if (arg - argv < argc - 1)
159 get_members_from_file(*arg, addlist);
164 else if (argis("d", "delete"))
166 if (arg - argv < argc - 1)
169 if ((memberstruct = parse_member(*arg)))
170 sq_save_data(dellist, memberstruct);
175 else if (argis("dl", "deletelist"))
177 if (arg - argv < argc - 1)
180 get_members_from_file(*arg, dellist);
185 else if (argis("f", "file"))
187 if (arg - argv < argc - 1)
191 get_members_from_file(*arg, synclist);
196 else if (argis("ct", "changetag"))
198 if (arg - argv < argc - 2)
201 if ((memberstruct = parse_member(*arg)))
202 sq_save_data(taglist, memberstruct);
203 memberstruct->tag = *++arg;
208 else if (argis("C", "create"))
210 else if (argis("P", "public"))
215 else if (argis("NP", "private"))
220 else if (argis("A", "active"))
225 else if (argis("I", "inactive"))
230 else if (argis("V", "visible"))
235 else if (argis("H", "hidden"))
240 else if (argis("M", "mail"))
245 else if (argis("NM", "notmail"))
250 else if (argis("G", "group"))
255 else if (argis("NG", "notgroup"))
260 else if (argis("N", "nfs"))
265 else if (argis("NN", "notnfs"))
270 else if (argis("D", "desc"))
272 if (arg - argv < argc - 1)
281 else if (argis("O", "owner"))
283 if (arg - argv < argc - 1)
287 owner = parse_member(*arg);
292 else if (argis("MA", "memacl"))
294 if (arg - argv < argc -1)
298 memacl = parse_member(*arg);
303 else if (argis("R", "rename"))
305 if (arg - argv < argc - 1)
317 else if (listname == NULL)
322 if (listname == NULL)
325 /* if no other options specified, turn on list members flag */
326 if (!(infoflg || syncflg || createflag || setinfo ||
327 addlist->q_next != addlist || dellist->q_next != dellist ||
328 taglist->q_next != taglist))
331 /* If none of {users,strings,lists,kerberos} specified, turn them all on */
332 if (!(showusers || showstrings || showlists || showkerberos))
333 showusers = showstrings = showlists = showkerberos = 1;
336 status = mrcl_connect(server, "blanche", 4, !noauth);
337 if (status == MRCL_AUTH_ERROR)
339 com_err(whoami, 0, "Try the -noauth flag if you don't "
340 "need authentication.");
345 /* check for username/listname clash */
346 if (createflag || (setinfo && newname && strcmp(newname, listname)))
348 status = mr_query("get_user_account_by_login", 1,
349 createflag ? &listname : &newname,
351 if (status != MR_NO_MATCH)
352 fprintf(stderr, "WARNING: A user by that name already exists.\n");
355 /* create if needed */
360 argv[L_NAME] = listname;
361 argv[L_ACTIVE] = (active == 0) ? "0" : "1";
362 argv[L_PUBLIC] = (public == 1) ? "1" : "0";
363 argv[L_HIDDEN] = (hidden == 1) ? "1" : "0";
364 argv[L_MAILLIST] = (maillist == 0) ? "0" : "1";
365 argv[L_GROUP] = (grouplist == 1) ? "1" : "0";
366 argv[L_GID] = UNIQUE_GID;
367 argv[L_NFSGROUP] = (nfsgroup == 1) ? "1" : "0";
368 argv[L_DESC] = desc ? desc : "none";
372 if (memacl->type == M_ANY)
374 status = mr_query("get_user_account_by_login", 1,
375 &memacl->name, NULL, NULL);
376 if (status == MR_NO_MATCH)
377 memacl->type = M_LIST;
379 memacl->type = M_USER;
381 argv[L_MEMACE_TYPE] = typename[memacl->type];
382 argv[L_MEMACE_NAME] = memacl->name;
385 argv[L_MEMACE_TYPE] = argv[L_MEMACE_NAME] = "NONE";
389 argv[L_ACE_NAME] = owner->name;
394 argv[L_ACE_TYPE] = "USER";
395 status = mr_query("add_list", 13, argv, NULL, NULL);
396 if (owner->type != M_ANY || status != MR_USER)
400 argv[L_ACE_TYPE] = "LIST";
401 status = mr_query("add_list", 13, argv, NULL, NULL);
405 argv[L_ACE_TYPE] = "KERBEROS";
406 status = mr_query("add_list", 13, argv, NULL, NULL);
412 argv[L_ACE_TYPE] = "USER";
413 argv[L_ACE_NAME] = get_username();
415 status = mr_query("add_list", 13, argv, NULL, NULL);
420 com_err(whoami, status, "while creating list.");
428 status = mr_query("get_list_info", 1, &listname,
429 save_list_info, argv);
432 com_err(whoami, status, "while getting list information");
438 argv[L_NAME + 1] = newname;
440 argv[L_ACTIVE + 1] = active ? "1" : "0";
442 argv[L_PUBLIC + 1] = public ? "1" : "0";
444 argv[L_HIDDEN + 1] = hidden ? "1" : "0";
446 argv[L_MAILLIST + 1] = maillist ? "1" : "0";
448 argv[L_GROUP + 1] = grouplist ? "1" : "0";
450 argv[L_NFSGROUP + 1] = nfsgroup ? "1" : "0";
452 argv[L_DESC + 1] = desc;
456 if (memacl->type == M_ANY)
458 status = mr_query("get_user_account_by_login", 1,
459 &memacl->name, NULL, NULL);
460 if (status == MR_NO_MATCH)
461 memacl->type = M_LIST;
463 memacl->type = M_USER;
465 argv[L_MEMACE_TYPE + 1] = typename[memacl->type];
466 argv[L_MEMACE_NAME + 1] = memacl->name;
471 argv[L_ACE_NAME + 1] = owner->name;
476 argv[L_ACE_TYPE + 1] = "USER";
477 status = mr_query("update_list", 14, argv, NULL, NULL);
478 if (owner->type != M_ANY || status != MR_USER)
482 argv[L_ACE_TYPE + 1] = "LIST";
483 status = mr_query("update_list", 14, argv, NULL, NULL);
487 argv[L_ACE_TYPE + 1] = "KERBEROS";
488 status = mr_query("update_list", 14, argv, NULL, NULL);
493 status = mr_query("update_list", 14, argv, NULL, NULL);
497 com_err(whoami, status, "while updating list.");
504 /* display list info if requested to */
507 status = mr_query("get_list_info", 1, &listname, show_list_info, NULL);
510 com_err(whoami, status, "while getting list information");
513 if (verbose && !memberflg)
515 status = mr_query("count_members_of_list", 1, &listname,
516 show_list_count, NULL);
519 com_err(whoami, status, "while getting list count");
525 /* if we're synchronizing to a file, we need to:
526 * get the current members of the list
527 * for each member of the sync file
528 * if they are on the list, remove them from the in-memory copy
529 * if they're not on the list, add them to add-list
530 * if anyone is left on the in-memory copy, put them on the delete-list
531 * lastly, reset memberlist so we can use it again later
535 status = mr_query("get_members_of_list", 1, &listname,
536 get_list_members, memberlist);
539 com_err(whoami, status, "getting members of list %s", listname);
542 while (sq_get_data(synclist, &memberstruct))
544 struct save_queue *q;
547 for (q = memberlist->q_next; q != memberlist; q = q->q_next)
549 if (membercmp(q->q_data, memberstruct) == 0)
551 q->q_prev->q_next = q->q_next;
552 q->q_next->q_prev = q->q_prev;
558 sq_save_data(addlist, memberstruct);
560 while (sq_get_data(memberlist, &memberstruct))
561 sq_save_data(dellist, memberstruct);
562 sq_destroy(memberlist);
563 memberlist = sq_create();
566 /* Process the add list */
567 while (sq_get_data(addlist, &memberstruct))
569 /* canonicalize string if necessary */
570 if (memberstruct->type != M_KERBEROS &&
571 (p = strchr(memberstruct->name, '@')))
573 char *host = canonicalize_hostname(strdup(++p));
574 static char **mailhubs = NULL;
583 mailhubs = malloc(sizeof(char *));
585 status = mr_query("get_alias", 3, argv, collect,
587 if (status != MR_SUCCESS && status != MR_NO_MATCH)
589 com_err(whoami, status,
590 " while reading list of MAILHUB servers");
594 for (i = 0; (p = mailhubs[i]); i++)
596 if (!strcasecmp(p, host))
598 host = strdup(memberstruct->name);
599 *(strchr(memberstruct->name, '@')) = 0;
600 if (memberstruct->type == M_STRING)
601 memberstruct->type = M_ANY;
602 fprintf(stderr, "Warning: \"%s\" converted to "
603 "\"%s\" because it is a local name.\n",
604 host, memberstruct->name);
610 /* now continue adding member */
611 membervec[0] = listname;
612 membervec[2] = memberstruct->name;
613 membervec[3] = memberstruct->tag;
616 printf("Adding member ");
617 show_list_member(memberstruct);
619 switch (memberstruct->type)
623 membervec[1] = "USER";
624 status = mr_query("add_tagged_member_to_list", 4, membervec,
626 if (status == MR_SUCCESS)
628 else if (status != MR_USER || memberstruct->type != M_ANY)
630 com_err(whoami, status, "while adding member %s to %s",
631 memberstruct->name, listname);
636 membervec[1] = "LIST";
637 status = mr_query("add_tagged_member_to_list", 4, membervec,
639 if (status == MR_SUCCESS)
641 if (!strcmp(membervec[0], get_username()))
643 fprintf(stderr, "\nWARNING: \"LIST:%s\" was just added "
644 "to list \"%s\".\n", membervec[2], membervec[0]);
645 fprintf(stderr, "If you meant to add yourself to the list "
646 "\"%s\", type:\n", membervec[2]);
647 fprintf(stderr, "\tblanche %s -d %s\t(to undo this)\n",
648 membervec[0], membervec[2]);
649 fprintf(stderr, "\tblanche %s -a %s\t(to add yourself to "
650 "that list)\n", membervec[2], membervec[0]);
654 else if (status != MR_LIST || memberstruct->type != M_ANY)
656 com_err(whoami, status, "while adding member %s to %s",
657 memberstruct->name, listname);
662 status = mrcl_validate_string_member(memberstruct->name);
663 if (memberstruct->type == M_ANY && status == MRCL_WARN)
665 /* if user is trying to add something which isn't a
666 remote string, or a list, or a user, and didn't
667 explicitly specify `STRING:', it's probably a typo */
668 com_err(whoami, MR_NO_MATCH, "while adding member %s to %s",
669 memberstruct->name, listname);
674 mrcl_com_err(whoami);
676 if (status == MRCL_REJECT)
682 membervec[1] = "STRING";
683 status = mr_query("add_tagged_member_to_list", 4, membervec,
685 if (status != MR_SUCCESS)
687 com_err(whoami, status, "while adding member %s to %s",
688 memberstruct->name, listname);
693 membervec[1] = "KERBEROS";
694 status = mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
695 if (mrcl_get_message())
696 mrcl_com_err(whoami);
697 status = mr_query("add_tagged_member_to_list", 4, membervec,
699 if (status != MR_SUCCESS)
701 com_err(whoami, status, "while adding member %s to %s",
702 memberstruct->name, listname);
709 /* Process the delete list */
710 while (sq_get_data(dellist, &memberstruct))
712 membervec[0] = listname;
713 membervec[2] = memberstruct->name;
716 printf("Deleting member ");
717 show_list_member(memberstruct);
719 switch (memberstruct->type)
723 membervec[1] = "USER";
724 status = mr_query("delete_member_from_list", 3, membervec,
726 if (status == MR_SUCCESS)
728 else if ((status != MR_USER && status != MR_NO_MATCH) ||
729 memberstruct->type != M_ANY)
731 com_err(whoami, status, "while deleting member %s from %s",
732 memberstruct->name, listname);
737 membervec[1] = "LIST";
738 status = mr_query("delete_member_from_list", 3, membervec,
740 if (status == MR_SUCCESS)
742 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
743 memberstruct->type != M_ANY)
745 if (status == MR_PERM && memberstruct->type == M_ANY &&
746 !strcmp(membervec[2], get_username()))
748 /* M_ANY means we've fallen through from the user
749 * case. The user is trying to remove himself from
750 * a list, but we got MR_USER or MR_NO_MATCH above,
751 * meaning he's not really on it, and we got MR_PERM
752 * when trying to remove LIST:$USER because he's not
753 * on the acl. That error is useless, so return
754 * MR_NO_MATCH instead. However, this will generate the
755 * wrong error if the user was trying to remove the list
756 * with his username from a list he doesn't administrate
757 * without explicitly specifying "list:".
759 status = MR_NO_MATCH;
761 com_err(whoami, status, "while deleting member %s from %s",
762 memberstruct->name, listname);
767 membervec[1] = "STRING";
768 status = mr_query("delete_member_from_list", 3, membervec,
770 if (status == MR_STRING && memberstruct->type == M_ANY)
772 com_err(whoami, 0, " Unable to find member %s to delete from %s",
773 memberstruct->name, listname);
775 if (!strcmp(membervec[0], get_username()))
777 fprintf(stderr, "(If you were trying to remove yourself "
778 "from the list \"%s\",\n", membervec[2]);
779 fprintf(stderr, "the correct command is \"blanche %s -d "
780 "%s\".)\n", membervec[2], membervec[0]);
783 else if (status != MR_SUCCESS)
785 com_err(whoami, status, "while deleting member %s from %s",
786 memberstruct->name, listname);
791 membervec[1] = "KERBEROS";
792 status = mr_query("delete_member_from_list", 3, membervec,
794 if (status == MR_STRING || status == MR_NO_MATCH)
796 /* Try canonicalizing the Kerberos principal and trying
797 * again. If we succeed, print the message from mrcl.
798 * Otherwise, just pretend we never did this and print
799 * the original error message.
801 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
802 if (mrcl_get_message())
804 if (mr_query("delete_member_from_list", 3, membervec,
805 NULL, NULL) == MR_SUCCESS)
806 mrcl_com_err(whoami);
810 if (status != MR_SUCCESS)
812 com_err(whoami, status, "while deleting member %s from %s",
813 memberstruct->name, listname);
819 /* Process the tag list */
820 while (sq_get_data(taglist, &memberstruct))
822 membervec[0] = listname;
823 membervec[2] = memberstruct->name;
824 membervec[3] = memberstruct->tag;
827 printf("Tagging member ");
828 show_list_member(memberstruct);
830 switch (memberstruct->type)
834 membervec[1] = "USER";
835 status = mr_query("tag_member_of_list", 4, membervec,
837 if (status == MR_SUCCESS)
839 else if ((status != MR_USER && status != MR_NO_MATCH) ||
840 memberstruct->type != M_ANY)
842 com_err(whoami, status, "while changing tag on member %s of %s",
843 memberstruct->name, listname);
848 membervec[1] = "LIST";
849 status = mr_query("tag_member_of_list", 4, membervec,
851 if (status == MR_SUCCESS)
853 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
854 memberstruct->type != M_ANY)
856 com_err(whoami, status, "while changing tag on member %s of %s",
857 memberstruct->name, listname);
862 membervec[1] = "STRING";
863 status = mr_query("tag_member_of_list", 4, membervec,
865 if (status == MR_STRING && memberstruct->type == M_ANY)
867 com_err(whoami, 0, " Unable to find member %s on list %s",
868 memberstruct->name, listname);
871 else if (status != MR_SUCCESS)
873 com_err(whoami, status, "while retagging member %s on %s",
874 memberstruct->name, listname);
879 membervec[1] = "KERBEROS";
880 status = mr_query("tag_member_of_list", 4, membervec,
882 if (status == MR_STRING || status == MR_NO_MATCH)
884 /* Try canonicalizing the Kerberos principal and trying
885 * again. If we succeed, print the message from mrcl.
886 * Otherwise, just pretend we never did this and print
887 * the original error message.
889 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
890 if (mrcl_get_message())
892 if (mr_query("tag_member_of_list", 4, membervec,
893 NULL, NULL) == MR_SUCCESS)
894 mrcl_com_err(whoami);
898 if (status != MR_SUCCESS)
900 com_err(whoami, status, "while changing tag on member %s of %s",
901 memberstruct->name, listname);
907 /* Display the members of the list now, if requested */
911 recursive_display_list_members();
914 status = mr_query(showtags ? "get_tagged_members_of_list" :
915 "get_members_of_list", 1, &listname,
916 get_list_members, memberlist);
918 com_err(whoami, status, "while getting members of list %s",
920 while (sq_get_data(memberlist, &memberstruct))
921 show_list_member(memberstruct);
927 exit(success ? 0 : 1);
930 void usage(char **argv)
932 #define USAGE_OPTIONS_FORMAT " %-39s%s\n"
933 fprintf(stderr, "Usage: %s listname [options]\n", argv[0]);
934 fprintf(stderr, "Options are\n");
935 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-v | -verbose",
937 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-m | -members",
938 "-R | -rename newname");
939 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-u | -users",
941 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-l | -lists",
943 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-s | -strings",
945 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-k | -kerberos",
947 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-i | -info",
949 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-r | -recursive",
951 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-a | -add member",
953 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-d | -delete member",
955 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-al | -addlist filename",
957 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-dl | -deletelist filename",
959 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-f | -file filename",
961 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-at | -addtagged member tag",
963 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-ct | -changetag member tag",
964 "-D | -desc description");
965 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-t | -tags",
966 "-O | -owner owner");
967 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-n | -noauth",
968 "-MA | -memacl membership_acl");
969 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-db | -database host[:port]",
975 /* Display the members stored in the queue */
977 void show_list_member(struct member *memberstruct)
981 switch (memberstruct->type)
1004 printf("%s\n", memberstruct->name);
1009 printf("%s:%s", s, memberstruct->name);
1012 if (memberstruct->type == M_LIST)
1013 printf("LIST:%s", memberstruct->name);
1014 else if (memberstruct->type == M_KERBEROS)
1015 printf("KERBEROS:%s", memberstruct->name);
1016 else if (memberstruct->type == M_STRING &&
1017 !strchr(memberstruct->name, '@'))
1018 printf("STRING:%s", memberstruct->name);
1020 printf("%s", memberstruct->name);
1022 if (showtags && *(memberstruct->tag))
1023 printf(" (%s)\n", memberstruct->tag);
1029 /* Show the retrieved information about a list */
1031 int show_list_info(int argc, char **argv, void *hint)
1033 printf("List: %s\n", argv[L_NAME]);
1034 printf("Description: %s\n", argv[L_DESC]);
1035 printf("Flags: %s, %s, and %s\n",
1036 atoi(argv[L_ACTIVE]) ? "active" : "inactive",
1037 atoi(argv[L_PUBLIC]) ? "public" : "private",
1038 atoi(argv[L_HIDDEN]) ? "hidden" : "visible");
1039 printf("%s is %sa maillist and is %sa group", argv[L_NAME],
1040 atoi(argv[L_MAILLIST]) ? "" : "not ",
1041 atoi(argv[L_GROUP]) ? "" : "not ");
1042 if (atoi(argv[L_GROUP]))
1044 if (atoi(argv[L_NFSGROUP]))
1045 printf(" (and an NFS group)");
1046 printf(" with GID %d\n", atoi(argv[L_GID]));
1050 printf("Owner: %s %s\n", argv[L_ACE_TYPE], argv[L_ACE_NAME]);
1051 if (strcmp(argv[L_MEMACE_TYPE], "NONE"))
1052 printf("Membership ACL: %s %s\n", argv[L_MEMACE_TYPE],
1053 argv[L_MEMACE_NAME]);
1054 printf("Last modified by %s with %s on %s\n",
1055 argv[L_MODBY], argv[L_MODWITH], argv[L_MODTIME]);
1060 /* Copy retrieved information about a list into a new argv */
1062 int save_list_info(int argc, char **argv, void *hint)
1064 char **nargv = hint;
1066 for (argc = 0; argc < 14; argc++)
1067 nargv[argc + 1] = strdup(argv[argc]);
1071 /* Show the retrieve list member count */
1073 int show_list_count(int argc, char **argv, void *hint)
1075 printf("Members: %s\n", argv[0]);
1080 /* Recursively find all of the members of listname, and then display them */
1082 void recursive_display_list_members(void)
1084 int status, count, savecount;
1085 struct save_queue *lists, *members;
1086 struct member *m, *m1, *data;
1088 lists = sq_create();
1089 members = sq_create();
1090 m = malloc(sizeof(struct member));
1093 sq_save_data(lists, m);
1095 while (sq_get_data(lists, &m))
1097 sq_destroy(memberlist);
1098 memberlist = sq_create();
1099 status = mr_query("get_members_of_list", 1, &(m->name),
1100 get_list_members, memberlist);
1102 com_err(whoami, status, "while getting members of list %s", m->name);
1103 while (sq_get_data(memberlist, &m1))
1105 if (m1->type == M_LIST)
1106 unique_add_member(lists, m1);
1108 unique_add_member(members, m1);
1111 savecount = count = sq_count_elts(members);
1112 data = malloc(count * sizeof(struct member));
1114 while (sq_get_data(members, &m))
1115 memcpy(&data[count++], m, sizeof(struct member));
1116 qsort(data, count, sizeof(struct member), membercmp);
1117 for (count = 0; count < savecount; count++)
1118 show_list_member(&data[count]);
1122 /* add a struct member to a queue if that member isn't already there. */
1124 void unique_add_member(struct save_queue *q, struct member *m)
1126 struct save_queue *qp;
1128 for (qp = q->q_next; qp != q; qp = qp->q_next)
1130 if (!membercmp(qp->q_data, m))
1137 /* Collect the retrieved members of the list */
1139 int get_list_members(int argc, char **argv, void *sq)
1141 struct save_queue *q = sq;
1144 m = malloc(sizeof(struct member));
1157 m->type = M_KERBEROS;
1160 m->name = strdup(argv[1]);
1162 m->tag = strdup(argv[2]);
1164 m->tag = strdup("");
1170 /* Open file, parse members from file, and put them on the specified queue */
1171 void get_members_from_file(char *filename, struct save_queue *queue)
1175 struct member *memberstruct;
1177 if (!strcmp(filename, "-"))
1181 in = fopen(filename, "r");
1184 com_err(whoami, errno, "while opening %s for input", filename);
1189 while (fgets(buf, BUFSIZ, in))
1191 if ((memberstruct = parse_member(buf)))
1192 sq_save_data(queue, memberstruct);
1196 com_err(whoami, errno, "while reading from %s", filename);
1202 /* Collect the possible expansions of the alias MAILHUB */
1204 int collect(int argc, char **argv, void *l)
1209 for (i = 0; (*list)[i]; i++)
1211 *list = realloc(*list, (i + 2) * sizeof(char *));
1212 (*list)[i] = strdup(argv[2]);
1213 (*list)[i + 1] = NULL;
1218 /* Parse a line of input, fetching a member. NULL is returned if a member
1219 * is not found. ';' is a comment character.
1222 struct member *parse_member(char *s)
1227 while (*s && isspace(*s))
1230 while (*p && *p != '\n' && *p != ';')
1232 if (isprint(*p) && !isspace(*p))
1239 if (p == s || strlen(s) == 0)
1242 if (!(m = malloc(sizeof(struct member))))
1244 m->tag = strdup("");
1246 if ((p = strchr(s, ':')))
1250 if (!strcasecmp("user", s))
1252 else if (!strcasecmp("list", s))
1254 else if (!strcasecmp("string", s))
1256 else if (!strcasecmp("kerberos", s))
1257 m->type = M_KERBEROS;
1258 else if (!strcasecmp("none", s))
1266 m->name = strdup(m->name);
1270 m->name = strdup(s);
1271 m->type = strcasecmp(s, "none") ? M_ANY : M_NONE;
1278 * This routine two compares members by the following rules:
1279 * 1. A USER is less than a LIST
1280 * 2. A LIST is less than a STRING
1281 * 3. If two members are of the same type, the one alphabetically first
1282 * is less than the other
1283 * It returs < 0 if the first member is less, 0 if they are identical, and
1284 * > 0 if the second member is less (the first member is greater).
1287 int membercmp(const void *mem1, const void *mem2)
1289 const struct member *m1 = mem1, *m2 = mem2;
1291 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
1292 return strcmp(m1->name, m2->name);
1294 return m1->type - m2->type;
1298 int sq_count_elts(struct save_queue *q)
1304 while (sq_get_data(q, &foo))
1309 char *get_username(void)
1313 username = getenv("USER");
1316 username = mrcl_krb_user();
1319 com_err(whoami, 0, "Could not determine username");