1 /* -*- C -*-
2 * Spamtest connection library
3 * File: mess822.c
4 * (C) Alex Tutubalin <lexa@lexa.ru>
5 * Apr-May 2003
6 *
7 * Created: Wed Apr 23 22:08:08 2003
8 */
9 #include "mess822.h"
10
11 #include <string.h>
12 #include <stdlib.h>
13
14 extern unsigned int byte_chr();
15 extern unsigned int byte_rchr();
16 extern void byte_copy();
17 extern void byte_copyr();
18 extern int byte_diff();
19 extern void byte_zero();
20
21 #define byte_equal(s,n,t) (!byte_diff((s),(n),(t)))
22
23 extern unsigned int str_rchr();
24 #define str_equal(s,t) (!strcmp((s),(t)))
25 #define str_len(s) strlen(s)
26
27 #define alloc(n) ((char*)malloc(n))
28 #define alloc_free(p) free(p);
29
30 //extern /*@null@*//*@out@*/char *alloc();
31 //extern void alloc_free();
32 extern int alloc_re(char **xx, int old, int new);
33
34
35 #define stralloc_0(sa) stralloc_append(sa,"")
36
docomment(stralloc * out,stralloc * comment)37 static int docomment(stralloc *out,stralloc *comment)
38 {
39 int i;
40 int j;
41 char ch;
42
43 for (j = i = 0;j < comment->len;++j) {
44 ch = comment->s[j];
45 if (ch == ' ') if (!i || (comment->s[i - 1] == ' ')) continue;
46 comment->s[i++] = ch;
47 }
48 while (i && (comment->s[i - 1] == ' ')) --i;
49 comment->len = 0;
50
51 if (i) {
52 if (!stralloc_0(out)) return 0;
53 if (!stralloc_catb(out,comment->s,i)) return 0;
54 if (!stralloc_append(out,"(")) return 0;
55 }
56
57 return 1;
58 }
59
doit(stralloc * out,int * state,stralloc * addr,stralloc * comment)60 static int doit(stralloc *out,int *state,stralloc *addr,stralloc *comment)
61 {
62 if (!*state) return 1;
63
64 if (!stralloc_0(out)) return 0;
65 if (*state == 1)
66 if (!stralloc_append(out,"@")) return 0;
67 if (!stralloc_catb(out,addr->s,addr->len)) return 0;
68 if (!stralloc_append(out,"+")) return 0;
69
70 if (!docomment(out,comment)) return 0;
71
72 *state = 0;
73 addr->len = 0;
74 return 1;
75 }
76
addcomment(char * tok,stralloc * comment)77 static int addcomment(char *tok,stralloc *comment)
78 {
79 int i;
80
81 if (*tok == ',') return 1;
82 if (*tok == ':') return 1;
83 if (*tok == ';') return 1;
84 if (*tok == '<') return 1;
85 if (*tok == '>') return 1;
86
87 if ((*tok == '=') || (*tok == '(')) ++tok;
88
89 i = str_len(tok);
90 while (i--)
91 if (!stralloc_append(comment,tok + i)) return 0;
92
93 return 1;
94 }
95
addaddr(char * tok,int * state,stralloc * addr,stralloc * comment)96 static int addaddr(char *tok,int *state,stralloc *addr,stralloc *comment)
97 {
98 int i;
99
100 if ((*tok != '=') && (*tok != '.') && (*tok != '@'))
101 return addcomment(tok,comment);
102
103 if (!*state) *state = 1;
104 if (*tok == '@') *state = 2;
105
106 if (*tok == '=') ++tok;
107
108 i = str_len(tok);
109 while (i--)
110 if (!stralloc_append(addr,tok + i)) return 0;
111
112 return 1;
113 }
114
115
116 #define RETURN(x) \
117 do{ \
118 CLEAN_SA(tokens); \
119 CLEAN_SA(addr); \
120 CLEAN_SA(comment); \
121 return x; \
122 }while(0);
123
124
125
mess822_addrlist(stralloc * out,char * in)126 int mess822_addrlist(stralloc *out,char *in)
127 {
128 int flagwordok = 1;
129 int flagphrase = 0;
130 int j;
131 int i;
132 char ch;
133 int state;
134 stralloc tokens={0,0,0};
135 stralloc addr={0,0,0};
136 stralloc comment={0,0,0};
137
138 CLEAN_SA(tokens);
139 CLEAN_SA(addr);
140 CLEAN_SA(comment);
141 state = 0;
142 // stralloc comment;
143
144 // comment = {0};
145
146 if (!mess822_token(&tokens,in)) RETURN(0);
147
148 if (!stralloc_copys(out,"")) RETURN(0);
149 if (!stralloc_copys(&comment,"")) RETURN(0);
150 if (!stralloc_copys(&addr,"")) RETURN(0);
151 state = 0;
152
153 j = tokens.len;
154
155 while (j) {
156 while (j--) if (!j || !tokens.s[j - 1]) break;
157
158 ch = tokens.s[j];
159 if (flagphrase) {
160 if ((ch != ',') && (ch != ';') && (ch != ':') && (ch != '>')) {
161 if (!addcomment(tokens.s + j,&comment)) RETURN(0);
162 continue;
163 }
164 if (!doit(out,&state,&addr,&comment)) RETURN(0);
165 flagphrase = 0;
166 flagwordok = 1;
167 }
168
169 switch(tokens.s[j]) {
170 case ' ': case '\t':
171 if (!addcomment(" ",&comment)) RETURN(0);
172 break;
173
174 case ';': case ',':
175 if (!doit(out,&state,&addr,&comment)) RETURN(0);
176 if (!docomment(out,&comment)) RETURN(0);
177 flagwordok = 1;
178 break;
179
180 case '(':
181 if (!addcomment(" ",&comment)) RETURN(0);
182 if (!addcomment(tokens.s + j,&comment)) RETURN(0);
183 if (!addcomment(" ",&comment)) RETURN(0);
184 break;
185
186 case '=':
187 if (!flagwordok)
188 if (!doit(out,&state,&addr,&comment)) RETURN(0);
189 if (!addaddr(tokens.s + j,&state,&addr,&comment)) RETURN(0);
190 flagwordok = 0;
191 break;
192
193 case '>':
194 if (!doit(out,&state,&addr,&comment)) RETURN(0);
195
196 if (!state) state = 1; /* <> is an address */
197
198 for (;;) {
199 if (!addaddr(tokens.s + j,&state,&addr,&comment)) RETURN(0);
200 if (!j) break;
201 while (j--) if (!j || !tokens.s[j - 1]) break;
202 if (tokens.s[j] == ':') break;
203 if (tokens.s[j] == '<') break;
204 }
205
206 if (tokens.s[j] == ':')
207 for (;;) {
208 if (!addcomment(tokens.s + j,&comment)) RETURN(0);
209 if (!j) break;
210 while (j--) if (!j || !tokens.s[j - 1]) break;
211 if (tokens.s[j] == '<') break;
212 }
213 /* fall through */
214
215 case ':':
216 flagphrase = 1;
217 break;
218
219 default:
220 if (!addaddr(tokens.s + j,&state,&addr,&comment)) RETURN(0);
221 flagwordok = 1;
222 break;
223 }
224 }
225
226 if (!doit(out,&state,&addr,&comment)) RETURN(0);
227 if (!docomment(out,&comment)) RETURN(0);
228
229 i = 0;
230 j = out->len - 1;
231
232 while (i < j) {
233 ch = out->s[i];
234 out->s[i] = out->s[j];
235 out->s[j] = ch;
236 ++i;
237 --j;
238 }
239
240 RETURN(1);
241 }
242
243
244 #if 1
245 // QUOTE
needquote(buf,len)246 static int needquote(buf,len)
247 char *buf;
248 int len;
249 {
250 int i;
251 char ch;
252
253 if (!len) return 1;
254 if (buf[0] == '.') return 1;
255 if (buf[len - 1] == '.') return 1;
256
257 for (i = 0;i < len - 1;++i)
258 if ((buf[i] == '.') && (buf[i + 1] == '.')) return 1;
259
260 for (i = 0;i < len;++i) {
261 ch = buf[i];
262 if (ch < 33) return 1;
263 if (ch > 126) return 1;
264 if (ch == '@') return 1;
265 if (ch == '<') return 1;
266 if (ch == '>') return 1;
267 if (ch == '[') return 1;
268 if (ch == ']') return 1;
269 if (ch == '(') return 1;
270 if (ch == ')') return 1;
271 if (ch == ',') return 1;
272 if (ch == ';') return 1;
273 if (ch == ':') return 1;
274 if (ch == '"') return 1;
275 if (ch == '\\') return 1;
276 }
277
278 return 0;
279 }
280
doit2(out,buf,len,pre,post)281 static int doit2(out,buf,len,pre,post)
282 stralloc *out;
283 char *buf;
284 int len;
285 char *pre;
286 char *post;
287 {
288 char ch;
289
290 if (!stralloc_cats(out,pre)) return 0;
291
292 while (len--) {
293 ch = *buf++;
294 if (ch == '\n') ch = 0;
295 if ((ch == 0) || (ch == '\r') || (ch == '"') || (ch == '\\') || (ch == '[') || (ch == ']'))
296 if (!stralloc_append(out,"\\")) return 0;
297 if (!stralloc_append(out,&ch)) return 0;
298 }
299
300 if (!stralloc_cats(out,post)) return 0;
301 return 1;
302 }
303
mess822_quoteplus(stralloc * out,char * addr,char * comment)304 int mess822_quoteplus(stralloc *out,char *addr,char *comment)
305 {
306 int i;
307 char *quote;
308 int flagempty;
309 int flagbracket;
310
311 flagempty = 0;
312 if (str_equal(addr,"")) flagempty = 1;
313 if (str_equal(addr,"@")) flagempty = 1;
314
315 flagbracket = flagempty;
316
317 if (comment) {
318 if (!doit2(out,comment,str_len(comment),"\"","\" ")) return 0;
319 flagbracket = 1;
320 }
321
322 if (flagbracket) if (!stralloc_cats(out,"<")) return 0;
323
324 if (!flagempty) {
325 i = str_rchr(addr,'@');
326 quote = needquote(addr,i) ? "\"" : "";
327 if (!doit2(out,addr,i,quote,quote)) return 0;
328
329 addr += i;
330 if (*addr == '@') ++addr;
331
332 i = str_len(addr);
333 if (i) {
334 if (!stralloc_append(out,"@")) return 0;
335
336 quote = needquote(addr,i) ? "\"" : "";
337
338 if (*quote && (i >= 2) && (addr[0] == '[') && (addr[i - 1] == ']')) {
339 if (!doit2(out,addr + 1,i - 2,"[","]")) return 0;
340 }
341 else
342 if (!doit2(out,addr,i,quote,quote)) return 0;
343 }
344 }
345
346 if (flagbracket) if (!stralloc_cats(out,">")) return 0;
347
348 return 1;
349 }
350
mess822_quote(stralloc * out,char * addr,char * comment)351 int mess822_quote(stralloc *out,char *addr,char *comment)
352 {
353 if (!stralloc_copys(out,"")) return 0;
354 return mess822_quoteplus(out,addr,comment);
355 }
356
mess822_quotelist(stralloc * out,stralloc * in)357 int mess822_quotelist(stralloc *out,stralloc *in)
358 {
359 int i;
360 int j;
361 int comment;
362
363 if (!stralloc_copys(out,"")) return 0;
364
365 comment = 0;
366
367 for (j = i = 0;j < in->len;++j)
368 if (!in->s[j]) {
369 if (in->s[i] == '(') {
370 if (comment)
371 if (!doit2(out,in->s + comment,str_len(in->s + comment),"\"","\": ;,\n ")) return 0;
372 comment = i + 1;
373 }
374 else if (in->s[i] == '+') {
375 if (!mess822_quoteplus(out,in->s + i + 1,comment ? in->s + comment : (char *) 0)) return 0;
376 if (!stralloc_cats(out,",\n ")) return 0;
377 comment = 0;
378 }
379 i = j + 1;
380 }
381
382 if (comment)
383 if (!doit2(out,in->s + comment,str_len(in->s + comment),"\"","\": ;,\n ")) return 0;
384
385 if (out->len && (out->s[out->len - 1] == ' ')) --out->len;
386 if (out->len && (out->s[out->len - 1] == ' ')) --out->len;
387 if (out->len && (out->s[out->len - 1] == '\n')) --out->len;
388 if (out->len && (out->s[out->len - 1] == ',')) --out->len;
389
390 return 1;
391 }
392
393
mess822_token(stralloc * out,char * in)394 int mess822_token(stralloc *out, char* in)
395 {
396 char ch;
397 int level;
398
399 if (!stralloc_copys(out,"")) return 0;
400
401 for (;;)
402 switch(ch = *in++) {
403 case 0:
404 return 1;
405
406 case '"':
407 if (!stralloc_append(out,"=")) return 0;
408 while (*in) {
409 ch = *in++;
410 if (ch == '"') break;
411 if (ch == '\\') if (*in) ch = *in++;
412 if (!stralloc_append(out,&ch)) return 0;
413 }
414 if (!stralloc_0(out)) return 0;
415 break;
416
417 case '[':
418 if (!stralloc_append(out,"=")) return 0;
419 if (!stralloc_append(out,"[")) return 0;
420 while (*in) {
421 ch = *in++;
422 if (ch == ']') break;
423 if (ch == '\\') if (*in) ch = *in++;
424 if (!stralloc_append(out,&ch)) return 0;
425 }
426 if (!stralloc_append(out,"]")) return 0;
427 if (!stralloc_0(out)) return 0;
428 break;
429
430 case '(':
431 if (!stralloc_append(out,"(")) return 0;
432 level = 1;
433 while (*in) {
434 ch = *in++;
435 if (ch == ')') {
436 --level;
437 if (!level) break;
438 if (!stralloc_append(out,")")) return 0;
439 continue;
440 }
441 if (ch == '(') {
442 if (level) if (!stralloc_append(out,"(")) return 0;
443 ++level;
444 continue;
445 }
446 if (ch == '\\') if (*in) ch = *in++;
447 if (!stralloc_append(out,&ch)) return 0;
448 }
449 if (!stralloc_0(out)) return 0;
450 break;
451
452 case '<': case '>': case ',': case ';': case ':':
453 case '@': case '.':
454 case ' ': case '\t':
455 if (!stralloc_append(out,&ch)) return 0;
456 if (!stralloc_0(out)) return 0;
457 break;
458
459 default:
460 if (!stralloc_append(out,"=")) return 0;
461
462 for (;;) {
463 if (ch == '\\') if (*in) ch = *in++;
464 if (!stralloc_append(out,&ch)) return 0;
465 ch = *in;
466 if (!ch) break;
467 if (ch == '"') break;
468 if (ch == '[') break;
469 if (ch == '(') break;
470 if (ch == '<') break;
471 if (ch == '>') break;
472 if (ch == ',') break;
473 if (ch == ';') break;
474 if (ch == ':') break;
475 if (ch == '@') break;
476 if (ch == '.') break;
477 if (ch == ' ') break;
478 if (ch == '\t') break;
479 ++in;
480 }
481
482 if (!stralloc_0(out)) return 0;
483 break;
484 }
485 }
486 #endif
487
alloc_re(char ** xx,int old,int new)488 int alloc_re(char **xx, int old, int new)
489 {
490 char *y = (char*)malloc(new);
491 if(!y) return 0;
492 memmove(y,*xx,old);
493 free(*xx);
494 *xx=y;
495 return 1;
496 }
497
byte_chr(s,n,c)498 unsigned int byte_chr(s,n,c)
499 char *s;
500 register unsigned int n;
501 int c;
502 {
503 register char ch;
504 register char *t;
505
506 ch = c;
507 t = s;
508 for (;;) {
509 if (!n) break; if (*t == ch) break; ++t; --n;
510 if (!n) break; if (*t == ch) break; ++t; --n;
511 if (!n) break; if (*t == ch) break; ++t; --n;
512 if (!n) break; if (*t == ch) break; ++t; --n;
513 }
514 return t - s;
515 }
516
517
byte_rchr(s,n,c)518 unsigned int byte_rchr(s,n,c)
519 char *s;
520 register unsigned int n;
521 int c;
522 {
523 register char ch;
524 register char *t;
525 register char *u;
526
527 ch = c;
528 t = s;
529 u = 0;
530 for (;;) {
531 if (!n) break; if (*t == ch) u = t; ++t; --n;
532 if (!n) break; if (*t == ch) u = t; ++t; --n;
533 if (!n) break; if (*t == ch) u = t; ++t; --n;
534 if (!n) break; if (*t == ch) u = t; ++t; --n;
535 }
536 if (!u) u = t;
537 return u - s;
538 }
byte_copy(to,n,from)539 void byte_copy(to,n,from)
540 register char *to;
541 register unsigned int n;
542 register char *from;
543 {
544 for (;;) {
545 if (!n) return; *to++ = *from++; --n;
546 if (!n) return; *to++ = *from++; --n;
547 if (!n) return; *to++ = *from++; --n;
548 if (!n) return; *to++ = *from++; --n;
549 }
550 }
551
byte_copyr(to,n,from)552 void byte_copyr(to,n,from)
553 register char *to;
554 register unsigned int n;
555 register char *from;
556 {
557 to += n;
558 from += n;
559 for (;;) {
560 if (!n) return; *--to = *--from; --n;
561 if (!n) return; *--to = *--from; --n;
562 if (!n) return; *--to = *--from; --n;
563 if (!n) return; *--to = *--from; --n;
564 }
565 }
566
str_chr(s,c)567 unsigned int str_chr(s,c)
568 register char *s;
569 int c;
570 {
571 register char ch;
572 register char *t;
573
574 ch = c;
575 t = s;
576 for (;;) {
577 if (!*t) break; if (*t == ch) break; ++t;
578 if (!*t) break; if (*t == ch) break; ++t;
579 if (!*t) break; if (*t == ch) break; ++t;
580 if (!*t) break; if (*t == ch) break; ++t;
581 }
582 return t - s;
583 }
584
str_rchr(s,c)585 unsigned int str_rchr(s,c)
586 register char *s;
587 int c;
588 {
589 register char ch;
590 register char *t;
591 register char *u;
592
593 ch = c;
594 t = s;
595 u = 0;
596 for (;;) {
597 if (!*t) break; if (*t == ch) u = t; ++t;
598 if (!*t) break; if (*t == ch) u = t; ++t;
599 if (!*t) break; if (*t == ch) u = t; ++t;
600 if (!*t) break; if (*t == ch) u = t; ++t;
601 }
602 if (!u) u = t;
603 return u - s;
604 }
605
606
stralloc_cat(stralloc * sato,stralloc * safrom)607 int stralloc_cat(stralloc *sato,stralloc *safrom)
608 {
609 return stralloc_catb(sato,safrom->s,safrom->len);
610 }
611
stralloc_catb(stralloc * sa,char * s,unsigned int n)612 int stralloc_catb(stralloc *sa,char *s, unsigned int n)
613 {
614 if (!sa->s) return stralloc_copyb(sa,s,n);
615 if (!stralloc_readyplus(sa,n + 1)) return 0;
616 byte_copy(sa->s + sa->len,n,s);
617 sa->len += n;
618 sa->s[sa->len] = 'Z'; /* ``offensive programming'' */
619 return 1;
620 }
621
622
stralloc_cats(stralloc * sa,char * s)623 int stralloc_cats(stralloc *sa, char *s)
624 {
625 return stralloc_catb(sa,s,str_len(s));
626 }
627
stralloc_copy(stralloc * sato,stralloc * safrom)628 int stralloc_copy(stralloc *sato,stralloc *safrom)
629 {
630 return stralloc_copyb(sato,safrom->s,safrom->len);
631 }
632
stralloc_readyplus(stralloc * x,unsigned int n)633 int stralloc_readyplus(stralloc *x, unsigned int n)
634 {
635 register unsigned int i;
636 if (x->s) {
637 i = x->a;
638 n += x->len;
639 if (n > i) {
640 x->a = 30 + n + (n >> 3);
641 if (alloc_re(&x->s,i * sizeof(char),x->a * sizeof(char)))
642 return 1;
643 x->a = i;
644 return 0;
645 }
646 return 1;
647 }
648 x->len = 0;
649 return !!(x->s = (char *) alloc((x->a = n) * sizeof(char)));
650 }
651
652
653
654
stralloc_ready(stralloc * x,unsigned int n)655 int stralloc_ready(stralloc *x, unsigned int n)
656 {
657 register unsigned int i;
658 if (x->s)
659 {
660 i = x->a;
661 if (n > i) {
662 x->a = 30 + n + (n >> 3);
663 if (alloc_re(&x->s,i * sizeof(char),x->a * sizeof(char)))
664 return 1;
665 x->a = i;
666 return 0;
667 }
668 return 1;
669 }
670 x->len = 0;
671 return !!(x->s = (char *) alloc((x->a = n) * sizeof(char)));
672 }
673
674
675
676
677
stralloc_append(stralloc * x,char * i)678 int stralloc_append(stralloc *x, char *i)
679 {
680 if (!stralloc_readyplus(x,1))
681 return 0;
682 x->s[x->len++] = *i;
683 return 1;
684 }
685
686
stralloc_copyb(stralloc * sa,char * s,unsigned int n)687 int stralloc_copyb(stralloc * sa, char *s, unsigned int n)
688 {
689 if (!stralloc_ready(sa,n + 1)) return 0;
690 byte_copy(sa->s,n,s);
691 sa->len = n;
692 sa->s[n] = 'Z'; /* ``offensive programming'' */
693 return 1;
694 }
695
stralloc_copys(stralloc * sa,char * s)696 int stralloc_copys(stralloc *sa, char *s)
697 {
698 return stralloc_copyb(sa,s,str_len(s));
699 }
700
701