From: David Levine Date: Thu, 10 May 2012 03:05:28 +0000 (-0500) Subject: Wrap local part (username) of address with double quotes if needed. X-Git-Url: http://git.marmaro.de/?a=commitdiff_plain;h=af586ebe59b73c23b2291624ab0015913c5a3687;p=mmh Wrap local part (username) of address with double quotes if needed. --- diff --git a/Makefile.am b/Makefile.am index 8a384a7..ad6b1e6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -478,7 +478,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/escape_display_name.c \ + sbr/done.c sbr/dtime.c sbr/escape_addresses.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 \ diff --git a/h/prototypes.h b/h/prototypes.h index 5304548..914036c 100644 --- a/h/prototypes.h +++ b/h/prototypes.h @@ -48,6 +48,7 @@ int decode_rfc2047 (char *, char *, size_t); void discard (FILE *); int default_done (int); void escape_display_name (char *, size_t); +void escape_local_part (char *, size_t); 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_addresses.c similarity index 63% rename from sbr/escape_display_name.c rename to sbr/escape_addresses.c index 4e98e97..a7dc146 100644 --- a/sbr/escape_display_name.c +++ b/sbr/escape_addresses.c @@ -1,5 +1,5 @@ /* - * escape_display_name.c -- Escape a display name, hopefully per RFC 5322. + * escape_addresses.c -- Escape address components, hopefully per RFC 5322. * * This code is Copyright (c) 2012, by the authors of nmh. See the * COPYRIGHT file in the root directory of the nmh distribution for @@ -11,14 +11,38 @@ #include #include -/* Escape a display name, hopefully per RFC 5322. Assumes one-byte - characters. The char array pointed to by the name argument is - modified in place. Its size is specified by the namesize - argument. */ +static void +escape_component (char *name, size_t namesize, char *chars); + + void escape_display_name (char *name, size_t namesize) { - /* Quote and escape name that contains any specials, as necessary. */ - if (strpbrk("\"(),.:;<>@[\\]", name)) { + char *specials = "\"(),.:;<>@[\\]"; + escape_component (name, namesize, specials); +} + + +void +escape_local_part (char *name, size_t namesize) { + /* wsp (whitespace) is horizontal tab or space, according to + RFC 5234. */ + char *specials_less_dot_plus_wsp = " \"(),:;<>@[\\]"; + escape_component (name, namesize, specials_less_dot_plus_wsp); +} + + +/* Escape an address component, hopefully per RFC 5322. Assumes + one-byte characters. The char array pointed to by the name + argument is modified in place. Its size is specified by the + namesize argument. The need_escape argument is a string of + characters that require that name be escaped. */ +void +escape_component (char *name, size_t namesize, char *chars_to_escape) { + /* If name contains any chars_to_escape: + 1) enclose it in "" + 2) escape any embedded " + */ + if (strpbrk(name, chars_to_escape)) { char *destp, *srcp; /* Maximum space requirement would be if each character had to be escaped, plus enclosing double quotes, plus null termintor. diff --git a/sbr/mts.c b/sbr/mts.c index cb11a77..548731e 100644 --- a/sbr/mts.c +++ b/sbr/mts.c @@ -337,19 +337,6 @@ getlocalmbox (void) if (username[0] == '\0') getuserinfo(); - if (localmbox[0] == '\0') { - char *cp; - - if ((cp = context_find("Local-Mailbox")) != NULL) { - strncpy(localmbox, cp, sizeof(localmbox)); - } else { - snprintf(localmbox, sizeof(localmbox), "%s <%s@%s>", fullname, - username, LocalName(0)); - } - - localmbox[sizeof(localmbox) - 1] = '\0'; - } - return localmbox; } @@ -373,6 +360,39 @@ getuserinfo (void) return; } + + /* username */ + /* If there's a Local-Mailbox profile component, try to extract + the username from it. But don't try very hard, this assumes + the very simple User Name form. + Note that post(8) and whom(1) use context_foil (), so they + won't see the profile component. */ + if ((np = context_find("Local-Mailbox")) != NULL) { + char *left_angle_bracket = strchr (np, '<'); + char *at_sign = strchr (np, '@'); + char *right_angle_bracket = strchr (np, '>'); + + strncpy(localmbox, np, sizeof(localmbox)); + + if (left_angle_bracket && at_sign && right_angle_bracket) { + if (at_sign > left_angle_bracket && + at_sign - left_angle_bracket < BUFSIZ) { + strncpy(username, left_angle_bracket + 1, + at_sign - left_angle_bracket - 1); + } + } + } + + if (username[0] == '\0') { + strncpy (username, pw->pw_name, sizeof(username)); + } + + username[sizeof(username) - 1] = '\0'; + + escape_local_part(username, sizeof(username)); + + + /* fullname */ np = pw->pw_gecos; /* Get the user's real name from the GECOS field. Stop once we hit a ',', @@ -382,8 +402,6 @@ getuserinfo (void) continue; *cp = '\0'; - strncpy (username, pw->pw_name, sizeof(username)); - /* The $SIGNATURE environment variable overrides the GECOS field's idea of your real name. If SIGNATURE isn't set, use the Signature profile setting if it exists. */ @@ -396,9 +414,14 @@ getuserinfo (void) escape_display_name(fullname, sizeof(fullname)); - localmbox[0] = '\0'; - return; + /* localmbox, if not using Local-Mailbox */ + if (localmbox[0] == '\0') { + snprintf(localmbox, sizeof(localmbox), "%s <%s@%s>", fullname, + username, LocalName(0)); + } + + localmbox[sizeof(localmbox) - 1] = '\0'; } static const char* diff --git a/test/format/test-mymbox b/test/format/test-mymbox index 39ab4c1..786d943 100755 --- a/test/format/test-mymbox +++ b/test/format/test-mymbox @@ -13,13 +13,17 @@ fi setup_test -user=${LOGNAME:-`id -un`} +#### Use ap to get the username. That will either be what's in the +#### Local-Mailbox profile component, which we don't use in the test +#### suite, or the user's login name. ap will escape (quote) it if +#### needed. +user=`${MH_LIB_DIR}/ap -format '%(me)' 0` host=`${MH_OBJ_DIR}/test/getfqdn` -run_test "${MH_LIB_DIR}/ap -format %(mymbox{text}) ${user}" \ - 1 "Basic user test" -run_test "${MH_LIB_DIR}/ap -format %(mymbox{text}) ${user}@${host}" \ - 1 "Basic user@host test" +output=`${MH_LIB_DIR}/ap -format '%(mymbox{text})' "${user}"` +run_test "echo $output" 1 "Basic user test" +output=`${MH_LIB_DIR}/ap -format '%(mymbox{text})' "${user}@${host}"` +run_test "echo $output" 1 "Basic user@host test" run_test "${MH_LIB_DIR}/ap -format %(mymbox{text}) nosuchuser@nosuchhost.blah" \ 0 "Basic non-matching test" @@ -34,7 +38,7 @@ echo "Local-Mailbox: ${myname}" >> ${MH} run_test "echo `${MH_LIB_DIR}/ap -format '%(mymbox{text})' "${myname}"`" \ 1 "Local-Mailbox test" -run_test "${MH_LIB_DIR}/ap -format %(mymbox{text}) ${user}@${host}" \ - 0 "Local-mailbox overriding user@host test" +output=`${MH_LIB_DIR}/ap -format '%(mymbox{text})' "${user}@${host}"` +run_test "echo $output" 0 "Local-mailbox overriding user@host test" exit $failed