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:
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 =
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 \
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 *);
--- /dev/null
+#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);
+ }
+}
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;
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
#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);