3 * This is the file lists.c for the Moira Client, which allows users
4 * to quickly and easily maintain most parts of the Moira database.
5 * It Contains: All list manipulation functions, except delete.
8 * By: Chris D. Peterson
10 * Copyright (C) 1988-1998 by the Massachusetts Institute of Technology.
11 * For copying and distribution information, please see the file
15 #include <mit-copyright.h>
17 #include <moira_site.h>
28 struct qelem *GetListInfo(int type, char *name1, char *name2);
29 char **AskListInfo(char **info, Bool name);
30 int AddList(int argc, char **argv);
31 void ListMembersByType(char *type);
32 int GetMemberInfo(char *action, char **ret_argv);
39 #define DEFAULT_ACTIVE DEFAULT_YES
40 #define DEFAULT_PUBLIC DEFAULT_YES
41 #define DEFAULT_HIDDEN DEFAULT_NO
42 #define DEFAULT_MAILLIST DEFAULT_YES
43 #define DEFAULT_GROUP DEFAULT_NO
44 #define DEFAULT_GID UNIQUE_GID
45 #define DEFAULT_ACE_TYPE "user"
46 #define DEFAULT_ACE_NAME (user)
47 #define DEFAULT_DESCRIPTION DEFAULT_COMMENT
49 /* globals only for this file. */
51 static char current_list[BUFSIZ];
53 /* Function Name: PrintListAce
54 * Description: This function prints the list ace information.
55 * Arguments: info - an info structure.
59 static void PrintListAce(char **info)
63 sprintf(buf, "Item: %-20s Name: %s", info[ACE_TYPE], info[ACE_NAME]);
67 /* Function Name: PrintListInfo
68 * Description: This function Prints out the List info in a coherent form.
69 * Arguments: info - the List info.
73 static void PrintListInfo(char **info)
78 sprintf(buf, "%20sList: %s", "", info[L_NAME]);
80 sprintf(buf, "Description: %s", info[L_DESC]);
82 if (atoi(info[L_MAILLIST]))
83 Put_message("This list is a mailing list.");
85 Put_message("This list is NOT a mailing list.");
86 if (atoi(info[L_GROUP]))
88 sprintf(buf, "This list is a Group and its ID number is %s",
93 Put_message("This list is NOT a Group.");
95 if (!strcmp(info[L_ACE_TYPE], "NONE"))
96 Put_message("This list has no Administrator, how strange?!");
99 sprintf(buf, "The Administrator of this list is the %s: %s",
100 info[L_ACE_TYPE], info[L_ACE_NAME]);
104 sprintf(buf, "This list is: %s, %s, and %s",
105 atoi(info[L_ACTIVE]) ? "active" : "inactive",
106 atoi(info[L_PUBLIC]) ? "public" : "private",
107 atoi(info[L_HIDDEN]) ? "hidden" : "visible");
109 sprintf(buf, MOD_FORMAT, info[L_MODBY], info[L_MODTIME], info[L_MODWITH]);
113 /* Function Name: GetListInfo
114 * Description: Stores all info about a group of lists in a queue.
115 * Arguments: type - type of info to store.
116 * name - name of the info.
117 * Returns: the first element in the queue.
120 struct qelem *GetListInfo(int type, char *name1, char *name2)
123 struct qelem *elem = NULL;
130 if ((status = do_mr_query("get_list_info", 1, args, StoreInfo, &elem)))
132 com_err(program_name, status, " in get_list_info");
138 if ((status = do_mr_query("get_members_of_list", 1, args,
141 com_err(program_name, status, " in get_members_of_list");
148 if ((status = do_mr_query("get_lists_of_member", 2, args,
151 com_err(program_name, status, " in get_list_of_members");
158 if ((status = do_mr_query("get_ace_use", 2, args, StoreInfo, &elem)))
160 com_err(program_name, status, " in get_ace_use");
165 return QueueTop(elem);
168 /* Function Name: AskListInfo.
169 * Description: This function askes the user for information about a
170 * machine and saves it into a structure.
171 * Arguments: info - a pointer the the structure to put the
173 * name - add a newname field? (T/F)
174 * Returns: SUB_ERROR or SUB_NORMAL.
177 char **AskListInfo(char **info, Bool name)
179 char temp_buf[BUFSIZ], *newname;
182 sprintf(temp_buf, "Setting information of list %s.", info[L_NAME]);
183 Put_message(temp_buf);
190 newname = strdup(info[L_NAME]);
191 if (GetValueFromUser("The new name for this list", &newname) ==
194 if (ValidName(newname))
198 if (GetYesNoValueFromUser("Is this an active list", &info[L_ACTIVE]) ==
201 if (GetYesNoValueFromUser("Is this a public list", &info[L_PUBLIC]) ==
204 if (GetYesNoValueFromUser("Is this a hidden list", &info[L_HIDDEN]) ==
207 if (GetYesNoValueFromUser("Is this a maillist", &info[L_MAILLIST]) ==
210 if (GetYesNoValueFromUser("Is this a group", &info[L_GROUP]) == SUB_ERROR)
212 if (atoi(info[L_GROUP]))
214 if (GetValueFromUser("What is the GID for this group.", &info[L_GID]) ==
219 if (GetTypeFromUser("What Type of Administrator", "ace_type",
220 &info[L_ACE_TYPE]) == SUB_ERROR)
222 if (strcasecmp(info[L_ACE_TYPE], "NONE") &&
223 strcasecmp(info[L_ACE_TYPE], "none"))
225 sprintf(temp_buf, "Which %s will be the administrator of this list: ",
227 if (GetValueFromUser(temp_buf, &info[L_ACE_NAME]) == SUB_ERROR)
230 if (GetValueFromUser("Description: ", &info[L_DESC]) == SUB_ERROR)
233 FreeAndClear(&info[L_MODTIME], TRUE);
234 FreeAndClear(&info[L_MODBY], TRUE);
235 FreeAndClear(&info[L_MODWITH], TRUE);
237 * Slide the newname into the #2 slot, this screws up all future references
240 if (name) /* slide the newname into the #2 slot. */
241 SlipInNewName(info, newname);
246 /* -------------- List functions. -------------- */
248 /* Function Name: ShowListInfo.
249 * Description: shows info on a list.
250 * Arguments: argc, argv - name of list in argv[1].
251 * Returns: DM status code.
254 int ShowListInfo(int argc, char **argv)
256 struct qelem *top, *list;
258 top = list = GetListInfo(LIST, argv[1], NULL);
261 PrintListInfo(list->q_data);
269 /* Function Name: RealUpdateList
270 * Description: performs the actual update of the list.
271 * Arguments: info - all information needed to update the list.
272 * junk - an UNUSED boolean.
276 static void RealUpdateList(char **info, Bool junk)
280 struct qelem *elem = NULL;
282 if (!(args = AskListInfo(info, TRUE)))
284 Put_message("Aborted.");
289 * If the new list name is less than 8 characters, make sure it doesn't
290 * collide with a username.
292 if ((strlen(args[2]) <= 8) &&
293 do_mr_query("get_user_account_by_login", 1, args + 1,
294 StoreInfo, &elem) != MR_NO_MATCH)
298 sprintf(buf, "\nA user by the name `%s' already exists in the database.",
301 Loop(QueueTop(elem), FreeInfo);
303 if (YesNoQuestion("Do you still want to rename this list to that name",
306 Put_message("List ** NOT ** Updated.");
311 if ((stat = do_mr_query("update_list", CountArgs(args), args,
312 NULL, NULL)) != MR_SUCCESS)
314 com_err(program_name, stat, " in UpdateList.");
315 Put_message("List ** NOT ** Updated.");
318 Put_message("List successfully updated.");
321 /* Function Name: UpdateList
322 * Description: updates the information on a list.
323 * Arguments: argc, argv - name of list in argv[1].
324 * Returns: DM Status code.
327 int UpdateList(int argc, char **argv)
331 top = GetListInfo(LIST, argv[1], (char *) NULL);
332 QueryLoop(top, NullPrint, RealUpdateList, "Update the list");
338 /* Function Name: SetDefaults
339 * Description: sets defaults for AddList function
340 * Arguments: info - the array to add them to.
341 * name - name of the program to add.
342 * Returns: defaults - the default information.
345 static char **SetDefaults(char **info, char *name)
347 info[L_NAME] = strdup(name);
348 info[L_ACTIVE] = strdup(DEFAULT_ACTIVE);
349 info[L_PUBLIC] = strdup(DEFAULT_PUBLIC);
350 info[L_HIDDEN] = strdup(DEFAULT_HIDDEN);
351 info[L_MAILLIST] = strdup(DEFAULT_MAILLIST);
352 info[L_GROUP] = strdup(DEFAULT_GROUP);
353 info[L_GID] = strdup(DEFAULT_GID);
354 info[L_ACE_TYPE] = strdup(DEFAULT_ACE_TYPE);
355 info[L_ACE_NAME] = strdup(DEFAULT_ACE_NAME);
356 info[L_DESC] = strdup(DEFAULT_DESCRIPTION);
357 info[L_MODTIME] = info[L_MODBY] = info[L_MODWITH] = info[L_END] = NULL;
361 /* Function Name: AddList
363 * Arguments: argc, argv - name of list in argv[1].
364 * Returns: SUB_ERROR if list not created.
367 int AddList(int argc, char **argv)
369 static char *info[MAX_ARGS_SIZE], **add_args;
370 int status, ret_code = SUB_NORMAL;
371 struct qelem *elem = NULL;
373 if (!ValidName(argv[1]))
375 status = do_mr_query("get_list_info", 1, argv + 1, NULL, NULL);
376 if (status != MR_NO_MATCH)
378 if (status == MR_SUCCESS)
379 Put_message("This list already exists.");
381 com_err(program_name, status, " in AddList.");
386 * If the listname is less than 8 characters, make sure it doesn't
387 * collide with a username.
389 if ((strlen(argv[1]) <= 8) &&
390 do_mr_query("get_user_account_by_login", 1, argv + 1,
391 StoreInfo, &elem) != MR_NO_MATCH)
395 sprintf(buf, "\nA user by the name `%s' already exists in the database.",
398 Loop(QueueTop(elem), FreeInfo);
400 if (YesNoQuestion("Crate a list with the same name", FALSE) != TRUE)
404 if (!(add_args = AskListInfo(SetDefaults(info, argv[1]), FALSE)))
406 Put_message("Aborted.");
410 if ((status = do_mr_query("add_list", CountArgs(add_args), add_args,
411 NULL, NULL)) != MR_SUCCESS)
413 com_err(program_name, status, " in AddList.");
414 Put_message("List Not Created.");
415 ret_code = SUB_ERROR;
422 /* Function Name: Instructions
423 * Description: This func prints out instruction on manipulating lists.
425 * Returns: DM Status Code.
428 int ListHelp(int argc, char **argv)
430 static char *message[] = {
431 "Listmaint handles the creation, deletion, and updating of lists.",
432 "A list can be a mailing list, a group list, or both.",
433 "The concept behind lists is that a list has an owner",
434 "- administrator - and members.",
435 "The administrator of a list may be another list.",
436 "The members of a list can be users (login names), other lists,",
437 "or address strings.",
438 "You can use certain keys to do the following:",
439 " Refresh the screen - Type ctrl-L.",
440 " Escape from a function - Type ctrl-C.",
441 " Suspend the program (temporarily) - Type ctrl-Z.",
445 return PrintHelp(message);
448 /*-*-* LISTMAINT UPDATE MENU *-*-*/
450 /* Function Name: ListmaintMemberMenuEntry
451 * Description: entry routine into the listmaint member menu.
452 * Arguments: m - the member menu.
453 * argc, argv - name of the list in argv[1].
457 int ListmaintMemberMenuEntry(Menu *m, int argc, char **argv)
459 char temp_buf[BUFSIZ];
460 char *list_name = argv[1];
463 if (!ValidName(list_name))
468 if (AddList(argc, argv) == SUB_ERROR)
470 sprintf(temp_buf, "List '%s' created. Do you want to %s", list_name,
471 "change its membership (y/n)? ");
472 if (YesNoQuestion(temp_buf, TRUE) != TRUE)
476 /* All we want to know is if it exists. */
477 switch ((stat = do_mr_query("count_members_of_list", 1, argv + 1,
483 Put_message("This list does not exist.");
486 Put_message("You are not allowed to view this list.");
489 com_err(program_name, stat, " in get_list_info");
493 sprintf(temp_buf, "Change/Display membership of '%s'", list_name);
494 m->m_title = strdup(temp_buf);
495 strcpy(current_list, list_name);
499 /* Function Name: ListmaintMemberMenuExit
500 * Description: This is the function called when the member menu is
501 * exited, it frees the memory that is storing the name.
502 * Arguments: m - the menu
506 int ListmaintMemberMenuExit(Menu *m)
509 strcpy(current_list, "");
513 /* Function Name: ListMembersByType
514 * Description: This function lists the users of a list by type.
515 * Arguments: type - the type of the list "USER", "LIST", or "STRING".
517 * NOTE: if type is NULL, all lists members are listed.
520 void ListMembersByType(char *type)
522 char temp_buf[BUFSIZ];
526 args[0] = current_list;
530 if ((status = do_mr_query("get_members_of_list", CountArgs(args), args,
532 com_err(program_name, status, " in ListMembersByType");
536 Put_message("List is empty (no members).");
539 sprintf(temp_buf, "No %s Members", type);
540 Put_message(temp_buf);
545 /* Function Name: ListAllMembers
546 * Description: lists all members of the current list.
551 int ListAllMembers(int argc, char **argv)
553 ListMembersByType(NULL);
557 /* Function Name: ListUserMembers
558 * Description: This function lists all members of a list of type "USER".
560 * Returns: DM_NORMAL.
563 int ListUserMembers(int argc, char **argv)
565 ListMembersByType("USER");
569 /* Function Name: ListListMembers
570 * Description: This function lists all members of a list of type "LIST".
572 * Returns: DM_NORMAL.
575 int ListListMembers(int argc, char **argv)
577 ListMembersByType("LIST");
581 /* Function Name: ListStringMembers
582 * Description:This function lists all members of a list of type "STRING".
584 * Returns: DM_NORMAL.
587 int ListStringMembers(int argc, char **argv)
589 ListMembersByType("STRING");
593 /* Function Name: GetMemberInfo
594 * Description: This function gets the information needed to
595 * add or delete a user from a list.
596 * Arguments: argc, argv - standard.
597 * action - name of the action to be performed either
599 * ret_argc, ret_argv - the returned value of argc and argv.
600 * Returns: SUB_ERROR or SUB_NORMAL.
603 int GetMemberInfo(char *action, char **ret_argv)
605 char temp_buf[BUFSIZ];
607 ret_argv[LM_LIST] = strdup(current_list);
609 ret_argv[LM_TYPE] = strdup("user");
610 if (GetTypeFromUser("Type of member", "member", &ret_argv[LM_TYPE]) ==
614 sprintf(temp_buf, "Name of %s to %s", ret_argv[LM_TYPE], action);
615 ret_argv[LM_MEMBER] = strdup(user);
616 if (GetValueFromUser(temp_buf, &ret_argv[LM_MEMBER]) == SUB_ERROR)
618 ret_argv[LM_END] = NULL; /* NULL terminate this list. */
620 if (strcasecmp(ret_argv[LM_TYPE], "string") &&
621 !ValidName(ret_argv[LM_MEMBER]))
629 /* Function Name: AddMember
630 * Description: This function adds a member to a list.
632 * Returns: DM_NORMAL.
635 int AddMember(int argc, char **argv)
637 char *args[10], temp_buf[BUFSIZ], *p;
639 struct qelem *mailhubs, *elem;
641 if (GetMemberInfo("add", args) == SUB_ERROR)
644 if (!strcmp(args[LM_TYPE], "STRING"))
646 if ((p = strchr(args[LM_MEMBER], '@')))
648 char *host = canonicalize_hostname(strdup(++p));
649 mailhubs = GetTypeValues("mailhub");
650 for (elem = mailhubs; elem; elem = elem->q_forw)
652 if (!strcasecmp(host, elem->q_data))
655 host = strdup(args[LM_MEMBER]);
657 sprintf(temp_buf, "String \"%s\" should be USER or LIST "
658 "\"%s\" because it is a local name.", host,
660 Put_message(temp_buf);
668 else if (!strchr(args[LM_MEMBER], '!'))
670 Put_message("Member which is not a foreign mail address "
671 "should not be type STRING.");
676 if ((status = do_mr_query("add_member_to_list", CountArgs(args), args,
677 NULL, NULL)) != MR_SUCCESS)
679 if (status == MR_EXISTS)
681 sprintf(temp_buf, "The %s %s is already a member of LIST %s.",
682 args[LM_TYPE], args[LM_MEMBER], args[LM_LIST]);
683 Put_message(temp_buf);
686 com_err(program_name, status, " in AddMember");
693 /* Function Name: DeleteMember
694 * Description: This function deletes a member from a list.
699 int DeleteMember(int argc, char **argv)
704 if (GetMemberInfo("delete", args) == SUB_ERROR)
707 if (Confirm("Are you sure you want to delete this member?"))
709 if ((status = do_mr_query("delete_member_from_list", CountArgs(args),
711 com_err(program_name, status, " in DeleteMember");
713 Put_message("Deletion Completed.");
716 Put_message("Deletion has been Aborted.");
722 /* Function Name: InterRemoveItemFromLists
723 * Description: This function allows interactive removal of an item
724 * (user, string, list) for all list that it is on.
726 * Returns: DM_NORMAL.
727 * NOTES: QueryLoop() does not work here because info does not have
728 * enough information in it to delete the member from the list.
731 int InterRemoveItemFromLists(int argc, char **argv)
734 char *type, *name, *args[10], buf[BUFSIZ];
735 struct qelem *top, *elem;
737 type = strdup("USER");
738 if (GetTypeFromUser("Type of member", "member", &type) == SUB_ERROR)
741 sprintf(buf, "Name of %s", type);
743 if (GetValueFromUser(buf, &name) == SUB_ERROR)
746 if (!ValidName(name))
749 top = elem = GetListInfo(GLOM, type, name);
754 char **info = elem->q_data;
755 sprintf(line, "Delete %s %s from the list \"%s\" (y/n/q)? ", type,
756 name, info[GLOM_NAME]);
757 switch (YesNoQuitQuestion(line, FALSE))
760 Put_message("deleting...");
761 args[DM_LIST] = info[GLOM_NAME];
762 args[DM_TYPE] = type;
763 args[DM_MEMBER] = name;
764 if ((status = do_mr_query("delete_member_from_list", 3, args,
767 /* should probabally check to delete list. */
768 com_err(program_name, status, " in delete_member");
774 Put_message("Aborting...");
784 /*-*-* LIST MENU *-*-*/
786 /* Function Name: ListByMember
787 * Description: This gets all lists that a given member is a member of.
789 * Returns: DM_NORMAL.
792 int ListByMember(int argc, char **argv)
794 char buf[BUFSIZ], temp_buf[BUFSIZ], *type, *name, **info;
795 Bool maillist, group;
796 struct qelem *top, *elem;
798 type = strdup("USER");
799 if (GetTypeFromUser("Type of member", "member", &type) == SUB_ERROR)
802 sprintf(buf, "Name of %s", type);
804 if (GetValueFromUser(buf, &name) == SUB_ERROR)
807 /* What we really want is a recursive search */
808 sprintf(temp_buf, "R%s", type);
810 type = strdup(temp_buf);
812 if ((maillist = YesNoQuestion("Show Lists that are Maillists (y/n) ?",
815 if ((group = YesNoQuestion("Show Lists that are Groups (y/n) ?",
819 elem = top = GetListInfo(GLOM, type, name);
824 if ((maillist == TRUE && !strcmp(info[GLOM_MAILLIST], "1")) ||
825 (group == TRUE && !strcmp(info[GLOM_GROUP], "1")))
826 Put_message(info[GLOM_NAME]);
833 /* Function Name: ListByAdministrator
834 * Description: This function prints all lists which a given user or
837 * Returns: DM_NORMAL.
840 int ListByAdministrator(int argc, char **argv)
842 char buf[BUFSIZ], temp_buf[BUFSIZ], *type, *name;
845 type = strdup("USER");
846 if (GetTypeFromUser("Type of member", "member", &type) == SUB_ERROR)
849 sprintf(buf, "Name of %s", type);
851 if (GetValueFromUser(buf, &name) == SUB_ERROR)
854 switch (YesNoQuestion("Do you want a recursive search (y/n)", FALSE))
857 sprintf(temp_buf, "R%s", type); /* "USER" to "RUSER" etc. */
859 type = strdup(temp_buf);
867 top = GetListInfo(ACE_USE, type, name);
868 Loop(top, PrintListAce);
874 /* Function Name: ListAllPublicMailLists
875 * Description: This function lists all public mailing lists.
877 * Returns: DM_NORMAL.
880 int ListAllPublicMailLists(int argc, char **argv)
883 static char *args[] = {
886 "FALSE", /* hidden */
887 "TRUE", /* maillist */
888 "DONTCARE", /* group. */
891 if (YesNoQuestion("This query will take a while. Do you wish to continue?",
894 if ((status = do_mr_query("qualified_get_lists", 5, args,
895 Print, NULL)) != MR_SUCCESS)
896 com_err(program_name, status, " in ListAllGroups");