* h/mh.h, h/prototypes.h, uip/mhbuildsbr.c, uip/send.c,
authorDavid Levine <levinedl@acm.org>
Tue, 21 Feb 2006 03:58:31 +0000 (03:58 +0000)
committerDavid Levine <levinedl@acm.org>
Tue, 21 Feb 2006 03:58:31 +0000 (03:58 +0000)
  uip/sendsbr.c, uip/viamail.c, uip/whatnowsbr.c, man/send.man:
  added -attachformat switch to send, to support alternate MIME
  header contents when using -attach.  See send man page for
  description.

ChangeLog
h/mh.h
h/prototypes.h
man/send.man
uip/mhbuildsbr.c
uip/send.c
uip/sendsbr.c
uip/viamail.c
uip/whatnowsbr.c

index 79d6428..2e6103c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
 2006-02-20  David Levine <levinedl@acm.org>
 
+       * h/mh.h, h/prototypes.h, uip/mhbuildsbr.c, uip/send.c,
+       uip/sendsbr.c, uip/viamail.c, uip/whatnowsbr.c, man/send.man:
+       added -attachformat switch to send, to support alternate MIME
+       header contents when using -attach.  See send man page for
+       description.
+
        * man/mhbuild.man: wrapped one appearance of "Content-Disposition"
        with quotes, to be consistent with others.
 
diff --git a/h/mh.h b/h/mh.h
index 81a6021..130bfde 100644 (file)
--- a/h/mh.h
+++ b/h/mh.h
@@ -58,6 +58,8 @@ struct swit {
 
 extern struct swit anoyes[];   /* standard yes/no switches */
 
+#define ATTACHFORMATS 3                /* Number of send attach formats. */
+
 /*
  * general folder attributes
  */
index de57cb8..1d1d456 100644 (file)
@@ -158,7 +158,7 @@ void annopreserve(int);
 int distout (char *, char *, char *);
 void replout (FILE *, char *, char *, struct msgs *, int,
        int, char *, char *, char *);
-int sendsbr (char **, int, char *, struct stat *, int, char *);
+int sendsbr (char **, int, char *, struct stat *, int, char *, int);
 int what_now (char *, int, int, char *, char *,
        int, struct msgs *, char *, int, char *);
 
index 65a5d1e..57f37b7 100644 (file)
@@ -42,6 +42,8 @@ send \- send a message
 .RB [ \-help ]
 .RB [ \-attach
 .IR header-field-name ]
+.RB [ \-attachformat
+.IR 0 " | " 1 " | " 2 ]
 .ad
 .SH DESCRIPTION
 .B Send
@@ -101,6 +103,44 @@ Finally, a description attribute is generated by running the
 .I file
 command on the file.
 .PP
+The
+.B -attachformat
+option specifies the MIME header field formats:  a value of
+.B 0,
+the default,
+includes the
+.I x-unix-mode
+attribute as noted above.  A value of
+.B 1
+suppresses both that and the \*(lqContent-Description\*(rq header, and
+adds a \*(lqContent-Disposition\*(rq header.  A value of
+.B 2
+adds the file
+.I modification-date
+parameter to the \*(lqContent-Disposition\*(rq header.  You can
+specify one value in your profile, and override it for individual
+messages at the
+.I whatnow
+prompt.
+.PP
+Here are example message part headers for each of the
+.B -attachformat
+values:
+.PP
+.nf
+-attachformat 0:
+Content-Type: text/plain; name="VERSION"; x-unix-mode="0644";
+Content-Description: ASCII text 
+
+-attachformat 1:
+Content-Type: text/plain; charset="us-ascii"
+Content-Disposition: attachment; filename="VERSION"
+
+-attachformat 2:
+Content-Type: text/plain; charset="us-ascii"
+Content-Disposition: attachment; filename="VERSION"; modification-date="Mon, 19 Dec 2005 22:39:51 -0600"
+.fi
+.PP
 If
 .B \-push
 is specified,
@@ -350,6 +390,7 @@ comp(1), dist(1), forw(1), repl(1), mh\-alias(5), post(8)
 .RB ` \-noverbose '
 .RB ` \-nowatch '
 .RB ` "\-width\ 72" '
+.RB ` "\-attachformat\ 0" '
 .fi
 
 .SH CONTEXT
index 25924e9..c6f5098 100644 (file)
@@ -1108,17 +1108,18 @@ bad_quote:
                The r1bindex call skips any leading directory
                components. */
             if (ct->c_dispo)
-              ct->c_dispo =
-                incl_name_value (ct->c_dispo,
-                                 "filename",
-                                 r1bindex (extract_name_value ("name",
-                                                               ci->ci_magic),
-                                           '/'));
+                ct->c_dispo =
+                    incl_name_value (ct->c_dispo,
+                                     "filename",
+                                     r1bindex (extract_name_value ("name",
+                                                                   ci->
+                                                                   ci_magic),
+                                               '/'));
         }
        else
            advise (NULL,
                    "extraneous information in message %s's %s: field\n%*.*s(%s)",
-               ct->c_file, TYPE_FIELD, i, i, "", cp);
+                    ct->c_file, TYPE_FIELD, i, i, "", cp);
     }
 
     return OK;
@@ -4317,64 +4318,85 @@ invalid_digest:
 
 
 /* Make sure that buf contains at least one appearance of name,
-   followed by =.  If not, append both name and value.  Note that name
-   should not contain a trailing =.  And quotes will be added around
-   the value.  Typical usage:  make sure that a Content-Disposition
-   header contains filename="foo".  If it doesn't and value does, use
-   value from that. */
+   followed by =.  If not, insert both name and value, just after
+   first semicolon, if any.  Note that name should not contain a
+   trailing =. And quotes will be added around the value.  Typical
+   usage:  make sure that a Content-Disposition header contains
+   filename="foo".  If it doesn't and value does, use value from
+   that. */
 static char *
 incl_name_value (char *buf, char *name, char *value) {
-  char *newbuf = buf;
+    char *newbuf = buf;
 
-  /* Assume that name is non-null. */
-  if (buf && value) {
-    char *name_plus_equal = concat (name, "=", NULL);
+    /* Assume that name is non-null. */
+    if (buf && value) {
+       char *name_plus_equal = concat (name, "=", NULL);
 
-    if (! strstr (buf, name_plus_equal)) {
-      char *appendage;
-      char *cp;
+       if (! strstr (buf, name_plus_equal)) {
+           char *insertion;
+           char *cp;
+           char *prefix, *suffix;
 
-      /* Trim trailing space, esp. newline. */
-      for (cp = &buf[strlen (buf) - 1]; cp >= buf && isspace (*cp); --cp) {
-        *cp = '\0';
-      }
+           /* Trim trailing space, esp. newline. */
+           for (cp = &buf[strlen (buf) - 1];
+                cp >= buf && isspace (*cp);
+                --cp) {
+               *cp = '\0';
+           }
 
-      appendage = concat ("; ", name, "=", "\"", value, "\"\n", NULL);
-      newbuf = add (appendage, buf);
-      free (appendage);
-    }
+           insertion = concat ("; ", name, "=", "\"", value, "\"", NULL);
+
+           /* Insert at first semicolon, if any.  If none, append to
+              end. */
+           prefix = add (buf, NULL);
+           if ((cp = strchr (prefix, ';'))) {
+               suffix = concat (cp, NULL);
+               *cp = '\0';
+               newbuf = concat (prefix, insertion, suffix, "\n", NULL);
+               free (suffix);
+           } else {
+               /* Append to end. */
+               newbuf = concat (buf, insertion, "\n", NULL);
+           }
+
+           free (prefix);
+           free (insertion);
+           free (buf);
+       }
 
-    free (name_plus_equal);
-  }
+       free (name_plus_equal);
+    }
 
-  return newbuf;
+    return newbuf;
 }
 
 
-/* Extract just name_suffix="foo", if any, from value.  If there isn't
+/* Extract just name_suffix="foo", if any, from value. If there isn't
    one, return the entire value.  Note that, for example, a name_suffix
    of name will match filename="foo", and return foo. */
 static char *
 extract_name_value (char *name_suffix, char *value) {
-  char *extracted_name_value = value;
-  char *name_suffix_plus_quote = concat (name_suffix, "=\"", NULL);
-  char *name_suffix_equals = strstr (value, name_suffix_plus_quote);
-  char *cp;
-
-  free (name_suffix_plus_quote);
-  if (name_suffix_equals) {
-    char *name_suffix_begin;
-
-    /* Find first \". */
-    for (cp = name_suffix_equals; *cp != '"'; ++cp) /* empty */;
-    name_suffix_begin = ++cp;
-    /* Find second \". */
-    for (; *cp != '"'; ++cp) /* empty */;
-
-    extracted_name_value = mh_xmalloc (cp - name_suffix_begin + 1);
-    memcpy (extracted_name_value, name_suffix_begin, cp - name_suffix_begin);
-    extracted_name_value[cp - name_suffix_begin] = '\0';
-  }
-
-  return extracted_name_value;
+    char *extracted_name_value = value;
+    char *name_suffix_plus_quote = concat (name_suffix, "=\"", NULL);
+    char *name_suffix_equals = strstr (value, name_suffix_plus_quote);
+    char *cp;
+
+    free (name_suffix_plus_quote);
+    if (name_suffix_equals) {
+       char *name_suffix_begin;
+
+       /* Find first \". */
+       for (cp = name_suffix_equals; *cp != '"'; ++cp) /* empty */;
+       name_suffix_begin = ++cp;
+       /* Find second \". */
+       for (; *cp != '"'; ++cp) /* empty */;
+
+       extracted_name_value = mh_xmalloc (cp - name_suffix_begin + 1);
+       memcpy (extracted_name_value,
+               name_suffix_begin,
+               cp - name_suffix_begin);
+       extracted_name_value[cp - name_suffix_begin] = '\0';
+    }
+
+    return extracted_name_value;
 }
index 514f073..7849472 100644 (file)
@@ -104,6 +104,8 @@ static struct swit switches[] = {
     { "user", SASLminc(-4) },
 #define ATTACHSW              40
     { "attach", 6 },
+#define ATTACHFORMATSW        41
+    { "attachformat", 7 },
     { NULL, 0 }
 };
 
@@ -142,6 +144,7 @@ main (int argc, char **argv)
     struct msgs *mp;
     struct stat st;
     char       *attach = (char *)0;    /* header field name for attachments */
+    int attachformat = 0; /* mhbuild format specifier for attachments */
 #ifdef UCI
     FILE *fp;
 #endif /* UCI */
@@ -280,6 +283,21 @@ main (int argc, char **argv)
                    if (!(attach = *argp++) || *attach == '-')
                        adios (NULL, "missing argument to %s", argp[-2]);
                    continue;
+
+               case ATTACHFORMATSW:
+                   if (! *argp || **argp == '-')
+                       adios (NULL, "missing argument to %s", argp[-1]);
+                   else {
+                       attachformat = atoi (*argp);
+                       if (attachformat < 0 ||
+                           attachformat > ATTACHFORMATS - 1) {
+                           advise (NULL, "unsupported attachformat %d",
+                                   attachformat);
+                           continue;
+                       }
+                   }
+                   ++argp;
+                   continue;
            }
        } else {
            msgs[msgp++] = cp;
@@ -443,7 +461,8 @@ go_to_it:
     closefds (3);
 
     for (msgnum = 0; msgnum < msgp; msgnum++) {
-       switch (sendsbr (vec, vecp, msgs[msgnum], &st, 1, attach)) {
+       switch (sendsbr (vec, vecp, msgs[msgnum], &st, 1, attach,
+                        attachformat)) {
            case DONE: 
                done (++status);
            case NOTOK: 
index f793b1c..a43627f 100644 (file)
@@ -54,7 +54,7 @@ static        FILE    *composition_file;                      /* composition file pointer */
 /*
  * external prototypes
  */
-int sendsbr (char **, int, char *, struct stat *, int, char *);
+int sendsbr (char **, int, char *, struct stat *, int, char *, int);
 int done (int);
 char *getusername (void);
 
@@ -68,10 +68,10 @@ static void annoaux (int);
 static int splitmsg (char **, int, char *, struct stat *, int);
 static int sendaux (char **, int, char *, struct stat *);
 
-static int     attach(char *, char *);
+static int     attach(char *, char *, int);
 static void    clean_up_temporary_files(void);
 static int     get_line(void);
-static void    make_mime_composition_file_entry(char *);
+static void    make_mime_composition_file_entry(char *, int);
 
 
 /*
@@ -79,7 +79,7 @@ static        void    make_mime_composition_file_entry(char *);
  */
 
 int
-sendsbr (char **vec, int vecp, char *drft, struct stat *st, int rename_drft, char *attachment_header_field_name)
+sendsbr (char **vec, int vecp, char *drft, struct stat *st, int rename_drft, char *attachment_header_field_name, int attachformat)
 {
     int status;
     char buffer[BUFSIZ], file[BUFSIZ];
@@ -104,7 +104,7 @@ sendsbr (char **vec, int vecp, char *drft, struct stat *st, int rename_drft, cha
      */
 
     if (attachment_header_field_name != (char *)0) {
-       switch (attach(attachment_header_field_name, drft)) {
+       switch (attach(attachment_header_field_name, drft, attachformat)) {
        case OK:
            drft = composition_file_name;
            break;
@@ -188,7 +188,8 @@ sendsbr (char **vec, int vecp, char *drft, struct stat *st, int rename_drft, cha
 }
 
 static int
-attach(char *attachment_header_field_name, char *draft_file_name)
+attach(char *attachment_header_field_name, char *draft_file_name,
+       int attachformat)
 {
     char               buf[MAXPATHLEN + 6];    /* miscellaneous buffer */
     int                        c;                      /* current character for body copy */
@@ -294,7 +295,7 @@ attach(char *attachment_header_field_name, char *draft_file_name)
      */
 
     if (has_body)
-       make_mime_composition_file_entry(body_file_name);
+       make_mime_composition_file_entry(body_file_name, attachformat);
 
     /*
      * Now, go back to the beginning of the draft file and look for header fields
@@ -308,7 +309,7 @@ attach(char *attachment_header_field_name, char *draft_file_name)
            for (p = field + length + 1; *p == ' ' || *p == '\t'; p++)
                ;
 
-           make_mime_composition_file_entry(p);
+           make_mime_composition_file_entry(p, attachformat);
        }
     }
 
@@ -376,7 +377,7 @@ get_line(void)
 }
 
 static void
-make_mime_composition_file_entry(char *file_name)
+make_mime_composition_file_entry(char *file_name, int attachformat)
 {
     int                        binary;                 /* binary character found flag */
     int                        c;                      /* current character */
@@ -444,41 +445,64 @@ make_mime_composition_file_entry(char *file_name)
        adios((char *)0, "unable to access file \"%s\"", file_name);
     }
 
-    (void)fprintf(composition_file, "#%s; name=\"%s\"; x-unix-mode=0%.3ho",
-     content_type, ((p = strrchr(file_name, '/')) == (char *)0) ? file_name : p + 1, (unsigned short)(st.st_mode & 0777));
-
-    if (strlen(file_name) > MAXPATHLEN) {
-       clean_up_temporary_files();
-       adios((char *)0, "attachment file name `%s' too long.", file_name);
-    }
-
-    (void)sprintf(cmd, "file '%s'", file_name);
-
-    if ((fp = popen(cmd, "r")) != (FILE *)0 && fgets(cmd, sizeof (cmd), fp) != (char *)0) {
-       *strchr(cmd, '\n') = '\0';
-
-       /*
-        *  The output of the "file" command is of the form
-        *
-        *      file:   description
-        *
-        *  Strip off the "file:" and subsequent white space.
-        */
-
-       for (p = cmd; *p != '\0'; p++) {
-           if (*p == ':') {
-               for (p++; *p != '\0'; p++) {
-                   if (*p != '\t')
-                       break;
-               }
-               break;
-           }
-       }
-
-       if (*p != '\0')
-           (void)fprintf(composition_file, " [ %s ]", p);
-
-       (void)pclose(fp);
+    switch (attachformat) {
+    case 0:
+        /* Insert name, file mode, and Content-Id. */
+        (void)fprintf(composition_file, "#%s; name=\"%s\"; x-unix-mode=0%.3ho",
+            content_type, ((p = strrchr(file_name, '/')) == (char *)0) ? file_name : p + 1, (unsigned short)(st.st_mode & 0777));
+
+        if (strlen(file_name) > MAXPATHLEN) {
+            clean_up_temporary_files();
+            adios((char *)0, "attachment file name `%s' too long.", file_name);
+        }
+
+        (void)sprintf(cmd, "file '%s'", file_name);
+
+        if ((fp = popen(cmd, "r")) != (FILE *)0 && fgets(cmd, sizeof (cmd), fp) != (char *)0) {
+            *strchr(cmd, '\n') = '\0';
+
+            /*
+             *  The output of the "file" command is of the form
+             *
+             *         file:   description
+             *
+             *  Strip off the "file:" and subsequent white space.
+             */
+
+            for (p = cmd; *p != '\0'; p++) {
+                if (*p == ':') {
+                    for (p++; *p != '\0'; p++) {
+                        if (*p != '\t')
+                            break;
+                    }
+                    break;
+                }
+            }
+
+            if (*p != '\0')
+                /* Insert Content-Description. */
+                (void)fprintf(composition_file, " [ %s ]", p);
+
+            (void)pclose(fp);
+        }
+
+        break;
+    case 1:
+        /* Suppress Content-Id, insert simple Content-Disposition. */
+        (void) fprintf (composition_file, "#%s <>{attachment}", content_type);
+
+        break;
+    case 2:
+        /* Suppress Content-Id, insert Content-Disposition with
+           modification date. */
+        (void) fprintf (composition_file,
+                        "#%s <>{attachment; modification-date=\"%s\"}",
+                        content_type,
+                        dtime (&st.st_mtim, 0));
+
+        break;
+    default:
+        adios ((char *)0, "unsupported attachformat %d", attachformat);
     }
 
     /*
index 3dbd27c..859dfaf 100644 (file)
@@ -236,7 +236,7 @@ via_mail (char *mailsw, char *subjsw, char *parmsw, char *descsw,
     if (verbsw)
        vec[vecp++] = "-verbose";
 
-    switch (sendsbr (vec, vecp, tmpfil, &st, 0, (char *)0)) {
+    switch (sendsbr (vec, vecp, tmpfil, &st, 0, (char *)0, 0)) {
        case DONE:
        case NOTOK:
            status++;
index d863b5b..0a959db 100644 (file)
@@ -1005,6 +1005,8 @@ static struct swit  sendswitches[] = {
     { "user", SASLminc(-4) },
 #define SNDATTACHSW       39
     { "attach file", 6 },
+#define SNDATTACHFORMAT   40
+    { "attachformat", 7 },
     { NULL, 0 }
 };
 
@@ -1030,6 +1032,8 @@ sendit (char *sp, char **arg, char *file, int pushed)
     char **arguments, *vec[MAXARGS];
     struct stat st;
     char       *attach = (char *)0;    /* attachment header field name */
+    int                attachformat = 0;       /* mhbuild format specifier for
+                                          attachments */
 
 #ifndef        lint
     int        distsw = 0;
@@ -1190,6 +1194,21 @@ sendit (char *sp, char **arg, char *file, int pushed)
                        return;
                    }
                    continue;
+
+               case SNDATTACHFORMAT:
+                   if (! *argp || **argp == '-')
+                       adios (NULL, "missing argument to %s", argp[-1]);
+                   else {
+                       attachformat = atoi (*argp);
+                       if (attachformat < 0 ||
+                           attachformat > ATTACHFORMATS - 1) {
+                           advise (NULL, "unsupported attachformat %d",
+                                   attachformat);
+                           continue;
+                       }
+                   }
+                   ++argp;
+                   continue;
            }
        }
        advise (NULL, "usage: %s [switches]", sp);
@@ -1255,7 +1274,7 @@ sendit (char *sp, char **arg, char *file, int pushed)
     vec[0] = r1bindex (postproc, '/');
     closefds (3);
 
-    if (sendsbr (vec, vecp, file, &st, 1, attach) == OK)
+    if (sendsbr (vec, vecp, file, &st, 1, attach, attachformat) == OK)
        done (0);
 }