1 #include "die.h"
2 #include "mime.h"
3 
author_name(stralloc * out,const char * s,unsigned int l)4 void author_name(stralloc *out,const char *s,unsigned int l)
5 /* s is a string that contains a from: line argument\n. We parse */
6 /* s as follows: If there is an unquoted '<' we eliminate everything after */
7 /* it else if there is a unquoted ';' we eliminate everything after it.    */
8 /* Then, we eliminate LWSP and '"' from the beginning and end. Note that   */
9 /* this is not strict rfc822, but all we need is a display handle that     */
10 /* doesn't show the address. If in the remaining text there is a '@' we put*/
11 /* in a '.' instead. Also, there are some non-rfc822 from lines out there  */
12 /* and we still want to maximize the chance of getting a handle, even if it*/
13 /* costs a little extra work.*/
14 {
15   int squote = 0;
16   int dquote = 0;
17   int level = 0;
18   int flagdone;
19   unsigned int len;
20   char ch;
21   const char *cpfirst,*cp;
22   const char *cpcomlast = 0;
23   const char *cpquotlast = 0;
24   const char *cpquot = 0;
25   const char *cpcom = 0;
26   const char *cplt = 0;
27   char *cpout;
28 
29   if (!s || !l)		/* Yuck - pass the buck */
30     if (!stralloc_copyb(out,"",0)) die_nomem();
31   cp = s; len = l;
32 
33   while (len--) {
34     ch = *(cp++);
35     if (squote)
36       squote = 0;
37     else if (ch == '\\')
38       squote = 1;
39     else if (ch == '"') {	/* "name" <address@host> */
40       if (dquote) {
41 	cpquotlast = cp - 2;
42         break;
43       } else {
44 	cpquot = cp;
45         dquote = 1;
46       }
47     }
48     else if (dquote)
49       ;
50     else if (ch == '(') {
51 	if (!level) cpcom = cp;
52 	level++;
53     }
54     else if (ch == ')') {
55 	level--;
56 	if (!level)
57 	  cpcomlast = cp - 2;	/* address@host (name) */
58     }
59     else if (!level) {
60       if (ch == '<') {		/* name <address@host> */
61 	cplt = cp - 2;
62 	break;
63       } else if (ch == ';') break;	/* address@host ;garbage */
64     }
65   }
66   if (cplt) {			/* non-comment '<' */
67     cp = cplt;
68     cpfirst = s;
69   } else if (cpquot && cpquotlast >= cpquot) {
70     cpfirst = cpquot;
71     cp = cpquotlast;
72   } else if (cpcom && cpcomlast >= cpcom) {
73     cpfirst = cpcom;
74     cp = cpcomlast;
75   } else {
76     cp = s + l - 1;
77     cpfirst = s;
78   }
79   flagdone = 0;
80   for (;;) {		/* e.g. LWSP <user@host> */
81     while (cpfirst <= cp &&
82 	(*cpfirst == ' ' || *cpfirst == '\t' || *cpfirst == '<')) cpfirst++;
83     while (cp >= cpfirst &&
84 	(*cp == ' ' || *cp == '\t' || *cp == '\n' || *cp == '>')) cp--;
85     if (cp >= cpfirst || flagdone)
86       break;
87     cp = s + l - 1;
88     cpfirst = s;
89     flagdone = 1;
90   }
91 
92   decodeHDR(cpfirst,cp - cpfirst + 1,out);
93   for (cpout = out->s, len = out->len; len > 0; --len, ++cpout)
94     if (*cpout == '@')
95       *cpout = '.';
96 }
97 
author_addr(stralloc * out,const char * s,unsigned int l)98 void author_addr(stralloc *out,const char *s,unsigned int l)
99 /* s is a string that contains a from: line argument\n. We parse */
100 /* s as follows: If there is an unquoted '<' we eliminate everything after */
101 /* it else if there is a unquoted ';' we eliminate everything after it.    */
102 /* Then, we eliminate LWSP and '"' from the beginning and end. Note that   */
103 /* this is not strict rfc822, but all we need is a display handle that     */
104 /* doesn't show the address. If in the remaining text there is a '@' we put*/
105 /* in a '.' instead. Also, there are some non-rfc822 from lines out there  */
106 /* and we still want to maximize the chance of getting a handle, even if it*/
107 /* costs a little extra work.*/
108 {
109   int squote = 0;
110   int dquote = 0;
111   int level = 0;
112   unsigned int len;
113   char ch;
114   const char *cp;
115   const char *cpgt = 0;
116   const char *cplt = 0;
117   const char *cpat = 0;
118   const char *cplast = 0;
119 
120   if (!s || !l)		/* Yuck - pass the buck */
121     if (!stralloc_copyb(out,"",0)) die_nomem();
122   cp = s; len = l;
123   cplast = s + len;
124 
125   for (cp = s, len = l; len > 0; --len, ++cp) {
126     ch = *cp;
127     if (squote)
128       squote = 0;
129     else if (ch == '\\')
130       squote = 1;
131     else if (ch == '"')		/* "name" <address@host> */
132       dquote = !dquote;
133     else if (dquote)
134       ;
135     else if (ch == '(') {
136       level++;
137     }
138     else if (ch == ')') {
139       level--;
140     }
141     else if (!level) {
142       if (ch == '<') {		/* name <address@host> */
143 	cplt = cp;
144       }
145       else if (ch == '>') {
146 	cpgt = cp;
147 	if (cplt)
148 	  break;
149       }
150       else if (ch == ';') {	/* address@host ;garbage */
151 	cplast = cp;
152 	break;
153       }
154       else if (ch == '@')
155 	cpat = cp;
156     }
157   }
158   /* make cplt point to first character of address, cpgt point to one character after end */
159   if (cplt && cpgt)
160     ++cplt;
161   else if (cpat) {
162     /* backup strategy, we found an @, grab everything from before and after. */
163     for (cplt = cpat - 1; cplt > cp && (*cplt != ' ' && *cplt != '\t'); --cplt)
164       ;
165     for (cpgt = cpat + 1; cpgt < cplast && (*cpgt != ' ' && *cpgt != '\t'); ++cpgt)
166       ;
167   }
168   else
169     cpgt = cplt = cp;		/* Empty result means no address found */
170   stralloc_copyb(out,cplt,cpgt-cplt);
171 }
172