1 #if (!defined(lint) && !defined(SABER))
2 static char rcsid_module_c[] = "$Header$";
5 /* This is the file lists.c for the SMS Client, which allows a nieve
6 * user to quickly and easily maintain most parts of the SMS 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
27 #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.
65 sprintf(buf, "Item Administered: %-20s Name: %s", info[ACE_TYPE],
70 /* Function Name: PrintListInfo
71 * Description: This function Prints out the List info in a coherent form.
72 * Arguments: info - the List info.
83 (void) sprintf(buf, "%20sList: %s", "", info[L_NAME]);
84 (void) Put_message(buf);
85 (void) sprintf(buf, "Description: %s", info[L_DESC]);
86 (void) Put_message(buf);
87 if ( atoi(info[L_MAILLIST]))
88 Put_message("This list is a mailing list.");
90 Put_message("This list is NOT a mailing list.");
91 if ( atoi(info[L_GROUP]) ) {
92 (void) sprintf(buf,"This list is Group and its ID number is %s",
97 Put_message("This list is NOT a Group.");
99 if (strcmp(info[L_ACE_TYPE],"NONE") == 0)
100 Put_message("This list has no Administrator, how strange?!");
102 sprintf(buf, "The Administrator of this list is the %s: %s",
103 info[L_ACE_TYPE], info[L_ACE_NAME]);
107 (void) sprintf(buf, "This list is: %s, %s, and %s",
108 atoi(info[L_ACTIVE]) ? "active" : "inactive",
109 atoi(info[L_PUBLIC]) ? "public" : "private",
110 atoi(info[L_HIDDEN]) ? "hidden" : "visible");
111 (void) Put_message(buf);
112 sprintf(buf, MOD_FORMAT, info[L_MODBY], info[L_MODTIME], info[L_MODWITH]);
113 (void) Put_message(buf);
116 /* Function Name: GetListInfo
117 * Description: Stores all info about a group of lists in a queue.
118 * Arguments: type - type of info to store.
119 * name - name of the info.
120 * Returns: the first element in the queue.
125 GetListInfo(type, name1, name2)
127 char * name1, *name2;
130 struct qelem * elem = NULL;
136 if ( (status = sms_query("get_list_info", 1, args,
137 StoreInfo, (char *) &elem)) != 0) {
138 com_err(program_name, status, " in get_list_info");
144 if ( (status = sms_query("get_members_of_list", 1, args,
145 StoreInfo, (char *) &elem)) != 0) {
146 com_err(program_name, status, " in get_members_of_list");
153 if ( (status = sms_query("get_lists_of_member", 2, args,
154 StoreInfo, (char *) &elem)) != 0) {
155 com_err(program_name, status, " in get_list_of_members");
162 if ( (status = sms_query("get_ace_use", 2, args,
163 StoreInfo, (char *) &elem)) != 0) {
164 com_err(program_name, status, " in get_ace_use");
169 return( QueueTop(elem) );
172 /* Function Name: AskListInfo.
173 * Description: This function askes the user for information about a
174 * machine and saves it into a structure.
175 * Arguments: info - a pointer the the structure to put the
177 * name - add a newname field? (T/F)
178 * Returns: SUB_ERROR or SUB_NORMAL.
182 AskListInfo(info, name)
186 char temp_buf[BUFSIZ], *newname;
189 sprintf(temp_buf,"Setting information of list %s.",info[L_NAME]);
190 Put_message(temp_buf);
194 newname = Strsave(info[L_NAME]);
195 GetValueFromUser("The new name for this list", &newname);
197 GetYesNoValueFromUser("Is this an active list", &info[L_ACTIVE]);
198 GetYesNoValueFromUser("Is this a public list", &info[L_PUBLIC]);
199 GetYesNoValueFromUser("Is this a hidden list", &info[L_HIDDEN]);
200 GetYesNoValueFromUser("Is this a maillist", &info[L_MAILLIST]);
201 GetYesNoValueFromUser("is this a group", &info[L_GROUP]);
202 if (atoi(info[L_GROUP]))
203 GetValueFromUser("What is the GID for this group.", &info[L_GID]);
205 GetValueFromUser("What Type of Administrator (none, user, list): ",
207 if ( (strcmp(info[L_ACE_TYPE], "USER") == 0) ||
208 (strcmp(info[L_ACE_TYPE], "user") == 0) )
209 GetValueFromUser("Who will be the administrator of this list: ",
211 if ( (strcmp(info[L_ACE_TYPE], "LIST") == 0) ||
212 (strcmp(info[L_ACE_TYPE], "list") == 0) )
213 GetValueFromUser("Which group will be the administrator of this list: ",
215 GetValueFromUser("Description: ", &info[L_DESC]);
217 FreeAndClear(&info[L_MODTIME], TRUE);
218 FreeAndClear(&info[L_MODBY], TRUE);
219 FreeAndClear(&info[L_MODWITH], TRUE);
221 * Slide the newname into the #2 slot, this screws up all future references
224 if (name) /* slide the newname into the #2 slot. */
225 SlipInNewName(info, newname);
230 /* -------------- List functions. -------------- */
232 /* Function Name: ShowListInfo.
233 * Description: shows info on a list.
234 * Arguments: argc, argv - name of list in argv[1].
235 * Returns: DM status code.
240 ShowListInfo(argc, argv)
244 struct qelem *top, *list;
246 top = list = GetListInfo(LIST, argv[1], (char *) NULL);
247 while (list != NULL) {
248 PrintListInfo( (char **) list->q_data);
256 /* Function Name: RealUpdateList
257 * Description: performs the actual update of the list.
258 * Arguments: info - all information needed to update the list.
259 * junk - an UNUSED boolean.
265 RealUpdateList(info, junk)
272 args = AskListInfo(info, TRUE);
273 if ( (stat = sms_query("update_list", CountArgs(args), args,
274 Scream, (char *) NULL)) != SMS_SUCCESS) {
275 com_err(program_name, stat, " in UpdateList.");
276 Put_message("List ** NOT ** Updated.");
279 Put_message("List successfully updated.");
282 /* Function Name: UpdateList
283 * Description: updates the information on a list.
284 * Arguments: argc, argv - name of list in argv[1].
285 * Returns: DM Status code.
290 UpdateList(argc, argv)
296 top = GetListInfo(LIST, argv[1], (char *) NULL);
297 QueryLoop(top, NullPrint, RealUpdateList, "Update the list");
303 /* Function Name: SetDefaults
304 * Description: sets defaults for AddList function
305 * Arguments: info - the array to add them to.
306 * name - name of the program to add.
307 * Returns: defaults - the default information.
311 SetDefaults(info, name)
315 info[L_NAME] = Strsave(name);
316 info[L_ACTIVE] = Strsave(DEFAULT_ACTIVE);
317 info[L_PUBLIC] = Strsave(DEFAULT_PUBLIC);
318 info[L_HIDDEN] = Strsave(DEFAULT_HIDDEN);
319 info[L_MAILLIST] = Strsave(DEFAULT_MAILLIST);
320 info[L_GROUP] = Strsave(DEFAULT_GROUP);
321 info[L_GID] = Strsave(DEFAULT_GID);
322 info[L_ACE_TYPE] = Strsave(DEFAULT_ACE_TYPE);
323 info[L_ACE_NAME] = Strsave(DEFAULT_ACE_NAME);
324 info[L_DESC] = Strsave(DEFAULT_DESCRIPTION);
325 info[L_MODTIME] = info[L_MODBY] = info[L_MODWITH] = info[L_END] = NULL;
329 /* Function Name: AddList
331 * Arguments: argc, argv - name of list in argv[1].
332 * Returns: SUB_ERROR if list not created.
341 static char *info[MAX_ARGS_SIZE], **add_args;
342 int status, ret_code = SUB_NORMAL;
344 status = sms_query("get_list_info", 1, argv + 1, NullFunc,
346 if (status != SMS_NO_MATCH) {
347 if (status == SMS_SUCCESS)
348 Put_message("This list already exists.");
350 com_err(program_name, status, " in AddList.");
354 add_args = AskListInfo(SetDefaults(info,argv[1]), FALSE);
356 if ( (status = sms_query("add_list", CountArgs(add_args), add_args,
357 Scream, (char *) NULL)) != SMS_SUCCESS) {
358 com_err(program_name, status, " in AddList.");
359 Put_message("List Not Created.");
360 ret_code = SUB_ERROR;
367 /* Function Name: Instructions
368 * Description: This func prints out instruction on manipulating lists.
370 * Returns: DM Status Code.
376 static char * message[] = {
377 "Listmaint handles the creation, deletion, and updating of lists.",
378 "A list can be a mailing list, a group list, or both.",
379 "The concept behind lists is that a list has an owner",
380 "- administrator - and members.",
381 "The administrator of a list may be another list.",
382 "The members of a list can be users (login names), other lists,",
383 "or address strings.",
384 "You can use certain keys to do the following:",
385 " Refresh the screen - Type ctrl-L.",
386 " Escape from a function - Type ctrl-C.",
387 " Suspend the program (temporarily) - Type ctrl-Z.",
391 return(PrintHelp(message));
394 /*-*-* LISTMAINT UPDATE MENU *-*-*/
396 /* Function Name: ListmaintMemberMenuEntry
397 * Description: entry routine into the listmaint member menu.
398 * Arguments: m - the member menu.
399 * argc, argv - name of the list in argv[1].
405 ListmaintMemberMenuEntry(m, argc, argv)
410 char temp_buf[BUFSIZ];
411 char *list_name = argv[1];
414 if (!ValidName(list_name))
417 if (*argv[0] == 'a') { /* add_list */
418 if (AddList(argc, argv) == SUB_ERROR)
420 (void) sprintf(temp_buf, "List '%s' created. Do you want to %s",
421 list_name, "change its membership (y/n)? ");
422 if (YesNoQuestion(temp_buf, TRUE) != TRUE )
426 /* All we want to know is if it exists. */
427 switch( (stat = sms_query("count_members_of_list", 1, argv + 1,
428 NullFunc, (char *) NULL))) {
432 Put_message("This list does not exist.");
435 Put_message("You are not allowed to view this list.");
438 com_err(program_name, stat, " in get_list_info");
442 (void) sprintf(temp_buf,
443 "Change/Display membership of '%s'", list_name);
444 m->m_title = Strsave(temp_buf);
445 strcpy(current_list, list_name);
449 /* Function Name: ListmaintMemberMenuExit
450 * Description: This is the function called when the member menu is
451 * exited, it frees the memory that is storing the name.
452 * Arguments: m - the menu
457 ListmaintMemberMenuExit(m)
461 strcpy(current_list, "");
465 /* Function Name: ListMembersByType
466 * Description: This function lists the users of a list by type.
467 * Arguments: type - the type of the list "USER", "LIST", or "STRING".
469 * NOTE: if type is NULL, all lists members are listed.
473 ListMembersByType(type)
476 char temp_buf[BUFSIZ];
480 args[0] = current_list;
484 if ( (status = sms_query("get_members_of_list", CountArgs(args), args,
485 PrintByType, type)) != 0)
486 com_err(program_name, status, " in ListMembersByType");
489 Put_message("List is empty (no members).");
491 sprintf(temp_buf,"No %s Members",type);
492 Put_message(temp_buf);
497 /* Function Name: ListAllMembers
498 * Description: lists all members of the current list.
506 ListMembersByType(NULL);
510 /* Function Name: ListUserMembers
511 * Description: This function lists all members of a list of type "USER".
513 * Returns: DM_NORMAL.
518 ListMembersByType("USER");
522 /* Function Name: ListListMembers
523 * Description: This function lists all members of a list of type "LIST".
525 * Returns: DM_NORMAL.
530 ListMembersByType("LIST");
534 /* Function Name: ListStringMembers
535 * Description:This function lists all members of a list of type "STRING".
537 * Returns: DM_NORMAL.
542 ListMembersByType("STRING");
546 /* Function Name: GetMemberInfo
547 * Description: This function gets the information needed to
548 * add or delete a user from a list.
549 * Arguments: argc, argv - standard.
550 * action - name of the action to be performed either
552 * ret_argc, ret_argv - the returned value of argc and argv.
553 * Returns: SUB_ERROR or SUB_NORMAL.
557 GetMemberInfo(action, ret_argv)
558 char *action, **ret_argv;
560 char temp_buf[BUFSIZ], ret_buf[BUFSIZ];
562 ret_argv[LM_LIST] = Strsave(current_list);
564 PromptWithDefault("Type of member (user, list, or string)",
565 ret_buf, BUFSIZ, "user");
566 ret_argv[LM_TYPE]= Strsave(ret_buf);
569 * A type check needs to be added here, to see if we match the
570 * allowable types, currently (user, list, and string).
573 sprintf(temp_buf,"Name of %s to %s", ret_argv[LM_TYPE], action);
574 PromptWithDefault(temp_buf, ret_buf, BUFSIZ, user);
575 ret_argv[LM_MEMBER] = Strsave(ret_buf);
576 ret_argv[LM_END] = NULL; /* NULL terminate this list. */
578 if (!ValidName( ret_argv[LM_MEMBER] ) ) {
585 /* Function Name: AddMember
586 * Description: This function adds a member to a list.
588 * Returns: DM_NORMAL.
594 char *args[10], temp_buf[BUFSIZ];
597 if ( GetMemberInfo("add", args) == SUB_ERROR )
600 if ( (status = sms_query("add_member_to_list", CountArgs(args), args,
601 Scream, NULL)) != SMS_SUCCESS) {
602 if (status == SMS_EXISTS) {
603 sprintf(temp_buf, "The %s %s is already a member of LIST %s.",
604 args[LM_TYPE], args[LM_MEMBER], args[LM_LIST]);
605 Put_message(temp_buf);
608 com_err(program_name, status, " in AddMember");
615 /* Function Name: DeleteMember
616 * Description: This function deletes a member from a list.
627 if( GetMemberInfo("delete", args) == SUB_ERROR )
630 if (Confirm("Are you sure you want to delete this member?") ) {
631 if (status = sms_query("delete_member_from_list", CountArgs(args),
633 com_err(program_name, status, " in DeleteMember");
635 Put_message("Deletion Completed.");
638 Put_message("Deletion has been Aborted.");
644 /* Function Name: InterRemoveItemFromLists
645 * Description: This function allows interactive removal of an item
646 * (user, string, list) for all list that it is on.
648 * Returns: DM_NORMAL.
649 * NOTES: QueryLoop() does not work here because info does not have
650 * enough information in it to delete the member from the list.
654 InterRemoveItemFromLists()
657 char type[BUFSIZ], name[BUFSIZ], *args[10], buf[BUFSIZ];
658 struct qelem *top, *elem;
660 if ( !(PromptWithDefault("Type of member (user, list, string)", type,
664 sprintf(buf, "Name of %s", type);
665 if ( !(PromptWithDefault(buf, name, BUFSIZ, user)) ) {
669 if (!ValidName(name))
672 top = elem = GetListInfo(GLOM, type, name);
674 while(elem != NULL) {
676 char ** info = (char **) elem->q_data;
677 sprintf(line, "Delete %s %s from the list \"%s\" (y/n/q)? ", type,
678 name, info[GLOM_NAME]);
679 switch (YesNoQuitQuestion(line, FALSE)) {
681 Put_message("deleting...");
682 args[DM_LIST] = info[GLOM_NAME];
683 args[DM_TYPE] = type;
684 args[DM_MEMBER] = name;
685 if ( (status = sms_query("delete_member_from_list", 3, args,
686 Scream, (char *) NULL)) != 0)
687 /* should probabally check to delete list. */
688 com_err(program_name, status, " in delete_member");
693 Put_message("Aborting...");
703 /*-*-* LIST MENU *-*-*/
705 /* Function Name: ListByMember
706 * Description: This gets all lists that a given member is a member of.
708 * Returns: DM_NORMAL.
714 char buf[BUFSIZ], temp_buf[BUFSIZ], *type, *name, **info;
715 Bool maillist, group;
716 struct qelem *top, *elem;
718 if ( !(PromptWithDefault("Type of member (user, list, string)", buf,
722 /* What we really want is a recursive search */
723 sprintf(temp_buf, "R%s", buf);
724 type = Strsave(temp_buf);
726 sprintf(temp_buf, "Name of %s", buf);
727 if ( !(PromptWithDefault(temp_buf, buf, BUFSIZ, user)) ) {
733 maillist = YesNoQuestion("Show only Lists that are Maillists (y/n) ?",
735 group = YesNoQuestion("Show only Lists that are Groups (y/n) ?", TRUE);
737 elem = top = GetListInfo(GLOM, type, name);
739 while (elem != NULL) {
740 info = (char**) elem->q_data;
741 if (maillist != TRUE || !strcmp(info[GLOM_MAILLIST], "1"))
742 if (group != TRUE || !strcmp(info[GLOM_GROUP], "1"))
743 Put_message(info[GLOM_NAME]);
750 /* Function Name: ListByAdministrator
751 * Description: This function prints all lists which a given user or
754 * Returns: DM_NORMAL.
758 ListByAdministrator()
760 char buf[BUFSIZ], temp_buf[BUFSIZ], *type, *name;
763 if ( !(PromptWithDefault("Type of member (user, list, string)", buf,
767 if ( YesNoQuestion("Do you want a recursive search (y/n)", TRUE) == 1 ) {
768 sprintf(temp_buf, "R%s", buf); /* "USER" to "RUSER" etc. */
769 type = Strsave(temp_buf);
774 sprintf(temp_buf, "Name of %s", buf);
775 if ( !(PromptWithDefault(temp_buf, buf, BUFSIZ, user)) ) {
781 top = GetListInfo(ACE_USE, type, name);
782 Loop(top, PrintListAce);
788 /* Function Name: ListAllGroups
789 * Description: This function lists all visable groups.
791 * Returns: DM_NORMAL.
797 static char * args[] = {
799 "DONTCARE", /* public */
800 "FALSE", /* hidden */
801 "DONTCARE", /* maillist */
805 if (YesNoQuestion("This query will take a while, Do you wish to continue?",
807 if (status = sms_query("qualified_get_lists", 5, args,
808 Print, (char *) NULL) != 0)
809 com_err(program_name, status, " in ListAllGroups");
813 /* Function Name: ListAllMailLists
814 * Description: This function lists all visable maillists.
816 * Returns: DM_NORMAL.
822 static char * args[] = {
824 "DONTCARE", /* public */
825 "FALSE", /* hidden */
826 "TRUE", /* maillist */
827 "DONTCARE", /* group. */
830 if (YesNoQuestion("This query will take a while. Do you wish to continue?",
832 if (status = sms_query("qualified_get_lists", 5, args,
833 Print, (char *) NULL) != 0)
834 com_err(program_name, status, " in ListAllGroups");
839 /* Function Name: ListAllPublicMailLists
840 * Description: This function lists all public mailing lists.
842 * Returns: DM_NORMAL.
845 ListAllPublicMailLists()
848 static char * args[] = {
851 "FALSE", /* hidden */
852 "TRUE", /* maillist */
853 "DONTCARE", /* group. */
856 if (YesNoQuestion("This query will take a while. Do you wish to continue?",
858 if (status = sms_query("qualified_get_lists", 5, args,
859 Print, (char *) NULL) != 0)
860 com_err(program_name, status, " in ListAllGroups");
869 * c-continued-statement-offset: 4
871 * c-argdecl-indent: 4