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.
64 sprintf(buf, "Item: %-20s Name: %s", info[ACE_TYPE],
69 /* Function Name: PrintListInfo
70 * Description: This function Prints out the List info in a coherent form.
71 * Arguments: info - the List info.
82 (void) sprintf(buf, "%20sList: %s", "", info[L_NAME]);
83 (void) Put_message(buf);
84 (void) sprintf(buf, "Description: %s", info[L_DESC]);
85 (void) Put_message(buf);
86 if ( atoi(info[L_MAILLIST]))
87 Put_message("This list is a mailing list.");
89 Put_message("This list is NOT a mailing list.");
90 if ( atoi(info[L_GROUP]) ) {
91 (void) sprintf(buf,"This list is a Group and its ID number is %s",
96 Put_message("This list is NOT a Group.");
98 if (strcmp(info[L_ACE_TYPE],"NONE") == 0)
99 Put_message("This list has no Administrator, how strange?!");
101 sprintf(buf, "The Administrator of this list is the %s: %s",
102 info[L_ACE_TYPE], info[L_ACE_NAME]);
106 (void) sprintf(buf, "This list is: %s, %s, and %s",
107 atoi(info[L_ACTIVE]) ? "active" : "inactive",
108 atoi(info[L_PUBLIC]) ? "public" : "private",
109 atoi(info[L_HIDDEN]) ? "hidden" : "visible");
110 (void) Put_message(buf);
111 sprintf(buf, MOD_FORMAT, info[L_MODBY], info[L_MODTIME], info[L_MODWITH]);
112 (void) Put_message(buf);
115 /* Function Name: GetListInfo
116 * Description: Stores all info about a group of lists in a queue.
117 * Arguments: type - type of info to store.
118 * name - name of the info.
119 * Returns: the first element in the queue.
124 GetListInfo(type, name1, name2)
126 char * name1, *name2;
129 struct qelem * elem = NULL;
135 if ( (status = do_mr_query("get_list_info", 1, args,
136 StoreInfo, (char *) &elem)) != 0) {
137 com_err(program_name, status, " in get_list_info");
143 if ( (status = do_mr_query("get_members_of_list", 1, args,
144 StoreInfo, (char *) &elem)) != 0) {
145 com_err(program_name, status, " in get_members_of_list");
152 if ( (status = do_mr_query("get_lists_of_member", 2, args,
153 StoreInfo, (char *) &elem)) != 0) {
154 com_err(program_name, status, " in get_list_of_members");
161 if ( (status = do_mr_query("get_ace_use", 2, args,
162 StoreInfo, (char *) &elem)) != 0) {
163 com_err(program_name, status, " in get_ace_use");
168 return( QueueTop(elem) );
171 /* Function Name: AskListInfo.
172 * Description: This function askes the user for information about a
173 * machine and saves it into a structure.
174 * Arguments: info - a pointer the the structure to put the
176 * name - add a newname field? (T/F)
177 * Returns: SUB_ERROR or SUB_NORMAL.
181 AskListInfo(info, name)
185 char temp_buf[BUFSIZ], *newname;
188 sprintf(temp_buf,"Setting information of list %s.",info[L_NAME]);
189 Put_message(temp_buf);
194 newname = Strsave(info[L_NAME]);
195 if (GetValueFromUser("The new name for this list", &newname) ==
198 if (ValidName(newname))
202 if (GetYesNoValueFromUser("Is this an active list", &info[L_ACTIVE]) ==
205 if (GetYesNoValueFromUser("Is this a public list", &info[L_PUBLIC]) ==
208 if (GetYesNoValueFromUser("Is this a hidden list", &info[L_HIDDEN]) ==
211 if (GetYesNoValueFromUser("Is this a maillist", &info[L_MAILLIST]) ==
214 if (GetYesNoValueFromUser("Is this a group", &info[L_GROUP]) == SUB_ERROR)
216 if (atoi(info[L_GROUP]))
217 if (GetValueFromUser("What is the GID for this group.", &info[L_GID]) ==
221 if (GetTypeFromUser("What Type of Administrator", "ace_type",
222 &info[L_ACE_TYPE]) == SUB_ERROR)
224 if ((strcasecmp(info[L_ACE_TYPE], "NONE") != 0) &&
225 (strcasecmp(info[L_ACE_TYPE], "none") != 0)) {
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.
257 ShowListInfo(argc, argv)
261 struct qelem *top, *list;
263 top = list = GetListInfo(LIST, argv[1], (char *) NULL);
264 while (list != NULL) {
265 PrintListInfo( (char **) list->q_data);
273 /* Function Name: RealUpdateList
274 * Description: performs the actual update of the list.
275 * Arguments: info - all information needed to update the list.
276 * junk - an UNUSED boolean.
282 RealUpdateList(info, junk)
289 if ((args = AskListInfo(info, TRUE)) == NULL) {
290 Put_message("Aborted.");
293 if ( (stat = do_mr_query("update_list", CountArgs(args), args,
294 Scream, (char *) NULL)) != MR_SUCCESS) {
295 com_err(program_name, stat, " in UpdateList.");
296 Put_message("List ** NOT ** Updated.");
299 Put_message("List successfully updated.");
302 /* Function Name: UpdateList
303 * Description: updates the information on a list.
304 * Arguments: argc, argv - name of list in argv[1].
305 * Returns: DM Status code.
310 UpdateList(argc, argv)
316 top = GetListInfo(LIST, argv[1], (char *) NULL);
317 QueryLoop(top, NullPrint, RealUpdateList, "Update the list");
323 /* Function Name: SetDefaults
324 * Description: sets defaults for AddList function
325 * Arguments: info - the array to add them to.
326 * name - name of the program to add.
327 * Returns: defaults - the default information.
331 SetDefaults(info, name)
335 info[L_NAME] = Strsave(name);
336 info[L_ACTIVE] = Strsave(DEFAULT_ACTIVE);
337 info[L_PUBLIC] = Strsave(DEFAULT_PUBLIC);
338 info[L_HIDDEN] = Strsave(DEFAULT_HIDDEN);
339 info[L_MAILLIST] = Strsave(DEFAULT_MAILLIST);
340 info[L_GROUP] = Strsave(DEFAULT_GROUP);
341 info[L_GID] = Strsave(DEFAULT_GID);
342 info[L_ACE_TYPE] = Strsave(DEFAULT_ACE_TYPE);
343 info[L_ACE_NAME] = Strsave(DEFAULT_ACE_NAME);
344 info[L_DESC] = Strsave(DEFAULT_DESCRIPTION);
345 info[L_MODTIME] = info[L_MODBY] = info[L_MODWITH] = info[L_END] = NULL;
349 /* Function Name: AddList
351 * Arguments: argc, argv - name of list in argv[1].
352 * Returns: SUB_ERROR if list not created.
361 static char *info[MAX_ARGS_SIZE], **add_args;
362 int status, ret_code = SUB_NORMAL;
363 struct qelem *elem = NULL;
365 if (!ValidName(argv[1]))
367 status = do_mr_query("get_list_info", 1, argv + 1, NullFunc,
369 if (status != MR_NO_MATCH) {
370 if (status == MR_SUCCESS)
371 Put_message("This list already exists.");
373 com_err(program_name, status, " in AddList.");
378 * If the listname is less than 8 characters, make sure it doesn't
379 * collide with a username.
381 if ((strlen(argv[1]) <= 8) &&
382 do_mr_query("get_user_account_by_login", 1, argv + 1,
383 StoreInfo, (char *) &elem) == 0) {
384 Put_message("A user by that name already exists in the database.");
385 Loop(QueueTop(elem), FreeInfo);
387 if (YesNoQuestion("Crate a list with the same name",
392 if ((add_args = AskListInfo(SetDefaults(info,argv[1]), FALSE)) == NULL) {
393 Put_message("Aborted.");
397 if ( (status = do_mr_query("add_list", CountArgs(add_args), add_args,
398 Scream, (char *) NULL)) != MR_SUCCESS) {
399 com_err(program_name, status, " in AddList.");
400 Put_message("List Not Created.");
401 ret_code = SUB_ERROR;
408 /* Function Name: Instructions
409 * Description: This func prints out instruction on manipulating lists.
411 * Returns: DM Status Code.
417 static char * message[] = {
418 "Listmaint handles the creation, deletion, and updating of lists.",
419 "A list can be a mailing list, a group list, or both.",
420 "The concept behind lists is that a list has an owner",
421 "- administrator - and members.",
422 "The administrator of a list may be another list.",
423 "The members of a list can be users (login names), other lists,",
424 "or address strings.",
425 "You can use certain keys to do the following:",
426 " Refresh the screen - Type ctrl-L.",
427 " Escape from a function - Type ctrl-C.",
428 " Suspend the program (temporarily) - Type ctrl-Z.",
432 return(PrintHelp(message));
435 /*-*-* LISTMAINT UPDATE MENU *-*-*/
437 /* Function Name: ListmaintMemberMenuEntry
438 * Description: entry routine into the listmaint member menu.
439 * Arguments: m - the member menu.
440 * argc, argv - name of the list in argv[1].
446 ListmaintMemberMenuEntry(m, argc, argv)
451 char temp_buf[BUFSIZ];
452 char *list_name = argv[1];
455 if (!ValidName(list_name))
458 if (*argv[0] == 'a') { /* add_list */
459 if (AddList(argc, argv) == SUB_ERROR)
461 (void) sprintf(temp_buf, "List '%s' created. Do you want to %s",
462 list_name, "change its membership (y/n)? ");
463 if (YesNoQuestion(temp_buf, TRUE) != TRUE )
467 /* All we want to know is if it exists. */
468 switch( (stat = do_mr_query("count_members_of_list", 1, argv + 1,
469 NullFunc, (char *) NULL))) {
473 Put_message("This list does not exist.");
476 Put_message("You are not allowed to view this list.");
479 com_err(program_name, stat, " in get_list_info");
483 (void) sprintf(temp_buf,
484 "Change/Display membership of '%s'", list_name);
485 m->m_title = Strsave(temp_buf);
486 strcpy(current_list, list_name);
490 /* Function Name: ListmaintMemberMenuExit
491 * Description: This is the function called when the member menu is
492 * exited, it frees the memory that is storing the name.
493 * Arguments: m - the menu
498 ListmaintMemberMenuExit(m)
502 strcpy(current_list, "");
506 /* Function Name: ListMembersByType
507 * Description: This function lists the users of a list by type.
508 * Arguments: type - the type of the list "USER", "LIST", or "STRING".
510 * NOTE: if type is NULL, all lists members are listed.
514 ListMembersByType(type)
517 char temp_buf[BUFSIZ];
521 args[0] = current_list;
525 if ( (status = do_mr_query("get_members_of_list", CountArgs(args), args,
526 PrintByType, type)) != 0) {
527 com_err(program_name, status, " in ListMembersByType");
532 Put_message("List is empty (no members).");
534 sprintf(temp_buf,"No %s Members",type);
535 Put_message(temp_buf);
540 /* Function Name: ListAllMembers
541 * Description: lists all members of the current list.
549 ListMembersByType(NULL);
553 /* Function Name: ListUserMembers
554 * Description: This function lists all members of a list of type "USER".
556 * Returns: DM_NORMAL.
561 ListMembersByType("USER");
565 /* Function Name: ListListMembers
566 * Description: This function lists all members of a list of type "LIST".
568 * Returns: DM_NORMAL.
573 ListMembersByType("LIST");
577 /* Function Name: ListStringMembers
578 * Description:This function lists all members of a list of type "STRING".
580 * Returns: DM_NORMAL.
585 ListMembersByType("STRING");
589 /* Function Name: GetMemberInfo
590 * Description: This function gets the information needed to
591 * add or delete a user from a list.
592 * Arguments: argc, argv - standard.
593 * action - name of the action to be performed either
595 * ret_argc, ret_argv - the returned value of argc and argv.
596 * Returns: SUB_ERROR or SUB_NORMAL.
600 GetMemberInfo(action, ret_argv)
601 char *action, **ret_argv;
603 char temp_buf[BUFSIZ];
605 ret_argv[LM_LIST] = Strsave(current_list);
607 ret_argv[LM_TYPE] = Strsave("user");
608 if (GetTypeFromUser("Type of member", "member", &ret_argv[LM_TYPE]) ==
612 sprintf(temp_buf,"Name of %s to %s", ret_argv[LM_TYPE], action);
613 ret_argv[LM_MEMBER] = Strsave(user);
614 if (GetValueFromUser(temp_buf, &ret_argv[LM_MEMBER]) == SUB_ERROR)
616 ret_argv[LM_END] = NULL; /* NULL terminate this list. */
618 if (strcasecmp(ret_argv[LM_TYPE], "string") &&
619 !ValidName( ret_argv[LM_MEMBER] ) ) {
626 /* Function Name: AddMember
627 * Description: This function adds a member to a list.
629 * Returns: DM_NORMAL.
635 char *args[10], temp_buf[BUFSIZ], *p;
637 struct qelem *mailhubs, *elem, *GetTypeValues();
639 if ( GetMemberInfo("add", args) == SUB_ERROR )
642 if (!strcmp(args[LM_TYPE], "STRING")) {
643 if (p = strchr(args[LM_MEMBER], '@')) {
644 char *host = canonicalize_hostname(strsave(++p));
645 mailhubs = GetTypeValues("mailhub");
646 for (elem = mailhubs; elem; elem = elem->q_forw) {
647 if (!strcasecmp(host, elem->q_data)) {
649 host = strsave(args[LM_MEMBER]);
651 sprintf(temp_buf, "String \"%s\" should be USER or LIST \"%s\" because it is a local name.",
652 host, args[LM_MEMBER]);
653 Put_message(temp_buf);
660 } else if (!strchr(args[LM_MEMBER], '!')) {
661 Put_message("Member which is not a foreign mail address should not be type STRING.");
666 if ( (status = do_mr_query("add_member_to_list", CountArgs(args), args,
667 Scream, NULL)) != MR_SUCCESS) {
668 if (status == MR_EXISTS) {
669 sprintf(temp_buf, "The %s %s is already a member of LIST %s.",
670 args[LM_TYPE], args[LM_MEMBER], args[LM_LIST]);
671 Put_message(temp_buf);
674 com_err(program_name, status, " in AddMember");
681 /* Function Name: DeleteMember
682 * Description: This function deletes a member from a list.
693 if( GetMemberInfo("delete", args) == SUB_ERROR )
696 if (Confirm("Are you sure you want to delete this member?") ) {
697 if (status = do_mr_query("delete_member_from_list", CountArgs(args),
699 com_err(program_name, status, " in DeleteMember");
701 Put_message("Deletion Completed.");
704 Put_message("Deletion has been Aborted.");
710 /* Function Name: InterRemoveItemFromLists
711 * Description: This function allows interactive removal of an item
712 * (user, string, list) for all list that it is on.
714 * Returns: DM_NORMAL.
715 * NOTES: QueryLoop() does not work here because info does not have
716 * enough information in it to delete the member from the list.
720 InterRemoveItemFromLists()
723 char *type, *name, *args[10], buf[BUFSIZ];
724 struct qelem *top, *elem;
726 type = strsave("USER");
727 if (GetTypeFromUser("Type of member", "member", &type) == SUB_ERROR)
730 sprintf(buf, "Name of %s", type);
731 name = strsave(user);
732 if (GetValueFromUser(buf, &name) == SUB_ERROR)
735 if (!ValidName(name))
738 top = elem = GetListInfo(GLOM, type, name);
740 while(elem != NULL) {
742 char ** info = (char **) elem->q_data;
743 sprintf(line, "Delete %s %s from the list \"%s\" (y/n/q)? ", type,
744 name, info[GLOM_NAME]);
745 switch (YesNoQuitQuestion(line, FALSE)) {
747 Put_message("deleting...");
748 args[DM_LIST] = info[GLOM_NAME];
749 args[DM_TYPE] = type;
750 args[DM_MEMBER] = name;
751 if ( (status = do_mr_query("delete_member_from_list", 3, args,
752 Scream, (char *) NULL)) != 0)
753 /* should probabally check to delete list. */
754 com_err(program_name, status, " in delete_member");
759 Put_message("Aborting...");
769 /*-*-* LIST MENU *-*-*/
771 /* Function Name: ListByMember
772 * Description: This gets all lists that a given member is a member of.
774 * Returns: DM_NORMAL.
780 char buf[BUFSIZ], temp_buf[BUFSIZ], *type, *name, **info;
781 Bool maillist, group;
782 struct qelem *top, *elem;
784 type = strsave("USER");
785 if (GetTypeFromUser("Type of member", "member", &type) == SUB_ERROR)
788 sprintf(buf, "Name of %s", type);
789 name = strsave(user);
790 if (GetValueFromUser(buf, &name) == SUB_ERROR)
793 /* What we really want is a recursive search */
794 sprintf(temp_buf, "R%s", type);
795 free(type); type = Strsave(temp_buf);
797 if ((maillist = YesNoQuestion("Show Lists that are Maillists (y/n) ?",
800 if ((group = YesNoQuestion("Show Lists that are Groups (y/n) ?",
804 elem = top = GetListInfo(GLOM, type, name);
806 while (elem != NULL) {
807 info = (char**) elem->q_data;
808 if ((maillist == TRUE && !strcmp(info[GLOM_MAILLIST], "1")) ||
809 (group == TRUE && !strcmp(info[GLOM_GROUP], "1")))
810 Put_message(info[GLOM_NAME]);
817 /* Function Name: ListByAdministrator
818 * Description: This function prints all lists which a given user or
821 * Returns: DM_NORMAL.
825 ListByAdministrator()
827 char buf[BUFSIZ], temp_buf[BUFSIZ], *type, *name;
830 type = strsave("USER");
831 if (GetTypeFromUser("Type of member", "member", &type) == SUB_ERROR)
834 sprintf(buf, "Name of %s", type);
835 name = strsave(user);
836 if (GetValueFromUser(buf, &name) == SUB_ERROR)
839 switch (YesNoQuestion("Do you want a recursive search (y/n)", FALSE)) {
841 sprintf(temp_buf, "R%s", type); /* "USER" to "RUSER" etc. */
843 type = Strsave(temp_buf);
851 top = GetListInfo(ACE_USE, type, name);
852 Loop(top, PrintListAce);
858 /* Function Name: ListAllPublicMailLists
859 * Description: This function lists all public mailing lists.
861 * Returns: DM_NORMAL.
864 ListAllPublicMailLists()
867 static char * args[] = {
870 "FALSE", /* hidden */
871 "TRUE", /* maillist */
872 "DONTCARE", /* group. */
875 if (YesNoQuestion("This query will take a while. Do you wish to continue?",
877 if (status = do_mr_query("qualified_get_lists", 5, args,
878 Print, (char *) NULL) != 0)
879 com_err(program_name, status, " in ListAllGroups");