Add %(unmailto) format function for List-Post headers
[mmh] / sbr / fmt_scan.c
index 14ec48b..9ad7b8a 100644 (file)
@@ -1,94 +1,71 @@
 /*
- * fmt_scan.c -- format string interpretation
- *
- * This code is Copyright (c) 2002, by the authors of nmh.  See the
- * COPYRIGHT file in the root directory of the nmh distribution for
- * complete copyright information.
- */
+** fmt_scan.c -- format string interpretation
+**
+** This code is Copyright (c) 2002, by the authors of nmh.  See the
+** COPYRIGHT file in the root directory of the nmh distribution for
+** complete copyright information.
+**
+** This is the engine that processes the format instructions created by
+** fmt_compile (found in fmt_compile.c).
+*/
 
 #include <h/mh.h>
 #include <h/addrsbr.h>
 #include <h/fmt_scan.h>
 #include <h/tws.h>
 #include <h/fmt_compile.h>
+#include <ctype.h>
+#include <sysexits.h>
 
-#ifdef TIME_WITH_SYS_TIME
+#ifdef HAVE_SYS_TIME_H
 # include <sys/time.h>
-# include <time.h>
-#else
-# ifdef TM_IN_SYS_TIME
-#  include <sys/time.h>
-# else
-#  include <time.h>
-# endif
 #endif
+#include <time.h>
+
 #ifdef MULTIBYTE_SUPPORT
 #  include <wctype.h>
 #  include <wchar.h>
 #endif
 
-#define NFMTS MAXARGS
-
-extern char *formataddr ();  /* hook for custom address formatting */
-
-#ifdef LBL
-struct msgs *fmt_current_folder; /* current folder (set by main program) */
-#endif
-
 extern int fmt_norm;  /* defined in sbr/fmt_def.c = AD_NAME */
 struct mailname fmt_mnull;
 
 /*
- * static prototypes
- */
-static int match (char *, char *);
-static char *get_x400_friendly (char *, char *, int);
-static int get_x400_comp (char *, char *, char *, int);
+** static prototypes
+*/
+static int match(char *, char *);
+static char *get_x400_friendly(char *, char *, int);
+static int get_x400_comp(char *, char *, char *, int);
 
 
 /*
- * test if string "sub" appears anywhere in
- * string "str" (case insensitive).
- */
+** test if string "sub" appears anywhere in
+** string "str" (case insensitive).
+*/
 
 static int
-match (char *str, char *sub)
+match(char *str, char *sub)
 {
        int c1, c2;
        char *s1, *s2;
 
-#ifdef LOCALE
        while ((c1 = *sub)) {
-               c1 = (isalpha(c1) && isupper(c1)) ? tolower(c1) : c1;
-               while ((c2 = *str++) && c1 != ((isalpha(c2) && isupper(c2)) ? tolower(c2) : c2))
+               while ((c2 = *str++) && tolower(c1) != tolower(c2))
                        ;
                if (! c2)
                        return 0;
                s1 = sub + 1; s2 = str;
-               while ((c1 = *s1++) && ((isalpha(c1) && isupper(c1)) ? tolower(c1) : c1) == ((isalpha(c2 =*s2++) && isupper(c2)) ? tolower(c2) : c2))
+               while ((c1 = *s1++) && tolower(c1) == tolower(*s2++))
                        ;
                if (! c1)
                        return 1;
        }
-#else
-       while ((c1 = *sub)) {
-               while ((c2 = *str++) && (c1 | 040) != (c2 | 040))
-                       ;
-               if (! c2)
-                       return 0;
-               s1 = sub + 1; s2 = str;
-               while ((c1 = *s1++) && (c1 | 040) == (*s2++ | 040))
-                       ;
-               if (! c1)
-                       return 1;
-       }
-#endif
        return 1;
 }
 
 /*
- * copy a number to the destination subject to a maximum width
- */
+** copy a number to the destination subject to a maximum width
+*/
 static void
 cpnumber(char **dest, int num, unsigned int wid, char fill, size_t n) {
        int i, c;
@@ -118,10 +95,10 @@ cpnumber(char **dest, int num, unsigned int wid, char fill, size_t n) {
 }
 
 /*
- * copy string from str to dest padding with the fill character to a size
- * of wid characters. if wid is negative, the string is right aligned
- * no more than n bytes are copied
- */
+** copy string from str to dest padding with the fill character to a size
+** of wid characters. if wid is negative, the string is right aligned
+** no more than n bytes are copied
+*/
 static void
 cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n) {
        int remaining; /* remaining output width available */
@@ -208,7 +185,7 @@ cptrimmed(char **dest, char *str, unsigned int wid, char fill, size_t n) {
 }
 
 static void
-cpstripped (char **start, char *end, char *str)
+cpstripped(char **start, char *end, char *str)
 {
        int c;
        char *s = str;
@@ -217,12 +194,7 @@ cpstripped (char **start, char *end, char *str)
                return;
 
        /* skip any initial control characters or spaces */
-       while ((c = (unsigned char) *s) &&
-#ifdef LOCALE
-                       (iscntrl(c) || isspace(c)))
-#else
-                       (c <= 32))
-#endif
+       while ((c = (unsigned char) *s) && (iscntrl(c) || isspace(c)))
                s++;
 
        /* compact repeated control characters and spaces into a single space */
@@ -231,11 +203,7 @@ cpstripped (char **start, char *end, char *str)
                        *(*start)++ = c;
                else {
                        while ((c = (unsigned char) *s) &&
-#ifdef LOCALE
-                               (iscntrl(c) || isspace(c)))
-#else
-                               (c <= 32))
-#endif
+                                       (iscntrl(c) || isspace(c)))
                                s++;
                        *(*start)++ = ' ';
                }
@@ -248,7 +216,7 @@ static char *lmonth[] = {
 };
 
 static char *
-get_x400_friendly (char *mbox, char *buffer, int buffer_len)
+get_x400_friendly(char *mbox, char *buffer, int buffer_len)
 {
        char given[BUFSIZ], surname[BUFSIZ];
 
@@ -259,40 +227,40 @@ get_x400_friendly (char *mbox, char *buffer, int buffer_len)
        if (*mbox != '/')
                return NULL;
 
-       if (get_x400_comp (mbox, "/PN=", buffer, buffer_len)) {
+       if (get_x400_comp(mbox, "/PN=", buffer, buffer_len)) {
                for (mbox = buffer; (mbox = strchr(mbox, '.')); )
                        *mbox++ = ' ';
 
                return buffer;
        }
 
-       if (!get_x400_comp (mbox, "/S=", surname, sizeof(surname)))
+       if (!get_x400_comp(mbox, "/S=", surname, sizeof(surname)))
                return NULL;
 
-       if (get_x400_comp (mbox, "/G=", given, sizeof(given)))
-               snprintf (buffer, buffer_len, "%s %s", given, surname);
+       if (get_x400_comp(mbox, "/G=", given, sizeof(given)))
+               snprintf(buffer, buffer_len, "%s %s", given, surname);
        else
-               snprintf (buffer, buffer_len, "%s", surname);
+               snprintf(buffer, buffer_len, "%s", surname);
 
        return buffer;
 }
 
 static int
-get_x400_comp (char *mbox, char *key, char *buffer, int buffer_len)
+get_x400_comp(char *mbox, char *key, char *buffer, int buffer_len)
 {
        int idx;
        char *cp;
 
-       if ((idx = stringdex (key, mbox)) < 0
-               || !(cp = strchr(mbox += idx + strlen (key), '/')))
+       if ((idx = stringdex(key, mbox)) < 0
+               || !(cp = strchr(mbox += idx + strlen(key), '/')))
                return 0;
 
-       snprintf (buffer, buffer_len, "%*.*s", (int)(cp - mbox), (int)(cp - mbox), mbox);
+       snprintf(buffer, buffer_len, "%*.*s", (int)(cp - mbox), (int)(cp - mbox), mbox);
        return 1;
 }
 
 struct format *
-fmt_scan (struct format *format, char *scanl, int width, int *dat)
+fmt_scan(struct format *format, char *scanl, int width, int *dat)
 {
        char *cp, *ep;
        unsigned char *sp;
@@ -324,10 +292,10 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                switch (fmt->f_type) {
 
                case FT_COMP:
-                       cpstripped (&cp, ep, fmt->f_comp->c_text);
+                       cpstripped(&cp, ep, fmt->f_comp->c_text);
                        break;
                case FT_COMPF:
-                       cptrimmed (&cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill, ep - cp);
+                       cptrimmed(&cp, fmt->f_comp->c_text, fmt->f_width, fmt->f_fill, ep - cp);
                        break;
 
                case FT_LIT:
@@ -350,13 +318,13 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                        break;
 
                case FT_STR:
-                       cpstripped (&cp, ep, str);
+                       cpstripped(&cp, ep, str);
                        break;
                case FT_STRF:
-                       cptrimmed (&cp, str, fmt->f_width, fmt->f_fill, ep - cp);
+                       cptrimmed(&cp, str, fmt->f_width, fmt->f_fill, ep - cp);
                        break;
                case FT_STRFW:
-                       adios (NULL, "internal error (FT_STRFW)");
+                       adios(EX_SOFTWARE, NULL, "internal error (FT_STRFW)");
 
                case FT_NUM:
                        n = snprintf(cp, ep - cp + 1, "%d", value);
@@ -368,7 +336,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                        }
                        break;
                case FT_NUMF:
-                       cpnumber (&cp, value, fmt->f_width, fmt->f_fill, ep - cp);
+                       cpnumber(&cp, value, fmt->f_width, fmt->f_fill, ep - cp);
                        break;
 
                case FT_CHAR:
@@ -414,7 +382,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                        break;
 
                case FT_IF_MATCH:
-                       if (!(value = (str && match (str, fmt->f_text)))) {
+                       if (!(value = (str && match(str, fmt->f_text)))) {
                                fmt += fmt->f_skip;
                                continue;
                        }
@@ -422,20 +390,20 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
 
                case FT_V_MATCH:
                        if (str)
-                               value = match (str, fmt->f_text);
+                               value = match(str, fmt->f_text);
                        else
                                value = 0;
                        break;
 
                case FT_IF_AMATCH:
-                       if (!(value = (str && uprf (str, fmt->f_text)))) {
+                       if (!(value = (str && uprf(str, fmt->f_text)))) {
                                fmt += fmt->f_skip;
                                continue;
                        }
                        break;
 
                case FT_V_AMATCH:
-                       value = uprf (str, fmt->f_text);
+                       value = uprf(str, fmt->f_text);
                        break;
 
                case FT_S_NONNULL:
@@ -472,11 +440,11 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                        str = fmt->f_text;
                        break;
                case FT_LS_GETENV:
-                       if (!(str = getenv (fmt->f_text)))
+                       if (!(str = getenv(fmt->f_text)))
                                str = "";
                        break;
                case FT_LS_CFIND:
-                       if (!(str = context_find (fmt->f_text)))
+                       if (!(str = context_find(fmt->f_text)))
                                str = "";
                        break;
 
@@ -507,13 +475,13 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                                                ljust++;
                                }
 
-                               if (!ljust && i > 0 && strlen(str) > i)
+                               if (!ljust && i > 0 && (int)strlen(str) > i)
                                                str[i] = '\0';
                                xp = str;
                                xp += strlen(str) - 1;
                                while (xp > str && isspace(*xp))
                                                *xp-- = '\0';
-                               if (ljust && i > 0 && strlen(str) > i)
+                               if (ljust && i > 0 && (int)strlen(str) > i)
                                        str += strlen(str) - i;
                        }
                        break;
@@ -583,24 +551,24 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                        str = lmonth[fmt->f_comp->c_tws->tw_mon];
                        break;
                case FT_LS_ZONE:
-                       str = dtwszone (fmt->f_comp->c_tws);
+                       str = dtwszone(fmt->f_comp->c_tws);
                        break;
                case FT_LV_YEAR:
                        value = fmt->f_comp->c_tws->tw_year;
                        break;
                case FT_LV_WDAY:
                        if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
-                               set_dotw (tws);
+                               set_dotw(tws);
                        value = tws->tw_wday;
                        break;
                case FT_LS_DAY:
                        if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
-                               set_dotw (tws);
+                               set_dotw(tws);
                        str = tw_dotw[tws->tw_wday];
                        break;
                case FT_LS_WEEKDAY:
                        if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
-                               set_dotw (tws);
+                               set_dotw(tws);
                        str = tw_ldotw[tws->tw_wday];
                        break;
                case FT_LV_YDAY:
@@ -620,14 +588,14 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                        break;
                case FT_LV_DAYF:
                        if (!(((tws = fmt->f_comp->c_tws)->tw_flags) & (TW_SEXP|TW_SIMP)))
-                               set_dotw (tws);
+                               set_dotw(tws);
                        switch (fmt->f_comp->c_tws->tw_flags & TW_SDAY) {
-                               case TW_SEXP:
-                                       value = 1; break;
-                               case TW_SIMP:
-                                       value = 0; break;
-                               default:
-                                       value = -1; break;
+                       case TW_SEXP:
+                               value = 1; break;
+                       case TW_SIMP:
+                               value = 0; break;
+                       default:
+                               value = -1; break;
                        }
                case FT_LV_ZONEF:
                        if ((fmt->f_comp->c_tws->tw_flags & TW_SZONE) == TW_SZEXP)
@@ -639,10 +607,8 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                        value = fmt->f_comp->c_tws->tw_flags & TW_DST;
                        break;
                case FT_LS_822DATE:
-                       str = dasctime (fmt->f_comp->c_tws , TW_ZONE);
-                       break;
                case FT_LS_PRETTY:
-                       str = dasctime (fmt->f_comp->c_tws, TW_NULL);
+                       str = dasctime(fmt->f_comp->c_tws);
                        break;
 
                case FT_LS_PERS:
@@ -685,7 +651,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                                goto unfriendly;
                        if ((str = mn->m_pers) == NULL) {
                                if ((str = mn->m_note)) {
-                                       strncpy (buffer, str, sizeof(buffer));
+                                       strncpy(buffer, str, sizeof(buffer));
                                        buffer[sizeof(buffer)-1] = '\0';
                                        str = buffer;
                                        if (*str == '(')
@@ -699,27 +665,21 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                                                        else
                                                                break;
                                        }
-                               } else if (!(str = get_x400_friendly (mn->m_mbox,
+                               } else if (!(str = get_x400_friendly(mn->m_mbox,
                                        buffer, sizeof(buffer)))) {
                unfriendly: ;
                                        switch (mn->m_type) {
                                        case LOCALHOST:
                                                str = mn->m_mbox;
                                                break;
-                                       case UUCPHOST:
-                                               snprintf (buffer, sizeof(buffer), "%s!%s",
-                                                       mn->m_host, mn->m_mbox);
-                                               str = buffer;
-                                               break;
                                        default:
                                                if (mn->m_mbox) {
-                                                       snprintf (buffer, sizeof(buffer), "%s@%s",
-                                                               mn->m_mbox, mn->m_host);
+                                                       snprintf(buffer, sizeof(buffer), "%s@%s", mn->m_mbox, mn->m_host);
                                                        str= buffer;
                                                } else
                                                        str = mn->m_text;
                                                break;
-                                 }
+                                       }
                                }
                        }
                        break;
@@ -728,32 +688,10 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                /* UNQUOTEs RFC-2822 quoted-string and quoted-pair */
                case FT_LS_UNQUOTE:
                        if (str) {
-                               int m;
                                strncpy(buffer, str, sizeof(buffer));
                                /* strncpy doesn't NUL-terminate if it fills the buffer */
                                buffer[sizeof(buffer)-1] = '\0';
-                               str = buffer;
-
-                               /* we will parse from buffer to buffer2 */
-                               n = 0; /* n is the input position in str */
-                               m = 0; /* m is the ouput position in buffer2 */
-
-                               while ( str[n] != '\0') {
-                                       switch ( str[n] ) {
-                                               case '\\':
-                                                       n++;
-                                                       if ( str[n] != '\0')
-                                                               buffer2[m++] = str[n++];
-                                                       break;
-                                               case '"':
-                                                       n++;
-                                                       break;
-                                               default:
-                                                       buffer2[m++] = str[n++];
-                                                       break;
-                                               }
-                               }
-                               buffer2[m] = '\0';
+                               unquote_string(buffer, buffer2);
                                str = buffer2;
                        }
                        break;
@@ -782,24 +720,28 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                                *comp->c_tws = *tws;
                                comp->c_flags &= ~CF_TRUE;
                        } else if ((comp->c_flags & CF_DATEFAB) == 0) {
-                               memset ((char *) comp->c_tws, 0, sizeof *comp->c_tws);
+                               memset((char *) comp->c_tws, 0, sizeof *comp->c_tws);
                                comp->c_flags = CF_TRUE;
                        }
                        comp->c_flags |= CF_PARSED;
                        break;
 
                case FT_FORMATADDR:
-                       /* hook for custom address list formatting (see replsbr.c) */
-                       str = formataddr (savestr, str);
+                       /*
+                       ** hook for custom address list formatting
+                       ** (see replsbr.c)
+                       */
+                       str = formataddr(savestr, str);
                        break;
 
                case FT_PUTADDR:
-                       /* output the str register as an address component,
-                        * splitting it into multiple lines if necessary.  The
-                        * value reg. contains the max line length.  The lit.
-                        * field may contain a string to prepend to the result
-                        * (e.g., "To: ")
-                        */
+                       /*
+                       ** output the str register as an address component,
+                       ** splitting it into multiple lines if necessary.  The
+                       ** value reg. contains the max line length.  The lit.
+                       ** field may contain a string to prepend to the result
+                       ** (e.g., "To: ")
+                       */
                        {
                        unsigned char *lp;
                        char *lastb;
@@ -807,16 +749,22 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
 
                        lp = str;
                        wid = value;
-                       len = strlen (str);
+                       len = strlen(str);
                        sp = fmt->f_text;
-                       indent = strlen (sp);
+                       indent = strlen(sp);
                        wid -= indent;
+                       if (wid <= 0) {
+                               adios(EX_SOFTWARE, NULL, "putaddr -- num register (%d) "
+                                               "must be greater than label "
+                                               "width (%d)", value, indent);
+                       }
                        while( (c = *sp++) && cp < ep)
                                *cp++ = c;
                        while (len > wid) {
-                               /* try to break at a comma; failing that,
-                                * break at a space.
-                                */
+                               /*
+                               ** try to break at a comma; failing that,
+                               ** break at a space.
+                               */
                                lastb = 0; sp = lp + wid;
                                while (sp > lp && (c = *--sp) != ',') {
                                        if (! lastb && isspace(c))
@@ -843,7 +791,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                                                *cp++ = ' ';
                                }
                        }
-                       cpstripped (&cp, ep, lp);
+                       cpstripped(&cp, ep, lp);
                        }
                        break;
 
@@ -852,9 +800,9 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                        if (comp->c_flags & CF_PARSED)
                                break;
                        if (comp->c_mn != &fmt_mnull)
-                               mnfree (comp->c_mn);
+                               mnfree(comp->c_mn);
                        if ((sp = comp->c_text) && (sp = getname(sp)) &&
-                               (mn = getm (sp, NULL, 0, fmt_norm, NULL))) {
+                               (mn = getm(sp, NULL, 0, fmt_norm, NULL))) {
                                comp->c_mn = mn;
                                while (getname(""))
                                        ;
@@ -868,15 +816,15 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
 
                case FT_MYMBOX:
                        /*
-                        * if there's no component, we say true.  Otherwise we
-                        * say "true" only if we can parse the address and it
-                        * matches one of our addresses.
-                        */
+                       ** if there's no component, we say true.  Otherwise we
+                       ** say "true" only if we can parse the address and it
+                       ** matches one of our addresses.
+                       */
                        comp = fmt->f_comp;
                        if (comp->c_mn != &fmt_mnull)
-                               mnfree (comp->c_mn);
+                               mnfree(comp->c_mn);
                        if ((sp = comp->c_text) && (sp = getname(sp)) &&
-                               (mn = getm (sp, NULL, 0, AD_NAME, NULL))) {
+                               (mn = getm(sp, NULL, 0, AD_NAME, NULL))) {
                                comp->c_mn = mn;
                                if (ismymbox(mn))
                                        comp->c_flags |= CF_TRUE;
@@ -884,7 +832,7 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                                        comp->c_flags &= ~CF_TRUE;
                                while ((sp = getname(sp)))
                                        if ((comp->c_flags & CF_TRUE) == 0 &&
-                                               (mn = getm (sp, NULL, 0, AD_NAME, NULL)))
+                                               (mn = getm(sp, NULL, 0, AD_NAME, NULL)))
                                                if (ismymbox(mn))
                                                        comp->c_flags |= CF_TRUE;
                        } else {
@@ -898,26 +846,31 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
                        }
                        break;
 
-               case FT_ADDTOSEQ:
-#ifdef LBL
-                       /* If we're working on a folder (as opposed to a file), add the
-                        * current msg to sequence given in literal field.  Don't
-                        * disturb string or value registers.
-                        */
-                       if (fmt_current_folder)
-                               seq_addmsg(fmt_current_folder, fmt->f_text, dat[0], -1);
-#endif
+               case FT_LS_UNMAILTO:
+                       if (!str) {
+                               break;
+                       }
+                       str = trim(str);
+                       if (*str == '<' && str[strlen(str)-1] == '>') {
+                               str++;
+                               str[strlen(str)-1] = '\0';
+                       }
+                       if (strncmp("mailto:", str, 7)==0) {
+                               str += 7;
+                       }
                        break;
+
                }
                fmt++;
        }
-#ifndef JLR
-       finished:;
+finished:;
        if (cp[-1] != '\n')
                *cp++ = '\n';
-       *cp   = 0;
+       *cp = '\0';
        return ((struct format *)0);
-#else /* JLR */
+
+#ifdef JLR
+       /* I'll remove this as soon as I understand what it does. --meillo */
        if (cp[-1] != '\n')
                *cp++ = '\n';
        while (fmt->f_type != FT_DONE)
@@ -926,6 +879,6 @@ fmt_scan (struct format *format, char *scanl, int width, int *dat)
        finished:;
        *cp = '\0';
        return (fmt->f_value ? ++fmt : (struct format *) 0);
-
 #endif /* JLR */
+
 }