home *** CD-ROM | disk | FTP | other *** search
/ ftp.uv.es / 2014.11.ftp.uv.es.tar / ftp.uv.es / pub / unix / aix-rs6000 / elm2.3.11.AIX3.1.5.Z / elm2.3.11.AIX3.1.5 / src / editmsg.c < prev    next >
C/C++ Source or Header  |  1991-11-26  |  20KB  |  675 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: editmsg.c,v 4.1.1.4 91/01/07 20:36:26 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 4.1.1.4 $   $State: Exp $
  6.  *
  7.  *             Copyright (c) 1986, 1987 Dave Taylor
  8.  *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log:    editmsg.c,v $
  17.  * Revision 4.1.1.4  91/01/07  20:36:26  syd
  18.  * Fix warning message on compiling editmsg on voidsig machines
  19.  * From: Chip Salzenberg
  20.  * 
  21.  * Revision 4.1.1.3  90/07/12  22:43:08  syd
  22.  * Make it aware of the fact that we loose the cursor position on
  23.  * some system calls, so set it far enough off an absolute move will
  24.  * be done on the next cursor address, and then place it where we want it.
  25.  * From: Syd, reported by Douglas Lamb
  26.  * 
  27.  * Revision 4.1.1.2  90/06/21  21:14:09  syd
  28.  * Force Carriage return on return from editor, as column is lost
  29.  * From: Steve Cambell
  30.  * 
  31.  * Revision 4.1.1.1  90/06/09  23:33:06  syd
  32.  * Only say cannot invoke on -1 error which is cannot do exec in system call
  33.  * From: Syd
  34.  * 
  35.  * Revision 4.1  90/04/28  22:42:47  syd
  36.  * checkin of Elm 2.3 as of Release PL0
  37.  * 
  38.  *
  39.  ******************************************************************************/
  40.  
  41. /** This contains routines to do with starting up and using an editor (or two)
  42.     from within Elm.  This stuff used to be in mailmsg2.c...
  43. **/
  44.  
  45. #include "headers.h"
  46. #include <errno.h>
  47. #ifndef BSD
  48. /* BSD has already included setjmp.h in headers.h */
  49. #include <setjmp.h>
  50. #endif /* BSD */
  51. #include <signal.h>
  52. #include <ctype.h>
  53.  
  54. #ifdef BSD
  55. #undef        tolower
  56. #endif
  57.  
  58. extern int errno;
  59.  
  60. char *error_name(), *error_description(), /* *strcpy(), */ *format_long();
  61. unsigned long sleep();
  62.  
  63. int
  64. edit_the_message(filename, already_has_text)
  65. char *filename;
  66. int  already_has_text;
  67. {
  68.     /** Invoke the users editor on the filename.  Return when done. 
  69.         If 'already has text' then we can't use the no-editor option
  70.         and must use 'alternative editor' (e.g. $EDITOR or default_editor)
  71.         instead... **/
  72.  
  73.     char buffer[SLEN];
  74.     register int stat, return_value = 0, old_raw;
  75.  
  76.     buffer[0] = '\0';
  77.  
  78.     if (strcmp(editor, "builtin") == 0 || strcmp(editor, "none") == 0) {
  79.       if (already_has_text) 
  80.         sprintf(buffer, "%s %s", alternative_editor, filename);
  81.       else
  82.         return(no_editor_edit_the_message(filename));
  83.     }
  84.  
  85.     PutLine0(LINES, 0, "Invoking editor...");  fflush(stdout);
  86.     if (strlen(buffer) == 0)
  87.       sprintf(buffer,"%s %s", editor, filename);
  88.  
  89.     chown(filename, userid, groupid);    /* file was owned by root! */
  90.  
  91.     if (( old_raw = RawState()) == ON)
  92.       Raw(OFF);
  93.  
  94.     if (cursor_control)
  95.       transmit_functions(OFF);        /* function keys are local */
  96.  
  97.     if ((stat = system_call(buffer, SH, TRUE, FALSE)) == -1) { 
  98.       dprint(1,(debugfile, 
  99.           "System call failed with stat %d (edit_the_message)\n", 
  100.           stat));
  101.       dprint(1, (debugfile, "** %s - %s **\n", error_name(errno), 
  102.         error_description(errno)));
  103.       ClearLine(LINES-1);
  104.       error1("Can't invoke editor '%s' for composition.", editor);
  105.       sleep(2);
  106.       return_value = 1;
  107.     }
  108.  
  109.     if (old_raw == ON)
  110.        Raw(ON);
  111.  
  112.     SetXYLocation(0, 40);    /* a location not near the next request, so an absolute is used */
  113.     MoveCursor(LINES, 0);    /* dont know where we are, force last row, col 0 */
  114.  
  115.     if (cursor_control)
  116.       transmit_functions(ON);        /* function keys are local */
  117.     
  118.     return(return_value);
  119. }
  120.  
  121. static char simple_continue[] = "(Continue.)\n\r";
  122. static char post_ed_continue[] = 
  123. "(Continue entering message.  Type ^D or '.' on a line by itself to end.)\n\r";
  124.  
  125. extern char to[VERY_LONG_STRING], cc[VERY_LONG_STRING], 
  126.         expanded_to[VERY_LONG_STRING], expanded_cc[VERY_LONG_STRING], 
  127.         bcc[VERY_LONG_STRING], expanded_bcc[VERY_LONG_STRING],
  128.             subject[SLEN];
  129.  
  130. int      interrupts_while_editing;    /* keep track 'o dis stuff         */
  131. jmp_buf  edit_location;                /* for getting back from interrupt */
  132.  
  133. char *strip_commas();
  134. long  fsize();
  135.  
  136. int
  137. no_editor_edit_the_message(filename)
  138. char *filename;
  139. {
  140.     /** If the current editor is set to either "builtin" or "none", then
  141.         invoke this program instead.  As it turns out, this and the 
  142.         routine above have a pretty incestuous relationship (!)...
  143.     **/
  144.  
  145.     FILE *edit_fd;
  146.     char buffer[SLEN], editor_name[SLEN], buf[SLEN];
  147.     int      old_raw;
  148. #ifdef VOIDSIG
  149.     void    edit_interrupt();
  150.     void    (*oldint)(), (*oldquit)();
  151. #else
  152.     int    edit_interrupt();
  153.     int    (*oldint)(), (*oldquit)();
  154. #endif
  155.  
  156.     if ((edit_fd = fopen(filename, "a")) == NULL) {
  157.       error2("Couldn't open %s for appending [%s].", filename, 
  158.           error_name(errno));
  159.       sleep (2);
  160.       dprint(1, (debugfile,
  161.         "Error encountered trying to open file %s;\n", filename));
  162.       dprint(1, (debugfile, "** %s - %s **\n", error_name(errno),
  163.             error_description(errno)));
  164.       return(1);
  165.     }
  166.  
  167.     /** is there already text in this file? **/
  168.  
  169.     if (fsize(edit_fd) > 0L)
  170.       strcpy(buf, "\n\rContinue entering message.");
  171.     else
  172.       strcpy(buf, "\n\rEnter message.");
  173.     strcat(buf, "  Type Elm commands on lines by themselves.\n\r");
  174.     sprintf(buf + strlen(buf),
  175.     "Commands include:  ^D or '.' to end, %cp to list, %c? for help.\n\r\n\r",
  176.         escape_char, escape_char);
  177.     CleartoEOS();
  178.     Write_to_screen(buf, 0);
  179.  
  180.     oldint  = signal(SIGINT,  edit_interrupt);
  181.     oldquit = signal(SIGQUIT, edit_interrupt);
  182.  
  183.     interrupts_while_editing = 0;
  184.  
  185.     if (setjmp(edit_location) != 0) {
  186.       if (interrupts_while_editing > 1) {
  187.  
  188.         (void) signal(SIGINT,  oldint);
  189.         (void) signal(SIGQUIT, oldquit);
  190.  
  191.         if (edit_fd != NULL)    /* insurance... */
  192.           fclose(edit_fd);
  193.         return(1);
  194.       }
  195.       goto more_input;    /* read input again, please! */
  196.     }
  197.     
  198. more_input: buffer[0] = '\0';
  199.  
  200.     while (optionally_enter(buffer, -1,-1, FALSE, FALSE) == 0) {
  201.  
  202.       interrupts_while_editing = 0;    /* reset to zero... */
  203.  
  204.       if (strcmp(buffer, ".") == 0)
  205.         break;    /* '.' is as good as a ^D to us dumb programs :-) */
  206.       if (buffer[0] == escape_char) {
  207.         switch (tolower(buffer[1])) {
  208.               case '?' : tilde_help();
  209.              goto more_input;
  210.  
  211.           case TILDE_ESCAPE: move_left(buffer, 1); 
  212.                    goto tilde_input;    /*!!*/
  213.  
  214.           case 't' : get_with_expansion("\n\rTo: ",
  215.                      to, expanded_to, buffer);
  216.              goto more_input;
  217.           case 'b' : get_with_expansion("\n\rBcc: ",
  218.                bcc, expanded_bcc, buffer);
  219.              goto more_input;
  220.           case 'c' : get_with_expansion("\n\rCc: ",
  221.                cc, expanded_cc, buffer);
  222.              goto more_input;
  223.           case 's' : get_with_expansion("\n\rSubject: ",
  224.                subject,NULL,buffer);
  225.                 goto more_input;
  226.  
  227.           case 'h' : get_with_expansion("\n\rTo: ", to, expanded_to, NULL);    
  228.                      get_with_expansion("Cc: ", cc, expanded_cc, NULL);
  229.                      get_with_expansion("Bcc: ", bcc,expanded_bcc, NULL);
  230.                      get_with_expansion("Subject: ", subject, NULL, NULL);
  231.              goto more_input;
  232.  
  233.           case 'r' : read_in_file(edit_fd, (char *) buffer + 2, 1);
  234.                goto more_input;
  235.           case 'e' : if (strlen(emacs_editor) > 0) 
  236.                        if (access(emacs_editor, ACCESS_EXISTS) == 0) {
  237.                          strcpy(buffer, editor);
  238.                  strcpy(editor, emacs_editor);
  239.                    fclose(edit_fd);
  240.                  (void) edit_the_message(filename,0);
  241.                  strcpy(editor, buffer);
  242.                  edit_fd = fopen(filename, "a");
  243.                              Write_to_screen(post_ed_continue, 0);
  244.                          goto more_input;
  245.                    }
  246.                    else
  247.                          Write_to_screen(
  248.             "\n\r(Can't find Emacs on this system! Continue.)\n\r",
  249.             0);
  250.              else
  251.                Write_to_screen(
  252.             "\n\r(Don't know where Emacs would be. Continue.)\n\r",
  253.             0);    
  254.              goto more_input;
  255.  
  256.            case 'v' : NewLine();
  257.               strcpy(buffer, editor);
  258.               strcpy(editor, default_editor);
  259.               fclose(edit_fd);
  260.               (void) edit_the_message(filename,0);
  261.               strcpy(editor, buffer);
  262.               edit_fd = fopen(filename, "a");
  263.                           Write_to_screen(post_ed_continue, 0);
  264.                       goto more_input;
  265.  
  266.            case 'o' : Write_to_screen(
  267.                  "\n\rPlease enter the name of the editor: ", 0);
  268.               editor_name[0] = '\0';
  269.               optionally_enter(editor_name,-1,-1, FALSE, FALSE);
  270.               NewLine();
  271.                       if (strlen(editor_name) > 0) {
  272.                         strcpy(buffer, editor);
  273.                 strcpy(editor, editor_name);
  274.                 fclose(edit_fd);
  275.                 (void) edit_the_message(filename,0);
  276.                 strcpy(editor, buffer);
  277.                 edit_fd = fopen(filename, "a");
  278.                             Write_to_screen(post_ed_continue, 0);
  279.                         goto more_input;
  280.                   }
  281.                 Write_to_screen(simple_continue, 0);
  282.                       goto more_input; 
  283.  
  284.         case '<' : NewLine();
  285.                if (strlen(buffer) < 3)
  286.                  Write_to_screen(
  287.          "(You need to use a specific command here. Continue.)\n\r");
  288.                else {
  289.                  sprintf(buf, " > %s%s.%d 2>&1", temp_dir, temp_edit, getpid());
  290.                  strcat(buffer, buf);
  291.                  if (( old_raw = RawState()) == ON)
  292.                    Raw(OFF);
  293.                  (void) system_call((char *) buffer+2, SH, TRUE, TRUE);
  294.                  if (old_raw == ON)
  295.                     Raw(ON);
  296.                  sprintf(buffer, "~r %s%s.%d", temp_dir, temp_edit, getpid());
  297.                            read_in_file(edit_fd, (char *) buffer + 3, 0);
  298.                  (void) unlink((char *) buffer+3);
  299.                  SetXYLocation(0, 40);    /* a location not near the next request, so an absolute is used */
  300.                  MoveCursor(LINES, 0);    /* and go to a known location, last row col 0 */
  301.                }
  302.                        goto more_input; 
  303.  
  304.         case '!' : NewLine();
  305.                if (( old_raw = RawState()) == ON)
  306.                  Raw(OFF);
  307.                if (strlen(buffer) < 3) 
  308.                  (void) system_call(shell, USER_SHELL, TRUE, TRUE);
  309.                else
  310.                          (void) system_call((char *) buffer+2, USER_SHELL, TRUE, TRUE);
  311.                if (old_raw == ON)
  312.                   Raw(ON);
  313.                SetXYLocation(0, 40);    /* a location not near the next request, so an absolute is used */
  314.                MoveCursor(LINES, 0);    /* and go to a known location, last row col 0 */
  315.                    Write_to_screen(simple_continue, 0);
  316.                goto more_input;
  317.  
  318.          case 'm' : /* same as 'f' but with leading prefix added */
  319.  
  320.              case 'f' : /* this can be directly translated into a
  321.                    'readmsg' call with the same params! */
  322.                 NewLine();
  323.                 read_in_messages(edit_fd, (char *) buffer + 1);
  324.                 goto more_input;
  325.  
  326.              case 'p' : /* print out message so far.  Soooo simple! */
  327.                 print_message_so_far(edit_fd, filename);
  328.                 goto more_input;
  329.  
  330.          default  : sprintf(buf,
  331.              "\n\r(Don't know what %c%c is. Try %c? for help.)\n\r",
  332.                     escape_char, buffer[1], escape_char);
  333.                 Write_to_screen(buf, 0);
  334.            }
  335.          }
  336.          else {
  337. tilde_input:
  338.            fprintf(edit_fd, "%s\n", buffer);
  339.            NewLine();
  340.          }
  341.       buffer[0] = '\0';
  342.     }
  343.  
  344.  
  345.     Write_to_screen("\n\r<end-of-message>\n\r\n\r\n\r\n\r", 0);
  346.  
  347.     (void) signal(SIGINT,  oldint);
  348.     (void) signal(SIGQUIT, oldquit);
  349.  
  350.     if (edit_fd != NULL)    /* insurance... */
  351.       fclose(edit_fd);
  352.  
  353.     return(0);
  354. }
  355.  
  356. tilde_help()
  357. {
  358.     /* a simple routine to print out what is available at this level */
  359.  
  360.     char    buf[SLEN];
  361.  
  362.     Write_to_screen("\n\r(Available options at this point are:\n\r\n\r", 0);
  363.     sprintf(buf, "\t%c?\tPrint this help menu.\n\r", escape_char);
  364.     Write_to_screen(buf, 0);
  365.     if (escape_char == TILDE_ESCAPE) /* doesn't make sense otherwise... */
  366.       Write_to_screen(
  367.           "\t~~\tAdd line prefixed by a single '~' character.\n\r", 0);
  368.  
  369.     sprintf(buf,
  370.       "\t%cb\tChange the addresses in the Blind-carbon-copy list.\n\r",
  371.       escape_char);
  372.     Write_to_screen(buf, 0);
  373.  
  374.     sprintf(buf,
  375.         "\t%cc\tChange the addresses in the Carbon-copy list.\n\r",
  376.         escape_char);
  377.     Write_to_screen(buf, 0);
  378.     sprintf(buf,
  379.           "\t%ce\tInvoke the Emacs editor on the message, if possible.\n\r",
  380.         escape_char);
  381.     Write_to_screen(buf, 0);
  382.     sprintf(buf,
  383.         "\t%cf\tAdd the specified message or current.\n\r",
  384.         escape_char);
  385.     Write_to_screen(buf, 0);
  386.     sprintf(buf,
  387.           "\t%ch\tChange all available headers (to, cc, bcc, subject).\n\r",
  388.         escape_char);
  389.     Write_to_screen(buf, 0);
  390.     sprintf(buf,
  391.         "\t%cm\tSame as '%cf', but with the current 'prefix'.\n\r",
  392.         escape_char, escape_char);
  393.     Write_to_screen(buf, 0);
  394.     sprintf(buf,
  395.         "\t%co\tInvoke a user specified editor on the message.\n\r",
  396.         escape_char);
  397.     Write_to_screen(buf, 0);
  398.     sprintf(buf,
  399.           "\t%cp\tPrint out message as typed in so far.\n\r", escape_char);
  400.     Write_to_screen(buf, 0);
  401.     sprintf(buf,
  402.         "\t%cr\tRead in the specified file.\n\r", escape_char);
  403.     Write_to_screen(buf, 0);
  404.     sprintf(buf,
  405.         "\t%cs\tChange the subject of the message.\n\r", escape_char);
  406.     Write_to_screen(buf, 0);
  407.     sprintf(buf,
  408.         "\t%ct\tChange the addresses in the To list.\n\r",
  409.         escape_char);
  410.     Write_to_screen(buf, 0);
  411.     sprintf(buf,
  412.         "\t%cv\tInvoke the Vi visual editor on the message.\n\r",
  413.         escape_char);
  414.     Write_to_screen(buf, 0);
  415.     sprintf(buf,
  416.           "\t%c!\tExecute a unix command (or give a shell if no command).\n\r",
  417.       escape_char);
  418.     Write_to_screen(buf, 0);
  419.     sprintf(buf,
  420.       "\t%c<\tExecute a unix command adding the output to the message.\n\r",
  421.       escape_char);
  422.     Write_to_screen(buf, 0);
  423.     sprintf(buf,
  424.       "\t.  \tby itself on a line (or a control-D) ends the message.\n\r");
  425.     Write_to_screen(buf, 0);
  426.     Write_to_screen("Continue.)\n\r", 0);
  427. }
  428.  
  429. read_in_file(fd, filename, show_user_filename)
  430. FILE *fd;
  431. char *filename;
  432. int   show_user_filename;
  433. {
  434.     /** Open the specified file and stream it in to the already opened 
  435.         file descriptor given to us.  When we're done output the number
  436.         of lines and characters we added, if any... **/
  437.  
  438.     FILE *myfd;
  439.     char myfname[SLEN], buffer[SLEN];
  440.     register int n;
  441.     register int lines = 0, nchars = 0;
  442.  
  443.     for ( n = 0 ; whitespace(filename[n]) ; n++ );
  444.  
  445.     /** expand any shell variables, '~' or other notation... **/
  446.     /* temp copy of filename to buffer since expand_env is destructive */
  447.     strcpy(buffer, &filename[n]);
  448.     expand_env(myfname, buffer);
  449.  
  450.     if (strlen(myfname) == 0) {
  451.       Write_to_screen(
  452.           "\n\r(No filename specified for file read! Continue.)\n\r", 0);
  453.       return;
  454.     }
  455.  
  456.     if ((myfd = fopen(myfname,"r")) == NULL) {
  457.       Write_to_screen("\n\r(Couldn't read file '%s'! Continue.)\n\r", 1,
  458.          myfname);
  459.       return;
  460.     }
  461.  
  462.     while (fgets(buffer, SLEN, myfd) != NULL) {
  463.       n = strlen(buffer);
  464.       if(buffer[n-1] == '\n') lines++;
  465.       nchars += n;
  466.         fputs(buffer, fd);
  467.       fflush(stdout);
  468.     }
  469.  
  470.     fclose(myfd);
  471.  
  472.     if (show_user_filename)
  473.       sprintf(buffer,
  474.         "\n\r(Added %d line%s [%d char%s] from file %s. Continue.)\n\r",
  475.         lines, plural(lines), nchars, plural(nchars), myfname);
  476.     else
  477.       sprintf(buffer,
  478.         "\n\r(Added %d line%s [%d char%s] to message. Continue.)\n\r",
  479.         lines, plural(lines), nchars, plural(nchars));
  480.     Write_to_screen(buffer, 0);
  481.  
  482.     return;
  483. }
  484.  
  485. print_message_so_far(edit_fd, filename)
  486. FILE *edit_fd;
  487. char *filename;
  488. {
  489.     /** This prints out the message typed in so far.  We accomplish
  490.         this in a cheap manner - close the file, reopen it for reading,
  491.         stream it to the screen, then close the file, and reopen it
  492.         for appending.  Simple, but effective!
  493.  
  494.         A nice enhancement would be for this to -> page <- the message
  495.         if it's sufficiently long.  Too much work for now, though.
  496.     **/
  497.     
  498.     char buffer[SLEN];
  499.  
  500.     fclose(edit_fd);
  501.  
  502.     if ((edit_fd = fopen(filename, "r")) == NULL) {
  503.       Write_to_screen("\n\rMayday!  Mayday!  Mayday!\n\r", 0);
  504.       Write_to_screen("\n\rPanic: Can't open file for reading!  Bail!\n\r",
  505.           0);
  506.       emergency_exit();
  507.     }
  508.  
  509.     Write_to_screen("\n\rTo: %s\n\r", 1, format_long(to, 4));
  510.     Write_to_screen("Cc: %s\n\r", 1, format_long(cc, 4));
  511.     Write_to_screen("Bcc: %s\n\r", 1, format_long(bcc, 5));
  512.     Write_to_screen("Subject: %s\n\r\n\r", 1, subject);
  513.  
  514.     while (fgets(buffer, SLEN, edit_fd) != NULL) {
  515.       Write_to_screen(buffer, 0);
  516.       CarriageReturn();
  517.         }
  518.  
  519.     fclose(edit_fd);
  520.  
  521.     if ((edit_fd = fopen(filename, "a")) == NULL) {
  522.       Write_to_screen("Mayday!  Mayday!  Abandon Ship!  Aiiieeeeee\n\r", 0);
  523.       Write_to_screen("\n\rPanic: Can't reopen file for appending!\n\r", 0);
  524.       emergency_exit();
  525.     }
  526.  
  527.     Write_to_screen("\n\r(Continue entering message.)\n\r", 0);
  528. }
  529.  
  530. read_in_messages(fd, buffer)
  531. FILE *fd;
  532. char *buffer;
  533. {
  534.     /** Read the specified messages into the open file.  If the
  535.         first character of "buffer" is 'm' then prefix it, other-
  536.         wise just stream it in straight...Since we're using the
  537.         pipe to 'readmsg' we can also allow the user to specify
  538.         patterns and such too...
  539.     **/
  540.  
  541.     FILE *myfd, *popen();
  542.     char  local_buffer[SLEN], *arg;
  543.     register int add_prefix=0, mindex;
  544.     register int n;
  545.     int lines = 0, nchars = 0;
  546.  
  547.     add_prefix = tolower(buffer[0]) == 'm';
  548.  
  549.     /* strip whitespace to get argument */
  550.     for(arg = &buffer[1]; whitespace(*arg); arg++)
  551.         ;
  552.  
  553.     /* if no argument or begins with a digit, then retrieve the
  554.      * appropriate message from the current folder, else
  555.      * just take the arguments as a pattern for readmsg to match in 
  556.      * the current folder.
  557.      */
  558.     if(isdigit(*arg) || *arg == '\0') {
  559.       if(message_count < 1) {
  560.         Write_to_screen("(No messages to read in! Continue.)\n\r", 0);
  561.         return;
  562.       }
  563.       if((mindex = atoi(arg)) == 0)    /* no argument - read in current msg */
  564.         mindex = current;
  565.       else if(mindex < 1 || mindex > message_count) {
  566.         sprintf(local_buffer,
  567.           "(Valid messsage numbers are between 1 and %d. Continue.)\n\r",
  568.           message_count);
  569.         Write_to_screen(local_buffer, 0);
  570.         return;
  571.       }
  572.  
  573.       sprintf(local_buffer, "%s -f %s %d", readmsg, cur_folder,
  574.           headers[mindex-1]->index_number);
  575.  
  576.     } else
  577.       sprintf(local_buffer, "%s -f %s %s", readmsg, cur_folder, arg);
  578.  
  579.  
  580.     /* now get output of readmsg */
  581.     if ((myfd = popen(local_buffer, "r")) == NULL) {
  582.        Write_to_screen("(Can't find 'readmsg' command! Continue.)\n\r",
  583.            0);
  584.        return;    
  585.     }
  586.  
  587.     dprint(5, (debugfile, "** readmsg call: \"%s\" **\n", local_buffer));
  588.  
  589.     while (fgets(local_buffer, SLEN, myfd) != NULL) {
  590.       n = strlen(local_buffer);
  591.       nchars += n;
  592.       if (local_buffer[n-1] == '\n') lines++;
  593.       if (add_prefix)
  594.         fprintf(fd, "%s%s", prefixchars, local_buffer);
  595.       else 
  596.         fputs(local_buffer, fd);
  597.     }
  598.  
  599.     pclose(myfd);
  600.     
  601.     if (lines == 0)
  602.       sprintf(local_buffer,
  603.           "(Couldn't add the requested message. Continue.)\n\r");
  604.     else
  605.       sprintf(local_buffer,
  606.         "(Added %d line%s [%d char%s] to message. Continue.)\n\r",
  607.         lines, plural(lines), nchars, plural(nchars));
  608.     Write_to_screen(local_buffer, 0);
  609.  
  610.     return;
  611. }
  612.  
  613. get_with_expansion(prompt, buffer, expanded_buffer, sourcebuf)
  614. char *prompt, *buffer, *expanded_buffer, *sourcebuf;
  615. {
  616.     /** This is used to prompt for a new value of the specified field.
  617.         If expanded_buffer == NULL then we won't bother trying to expand
  618.         this puppy out!  (sourcebuf could be an initial addition)
  619.     **/
  620.  
  621.     Write_to_screen(prompt, 0);    fflush(stdout);    /* output! */
  622.  
  623.     if (sourcebuf != NULL) {
  624.       while (!whitespace(*sourcebuf) && *sourcebuf != '\0') 
  625.         sourcebuf++;
  626.       if (*sourcebuf != '\0') {
  627.         while (whitespace(*sourcebuf)) 
  628.           sourcebuf++;
  629.         if (strlen(sourcebuf) > 0) {
  630.           strcat(buffer, " ");
  631.           strcat(buffer, sourcebuf);
  632.         }
  633.       }
  634.     }
  635.  
  636.     optionally_enter(buffer, -1, -1, TRUE, FALSE);    /* already data! */
  637.  
  638.     if(expanded_buffer != NULL) {
  639.       build_address(strip_commas(buffer), expanded_buffer);
  640.       if(*expanded_buffer != '\0') {
  641.         if (*prompt == '\n')
  642.           Write_to_screen("%s%s", 2, prompt, expanded_buffer);
  643.         else
  644.           Write_to_screen("\n\r%s%s", 2, prompt, expanded_buffer);
  645.       }
  646.     }
  647.     NewLine();
  648.  
  649.     return;
  650. }
  651.  
  652. #ifdef VOIDSIG
  653. void
  654. #else
  655. int
  656. #endif
  657. edit_interrupt()
  658. {
  659.     /** This routine is called when the user hits an interrupt key
  660.         while in the builtin editor...it increments the number of 
  661.         times an interrupt is hit and returns it.
  662.     **/
  663.  
  664.     signal(SIGINT, edit_interrupt);
  665.     signal(SIGQUIT, edit_interrupt);
  666.  
  667.     if (interrupts_while_editing++ == 0)
  668.       Write_to_screen("(Interrupt. One more to cancel this letter.)\n\r",
  669.           0);
  670.     else
  671.       Write_to_screen("(Interrupt. Letter cancelled.)\n\r", 0);
  672.  
  673.     longjmp(edit_location, 1);        /* get back */
  674. }
  675.