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>
31 #define CTL(ch) ((ch) & 037)
32 #define MAX(A, B) ((A) > (B) ? (A) : (B))
34 char *whoami; /* should not be static, for logging package */
37 typedef struct list_info {
51 static char *ascbuff = {"0123456789"};
52 static List_info *current_li = (List_info *) NULL;
54 typedef struct _menu {
60 MENU *main_menu, *help_menu;
62 int position[2], oldpos[2];
63 int level, found_some, currow, page, num_members;
64 int moreflg, toggle, first_time;
67 void get_main_input(void);
68 void show_list_info(void);
69 void display_buff(char *buf);
70 void start_display_buff(char *buff);
71 void add_member(void);
72 void delete_member(void);
73 void list_by_member(void);
75 static int print_1(int argc, char *argv[], void *callback);
76 static int print_all(int argc, char *argv[], void *callback);
77 void list_all_groups(void);
78 void list_members(void);
79 static int print_2(int argc, char *argv[], void *callback);
80 void start_display(char *buff);
81 void end_display(void);
82 void display_menu(MENU *menu);
83 void pack_main_menu(void);
84 void pack_help_menu(void);
85 void highlight(MENU *menu);
86 void title(char *buff);
87 void center_text(int row, char *buff);
88 void show_text(int row, int col, char *buff);
89 void erase_line(int row, int col);
91 void clrwin(int erase_row);
92 static int fetch_list_info(char *list, List_info *li);
93 static int get_list_info(int argc, char **argv, void *hint);
94 int Prompt(char *prompt, char *buf, int buflen, int crok);
95 void menu_err_hook(const char *who, long code, const char *fmt, va_list args);
97 /* This crock is because the original code was very broken and this makes
98 * it work. Someday, we should abandon the code or fix it right.
100 #define mvcur(oy, ox, ny, nx) move(ny, nx)
102 /****************************************************/
104 int main(int argc, char *argv[])
106 void (*old_hook)(const char *, long, const char *, va_list);
108 char buf[BUFSIZ], *motd;
110 if ((whoami = strrchr(argv[0], '/')) == NULL)
114 if (!(current_li = malloc(sizeof(List_info))))
116 sprintf(buf, ": allocating list info");
121 current_li->acl_type = NULL;
122 current_li->acl_name = NULL;
123 current_li->desc = NULL;
124 current_li->modtime = NULL;
125 current_li->modby = NULL;
126 current_li->modwith = NULL;
128 if (!(username = getlogin()))
129 username = getpwuid(getuid())->pw_name;
130 username = username ? strdup(username) : "";
132 printf("Connecting to database for %s...please hold on.\n", username);
134 status = mr_connect(NULL);
137 sprintf(buf, "\nConnection to Moira server failed");
141 status = mr_motd(&motd);
144 com_err(whoami, status, " unable to check server status");
150 fprintf(stderr, "The Moira server is currently unavailable:\n%s\n",
155 status = mr_auth("mailmaint");
158 sprintf(buf, "\nAuthorization failed.\n");
165 if ((LINES < 24) || (COLS < 60))
167 display_buff("Display window too small.\n\n");
169 "Current window parameters are (%d lines, %d columns)\n",
172 display_buff("Please resize your window\n");
173 display_buff("to at least 24 lines and 60 columns.\n");
178 old_hook = set_com_err_hook(menu_err_hook);
179 position[0] = oldpos[0] = 1;
183 display_menu(main_menu);
187 set_com_err_hook(old_hook);
192 com_err(whoami, status, buf);
196 /****************************************************/
197 void get_main_input(void)
204 oldpos[level] = position[level];
206 currow = DISPROW + 2;
208 toggle = num_members = moreflg = 0;
209 c = getchar() & 0x7f; /* mask parity bit */
210 if (c == '\r' || c == '\n')
212 if (position[level] == 7)
215 c = ascbuff[position[level]];
220 case 'L' & 037: /* clear screen */
221 display_menu(main_menu);
226 highlight(main_menu);
233 case '1': /* show all lists */
238 case '2': /* get all members of a list */
243 case '3': /* display list which user is a recipient */
248 case '4': /* show description */
253 case '5': /* add to list */
258 case '6': /* delete */
263 case 27: /* escape */
264 c = getchar() & 0x7f;
267 c = getchar() & 0x7f;
268 if (c == 65) /* up arrow */
271 if (!position[level])
276 if (c == 66) /* down arrow */
279 if (position[level] > 7)
289 highlight(main_menu);
293 /****************************************************/
294 void show_list_info(void)
298 show_text(DISPROW, STARTCOL, "Show information about a list.\n");
299 buf = calloc(1024, 1);
300 if (Prompt("Enter List Name: ", buf, LISTSIZE, 1) == 1)
303 if (fetch_list_info(buf, current_li) == 0)
305 sprintf(buf, "Description: %s\n", current_li->desc);
306 if (strlen(buf) > 60)
309 show_text(currow, STARTCOL, buf);
311 sprintf(buf, "List Administrator: %s %s",
312 current_li->acl_type, current_li->acl_name);
313 show_text(currow, STARTCOL, buf);
315 sprintf(buf, "Modified on %s by user %s with %s",
316 current_li->modtime, current_li->modby,
317 current_li->modwith);
318 show_text(currow, STARTCOL, buf);
323 show_text(currow, STARTCOL, "mailmaint: No such list found.");
326 show_text(currow, STARTCOL, "Press any Key to continue...");
332 /****************************************************/
333 void display_buff(char *buf)
342 printbuf = calloc(maxcol, 1);
343 for (i = 0; i <= strlen(buf); i++)
345 printbuf[cnt] = buf[i];
349 start_display_buff(printbuf);
352 printbuf = calloc(maxcol, 1);
355 if (strlen(buf) % maxcol != 0)
357 start_display_buff(printbuf);
363 /****************************************************/
364 void start_display_buff(char *buff)
371 if (currow >= LINES - 2)
375 mvcur(0, 0, currow, STARTCOL);
377 if (Prompt("--RETURN for more, ctl-c to exit--", buffer, 1, 0) == 0)
379 erase_line(currow, STARTCOL);
380 show_text(currow, STARTCOL, "Flushing query...");
385 currow = DISPROW + 2;
386 show_text(currow, STARTCOL, "continued");
389 show_text(currow, STARTCOL, buff);
394 /****************************************************/
395 void add_member(void)
400 show_text(DISPROW, STARTCOL, "Add yourself to a list\n");
401 buf = calloc(LISTMAX, 1);
402 if (Prompt("Enter List Name: ", buf, LISTSIZE, 1) == 1)
405 argv[0] = strdup(buf);
406 argv[1] = strdup("user");
407 argv[2] = strdup(username);
408 if ((status = mr_query("add_member_to_list", 3, argv, NULL, NULL)))
411 com_err(whoami, status, " found.\n");
415 sprintf(buf, "User %s added to list\n", username);
416 show_text(DISPROW + 3, STARTCOL, buf);
418 currow = DISPROW + 4;
419 show_text(DISPROW + 4, STARTCOL, "Press any Key to continue...");
425 /****************************************************/
426 void delete_member(void)
431 show_text(DISPROW, STARTCOL, "Remove yourself from a list\n");
432 buf = calloc(LISTMAX, 1);
433 if (Prompt("Enter List Name: ", buf, LISTSIZE, 1) == 1)
436 argv[0] = strdup(buf);
437 argv[1] = strdup("user");
438 argv[2] = strdup(username);
439 if ((status = mr_query("delete_member_from_list", 3, argv, NULL, NULL)))
442 com_err(whoami, status, " found.\n");
446 sprintf(buf, "User %s deleted from list\n", username);
447 show_text(DISPROW + 3, STARTCOL, buf);
449 currow = DISPROW + 4;
450 show_text(DISPROW + 4, STARTCOL, "Press any Key to continue...");
456 /****************************************************/
457 void list_by_member(void)
462 nargv[1] = strdup("ruser");
463 nargv[2] = strdup(username);
464 buf = calloc(BUFSIZ, 1);
465 sprintf(buf, "%s is on the following lists:\n", username);
466 show_text(DISPROW, STARTCOL, buf);
467 mvcur(0, 0, currow, STARTCOL);
469 if ((status = mr_query("get_lists_of_member", 2, nargv + 1, print_1, NULL)))
472 com_err(whoami, status, " in get_lists_of_member");
475 show_text(currow, STARTCOL, "Press any Key to continue...");
480 /****************************************************/
485 show_text(DISPROW, STARTCOL, "This function may take a while... proceed? [n] ");
486 c = getchar() & 0x7f;
487 if (c == 'y' || c == 'Y')
489 move(DISPROW + 1, STARTCOL);
490 addstr("Processing query...please hold");
495 erase_line(DISPROW, STARTCOL);
498 /****************************************************/
499 static int print_1(int argc, char *argv[], void *callback)
503 /* no newline 'cause display_buff adds one */
504 sprintf(buf, "%s\n", argv[0]);
510 /****************************************************/
511 static int print_all(int argc, char *argv[], void *callback)
519 erase_line(DISPROW + 1, STARTCOL);
520 show_text(DISPROW + 1, STARTCOL, "All mailing lists:");
523 sprintf(buf, "%s\n", argv[0]);
529 /****************************************************/
530 void list_all_groups(void)
533 argv[0] = argv[1] = argv[3] = "true";
534 argv[4] = "dontcare";
537 if ((status = mr_query("qualified_get_lists", 5, argv, print_all, NULL)))
540 com_err(whoami, status, " in list_all_groups\n");
545 /****************************************************/
546 void list_members(void)
553 move(DISPROW, STARTCOL);
554 mvcur(0, 0, DISPROW, STARTCOL);
556 buf = calloc(LISTMAX, 1);
557 if (Prompt("Enter List Name: ", buf, LISTSIZE, 1) == 1)
559 sprintf(buffer, "The members of list '%s' are:", buf);
560 show_text(DISPROW + 1, STARTCOL, buffer);
562 if ((status = mr_query("get_members_of_list", 1, argv, print_2, NULL)))
565 com_err(whoami, status, " found.\n");
570 show_text(currow, STARTCOL, "List is empty (no members).");
572 show_text(currow, STARTCOL, "Press any key to continue...");
583 /****************************************************/
584 static int print_2(int argc, char *argv[], void *callback)
589 sprintf(buf, "%s %s", argv[0], argv[1]);
595 /****************************************************/
596 void start_display(char *buff)
599 int secondcol; /* where to start the second column of text */
601 secondcol = (COLS / 2); /* 1/2 was accross the screen */
605 buffer = calloc(50, 1);
606 if (currow >= LINES - 2)
609 mvcur(0, 0, currow, STARTCOL);
611 if (Prompt("--RETURN for more, ctl-c to exit--", buffer, 1, 0) == 0)
613 erase_line(currow, STARTCOL);
614 show_text(currow, STARTCOL, "Flushing query...");
619 currow = DISPROW + 2;
620 sprintf(buffer, "Continued (Page %d)", page);
621 show_text(currow, STARTCOL, buffer);
626 show_text(currow, STARTCOL, buff);
629 erase_line(currow, secondcol - 1); /* in case the 1st col is too long */
630 show_text(currow, secondcol, buff);
636 /****************************************************/
637 void end_display(void)
647 buffer = calloc(50, 1);
649 sprintf(buffer, "End of List. %d Total Members\n", num_members - 1);
650 show_text(currow, STARTCOL, buffer);
652 show_text(currow, STARTCOL, "Press any key to continue...");
657 /****************************************************/
658 void display_menu(MENU *menu)
664 mvcur(0, 0, STARTROW, STARTCOL);
666 for (i = 0; i <= menu->num_items - 1; i++)
668 move(STARTROW + i, STARTCOL);
670 addstr(menu->items[i]);
673 center_text(STARTROW + menu->num_items + 2,
674 "Enter a number, <up arrow>, or <down arrow>.");
677 center_text(STARTROW + menu->num_items + 3,
678 "Press 'q' to exit, <return> to confirm choice.");
682 center_text(STARTROW + menu->num_items + 3,
683 "Press 'q' to exit, 'r' for main menu, "
684 "<return> to confirm choice.");
688 highlight(main_menu);
691 /****************************************************/
692 void pack_main_menu(void)
696 main_menu = malloc(sizeof(MENU));
697 main_menu->num_items = 7;
698 main_menu->items = malloc(sizeof(char *) * main_menu->num_items);
701 sprintf(buf, "Mail List Program for %s", username);
702 main_menu->title = strdup(buf);
703 main_menu->items[0] = strdup("1. Show all public mailing lists.");
704 main_menu->items[1] = strdup("2. Get all members of a mailing list.");
705 main_menu->items[2] = strdup("3. Display lists of which you are a member.");
706 main_menu->items[3] = strdup("4. Show description of list.");
707 main_menu->items[4] = strdup("5. Add yourself to a mailing list.");
708 main_menu->items[5] = strdup("6. Delete yourself from a mailing list.");
709 main_menu->items[6] = strdup("q. Quit.");
712 /****************************************************/
713 void pack_help_menu(void)
715 help_menu = malloc(sizeof(MENU));
716 help_menu->num_items = 5;
717 help_menu->items = malloc(sizeof(char *) * help_menu->num_items);
719 help_menu->title = strdup("mailmaint is designed as a basic mail list administration program.");
720 help_menu->items[0] = strdup("if you need to perform more advanced list manipulation like");
721 help_menu->items[1] = strdup("adding lists, or changing list characteristics, refer to the");
722 help_menu->items[2] = strdup("program listmaint.");
723 help_menu->items[3] = strdup(" ");
724 help_menu->items[4] = strdup("Press any key to continue.");
727 /****************************************************/
728 void highlight(MENU *menu)
730 if (oldpos[level] != position[level])
732 move(STARTROW + oldpos[level] - 1, STARTCOL);
734 addstr(menu->items[oldpos[level] - 1]);
738 move(STARTROW + position[level] - 1, STARTCOL);
740 addstr(menu->items[position[level] - 1]);
746 /****************************************************/
747 void title(char *buff)
749 move(0, MAX(0, (COLS - strlen(buff)) >> 1));
756 /****************************************************/
757 void center_text(int row, char *buff)
759 move(row, MAX(0, (COLS - strlen(buff)) >> 1));
764 /****************************************************/
765 void show_text(int row, int col, char *buff)
767 mvcur(0, 0, row, col);
772 /****************************************************/
773 void erase_line(int row, int col)
778 buff = calloc(COLS, 1);
779 for (i = 0; i <= COLS - 2; i++)
781 buff[i] = 0; /* just to be sure ! */
783 mvcur(0, 0, row, col);
786 free(buff); /* close mem. leak */
789 /****************************************************/
796 /****************************************************/
797 void clrwin(int erase_row)
805 buff = calloc(maxcol + 1, 1);
806 for (i = 0; i <= maxcol - 1; i++)
808 buff[i] = 0; /* just to be sure ! */
809 mvcur(0, 0, erase_row, STARTCOL);
811 for (i = erase_row; i <= currow - 1; i++)
814 mvcur(erase_row, STARTCOL, STARTROW + oldpos[level] - 1, STARTCOL);
819 /****************************************************/
820 static int fetch_list_info(char *list, List_info *li)
825 return mr_query("get_list_info", 1, argv, get_list_info, NULL);
828 static int get_list_info(int argc, char **argv, void *hint)
830 if (current_li->acl_type)
831 free(current_li->acl_type);
832 current_li->acl_type = strdup(argv[7]);
833 if (current_li->acl_name)
834 free(current_li->acl_name);
835 current_li->acl_name = strdup(argv[8]);
836 if (current_li->desc)
837 free(current_li->desc);
838 current_li->desc = strdup(argv[9]);
839 if (current_li->modtime)
840 free(current_li->modtime);
841 current_li->modtime = strdup(argv[10]);
842 if (current_li->modby)
843 free(current_li->modby);
844 current_li->modby = strdup(argv[11]);
845 if (current_li->modwith)
846 free(current_li->modwith);
847 current_li->modwith = strdup(argv[12]);
852 /****************************************************/
853 /* Prompt the user for input */
854 int Prompt(char *prompt, char *buf, int buflen, int crok)
861 for (p = buf; abs(strlen(p) - strlen(buf)) <= buflen;)
864 c = getchar() & 0x7f;
873 display_menu(main_menu);
880 if (strlen(buf) < 1) /* only \n or \r in buff */
900 if (abs(strlen(p) - strlen(buf)) >= buflen)
920 * Hook function to cause error messages to be printed through
921 * curses instead of around it.
924 void menu_err_hook(const char *who, long code, const char *fmt, va_list args)
926 char buf[BUFSIZ], *cp;
929 for (cp = buf; *cp; cp++)
935 strcpy(cp, error_message(code));
939 vsprintf(cp, fmt, args);