s/qmail 4.2.29a
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;
99 ++len; break;
101 if (t->type != TOKEN822_ATOM) len += 2;
102 for (j = 0; j < t->slen; ++j)
103 switch (ch = t->s[j]) {
104 case '"': case '[': case ']': case '(': case ')':
105 case '\\': case '\r': case '\n': ++len;
106 default: ++len;
107 }
108 break;
109 }
110 }
111 len += 2;
112
113 if (!stralloc_ready(sa,len)) return -1;
114
115 s = sa->s;
116 lineb = s;
117 linee = 0;
118
119 lasttype = 0;
120
121 for (i = 0; i < ta->len; ++i) {
122 t = ta->t + i;
123 newtype = t->type;
124 if (needspace(lasttype,newtype)) *s++ = ' ';
125 lasttype = newtype;
126
127 switch (newtype) {
128 case TOKEN822_COMMA:
129 *s++ = ',';
130#define NSUW \
131 s[0] = '\n'; s[1] = ' '; \
132 if (linee && (!linelen || (s - lineb <= linelen))) \
133 { while (linee < s) { linee[0] = linee[2]; ++linee; } linee -= 2; } \
134 else { if (linee) lineb = linee + 1; linee = s; s += 2; }
135 NSUW
136 break;
137 case TOKEN822_AT: *s++ = '@'; break;
138 case TOKEN822_DOT: *s++ = '.'; break;
139 case TOKEN822_LEFT: *s++ = '<'; break;
140 case TOKEN822_RIGHT: *s++ = '>'; break;
141 case TOKEN822_SEMI: *s++ = ';'; break;
142 case TOKEN822_COLON: *s++ = ':'; break;
144 if (t->type == TOKEN822_QUOTE) *s++ = '"';
145 if (t->type == TOKEN822_LITERAL) *s++ = '[';
146 if (t->type == TOKEN822_COMMENT) *s++ = '(';
147
148 for (j = 0; j < t->slen; ++j)
149 switch (ch = t->s[j]) {
150 case '"': case '[': case ']': case '(': case ')':
151 case '\\': case '\r': case '\n': *s++ = '\\';
152 default: *s++ = ch;
153 }
154 if (t->type == TOKEN822_QUOTE) *s++ = '"';
155 if (t->type == TOKEN822_LITERAL) *s++ = ']';
156 if (t->type == TOKEN822_COMMENT) *s++ = ')';
157 break;
158 }
159 }
160 NSUW
161 --s;
162 sa->len = s - sa->s;
163 return 1;
164}
165
166int token822_unquote(stralloc *sa,token822_alloc *ta)
167{
168 struct token822 *t;
169 int len;
170 int i;
171 int j;
172 char *s;
173
174 len = 0;
175
176 for (i = 0; i < ta->len; ++i) {
177 t = ta->t + i;
178 switch (t->type) {
181 ++len; break;
182 case TOKEN822_LITERAL:
183 len += 2;
184 case TOKEN822_ATOM: case TOKEN822_QUOTE:
185 len += t->slen;
186 }
187 }
188
189 if (!stralloc_ready(sa,len)) return -1;
190
191 s = sa->s;
192
193 for (i = 0; i < ta->len; ++i) {
194 t = ta->t + i;
195 switch (t->type) {
196 case TOKEN822_COMMA: *s++ = ','; break;
197 case TOKEN822_AT: *s++ = '@'; break;
198 case TOKEN822_DOT: *s++ = '.'; break;
199 case TOKEN822_LEFT: *s++ = '<'; break;
200 case TOKEN822_RIGHT: *s++ = '>'; break;
201 case TOKEN822_SEMI: *s++ = ';'; break;
202 case TOKEN822_COLON: *s++ = ':'; break;
204 if (t->type == TOKEN822_LITERAL) *s++ = '[';
205 for (j = 0; j < t->slen; ++j)
206 *s++ = t->s[j];
207 if (t->type == TOKEN822_LITERAL) *s++ = ']';
208 break;
209 case TOKEN822_COMMENT: break;
210 }
211 }
212 sa->len = s - sa->s;
213 return 1;
214}
215
216int token822_parse(token822_alloc *ta,stralloc *sa,stralloc *buf)
217{
218 int i;
219 int salen;
220 int level;
221 struct token822 *t;
222 int numtoks;
223 int numchars;
224 char *cbuf;
225
226 salen = sa->len;
227
228 numchars = 0;
229 numtoks = 0;
230
231 for (i = 0; i < salen; ++i)
232 switch (sa->s[i]) {
233 case '.': case ',': case '@': case '<': case '>': case ':': case ';':
234 ++numtoks; break;
235 case ' ': case '\t': case '\r': case '\n': break;
236 case ')': case ']': return 0;
237 /* other control chars and non-ASCII chars are also bad, in theory */
238 case '(':
239 level = 1;
240 while (level) {
241 if (++i >= salen) return 0;
242 switch (sa->s[i]) {
243 case '(': ++level; break;
244 case ')': --level; break;
245 case '\\': if (++i >= salen) return 0;
246 default: ++numchars;
247 }
248 }
249 ++numtoks;
250 break;
251 case '"':
252 level = 1;
253 while (level) {
254 if (++i >= salen) return 0;
255 switch (sa->s[i]) {
256 case '"': --level; break;
257 case '\\': if (++i >= salen) return 0;
258 default: ++numchars;
259 }
260 }
261 ++numtoks;
262 break;
263 case '[':
264 level = 1;
265 while (level) {
266 if (++i >= salen) return 0;
267 switch (sa->s[i]) {
268 case ']': --level; break;
269 case '\\': if (++i >= salen) return 0;
270 default: ++numchars;
271 }
272 }
273 ++numtoks;
274 break;
275 default:
276 do {
277 if (sa->s[i] == '\\') if (++i >= salen) break;
278 ++numchars;
279 if (++i >= salen) break;
280 } while (atomok(sa->s[i]));
281 --i;
282 ++numtoks;
283 }
284
285 if (!token822_ready(ta,numtoks)) return -1;
286 if (!stralloc_ready(buf,numchars)) return -1;
287 cbuf = buf->s;
288 ta->len = numtoks;
289
290 t = ta->t;
291
292 for (i = 0; i < salen; ++i)
293 switch (sa->s[i]) {
294 case '.': t->type = TOKEN822_DOT; ++t; break;
295 case ',': t->type = TOKEN822_COMMA; ++t; break;
296 case '@': t->type = TOKEN822_AT; ++t; break;
297 case '<': t->type = TOKEN822_LEFT; ++t; break;
298 case '>': t->type = TOKEN822_RIGHT; ++t; break;
299 case ':': t->type = TOKEN822_COLON; ++t; break;
300 case ';': t->type = TOKEN822_SEMI; ++t; break;
301 case ' ': case '\t': case '\r': case '\n': break;
302 case '(':
303 t->type = TOKEN822_COMMENT; t->s = cbuf; t->slen = 0;
304 level = 1;
305 while (level) {
306 ++i; /* assert: < salen */
307 switch (sa->s[i]) {
308 case '(': ++level; break;
309 case ')': --level; break;
310 case '\\': ++i; /* assert: < salen */
311 default: *cbuf++ = sa->s[i]; ++t->slen;
312 }
313 }
314 ++t;
315 break;
316 case '"':
317 t->type = TOKEN822_QUOTE; t->s = cbuf; t->slen = 0;
318 level = 1;
319 while (level) {
320 ++i; /* assert: < salen */
321 switch (sa->s[i]) {
322 case '"': --level; break;
323 case '\\': ++i; /* assert: < salen */
324 default: *cbuf++ = sa->s[i]; ++t->slen;
325 }
326 }
327 ++t;
328 break;
329 case '[':
330 t->type = TOKEN822_LITERAL; t->s = cbuf; t->slen = 0;
331 level = 1;
332 while (level) {
333 ++i; /* assert: < salen */
334 switch (sa->s[i]) {
335 case ']': --level; break;
336 case '\\': ++i; /* assert: < salen */
337 default: *cbuf++ = sa->s[i]; ++t->slen;
338 }
339 }
340 ++t;
341 break;
342 default:
343 t->type = TOKEN822_ATOM; t->s = cbuf; t->slen = 0;
344 do {
345 if (sa->s[i] == '\\') if (++i >= salen) break;
346 *cbuf++ = sa->s[i]; ++t->slen;
347 if (++i >= salen) break;
348 } while (atomok(sa->s[i]));
349 atomcheck(t);
350 --i;
351 ++t;
352 }
353 return 1;
354}
355
356static int gotaddr(token822_alloc *taout,token822_alloc *taaddr,int (*callback)())
357{
358 int i;
359
360 if (callback(taaddr) != 1)
361 return 0;
362
363 if (!token822_readyplus(taout,taaddr->len))
364 return 0;
365
366 for (i = 0; i < taaddr->len; ++i)
367 taout->t[taout->len++] = taaddr->t[i];
368
369 taaddr->len = 0;
370 return 1;
371}
372
373int token822_addrlist(token822_alloc *taout,token822_alloc *taaddr,token822_alloc *ta,int (*callback)())
374{
375 struct token822 *t;
376 struct token822 *beginning;
377 int ingroup;
378 int wordok;
379
380 taout->len = 0;
381 taaddr->len = 0;
382
383 if (!token822_readyplus(taout,1)) return -1;
384 if (!token822_readyplus(taaddr,1)) return -1;
385
386 ingroup = 0;
387 wordok = 1;
388
389 beginning = ta->t + 2;
390 t = ta->t + ta->len - 1;
391
392 /* rfc 822 address lists are easy to parse from right to left */
393
394#define FLUSH if (taaddr->len) if (!gotaddr(taout,taaddr,callback)) return -1;
395#define FLUSHCOMMA if (taaddr->len) { \
396if (!gotaddr(taout,taaddr,callback)) return -1; \
397if (!token822_append(taout,&comma)) return -1; }
398#define ADDRLEFT if (!token822_append(taaddr,t--)) return -1;
399#define OUTLEFT if (!token822_append(taout,t--)) return -1;
400
401 while (t >= beginning) {
402 switch (t->type) {
403 case TOKEN822_SEMI:
405 if (ingroup) return 0;
406 ingroup = 1;
407 wordok = 1;
408 break;
409 case TOKEN822_COLON:
410 FLUSH
411 if (!ingroup) return 0;
412 ingroup = 0;
413 while ((t >= beginning) && (t->type != TOKEN822_COMMA))
414 OUTLEFT
415 if (t >= beginning)
416 OUTLEFT
417 wordok = 1;
418 continue;
419 case TOKEN822_RIGHT:
421 OUTLEFT
422 while ((t >= beginning) && (t->type != TOKEN822_LEFT))
424 /* important to use address here even if it's empty: <> */
425 if (!gotaddr(taout,taaddr,callback)) return -1;
426 if (t < beginning) return 0;
427 OUTLEFT
428 while ((t >= beginning) && ((t->type == TOKEN822_COMMENT) ||
429 (t->type == TOKEN822_ATOM) || (t->type == TOKEN822_QUOTE) ||
430 (t->type == TOKEN822_AT) || (t->type == TOKEN822_DOT)))
431 OUTLEFT
432 wordok = 0;
433 continue;
435 if (!wordok)
437 wordok = 0;
439 continue;
440 case TOKEN822_COMMENT:
441 /* comment is lexically a space; shouldn't affect wordok */
442 break;
443 case TOKEN822_COMMA:
444 FLUSH
445 wordok = 1;
446 break;
447 default:
448 wordok = 1;
450 continue;
451 }
452 OUTLEFT
453 }
454 FLUSH
455 ++t;
456 while (t > ta->t)
457 if (!token822_append(taout,--t)) return -1;
458
459 token822_reverse(taout);
460 return 1;
461}
stralloc sa
Definition: dnscname.c:11
char buf[100+FMT_ULONG]
Definition: hier.c:10
stralloc cbuf
Definition: newaliases.c:86
void gotaddr()
Definition: newaliases.c:109
GEN_ALLOC_readyplus(prioq, struct prioq_elt, p, len, a, i, n, x, 100, prioq_readyplus)
Definition: prioq.c:5
void temp()
Definition: qmail-inject.c:64
int j
Definition: qmail-send.c:920
int slen
Definition: token822.h:9
char * s
Definition: token822.h:8
int type
Definition: token822.h:7
#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
#define FLUSHCOMMA
int token822_parse(token822_alloc *ta, stralloc *sa, stralloc *buf)
Definition: token822.c:216
#define TOKEN822_ATOM
Definition: token822.h:24
int token822_ready()
#define TOKEN822_COMMENT
Definition: token822.h:27
#define TOKEN822_RIGHT
Definition: token822.h:29
#define TOKEN822_LEFT
Definition: token822.h:28
#define TOKEN822_COMMA
Definition: token822.h:31
void token822_reverse()
#define TOKEN822_AT
Definition: token822.h:30
int token822_unparse()
int token822_append()
int token822_readyplus()
#define TOKEN822_SEMI
Definition: token822.h:32
int token822_unquote()
#define TOKEN822_DOT
Definition: token822.h:34
int token822_addrlist()
#define TOKEN822_COLON
Definition: token822.h:33
#define TOKEN822_LITERAL
Definition: token822.h:26
#define TOKEN822_QUOTE
Definition: token822.h:25