]> git.marmaro.de Git - mmh/commitdiff
Added function escape_display_name() to double quote, if not already,
authorDavid Levine <levinedl@acm.org>
Fri, 23 Mar 2012 02:06:47 +0000 (21:06 -0500)
committerDavid Levine <levinedl@acm.org>
Fri, 23 Mar 2012 02:06:47 +0000 (21:06 -0500)
a fullname that contains any of the special characters listed in RFC
5322, and escape unescaped, embedded double quotes.

With this change, nmh should work with no special configuration on
Cygwin, even if the user's fullname is of the form server\name.

MACHINES
Makefile.am
h/prototypes.h
sbr/escape_display_name.c [new file with mode: 0644]
sbr/mts.c
test/format/test-myname
test/getfullname.c

index ab0d2cb2d7b1baca8629bded06d94cee5d8792bd..8bae084a415e3b9f9f2f9075c336a2d0c755f1db 100644 (file)
--- a/MACHINES
+++ b/MACHINES
@@ -47,12 +47,6 @@ Libs category.  And libncurses10 or later in the Lib category.
 
 You may notice a few (three) compile warnings:  they can be ignored.
 
-If send, post, and whom fail, the cause might be a \ in your username.
-To avoid this, either add a Signature profile entry (see the
-mh-profile(5) man page) or set/export your SIGNATURE environment
-variable.  The value can be just the short form of your username, such
-as that displayed by "id -nu".
-
 --------------------------------------
 HPUX:
 
index 14d1dd1400b1d3ef376db3cc2db1d28654d2e8c1..c8006a9ab4b9b8850b5edda240d93f1ad8fa4897 100644 (file)
@@ -369,7 +369,7 @@ uip_viamail_SOURCES = uip/viamail.c uip/mhmisc.c uip/mhoutsbr.c uip/sendsbr.c \
                      uip/annosbr.c uip/distsbr.c
 
 test_getfullname_SOURCES = test/getfullname.c
-test_getfullname_LDADD =
+test_getfullname_LDADD = sbr/libmh.a
 
 test_getfqdn_SOURCES = test/getfqdn.c
 test_getfqdn_LDADD =
@@ -452,7 +452,7 @@ sbr_libmh_a_SOURCES = sbr/addrsbr.c sbr/ambigsw.c sbr/atooi.c sbr/brkstring.c \
                      sbr/context_replace.c sbr/context_save.c \
                      sbr/copy.c sbr/copyip.c sbr/cpydata.c \
                      sbr/cpydgst.c sbr/crawl_folders.c sbr/discard.c \
-                     sbr/done.c sbr/dtime.c \
+                     sbr/done.c sbr/dtime.c sbr/escape_display_name.c \
                      sbr/error.c  sbr/ext_hook.c sbr/fdcompare.c \
                      sbr/folder_addmsg.c sbr/folder_delmsgs.c \
                      sbr/folder_free.c sbr/folder_pack.c \
index 38357a8d59f01d61f9a28630bef13b5511569cb3..b4c004810f3ebb73bc942e8a7f59b171066630ca 100644 (file)
@@ -47,6 +47,7 @@ void cpydgst (int, int, char *, char *);
 int decode_rfc2047 (char *, char *, size_t);
 void discard (FILE *);
 int default_done (int);
+void escape_display_name (char *);
 int ext_hook(char *, char *, char *);
 int fdcompare (int, int);
 int folder_addmsg (struct msgs **, char *, int, int, int, int, char *);
diff --git a/sbr/escape_display_name.c b/sbr/escape_display_name.c
new file mode 100644 (file)
index 0000000..0918942
--- /dev/null
@@ -0,0 +1,63 @@
+#include <sys/types.h>
+#include <h/utils.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+/* Escape a display name, hopefully per RFC 5322.
+   The argument is assumed to be a pointer to a character array of
+   one-byte characters with enough space to handle the additional
+   characters. */
+void
+escape_display_name (char *name) {
+    /* Quote and escape name that contains any specials, as necessary. */
+    if (strpbrk("\"(),.:;<>@[\\]", name)) {
+        size_t len = strlen(name);
+        char *destp, *srcp;
+        size_t destpos, srcpos;
+        /* E.g., 2 characters, "", would require 7, "\"\""\0. */
+       char *tmp = malloc (2*len+3);
+
+        for (destp = tmp, srcp = name, destpos = 0, srcpos = 0;
+             *srcp;
+             ++destp, ++srcp, ++destpos, ++srcpos) {
+            if (srcpos == 0) {
+                /* Insert initial double quote, if needed. */
+                if (*srcp != '"') {
+                    *destp++ = '"';
+                    ++destpos;
+                }
+            } else {
+                /* Escape embedded, unescaped ". */
+                if (*srcp == '"'  &&  srcpos < len - 1  &&  *(srcp-1) != '\\') {
+                    *destp++ = '\\';
+                    ++destpos;
+                }
+            }
+
+            *destp = *srcp;
+
+            /* End of name. */
+            if (srcpos == len - 1) {
+                /* Insert final double quote, if needed. */
+                if (*srcp != '"') {
+                    *++destp = '"';
+                    ++destpos;
+                }
+
+                *++destp = '\0';
+                ++destpos;
+            }
+        }
+
+        if (strcmp (tmp, "\"")) {
+            /* assert (strlen(tmp) + 1 == destpos); */
+            strncpy (name, tmp, destpos);
+        } else {
+            /* Handle just " as special case here instead of above. */
+            strcpy (name, "\"\\\"\"");
+        }
+
+        free (tmp);
+    }
+}
index c5291565c16ad25f840125efcf40bab1c0487434..556d7400cecc82299a88d251e46b2a757f103fe6 100644 (file)
--- a/sbr/mts.c
+++ b/sbr/mts.c
@@ -395,16 +395,10 @@ getuserinfo (void)
     else if ((cp = context_find("Signature")))
        strncpy (fullname, cp, sizeof(fullname));
 
-    if (strchr(fullname, '.')) {               /*  quote any .'s */
-       char tmp[BUFSIZ];
-
-       /* should quote "'s too */
-       snprintf (tmp, sizeof(tmp), "\"%s\"", fullname);
-       strncpy (fullname, tmp, sizeof(fullname));
-    }
-
     fullname[sizeof(fullname) - 1] = '\0';
 
+    escape_display_name(fullname);
+
     localmbox[0] = '\0';
 
     return;
index 2b48c2f165899d41d531f5c18b6967b237fa7e17..d9dca2dcc5676f16bc5f1f98e242b8fc2da9a68b 100755 (executable)
@@ -31,4 +31,25 @@ export SIGNATURE="Some Random Name 2"
 run_test "${MH_LIB_DIR}/ap -format %(myname) ignore" \
          "${SIGNATURE}" "SIGNATURE Environment test"
 
+#### Test escaping of display names.
+escape="${MH_OBJ_DIR}/test/getfullname"
+run_test "$escape "'user'           'user'              'no escape'
+run_test "$escape "'first.last'     '"first.last"'      'escape'
+run_test "$escape "'"first.last"'   '"first.last"'      'already escaped'
+run_test "$escape "'embedded"quote' '"embedded\"quote"' 'embedded quote'
+run_test "$escape "'"'              '"\""'              'special "'
+run_test "$escape "'('              '"("'               'special ('
+run_test "$escape "')'              '")"'               'special )'
+#### We stop at the first comma so this one gets eliminated:
+run_test "$escape "','              ''                  'special ,'
+run_test "$escape "'.'              '"."'               'special .'
+run_test "$escape "':'              '":"'               'special :'
+run_test "$escape "';'              '";"'               'special ;'
+run_test "$escape "'<'              '"<"'               'special <'
+run_test "$escape "'>'              '">"'               'special >'
+run_test "$escape "'@'              '"@"'               'special @'
+run_test "$escape "'['              '"["'               'special ['
+run_test "$escape "'\\'             '"\\"'              'special \\'
+run_test "$escape "']'              '"]"'               'special ]'
+
 exit $failed
index d8ff10152649080443d1cbeb9f0ae466ca76ed71..ec83939f75ab537411194d269bc2ed98f26b406e 100644 (file)
 #include <sys/types.h>
 #include <pwd.h>
 
+extern void escape_display_name (char *);
+
 int
 main(int argc, char *argv[])
 {
        struct passwd *pwd;
-       char name[BUFSIZ], *p;
-
-       if (argc > 1) {
-               fprintf (stderr, "usage: %s\n", argv[0]);
-       }
-
-       pwd = getpwuid(getuid());
-
-       if (! pwd) {
-               fprintf(stderr, "Unable to retrieve user info for "
-                       "userid %ld\n", (long) getuid());
-               exit(1);
+       char buf[BUFSIZ], *p;
+       char *name = buf;
+
+       if (argc < 2) {
+               pwd = getpwuid(getuid());
+
+               if (! pwd) {
+                       fprintf(stderr, "Unable to retrieve user info for "
+                               "userid %ld\n", (long) getuid());
+                       exit(1);
+               }
+
+               strncpy(buf, pwd->pw_gecos, sizeof(buf));
+               buf[sizeof(buf) - 1] = '\0';
+       } else if (argc == 2) {
+               name = argv[1];
+       } else if (argc > 2) {
+               fprintf (stderr, "usage: %s [name]\n", argv[0]);
+               return 1;
        }
 
        /*
         * Perform the same processing that getuserinfo() does.
         */
 
-       strncpy(name, pwd->pw_gecos, sizeof(name));
-
-       name[sizeof(name) - 1] = '\0';
-
        /*
-        * Stop at the first comma
+        * Stop at the first comma.
         */
-
        if ((p = strchr(name, ',')))
                *p = '\0';
 
        /*
-        * Quote the entire string if it has a "." in it
+        * Quote the entire string if it has a special character in it.
         */
-
-       if (strchr(name, '.')) {
-               char tmp[BUFSIZ];
-
-               snprintf(tmp, sizeof(tmp), "\"%s\"", name);
-               strncpy(name, tmp, sizeof(name));
-
-               name[sizeof(name) - 2] = '"';
-               name[sizeof(name) - 1] = '\0';
-       }
+       escape_display_name (name);
 
        printf("%s\n", name);