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>
37 #define INPUT_MASK 0xff
41 #define getchar() _getch()
45 static void DELETE_A_CHAR(void)
53 #define INPUT_MASK 0x7f
54 #define DELETE_A_CHAR() printf("\b \b");
64 #define CTL(ch) ((ch) & 037)
68 #define MAX(A, B) ((A) > (B) ? (A) : (B))
70 char *whoami; /* should not be static, for logging package */
73 typedef struct list_info {
87 static char *ascbuff = {"0123456789"};
88 static List_info *current_li = (List_info *) NULL;
90 typedef struct _menu {
96 MENU *main_menu, *help_menu;
98 int position[2], oldpos[2];
99 int level, found_some, currow, page, num_members;
100 int moreflg, toggle, first_time;
103 void get_main_input(void);
104 void show_list_info(void);
105 void display_buff(char *buf);
106 void start_display_buff(char *buff);
107 void add_member(void);
108 void delete_member(void);
109 void list_by_member(void);
111 static int print_1(int argc, char *argv[], void *callback);
112 static int print_all(int argc, char *argv[], void *callback);
113 void list_all_groups(void);
114 void list_members(void);
115 static int print_2(int argc, char *argv[], void *callback);
116 void start_display(char *buff);
117 void end_display(void);
118 void display_menu(MENU *menu);
119 void pack_main_menu(void);
120 void pack_help_menu(void);
121 void free_menu(MENU* menu);
122 void highlight(MENU *menu);
123 void title(char *buff);
124 void center_text(int row, char *buff);
125 void show_text(int row, int col, char *buff);
126 void erase_line(int row, int col);
128 void clrwin(int erase_row);
129 static int fetch_list_info(char *list, List_info *li);
130 static int get_list_info(int argc, char **argv, void *hint);
131 int Prompt(char *prompt, char *buf, int buflen, int crok);
132 void menu_err_hook(const char *who, long code, const char *fmt, va_list args);
134 /* This crock is because the original code was very broken and this makes
135 * it work. Someday, we should abandon the code or fix it right.
137 #define mvcur(oy, ox, ny, nx) move(ny, nx)
139 /****************************************************/
141 int main(int argc, char *argv[])
143 void (*old_hook)(const char *, long, const char *, va_list);
144 int use_menu = 1, k_errno;
145 char buf[BUFSIZ], pname[ANAME_SZ];
147 if ((whoami = strrchr(argv[0], '/')) == NULL)
151 if (!(current_li = malloc(sizeof(List_info))))
153 sprintf(buf, ": allocating list info");
158 current_li->acl_type = NULL;
159 current_li->acl_name = NULL;
160 current_li->desc = NULL;
161 current_li->modtime = NULL;
162 current_li->modby = NULL;
163 current_li->modwith = NULL;
166 if ((k_errno = tf_init(TKT_FILE, R_TKT_FIL)) ||
167 (k_errno = tf_get_pname(pname)))
169 com_err(whoami, k_errno, "reading Kerberos ticket file");
175 printf("Connecting to database for %s...please hold on.\n", username);
177 if (mrcl_connect(NULL, "mailmaint", 2, 1))
181 if ((LINES < 24) || (COLS < 60))
183 display_buff("Display window too small.\n\n");
184 sprintf(buf, "Current window parameters are (%d lines, %d columns)\n",
187 display_buff("Please resize your window\n");
188 display_buff("to at least 24 lines and 60 columns.\n");
194 old_hook = set_com_err_hook(menu_err_hook);
195 position[0] = oldpos[0] = 1;
200 display_menu(main_menu);
204 set_com_err_hook(old_hook);
206 free_menu(main_menu);
207 free_menu(help_menu);
209 if (current_li->acl_type)
210 free(current_li->acl_type);
211 if (current_li->acl_name)
212 free(current_li->acl_name);
213 if (current_li->desc)
214 free(current_li->desc);
215 if (current_li->modtime)
216 free(current_li->modtime);
217 if (current_li->modby)
218 free(current_li->modby);
219 if (current_li->modwith)
220 free(current_li->modwith);
228 com_err(whoami, status, buf);
232 /****************************************************/
233 void get_main_input(void)
240 oldpos[level] = position[level];
242 currow = DISPROW + 2;
244 toggle = num_members = moreflg = 0;
245 c = getchar() & INPUT_MASK; /* mask parity bit */
246 if (c == '\r' || c == '\n')
248 if (position[level] == 7)
251 c = ascbuff[position[level]];
256 case 'L' & 037: /* clear screen */
257 display_menu(main_menu);
262 highlight(main_menu);
269 case '1': /* show all lists */
274 case '2': /* get all members of a list */
279 case '3': /* display list which user is a recipient */
284 case '4': /* show description */
289 case '5': /* add to list */
294 case '6': /* delete */
300 case 27: /* escape */
301 c = getchar() & INPUT_MASK;
304 c = getchar() & INPUT_MASK;
305 if (c == 65) /* up arrow */
308 if (!position[level])
313 if (c == 66) /* down arrow */
316 if (position[level] > 7)
323 c = getchar() & INPUT_MASK;
324 if (c == 0x48) /* up arrow */
327 if (!position[level])
332 if (c == 0x50) /* down arrow */
335 if (position[level] > 7)
345 highlight(main_menu);
349 /****************************************************/
350 void show_list_info(void)
354 show_text(DISPROW, STARTCOL, "Show information about a list.\n");
355 buf = calloc(1024, 1);
356 if (Prompt("Enter List Name: ", buf, LISTSIZE, 1) == 1)
359 if (fetch_list_info(buf, current_li) == 0)
361 sprintf(buf, "Description: %s\n", current_li->desc);
362 if (strlen(buf) > 60)
365 show_text(currow, STARTCOL, buf);
367 sprintf(buf, "List Administrator: %s %s",
368 current_li->acl_type, current_li->acl_name);
369 show_text(currow, STARTCOL, buf);
371 sprintf(buf, "Modified on %s by user %s with %s",
372 current_li->modtime, current_li->modby,
373 current_li->modwith);
374 show_text(currow, STARTCOL, buf);
379 show_text(currow, STARTCOL, "mailmaint: No such list found.");
382 show_text(currow, STARTCOL, "Press any Key to continue...");
389 /****************************************************/
390 void display_buff(char *buf)
393 char *printbuf = NULL;
400 printbuf = calloc(maxcol, 1);
402 for (i = 0; i <= len; i++)
404 printbuf[cnt] = buf[i];
408 start_display_buff(printbuf);
411 printbuf = calloc(maxcol, 1);
414 if (len % maxcol != 0)
416 start_display_buff(printbuf);
423 /****************************************************/
424 void start_display_buff(char *buff)
431 if (currow >= LINES - 2)
435 mvcur(0, 0, currow, STARTCOL);
437 if (Prompt("--RETURN for more, ctl-c to exit--", buffer, 1, 0) == 0)
439 erase_line(currow, STARTCOL);
440 show_text(currow, STARTCOL, "Flushing query...");
445 currow = DISPROW + 2;
446 show_text(currow, STARTCOL, "continued");
449 show_text(currow, STARTCOL, buff);
454 /****************************************************/
455 void add_member(void)
460 show_text(DISPROW, STARTCOL, "Add yourself to a list\n");
461 buf = calloc(LISTMAX, 1);
462 if (Prompt("Enter List Name: ", buf, LISTSIZE, 1) == 1)
465 argv[0] = strdup(buf);
466 argv[1] = strdup("user");
467 argv[2] = strdup(username);
468 if ((status = mr_query("add_member_to_list", 3, argv, NULL, NULL)))
471 com_err(whoami, status, " found.\n");
475 sprintf(buf, "User %s added to list\n", username);
476 show_text(DISPROW + 3, STARTCOL, buf);
478 currow = DISPROW + 4;
479 show_text(DISPROW + 4, STARTCOL, "Press any Key to continue...");
486 /****************************************************/
487 void delete_member(void)
492 show_text(DISPROW, STARTCOL, "Remove yourself from a list\n");
493 buf = calloc(LISTMAX, 1);
494 if (Prompt("Enter List Name: ", buf, LISTSIZE, 1) == 1)
497 argv[0] = strdup(buf);
498 argv[1] = strdup("user");
499 argv[2] = strdup(username);
500 if ((status = mr_query("delete_member_from_list", 3, argv, NULL, NULL)))
503 com_err(whoami, status, " found.\n");
507 sprintf(buf, "User %s deleted from list\n", username);
508 show_text(DISPROW + 3, STARTCOL, buf);
510 currow = DISPROW + 4;
511 show_text(DISPROW + 4, STARTCOL, "Press any Key to continue...");
521 /****************************************************/
522 void list_by_member(void)
527 nargv[1] = strdup("ruser");
528 nargv[2] = strdup(username);
529 buf = calloc(BUFSIZ, 1);
530 sprintf(buf, "%s is on the following lists:\n", username);
531 show_text(DISPROW, STARTCOL, buf);
532 mvcur(0, 0, currow, STARTCOL);
534 if ((status = mr_query("get_lists_of_member", 2, nargv + 1, print_1, NULL)))
537 com_err(whoami, status, " in get_lists_of_member");
540 show_text(currow, STARTCOL, "Press any Key to continue...");
546 /****************************************************/
551 show_text(DISPROW, STARTCOL, "This function may take a while... proceed? [n] ");
552 c = getchar() & INPUT_MASK;
553 if (c == 'y' || c == 'Y')
555 move(DISPROW + 1, STARTCOL);
556 addstr("Processing query...please hold");
561 erase_line(DISPROW, STARTCOL);
564 /****************************************************/
565 static int print_1(int argc, char *argv[], void *callback)
569 /* no newline 'cause display_buff adds one */
570 sprintf(buf, "%s\n", argv[0]);
576 /****************************************************/
577 static int print_all(int argc, char *argv[], void *callback)
585 erase_line(DISPROW + 1, STARTCOL);
586 show_text(DISPROW + 1, STARTCOL, "All mailing lists:");
589 sprintf(buf, "%s\n", argv[0]);
595 /****************************************************/
596 void list_all_groups(void)
599 argv[0] = argv[1] = argv[3] = "true";
600 argv[4] = "dontcare";
603 if ((status = mr_query("qualified_get_lists", 5, argv, print_all, NULL)))
606 com_err(whoami, status, " in list_all_groups\n");
611 /****************************************************/
612 void list_members(void)
619 move(DISPROW, STARTCOL);
620 mvcur(0, 0, DISPROW, STARTCOL);
622 buf = calloc(LISTMAX, 1);
623 if (Prompt("Enter List Name: ", buf, LISTSIZE, 1) == 1)
625 sprintf(buffer, "The members of list '%s' are:", buf);
626 show_text(DISPROW + 1, STARTCOL, buffer);
628 if ((status = mr_query("get_members_of_list", 1, argv, print_2, NULL)))
631 com_err(whoami, status, " found.\n");
636 show_text(currow, STARTCOL, "List is empty (no members).");
638 show_text(currow, STARTCOL, "Press any key to continue...");
651 /****************************************************/
652 static int print_2(int argc, char *argv[], void *callback)
657 sprintf(buf, "%s %s", argv[0], argv[1]);
663 /****************************************************/
664 void start_display(char *buff)
667 int secondcol; /* where to start the second column of text */
669 secondcol = (COLS / 2); /* 1/2 was accross the screen */
673 buffer = calloc(50, 1);
674 if (currow >= LINES - 2)
677 mvcur(0, 0, currow, STARTCOL);
679 if (Prompt("--RETURN for more, ctl-c to exit--", buffer, 1, 0) == 0)
681 erase_line(currow, STARTCOL);
682 show_text(currow, STARTCOL, "Flushing query...");
687 currow = DISPROW + 2;
688 sprintf(buffer, "Continued (Page %d)", page);
689 show_text(currow, STARTCOL, buffer);
694 show_text(currow, STARTCOL, buff);
697 erase_line(currow, secondcol - 1); /* in case the 1st col is too long */
698 show_text(currow, secondcol, buff);
706 /****************************************************/
707 void end_display(void)
717 buffer = calloc(50, 1);
719 sprintf(buffer, "End of List. %d Total Members\n", num_members - 1);
720 show_text(currow, STARTCOL, buffer);
722 show_text(currow, STARTCOL, "Press any key to continue...");
728 /****************************************************/
729 void display_menu(MENU *menu)
735 mvcur(0, 0, STARTROW, STARTCOL);
737 for (i = 0; i <= menu->num_items - 1; i++)
739 move(STARTROW + i, STARTCOL);
741 addstr(menu->items[i]);
744 center_text(STARTROW + menu->num_items + 2,
745 "Enter a number, <up arrow>, or <down arrow>.");
748 center_text(STARTROW + menu->num_items + 3,
749 "Press 'q' to exit, <return> to confirm choice.");
753 center_text(STARTROW + menu->num_items + 3,
754 "Press 'q' to exit, 'r' for main menu, "
755 "<return> to confirm choice.");
759 highlight(main_menu);
762 /****************************************************/
763 void pack_main_menu(void)
767 main_menu = malloc(sizeof(MENU));
768 main_menu->num_items = 7;
769 main_menu->items = malloc(sizeof(char *) * main_menu->num_items);
772 sprintf(buf, "Mail List Program for %s", username);
773 main_menu->title = strdup(buf);
774 main_menu->items[0] = strdup("1. Show all public mailing lists.");
775 main_menu->items[1] = strdup("2. Get all members of a mailing list.");
776 main_menu->items[2] = strdup("3. Display lists of which you are a member.");
777 main_menu->items[3] = strdup("4. Show description of list.");
778 main_menu->items[4] = strdup("5. Add yourself to a mailing list.");
779 main_menu->items[5] = strdup("6. Delete yourself from a mailing list.");
780 main_menu->items[6] = strdup("q. Quit.");
784 /****************************************************/
785 void pack_help_menu(void)
787 help_menu = malloc(sizeof(MENU));
788 help_menu->num_items = 5;
789 help_menu->items = malloc(sizeof(char *) * help_menu->num_items);
791 help_menu->title = strdup("mailmaint is designed as a basic mail list administration program.");
792 help_menu->items[0] = strdup("if you need to perform more advanced list manipulation like");
793 help_menu->items[1] = strdup("adding lists, or changing list characteristics, refer to the");
794 help_menu->items[2] = strdup("program listmaint.");
795 help_menu->items[3] = strdup(" ");
796 help_menu->items[4] = strdup("Press any key to continue.");
799 /****************************************************/
800 void free_menu(MENU* menu)
803 for (i = 0; i < menu->num_items; i++)
804 free(menu->items[i]);
810 /****************************************************/
811 void highlight(MENU *menu)
813 if (oldpos[level] != position[level])
815 move(STARTROW + oldpos[level] - 1, STARTCOL);
817 addstr(menu->items[oldpos[level] - 1]);
821 move(STARTROW + position[level] - 1, STARTCOL);
823 addstr(menu->items[position[level] - 1]);
829 /****************************************************/
830 void title(char *buff)
832 move(0, MAX(0, (COLS - (int)strlen(buff)) >> 1));
839 /****************************************************/
840 void center_text(int row, char *buff)
842 move(row, MAX(0, (COLS - (int)strlen(buff)) >> 1));
847 /****************************************************/
848 void show_text(int row, int col, char *buff)
850 mvcur(0, 0, row, col);
855 /****************************************************/
856 void erase_line(int row, int col)
861 buff = calloc(COLS, 1);
862 for (i = 0; i <= COLS - 2; i++)
864 buff[i] = 0; /* just to be sure ! */
866 mvcur(0, 0, row, col);
869 free(buff); /* close mem. leak */
872 /****************************************************/
879 /****************************************************/
880 void clrwin(int erase_row)
888 buff = calloc(maxcol + 1, 1);
889 for (i = 0; i <= maxcol - 1; i++)
891 buff[i] = 0; /* just to be sure ! */
892 mvcur(0, 0, erase_row, STARTCOL);
894 for (i = erase_row; i <= currow - 1; i++)
897 mvcur(erase_row, STARTCOL, STARTROW + oldpos[level] - 1, STARTCOL);
902 /****************************************************/
903 static int fetch_list_info(char *list, List_info *li)
908 return mr_query("get_list_info", 1, argv, get_list_info, NULL);
911 static int get_list_info(int argc, char **argv, void *hint)
913 if (current_li->acl_type)
914 free(current_li->acl_type);
915 current_li->acl_type = strdup(argv[7]);
916 if (current_li->acl_name)
917 free(current_li->acl_name);
918 current_li->acl_name = strdup(argv[8]);
919 if (current_li->desc)
920 free(current_li->desc);
921 current_li->desc = strdup(argv[9]);
922 if (current_li->modtime)
923 free(current_li->modtime);
924 current_li->modtime = strdup(argv[10]);
925 if (current_li->modby)
926 free(current_li->modby);
927 current_li->modby = strdup(argv[11]);
928 if (current_li->modwith)
929 free(current_li->modwith);
930 current_li->modwith = strdup(argv[12]);
935 /****************************************************/
936 /* Prompt the user for input */
937 int Prompt(char *prompt, char *buf, int buflen, int crok)
945 for (p = buf; abs(strlen(p) - strlen(buf)) <= buflen;)
948 c = getchar() & INPUT_MASK;
957 display_menu(main_menu);
964 if (strlen(buf) < 1) /* only \n or \r in buff */
985 c = getchar() & INPUT_MASK;
990 if (abs(strlen(p) - strlen(buf)) >= buflen)
1010 * Hook function to cause error messages to be printed through
1011 * curses instead of around it.
1014 void menu_err_hook(const char *who, long code, const char *fmt, va_list args)
1016 char buf[BUFSIZ], *cp;
1019 for (cp = buf; *cp; cp++)
1025 strcpy(cp, error_message(code));
1029 vsprintf(cp, fmt, args);