home *** CD-ROM | disk | FTP | other *** search
/ synchro.net / synchro.net.tar / synchro.net / modem.madness / SMMNETML / WML-401C.ZIP / COMMAND.C < prev    next >
Encoding:
C/C++ Source or Header  |  1993-02-08  |  24.6 KB  |  758 lines

  1. /*
  2.  * W-MAIL       MicroWalt Extended Mail Agent.
  3.  *              This module handles the interactive part of the mailer
  4.  *              program, when the user wants to read or send mail.
  5.  *
  6.  * Authors:     Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  7.  *              Message lists inspired by "clp", The Crouton Man.
  8.  *        Copyright 1988-1992 MicroWalt Corporation
  9.  */
  10. #include "wmail.h"
  11. #include <sys/stat.h>
  12. #include <setjmp.h>
  13. #include <signal.h>
  14.  
  15.  
  16. #define NR_MSGS         20              /* #messages per summary display    */
  17.  
  18.  
  19. typedef struct _mlist_ {
  20.   struct _mlist_    *next;              /* next message in list             */
  21.   MSG               *msg;               /* pointer to referenced message    */
  22. } MLIST;
  23.  
  24.  
  25. static jmp_buf sig_jmp;                 /* for quitting out of letters      */
  26.  
  27.  
  28. static _PROTOTYPE( void sig_catch, (int)                                    );
  29. static _PROTOTYPE( void ml_quit, (MLIST *)                                  );
  30. static _PROTOTYPE( void ml_add, (MLIST **, int)                             );
  31. static _PROTOTYPE( void ml_all, (MBOX *, MLIST **)                          );
  32. static _PROTOTYPE( void ml_range, (MSG *, MLIST **, int)                    );
  33. static _PROTOTYPE( MLIST *ml_scan, (MBOX *, MSG *, char **)                 );
  34. static _PROTOTYPE( void do_help, (void)                                     );
  35. static _PROTOTYPE( void do_save, (MSG *, char *, int)                       );
  36. static _PROTOTYPE( void do_prmsg, (MSG *)                                   );
  37. static _PROTOTYPE( void do_summary, (MBOX *, int)                           );
  38. static _PROTOTYPE( void do_mail, (int, char *, MSG *, int)            );
  39.  
  40.  
  41. /* Catch the SIGINT interrupt for interrupting the printing of letters. */
  42. static void sig_catch(sig)
  43. int sig;
  44. {
  45.   (void) sig;
  46.   (void) signal(SIGINT, sig_catch);
  47.   longjmp(sig_jmp, 1);
  48. }
  49.  
  50.  
  51. /* Free memory used by do_list(). Sets list to MESG_NIL. */
  52. static void ml_quit(list)
  53. register MLIST *list;
  54. {
  55.   register MLIST *temp;
  56.  
  57.   if (list == (MLIST *)NULL) return;
  58.   while(list != (MLIST *)NULL) {
  59.         temp = list->next;
  60.         free(list);
  61.         list = temp;
  62.   }
  63. }
  64.  
  65.  
  66. /* Add a letter to a message list. */
  67. static void ml_add(listp, msgnum)
  68. MLIST **listp;
  69. int msgnum;
  70. {
  71.   register MLIST *temp, *list;
  72.   MSG *msg;
  73.  
  74.   if ((msg = mb_select(msgnum)) == (MSG *)NULL) {
  75.         fprintf(stderr, "%d: no such letter!\n", msgnum);
  76.         ml_quit(*listp);
  77.         *listp = (MLIST *)NULL;
  78.         return;
  79.   }
  80.  
  81.   /* Allocate an MLIST frame for this letter. */
  82.   if ((temp = (MLIST *)malloc(sizeof(MLIST))) == (MLIST *)NULL) {
  83.         fprintf(stderr, "%d: Out of memory!\n", msgnum);
  84.         ml_quit(*listp);
  85.         *listp = (MLIST *)NULL;
  86.         return;
  87.   }
  88.  
  89.   /* Add to the MLIST chain. */
  90.   if (*listp == (MLIST *)NULL) {
  91.         *listp = temp;
  92.   } else {
  93.         list = *listp;
  94.         while(list->next != (MLIST *)NULL) list = list->next;
  95.         list->next = temp;
  96.   }
  97.   temp->next = (MLIST *)NULL;
  98.   temp->msg = msg;
  99. }
  100.  
  101.  
  102. /* Create a list of ALL messages. */
  103. static void ml_all(mbox, listp)
  104. MBOX *mbox;
  105. register MLIST **listp;
  106. {
  107.   register MSG *msg;
  108.  
  109.   msg = mbox->first;
  110.   while(msg != (MSG *)NULL) {
  111.         ml_add(listp, msg->seq);
  112.         msg = msg->next;
  113.   }
  114. }
  115.  
  116.  
  117. /* Create a range of messagesin a list. */
  118. static void ml_range(curmsg, listp, endnum)
  119. MSG *curmsg;
  120. MLIST **listp;
  121. int endnum;
  122. {
  123.   register MSG *msg;
  124.  
  125.   /* If no starting number was given, use the current letter. */
  126.   if (*listp == (MLIST *)NULL) ml_add(listp, curmsg->seq);
  127.  
  128.   msg = (*listp)->msg;
  129.   if (msg->seq > endnum) {
  130.         fprintf(stderr, "%d: Smaller than starting number (%d) !\n",
  131.                                                 endnum, msg->seq);
  132.         ml_quit(*listp);
  133.         *listp = (MLIST *)NULL;
  134.         return;
  135.   }
  136.   msg = msg->next;
  137.   while((msg != (MSG *)NULL) && (msg->seq <= endnum)) {
  138.         ml_add(listp, msg->seq);
  139.         msg = msg->next;
  140.   }
  141. }
  142.  
  143.  
  144. /*
  145.  * Take a mesg list as imput and create a useful list of messages.
  146.  * It is up to the calling function to figure out if let deleted
  147.  * or not.  Input syntax:
  148.  *
  149.  *      number  mesg numbers.
  150.  *      '-'             range. If a field is null, use current position
  151.  *      '*'             all messages
  152.  *      '$'             last message
  153.  *      ' ', '\t', ','  field seprators
  154.  *      other           next non-list field
  155.  */
  156. static MLIST *ml_scan(mbox, msg, spp)
  157. MBOX *mbox;
  158. MSG *msg;
  159. char **spp;
  160. {
  161.   MLIST *list = (MLIST *)NULL;
  162.   register char *sp;
  163.   int range, num;
  164.  
  165.   /* Save headache now, bound check. Are there messages? */
  166.   if (mbox->first == (MSG *)NULL) return((MLIST *)NULL);
  167.  
  168.   /* Quick check for "all messages". */
  169.   sp = *spp;
  170.   while((*sp == ' ') || (*sp == '\t')) sp++;
  171.   if (*sp == '*') {
  172.         ml_all(mbox, &list);
  173.         sp++;
  174.         while ((*sp == ' ') || (*sp == '\t')) sp++;
  175.         *spp = sp;
  176.         return(list);
  177.   }
  178.  
  179.   /* Scan the input text for list entries. */
  180.   range = 0;
  181.   while (sp != (char *)NULL) switch(*sp) {
  182.         case '\0':      /* end of text */
  183.                 if (range == 1) ml_range(msg, &list, msg->seq);
  184.                 while ((*sp == ' ') || (*sp == '\t')) sp++;
  185.                 *spp = sp;
  186.                 sp = (char *)NULL;
  187.                 continue;
  188.         case ' ':
  189.         case '\t':      /* whitespace */
  190.                 while ((*sp == ' ') || (*sp == '\t')) sp++;
  191.                 continue;
  192.         case '0':
  193.         case '1':
  194.         case '2':
  195.         case '3':
  196.         case '4':
  197.         case '5':
  198.         case '6':
  199.         case '7':
  200.         case '8':
  201.         case '9':       /* simple number */
  202.                 if ((num = atoi(sp)) == 0) num = 1;
  203.                 if (range == 1) {
  204.                         ml_range(msg, &list, num);
  205.                         range = 0;
  206.                 } else ml_add(&list, num);
  207.                 while((*sp >= '0') && (*sp <= '9')) sp++;
  208.                 continue;
  209.         case '-':       /* range */
  210.                 range = 1;
  211.                 sp++;
  212.                 continue;
  213.     case ',':    /* list */
  214.         sp++;
  215.         continue;
  216.         case '$':       /* last message */
  217.                 if (mbox->last != (MSG *)NULL) num = mbox->last->seq;
  218.                   else if (mbox->first != (MSG *)NULL) num = mbox->first->seq;
  219.                   else num = msg->seq;
  220.                 if (range == 1) ml_range(msg, &list, num);
  221.                   else ml_add(&list, num);
  222.                 sp++;
  223.                 continue;
  224.         default:        /* invalid field, assume next non-list.. */
  225.                 if (range == 1) ml_range(msg, &list, msg->seq);
  226.                 while ((*sp == ' ') || (*sp == '\t')) sp++;
  227.                 *spp = sp;
  228.                 sp = (char *)NULL;
  229.                 break;
  230.   }
  231.   return(list);
  232. }
  233.  
  234.  
  235. /* Give a list of possible commands. */
  236. static void do_help()
  237. {
  238.   printf("\n                ** W-MAIL Commands **\n\n");
  239.   printf(
  240.     "?       This help                 !       Shell Command Escape\n");
  241.   printf("-       Previous letter           +       Next letter\n");
  242.   printf(
  243.     "<ENTER> Show next letter          d       Delete current letter\n");
  244.   printf(
  245.     "f       Forward a letter          F       Forward a letter (quoted)\n");
  246.   printf("h       Display letter summary    m       Send mail\n");
  247.   printf("n       Same as ENTER             p       Print a letter again\n");
  248.   printf("q       Quit, update mailbox      t       Type a letter\n");
  249.   printf("s       Save current letter       u       Un-delete a letter\n");
  250.   printf("w       Save letter (no header)   x       Exit, no mbox update\n");
  251.   printf("z       Display next summary page\n\n");
  252.   printf("dp      Delete current letter, and show next\n");
  253.   printf("r       Reply to the current letter (with Reply-To:)\n");
  254.   printf("R       Reply to SENDER of current letter\n");
  255.   printf("\n");
  256. }
  257.  
  258.  
  259. /* Save the current letter to a disk-file. */
  260. static void do_save(msg, fname, header)
  261. MSG *msg;
  262. char *fname;
  263. int header;
  264. {
  265.   char buff[1024];
  266.   char path[PATH_MAX];
  267.   long chars;
  268.   int lines, i;
  269.   FILE *fp;
  270. #if _UNIX
  271.   int mymask;
  272. #endif
  273.  
  274.   /* Is this a valid message? */
  275.   if (msg->status == MS_DELETED) {
  276.         fprintf(stderr, "%d: inapropriate message!\n", msg->seq);
  277.         return;
  278.   }
  279.  
  280.   /* Did we get any save-file name? */
  281.   if (*fname == '\0') fname = rc_mbox;
  282.   if (fname == (char *)NULL) fname = SAVEFILE;
  283.  
  284.   /* Generate the complete path name of the save file. */
  285. #ifdef MSDOS
  286.   if (rc_folder != (char *)NULL) {
  287.         if (*fname == '\\' || *fname == '.') strcpy(path, fname);
  288.           else sprintf(path, "%s\\%s\\%s", u_home, rc_folder,
  289.                                 (*fname == '+') ? fname+1 : fname);
  290.   } else {
  291.         if (*fname == '\\' || *fname == '.') strcpy(path, fname);
  292.           else sprintf(path, "%s\\%s", u_home, fname);
  293.   }
  294. #else
  295.   if (rc_folder != (char *)NULL) {
  296.         if (*fname == '/' || *fname == '.') strcpy(path, fname);
  297.           else sprintf(path, "%s/%s", rc_folder,
  298.             (*fname == '+') ? fname+1 : fname);
  299.   } else {
  300.         if (*fname == '/' || *fname == '.') strcpy(path, fname);
  301.           else sprintf(path, "%s/%s", u_home, fname);
  302.   }
  303. #endif
  304.   if (opt_v == 1) fprintf(stderr, "do_save(\"%s\") --> \"%s\"\n",
  305.                                                             fname, path);
  306.  
  307.   /* Save the current file creation mask. */
  308. #if _UNIX
  309.   mymask = umask(u_mask);
  310. #endif
  311.  
  312.   /* Create (or append to) the save file. */
  313.   if ((fp = fopen(path, "a")) == (FILE *)NULL) {
  314.         perror(path);
  315. #if _UNIX
  316.         (void) umask(mymask);
  317. #endif
  318.         return;
  319.   }
  320.   msg->curr = msg->start;
  321.  
  322.   /* Skip the header if needed. */
  323.   if (header == 0) {
  324.         do {
  325.                 if (mb_rdline(msg, buff) <= 0) break;
  326.                 if (opt_v == 1) fprintf(stderr, "SAVE: skip \"%s\"\n", buff);
  327.                 if (buff[0] == '\0') break;
  328.         } while(1);
  329.   }
  330.  
  331.   /* Write the message body (poss. with header) to the save file. */
  332.   chars = 0L;
  333.   lines = 0;
  334.   while((i = mb_rdline(msg, buff)) > 0) {
  335.         chars += (long) i;
  336.         lines++;
  337.         if (opt_v == 1) fprintf(stderr, "SAVE: \"%s\"\n", buff);
  338.         fprintf(fp, "%s\n", buff);
  339.  
  340.   }
  341.   (void) fflush(fp);
  342.   if (fclose(fp) < 0) perror(path);
  343.  
  344. #if _UNIX
  345.   (void) umask(mymask);
  346. #endif
  347. }
  348.  
  349.  
  350. /* Show the contents of a message. */
  351. static void do_prmsg(msg)
  352. MSG *msg;
  353. {
  354.   char buff[1024];
  355.  
  356.   /* It this a valid message? */
  357.   if (msg->status == MS_DELETED) {
  358.         fprintf(stderr, "%d: inapropriate message!\n", msg->seq);
  359.         return;
  360.   } else printf("Message %d:\n", msg->seq);
  361.   msg->curr = msg->start;
  362.  
  363.   /* Yes.  Do we have to use the pager? */
  364.   if (opt_p == 0) {
  365.         pg_msg(msg);
  366.         return;
  367.   }
  368.  
  369.   while(mb_rdline(msg, buff) > 0) printf("%s\n", buff);
  370.   (void) fflush(stdout);
  371. }
  372.  
  373.  
  374. /* Give a summary of letters. */
  375. static void do_summary(mbox, nextmsg)
  376. MBOX *mbox;
  377. int nextmsg;
  378. {
  379.   register MSG *msg;
  380.   register int start;
  381.  
  382.   start = (((nextmsg - 1) / NR_MSGS) * NR_MSGS) + 1;
  383.   for (msg = mbox->first; msg->seq < start; msg = msg->next)
  384.                             ;
  385.   while ((msg != (MSG *)NULL) &&
  386.          (msg->seq < start + NR_MSGS) && (msg->seq > 0)) {
  387.         printf("%c%c%-2d %-17.17s %-12.12s %4d/%-7ld %-.30s\n",
  388.                 (nextmsg == msg->seq) ? '>' : ' ',
  389.                 (msg->status == MS_DELETED) ? 'D': ' ',
  390.                 msg->seq, msg->realname, msg->date,
  391.                 msg->lines, msg->chars, msg->subject);
  392.         msg = msg->next;
  393.   }
  394.   if (mbox->entries >= (start + NR_MSGS))
  395.         printf("%d more message(s)\n", (mbox->entries - start - (NR_MSGS - 1)));
  396. }
  397.  
  398.  
  399. /* Send a reply, forward a message or send mail. */
  400. static void do_mail(what, addr, msg, quote)
  401. int what;
  402. char *addr;
  403. MSG *msg;
  404. int quote;
  405. {
  406.   char buff[1024];
  407.   char *rcpts[2];
  408.   DRAFT *draft;
  409.   register FILE *fp;
  410.   register char *sp;
  411.  
  412.   /* See if this can be done at all. */
  413.   if (msg != (MSG *)NULL) {
  414.     if (msg->status == MS_DELETED) {
  415.             fprintf(stderr, "%d: inapropriate message!\n", msg->seq);
  416.         return;
  417.     }
  418.   }
  419.  
  420.   /* First of all, allocate a DRAFT selector. */
  421.   draft = (DRAFT *)NULL;
  422.   rcpts[0] = addr;
  423.   rcpts[1] = (char *)NULL;
  424.  
  425.   /* Now, see what we have to do. */
  426.   switch(what) {
  427.     case 0:        /* send mail */
  428.         if (*addr == '\0') {
  429.             do {
  430.                 fprintf(stderr, "To: ");
  431.                 (void) fflush(stderr);
  432.                 (void) fgets(buff, 1024, stdin);
  433.                 sp = strchr(buff, '\n');
  434.                 if (sp != (char *)NULL) *sp = '\0';
  435.                 sp = buff;
  436.             } while (*sp == '\0');
  437.         } else sp = addr;
  438.         draft = mk_draft(1, (char *)NULL, rcpts, "", "", "");
  439.           if (draft == (DRAFT *)NULL) return;
  440.         strncpy(draft->to, sp, 1024);
  441.         break;
  442.     case 1:        /* reply to sender */
  443.         draft = mk_draft(0, (char *)NULL, rcpts, "", "", "");
  444.           if (draft == (DRAFT *)NULL) return;
  445.                 if (!strncmp(msg->subject, "Re:", 3) ||
  446.                     !strncmp(msg->subject, "re:", 3) ||
  447.                     !strncmp(msg->subject, "RE:", 3) )
  448.                                 strcpy(draft->subject, msg->subject);
  449.                   else sprintf(draft->subject, "Re: %s", msg->subject);
  450.         break;
  451.     case 2:        /* forward a message */
  452.         draft = mk_draft(0, (char *)NULL, rcpts, "", "", "");
  453.           if (draft == (DRAFT *)NULL) return;
  454.         sprintf(draft->subject, "%s (fwd)", msg->subject);
  455.         break;
  456.   }
  457.  
  458.   /* For the "reply" and "forward" modes, copy the message body. */
  459.   if (msg != (MSG *)NULL) {
  460.     /* Create the temporary file. */
  461.     if ((fp = fopen(draft->dpath, "w")) == (FILE *)NULL) {
  462.             perror(draft->dpath);
  463.             rm_draft(draft);
  464.         return;
  465.     }
  466.  
  467.     /* Write the message to the temporary file. */
  468.     msg->curr = msg->start;
  469.     if (what == 2) fprintf(fp, "Forwarded message #1:\n----\n");
  470.     while(mb_rdline(msg, buff) > 0) {
  471.             if (quote || !strncmp(buff, "From ", 5))
  472.                     fprintf(fp, ">%s\n", buff);
  473.           else fprintf(fp, "%s\n", buff);
  474.     }
  475.     if (what == 2) fprintf(fp, "----\n\nEnd of forwarded messages.\n");
  476.     (void) fflush(fp);
  477.     (void) fclose(fp);
  478.   }
  479.  
  480.   /* Allow the user to edit the message. */
  481.   if (ed_draft(draft) != 0) {
  482.            rm_draft(draft);
  483.     return;
  484.   }
  485.  
  486.   /* All is well. Send it off... */
  487.   (void) do_send(draft);
  488.  
  489.   /* Clearnup. */
  490.   rm_draft(draft);
  491. }
  492.  
  493.  
  494. /* Interactively process the mail-box. */
  495. int do_cmd(mbox)
  496. register MBOX *mbox;
  497. {
  498.   char input[512], *sp;
  499.   MSG *msg, *xmsg;
  500.   MLIST *list, *xlist;
  501.   int intr, first, tmp;
  502.   register char c;
  503.  
  504.   if (mbox->first == (MSG *)NULL) {
  505.         fprintf(stderr, "Corrupted mailbox.\n");
  506.         return(-1);
  507.   }
  508.  
  509.   printf("W-MAIL %s.  Type ? for Help.\n", VERSION);
  510.   printf("\"%s\": %d message(s)\n", mbox->path, mbox->entries);
  511.  
  512.   msg = mbox->first;
  513.   first = 1;
  514.   intr = 0;
  515.  
  516.   do_summary(mbox, 1);
  517.  
  518.   while(1) {
  519.         if (opt_q == 0) {
  520.                 intr = setjmp(sig_jmp);
  521.                 (void) signal(SIGINT, sig_catch);
  522.         }
  523.         if (intr == 1) printf("\n");
  524.         printf(rc_prompt, msg->seq);
  525.         (void) fflush(stdout);
  526.         if (fgets(input, 512, stdin) == (char *)NULL) break;
  527. #ifdef MSDOS
  528.         if ((sp = strchr(input, '\r')) != (char *)NULL) *sp = '\0';
  529. #endif
  530.         if ((sp = strchr(input, '\n')) != (char *)NULL) *sp = '\0';
  531.         if (opt_q == 0) (void) signal(SIGINT, SIG_IGN);
  532.  
  533.         /* Look at the first valid character of the command line. */
  534.         sp = input;
  535.         while ((*sp == ' ') || (*sp == '\t')) sp++;
  536.         c = *sp++;
  537.         while ((*sp == ' ') || (*sp == '\t')) sp++;
  538.         switch(c) {
  539.                 case '!':   /* shell escape */
  540.                         (void) do_shell(sp);
  541.                         break;
  542.                 case '?':   /* type some help */
  543.                         do_help();
  544.                         break;
  545.                 case '-':   /* show previous message */
  546.                         if (msg->prev != (MSG *)NULL) msg = msg->prev;
  547.                           else printf("Top of mailbox\n");
  548.                         break;
  549.                 case '+':   /* show next message */
  550.                         if (msg->next != (MSG *)NULL) msg = msg->next;
  551.                           else printf("At EOF\n");
  552.                         break;
  553.                 case '\0':  /* move to next message and show current */
  554.                 case 'n':
  555.                         if (first == 0) {
  556.                                 if (msg->next == (MSG *)NULL) {
  557.                                         printf(rc_prompt, msg->seq);
  558.                                         printf("At EOF\n");
  559.                                 } else msg = msg->next;
  560.                         } else first = 0;
  561.                         if (msg->status == MS_DELETED) {
  562.                                 fprintf(stderr, "%d: inapropriate message!\n",
  563.                                                             msg->seq);
  564.                                 break;
  565.                         }
  566.                         if (intr == 0) {
  567.                             do_prmsg(msg);
  568.                             msg->status = MS_READ;
  569.                         }
  570.                         break;
  571.                 case 'd':   /* delete a range of letters */
  572.                         mbox->update = 1;
  573.                         list = ml_scan(mbox, msg, &sp);
  574.                         if ((xlist = list) == (MLIST *)NULL) {
  575.                                 msg->status = MS_DELETED;
  576.                                 printf("Message %d deleted.\n", msg->seq);
  577.                                 break;
  578.                         }
  579.                         while(list != (MLIST *)NULL) {
  580.                                 list->msg->status = MS_DELETED;
  581.                                 printf("Message %d deleted.\n",
  582.                                                 list->msg->seq);
  583.                                 list = list->next;
  584.                         }
  585.                         if (intr == 0) {
  586.                                 if ((*sp == 'p') || (*sp == 't')) {
  587.                                         if (msg->next == (MSG *)NULL) {
  588.                                                 printf("EOF\n");
  589.                                                 break;
  590.                                         } else msg = msg->next;
  591.                                 }
  592.                                 if (*sp == 'p') do_prmsg(msg);
  593.                                 if (*sp == 't') {
  594.                                         tmp = opt_p;
  595.                                         opt_p = 1;
  596.                                         do_prmsg(msg);
  597.                                         opt_p = tmp;
  598.                                 }
  599.                         }
  600.                         ml_quit(xlist);
  601.                         break;
  602.                 case 'f':   /* forward current letter */
  603.                         do_mail(2, sp, msg, 0);
  604.                         break;
  605.                 case 'F':   /* forward current letter (quoted) */
  606.                         do_mail(2, sp, msg, 0);
  607.                         break;
  608.                 case 'h':   /* show letter summary */
  609.                         list = ml_scan(mbox, msg, &sp);
  610.                         if (list != (MLIST *)NULL) {
  611.                                 do_summary(mbox, list->msg->seq);
  612.                                 msg = list->msg;
  613.                         } else do_summary(mbox, msg->seq);
  614.                         ml_quit(list);
  615.                         break;
  616.                 case 'm':   /* send mail */
  617.                         do_mail(0, sp, (MSG *)NULL, 0);
  618.                         break;
  619.                 case 'p':   /* print a letter */
  620.                 case '.':   /* print a letter */
  621.                         if (intr == 0) {
  622.                                 list = ml_scan(mbox, msg, &sp);
  623.                                 if (list == (MLIST *)NULL) {
  624.                                         do_prmsg(msg);
  625.                                         break;
  626.                                 }
  627.                                 xlist = list;
  628.                                 while (list != (MLIST *)NULL) {
  629.                                         do_prmsg(list->msg);
  630.                                         list = list->next;
  631.                                 }
  632.                                 ml_quit(xlist);
  633.                         }
  634.                         break;
  635.                 case 'q':   /* update mailbox and quit */
  636.                         return(0);
  637.                         /*NOTREACHED*/
  638.                 case 'r':   /* reply to a message (use Reply-To:) */
  639.                         list = ml_scan(mbox, msg, &sp);
  640.                         if (list == (MLIST *)NULL)
  641.                                 do_mail(1, msg->reply, msg, 1);
  642.                           else
  643.                                 do_mail(1, msg->reply, msg, 0);
  644.                         ml_quit(list);
  645.                         break;
  646.                 case 'R':   /* reply to SENDER of a message */
  647.                         list = ml_scan(mbox, msg, &sp);
  648.                         if (list == (MLIST *)NULL)
  649.                                 do_mail(1, msg->reply, msg, 1);
  650.                           else
  651.                                 do_mail(1, msg->reply, msg, 1);
  652.                         ml_quit(list);
  653.                         break;
  654.                 case 's':   /* save message to disk */
  655.                         list = ml_scan(mbox, msg, &sp);
  656.                         if (list == (MLIST *)NULL) {
  657.                                 do_save(msg, sp, 1);
  658.                                 break;
  659.                         }
  660.                         xlist = list;
  661.                         while (list != (MLIST *)NULL) {
  662.                                 do_save(list->msg, sp, 1);
  663.                                 list = list->next;
  664.                         }
  665.                         ml_quit(xlist);
  666.                         break;
  667.                 case 't':   /* type (no paging) current letter */
  668.                         if (intr == 0) {
  669.                                 tmp = opt_p;
  670.                                 opt_p = 1;
  671.                                 list = ml_scan(mbox, msg, &sp);
  672.                                 if (list == (MLIST *)NULL) {
  673.                                         do_prmsg(msg);
  674.                                         opt_p = tmp;
  675.                                         break;
  676.                                 }
  677.                                 xlist = list;
  678.                                 while (list != (MLIST *)NULL) {
  679.                                         do_prmsg(list->msg);
  680.                                         list = list->next;
  681.                                 }
  682.                                 ml_quit(xlist);
  683.                                 opt_p = tmp;
  684.                         }
  685.                         break;
  686.                 case 'u':   /* un-delete a letter */
  687.                         list = ml_scan(mbox, msg, &sp);
  688.                         if ((xlist = list) == (MLIST *)NULL) break;
  689.                         while(list != (MLIST *)NULL) {
  690.                                 list->msg->status &= ~MS_DELETED;
  691.                                 printf("Message %d un-deleted.\n",
  692.                                                 list->msg->seq);
  693.                                 list = list->next;
  694.                         }
  695.                         ml_quit(xlist);
  696.                         break;
  697.                 case 'w':   /* write (without header) message to disk */
  698.                         list = ml_scan(mbox, msg, &sp);
  699.                         if (list == (MLIST *)NULL) {
  700.                                 do_save(msg, sp, 0);
  701.                                 break;
  702.                         }
  703.                         xlist = list;
  704.                         while (list != (MLIST *)NULL) {
  705.                                 do_save(list->msg, sp, 0);
  706.                                 list = list->next;
  707.                         }
  708.                         ml_quit(xlist);
  709.                         break;
  710.                 case 'x':   /* abort, do not update mailbox */
  711.                         exit(0);
  712.                         /*NOTREACHED*/
  713.                 case 'z':   /* display next summary page */
  714.                         if (msg->next == (MSG *)NULL) tmp = msg->seq - 1;
  715.                           else tmp = msg->next->seq;
  716.                         tmp = ((tmp / NR_MSGS) * NR_MSGS) + NR_MSGS + 1;
  717.                         if (tmp > mbox->entries) msg = mbox->first;
  718.                           else while (msg->seq != tmp) msg = msg->next;
  719.                         do_summary(mbox, msg->seq);
  720.                         break;
  721.                 default:
  722.                         if (isdigit(*--sp)) {
  723.                                 xmsg = mb_select(atoi(sp));
  724.                                 if (xmsg == (MSG *)NULL) {
  725.                                         printf("No message number %s\n", sp);
  726.                                         break;
  727.                                 }
  728.                                 msg = xmsg;
  729.                                 do_prmsg(msg);
  730.                         } else printf("Unknown command\n");
  731.                         break;
  732.         }
  733.   }
  734.   /*NOTREACHED*/
  735.   return(0);
  736. }
  737.  
  738.  
  739. /* Print all letters and quit. */
  740. int do_prall(mbox)
  741. register MBOX *mbox;
  742. {
  743.   register MSG *msg;
  744.  
  745.   if (mbox->first == (MSG *)NULL) {
  746.         fprintf(stderr, "Corrupted mailbox.\n");
  747.         return(-1);
  748.   }
  749.  
  750.   msg = mbox->first;
  751.   if (msg == (MSG *)NULL) return(1);
  752.   while(msg != (MSG *)NULL) {
  753.         do_prmsg(msg);
  754.         msg = msg->next;
  755.   }
  756.   return(0);
  757. }
  758.