]> diplodocus.org Git - nmh/blobdiff - uip/comp.c
lock_file.c: close(2) file descriptor on failure, avoiding leak.
[nmh] / uip / comp.c
index 5ebce6ed0e0855957311933e206f8691bad68491..744ea19beb7c05c711cd719f640cad82a19da840 100644 (file)
@@ -1,6 +1,4 @@
-
-/*
- * comp.c -- compose a message
+/* comp.c -- compose a message
  *
  * This code is Copyright (c) 2002, by the authors of nmh.  See the
  * COPYRIGHT file in the root directory of the nmh distribution for
@@ -9,83 +7,82 @@
 
 #include <h/mh.h>
 #include <h/utils.h>
+#include <h/fmt_scan.h>
+#include "sbr/m_maildir.h"
 #include <fcntl.h>
 
-static struct swit switches[] = {
-#define        DFOLDSW                0
-    { "draftfolder +folder", 0 },
-#define        DMSGSW                 1
-    { "draftmessage msg", 0 },
-#define        NDFLDSW                2
-    { "nodraftfolder", 0 },
-#define        EDITRSW                3
-    { "editor editor", 0 },
-#define        NEDITSW                4
-    { "noedit", 0 },
-#define        FILESW                 5
-    { "file file", 0 },
-#define        FORMSW                 6
-    { "form formfile", 0 },
-#define        USESW                  7
-    { "use", 0 },
-#define        NUSESW                 8
-    { "nouse", 0 },
-#define        WHATSW                 9
-    { "whatnowproc program", 0 },
-#define        NWHATSW               10
-    { "nowhatnowproc", 0 },
-#define VERSIONSW             11
-    { "version", 0 },
-#define        HELPSW                12
-    { "help", 0 },
-    { NULL, 0 }
-};
-
-static struct swit aqrunl[] = {
-#define        NOSW          0
-    { "quit", 0 },
-#define        YESW          1
-    { "replace", 0 },
-#define        USELSW        2
-    { "use", 0 },
-#define        LISTDSW       3
-    { "list", 0 },
-#define        REFILSW       4
-    { "refile +folder", 0 },
-#define NEWSW         5
-    { "new", 0 },
-    { NULL, 0 }
-};
+#define COMP_SWITCHES \
+    X("draftfolder +folder", 0, DFOLDSW) \
+    X("draftmessage msg", 0, DMSGSW) \
+    X("nodraftfolder", 0, NDFLDSW) \
+    X("editor editor", 0, EDITRSW) \
+    X("noedit", 0, NEDITSW) \
+    X("file file", 0, FILESW) \
+    X("form formfile", 0, FORMSW) \
+    X("use", 0, USESW) \
+    X("nouse", 0, NUSESW) \
+    X("whatnowproc program", 0, WHATSW) \
+    X("nowhatnowproc", 0, NWHATSW) \
+    X("build", 5, BILDSW) \
+    X("version", 0, VERSIONSW) \
+    X("help", 0, HELPSW) \
+    X("to address", 0, TOSW) \
+    X("cc address", 0, CCSW) \
+    X("from address", 0, FROMSW) \
+    X("fcc mailbox", 0, FCCSW) \
+    X("width columns", 0, WIDTHSW) \
+    X("subject text", 0, SUBJECTSW) \
+
+#define X(sw, minchars, id) id,
+DEFINE_SWITCH_ENUM(COMP);
+#undef X
+
+#define X(sw, minchars, id) { sw, minchars, id },
+DEFINE_SWITCH_ARRAY(COMP, switches);
+#undef X
+
+#define DISPO_SWITCHES \
+    X("quit", 0, NOSW) \
+    X("replace", 0, YESW) \
+    X("use", 0, USELSW) \
+    X("list", 0, LISTDSW) \
+    X("refile +folder", 0, REFILSW) \
+    X("new", 0, NEWSW) \
+
+#define X(sw, minchars, id) id,
+DEFINE_SWITCH_ENUM(DISPO);
+#undef X
+
+#define X(sw, minchars, id) { sw, minchars, id },
+DEFINE_SWITCH_ARRAY(DISPO, aqrunl);
+#undef X
 
 static struct swit aqrul[] = {
-    { "quit", 0 },
-    { "replace", 0 },
-    { "use", 0 },
-    { "list", 0 },
-    { "refile", 0 },
-    { NULL, 0 }
+    { "quit", 0, NOSW },
+    { "replace", 0, YESW },
+    { "use", 0, USELSW },
+    { "list", 0, LISTDSW },
+    { "refile", 0, REFILSW },
+    { NULL, 0, 0 }
 };
 
-
 int
 main (int argc, char **argv)
 {
-    int use = NOUSE, nedit = 0, nwhat = 0;
-    int i, in, isdf = 0, out;
+    int use = NOUSE, nedit = 0, nwhat = 0, build = 0;
+    int i, in = NOTOK, isdf = 0, out, dat[5], format_len = 0;
+    int outputlinelen = OUTPUTLINELEN;
     char *cp, *cwd, *maildir, *dfolder = NULL;
     char *ed = NULL, *file = NULL, *form = NULL;
     char *folder = NULL, *msg = NULL, buf[BUFSIZ];
+    char *to = NULL, *from = NULL, *cc = NULL, *fcc = NULL, *dp;
+    char *subject = NULL;
     char drft[BUFSIZ], **argp, **arguments;
     struct msgs *mp = NULL;
+    struct format *fmt;
     struct stat st;
 
-#ifdef LOCALE
-    setlocale(LC_ALL, "");
-#endif
-    invo_name = r1bindex (argv[0], '/');
-
-    /* read user profile/context */
-    context_read();
+    if (nmh_init(argv[0], 1)) { return 1; }
 
     arguments = getarguments (invo_name, argc, argv, 1);
     argp = arguments;
@@ -103,10 +100,10 @@ main (int argc, char **argv)
                    snprintf (buf, sizeof(buf), "%s [+folder] [msg] [switches]",
                        invo_name);
                    print_help (buf, switches, 1);
-                   done (1);
+                   done (0);
                case VERSIONSW:
                    print_version(invo_name);
-                   done (1);
+                   done (0);
 
                case EDITRSW: 
                    if (!(ed = *argp++) || *ed == '-')
@@ -122,6 +119,10 @@ main (int argc, char **argv)
                        adios (NULL, "missing argument to %s", argp[-2]);
                    nwhat = 0;
                    continue;
+
+               case BILDSW:
+                   build++;
+                   /* FALLTHRU */
                case NWHATSW: 
                    nwhat++;
                    continue;
@@ -164,22 +165,61 @@ main (int argc, char **argv)
                    dfolder = NULL;
                    isdf = NOTOK;
                    continue;
+
+               case TOSW:
+                   if (!(cp = *argp++) || *cp == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+                   to = addlist(to, cp);
+                   continue;
+
+               case CCSW:
+                   if (!(cp = *argp++) || *cp == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+                   cc = addlist(cc, cp);
+                   continue;
+
+               case FROMSW:
+                   if (!(cp = *argp++) || *cp == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+                   from = addlist(from, cp);
+                   continue;
+
+               case FCCSW:
+                   if (!(cp = *argp++) || *cp == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+                   dp = NULL;
+                   if (*cp == '@')
+                       cp = dp = path(cp + 1, TSUBCWF);
+                   fcc = addlist(fcc, cp);
+                    free(dp);
+                   continue;
+
+               case WIDTHSW:
+                   if (!(cp = *argp++) || *cp == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+                   if ((outputlinelen = atoi(cp)) < 10)
+                       adios (NULL, "impossible width %d", outputlinelen);
+                   continue;
+
+               case SUBJECTSW:
+                   if (!(cp = *argp++) || *cp == '-')
+                       adios (NULL, "missing argument to %s", argp[-2]);
+                   subject = cp;
+                   continue;
            }
        }
        if (*cp == '+' || *cp == '@') {
            if (folder)
                adios (NULL, "only one folder at a time!");
-           else
-               folder = pluspath (cp);
+            folder = pluspath (cp);
        } else {
            if (msg)
                adios (NULL, "only one message at a time!");
-           else
-               msg = cp;
+            msg = cp;
        }
     }
 
-    cwd = getcpy (pwd ());
+    cwd = mh_xstrdup(pwd ());
 
     if (!context_find ("path"))
        free (path ("./", TFOLDER));
@@ -195,6 +235,8 @@ main (int argc, char **argv)
     if (form && (folder || msg))
            adios (NULL, "can't mix forms and folders/msgs");
 
+    cp = NULL;
+
     if (folder || msg) {
        /*
         * Use a message as the "form" for the new message.
@@ -209,7 +251,7 @@ main (int argc, char **argv)
            adios (maildir, "unable to change directory to");
 
        /* read folder and create message structure */
-       if (!(mp = folder_read (folder)))
+       if (!(mp = folder_read (folder, 1)))
            adios (NULL, "unable to read folder %s", folder);
 
        /* check for empty folder */
@@ -220,22 +262,62 @@ main (int argc, char **argv)
        if (!m_convert (mp, msg))
            done (1);
        seq_setprev (mp);       /* set the previous-sequence */
+       seq_save (mp);
 
        if (mp->numsel > 1)
            adios (NULL, "only one message at a time!");
 
-       if ((in = open (form = getcpy (m_name (mp->lowsel)), O_RDONLY)) == NOTOK)
+       if ((in = open (form = mh_xstrdup(m_name (mp->lowsel)), O_RDONLY)) == NOTOK)
            adios (form, "unable to open message");
-    } else
-       in = open_form(&form, components);
+    } else {
+       struct comp *cptr;
+
+       if (! form)
+           form = components;
+
+        cp = new_fs(form, NULL, NULL);
+       format_len = strlen(cp);
+       fmt_compile(cp, &fmt, 1);
+
+       /*
+        * Set up any components that were fed to us on the command line
+        */
+
+       if (from) {
+           cptr = fmt_findcomp("from");
+           if (cptr)
+               cptr->c_text = from;
+       }
+       if (to) {
+           cptr = fmt_findcomp("to");
+           if (cptr)
+               cptr->c_text = to;
+       }
+       if (cc) {
+           cptr = fmt_findcomp("cc");
+           if (cptr)
+               cptr->c_text = cc;
+       }
+       if (fcc) {
+           cptr = fmt_findcomp("fcc");
+           if (cptr)
+               cptr->c_text = fcc;
+       }
+       if (subject) {
+           cptr = fmt_findcomp("subject");
+           if (cptr)
+               cptr->c_text = subject;
+       }
+    }
 
 try_it_again:
-    strncpy (drft, m_draft (dfolder, file, use, &isdf), sizeof(drft));
+    strncpy (drft, build ? m_maildir ("draft")
+                       : m_draft (dfolder, file, use, &isdf), sizeof(drft));
 
     /*
      * Check if we have an existing draft
      */
-    if ((out = open (drft, O_RDONLY)) != NOTOK) {
+    if (!build && (out = open (drft, O_RDONLY)) != NOTOK) {
        i = fdcompare (in, out);
        close (out);
 
@@ -251,7 +333,8 @@ try_it_again:
            adios (drft, "unable to stat");
        printf ("Draft \"%s\" exists (%ld bytes).", drft, (long) st.st_size);
        for (i = LISTDSW; i != YESW;) {
-           if (!(argp = getans ("\nDisposition? ", isdf ? aqrunl : aqrul)))
+           if (!(argp = read_switch_multiword ("\nDisposition? ",
+                                               isdf ? aqrunl : aqrul)))
                done (1);
            switch (i = smatch (*argp, isdf ? aqrunl : aqrul)) {
                case NOSW: 
@@ -273,7 +356,7 @@ try_it_again:
                        i = YESW;
                    break;
                default: 
-                   advise (NULL, "say what?");
+                   inform("say what?");
                    break;
            }
        }
@@ -284,8 +367,26 @@ try_it_again:
 
     if ((out = creat (drft, m_gmprot ())) == NOTOK)
        adios (drft, "unable to create");
-    cpydata (in, out, form, drft);
-    close (in);
+    if (cp) {
+       charstring_t scanl;
+
+       i = format_len + 1024;
+       scanl = charstring_create (i + 2);
+       dat[0] = 0;
+       dat[1] = 0;
+       dat[2] = 0;
+       dat[3] = outputlinelen;
+       dat[4] = 0;
+       fmt_scan(fmt, scanl, i, dat, NULL);
+       if (write(out, charstring_buffer (scanl),
+                 charstring_bytes (scanl)) < 0) {
+           advise (drft, "write");
+       }
+       charstring_free(scanl);
+    } else {
+       cpydata (in, out, form, drft);
+       close (in);
+    }
     close (out);
 
 edit_it:
@@ -293,7 +394,7 @@ edit_it:
 
     if (nwhat)
        done (0);
-    what_now (ed, nedit, use, drft, NULL, 0, NULLMP, NULL, 0, cwd);
+    what_now (ed, nedit, use, drft, NULL, 0, NULL, NULL, 0, cwd, 0);
     done (1);
     return 1;
 }