3 * Simple add-me-to/remove-me-from list client
5 * mailmaint.c - pjlevine - 20 August 1987
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>
35 #define INPUT_MASK 0xff
39 #define getchar() _getch()
43 static void DELETE_A_CHAR(void)
51 #define INPUT_MASK 0x7f
52 #define DELETE_A_CHAR() printf("\b \b");
62 #define CTL(ch) ((ch) & 037)
66 #define MAX(A, B) ((A) > (B) ? (A) : (B))
68 char *whoami; /* should not be static, for logging package */
71 typedef struct list_info {
85 static char *ascbuff = {"0123456789"};
86 static List_info *current_li = (List_info *) NULL;
88 typedef struct _menu {
94 MENU *main_menu, *help_menu;
96 int position[2], oldpos[2];
97 int level, found_some, currow, page, num_members;
98 int moreflg, toggle, first_time;
101 void get_main_input(void);
102 void show_list_info(void);
103 void display_buff(char *buf);
104 void start_display_buff(char *buff);
105 void add_member(void);
106 void delete_member(void);
107 void list_by_member(void);
109 static int print_1(int argc, char *argv[], void *callback);
110 static int print_all(int argc, char *argv[], void *callback);
111 void list_all_groups(void);
112 void list_members(void);
113 static int print_2(int argc, char *argv[], void *callback);
114 void start_display(char *buff);
115 void end_display(void);
116 void display_menu(MENU *menu);
117 void pack_main_menu(void);
118 void pack_help_menu(void);
119 void free_menu(MENU* menu);
120 void highlight(MENU *menu);
121 void title(char *buff);
122 void center_text(int row, char *buff);
123 void show_text(int row, int col, char *buff);
124 void erase_line(int row, int col);
126 void clrwin(int erase_row);
127 static int fetch_list_info(char *list, List_info *li);
128 static int get_list_info(int argc, char **argv, void *hint);
129 int Prompt(char *prompt, char *buf, int buflen, int crok);
130 void menu_err_hook(const char *who, long code, const char *fmt, va_list args);
132 /* This crock is because the original code was very broken and this makes
133 * it work. Someday, we should abandon the code or fix it right.
135 #define mvcur(oy, ox, ny, nx) move(ny, nx)
137 /****************************************************/
139 int main(int argc, char *argv[])
141 void (*old_hook)(const char *, long, const char *, va_list);
142 int use_menu = 1, k_errno;
145 if ((whoami = strrchr(argv[0], '/')) == NULL)
149 if (!(current_li = malloc(sizeof(List_info))))
151 sprintf(buf, ": allocating list info");
156 current_li->acl_type = NULL;
157 current_li->acl_name = NULL;
158 current_li->desc = NULL;
159 current_li->modtime = NULL;
160 current_li->modby = NULL;
161 current_li->modwith = NULL;
164 username = mrcl_krb_user();
168 if (mrcl_connect(NULL, "mailmaint", 2, 1))
172 if ((LINES < 24) || (COLS < 60))
174 display_buff("Display window too small.\n\n");
175 sprintf(buf, "Current window parameters are (%d lines, %d columns)\n",
178 display_buff("Please resize your window\n");
179 display_buff("to at least 24 lines and 60 columns.\n");
185 old_hook = set_com_err_hook(menu_err_hook);
186 position[0] = oldpos[0] = 1;
191 display_menu(main_menu);
195 set_com_err_hook(old_hook);
197 free_menu(main_menu);
198 free_menu(help_menu);
200 if (current_li->acl_type)
201 free(current_li->acl_type);
202 if (current_li->acl_name)
203 free(current_li->acl_name);
204 if (current_li->desc)
205 free(current_li->desc);
206 if (current_li->modtime)
207 free(current_li->modtime);
208 if (current_li->modby)
209 free(current_li->modby);
210 if (current_li->modwith)
211 free(current_li->modwith);
219 com_err(whoami, status, buf);
223 /****************************************************/
224 void get_main_input(void)
231 oldpos[level] = position[level];
233 currow = DISPROW + 2;
235 toggle = num_members = moreflg = 0;
236 c = getchar() & INPUT_MASK; /* mask parity bit */
237 if (c == '\r' || c == '\n')
239 if (position[level] == 7)
242 c = ascbuff[position[level]];
247 case 'L' & 037: /* clear screen */
248 display_menu(main_menu);
253 highlight(main_menu);
260 case '1': /* show all lists */
265 case '2': /* get all members of a list */
270 case '3': /* display list which user is a recipient */
275 case '4': /* show description */
280 case '5': /* add to list */
285 case '6': /* delete */
291 case 27: /* escape */
292 c = getchar() & INPUT_MASK;
295 c = getchar() & INPUT_MASK;
296 if (c == 65) /* up arrow */
299 if (!position[level])
304 if (c == 66) /* down arrow */
307 if (position[level] > 7)
314 c = getchar() & INPUT_MASK;
315 if (c == 0x48) /* up arrow */
318 if (!position[level])
323 if (c == 0x50) /* down arrow */
326 if (position[level] > 7)
336 highlight(main_menu);
340 /****************************************************/
341 void show_list_info(void)
345 show_text(DISPROW, STARTCOL, "Show information about a list.\n");
346 buf = calloc(1024, 1);
347 if (Prompt("Enter List Name: ", buf, LISTSIZE, 1) == 1)
350 if (fetch_list_info(buf, current_li) == 0)
352 sprintf(buf, "Description: %s\n", current_li->desc);
353 if (strlen(buf) > 60)
356 show_text(currow, STARTCOL, buf);
358 sprintf(buf, "List Administrator: %s %s",
359 current_li->acl_type, current_li->acl_name);
360 show_text(currow, STARTCOL, buf);
362 sprintf(buf, "Modified on %s by user %s with %s",
363 current_li->modtime, current_li->modby,
364 current_li->modwith);
365 show_text(currow, STARTCOL, buf);
370 show_text(currow, STARTCOL, "mailmaint: No such list found.");
373 show_text(currow, STARTCOL, "Press any Key to continue...");
380 /****************************************************/
381 void display_buff(char *buf)
384 char *printbuf = NULL;
391 printbuf = calloc(maxcol, 1);
393 for (i = 0; i <= len; i++)
395 printbuf[cnt] = buf[i];
399 start_display_buff(printbuf);
402 printbuf = calloc(maxcol, 1);
405 if (len % maxcol != 0)
407 start_display_buff(printbuf);
414 /****************************************************/
415 void start_display_buff(char *buff)
422 if (currow >= LINES - 2)
426 mvcur(0, 0, currow, STARTCOL);
428 if (Prompt("--RETURN for more, ctl-c to exit--", buffer, 1, 0) == 0)
430 erase_line(currow, STARTCOL);
431 show_text(currow, STARTCOL, "Flushing query...");
436 currow = DISPROW + 2;
437 show_text(currow, STARTCOL, "continued");
440 show_text(currow, STARTCOL, buff);
445 /****************************************************/
446 void add_member(void)
451 show_text(DISPROW, STARTCOL, "Add yourself to a list\n");
452 buf = calloc(LISTMAX, 1);
453 if (Prompt("Enter List Name: ", buf, LISTSIZE, 1) == 1)
456 argv[0] = strdup(buf);
457 argv[1] = strdup("user");
458 argv[2] = strdup(username);
459 if ((status = mr_query("add_member_to_list", 3, argv, NULL, NULL)))
462 com_err(whoami, status, " found.\n");
466 sprintf(buf, "User %s added to list\n", username);
467 show_text(DISPROW + 3, STARTCOL, buf);
469 currow = DISPROW + 4;
470 show_text(DISPROW + 4, STARTCOL, "Press any Key to continue...");
477 /****************************************************/
478 void delete_member(void)
483 show_text(DISPROW, STARTCOL, "Remove yourself from a list\n");
484 buf = calloc(LISTMAX, 1);
485 if (Prompt("Enter List Name: ", buf, LISTSIZE, 1) == 1)
488 argv[0] = strdup(buf);
489 argv[1] = strdup("user");
490 argv[2] = strdup(username);
491 if ((status = mr_query("delete_member_from_list", 3, argv, NULL, NULL)))
494 com_err(whoami, status, " found.\n");
498 sprintf(buf, "User %s deleted from list\n", username);
499 show_text(DISPROW + 3, STARTCOL, buf);
501 currow = DISPROW + 4;
502 show_text(DISPROW + 4, STARTCOL, "Press any Key to continue...");
512 /****************************************************/
513 void list_by_member(void)
518 nargv[1] = strdup("ruser");
519 nargv[2] = strdup(username);
520 buf = calloc(BUFSIZ, 1);
521 sprintf(buf, "%s is on the following lists:\n", username);
522 show_text(DISPROW, STARTCOL, buf);
523 mvcur(0, 0, currow, STARTCOL);
525 if ((status = mr_query("get_lists_of_member", 2, nargv + 1, print_1, NULL)))
528 com_err(whoami, status, " in get_lists_of_member");
531 show_text(currow, STARTCOL, "Press any Key to continue...");
537 /****************************************************/
542 show_text(DISPROW, STARTCOL, "This function may take a while... proceed? [n] ");
543 c = getchar() & INPUT_MASK;
544 if (c == 'y' || c == 'Y')
546 move(DISPROW + 1, STARTCOL);
547 addstr("Processing query...please hold");
552 erase_line(DISPROW, STARTCOL);
555 /****************************************************/
556 static int print_1(int argc, char *argv[], void *callback)
560 /* no newline 'cause display_buff adds one */
561 sprintf(buf, "%s\n", argv[0]);
567 /****************************************************/
568 static int print_all(int argc, char *argv[], void *callback)
576 erase_line(DISPROW + 1, STARTCOL);
577 show_text(DISPROW + 1, STARTCOL, "All mailing lists:");
580 sprintf(buf, "%s\n", argv[0]);
586 /****************************************************/
587 void list_all_groups(void)
590 argv[0] = argv[1] = argv[3] = "true";
591 argv[4] = "dontcare";
594 if ((status = mr_query("qualified_get_lists", 5, argv, print_all, NULL)))
597 com_err(whoami, status, " in list_all_groups\n");
602 /****************************************************/
603 void list_members(void)
610 move(DISPROW, STARTCOL);
611 mvcur(0, 0, DISPROW, STARTCOL);
613 buf = calloc(LISTMAX, 1);
614 if (Prompt("Enter List Name: ", buf, LISTSIZE, 1) == 1)
616 sprintf(buffer, "The members of list '%s' are:", buf);
617 show_text(DISPROW + 1, STARTCOL, buffer);
619 if ((status = mr_query("get_members_of_list", 1, argv, print_2, NULL)))
622 com_err(whoami, status, " found.\n");
627 show_text(currow, STARTCOL, "List is empty (no members).");
629 show_text(currow, STARTCOL, "Press any key to continue...");
642 /****************************************************/
643 static int print_2(int argc, char *argv[], void *callback)
648 sprintf(buf, "%s %s", argv[0], argv[1]);
654 /****************************************************/
655 void start_display(char *buff)
658 int secondcol; /* where to start the second column of text */
660 secondcol = (COLS / 2); /* 1/2 was accross the screen */
664 buffer = calloc(50, 1);
665 if (currow >= LINES - 2)
668 mvcur(0, 0, currow, STARTCOL);
670 if (Prompt("--RETURN for more, ctl-c to exit--", buffer, 1, 0) == 0)
672 erase_line(currow, STARTCOL);
673 show_text(currow, STARTCOL, "Flushing query...");
678 currow = DISPROW + 2;
679 sprintf(buffer, "Continued (Page %d)", page);
680 show_text(currow, STARTCOL, buffer);
685 show_text(currow, STARTCOL, buff);
688 erase_line(currow, secondcol - 1); /* in case the 1st col is too long */
689 show_text(currow, secondcol, buff);
697 /****************************************************/
698 void end_display(void)
708 buffer = calloc(50, 1);
710 sprintf(buffer, "End of List. %d Total Members\n", num_members - 1);
711 show_text(currow, STARTCOL, buffer);
713 show_text(currow, STARTCOL, "Press any key to continue...");
719 /****************************************************/
720 void display_menu(MENU *menu)
726 mvcur(0, 0, STARTROW, STARTCOL);
728 for (i = 0; i <= menu->num_items - 1; i++)
730 move(STARTROW + i, STARTCOL);
732 addstr(menu->items[i]);
735 center_text(STARTROW + menu->num_items + 2,
736 "Enter a number, <up arrow>, or <down arrow>.");
739 center_text(STARTROW + menu->num_items + 3,
740 "Press 'q' to exit, <return> to confirm choice.");
744 center_text(STARTROW + menu->num_items + 3,
745 "Press 'q' to exit, 'r' for main menu, "
746 "<return> to confirm choice.");
750 highlight(main_menu);
753 /****************************************************/
754 void pack_main_menu(void)
758 main_menu = malloc(sizeof(MENU));
759 main_menu->num_items = 7;
760 main_menu->items = malloc(sizeof(char *) * main_menu->num_items);
763 sprintf(buf, "Mail List Program for %s", username);
764 main_menu->title = strdup(buf);
765 main_menu->items[0] = strdup("1. Show all public mailing lists.");
766 main_menu->items[1] = strdup("2. Get all members of a mailing list.");
767 main_menu->items[2] = strdup("3. Display lists of which you are a member.");
768 main_menu->items[3] = strdup("4. Show description of list.");
769 main_menu->items[4] = strdup("5. Add yourself to a mailing list.");
770 main_menu->items[5] = strdup("6. Delete yourself from a mailing list.");
771 main_menu->items[6] = strdup("q. Quit.");
775 /****************************************************/
776 void pack_help_menu(void)
778 help_menu = malloc(sizeof(MENU));
779 help_menu->num_items = 5;
780 help_menu->items = malloc(sizeof(char *) * help_menu->num_items);
782 help_menu->title = strdup("mailmaint is designed as a basic mail list administration program.");
783 help_menu->items[0] = strdup("if you need to perform more advanced list manipulation like");
784 help_menu->items[1] = strdup("adding lists, or changing list characteristics, refer to the");
785 help_menu->items[2] = strdup("program listmaint.");
786 help_menu->items[3] = strdup(" ");
787 help_menu->items[4] = strdup("Press any key to continue.");
790 /****************************************************/
791 void free_menu(MENU* menu)
794 for (i = 0; i < menu->num_items; i++)
795 free(menu->items[i]);
801 /****************************************************/
802 void highlight(MENU *menu)
804 if (oldpos[level] != position[level])
806 move(STARTROW + oldpos[level] - 1, STARTCOL);
808 addstr(menu->items[oldpos[level] - 1]);
812 move(STARTROW + position[level] - 1, STARTCOL);
814 addstr(menu->items[position[level] - 1]);
820 /****************************************************/
821 void title(char *buff)
823 move(0, MAX(0, (COLS - (int)strlen(buff)) >> 1));
830 /****************************************************/
831 void center_text(int row, char *buff)
833 move(row, MAX(0, (COLS - (int)strlen(buff)) >> 1));
838 /****************************************************/
839 void show_text(int row, int col, char *buff)
841 mvcur(0, 0, row, col);
846 /****************************************************/
847 void erase_line(int row, int col)
852 buff = calloc(COLS, 1);
853 for (i = 0; i <= COLS - 2; i++)
855 buff[i] = 0; /* just to be sure ! */
857 mvcur(0, 0, row, col);
860 free(buff); /* close mem. leak */
863 /****************************************************/
870 /****************************************************/
871 void clrwin(int erase_row)
879 buff = calloc(maxcol + 1, 1);
880 for (i = 0; i <= maxcol - 1; i++)
882 buff[i] = 0; /* just to be sure ! */
883 mvcur(0, 0, erase_row, STARTCOL);
885 for (i = erase_row; i <= currow - 1; i++)
888 mvcur(erase_row, STARTCOL, STARTROW + oldpos[level] - 1, STARTCOL);
893 /****************************************************/
894 static int fetch_list_info(char *list, List_info *li)
899 return mr_query("get_list_info", 1, argv, get_list_info, NULL);
902 static int get_list_info(int argc, char **argv, void *hint)
904 if (current_li->acl_type)
905 free(current_li->acl_type);
906 current_li->acl_type = strdup(argv[7]);
907 if (current_li->acl_name)
908 free(current_li->acl_name);
909 current_li->acl_name = strdup(argv[8]);
910 if (current_li->desc)
911 free(current_li->desc);
912 current_li->desc = strdup(argv[9]);
913 if (current_li->modtime)
914 free(current_li->modtime);
915 current_li->modtime = strdup(argv[10]);
916 if (current_li->modby)
917 free(current_li->modby);
918 current_li->modby = strdup(argv[11]);
919 if (current_li->modwith)
920 free(current_li->modwith);
921 current_li->modwith = strdup(argv[12]);
926 /****************************************************/
927 /* Prompt the user for input */
928 int Prompt(char *prompt, char *buf, int buflen, int crok)
936 for (p = buf; abs(strlen(p) - strlen(buf)) <= buflen;)
939 c = getchar() & INPUT_MASK;
948 display_menu(main_menu);
955 if (strlen(buf) < 1) /* only \n or \r in buff */
976 c = getchar() & INPUT_MASK;
981 if (abs(strlen(p) - strlen(buf)) >= buflen)
1001 * Hook function to cause error messages to be printed through
1002 * curses instead of around it.
1005 void menu_err_hook(const char *who, long code, const char *fmt, va_list args)
1007 char buf[BUFSIZ], *cp;
1010 for (cp = buf; *cp; cp++)
1016 strcpy(cp, error_message(code));
1020 vsprintf(cp, fmt, args);