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