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 */
37 char *typename[] = { "ANY", "USER", "LIST", "STRING", "KERBEROS" };
39 /* argument parsing macro */
40 #define argis(a, b) (!strcmp(*arg + 1, a) || !strcmp(*arg + 1, b))
42 /* flags from command line */
43 int infoflg, verbose, syncflg, memberflg, recursflg, noauth;
44 int showusers, showstrings, showkerberos, showlists, showtags;
45 int createflag, setinfo, active, public, hidden, maillist, grouplist;
47 struct member *owner, *memacl;
50 /* various member lists */
51 struct save_queue *addlist, *dellist, *memberlist, *synclist, *taglist;
53 char *listname, *whoami;
55 void usage(char **argv);
56 void show_list_member(struct member *memberstruct);
57 int show_list_info(int argc, char **argv, void *hint);
58 int save_list_info(int argc, char **argv, void *hint);
59 int show_list_count(int argc, char **argv, void *hint);
60 void recursive_display_list_members(void);
61 void unique_add_member(struct save_queue *q, struct member *m);
62 int get_list_members(int argc, char **argv, void *sq);
63 void get_members_from_file(char *filename, struct save_queue *queue);
64 int collect(int argc, char **argv, void *l);
65 struct member *parse_member(char *s);
66 int membercmp(const void *mem1, const void *mem2);
67 int sq_count_elts(struct save_queue *q);
68 char *get_username(void);
70 int main(int argc, char **argv)
75 struct member *memberstruct;
76 char *server = NULL, *p;
78 /* clear all flags & lists */
79 infoflg = verbose = syncflg = memberflg = recursflg = 0;
80 noauth = showusers = showstrings = showkerberos = showlists = 0;
81 createflag = setinfo = 0;
82 active = public = hidden = maillist = grouplist = nfsgroup = -1;
83 listname = newname = desc = NULL;
86 addlist = sq_create();
87 dellist = sq_create();
88 memberlist = sq_create();
89 synclist = sq_create();
90 taglist = sq_create();
95 /* parse args, building addlist, dellist, & synclist */
96 while (++arg - argv < argc)
100 if (argis("m", "members"))
102 else if (argis("u", "users"))
104 else if (argis("s", "strings"))
106 else if (argis("l", "lists"))
108 else if (argis("k", "kerberos"))
110 else if (argis("t", "tags"))
112 else if (argis("i", "info"))
114 else if (argis("n", "noauth"))
116 else if (argis("v", "verbose"))
118 else if (argis("r", "recursive"))
120 else if (argis("S", "server") || argis("db", "database"))
122 if (arg - argv < argc - 1)
130 else if (argis("a", "add"))
132 if (arg - argv < argc - 1)
135 if ((memberstruct = parse_member(*arg)))
136 sq_save_data(addlist, memberstruct);
141 else if (argis("at", "addtagged"))
143 if (arg - argv < argc - 2)
146 if ((memberstruct = parse_member(*arg)))
147 sq_save_data(addlist, memberstruct);
148 memberstruct->tag = *++arg;
153 else if (argis("al", "addlist"))
155 if (arg - argv < argc - 1)
158 get_members_from_file(*arg, addlist);
163 else if (argis("d", "delete"))
165 if (arg - argv < argc - 1)
168 if ((memberstruct = parse_member(*arg)))
169 sq_save_data(dellist, memberstruct);
174 else if (argis("dl", "deletelist"))
176 if (arg - argv < argc - 1)
179 get_members_from_file(*arg, dellist);
184 else if (argis("f", "file"))
186 if (arg - argv < argc - 1)
190 get_members_from_file(*arg, synclist);
195 else if (argis("ct", "changetag"))
197 if (arg - argv < argc - 2)
200 if ((memberstruct = parse_member(*arg)))
201 sq_save_data(taglist, memberstruct);
202 memberstruct->tag = *++arg;
207 else if (argis("C", "create"))
209 else if (argis("P", "public"))
214 else if (argis("NP", "private"))
219 else if (argis("A", "active"))
224 else if (argis("I", "inactive"))
229 else if (argis("V", "visible"))
234 else if (argis("H", "hidden"))
239 else if (argis("M", "mail"))
244 else if (argis("NM", "notmail"))
249 else if (argis("G", "group"))
254 else if (argis("NG", "notgroup"))
259 else if (argis("N", "nfs"))
264 else if (argis("NN", "notnfs"))
269 else if (argis("D", "desc"))
271 if (arg - argv < argc - 1)
280 else if (argis("O", "owner"))
282 if (arg - argv < argc - 1)
286 owner = parse_member(*arg);
291 else if (argis("MA", "memacl"))
293 if (arg - argv < argc -1)
297 memacl = parse_member(*arg);
302 else if (argis("R", "rename"))
304 if (arg - argv < argc - 1)
316 else if (listname == NULL)
321 if (listname == NULL)
324 /* if no other options specified, turn on list members flag */
325 if (!(infoflg || syncflg || createflag || setinfo ||
326 addlist->q_next != addlist || dellist->q_next != dellist ||
327 taglist->q_next != taglist))
330 /* If none of {users,strings,lists,kerberos} specified, turn them all on */
331 if (!(showusers || showstrings || showlists || showkerberos))
332 showusers = showstrings = showlists = showkerberos = 1;
335 status = mrcl_connect(server, "blanche", 4, !noauth);
336 if (status == MRCL_AUTH_ERROR)
338 com_err(whoami, 0, "Try the -noauth flag if you don't "
339 "need authentication.");
344 /* check for username/listname clash */
345 if (createflag || (setinfo && newname && strcmp(newname, listname)))
347 status = mr_query("get_user_account_by_login", 1,
348 createflag ? &listname : &newname,
350 if (status != MR_NO_MATCH)
351 fprintf(stderr, "WARNING: A user by that name already exists.\n");
354 /* create if needed */
359 argv[L_NAME] = listname;
360 argv[L_ACTIVE] = (active == 0) ? "0" : "1";
361 argv[L_PUBLIC] = (public == 1) ? "1" : "0";
362 argv[L_HIDDEN] = (hidden == 1) ? "1" : "0";
363 argv[L_MAILLIST] = (maillist == 0) ? "0" : "1";
364 argv[L_GROUP] = (grouplist == 1) ? "1" : "0";
365 argv[L_GID] = UNIQUE_GID;
366 argv[L_NFSGROUP] = (nfsgroup == 1) ? "1" : "0";
367 argv[L_DESC] = desc ? desc : "none";
371 if (memacl->type == M_ANY)
373 status = mr_query("get_user_account_by_login", 1,
374 &memacl->name, NULL, NULL);
375 if (status == MR_NO_MATCH)
376 memacl->type = M_LIST;
378 memacl->type = M_USER;
380 argv[L_MEMACE_TYPE] = typename[memacl->type];
381 argv[L_MEMACE_NAME] = memacl->name;
384 argv[L_MEMACE_TYPE] = argv[L_MEMACE_NAME] = "NONE";
388 argv[L_ACE_NAME] = owner->name;
393 argv[L_ACE_TYPE] = "USER";
394 status = mr_query("add_list", 13, argv, NULL, NULL);
395 if (owner->type != M_ANY || status != MR_USER)
399 argv[L_ACE_TYPE] = "LIST";
400 status = mr_query("add_list", 13, argv, NULL, NULL);
404 argv[L_ACE_TYPE] = "KERBEROS";
405 status = mr_query("add_list", 13, argv, NULL, NULL);
411 argv[L_ACE_TYPE] = "USER";
412 argv[L_ACE_NAME] = get_username();
414 status = mr_query("add_list", 13, argv, NULL, NULL);
419 com_err(whoami, status, "while creating list.");
427 status = mr_query("get_list_info", 1, &listname,
428 save_list_info, argv);
431 com_err(whoami, status, "while getting list information");
437 argv[L_NAME + 1] = newname;
439 argv[L_ACTIVE + 1] = active ? "1" : "0";
441 argv[L_PUBLIC + 1] = public ? "1" : "0";
443 argv[L_HIDDEN + 1] = hidden ? "1" : "0";
445 argv[L_MAILLIST + 1] = maillist ? "1" : "0";
447 argv[L_GROUP + 1] = grouplist ? "1" : "0";
449 argv[L_NFSGROUP + 1] = nfsgroup ? "1" : "0";
451 argv[L_DESC + 1] = desc;
455 if (memacl->type == M_ANY)
457 status = mr_query("get_user_account_by_login", 1,
458 &memacl->name, NULL, NULL);
459 if (status == MR_NO_MATCH)
460 memacl->type = M_LIST;
462 memacl->type = M_USER;
464 argv[L_MEMACE_TYPE + 1] = typename[memacl->type];
465 argv[L_MEMACE_NAME + 1] = memacl->name;
470 argv[L_ACE_NAME + 1] = owner->name;
475 argv[L_ACE_TYPE + 1] = "USER";
476 status = mr_query("update_list", 14, argv, NULL, NULL);
477 if (owner->type != M_ANY || status != MR_USER)
481 argv[L_ACE_TYPE + 1] = "LIST";
482 status = mr_query("update_list", 14, argv, NULL, NULL);
486 argv[L_ACE_TYPE + 1] = "KERBEROS";
487 status = mr_query("update_list", 14, argv, NULL, NULL);
492 status = mr_query("update_list", 14, argv, NULL, NULL);
496 com_err(whoami, status, "while updating list.");
503 /* display list info if requested to */
506 status = mr_query("get_list_info", 1, &listname, show_list_info, NULL);
509 com_err(whoami, status, "while getting list information");
512 if (verbose && !memberflg)
514 status = mr_query("count_members_of_list", 1, &listname,
515 show_list_count, NULL);
518 com_err(whoami, status, "while getting list count");
524 /* if we're synchronizing to a file, we need to:
525 * get the current members of the list
526 * for each member of the sync file
527 * if they are on the list, remove them from the in-memory copy
528 * if they're not on the list, add them to add-list
529 * if anyone is left on the in-memory copy, put them on the delete-list
530 * lastly, reset memberlist so we can use it again later
534 status = mr_query("get_members_of_list", 1, &listname,
535 get_list_members, memberlist);
538 com_err(whoami, status, "getting members of list %s", listname);
541 while (sq_get_data(synclist, &memberstruct))
543 struct save_queue *q;
546 for (q = memberlist->q_next; q != memberlist; q = q->q_next)
548 if (membercmp(q->q_data, memberstruct) == 0)
550 q->q_prev->q_next = q->q_next;
551 q->q_next->q_prev = q->q_prev;
557 sq_save_data(addlist, memberstruct);
559 while (sq_get_data(memberlist, &memberstruct))
560 sq_save_data(dellist, memberstruct);
561 sq_destroy(memberlist);
562 memberlist = sq_create();
565 /* Process the add list */
566 while (sq_get_data(addlist, &memberstruct))
568 /* canonicalize string if necessary */
569 if (memberstruct->type != M_KERBEROS &&
570 (p = strchr(memberstruct->name, '@')))
572 char *host = canonicalize_hostname(strdup(++p));
573 static char **mailhubs = NULL;
582 mailhubs = malloc(sizeof(char *));
584 status = mr_query("get_alias", 3, argv, collect,
586 if (status != MR_SUCCESS && status != MR_NO_MATCH)
588 com_err(whoami, status,
589 " while reading list of MAILHUB servers");
593 for (i = 0; (p = mailhubs[i]); i++)
595 if (!strcasecmp(p, host))
597 host = strdup(memberstruct->name);
598 *(strchr(memberstruct->name, '@')) = 0;
599 if (memberstruct->type == M_STRING)
600 memberstruct->type = M_ANY;
601 fprintf(stderr, "Warning: \"%s\" converted to "
602 "\"%s\" because it is a local name.\n",
603 host, memberstruct->name);
609 /* now continue adding member */
610 membervec[0] = listname;
611 membervec[2] = memberstruct->name;
612 membervec[3] = memberstruct->tag;
615 printf("Adding member ");
616 show_list_member(memberstruct);
618 switch (memberstruct->type)
622 membervec[1] = "USER";
623 status = mr_query("add_tagged_member_to_list", 4, membervec,
625 if (status == MR_SUCCESS)
627 else if (status != MR_USER || memberstruct->type != M_ANY)
629 com_err(whoami, status, "while adding member %s to %s",
630 memberstruct->name, listname);
635 membervec[1] = "LIST";
636 status = mr_query("add_tagged_member_to_list", 4, membervec,
638 if (status == MR_SUCCESS)
640 if (!strcmp(membervec[0], get_username()))
642 fprintf(stderr, "\nWARNING: \"LIST:%s\" was just added "
643 "to list \"%s\".\n", membervec[2], membervec[0]);
644 fprintf(stderr, "If you meant to add yourself to the list "
645 "\"%s\", type:\n", membervec[2]);
646 fprintf(stderr, "\tblanche %s -d %s\t(to undo this)\n",
647 membervec[0], membervec[2]);
648 fprintf(stderr, "\tblanche %s -a %s\t(to add yourself to "
649 "that list)\n", membervec[2], membervec[0]);
653 else if (status != MR_LIST || memberstruct->type != M_ANY)
655 com_err(whoami, status, "while adding member %s to %s",
656 memberstruct->name, listname);
661 status = mrcl_validate_string_member(memberstruct->name);
662 if (status == MRCL_REJECT)
664 mrcl_com_err(whoami);
668 else if (memberstruct->type == M_ANY && status != MR_SUCCESS)
670 /* if user is trying to add something which isn't a
671 remote string, or a list, or a user, and didn't
672 explicitly specify `STRING:', it's probably a typo */
673 com_err(whoami, MR_NO_MATCH, "while adding member %s to %s",
674 memberstruct->name, listname);
679 membervec[1] = "STRING";
680 status = mr_query("add_tagged_member_to_list", 4, membervec,
682 if (status != MR_SUCCESS)
684 com_err(whoami, status, "while adding member %s to %s",
685 memberstruct->name, listname);
690 membervec[1] = "KERBEROS";
691 status = mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
692 if (mrcl_get_message())
693 mrcl_com_err(whoami);
694 status = mr_query("add_tagged_member_to_list", 4, membervec,
696 if (status != MR_SUCCESS)
698 com_err(whoami, status, "while adding member %s to %s",
699 memberstruct->name, listname);
706 /* Process the delete list */
707 while (sq_get_data(dellist, &memberstruct))
709 membervec[0] = listname;
710 membervec[2] = memberstruct->name;
713 printf("Deleting member ");
714 show_list_member(memberstruct);
716 switch (memberstruct->type)
720 membervec[1] = "USER";
721 status = mr_query("delete_member_from_list", 3, membervec,
723 if (status == MR_SUCCESS)
725 else if ((status != MR_USER && status != MR_NO_MATCH) ||
726 memberstruct->type != M_ANY)
728 com_err(whoami, status, "while deleting member %s from %s",
729 memberstruct->name, listname);
734 membervec[1] = "LIST";
735 status = mr_query("delete_member_from_list", 3, membervec,
737 if (status == MR_SUCCESS)
739 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
740 memberstruct->type != M_ANY)
742 if (status == MR_PERM && memberstruct->type == M_ANY &&
743 !strcmp(membervec[2], get_username()))
745 /* M_ANY means we've fallen through from the user
746 * case. The user is trying to remove himself from
747 * a list, but we got MR_USER or MR_NO_MATCH above,
748 * meaning he's not really on it, and we got MR_PERM
749 * when trying to remove LIST:$USER because he's not
750 * on the acl. That error is useless, so return
751 * MR_NO_MATCH instead. However, this will generate the
752 * wrong error if the user was trying to remove the list
753 * with his username from a list he doesn't administrate
754 * without explicitly specifying "list:".
756 status = MR_NO_MATCH;
758 com_err(whoami, status, "while deleting member %s from %s",
759 memberstruct->name, listname);
764 membervec[1] = "STRING";
765 status = mr_query("delete_member_from_list", 3, membervec,
767 if (status == MR_STRING && memberstruct->type == M_ANY)
769 com_err(whoami, 0, " Unable to find member %s to delete from %s",
770 memberstruct->name, listname);
772 if (!strcmp(membervec[0], get_username()))
774 fprintf(stderr, "(If you were trying to remove yourself "
775 "from the list \"%s\",\n", membervec[2]);
776 fprintf(stderr, "the correct command is \"blanche %s -d "
777 "%s\".)\n", membervec[2], membervec[0]);
780 else if (status != MR_SUCCESS)
782 com_err(whoami, status, "while deleting member %s from %s",
783 memberstruct->name, listname);
788 membervec[1] = "KERBEROS";
789 status = mr_query("delete_member_from_list", 3, membervec,
791 if (status == MR_STRING || status == MR_NO_MATCH)
793 /* Try canonicalizing the Kerberos principal and trying
794 * again. If we succeed, print the message from mrcl.
795 * Otherwise, just pretend we never did this and print
796 * the original error message.
798 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
799 if (mrcl_get_message())
801 if (mr_query("delete_member_from_list", 3, membervec,
802 NULL, NULL) == MR_SUCCESS)
803 mrcl_com_err(whoami);
807 if (status != MR_SUCCESS)
809 com_err(whoami, status, "while deleting member %s from %s",
810 memberstruct->name, listname);
816 /* Process the tag list */
817 while (sq_get_data(taglist, &memberstruct))
819 membervec[0] = listname;
820 membervec[2] = memberstruct->name;
821 membervec[3] = memberstruct->tag;
824 printf("Tagging member ");
825 show_list_member(memberstruct);
827 switch (memberstruct->type)
831 membervec[1] = "USER";
832 status = mr_query("tag_member_of_list", 4, membervec,
834 if (status == MR_SUCCESS)
836 else if ((status != MR_USER && status != MR_NO_MATCH) ||
837 memberstruct->type != M_ANY)
839 com_err(whoami, status, "while changing tag on member %s of %s",
840 memberstruct->name, listname);
845 membervec[1] = "LIST";
846 status = mr_query("tag_member_of_list", 4, membervec,
848 if (status == MR_SUCCESS)
850 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
851 memberstruct->type != M_ANY)
853 com_err(whoami, status, "while changing tag on member %s of %s",
854 memberstruct->name, listname);
859 membervec[1] = "STRING";
860 status = mr_query("tag_member_of_list", 4, membervec,
862 if (status == MR_STRING && memberstruct->type == M_ANY)
864 com_err(whoami, 0, " Unable to find member %s on list %s",
865 memberstruct->name, listname);
868 else if (status != MR_SUCCESS)
870 com_err(whoami, status, "while retagging member %s on %s",
871 memberstruct->name, listname);
876 membervec[1] = "KERBEROS";
877 status = mr_query("tag_member_of_list", 4, membervec,
879 if (status == MR_STRING || status == MR_NO_MATCH)
881 /* Try canonicalizing the Kerberos principal and trying
882 * again. If we succeed, print the message from mrcl.
883 * Otherwise, just pretend we never did this and print
884 * the original error message.
886 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
887 if (mrcl_get_message())
889 if (mr_query("tag_member_of_list", 4, membervec,
890 NULL, NULL) == MR_SUCCESS)
891 mrcl_com_err(whoami);
895 if (status != MR_SUCCESS)
897 com_err(whoami, status, "while changing tag on member %s of %s",
898 memberstruct->name, listname);
904 /* Display the members of the list now, if requested */
908 recursive_display_list_members();
911 status = mr_query(showtags ? "get_tagged_members_of_list" :
912 "get_members_of_list", 1, &listname,
913 get_list_members, memberlist);
915 com_err(whoami, status, "while getting members of list %s",
917 while (sq_get_data(memberlist, &memberstruct))
918 show_list_member(memberstruct);
924 exit(success ? 0 : 1);
927 void usage(char **argv)
929 #define USAGE_OPTIONS_FORMAT " %-39s%s\n"
930 fprintf(stderr, "Usage: %s listname [options]\n", argv[0]);
931 fprintf(stderr, "Options are\n");
932 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-v | -verbose",
934 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-m | -members",
935 "-R | -rename newname");
936 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-u | -users",
938 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-l | -lists",
940 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-s | -strings",
942 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-k | -kerberos",
944 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-i | -info",
946 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-r | -recursive",
948 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-a | -add member",
950 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-d | -delete member",
952 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-al | -addlist filename",
954 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-dl | -deletelist filename",
956 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-f | -file filename",
958 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-at | -addtagged member tag",
960 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-ct | -changetag member tag",
961 "-D | -desc description");
962 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-t | -tags",
963 "-O | -owner owner");
964 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-n | -noauth",
965 "-MA | -memacl membership_acl");
966 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-db | -database host[:port]",
972 /* Display the members stored in the queue */
974 void show_list_member(struct member *memberstruct)
978 switch (memberstruct->type)
1001 printf("%s\n", memberstruct->name);
1006 printf("%s:%s", s, memberstruct->name);
1009 if (memberstruct->type == M_LIST)
1010 printf("LIST:%s", memberstruct->name);
1011 else if (memberstruct->type == M_KERBEROS)
1012 printf("KERBEROS:%s", memberstruct->name);
1013 else if (memberstruct->type == M_STRING &&
1014 !strchr(memberstruct->name, '@'))
1015 printf("STRING:%s", memberstruct->name);
1017 printf("%s", memberstruct->name);
1019 if (showtags && *(memberstruct->tag))
1020 printf(" (%s)\n", memberstruct->tag);
1026 /* Show the retrieved information about a list */
1028 int show_list_info(int argc, char **argv, void *hint)
1030 printf("List: %s\n", argv[L_NAME]);
1031 printf("Description: %s\n", argv[L_DESC]);
1032 printf("Flags: %s, %s, and %s\n",
1033 atoi(argv[L_ACTIVE]) ? "active" : "inactive",
1034 atoi(argv[L_PUBLIC]) ? "public" : "private",
1035 atoi(argv[L_HIDDEN]) ? "hidden" : "visible");
1036 printf("%s is %sa maillist and is %sa group", argv[L_NAME],
1037 atoi(argv[L_MAILLIST]) ? "" : "not ",
1038 atoi(argv[L_GROUP]) ? "" : "not ");
1039 if (atoi(argv[L_GROUP]))
1041 if (atoi(argv[L_NFSGROUP]))
1042 printf(" (and an NFS group)");
1043 printf(" with GID %d\n", atoi(argv[L_GID]));
1047 printf("Owner: %s %s\n", argv[L_ACE_TYPE], argv[L_ACE_NAME]);
1048 if (strcmp(argv[L_MEMACE_TYPE], "NONE"))
1049 printf("Membership ACL: %s %s\n", argv[L_MEMACE_TYPE],
1050 argv[L_MEMACE_NAME]);
1051 printf("Last modified by %s with %s on %s\n",
1052 argv[L_MODBY], argv[L_MODWITH], argv[L_MODTIME]);
1057 /* Copy retrieved information about a list into a new argv */
1059 int save_list_info(int argc, char **argv, void *hint)
1061 char **nargv = hint;
1063 for (argc = 0; argc < 14; argc++)
1064 nargv[argc + 1] = strdup(argv[argc]);
1068 /* Show the retrieve list member count */
1070 int show_list_count(int argc, char **argv, void *hint)
1072 printf("Members: %s\n", argv[0]);
1077 /* Recursively find all of the members of listname, and then display them */
1079 void recursive_display_list_members(void)
1081 int status, count, savecount;
1082 struct save_queue *lists, *members;
1083 struct member *m, *m1, *data;
1085 lists = sq_create();
1086 members = sq_create();
1087 m = malloc(sizeof(struct member));
1090 sq_save_data(lists, m);
1092 while (sq_get_data(lists, &m))
1094 sq_destroy(memberlist);
1095 memberlist = sq_create();
1096 status = mr_query("get_members_of_list", 1, &(m->name),
1097 get_list_members, memberlist);
1099 com_err(whoami, status, "while getting members of list %s", m->name);
1100 while (sq_get_data(memberlist, &m1))
1102 if (m1->type == M_LIST)
1103 unique_add_member(lists, m1);
1105 unique_add_member(members, m1);
1108 savecount = count = sq_count_elts(members);
1109 data = malloc(count * sizeof(struct member));
1111 while (sq_get_data(members, &m))
1112 memcpy(&data[count++], m, sizeof(struct member));
1113 qsort(data, count, sizeof(struct member), membercmp);
1114 for (count = 0; count < savecount; count++)
1115 show_list_member(&data[count]);
1119 /* add a struct member to a queue if that member isn't already there. */
1121 void unique_add_member(struct save_queue *q, struct member *m)
1123 struct save_queue *qp;
1125 for (qp = q->q_next; qp != q; qp = qp->q_next)
1127 if (!membercmp(qp->q_data, m))
1134 /* Collect the retrieved members of the list */
1136 int get_list_members(int argc, char **argv, void *sq)
1138 struct save_queue *q = sq;
1141 m = malloc(sizeof(struct member));
1154 m->type = M_KERBEROS;
1157 m->name = strdup(argv[1]);
1159 m->tag = strdup(argv[2]);
1161 m->tag = strdup("");
1167 /* Open file, parse members from file, and put them on the specified queue */
1168 void get_members_from_file(char *filename, struct save_queue *queue)
1172 struct member *memberstruct;
1174 if (!strcmp(filename, "-"))
1178 in = fopen(filename, "r");
1181 com_err(whoami, errno, "while opening %s for input", filename);
1186 while (fgets(buf, BUFSIZ, in))
1188 if ((memberstruct = parse_member(buf)))
1189 sq_save_data(queue, memberstruct);
1193 com_err(whoami, errno, "while reading from %s", filename);
1199 /* Collect the possible expansions of the alias MAILHUB */
1201 int collect(int argc, char **argv, void *l)
1206 for (i = 0; (*list)[i]; i++)
1208 *list = realloc(*list, (i + 2) * sizeof(char *));
1209 (*list)[i] = strdup(argv[2]);
1210 (*list)[i + 1] = NULL;
1215 /* Parse a line of input, fetching a member. NULL is returned if a member
1216 * is not found. ';' is a comment character.
1219 struct member *parse_member(char *s)
1224 while (*s && isspace(*s))
1227 while (*p && *p != '\n' && *p != ';')
1229 if (isprint(*p) && !isspace(*p))
1236 if (p == s || strlen(s) == 0)
1239 if (!(m = malloc(sizeof(struct member))))
1241 m->tag = strdup("");
1243 if ((p = strchr(s, ':')))
1247 if (!strcasecmp("user", s))
1249 else if (!strcasecmp("list", s))
1251 else if (!strcasecmp("string", s))
1253 else if (!strcasecmp("kerberos", s))
1254 m->type = M_KERBEROS;
1261 m->name = strdup(m->name);
1265 m->name = strdup(s);
1273 * This routine two compares members by the following rules:
1274 * 1. A USER is less than a LIST
1275 * 2. A LIST is less than a STRING
1276 * 3. If two members are of the same type, the one alphabetically first
1277 * is less than the other
1278 * It returs < 0 if the first member is less, 0 if they are identical, and
1279 * > 0 if the second member is less (the first member is greater).
1282 int membercmp(const void *mem1, const void *mem2)
1284 const struct member *m1 = mem1, *m2 = mem2;
1286 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
1287 return strcmp(m1->name, m2->name);
1289 return m1->type - m2->type;
1293 int sq_count_elts(struct save_queue *q)
1299 while (sq_get_data(q, &foo))
1304 char *get_username(void)
1308 username = getenv("USER");
1311 username = mrcl_krb_user();
1314 com_err(whoami, 0, "Could not determine username");