Add %(unmailto) format function for List-Post headers
[mmh] / sbr / fmt_addr.c
1 /*
2 ** fmt_addr.c -- format an address field (from fmt_scan)
3 **
4 ** This code is Copyright (c) 2002, by the authors of nmh.  See the
5 ** COPYRIGHT file in the root directory of the nmh distribution for
6 ** complete copyright information.
7 */
8
9 #include <h/mh.h>
10 #include <h/addrsbr.h>
11 #include <h/fmt_scan.h>
12 #include <h/utils.h>
13
14 static char *buf;            /* our current working buffer  */
15 static char *bufend;         /* end of working buffer       */
16 static char *last_dst;       /* buf ptr at end of last call */
17 static unsigned int bufsiz;  /* current size of buf         */
18
19 #define BUFINCR 512  /* how much to expand buf when if fills */
20
21 #define CPY(s) { cp = (s); while ((*dst++ = *cp++)) ; --dst; }
22
23 /* check if there's enough room in buf for str.  add more mem if needed */
24 #define CHECKMEM(str) \
25         if ((len = strlen(str)) >= bufend - dst) {\
26                 int i = dst - buf;\
27                 int n = last_dst - buf;\
28                 bufsiz += ((dst + len - bufend) / BUFINCR + 1) * BUFINCR;\
29                 buf = mh_xrealloc(buf, bufsiz);\
30                 dst = buf + i;\
31                 last_dst = buf + n;\
32                 bufend = buf + bufsiz;\
33         }
34
35
36 /*
37 ** fmt_scan will call this routine if the user includes the function
38 ** "(formataddr {component})" in a format string.  "orig" is the
39 ** original contents of the string register.  "str" is the address
40 ** string to be formatted and concatenated onto orig.  This routine
41 ** returns a pointer to the concatenated address string.
42 **
43 ** We try to not do a lot of malloc/copy/free's (which is why we
44 ** don't call "mh_xstrdup") but still place no upper limit on the
45 ** length of the result string.
46 **
47 ** This routine is placed in a separate library so it can be
48 ** overridden by particular programs (e.g., "replsbr").
49 */
50
51 char *
52 formataddr(char *orig, char *str)
53 {
54         int len;
55         int isgroup;
56         char *dst;
57         char *cp;
58         char *sp;
59         struct mailname *mp = NULL;
60
61         /* if we don't have a buffer yet, get one */
62         if (bufsiz == 0) {
63                 buf = mh_xcalloc(BUFINCR, sizeof(char));
64                 last_dst = buf;  /* XXX */
65                 bufsiz = BUFINCR - 6;  /* leave some slop */
66                 bufend = buf + bufsiz;
67         }
68         /*
69         ** If "orig" points to our buffer we can just pick up where we
70         ** left off.  Otherwise we have to copy orig into our buffer.
71         */
72         if (orig == buf)
73                 dst = last_dst;
74         else if (!orig || !*orig) {
75                 dst = buf;
76                 *dst = '\0';
77         } else {
78                 dst = last_dst;  /* XXX */
79                 CHECKMEM(orig);
80                 CPY(orig);
81         }
82
83         /* concatenate all the new addresses onto 'buf' */
84         for (isgroup = 0; (cp = getname(str)); ) {
85                 if ((mp = getm(cp, NULL, 0, fmt_norm, NULL)) == NULL)
86                         continue;
87
88                 if (isgroup && (mp->m_gname || !mp->m_ingrp)) {
89                         *dst++ = ';';
90                         isgroup = 0;
91                 }
92                 /* if we get here we're going to add an address */
93                 if (dst != buf) {
94                         *dst++ = ',';
95                         *dst++ = ' ';
96                 }
97                 if (mp->m_gname) {
98                         CHECKMEM(mp->m_gname);
99                         CPY(mp->m_gname);
100                         isgroup++;
101                 }
102                 sp = adrformat(mp);
103                 CHECKMEM(sp);
104                 CPY(sp);
105                 mnfree(mp);
106         }
107
108         if (isgroup)
109                 *dst++ = ';';
110
111         *dst = '\0';
112         last_dst = dst;
113         return (buf);
114 }