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 mrcl_com_err(whoami);
664 if (status == MRCL_REJECT)
669 else if (memberstruct->type == M_ANY && status != MR_SUCCESS)
671 /* if user is trying to add something which isn't a
672 remote string, or a list, or a user, and didn't
673 explicitly specify `STRING:', it's probably a typo */
674 com_err(whoami, MR_NO_MATCH, "while adding member %s to %s",
675 memberstruct->name, listname);
680 membervec[1] = "STRING";
681 status = mr_query("add_tagged_member_to_list", 4, membervec,
683 if (status != MR_SUCCESS)
685 com_err(whoami, status, "while adding member %s to %s",
686 memberstruct->name, listname);
691 membervec[1] = "KERBEROS";
692 status = mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
693 if (mrcl_get_message())
694 mrcl_com_err(whoami);
695 status = mr_query("add_tagged_member_to_list", 4, membervec,
697 if (status != MR_SUCCESS)
699 com_err(whoami, status, "while adding member %s to %s",
700 memberstruct->name, listname);
707 /* Process the delete list */
708 while (sq_get_data(dellist, &memberstruct))
710 membervec[0] = listname;
711 membervec[2] = memberstruct->name;
714 printf("Deleting member ");
715 show_list_member(memberstruct);
717 switch (memberstruct->type)
721 membervec[1] = "USER";
722 status = mr_query("delete_member_from_list", 3, membervec,
724 if (status == MR_SUCCESS)
726 else if ((status != MR_USER && status != MR_NO_MATCH) ||
727 memberstruct->type != M_ANY)
729 com_err(whoami, status, "while deleting member %s from %s",
730 memberstruct->name, listname);
735 membervec[1] = "LIST";
736 status = mr_query("delete_member_from_list", 3, membervec,
738 if (status == MR_SUCCESS)
740 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
741 memberstruct->type != M_ANY)
743 if (status == MR_PERM && memberstruct->type == M_ANY &&
744 !strcmp(membervec[2], get_username()))
746 /* M_ANY means we've fallen through from the user
747 * case. The user is trying to remove himself from
748 * a list, but we got MR_USER or MR_NO_MATCH above,
749 * meaning he's not really on it, and we got MR_PERM
750 * when trying to remove LIST:$USER because he's not
751 * on the acl. That error is useless, so return
752 * MR_NO_MATCH instead. However, this will generate the
753 * wrong error if the user was trying to remove the list
754 * with his username from a list he doesn't administrate
755 * without explicitly specifying "list:".
757 status = MR_NO_MATCH;
759 com_err(whoami, status, "while deleting member %s from %s",
760 memberstruct->name, listname);
765 membervec[1] = "STRING";
766 status = mr_query("delete_member_from_list", 3, membervec,
768 if (status == MR_STRING && memberstruct->type == M_ANY)
770 com_err(whoami, 0, " Unable to find member %s to delete from %s",
771 memberstruct->name, listname);
773 if (!strcmp(membervec[0], get_username()))
775 fprintf(stderr, "(If you were trying to remove yourself "
776 "from the list \"%s\",\n", membervec[2]);
777 fprintf(stderr, "the correct command is \"blanche %s -d "
778 "%s\".)\n", membervec[2], membervec[0]);
781 else if (status != MR_SUCCESS)
783 com_err(whoami, status, "while deleting member %s from %s",
784 memberstruct->name, listname);
789 membervec[1] = "KERBEROS";
790 status = mr_query("delete_member_from_list", 3, membervec,
792 if (status == MR_STRING || status == MR_NO_MATCH)
794 /* Try canonicalizing the Kerberos principal and trying
795 * again. If we succeed, print the message from mrcl.
796 * Otherwise, just pretend we never did this and print
797 * the original error message.
799 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
800 if (mrcl_get_message())
802 if (mr_query("delete_member_from_list", 3, membervec,
803 NULL, NULL) == MR_SUCCESS)
804 mrcl_com_err(whoami);
808 if (status != MR_SUCCESS)
810 com_err(whoami, status, "while deleting member %s from %s",
811 memberstruct->name, listname);
817 /* Process the tag list */
818 while (sq_get_data(taglist, &memberstruct))
820 membervec[0] = listname;
821 membervec[2] = memberstruct->name;
822 membervec[3] = memberstruct->tag;
825 printf("Tagging member ");
826 show_list_member(memberstruct);
828 switch (memberstruct->type)
832 membervec[1] = "USER";
833 status = mr_query("tag_member_of_list", 4, membervec,
835 if (status == MR_SUCCESS)
837 else if ((status != MR_USER && status != MR_NO_MATCH) ||
838 memberstruct->type != M_ANY)
840 com_err(whoami, status, "while changing tag on member %s of %s",
841 memberstruct->name, listname);
846 membervec[1] = "LIST";
847 status = mr_query("tag_member_of_list", 4, membervec,
849 if (status == MR_SUCCESS)
851 else if ((status != MR_LIST && status != MR_NO_MATCH) ||
852 memberstruct->type != M_ANY)
854 com_err(whoami, status, "while changing tag on member %s of %s",
855 memberstruct->name, listname);
860 membervec[1] = "STRING";
861 status = mr_query("tag_member_of_list", 4, membervec,
863 if (status == MR_STRING && memberstruct->type == M_ANY)
865 com_err(whoami, 0, " Unable to find member %s on list %s",
866 memberstruct->name, listname);
869 else if (status != MR_SUCCESS)
871 com_err(whoami, status, "while retagging member %s on %s",
872 memberstruct->name, listname);
877 membervec[1] = "KERBEROS";
878 status = mr_query("tag_member_of_list", 4, membervec,
880 if (status == MR_STRING || status == MR_NO_MATCH)
882 /* Try canonicalizing the Kerberos principal and trying
883 * again. If we succeed, print the message from mrcl.
884 * Otherwise, just pretend we never did this and print
885 * the original error message.
887 mrcl_validate_kerberos_member(membervec[2], &membervec[2]);
888 if (mrcl_get_message())
890 if (mr_query("tag_member_of_list", 4, membervec,
891 NULL, NULL) == MR_SUCCESS)
892 mrcl_com_err(whoami);
896 if (status != MR_SUCCESS)
898 com_err(whoami, status, "while changing tag on member %s of %s",
899 memberstruct->name, listname);
905 /* Display the members of the list now, if requested */
909 recursive_display_list_members();
912 status = mr_query(showtags ? "get_tagged_members_of_list" :
913 "get_members_of_list", 1, &listname,
914 get_list_members, memberlist);
916 com_err(whoami, status, "while getting members of list %s",
918 while (sq_get_data(memberlist, &memberstruct))
919 show_list_member(memberstruct);
925 exit(success ? 0 : 1);
928 void usage(char **argv)
930 #define USAGE_OPTIONS_FORMAT " %-39s%s\n"
931 fprintf(stderr, "Usage: %s listname [options]\n", argv[0]);
932 fprintf(stderr, "Options are\n");
933 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-v | -verbose",
935 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-m | -members",
936 "-R | -rename newname");
937 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-u | -users",
939 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-l | -lists",
941 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-s | -strings",
943 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-k | -kerberos",
945 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-i | -info",
947 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-r | -recursive",
949 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-a | -add member",
951 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-d | -delete member",
953 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-al | -addlist filename",
955 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-dl | -deletelist filename",
957 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-f | -file filename",
959 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-at | -addtagged member tag",
961 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-ct | -changetag member tag",
962 "-D | -desc description");
963 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-t | -tags",
964 "-O | -owner owner");
965 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-n | -noauth",
966 "-MA | -memacl membership_acl");
967 fprintf(stderr, USAGE_OPTIONS_FORMAT, "-db | -database host[:port]",
973 /* Display the members stored in the queue */
975 void show_list_member(struct member *memberstruct)
979 switch (memberstruct->type)
1002 printf("%s\n", memberstruct->name);
1007 printf("%s:%s", s, memberstruct->name);
1010 if (memberstruct->type == M_LIST)
1011 printf("LIST:%s", memberstruct->name);
1012 else if (memberstruct->type == M_KERBEROS)
1013 printf("KERBEROS:%s", memberstruct->name);
1014 else if (memberstruct->type == M_STRING &&
1015 !strchr(memberstruct->name, '@'))
1016 printf("STRING:%s", memberstruct->name);
1018 printf("%s", memberstruct->name);
1020 if (showtags && *(memberstruct->tag))
1021 printf(" (%s)\n", memberstruct->tag);
1027 /* Show the retrieved information about a list */
1029 int show_list_info(int argc, char **argv, void *hint)
1031 printf("List: %s\n", argv[L_NAME]);
1032 printf("Description: %s\n", argv[L_DESC]);
1033 printf("Flags: %s, %s, and %s\n",
1034 atoi(argv[L_ACTIVE]) ? "active" : "inactive",
1035 atoi(argv[L_PUBLIC]) ? "public" : "private",
1036 atoi(argv[L_HIDDEN]) ? "hidden" : "visible");
1037 printf("%s is %sa maillist and is %sa group", argv[L_NAME],
1038 atoi(argv[L_MAILLIST]) ? "" : "not ",
1039 atoi(argv[L_GROUP]) ? "" : "not ");
1040 if (atoi(argv[L_GROUP]))
1042 if (atoi(argv[L_NFSGROUP]))
1043 printf(" (and an NFS group)");
1044 printf(" with GID %d\n", atoi(argv[L_GID]));
1048 printf("Owner: %s %s\n", argv[L_ACE_TYPE], argv[L_ACE_NAME]);
1049 if (strcmp(argv[L_MEMACE_TYPE], "NONE"))
1050 printf("Membership ACL: %s %s\n", argv[L_MEMACE_TYPE],
1051 argv[L_MEMACE_NAME]);
1052 printf("Last modified by %s with %s on %s\n",
1053 argv[L_MODBY], argv[L_MODWITH], argv[L_MODTIME]);
1058 /* Copy retrieved information about a list into a new argv */
1060 int save_list_info(int argc, char **argv, void *hint)
1062 char **nargv = hint;
1064 for (argc = 0; argc < 14; argc++)
1065 nargv[argc + 1] = strdup(argv[argc]);
1069 /* Show the retrieve list member count */
1071 int show_list_count(int argc, char **argv, void *hint)
1073 printf("Members: %s\n", argv[0]);
1078 /* Recursively find all of the members of listname, and then display them */
1080 void recursive_display_list_members(void)
1082 int status, count, savecount;
1083 struct save_queue *lists, *members;
1084 struct member *m, *m1, *data;
1086 lists = sq_create();
1087 members = sq_create();
1088 m = malloc(sizeof(struct member));
1091 sq_save_data(lists, m);
1093 while (sq_get_data(lists, &m))
1095 sq_destroy(memberlist);
1096 memberlist = sq_create();
1097 status = mr_query("get_members_of_list", 1, &(m->name),
1098 get_list_members, memberlist);
1100 com_err(whoami, status, "while getting members of list %s", m->name);
1101 while (sq_get_data(memberlist, &m1))
1103 if (m1->type == M_LIST)
1104 unique_add_member(lists, m1);
1106 unique_add_member(members, m1);
1109 savecount = count = sq_count_elts(members);
1110 data = malloc(count * sizeof(struct member));
1112 while (sq_get_data(members, &m))
1113 memcpy(&data[count++], m, sizeof(struct member));
1114 qsort(data, count, sizeof(struct member), membercmp);
1115 for (count = 0; count < savecount; count++)
1116 show_list_member(&data[count]);
1120 /* add a struct member to a queue if that member isn't already there. */
1122 void unique_add_member(struct save_queue *q, struct member *m)
1124 struct save_queue *qp;
1126 for (qp = q->q_next; qp != q; qp = qp->q_next)
1128 if (!membercmp(qp->q_data, m))
1135 /* Collect the retrieved members of the list */
1137 int get_list_members(int argc, char **argv, void *sq)
1139 struct save_queue *q = sq;
1142 m = malloc(sizeof(struct member));
1155 m->type = M_KERBEROS;
1158 m->name = strdup(argv[1]);
1160 m->tag = strdup(argv[2]);
1162 m->tag = strdup("");
1168 /* Open file, parse members from file, and put them on the specified queue */
1169 void get_members_from_file(char *filename, struct save_queue *queue)
1173 struct member *memberstruct;
1175 if (!strcmp(filename, "-"))
1179 in = fopen(filename, "r");
1182 com_err(whoami, errno, "while opening %s for input", filename);
1187 while (fgets(buf, BUFSIZ, in))
1189 if ((memberstruct = parse_member(buf)))
1190 sq_save_data(queue, memberstruct);
1194 com_err(whoami, errno, "while reading from %s", filename);
1200 /* Collect the possible expansions of the alias MAILHUB */
1202 int collect(int argc, char **argv, void *l)
1207 for (i = 0; (*list)[i]; i++)
1209 *list = realloc(*list, (i + 2) * sizeof(char *));
1210 (*list)[i] = strdup(argv[2]);
1211 (*list)[i + 1] = NULL;
1216 /* Parse a line of input, fetching a member. NULL is returned if a member
1217 * is not found. ';' is a comment character.
1220 struct member *parse_member(char *s)
1225 while (*s && isspace(*s))
1228 while (*p && *p != '\n' && *p != ';')
1230 if (isprint(*p) && !isspace(*p))
1237 if (p == s || strlen(s) == 0)
1240 if (!(m = malloc(sizeof(struct member))))
1242 m->tag = strdup("");
1244 if ((p = strchr(s, ':')))
1248 if (!strcasecmp("user", s))
1250 else if (!strcasecmp("list", s))
1252 else if (!strcasecmp("string", s))
1254 else if (!strcasecmp("kerberos", s))
1255 m->type = M_KERBEROS;
1256 else if (!strcasecmp("none", s))
1264 m->name = strdup(m->name);
1268 m->name = strdup(s);
1269 m->type = strcasecmp(s, "none") ? M_ANY : M_NONE;
1276 * This routine two compares members by the following rules:
1277 * 1. A USER is less than a LIST
1278 * 2. A LIST is less than a STRING
1279 * 3. If two members are of the same type, the one alphabetically first
1280 * is less than the other
1281 * It returs < 0 if the first member is less, 0 if they are identical, and
1282 * > 0 if the second member is less (the first member is greater).
1285 int membercmp(const void *mem1, const void *mem2)
1287 const struct member *m1 = mem1, *m2 = mem2;
1289 if (m1->type == M_ANY || m2->type == M_ANY || (m1->type == m2->type))
1290 return strcmp(m1->name, m2->name);
1292 return m1->type - m2->type;
1296 int sq_count_elts(struct save_queue *q)
1302 while (sq_get_data(q, &foo))
1307 char *get_username(void)
1311 username = getenv("USER");
1314 username = mrcl_krb_user();
1317 com_err(whoami, 0, "Could not determine username");