home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mm / mm-0.90 / edit.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-12-18  |  19.6 KB  |  794 lines

  1. /*
  2.  * Copyright (c) 1986, 1990 by The Trustees of Columbia University in
  3.  * the City of New York.  Permission is granted to any individual or
  4.  * institution to use, copy, or redistribute this software so long as it
  5.  * is not sold for profit, provided this copyright notice is retained.
  6.  */
  7.  
  8. #ifndef lint
  9. static char *rcsid = "$Header: /f/src2/encore.bin/cucca/mm/tarring-it-up/RCS/edit.c,v 2.2 90/10/04 18:24:03 melissa Exp $";
  10. #endif
  11.  
  12. /*
  13.  * edit.c:
  14.  * edit message in mail file, edit outgoing message, ^E action in
  15.  * paragraph parse to edit outgoing message being composed.
  16.  */
  17.  
  18. #include "mm.h"
  19. #include "ccmd.h"
  20. #include "rd.h"
  21. #include "message.h"
  22.  
  23. #define EDIT_HEADERS    0x1
  24. #define EDIT_TEXT    0x2
  25. #define EDIT_MESSAGE    0x4
  26.  
  27. /* prefix for creating temp files */
  28. #ifndef HAVE_FLEXFILENAMES
  29. #define PRE_OUTGOING ".mm-o"
  30. #define PRE_INREPLY  ".mm-i"
  31. #define PRE_HEADERS  ".mm-h"
  32. #define PRE_MESSAGE  ".mm-m"
  33. #define PRE_COMMAND  ".mm-c"
  34. #define PRE_SPELL    ".mm-s"
  35. #else
  36. #define PRE_OUTGOING ".mm-outgoing."
  37. #define PRE_INREPLY  ".mm-in-reply-to."
  38. #define PRE_HEADERS  ".mm-headers."
  39. #define PRE_MESSAGE  ".mm-message."
  40. #define PRE_COMMAND  ".mm-command."
  41. #define PRE_SPELL    ".mm-spell."
  42. #endif
  43.  
  44. /* type of backup file to remove */
  45. #define GEMACS    1
  46. #define SPELL    2
  47.  
  48. #define purge(tf) { if (tf) { unlink(tf); free(tf); tf=NULL; } }
  49.  
  50. char *mktempfile();            /* create a temporary file */
  51. char *write_to_temp();            /* write string to tempfile */
  52. char *read_from_temp();            /* read tempfile into string */
  53.  
  54. static char *msgfile = NULL;        /* msg being replied to's temp  */
  55.                     /* file name */
  56. static char *outfile = NULL;        /* outgoing msg's temp file */
  57. static char *hfile = NULL;        /* header temp file */
  58. static char *cmdfile = NULL;        /* cmd file */
  59.  
  60.  
  61. /*
  62.  * CMD_EDIT:
  63.  */
  64.  
  65. cmd_edit (n)
  66. int n;
  67. {
  68.   if (mode & MM_SEND) {
  69.     edit_outgoing (TRUE);
  70.   }
  71.   else {
  72.     edit_sequence();
  73.   }
  74. }
  75.  
  76. /**********************************************************************/
  77.  
  78. /*
  79.  * EDIT_SEQUENCE:
  80.  */
  81.  
  82. edit_sequence () {
  83.   int do_edit_seqmsg();
  84.  
  85.   if (!check_cf (O_RDWR))        /* pre-check file existence */
  86.     return;
  87.   parse_sequence ("current",NULL,NULL);    /* parse the message sequence */
  88.   if (!check_cf (O_WRONLY))        /* check writable after they CR */
  89.     return;
  90.   if (editor == NULL) {
  91.     fprintf (stderr, "\
  92. Cannot edit.  The editor variable is not set.  Use the SET EDITOR command\n\
  93. to set it first.\n");
  94.     return;
  95.   }
  96.   if (gnuemacs_mmail) {
  97.     if (mmail_path[0] == '\0') {
  98.       fprintf (stderr, "\
  99. Cannot edit.  You are attempting to use gnuemacs mmail mode, but the\n\
  100. mmail-path variable is not set.  Use the SET MMAIL-PATH command to set\n\
  101. it first.\n");
  102.       return;
  103.     }
  104.   }
  105.   sequence_loop (do_edit_seqmsg);    /* run run the edit command over it */
  106. }
  107.  
  108.  
  109. /*
  110.  * DO_EDIT_SEQMSG:
  111.  */
  112.  
  113. do_edit_seqmsg(n) 
  114. int n; 
  115. {
  116.   message *m;
  117.   char *fname, *mktempfile();
  118.   int fd;
  119.   FILE *fp;
  120.   char **editargv;
  121.   char *newtext = NULL;
  122.   keylist free_keylist();
  123.   int count, i;
  124.  
  125.   if (n <= 0)
  126.     return (true);            /* no initializing or ending */
  127.  
  128.   m = &cf->msgs[n];            /* the message we are editting */
  129.  
  130.   if ((fname = write_to_temp (PRE_MESSAGE, FALSE, m->text)) == NULL)
  131.     return;                /* couldn't write to temp file */
  132.  
  133.   for (count = 0; editor[count] != NULL; count++)
  134.     ;
  135.   if (gnuemacs_mmail) {            /* write out command file */
  136.     cmdfile = mktempfile (PRE_COMMAND, TRUE);
  137.     if ((fd = open(cmdfile, O_WRONLY|O_CREAT, 0700)) < 0) {
  138.       fprintf (stderr, "Trouble creating tempfile\n");
  139.       purge(fname);
  140.       purge(cmdfile);
  141.       return;
  142.     }
  143.     else {
  144.       fp = fdopen (fd, "w");
  145.       fprintf (fp, "nil\nnil\nnil\n%s\n", fname);
  146.       fclose (fp);
  147.     }
  148.     
  149.     editargv = (char **) malloc ((count+4)*sizeof (char *));
  150.     for (i = 0; i < count; i++)
  151.       editargv[i] = editor[i];
  152.     editargv[count++] = cmdfile;
  153.     editargv[count++] = "-l";
  154.     editargv[count++] = mmail_path;
  155.     editargv[count++] = 0;
  156.   }
  157.   else {                /* not gnuemacs_mmail */
  158.     editargv = (char **) malloc ((count+2)*sizeof (char *));
  159.     for (i = 0; i < count; i++)
  160.       editargv[i] = editor[i];
  161.     editargv[count++] = fname;
  162.     editargv[count++] = 0;
  163.   }
  164.  
  165.   if (mm_execute (editor[0], editargv) != 0) {
  166.     fprintf (stderr, "Edit failed\n");
  167.     purge(fname);
  168.     purge (cmdfile);
  169.     free (editargv);
  170.     return;
  171.   }
  172.   purge(cmdfile);
  173.   free (editargv);
  174.  
  175.   if ((newtext = read_from_temp(fname)) == NULL) {
  176.     purge(fname);
  177.     return;
  178.   }
  179.   if (gnuemacs_mmail)
  180.       maybe_remove_backups (fname, GEMACS);
  181.   purge(fname);
  182.   free (m->text);
  183.   m->text = newtext;
  184.   m->keywords = free_keylist(m->keywords);
  185.   get_incoming_keywords(cf, m);
  186.   m->size = strlen(m->text);        /* update the message length */
  187.   if (m->hdrsum) {
  188.     free (m->hdrsum);
  189.     m->hdrsum = NULL;            /* cached header may be wrong */
  190.   }
  191.   m->flags |= M_EDITED|M_SEEN;        /* message has been edited */
  192.   (*msg_ops[cf->type].wr_msg) (cf, m, n, 0); /* write it out (mark as dirty) */
  193. }
  194.  
  195.  
  196. /**********************************************************************/
  197.  
  198. /*
  199.  * EDIT_OUTGOING:
  200.  */
  201.  
  202. edit_outgoing (p) int p; {
  203.   static keywrd editkeys[] = {
  204.     { "all",    0,    (keyval) EDIT_HEADERS|EDIT_TEXT|EDIT_MESSAGE },
  205.     { "headers",0,    (keyval) EDIT_HEADERS },
  206.     { "text",    0,    (keyval) EDIT_TEXT },
  207.   };
  208.   static keytab edittab = { (sizeof(editkeys)/sizeof(keywrd)), editkeys };
  209.   static fdb editfdb = { _CMKEY, 0, NULL, (pdat)&edittab, NULL, "all", NULL };
  210.   pval parseval;
  211.   fdb used;
  212.   int what;
  213.  
  214.   if (p) {                /* should we parse? */
  215.     parse (&editfdb, &parseval, &used);
  216.     confirm();
  217.     what = parseval._pvint;
  218.   }
  219.   else {
  220.     what = EDIT_HEADERS|EDIT_TEXT|EDIT_MESSAGE;
  221.   }
  222.  
  223.   if (editor == NULL) {
  224.     fprintf (stderr, "\
  225. Cannot edit.  The editor variable is not set.  Use the SET EDITOR command\n\
  226. to set it first.\n");
  227.     return;
  228.   }
  229.  
  230.   if (gnuemacs_mmail) {
  231.     if (mmail_path[0] == '\0') {
  232.       fprintf (stderr, "\
  233. Cannot edit.  You are attempting to use gnuemacs mmail mode, but the\n\
  234. mmail-path variable is not set.  Use the SET MMAIL-PATH command to set\n\
  235. it first.\n");
  236.       return;
  237.     }
  238.     gnuemacs_edit_outgoing (what);
  239.     return;
  240.   }
  241.   else
  242.     other_edit_outgoing (what);
  243. }
  244.  
  245.  
  246. /*
  247.  * GNUEMACS_EDIT_OUTGOING:
  248.  */
  249.  
  250. gnuemacs_edit_outgoing (what) int what; {
  251.   mail_msg *outmsg, *get_outgoing();
  252.   headers *h;
  253.   int fd;
  254.   FILE *fp;
  255.   char **editargv;
  256.   char *newoutmsg = NULL;        /* new outgoing msg */
  257.   char *newheaders = NULL;        /* new headers from temp file */
  258.   message tmessage;
  259.   mail_msg *new_mail_msg = NULL, *parse_msg();
  260.   int count, i;
  261.  
  262.   outmsg = get_outgoing();
  263.  
  264.  
  265.   /* always write out the headers */
  266.   h = outmsg->headers;
  267.   hfile = mktempfile (PRE_HEADERS, FALSE);
  268.   if ((fd = open(hfile, O_WRONLY|O_CREAT, 0700)) < 0) { /* open temp file */
  269.     fprintf (stderr, "Trouble creating tempfile\n");
  270.     clear_edit_tempfiles();
  271.     return;
  272.   }
  273.   fp = fdopen (fd, "w");        /* get a FILE * for it */
  274.   display_header (fp, outmsg, TRUE, FALSE); /* expand, not in sendmail mode */
  275.   fclose (fp);
  276.  
  277.   if (what & EDIT_TEXT) {        /* write out outgoing message text */
  278.     if ((outfile = write_to_temp (PRE_OUTGOING, FALSE, outmsg->body))
  279.     == NULL) {
  280.       clear_edit_tempfiles();
  281.       return;
  282.     }
  283.   }
  284.  
  285.   if ((mode&MM_ANSWER) && (what&EDIT_MESSAGE)) { /* we are replying to a msg */
  286.     if ((msgfile = write_to_temp (PRE_INREPLY, FALSE,
  287.                   cf->msgs[cf->current].text)) == NULL) {
  288.       clear_edit_tempfiles();
  289.       return;
  290.     }
  291.   }
  292.  
  293.   /* write out command file for gnuemacs mode */
  294.   cmdfile = mktempfile (PRE_COMMAND, TRUE);
  295.   if ((fd = open(cmdfile, O_WRONLY|O_CREAT, 0700)) < 0) { /* open temp file */
  296.     fprintf (stderr, "Trouble creating tempfile\n");
  297.     clear_edit_tempfiles();
  298.     return;
  299.   }
  300.   else {
  301.     fp = fdopen (fd, "w");
  302.     fprintf (fp, "%s\n", (what & EDIT_TEXT) ? outfile : "nil");
  303.     fprintf (fp, "%s\n", 
  304.          ((mode&MM_ANSWER)&&(what&EDIT_MESSAGE)) ? msgfile : "nil");    
  305.     fprintf (fp, "%s\n", (what & EDIT_HEADERS) ? hfile : "nil");
  306.     fprintf (fp, "nil\n");
  307.     fclose (fp);
  308.   }
  309.  
  310.   for (count = 0; editor[count] != NULL; count++)
  311.     ;
  312.   editargv = (char **) malloc ((count+4)*sizeof(char *));
  313.   for (i = 0; i < count; i++)
  314.     editargv[i] = editor[i];
  315.   editargv[count++] = cmdfile;
  316.   editargv[count++] = "-l";
  317.   editargv[count++] = mmail_path;
  318.   editargv[count++] = 0;
  319.  
  320.   if (mm_execute (editor[0], editargv) != 0) {
  321.     fprintf (stderr, "Edit failed\n");
  322.     clear_edit_tempfiles();
  323.     free (editargv);
  324.     return;
  325.   }
  326.   free (editargv);
  327.  
  328.   if (outfile) {
  329.     if ((newoutmsg = read_from_temp (outfile)) == NULL) {
  330.       clear_edit_tempfiles();
  331.       return;
  332.     }
  333.   }
  334.  
  335.   if ((newheaders = read_from_temp (hfile)) == NULL) {
  336.     clear_edit_tempfiles();
  337.     return;
  338.   }
  339.  
  340.   tmessage.text = newheaders;        /* copy into temp message struct */
  341.   tmessage.size = strlen(newheaders);    /* in order to call parse_msg */
  342.   new_mail_msg = parse_msg (&tmessage);    /* parse the msg (header) */
  343.   if (new_mail_msg->to)
  344.       files_to_fcc(new_mail_msg->to->address, new_mail_msg);
  345.   if (new_mail_msg->cc)
  346.       files_to_fcc(new_mail_msg->cc->address, new_mail_msg);
  347.   if (new_mail_msg->bcc)
  348.       files_to_fcc(new_mail_msg->bcc->address, new_mail_msg);
  349.   free (newheaders);
  350.  
  351.   if (newoutmsg)
  352.     new_mail_msg->body = newoutmsg;
  353.   else {
  354.     new_mail_msg->body = (char *) malloc (strlen(outmsg->body)+1);
  355.     strcpy (new_mail_msg->body, outmsg->body);
  356.   }
  357.   
  358.   free_msg(outmsg);            /* to prevent mem leak */
  359.   set_outgoing (new_mail_msg);
  360.   if (hfile)
  361.       maybe_remove_backups (hfile, GEMACS);
  362.   if (outfile)
  363.       maybe_remove_backups (outfile, GEMACS);
  364.   if (msgfile)
  365.       maybe_remove_backups (msgfile, GEMACS);
  366.   clear_edit_tempfiles();
  367. }
  368.  
  369.  
  370.  
  371. /*
  372.  * CLEAR_EDIT_TEMPFILES:
  373.  * clean up when edit_outgoing fails for some reason.
  374.  */
  375.  
  376.  
  377. clear_edit_tempfiles() {
  378.   purge(hfile);                /* header file */
  379.   purge(outfile);            /* outgoing message file */;
  380.   purge(msgfile);            /* and/or message file */
  381.   purge(cmdfile);            /* gnuemacs cmd file */
  382. }
  383.  
  384.  
  385.  
  386. /*
  387.  * OTHER_EDIT_OUTGOING:
  388.  */
  389.  
  390. other_edit_outgoing (what) int what; {
  391.   char *tfile = NULL, *hfile = NULL;
  392.   mail_msg *outmsg, *get_outgoing();
  393.   char *newmsg, *headerstring;
  394.   char **editargv;
  395.   int fd;
  396.   FILE *fp;
  397.   headers *h;
  398.   message tmessage;
  399.   mail_msg *new_mail_msg = NULL, *parse_msg();
  400.   int count, i;
  401.  
  402.   outmsg = get_outgoing();
  403.  
  404.   if (!(what & EDIT_HEADERS)) {        /* have to save headers */
  405.     h = outmsg->headers;
  406.     hfile = mktempfile (PRE_HEADERS, FALSE);
  407.     if ((fd = open(hfile, O_WRONLY|O_CREAT, 0700)) < 0) { /* open temp file */
  408.       fprintf (stderr, "Trouble creating tempfile\n");
  409.       purge(hfile);
  410.       return;
  411.     }
  412.     else {
  413.       fp = fdopen (fd, "w");        /* get a FILE * for it */
  414.       display_header (fp, outmsg, TRUE, FALSE); /* not in sendmail mode */
  415.       fclose (fp);
  416.     }
  417.   }
  418.  
  419.   tfile = mktempfile (PRE_OUTGOING, FALSE);
  420.   if ((fd = open(tfile, O_WRONLY|O_CREAT, 0700)) < 0) { /* open temp file */
  421.     fprintf (stderr, "Trouble creating tempfile\n");
  422.     purge(hfile);
  423.     purge(tfile);
  424.     return;
  425.   }
  426.   else {
  427.     fp = fdopen (fd, "w");        /* get a FILE * for it */
  428.     if (what & EDIT_HEADERS) {
  429.       display_header (fp, outmsg, TRUE, FALSE); /* not in sendmail mode */
  430.       if (what & EDIT_TEXT)        /* both HEADERS and TEXT */
  431.     fputc ('\n', fp);        /* then separate them */
  432.     }
  433.     if (what & EDIT_TEXT)
  434.       display_text (fp, outmsg);
  435.     fclose (fp);
  436.   }
  437.  
  438.   for (count = 0; editor[count] != NULL; count++)
  439.     ;
  440.   editargv = (char **) malloc ((count+2)*sizeof (char *));
  441.   for (i = 0; i < count; i++)
  442.     editargv[i] = editor[i];
  443.   editargv[count++] = tfile;
  444.   editargv[count++] = 0;
  445.  
  446.   if (mm_execute (editor[0], editargv) != 0) {
  447.     fprintf (stderr, "Edit failed\n");
  448.     purge(hfile);
  449.     purge(tfile);
  450.     free (editargv);
  451.     return;
  452.   }
  453.   free (editargv);
  454.  
  455.   if ((newmsg = read_from_temp (tfile)) == NULL) {
  456.     purge(hfile);
  457.     purge(tfile);
  458.     return;
  459.   }
  460.  
  461.   if (hfile) {
  462.     if ((headerstring = read_from_temp (hfile)) == NULL) {
  463.       fprintf (stderr, "Error reading tempfile\n");
  464.       purge(hfile);
  465.       purge(tfile);
  466.       return;
  467.     }
  468.     tmessage.size = strlen(headerstring)+strlen(newmsg);
  469.     tmessage.text = (char *) malloc (tmessage.size+2);
  470.     sprintf (tmessage.text, "%s\n%s", headerstring, newmsg);
  471.     free (headerstring);
  472.   }
  473.   else {
  474.     tmessage.size = strlen(newmsg);
  475.     tmessage.text = (char *) malloc (tmessage.size+1);
  476.     strcpy (tmessage.text, newmsg);
  477.   }
  478.   free (newmsg);
  479.   new_mail_msg = parse_msg (&tmessage); /* parse the msg */
  480.   free (tmessage.text);
  481.   if (!(what & EDIT_TEXT)) {
  482.     new_mail_msg->body = (char *) malloc (strlen(outmsg->body)+1);
  483.     strcpy (new_mail_msg->body, outmsg->body);
  484.   }
  485.   
  486.   free_msg(outmsg);            /* to prevent mem leak */
  487.   set_outgoing (new_mail_msg);
  488.  
  489.   purge(hfile);
  490.   purge(tfile);
  491. }
  492.  
  493.  
  494. /**********************************************************************/
  495.  
  496. cmd_save_draft (n)
  497. int n;
  498. {
  499.   char *ofile, *parse_output_file();
  500.   mail_msg *m, *get_outgoing();
  501.   FILE *fp;
  502.  
  503.   noise ("in file");
  504.   ofile = parse_output_file ("file name", NULL, false);
  505.   confirm();
  506.   if (access(ofile, F_OK) == 0) {    /* output file exists */
  507.     cmxprintf ("%s exists, ", ofile);
  508.     if (!yesno("overwrite? ", "no"))    /* shall we overwrite? */
  509.       return;
  510.   }
  511.   m = get_outgoing();
  512.   if ((fp = fopen (ofile, "w")) == NULL) {
  513.     cmpemsg ("Trouble creating output file, draft not saved",CM_SDE);
  514.     return;
  515.   }
  516.   display_header (fp, m, TRUE, FALSE);
  517.   fputc ('\n', fp);
  518.   display_text (fp, m);
  519.   fclose (fp);
  520.   free (ofile);
  521.   printf ("Draft saved in %s\n", ofile);
  522. }
  523.  
  524.  
  525. cmd_restore_draft (n)
  526. int n;
  527. {
  528.   char *text;                /* whole the message text */
  529.   char *fname;                /* file name to read */
  530.   char *parse_input_file();
  531.   mail_msg *msg, *get_outgoing();    /* the parsed message. */
  532.   message tmessage;
  533.     
  534.   noise ("from file");
  535.   fname = parse_input_file( nil, nil, false); /* get the filename */
  536.   confirm();
  537.   if ((text = read_from_temp(fname)) == NULL) { /* read the file */
  538.     free(fname);            /* failure, clean up */
  539.     return;
  540.   }
  541.   free(fname);
  542.   tmessage.text = text;
  543.   tmessage.size = strlen(text);
  544.   msg = parse_msg(&tmessage);        /* parse the message. */
  545.   free(text);                /* throw away the buffer */
  546.   set_outgoing(msg);            /* copy in */
  547.   send_mode(get_outgoing());
  548. }
  549.  
  550.  
  551. /**********************************************************************/
  552.  
  553. /*
  554.  * MKTEMPFILE:
  555.  * create a temp file using the passed prefix and tacking on this
  556.  * process's pid.
  557.  * NOTE: It is assumed that the string representation of a process pid 
  558.  * is at most 9 characters long.
  559.  */
  560.  
  561. char *
  562. mktempfile (pref, usetmp) char *pref; int usetmp; {
  563.   char *name;
  564.   char *dir, *get_default_temp_dir();
  565.  
  566.   if (usetmp)
  567.     dir = TMPDIR;
  568.   else
  569.     dir = (temp_directory[0] != '\0') ? temp_directory 
  570.                                       : get_default_temp_dir();
  571.   name = (char *) malloc (strlen(dir) + 1 + strlen(pref)+10);
  572.   sprintf (name, "%s/%s%d", dir, pref, PID);
  573.   return (name);
  574. }
  575.  
  576.  
  577. /*
  578.  * WRITE_TO_TEMP:
  579.  * open a temp file, place string in file, close temp file, and return
  580.  * the name of the tempfile.
  581.  * Returns the temp filename upon success, NULL otherwise.
  582.  * Note: the filename should be free'd by the caller when done.
  583.  */
  584.  
  585. char *
  586. write_to_temp(pref, usetmp, str) 
  587. char *pref;
  588. int usetmp;
  589. char *str; 
  590. {
  591.   char *fname;                /* place to create file name */
  592.   int fd;
  593.   int len; 
  594.  
  595.   fname = mktempfile(pref, usetmp);    /* create a temp file */
  596.   if ((fd = open(fname, O_WRONLY|O_CREAT, 0700)) < 0) { /* open temp file */
  597.     fprintf (stderr, "Trouble creating tempfile\n");
  598.     free (fname);
  599.     fname = NULL;
  600.     return (NULL);
  601.   }
  602.   if (str != NULL) {
  603.       len = strlen(str);
  604.       if (write(fd, str, len) != len) {
  605.       fprintf (stderr, "Trouble writing to tempfile\n");
  606.       close (fd);
  607.       purge(fname);
  608.       return (NULL);
  609.       }
  610.   }
  611.   close (fd);
  612.   return (fname);
  613. }
  614.  
  615.  
  616. /*
  617.  * READ_FROM_TEMP:
  618.  * read temp file into string.  
  619.  * Returns pointer to string on success and NULL on failure.
  620.  * Note: Caller should free the returned string.
  621.  */
  622.  
  623. char *
  624. read_from_temp (fname) char *fname; {
  625.   struct stat sbuf;
  626.   int fd;
  627.   char *newtext;
  628.  
  629.   if (stat(fname, &sbuf) == -1) {    /* get file length */
  630.     fprintf (stderr, "Temporary file disappeared\n");
  631.     return (NULL);
  632.   }
  633.   if ((fd = open(fname, O_RDONLY,0)) < 0) { /* open file for read */
  634.     fprintf (stderr, "Could not open temporary file\n");
  635.     return (NULL);
  636.   }
  637.   newtext = (char *) malloc (sbuf.st_size+2);
  638.   if (read(fd, newtext, sbuf.st_size) != sbuf.st_size) {
  639.     fprintf (stderr, "Could not read temporary file\n");
  640.     close (fd);
  641.     free (newtext);
  642.     return (NULL);
  643.   }
  644.   close (fd);
  645.   if (sbuf.st_size > 1) 
  646.       if (newtext[sbuf.st_size-1] != '\n')
  647.       newtext[sbuf.st_size++] = '\n';
  648.   newtext[sbuf.st_size] = '\0';        /* null terminate the text */
  649.   return (newtext);
  650. }
  651.  
  652.  
  653. char *spell_text();
  654. cmd_spell(n)
  655. {
  656.     char *ntext, *otext;
  657.     mail_msg *m;
  658.  
  659.     if (mode & MM_SEND) {
  660.     confirm();
  661.     m = get_outgoing();
  662.     otext = m->body;
  663.     ntext = spell_text(otext);
  664.     free(otext);
  665.     m->body = ntext;
  666.     }
  667.     else {
  668.     int spell_seq();
  669.     if (!check_cf(O_RDWR))        /* pre-check we have a file */
  670.         return;
  671.     parse_sequence ("current",NULL,NULL); /* parse the message sequence */
  672.     if (!check_cf(O_WRONLY))    /* make sure we can write it */
  673.         return;
  674.     sequence_loop (spell_seq);    /* run the spell command over it */
  675.     }
  676. }
  677.  
  678.  
  679. spell_seq(n)
  680. int n;
  681. {
  682.     char *otext, *ntext;
  683.     message *m = &cf->msgs[n];
  684.     if (n <= 0)
  685.     return (true);            /* no initializing or ending */
  686.  
  687.     otext = m->text;
  688.     ntext = spell_text(otext);
  689.     free(otext);
  690.     m->text = ntext;
  691.     m->keywords = free_keylist(m->keywords);
  692.     get_incoming_keywords(cf, m);
  693.     m->size = strlen(m->text);        /* update the message length */
  694.     if (m->hdrsum) {
  695.     free (m->hdrsum);
  696.     m->hdrsum = NULL;        /* cached header may be wrong */
  697.     }
  698.     (*msg_ops[cf->type].wr_msg) (cf, m, n, 0);/* write out (mark as dirty) */
  699. }
  700.  
  701. char *
  702. spell_text(txt)
  703. char *txt;
  704. {
  705.     char *fname;
  706.     char *ntxt;
  707.     char **spellargv;
  708.     int count, i;
  709.  
  710.     if (speller == NULL) {
  711.         fprintf (stderr, "\
  712. Cannot run speller.  The speller variable is not set.  Use the SET SPELLER\n\
  713. command to set it first.\n");
  714.     return (txt);
  715.     }
  716.  
  717.     if ((fname = write_to_temp (PRE_SPELL, FALSE, txt)) == NULL) {
  718.     fprintf(stderr,"Could not write spell file: %s\n", fname);
  719.     return(txt);            /* couldn't write to temp file */
  720.     }    
  721.     
  722.     for (count = 0; speller[count] != NULL; count++)
  723.     ;
  724.     spellargv = (char **) malloc ((count+2)*sizeof(char *));
  725.     for (i = 0; i < count; i++)
  726.     spellargv[i] = speller[i];
  727.     spellargv[count++] = fname;
  728.     spellargv[count++] = 0;
  729.  
  730.     if (mm_execute (speller[0], spellargv) != 0) {
  731.         fprintf (stderr, "Could not run speller\n");
  732.     purge(fname);
  733.     free (spellargv);
  734.     return(txt);
  735.     }
  736.     free (spellargv);
  737.  
  738.     ntxt = read_from_temp(fname);
  739.     if (ntxt == nil) {
  740.     fprintf(stderr,"Could not read spell file: %s\n", fname);
  741.     purge(fname);
  742.     return(txt);
  743.     }
  744.     maybe_remove_backups (fname, SPELL);
  745.     purge(fname);
  746.     return(ntxt);
  747. }
  748.  
  749.  
  750. /*
  751.  * maybe_remove_backups:
  752.  * remove backup files created by editor, speller, etc.
  753.  * name is the name of the file whose backups we are going to remove.
  754.  * type is one of the following: GEMACS or SPELL.
  755.  */
  756.  
  757. maybe_remove_backups (name, type)
  758. char *name;
  759. int type;
  760. {
  761.     static fdb backfilfdb = { _CMFIL, FIL_OLD|FIL_WLD, 
  762.                   NULL, NULL, NULL, NULL, NULL };
  763.     static fdb tfdb = { _CMTXT, 0, NULL, NULL, NULL, NULL, NULL };
  764.     pval p;
  765.     fdb *u;
  766.     char *template;
  767.     int plen;
  768.     int i;
  769.  
  770.     /* XXX check a variable controlling removal of backups? */
  771.  
  772.     template = (char *) malloc (strlen(name)+10); /* sufficient space */
  773.     switch (type) {
  774.     case GEMACS:
  775.     strcpy (template, name);
  776.     strcat (template, "*~");
  777.     break;
  778.     case SPELL:
  779.     strcpy (template, name);
  780.     strcat (template, ".bak");
  781.     break;
  782.     default:
  783.     return;
  784.     }
  785.     match (template, strlen(template), fdbchn(&backfilfdb,&tfdb,NULL), 
  786.        &p, &u, &plen);
  787.     free (template);
  788.     if (u == &tfdb)            /* did not get filenames */
  789.     return;
  790.     for (i = 0; p._pvfil[i] != NULL; i++)
  791.     unlink(p._pvfil[i]);
  792. }
  793.  
  794.