1 #if (!defined(lint) && !defined(SABER))
2 static char rcsid_module_c[] = "$Header$";
5 /* This is the file lists.c for the MOIRA Client, which allows a nieve
6 * user to quickly and easily maintain most parts of the MOIRA database.
7 * It Contains: All list manipulation functions, except delete.
10 * By: Chris D. Peterson
16 * Copyright 1988 by the Massachusetts Institute of Technology.
18 * For further information on copyright and distribution
19 * see the file mit-copyright.h
25 #include <moira_site.h>
28 #include "mit-copyright.h"
38 #define DEFAULT_ACTIVE DEFAULT_YES
39 #define DEFAULT_PUBLIC DEFAULT_YES
40 #define DEFAULT_HIDDEN DEFAULT_NO
41 #define DEFAULT_MAILLIST DEFAULT_YES
42 #define DEFAULT_GROUP DEFAULT_NO
43 #define DEFAULT_GID UNIQUE_GID
44 #define DEFAULT_ACE_TYPE "user"
45 #define DEFAULT_ACE_NAME (user)
46 #define DEFAULT_DESCRIPTION DEFAULT_COMMENT
48 /* globals only for this file. */
50 static char current_list[BUFSIZ];
52 /* Function Name: PrintListAce
53 * Description: This function prints the list ace information.
54 * Arguments: info - an info structure.
58 static void PrintListAce(char **info)
62 sprintf(buf, "Item: %-20s Name: %s", info[ACE_TYPE], info[ACE_NAME]);
66 /* Function Name: PrintListInfo
67 * Description: This function Prints out the List info in a coherent form.
68 * Arguments: info - the List info.
72 static void PrintListInfo(char **info)
77 sprintf(buf, "%20sList: %s", "", info[L_NAME]);
79 sprintf(buf, "Description: %s", info[L_DESC]);
81 if (atoi(info[L_MAILLIST]))
82 Put_message("This list is a mailing list.");
84 Put_message("This list is NOT a mailing list.");
85 if (atoi(info[L_GROUP]))
87 sprintf(buf, "This list is a Group and its ID number is %s",
92 Put_message("This list is NOT a Group.");
94 if (!strcmp(info[L_ACE_TYPE], "NONE"))
95 Put_message("This list has no Administrator, how strange?!");
98 sprintf(buf, "The Administrator of this list is the %s: %s",
99 info[L_ACE_TYPE], info[L_ACE_NAME]);
103 sprintf(buf, "This list is: %s, %s, and %s",
104 atoi(info[L_ACTIVE]) ? "active" : "inactive",
105 atoi(info[L_PUBLIC]) ? "public" : "private",
106 atoi(info[L_HIDDEN]) ? "hidden" : "visible");
108 sprintf(buf, MOD_FORMAT, info[L_MODBY], info[L_MODTIME], info[L_MODWITH]);
112 /* Function Name: GetListInfo
113 * Description: Stores all info about a group of lists in a queue.
114 * Arguments: type - type of info to store.
115 * name - name of the info.
116 * Returns: the first element in the queue.
119 struct qelem *GetListInfo(int type, char *name1, char *name2)
122 struct qelem *elem = NULL;
129 if ((status = do_mr_query("get_list_info", 1, args,
130 StoreInfo, (char *) &elem)))
132 com_err(program_name, status, " in get_list_info");
138 if ((status = do_mr_query("get_members_of_list", 1, args,
139 StoreInfo, (char *) &elem)))
141 com_err(program_name, status, " in get_members_of_list");
148 if ((status = do_mr_query("get_lists_of_member", 2, args,
149 StoreInfo, (char *) &elem)))
151 com_err(program_name, status, " in get_list_of_members");
158 if ((status = do_mr_query("get_ace_use", 2, args,
159 StoreInfo, (char *) &elem)))
161 com_err(program_name, status, " in get_ace_use");
166 return QueueTop(elem);
169 /* Function Name: AskListInfo.
170 * Description: This function askes the user for information about a
171 * machine and saves it into a structure.
172 * Arguments: info - a pointer the the structure to put the
174 * name - add a newname field? (T/F)
175 * Returns: SUB_ERROR or SUB_NORMAL.
178 char **AskListInfo(char **info, Bool name)
180 char temp_buf[BUFSIZ], *newname;
183 sprintf(temp_buf, "Setting information of list %s.", info[L_NAME]);
184 Put_message(temp_buf);
191 newname = Strsave(info[L_NAME]);
192 if (GetValueFromUser("The new name for this list", &newname) ==
195 if (ValidName(newname))
199 if (GetYesNoValueFromUser("Is this an active list", &info[L_ACTIVE]) ==
202 if (GetYesNoValueFromUser("Is this a public list", &info[L_PUBLIC]) ==
205 if (GetYesNoValueFromUser("Is this a hidden list", &info[L_HIDDEN]) ==
208 if (GetYesNoValueFromUser("Is this a maillist", &info[L_MAILLIST]) ==
211 if (GetYesNoValueFromUser("Is this a group", &info[L_GROUP]) == SUB_ERROR)
213 if (atoi(info[L_GROUP]))
215 if (GetValueFromUser("What is the GID for this group.", &info[L_GID]) ==
220 if (GetTypeFromUser("What Type of Administrator", "ace_type",
221 &info[L_ACE_TYPE]) == SUB_ERROR)
223 if (strcasecmp(info[L_ACE_TYPE], "NONE") &&
224 strcasecmp(info[L_ACE_TYPE], "none"))
226 sprintf(temp_buf, "Which %s will be the administrator of this list: ",
228 if (GetValueFromUser(temp_buf, &info[L_ACE_NAME]) == SUB_ERROR)
231 if (GetValueFromUser("Description: ", &info[L_DESC]) == SUB_ERROR)
234 FreeAndClear(&info[L_MODTIME], TRUE);
235 FreeAndClear(&info[L_MODBY], TRUE);
236 FreeAndClear(&info[L_MODWITH], TRUE);
238 * Slide the newname into the #2 slot, this screws up all future references
241 if (name) /* slide the newname into the #2 slot. */
242 SlipInNewName(info, newname);
247 /* -------------- List functions. -------------- */
249 /* Function Name: ShowListInfo.
250 * Description: shows info on a list.
251 * Arguments: argc, argv - name of list in argv[1].
252 * Returns: DM status code.
255 int ShowListInfo(int argc, char **argv)
257 struct qelem *top, *list;
259 top = list = GetListInfo(LIST, argv[1], NULL);
262 PrintListInfo((char **) list->q_data);
270 /* Function Name: RealUpdateList
271 * Description: performs the actual update of the list.
272 * Arguments: info - all information needed to update the list.
273 * junk - an UNUSED boolean.
277 static void RealUpdateList(char **info, Bool junk)
281 struct qelem *elem = NULL;
283 if (!(args = AskListInfo(info, TRUE)))
285 Put_message("Aborted.");
290 * If the new list name is less than 8 characters, make sure it doesn't
291 * collide with a username.
293 if ((strlen(args[2]) <= 8) &&
294 do_mr_query("get_user_account_by_login", 1, args + 1,
295 StoreInfo, (char *) &elem) != MR_NO_MATCH)
299 sprintf(buf, "\nA user by the name `%s' already exists in the database.",
302 Loop(QueueTop(elem), FreeInfo);
304 if (YesNoQuestion("Do you still want to rename this list to that name",
307 Put_message("List ** NOT ** Updated.");
312 if ((stat = do_mr_query("update_list", CountArgs(args), args,
313 Scream, (char *) NULL)) != MR_SUCCESS)
315 com_err(program_name, stat, " in UpdateList.");
316 Put_message("List ** NOT ** Updated.");
319 Put_message("List successfully updated.");
322 /* Function Name: UpdateList
323 * Description: updates the information on a list.
324 * Arguments: argc, argv - name of list in argv[1].
325 * Returns: DM Status code.
328 int UpdateList(int argc, char **argv)
332 top = GetListInfo(LIST, argv[1], (char *) NULL);
333 QueryLoop(top, NullPrint, RealUpdateList, "Update the list");
339 /* Function Name: SetDefaults
340 * Description: sets defaults for AddList function
341 * Arguments: info - the array to add them to.
342 * name - name of the program to add.
343 * Returns: defaults - the default information.
346 static char **SetDefaults(char **info, char *name)
348 info[L_NAME] = Strsave(name);
349 info[L_ACTIVE] = Strsave(DEFAULT_ACTIVE);
350 info[L_PUBLIC] = Strsave(DEFAULT_PUBLIC);
351 info[L_HIDDEN] = Strsave(DEFAULT_HIDDEN);
352 info[L_MAILLIST] = Strsave(DEFAULT_MAILLIST);
353 info[L_GROUP] = Strsave(DEFAULT_GROUP);
354 info[L_GID] = Strsave(DEFAULT_GID);
355 info[L_ACE_TYPE] = Strsave(DEFAULT_ACE_TYPE);
356 info[L_ACE_NAME] = Strsave(DEFAULT_ACE_NAME);
357 info[L_DESC] = Strsave(DEFAULT_DESCRIPTION);
358 info[L_MODTIME] = info[L_MODBY] = info[L_MODWITH] = info[L_END] = NULL;
362 /* Function Name: AddList
364 * Arguments: argc, argv - name of list in argv[1].
365 * Returns: SUB_ERROR if list not created.
368 int AddList(int argc, char **argv)
370 static char *info[MAX_ARGS_SIZE], **add_args;
371 int status, ret_code = SUB_NORMAL;
372 struct qelem *elem = NULL;
374 if (!ValidName(argv[1]))
376 status = do_mr_query("get_list_info", 1, argv + 1, NullFunc, NULL);
377 if (status != MR_NO_MATCH)
379 if (status == MR_SUCCESS)
380 Put_message("This list already exists.");
382 com_err(program_name, status, " in AddList.");
387 * If the listname is less than 8 characters, make sure it doesn't
388 * collide with a username.
390 if ((strlen(argv[1]) <= 8) &&
391 do_mr_query("get_user_account_by_login", 1, argv + 1,
392 StoreInfo, (char *) &elem) != MR_NO_MATCH)
396 sprintf(buf, "\nA user by the name `%s' already exists in the database.",
399 Loop(QueueTop(elem), FreeInfo);
401 if (YesNoQuestion("Crate a list with the same name", FALSE) != TRUE)
405 if (!(add_args = AskListInfo(SetDefaults(info, argv[1]), FALSE)))
407 Put_message("Aborted.");
411 if ((status = do_mr_query("add_list", CountArgs(add_args), add_args,
412 Scream, (char *) NULL)) != MR_SUCCESS)
414 com_err(program_name, status, " in AddList.");
415 Put_message("List Not Created.");
416 ret_code = SUB_ERROR;
423 /* Function Name: Instructions
424 * Description: This func prints out instruction on manipulating lists.
426 * Returns: DM Status Code.
431 static char *message[] = {
432 "Listmaint handles the creation, deletion, and updating of lists.",
433 "A list can be a mailing list, a group list, or both.",
434 "The concept behind lists is that a list has an owner",
435 "- administrator - and members.",
436 "The administrator of a list may be another list.",
437 "The members of a list can be users (login names), other lists,",
438 "or address strings.",
439 "You can use certain keys to do the following:",
440 " Refresh the screen - Type ctrl-L.",
441 " Escape from a function - Type ctrl-C.",
442 " Suspend the program (temporarily) - Type ctrl-Z.",
446 return PrintHelp(message);
449 /*-*-* LISTMAINT UPDATE MENU *-*-*/
451 /* Function Name: ListmaintMemberMenuEntry
452 * Description: entry routine into the listmaint member menu.
453 * Arguments: m - the member menu.
454 * argc, argv - name of the list in argv[1].
458 int ListmaintMemberMenuEntry(Menu *m, int argc, char **argv)
460 char temp_buf[BUFSIZ];
461 char *list_name = argv[1];
464 if (!ValidName(list_name))
469 if (AddList(argc, argv) == SUB_ERROR)
471 sprintf(temp_buf, "List '%s' created. Do you want to %s", list_name,
472 "change its membership (y/n)? ");
473 if (YesNoQuestion(temp_buf, TRUE) != TRUE)
477 /* All we want to know is if it exists. */
478 switch ((stat = do_mr_query("count_members_of_list", 1, argv + 1,
484 Put_message("This list does not exist.");
487 Put_message("You are not allowed to view this list.");
490 com_err(program_name, stat, " in get_list_info");
494 sprintf(temp_buf, "Change/Display membership of '%s'", list_name);
495 m->m_title = Strsave(temp_buf);
496 strcpy(current_list, list_name);
500 /* Function Name: ListmaintMemberMenuExit
501 * Description: This is the function called when the member menu is
502 * exited, it frees the memory that is storing the name.
503 * Arguments: m - the menu
507 int ListmaintMemberMenuExit(Menu *m)
510 strcpy(current_list, "");
514 /* Function Name: ListMembersByType
515 * Description: This function lists the users of a list by type.
516 * Arguments: type - the type of the list "USER", "LIST", or "STRING".
518 * NOTE: if type is NULL, all lists members are listed.
521 int ListMembersByType(char *type)
523 char temp_buf[BUFSIZ];
527 args[0] = current_list;
531 if ((status = do_mr_query("get_members_of_list", CountArgs(args), args,
534 com_err(program_name, status, " in ListMembersByType");
540 Put_message("List is empty (no members).");
543 sprintf(temp_buf, "No %s Members", type);
544 Put_message(temp_buf);
549 /* Function Name: ListAllMembers
550 * Description: lists all members of the current list.
555 int ListAllMembers(void)
557 ListMembersByType(NULL);
561 /* Function Name: ListUserMembers
562 * Description: This function lists all members of a list of type "USER".
564 * Returns: DM_NORMAL.
567 int ListUserMembers(void)
569 ListMembersByType("USER");
573 /* Function Name: ListListMembers
574 * Description: This function lists all members of a list of type "LIST".
576 * Returns: DM_NORMAL.
579 int ListListMembers(void)
581 ListMembersByType("LIST");
585 /* Function Name: ListStringMembers
586 * Description:This function lists all members of a list of type "STRING".
588 * Returns: DM_NORMAL.
591 int ListStringMembers(void)
593 ListMembersByType("STRING");
597 /* Function Name: GetMemberInfo
598 * Description: This function gets the information needed to
599 * add or delete a user from a list.
600 * Arguments: argc, argv - standard.
601 * action - name of the action to be performed either
603 * ret_argc, ret_argv - the returned value of argc and argv.
604 * Returns: SUB_ERROR or SUB_NORMAL.
607 int GetMemberInfo(char *action, char **ret_argv)
609 char temp_buf[BUFSIZ];
611 ret_argv[LM_LIST] = Strsave(current_list);
613 ret_argv[LM_TYPE] = Strsave("user");
614 if (GetTypeFromUser("Type of member", "member", &ret_argv[LM_TYPE]) ==
618 sprintf(temp_buf, "Name of %s to %s", ret_argv[LM_TYPE], action);
619 ret_argv[LM_MEMBER] = Strsave(user);
620 if (GetValueFromUser(temp_buf, &ret_argv[LM_MEMBER]) == SUB_ERROR)
622 ret_argv[LM_END] = NULL; /* NULL terminate this list. */
624 if (strcasecmp(ret_argv[LM_TYPE], "string") &&
625 !ValidName(ret_argv[LM_MEMBER]))
633 /* Function Name: AddMember
634 * Description: This function adds a member to a list.
636 * Returns: DM_NORMAL.
641 char *args[10], temp_buf[BUFSIZ], *p;
643 struct qelem *mailhubs, *elem, *GetTypeValues();
645 if (GetMemberInfo("add", args) == SUB_ERROR)
648 if (!strcmp(args[LM_TYPE], "STRING"))
650 if ((p = strchr(args[LM_MEMBER], '@')))
652 char *host = canonicalize_hostname(strsave(++p));
653 mailhubs = GetTypeValues("mailhub");
654 for (elem = mailhubs; elem; elem = elem->q_forw)
656 if (!strcasecmp(host, elem->q_data))
659 host = strsave(args[LM_MEMBER]);
661 sprintf(temp_buf, "String \"%s\" should be USER or LIST "
662 "\"%s\" because it is a local name.", host,
664 Put_message(temp_buf);
672 else if (!strchr(args[LM_MEMBER], '!'))
674 Put_message("Member which is not a foreign mail address "
675 "should not be type STRING.");
680 if ((status = do_mr_query("add_member_to_list", CountArgs(args), args,
681 Scream, NULL)) != MR_SUCCESS)
683 if (status == MR_EXISTS)
685 sprintf(temp_buf, "The %s %s is already a member of LIST %s.",
686 args[LM_TYPE], args[LM_MEMBER], args[LM_LIST]);
687 Put_message(temp_buf);
690 com_err(program_name, status, " in AddMember");
697 /* Function Name: DeleteMember
698 * Description: This function deletes a member from a list.
703 int DeleteMember(void)
708 if (GetMemberInfo("delete", args) == SUB_ERROR)
711 if (Confirm("Are you sure you want to delete this member?"))
713 if ((status = do_mr_query("delete_member_from_list", CountArgs(args),
714 args, Scream, NULL)))
715 com_err(program_name, status, " in DeleteMember");
717 Put_message("Deletion Completed.");
720 Put_message("Deletion has been Aborted.");
726 /* Function Name: InterRemoveItemFromLists
727 * Description: This function allows interactive removal of an item
728 * (user, string, list) for all list that it is on.
730 * Returns: DM_NORMAL.
731 * NOTES: QueryLoop() does not work here because info does not have
732 * enough information in it to delete the member from the list.
735 int InterRemoveItemFromLists(void)
738 char *type, *name, *args[10], buf[BUFSIZ];
739 struct qelem *top, *elem;
741 type = strsave("USER");
742 if (GetTypeFromUser("Type of member", "member", &type) == SUB_ERROR)
745 sprintf(buf, "Name of %s", type);
746 name = strsave(user);
747 if (GetValueFromUser(buf, &name) == SUB_ERROR)
750 if (!ValidName(name))
753 top = elem = GetListInfo(GLOM, type, name);
758 char **info = (char **) elem->q_data;
759 sprintf(line, "Delete %s %s from the list \"%s\" (y/n/q)? ", type,
760 name, info[GLOM_NAME]);
761 switch (YesNoQuitQuestion(line, FALSE))
764 Put_message("deleting...");
765 args[DM_LIST] = info[GLOM_NAME];
766 args[DM_TYPE] = type;
767 args[DM_MEMBER] = name;
768 if ((status = do_mr_query("delete_member_from_list", 3, args,
769 Scream, (char *) NULL)))
771 /* should probabally check to delete list. */
772 com_err(program_name, status, " in delete_member");
778 Put_message("Aborting...");
788 /*-*-* LIST MENU *-*-*/
790 /* Function Name: ListByMember
791 * Description: This gets all lists that a given member is a member of.
793 * Returns: DM_NORMAL.
796 int ListByMember(void)
798 char buf[BUFSIZ], temp_buf[BUFSIZ], *type, *name, **info;
799 Bool maillist, group;
800 struct qelem *top, *elem;
802 type = strsave("USER");
803 if (GetTypeFromUser("Type of member", "member", &type) == SUB_ERROR)
806 sprintf(buf, "Name of %s", type);
807 name = strsave(user);
808 if (GetValueFromUser(buf, &name) == SUB_ERROR)
811 /* What we really want is a recursive search */
812 sprintf(temp_buf, "R%s", type);
814 type = Strsave(temp_buf);
816 if ((maillist = YesNoQuestion("Show Lists that are Maillists (y/n) ?",
819 if ((group = YesNoQuestion("Show Lists that are Groups (y/n) ?",
823 elem = top = GetListInfo(GLOM, type, name);
827 info = (char **) elem->q_data;
828 if ((maillist == TRUE && !strcmp(info[GLOM_MAILLIST], "1")) ||
829 (group == TRUE && !strcmp(info[GLOM_GROUP], "1")))
830 Put_message(info[GLOM_NAME]);
837 /* Function Name: ListByAdministrator
838 * Description: This function prints all lists which a given user or
841 * Returns: DM_NORMAL.
844 int ListByAdministrator(void)
846 char buf[BUFSIZ], temp_buf[BUFSIZ], *type, *name;
849 type = strsave("USER");
850 if (GetTypeFromUser("Type of member", "member", &type) == SUB_ERROR)
853 sprintf(buf, "Name of %s", type);
854 name = strsave(user);
855 if (GetValueFromUser(buf, &name) == SUB_ERROR)
858 switch (YesNoQuestion("Do you want a recursive search (y/n)", FALSE))
861 sprintf(temp_buf, "R%s", type); /* "USER" to "RUSER" etc. */
863 type = Strsave(temp_buf);
871 top = GetListInfo(ACE_USE, type, name);
872 Loop(top, PrintListAce);
878 /* Function Name: ListAllPublicMailLists
879 * Description: This function lists all public mailing lists.
881 * Returns: DM_NORMAL.
884 int ListAllPublicMailLists(void)
887 static char *args[] = {
890 "FALSE", /* hidden */
891 "TRUE", /* maillist */
892 "DONTCARE", /* group. */
895 if (YesNoQuestion("This query will take a while. Do you wish to continue?",
898 if (status = do_mr_query("qualified_get_lists", 5, args,
899 Print, NULL) != MR_SUCCESS)
900 com_err(program_name, status, " in ListAllGroups");