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 \
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 *);
/*
- * 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
#include <string.h>
#include <stdlib.h>
-/* 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.
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;
}
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 <user@name.com> 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 ',',
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. */
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*
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"
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