s/qmail 4.3.20
Next generation secure email transport
Loading...
Searching...
No Matches
token822.c
Go to the documentation of this file.
1#include "stralloc.h"
2#include "alloc.h"
3#include "genalloc.h"
4#include "str.h"
5#include "token822.h"
6
7static struct token822 comma = { TOKEN822_COMMA };
8
9void token822_reverse(token822_alloc *ta)
10{
11 int i;
12 int n;
13 struct token822 temp;
14
15 n = ta->len - 1;
16 for (i = 0; i + i < n; ++i) {
17 temp = ta->t[i];
18 ta->t[i] = ta->t[n - i];
19 ta->t[n - i] = temp;
20 }
21}
22
23GEN_ALLOC_ready(token822_alloc,struct token822,t,len,a,i,n,x,30,token822_ready)
24GEN_ALLOC_readyplus(token822_alloc,struct token822,t,len,a,i,n,x,30,token822_readyplus)
25GEN_ALLOC_append(token822_alloc,struct token822,t,len,a,i,n,x,30,token822_readyplus,token822_append)
26
27static int needspace(int t1,int t2)
28{
29 if (!t1) return 0;
30 if (t1 == TOKEN822_COLON) return 1;
31 if (t1 == TOKEN822_COMMA) return 1;
32 if (t2 == TOKEN822_LEFT) return 1;
33
34 switch (t1) {
37 switch (t2) {
40 return 1;
41 }
42 }
43 return 0;
44}
45
46static int atomok(char ch)
47{
48 switch (ch) {
49 case ' ': case '\t': case '\r': case '\n':
50 case '(': case '[': case '"':
51 case '<': case '>': case ';': case ':':
52 case '@': case ',': case '.':
53 return 0;
54 }
55 return 1;
56}
57
58static void atomcheck(struct token822 *t)
59{
60 int i;
61 char ch;
62
63 for (i = 0; i < t->slen; ++i) {
64 ch = t->s[i];
65 if ((ch < 32) || (ch > 126) || (ch == ')') || (ch == ']') || (ch == '\\')) {
67 return;
68 }
69 }
70}
71
72int token822_unparse(stralloc *sa,token822_alloc *ta,unsigned int linelen)
73{
74 struct token822 *t;
75 int len;
76 int ch;
77 int i;
78 int j;
79 int lasttype;
80 int newtype;
81 char *s;
82 char *lineb;
83 char *linee;
84
85 len = 0;
86 lasttype = 0;
87
88 for (i = 0; i < ta->len; ++i) {
89 t = ta->t + i;
90 newtype = t->type;
91 if (needspace(lasttype,newtype)) ++len;
92 lasttype = newtype;
93
94 switch (newtype) {
95 case TOKEN822_COMMA:
96 len += 3; break;
97 case TOKEN822_AT: case TOKEN822_DOT:
100 ++len; break;
101 case TOKEN822_ATOM: case TOKEN822_QUOTE:
103 if (t->type != TOKEN822_ATOM) len += 2;
104 for (j = 0; j < t->slen; ++j)
105 switch (ch = t->s[j]) {
106 case '"': case '[': case ']': case '(': case ')':
107 case '\\': case '\r': case '\n': ++len;
108 default: ++len;
109 }
110 break;
111 }
112 }
113 len += 2;
114
115 if (!stralloc_ready(sa,len)) return -1;
116
117 s = sa->s;
118 lineb = s;
119 linee = 0;
120
121 lasttype = 0;
122
123 for (i = 0; i < ta->len; ++i) {
124 t = ta->t + i;
125 newtype = t->type;
126 if (needspace(lasttype,newtype)) *s++ = ' ';
127 lasttype = newtype;
128
129 switch (newtype) {
130 case TOKEN822_COMMA:
131 *s++ = ',';
132#define NSUW \
133 s[0] = '\n'; s[1] = ' '; \
134 if (linee && (!linelen || (s - lineb <= linelen))) \
135 { while (linee < s) { linee[0] = linee[2]; ++linee; } linee -= 2; } \
136 else { if (linee) lineb = linee + 1; linee = s; s += 2; }
137 NSUW
138 break;
139 case TOKEN822_AT: *s++ = '@'; break;
140 case TOKEN822_DOT: *s++ = '.'; break;
141 case TOKEN822_LEFT: *s++ = '<'; break;
142 case TOKEN822_RIGHT: *s++ = '>'; break;
143 case TOKEN822_SEMI: *s++ = ';'; break;
144 case TOKEN822_COLON: *s++ = ':'; break;
146 if (t->type == TOKEN822_QUOTE) *s++ = '"';
147 if (t->type == TOKEN822_LITERAL) *s++ = '[';
148 if (t->type == TOKEN822_COMMENT) *s++ = '(';
149
150 for (j = 0; j < t->slen; ++j)
151 switch (ch = t->s[j]) {
152 case '"': case '[': case ']': case '(': case ')':
153 case '\\': case '\r': case '\n': *s++ = '\\';
154 default: *s++ = ch;
155 }
156 if (t->type == TOKEN822_QUOTE) *s++ = '"';
157 if (t->type == TOKEN822_LITERAL) *s++ = ']';
158 if (t->type == TOKEN822_COMMENT) *s++ = ')';
159 break;
160 }
161 }
162 NSUW
163 --s;
164 sa->len = s - sa->s;
165 return 1;
166}
167
168int token822_unquote(stralloc *sa,token822_alloc *ta)
169{
170 struct token822 *t;
171 int len;
172 int i;
173 int j;
174 char *s;
175
176 len = 0;
177
178 for (i = 0; i < ta->len; ++i) {
179 t = ta->t + i;
180 switch (t->type) {
181 case TOKEN822_COMMA: case TOKEN822_AT:
182 case TOKEN822_DOT: case TOKEN822_LEFT:
183 case TOKEN822_RIGHT: case TOKEN822_SEMI:
184 case TOKEN822_COLON:
185 ++len; break;
186 case TOKEN822_LITERAL:
187 len += 2;
188 case TOKEN822_ATOM: case TOKEN822_QUOTE:
189 len += t->slen;
190 }
191 }
192
193 if (!stralloc_ready(sa,len)) return -1;
194
195 s = sa->s;
196
197 for (i = 0; i < ta->len; ++i) {
198 t = ta->t + i;
199 switch (t->type) {
200 case TOKEN822_COMMA: *s++ = ','; break;
201 case TOKEN822_AT: *s++ = '@'; break;
202 case TOKEN822_DOT: *s++ = '.'; break;
203 case TOKEN822_LEFT: *s++ = '<'; break;
204 case TOKEN822_RIGHT: *s++ = '>'; break;
205 case TOKEN822_SEMI: *s++ = ';'; break;
206 case TOKEN822_COLON: *s++ = ':'; break;
208 if (t->type == TOKEN822_LITERAL) *s++ = '[';
209 for (j = 0; j < t->slen; ++j)
210 *s++ = t->s[j];
211 if (t->type == TOKEN822_LITERAL) *s++ = ']';
212 break;
213 case TOKEN822_COMMENT: break;
214 }
215 }
216 sa->len = s - sa->s;
217 return 1;
218}
219
220int token822_parse(token822_alloc *ta,stralloc *sa,stralloc *buf)
221{
222 int i;
223 int salen;
224 int level;
225 struct token822 *t;
226 int numtoks;
227 int numchars;
228 char *cbuf;
229
230 salen = sa->len;
231
232 numchars = 0;
233 numtoks = 0;
234
235 for (i = 0; i < salen; ++i)
236 switch (sa->s[i]) {
237 case '.': case ',': case '@':
238 case '<': case '>': case ':': case ';':
239 ++numtoks; break;
240 case ' ': case '\t': case '\r': case '\n': break;
241 case ')': case ']': return 0;
242 /* other control chars and non-ASCII chars are also bad, in theory */
243 case '(':
244 level = 1;
245 while (level) {
246 if (++i >= salen) return 0;
247 switch (sa->s[i]) {
248 case '(': ++level; break;
249 case ')': --level; break;
250 case '\\': if (++i >= salen) return 0;
251 default: ++numchars;
252 }
253 }
254 ++numtoks;
255 break;
256 case '"':
257 level = 1;
258 while (level) {
259 if (++i >= salen) return 0;
260 switch (sa->s[i]) {
261 case '"': --level; break;
262 case '\\': if (++i >= salen) return 0;
263 default: ++numchars;
264 }
265 }
266 ++numtoks;
267 break;
268 case '[':
269 level = 1;
270 while (level) {
271 if (++i >= salen) return 0;
272 switch (sa->s[i]) {
273 case ']': --level; break;
274 case '\\': if (++i >= salen) return 0;
275 default: ++numchars;
276 }
277 }
278 ++numtoks;
279 break;
280 default:
281 do {
282 if (sa->s[i] == '\\') if (++i >= salen) break;
283 ++numchars;
284 if (++i >= salen) break;
285 } while (atomok(sa->s[i]));
286 --i;
287 ++numtoks;
288 }
289
290 if (!token822_ready(ta,numtoks)) return -1;
291 if (!stralloc_ready(buf,numchars)) return -1;
292 cbuf = buf->s;
293 ta->len = numtoks;
294
295 t = ta->t;
296
297 for (i = 0; i < salen; ++i)
298 switch (sa->s[i]) {
299 case '.': t->type = TOKEN822_DOT; ++t; break;
300 case ',': t->type = TOKEN822_COMMA; ++t; break;
301 case '@': t->type = TOKEN822_AT; ++t; break;
302 case '<': t->type = TOKEN822_LEFT; ++t; break;
303 case '>': t->type = TOKEN822_RIGHT; ++t; break;
304 case ':': t->type = TOKEN822_COLON; ++t; break;
305 case ';': t->type = TOKEN822_SEMI; ++t; break;
306 case ' ': case '\t': case '\r': case '\n': break;
307 case '(':
308 t->type = TOKEN822_COMMENT; t->s = cbuf; t->slen = 0;
309 level = 1;
310 while (level) {
311 ++i; /* assert: < salen */
312 switch (sa->s[i]) {
313 case '(': ++level; break;
314 case ')': --level; break;
315 case '\\': ++i; /* assert: < salen */
316 default: *cbuf++ = sa->s[i]; ++t->slen;
317 }
318 }
319 ++t;
320 break;
321 case '"':
322 t->type = TOKEN822_QUOTE; t->s = cbuf; t->slen = 0;
323 level = 1;
324 while (level) {
325 ++i; /* assert: < salen */
326 switch (sa->s[i]) {
327 case '"': --level; break;
328 case '\\': ++i; /* assert: < salen */
329 default: *cbuf++ = sa->s[i]; ++t->slen;
330 }
331 }
332 ++t;
333 break;
334 case '[':
335 t->type = TOKEN822_LITERAL; t->s = cbuf; t->slen = 0;
336 level = 1;
337 while (level) {
338 ++i; /* assert: < salen */
339 switch (sa->s[i]) {
340 case ']': --level; break;
341 case '\\': ++i; /* assert: < salen */
342 default: *cbuf++ = sa->s[i]; ++t->slen;
343 }
344 }
345 ++t;
346 break;
347 default:
348 t->type = TOKEN822_ATOM; t->s = cbuf; t->slen = 0;
349 do {
350 if (sa->s[i] == '\\') if (++i >= salen) break;
351 *cbuf++ = sa->s[i]; ++t->slen;
352 if (++i >= salen) break;
353 } while (atomok(sa->s[i]));
354 atomcheck(t);
355 --i;
356 ++t;
357 }
358 return 1;
359}
360
361static int gotaddr(token822_alloc *taout,token822_alloc *taaddr,int (*callback)())
362{
363 int i;
364
365 if (callback(taaddr) != 1)
366 return 0;
367
368 if (!token822_readyplus(taout,taaddr->len))
369 return 0;
370
371 for (i = 0; i < taaddr->len; ++i)
372 taout->t[taout->len++] = taaddr->t[i];
373
374 taaddr->len = 0;
375 return 1;
376}
377
378int token822_addrlist(token822_alloc *taout,token822_alloc *taaddr,token822_alloc *ta,int (*callback)())
379{
380 struct token822 *t;
381 struct token822 *beginning;
382 int ingroup;
383 int wordok;
384
385 taout->len = 0;
386 taaddr->len = 0;
387
388 if (!token822_readyplus(taout,1)) return -1;
389 if (!token822_readyplus(taaddr,1)) return -1;
390
391 ingroup = 0;
392 wordok = 1;
393
394 beginning = ta->t + 2;
395 t = ta->t + ta->len - 1;
396
397 /* rfc 822 address lists are easy to parse from right to left */
398
399#define FLUSH if (taaddr->len) if (!gotaddr(taout,taaddr,callback)) return -1;
400#define FLUSHCOMMA if (taaddr->len) { \
401if (!gotaddr(taout,taaddr,callback)) return -1; \
402if (!token822_append(taout,&comma)) return -1; }
403#define ADDRLEFT if (!token822_append(taaddr,t--)) return -1;
404#define OUTLEFT if (!token822_append(taout,t--)) return -1;
405
406 while (t >= beginning) {
407 switch (t->type) {
408 case TOKEN822_SEMI:
410 if (ingroup) return 0;
411 ingroup = 1;
412 wordok = 1;
413 break;
414 case TOKEN822_COLON:
415 FLUSH
416 if (!ingroup) return 0;
417 ingroup = 0;
418 while ((t >= beginning) && (t->type != TOKEN822_COMMA))
419 OUTLEFT
420 if (t >= beginning)
421 OUTLEFT
422 wordok = 1;
423 continue;
424 case TOKEN822_RIGHT:
426 OUTLEFT
427 while ((t >= beginning) && (t->type != TOKEN822_LEFT))
429 /* important to use address here even if it's empty: <> */
430 if (!gotaddr(taout,taaddr,callback)) return -1;
431 if (t < beginning) return 0;
432 OUTLEFT
433 while ((t >= beginning) && ((t->type == TOKEN822_COMMENT) ||
434 (t->type == TOKEN822_ATOM) || (t->type == TOKEN822_QUOTE) ||
435 (t->type == TOKEN822_AT) || (t->type == TOKEN822_DOT)))
436 OUTLEFT
437 wordok = 0;
438 continue;
439 case TOKEN822_ATOM: case TOKEN822_QUOTE:
440 case TOKEN822_LITERAL:
441 if (!wordok)
443 wordok = 0;
445 continue;
446 case TOKEN822_COMMENT:
447 /* comment is lexically a space; shouldn't affect wordok */
448 break;
449 case TOKEN822_COMMA:
450 FLUSH
451 wordok = 1;
452 break;
453 default:
454 wordok = 1;
456 continue;
457 }
458 OUTLEFT
459 }
460 FLUSH
461 ++t;
462 while (t > ta->t)
463 if (!token822_append(taout,--t)) return -1;
464
465 token822_reverse(taout);
466 return 1;
467}
stralloc sa
Definition: dnscname.c:11
char buf[100+FMT_ULONG]
Definition: hier.c:11
stralloc cbuf
Definition: newaliases.c:87
GEN_ALLOC_readyplus(prioq, struct prioq_elt, p, len, a, i, n, x, 100, prioq_readyplus)
Definition: prioq.c:5
int j
Definition: qmail-send.c:926
int slen
Definition: token822.h:9
char * s
Definition: token822.h:8
int type
Definition: token822.h:7
int token822_unparse(stralloc *sa, token822_alloc *ta, unsigned int linelen)
Definition: token822.c:72
int token822_addrlist(token822_alloc *taout, token822_alloc *taaddr, token822_alloc *ta, int(*callback)())
Definition: token822.c:378
#define FLUSH
GEN_ALLOC_ready(GEN_ALLOC_readyplus(token822_alloc, GEN_ALLOC_readyplus(struct token822, GEN_ALLOC_readyplus(t, GEN_ALLOC_readyplus(len, GEN_ALLOC_readyplus(a, GEN_ALLOC_readyplus(i, GEN_ALLOC_readyplus(n, GEN_ALLOC_readyplus(x, GEN_ALLOC_readyplus(30, token822_ready)
Definition: token822.c:23
#define NSUW
#define OUTLEFT
#define ADDRLEFT
int token822_unquote(stralloc *sa, token822_alloc *ta)
Definition: token822.c:168
#define FLUSHCOMMA
void token822_reverse(token822_alloc *ta)
Definition: token822.c:9
int token822_parse(token822_alloc *ta, stralloc *sa, stralloc *buf)
Definition: token822.c:220
#define TOKEN822_ATOM
Definition: token822.h:29
#define TOKEN822_COMMENT
Definition: token822.h:32
int token822_append(token822_alloc *, struct token822 *)
#define TOKEN822_RIGHT
Definition: token822.h:34
#define TOKEN822_LEFT
Definition: token822.h:33
#define TOKEN822_COMMA
Definition: token822.h:36
#define TOKEN822_AT
Definition: token822.h:35
#define TOKEN822_SEMI
Definition: token822.h:37
#define TOKEN822_DOT
Definition: token822.h:39
int token822_ready(token822_alloc *, unsigned int)
#define TOKEN822_COLON
Definition: token822.h:38
#define TOKEN822_LITERAL
Definition: token822.h:31
#define TOKEN822_QUOTE
Definition: token822.h:30
int token822_readyplus(token822_alloc *, unsigned int)