180ee5cbfSDavid du Colombier #include <u.h>
280ee5cbfSDavid du Colombier #include <libc.h>
380ee5cbfSDavid du Colombier #include <bio.h>
480ee5cbfSDavid du Colombier #include <regexp.h>
580ee5cbfSDavid du Colombier #include "spam.h"
680ee5cbfSDavid du Colombier
780ee5cbfSDavid du Colombier enum {
880ee5cbfSDavid du Colombier Quanta = 8192,
980ee5cbfSDavid du Colombier Minbody = 6000,
1080ee5cbfSDavid du Colombier HdrMax = 15,
1180ee5cbfSDavid du Colombier };
1280ee5cbfSDavid du Colombier
1380ee5cbfSDavid du Colombier typedef struct keyword Keyword;
1480ee5cbfSDavid du Colombier typedef struct word Word;
1580ee5cbfSDavid du Colombier
1680ee5cbfSDavid du Colombier struct word{
1780ee5cbfSDavid du Colombier char *string;
1880ee5cbfSDavid du Colombier int n;
1980ee5cbfSDavid du Colombier };
2080ee5cbfSDavid du Colombier
2180ee5cbfSDavid du Colombier struct keyword{
2280ee5cbfSDavid du Colombier char *string;
2380ee5cbfSDavid du Colombier int value;
2480ee5cbfSDavid du Colombier };
2580ee5cbfSDavid du Colombier
2680ee5cbfSDavid du Colombier Word htmlcmds[] =
2780ee5cbfSDavid du Colombier {
2880ee5cbfSDavid du Colombier "html", 4,
2980ee5cbfSDavid du Colombier "!doctype html", 13,
3080ee5cbfSDavid du Colombier 0,
3180ee5cbfSDavid du Colombier
3280ee5cbfSDavid du Colombier };
3380ee5cbfSDavid du Colombier
3480ee5cbfSDavid du Colombier Word hrefs[] =
3580ee5cbfSDavid du Colombier {
3680ee5cbfSDavid du Colombier "a href=", 7,
3780ee5cbfSDavid du Colombier "a title=", 8,
38*9a747e4fSDavid du Colombier "a target=", 9,
3980ee5cbfSDavid du Colombier "base href=", 10,
4080ee5cbfSDavid du Colombier "img src=", 8,
4180ee5cbfSDavid du Colombier "img border=", 11,
4280ee5cbfSDavid du Colombier "form action=", 12,
4380ee5cbfSDavid du Colombier "!--", 3,
4480ee5cbfSDavid du Colombier 0,
4580ee5cbfSDavid du Colombier
4680ee5cbfSDavid du Colombier };
4780ee5cbfSDavid du Colombier
4880ee5cbfSDavid du Colombier /*
4980ee5cbfSDavid du Colombier * RFC822 header keywords to look for for fractured header.
5080ee5cbfSDavid du Colombier * all lengths must be less than HdrMax defined above.
5180ee5cbfSDavid du Colombier */
5280ee5cbfSDavid du Colombier Word hdrwords[] =
5380ee5cbfSDavid du Colombier {
5480ee5cbfSDavid du Colombier "cc:", 3,
5580ee5cbfSDavid du Colombier "bcc:", 4,
5680ee5cbfSDavid du Colombier "to:", 3,
5780ee5cbfSDavid du Colombier 0, 0,
5880ee5cbfSDavid du Colombier
5980ee5cbfSDavid du Colombier };
6080ee5cbfSDavid du Colombier
6180ee5cbfSDavid du Colombier Keyword keywords[] =
6280ee5cbfSDavid du Colombier {
6380ee5cbfSDavid du Colombier "header", HoldHeader,
6480ee5cbfSDavid du Colombier "line", SaveLine,
6580ee5cbfSDavid du Colombier "hold", Hold,
6680ee5cbfSDavid du Colombier "dump", Dump,
6780ee5cbfSDavid du Colombier "loff", Lineoff,
6880ee5cbfSDavid du Colombier 0, Nactions,
6980ee5cbfSDavid du Colombier };
7080ee5cbfSDavid du Colombier
7180ee5cbfSDavid du Colombier Patterns patterns[] = {
7280ee5cbfSDavid du Colombier [Dump] { "DUMP:", 0, 0 },
7380ee5cbfSDavid du Colombier [HoldHeader] { "HEADER:", 0, 0 },
7480ee5cbfSDavid du Colombier [Hold] { "HOLD:", 0, 0 },
7580ee5cbfSDavid du Colombier [SaveLine] { "LINE:", 0, 0 },
7680ee5cbfSDavid du Colombier [Lineoff] { "LINEOFF:", 0, 0 },
7780ee5cbfSDavid du Colombier [Nactions] { 0, 0, 0 },
7880ee5cbfSDavid du Colombier };
7980ee5cbfSDavid du Colombier
8080ee5cbfSDavid du Colombier static char* endofhdr(char*, char*);
8180ee5cbfSDavid du Colombier static int escape(char**);
8280ee5cbfSDavid du Colombier static int extract(char*);
8380ee5cbfSDavid du Colombier static int findkey(char*);
8480ee5cbfSDavid du Colombier static int hash(int);
8580ee5cbfSDavid du Colombier static int isword(Word*, char*, int);
8680ee5cbfSDavid du Colombier static void parsealt(Biobuf*, char*, Spat**);
8780ee5cbfSDavid du Colombier
8880ee5cbfSDavid du Colombier /*
8980ee5cbfSDavid du Colombier * The canonicalizer: convert input to canonical representation
9080ee5cbfSDavid du Colombier */
9180ee5cbfSDavid du Colombier char*
readmsg(Biobuf * bp,int * hsize,int * bufsize)9280ee5cbfSDavid du Colombier readmsg(Biobuf *bp, int *hsize, int *bufsize)
9380ee5cbfSDavid du Colombier {
9480ee5cbfSDavid du Colombier char *p, *buf;
9580ee5cbfSDavid du Colombier int n, offset, eoh, bsize, delta;
9680ee5cbfSDavid du Colombier
9780ee5cbfSDavid du Colombier buf = 0;
9880ee5cbfSDavid du Colombier offset = 0;
9980ee5cbfSDavid du Colombier if(bufsize)
10080ee5cbfSDavid du Colombier *bufsize = 0;
10180ee5cbfSDavid du Colombier if(hsize)
10280ee5cbfSDavid du Colombier *hsize = 0;
10380ee5cbfSDavid du Colombier for(;;) {
10480ee5cbfSDavid du Colombier buf = Realloc(buf, offset+Quanta+1);
10580ee5cbfSDavid du Colombier n = Bread(bp, buf+offset, Quanta);
10680ee5cbfSDavid du Colombier if(n < 0){
10780ee5cbfSDavid du Colombier free(buf);
10880ee5cbfSDavid du Colombier return 0;
10980ee5cbfSDavid du Colombier }
11080ee5cbfSDavid du Colombier p = buf+offset; /* start of this chunk */
11180ee5cbfSDavid du Colombier offset += n; /* end of this chunk */
11280ee5cbfSDavid du Colombier buf[offset] = 0;
11380ee5cbfSDavid du Colombier if(n == 0){
11480ee5cbfSDavid du Colombier if(offset == 0)
11580ee5cbfSDavid du Colombier return 0;
11680ee5cbfSDavid du Colombier break;
11780ee5cbfSDavid du Colombier }
11880ee5cbfSDavid du Colombier
11980ee5cbfSDavid du Colombier if(hsize == 0) /* don't process header */
12080ee5cbfSDavid du Colombier break;
12180ee5cbfSDavid du Colombier if(p != buf && p[-1] == '\n') /* check for EOH across buffer split */
12280ee5cbfSDavid du Colombier p--;
12380ee5cbfSDavid du Colombier p = endofhdr(p, buf+offset);
12480ee5cbfSDavid du Colombier if(p)
12580ee5cbfSDavid du Colombier break;
12680ee5cbfSDavid du Colombier if(offset >= Maxread) /* gargantuan header - just punt*/
12780ee5cbfSDavid du Colombier {
12880ee5cbfSDavid du Colombier if(hsize)
12980ee5cbfSDavid du Colombier *hsize = offset;
13080ee5cbfSDavid du Colombier if(bufsize)
13180ee5cbfSDavid du Colombier *bufsize = offset;
13280ee5cbfSDavid du Colombier return buf;
13380ee5cbfSDavid du Colombier }
13480ee5cbfSDavid du Colombier }
13580ee5cbfSDavid du Colombier eoh = p-buf; /* End of header */
13680ee5cbfSDavid du Colombier bsize = offset - eoh; /* amount of body already read */
13780ee5cbfSDavid du Colombier
13880ee5cbfSDavid du Colombier /* Read at least Minbody bytes of the body */
13980ee5cbfSDavid du Colombier if (bsize < Minbody){
14080ee5cbfSDavid du Colombier delta = Minbody-bsize;
14180ee5cbfSDavid du Colombier buf = Realloc(buf, offset+delta+1);
14280ee5cbfSDavid du Colombier n = Bread(bp, buf+offset, delta);
14380ee5cbfSDavid du Colombier if(n > 0) {
14480ee5cbfSDavid du Colombier offset += n;
14580ee5cbfSDavid du Colombier buf[offset] = 0;
14680ee5cbfSDavid du Colombier }
14780ee5cbfSDavid du Colombier }
14880ee5cbfSDavid du Colombier if(hsize)
14980ee5cbfSDavid du Colombier *hsize = eoh;
15080ee5cbfSDavid du Colombier if(bufsize)
15180ee5cbfSDavid du Colombier *bufsize = offset;
15280ee5cbfSDavid du Colombier return buf;
15380ee5cbfSDavid du Colombier }
15480ee5cbfSDavid du Colombier
15580ee5cbfSDavid du Colombier static int
isword(Word * wp,char * text,int len)15680ee5cbfSDavid du Colombier isword(Word *wp, char *text, int len)
15780ee5cbfSDavid du Colombier {
15880ee5cbfSDavid du Colombier for(;wp->string; wp++)
15980ee5cbfSDavid du Colombier if(len >= wp->n && strncmp(text, wp->string, wp->n) == 0)
16080ee5cbfSDavid du Colombier return 1;
16180ee5cbfSDavid du Colombier return 0;
16280ee5cbfSDavid du Colombier }
16380ee5cbfSDavid du Colombier
16480ee5cbfSDavid du Colombier static char*
endofhdr(char * raw,char * end)16580ee5cbfSDavid du Colombier endofhdr(char *raw, char *end)
16680ee5cbfSDavid du Colombier {
16780ee5cbfSDavid du Colombier int i;
16880ee5cbfSDavid du Colombier char *p, *q;
16980ee5cbfSDavid du Colombier char buf[HdrMax];
17080ee5cbfSDavid du Colombier
17180ee5cbfSDavid du Colombier /*
17280ee5cbfSDavid du Colombier * can't use strchr to search for newlines because
17380ee5cbfSDavid du Colombier * there may be embedded NULL's.
17480ee5cbfSDavid du Colombier */
17580ee5cbfSDavid du Colombier for(p = raw; p < end; p++){
17680ee5cbfSDavid du Colombier if(*p != '\n' || p[1] != '\n')
17780ee5cbfSDavid du Colombier continue;
17880ee5cbfSDavid du Colombier p++;
17980ee5cbfSDavid du Colombier for(i = 0, q = p+1; i < sizeof(buf) && *q; q++){
18080ee5cbfSDavid du Colombier buf[i++] = tolower(*q);
18180ee5cbfSDavid du Colombier if(*q == ':' || *q == '\n')
18280ee5cbfSDavid du Colombier break;
18380ee5cbfSDavid du Colombier }
18480ee5cbfSDavid du Colombier if(!isword(hdrwords, buf, i))
18580ee5cbfSDavid du Colombier return p+1;
18680ee5cbfSDavid du Colombier }
18780ee5cbfSDavid du Colombier return 0;
18880ee5cbfSDavid du Colombier }
18980ee5cbfSDavid du Colombier
19080ee5cbfSDavid du Colombier static int
htmlmatch(Word * wp,char * text,char * end,int * n)19180ee5cbfSDavid du Colombier htmlmatch(Word *wp, char *text, char *end, int *n)
19280ee5cbfSDavid du Colombier {
19380ee5cbfSDavid du Colombier char *cp;
19480ee5cbfSDavid du Colombier int i, c, lastc;
19580ee5cbfSDavid du Colombier char buf[MaxHtml];
19680ee5cbfSDavid du Colombier
19780ee5cbfSDavid du Colombier /*
19880ee5cbfSDavid du Colombier * extract a string up to '>'
19980ee5cbfSDavid du Colombier */
20080ee5cbfSDavid du Colombier
20180ee5cbfSDavid du Colombier i = lastc = 0;
20280ee5cbfSDavid du Colombier cp = text;
20380ee5cbfSDavid du Colombier while (cp < end && i < sizeof(buf)-1){
20480ee5cbfSDavid du Colombier c = *cp++;
20580ee5cbfSDavid du Colombier if(c == '=')
20680ee5cbfSDavid du Colombier c = escape(&cp);
20780ee5cbfSDavid du Colombier switch(c){
20880ee5cbfSDavid du Colombier case 0:
20980ee5cbfSDavid du Colombier case '\r':
21080ee5cbfSDavid du Colombier continue;
21180ee5cbfSDavid du Colombier case '>':
21280ee5cbfSDavid du Colombier goto out;
21380ee5cbfSDavid du Colombier case '\n':
21480ee5cbfSDavid du Colombier case ' ':
21580ee5cbfSDavid du Colombier case '\t':
21680ee5cbfSDavid du Colombier if(lastc == ' ')
21780ee5cbfSDavid du Colombier continue;
21880ee5cbfSDavid du Colombier c = ' ';
21980ee5cbfSDavid du Colombier break;
22080ee5cbfSDavid du Colombier default:
22180ee5cbfSDavid du Colombier c = tolower(c);
22280ee5cbfSDavid du Colombier break;
22380ee5cbfSDavid du Colombier }
22480ee5cbfSDavid du Colombier buf[i++] = lastc = c;
22580ee5cbfSDavid du Colombier }
22680ee5cbfSDavid du Colombier out:
22780ee5cbfSDavid du Colombier buf[i] = 0;
22880ee5cbfSDavid du Colombier if(n)
22980ee5cbfSDavid du Colombier *n = cp-text;
23080ee5cbfSDavid du Colombier return isword(wp, buf, i);
23180ee5cbfSDavid du Colombier }
23280ee5cbfSDavid du Colombier
23380ee5cbfSDavid du Colombier static int
escape(char ** msg)23480ee5cbfSDavid du Colombier escape(char **msg)
23580ee5cbfSDavid du Colombier {
23680ee5cbfSDavid du Colombier int c;
23780ee5cbfSDavid du Colombier char *p;
23880ee5cbfSDavid du Colombier
23980ee5cbfSDavid du Colombier p = *msg;
24080ee5cbfSDavid du Colombier c = *p;
24180ee5cbfSDavid du Colombier if(c == '\n'){
24280ee5cbfSDavid du Colombier p++;
24380ee5cbfSDavid du Colombier c = *p++;
24480ee5cbfSDavid du Colombier } else
24580ee5cbfSDavid du Colombier if(c == '2'){
24680ee5cbfSDavid du Colombier c = tolower(p[1]);
24780ee5cbfSDavid du Colombier if(c == 'e'){
24880ee5cbfSDavid du Colombier p += 2;
24980ee5cbfSDavid du Colombier c = '.';
25080ee5cbfSDavid du Colombier }else
25180ee5cbfSDavid du Colombier if(c == 'f'){
25280ee5cbfSDavid du Colombier p += 2;
25380ee5cbfSDavid du Colombier c = '/';
25480ee5cbfSDavid du Colombier }else
25580ee5cbfSDavid du Colombier if(c == '0'){
25680ee5cbfSDavid du Colombier p += 2;
25780ee5cbfSDavid du Colombier c = ' ';
25880ee5cbfSDavid du Colombier }
25980ee5cbfSDavid du Colombier else c = '=';
26080ee5cbfSDavid du Colombier } else {
26180ee5cbfSDavid du Colombier if(c == '3' && tolower(p[1]) == 'd')
26280ee5cbfSDavid du Colombier p += 2;
26380ee5cbfSDavid du Colombier c = '=';
26480ee5cbfSDavid du Colombier }
26580ee5cbfSDavid du Colombier *msg = p;
26680ee5cbfSDavid du Colombier return c;
26780ee5cbfSDavid du Colombier }
26880ee5cbfSDavid du Colombier
26980ee5cbfSDavid du Colombier static int
htmlchk(char ** msg,char * end)27080ee5cbfSDavid du Colombier htmlchk(char **msg, char *end)
27180ee5cbfSDavid du Colombier {
27280ee5cbfSDavid du Colombier int n;
27380ee5cbfSDavid du Colombier char *p;
27480ee5cbfSDavid du Colombier
27580ee5cbfSDavid du Colombier static int ishtml;
27680ee5cbfSDavid du Colombier
27780ee5cbfSDavid du Colombier p = *msg;
27880ee5cbfSDavid du Colombier if(ishtml == 0){
27980ee5cbfSDavid du Colombier ishtml = htmlmatch(htmlcmds, p, end, &n);
28080ee5cbfSDavid du Colombier
28180ee5cbfSDavid du Colombier /* If not an HTML keyword, check if it's
28280ee5cbfSDavid du Colombier * an HTML comment (<!comment>). if so,
28380ee5cbfSDavid du Colombier * skip over it; otherwise copy it in.
28480ee5cbfSDavid du Colombier */
28580ee5cbfSDavid du Colombier if(ishtml == 0 && *p != '!') /* not comment */
28680ee5cbfSDavid du Colombier return '<'; /* copy it */
28780ee5cbfSDavid du Colombier
28880ee5cbfSDavid du Colombier } else if(htmlmatch(hrefs, p, end, &n)) /* if special HTML string */
28980ee5cbfSDavid du Colombier return '<'; /* copy it */
29080ee5cbfSDavid du Colombier
29180ee5cbfSDavid du Colombier /*
29280ee5cbfSDavid du Colombier * this is an uninteresting HTML command; skip over it.
29380ee5cbfSDavid du Colombier */
29480ee5cbfSDavid du Colombier p += n;
29580ee5cbfSDavid du Colombier *msg = p+1;
29680ee5cbfSDavid du Colombier return *p;
29780ee5cbfSDavid du Colombier }
29880ee5cbfSDavid du Colombier
299*9a747e4fSDavid du Colombier /*
300*9a747e4fSDavid du Colombier * decode a base 64 encode body
301*9a747e4fSDavid du Colombier */
30280ee5cbfSDavid du Colombier void
conv64(char * msg,char * end,char * buf,int bufsize)303*9a747e4fSDavid du Colombier conv64(char *msg, char *end, char *buf, int bufsize)
304*9a747e4fSDavid du Colombier {
305*9a747e4fSDavid du Colombier int len, i;
306*9a747e4fSDavid du Colombier char *cp;
307*9a747e4fSDavid du Colombier
308*9a747e4fSDavid du Colombier len = end - msg;
309*9a747e4fSDavid du Colombier i = (len*3)/4+1; // room for max chars + null
310*9a747e4fSDavid du Colombier cp = Malloc(i);
311*9a747e4fSDavid du Colombier len = dec64((uchar*)cp, i, msg, len);
312*9a747e4fSDavid du Colombier convert(cp, cp+len, buf, bufsize, 1);
313*9a747e4fSDavid du Colombier free(cp);
314*9a747e4fSDavid du Colombier }
315*9a747e4fSDavid du Colombier
316*9a747e4fSDavid du Colombier int
convert(char * msg,char * end,char * buf,int bufsize,int isbody)31780ee5cbfSDavid du Colombier convert(char *msg, char *end, char *buf, int bufsize, int isbody)
31880ee5cbfSDavid du Colombier {
31980ee5cbfSDavid du Colombier
32080ee5cbfSDavid du Colombier char *p;
321*9a747e4fSDavid du Colombier int c, lastc, base64;
32280ee5cbfSDavid du Colombier
32380ee5cbfSDavid du Colombier lastc = 0;
324*9a747e4fSDavid du Colombier base64 = 0;
32580ee5cbfSDavid du Colombier while(msg < end && bufsize > 0){
32680ee5cbfSDavid du Colombier c = *msg++;
32780ee5cbfSDavid du Colombier
32880ee5cbfSDavid du Colombier /*
32980ee5cbfSDavid du Colombier * In the body only, try to strip most HTML and
33080ee5cbfSDavid du Colombier * replace certain MIME escape sequences with the character
33180ee5cbfSDavid du Colombier */
33280ee5cbfSDavid du Colombier if(isbody) {
33380ee5cbfSDavid du Colombier do{
33480ee5cbfSDavid du Colombier p = msg;
33580ee5cbfSDavid du Colombier if(c == '<')
33680ee5cbfSDavid du Colombier c = htmlchk(&msg, end);
33780ee5cbfSDavid du Colombier if(c == '=')
33880ee5cbfSDavid du Colombier c = escape(&msg);
33980ee5cbfSDavid du Colombier } while(p != msg && p < end);
34080ee5cbfSDavid du Colombier }
34180ee5cbfSDavid du Colombier switch(c){
34280ee5cbfSDavid du Colombier case 0:
34380ee5cbfSDavid du Colombier case '\r':
34480ee5cbfSDavid du Colombier continue;
34580ee5cbfSDavid du Colombier case '\t':
34680ee5cbfSDavid du Colombier case ' ':
34780ee5cbfSDavid du Colombier case '\n':
34880ee5cbfSDavid du Colombier if(lastc == ' ')
34980ee5cbfSDavid du Colombier continue;
35080ee5cbfSDavid du Colombier c = ' ';
35180ee5cbfSDavid du Colombier break;
352*9a747e4fSDavid du Colombier case 'C': /* check for MIME base 64 encoding in header */
353*9a747e4fSDavid du Colombier case 'c':
354*9a747e4fSDavid du Colombier if(isbody == 0)
355*9a747e4fSDavid du Colombier if(msg < end-32 && *msg == 'o' && msg[1] == 'n')
356*9a747e4fSDavid du Colombier if(cistrncmp(msg+2, "tent-transfer-encoding: base64", 30) == 0)
357*9a747e4fSDavid du Colombier base64 = 1;
358*9a747e4fSDavid du Colombier c = 'c';
359*9a747e4fSDavid du Colombier break;
36080ee5cbfSDavid du Colombier default:
36180ee5cbfSDavid du Colombier c = tolower(c);
36280ee5cbfSDavid du Colombier break;
36380ee5cbfSDavid du Colombier }
36480ee5cbfSDavid du Colombier *buf++ = c;
36580ee5cbfSDavid du Colombier lastc = c;
36680ee5cbfSDavid du Colombier bufsize--;
36780ee5cbfSDavid du Colombier }
36880ee5cbfSDavid du Colombier *buf = 0;
369*9a747e4fSDavid du Colombier return base64;
37080ee5cbfSDavid du Colombier }
37180ee5cbfSDavid du Colombier
37280ee5cbfSDavid du Colombier /*
37380ee5cbfSDavid du Colombier * The pattern parser: build data structures from the pattern file
37480ee5cbfSDavid du Colombier */
37580ee5cbfSDavid du Colombier
37680ee5cbfSDavid du Colombier static int
hash(int c)37780ee5cbfSDavid du Colombier hash(int c)
37880ee5cbfSDavid du Colombier {
37980ee5cbfSDavid du Colombier return c & 127;
38080ee5cbfSDavid du Colombier }
38180ee5cbfSDavid du Colombier
38280ee5cbfSDavid du Colombier static int
findkey(char * val)38380ee5cbfSDavid du Colombier findkey(char *val)
38480ee5cbfSDavid du Colombier {
38580ee5cbfSDavid du Colombier Keyword *kp;
38680ee5cbfSDavid du Colombier
38780ee5cbfSDavid du Colombier for(kp = keywords; kp->string; kp++)
38880ee5cbfSDavid du Colombier if(strcmp(val, kp->string) == 0)
38980ee5cbfSDavid du Colombier break;
39080ee5cbfSDavid du Colombier return kp->value;
39180ee5cbfSDavid du Colombier }
39280ee5cbfSDavid du Colombier
39380ee5cbfSDavid du Colombier #define whitespace(c) ((c) == ' ' || (c) == '\t')
39480ee5cbfSDavid du Colombier
39580ee5cbfSDavid du Colombier void
parsepats(Biobuf * bp)39680ee5cbfSDavid du Colombier parsepats(Biobuf *bp)
39780ee5cbfSDavid du Colombier {
39880ee5cbfSDavid du Colombier Pattern *p, *new;
39980ee5cbfSDavid du Colombier char *cp, *qp;
40080ee5cbfSDavid du Colombier int type, action, n, h;
40180ee5cbfSDavid du Colombier Spat *spat;
40280ee5cbfSDavid du Colombier
40380ee5cbfSDavid du Colombier for(;;){
40480ee5cbfSDavid du Colombier cp = Brdline(bp, '\n');
40580ee5cbfSDavid du Colombier if(cp == 0)
40680ee5cbfSDavid du Colombier break;
40780ee5cbfSDavid du Colombier cp[Blinelen(bp)-1] = 0;
40880ee5cbfSDavid du Colombier while(*cp == ' ' || *cp == '\t')
40980ee5cbfSDavid du Colombier cp++;
41080ee5cbfSDavid du Colombier if(*cp == '#' || *cp == 0)
41180ee5cbfSDavid du Colombier continue;
41280ee5cbfSDavid du Colombier type = regexp;
41380ee5cbfSDavid du Colombier if(*cp == '*'){
41480ee5cbfSDavid du Colombier type = string;
41580ee5cbfSDavid du Colombier cp++;
41680ee5cbfSDavid du Colombier }
41780ee5cbfSDavid du Colombier qp = strchr(cp, ':');
41880ee5cbfSDavid du Colombier if(qp == 0)
41980ee5cbfSDavid du Colombier continue;
42080ee5cbfSDavid du Colombier *qp = 0;
42180ee5cbfSDavid du Colombier if(debug)
42280ee5cbfSDavid du Colombier fprint(2, "action = %s\n", cp);
42380ee5cbfSDavid du Colombier action = findkey(cp);
42480ee5cbfSDavid du Colombier if(action >= Nactions)
42580ee5cbfSDavid du Colombier continue;
42680ee5cbfSDavid du Colombier cp = qp+1;
42780ee5cbfSDavid du Colombier n = extract(cp);
42880ee5cbfSDavid du Colombier if(n <= 0 || *cp == 0)
42980ee5cbfSDavid du Colombier continue;
43080ee5cbfSDavid du Colombier
43180ee5cbfSDavid du Colombier qp = strstr(cp, "~~");
43280ee5cbfSDavid du Colombier if(qp){
43380ee5cbfSDavid du Colombier *qp = 0;
43480ee5cbfSDavid du Colombier n = strlen(cp);
43580ee5cbfSDavid du Colombier }
43680ee5cbfSDavid du Colombier if(debug)
43780ee5cbfSDavid du Colombier fprint(2, " Pattern: `%s'\n", cp);
43880ee5cbfSDavid du Colombier
43980ee5cbfSDavid du Colombier /* Hook regexps into a chain */
44080ee5cbfSDavid du Colombier if(type == regexp) {
44180ee5cbfSDavid du Colombier new = Malloc(sizeof(Pattern));
44280ee5cbfSDavid du Colombier new->action = action;
44380ee5cbfSDavid du Colombier new->pat = regcomp(cp);
44480ee5cbfSDavid du Colombier if(new->pat == 0){
44580ee5cbfSDavid du Colombier free(new);
44680ee5cbfSDavid du Colombier continue;
44780ee5cbfSDavid du Colombier }
44880ee5cbfSDavid du Colombier new->type = regexp;
44980ee5cbfSDavid du Colombier new->alt = 0;
45080ee5cbfSDavid du Colombier new->next = 0;
45180ee5cbfSDavid du Colombier
45280ee5cbfSDavid du Colombier if(qp)
45380ee5cbfSDavid du Colombier parsealt(bp, qp+2, &new->alt);
45480ee5cbfSDavid du Colombier
45580ee5cbfSDavid du Colombier new->next = patterns[action].regexps;
45680ee5cbfSDavid du Colombier patterns[action].regexps = new;
45780ee5cbfSDavid du Colombier continue;
45880ee5cbfSDavid du Colombier
45980ee5cbfSDavid du Colombier }
46080ee5cbfSDavid du Colombier /* not a Regexp - hook strings into Pattern hash chain */
46180ee5cbfSDavid du Colombier spat = Malloc(sizeof(*spat));
46280ee5cbfSDavid du Colombier spat->next = 0;
46380ee5cbfSDavid du Colombier spat->alt = 0;
46480ee5cbfSDavid du Colombier spat->len = n;
46580ee5cbfSDavid du Colombier spat->string = Malloc(n+1);
46680ee5cbfSDavid du Colombier spat->c1 = cp[1];
46780ee5cbfSDavid du Colombier strcpy(spat->string, cp);
46880ee5cbfSDavid du Colombier
46980ee5cbfSDavid du Colombier if(qp)
47080ee5cbfSDavid du Colombier parsealt(bp, qp+2, &spat->alt);
47180ee5cbfSDavid du Colombier
47280ee5cbfSDavid du Colombier p = patterns[action].strings;
47380ee5cbfSDavid du Colombier if(p == 0) {
47480ee5cbfSDavid du Colombier p = Malloc(sizeof(Pattern));
47580ee5cbfSDavid du Colombier memset(p, 0, sizeof(*p));
47680ee5cbfSDavid du Colombier p->action = action;
47780ee5cbfSDavid du Colombier p->type = string;
47880ee5cbfSDavid du Colombier patterns[action].strings = p;
47980ee5cbfSDavid du Colombier }
48080ee5cbfSDavid du Colombier h = hash(*spat->string);
48180ee5cbfSDavid du Colombier spat->next = p->spat[h];
48280ee5cbfSDavid du Colombier p->spat[h] = spat;
48380ee5cbfSDavid du Colombier }
48480ee5cbfSDavid du Colombier }
48580ee5cbfSDavid du Colombier
48680ee5cbfSDavid du Colombier static void
parsealt(Biobuf * bp,char * cp,Spat ** head)48780ee5cbfSDavid du Colombier parsealt(Biobuf *bp, char *cp, Spat** head)
48880ee5cbfSDavid du Colombier {
48980ee5cbfSDavid du Colombier char *p;
49080ee5cbfSDavid du Colombier Spat *alt;
49180ee5cbfSDavid du Colombier
49280ee5cbfSDavid du Colombier while(cp){
49380ee5cbfSDavid du Colombier if(*cp == 0){ /*escaped newline*/
49480ee5cbfSDavid du Colombier do{
49580ee5cbfSDavid du Colombier cp = Brdline(bp, '\n');
49680ee5cbfSDavid du Colombier if(cp == 0)
49780ee5cbfSDavid du Colombier return;
49880ee5cbfSDavid du Colombier cp[Blinelen(bp)-1] = 0;
49980ee5cbfSDavid du Colombier } while(extract(cp) <= 0 || *cp == 0);
50080ee5cbfSDavid du Colombier }
50180ee5cbfSDavid du Colombier
50280ee5cbfSDavid du Colombier p = cp;
50380ee5cbfSDavid du Colombier cp = strstr(p, "~~");
50480ee5cbfSDavid du Colombier if(cp){
50580ee5cbfSDavid du Colombier *cp = 0;
50680ee5cbfSDavid du Colombier cp += 2;
50780ee5cbfSDavid du Colombier }
50880ee5cbfSDavid du Colombier if(strlen(p)){
50980ee5cbfSDavid du Colombier alt = Malloc(sizeof(*alt));
51080ee5cbfSDavid du Colombier alt->string = strdup(p);
51180ee5cbfSDavid du Colombier alt->next = *head;
51280ee5cbfSDavid du Colombier *head = alt;
51380ee5cbfSDavid du Colombier }
51480ee5cbfSDavid du Colombier }
51580ee5cbfSDavid du Colombier }
51680ee5cbfSDavid du Colombier
51780ee5cbfSDavid du Colombier static int
extract(char * cp)51880ee5cbfSDavid du Colombier extract(char *cp)
51980ee5cbfSDavid du Colombier {
52080ee5cbfSDavid du Colombier int c;
52180ee5cbfSDavid du Colombier char *p, *q, *r;
52280ee5cbfSDavid du Colombier
52380ee5cbfSDavid du Colombier p = q = r = cp;
52480ee5cbfSDavid du Colombier while(whitespace(*p))
52580ee5cbfSDavid du Colombier p++;
52680ee5cbfSDavid du Colombier while(c = *p++){
52780ee5cbfSDavid du Colombier if (c == '#')
52880ee5cbfSDavid du Colombier break;
52980ee5cbfSDavid du Colombier if(c == '"'){
53080ee5cbfSDavid du Colombier while(*p && *p != '"'){
53180ee5cbfSDavid du Colombier if(*p == '\\' && p[1] == '"')
53280ee5cbfSDavid du Colombier p++;
53380ee5cbfSDavid du Colombier if('A' <= *p && *p <= 'Z')
53480ee5cbfSDavid du Colombier *q++ = *p++ + ('a'-'A');
53580ee5cbfSDavid du Colombier else
53680ee5cbfSDavid du Colombier *q++ = *p++;
53780ee5cbfSDavid du Colombier }
53880ee5cbfSDavid du Colombier if(*p)
53980ee5cbfSDavid du Colombier p++;
54080ee5cbfSDavid du Colombier r = q; /* never back up over a quoted string */
54180ee5cbfSDavid du Colombier } else {
54280ee5cbfSDavid du Colombier if('A' <= c && c <= 'Z')
54380ee5cbfSDavid du Colombier c += ('a'-'A');
54480ee5cbfSDavid du Colombier *q++ = c;
54580ee5cbfSDavid du Colombier }
54680ee5cbfSDavid du Colombier }
54780ee5cbfSDavid du Colombier while(q > r && whitespace(q[-1]))
54880ee5cbfSDavid du Colombier q--;
54980ee5cbfSDavid du Colombier *q = 0;
55080ee5cbfSDavid du Colombier return q-cp;
55180ee5cbfSDavid du Colombier }
55280ee5cbfSDavid du Colombier
55380ee5cbfSDavid du Colombier /*
55480ee5cbfSDavid du Colombier * The matching engine: compare canonical input to pattern structures
55580ee5cbfSDavid du Colombier */
55680ee5cbfSDavid du Colombier
55780ee5cbfSDavid du Colombier static Spat*
isalt(char * message,Spat * alt)55880ee5cbfSDavid du Colombier isalt(char *message, Spat *alt)
55980ee5cbfSDavid du Colombier {
56080ee5cbfSDavid du Colombier while(alt) {
56180ee5cbfSDavid du Colombier if(*cmd)
56280ee5cbfSDavid du Colombier if(message != cmd && strstr(cmd, alt->string))
56380ee5cbfSDavid du Colombier break;
56480ee5cbfSDavid du Colombier if(message != header+1 && strstr(header+1, alt->string))
56580ee5cbfSDavid du Colombier break;
56680ee5cbfSDavid du Colombier if(strstr(message, alt->string))
56780ee5cbfSDavid du Colombier break;
56880ee5cbfSDavid du Colombier alt = alt->next;
56980ee5cbfSDavid du Colombier }
57080ee5cbfSDavid du Colombier return alt;
57180ee5cbfSDavid du Colombier }
57280ee5cbfSDavid du Colombier
57380ee5cbfSDavid du Colombier int
matchpat(Pattern * p,char * message,Resub * m)57480ee5cbfSDavid du Colombier matchpat(Pattern *p, char *message, Resub *m)
57580ee5cbfSDavid du Colombier {
57680ee5cbfSDavid du Colombier Spat *spat;
57780ee5cbfSDavid du Colombier char *s;
57880ee5cbfSDavid du Colombier int c, c1;
57980ee5cbfSDavid du Colombier
58080ee5cbfSDavid du Colombier if(p->type == string){
58180ee5cbfSDavid du Colombier c1 = *message;
58280ee5cbfSDavid du Colombier for(s=message; c=c1; s++){
58380ee5cbfSDavid du Colombier c1 = s[1];
58480ee5cbfSDavid du Colombier for(spat=p->spat[hash(c)]; spat; spat=spat->next){
58580ee5cbfSDavid du Colombier if(c1 == spat->c1)
58680ee5cbfSDavid du Colombier if(memcmp(s, spat->string, spat->len) == 0)
58780ee5cbfSDavid du Colombier if(!isalt(message, spat->alt)){
58880ee5cbfSDavid du Colombier m->sp = s;
58980ee5cbfSDavid du Colombier m->ep = s + spat->len;
59080ee5cbfSDavid du Colombier return 1;
59180ee5cbfSDavid du Colombier }
59280ee5cbfSDavid du Colombier }
59380ee5cbfSDavid du Colombier }
59480ee5cbfSDavid du Colombier return 0;
59580ee5cbfSDavid du Colombier }
59680ee5cbfSDavid du Colombier m->sp = m->ep = 0;
59780ee5cbfSDavid du Colombier if(regexec(p->pat, message, m, 1) == 0)
59880ee5cbfSDavid du Colombier return 0;
59980ee5cbfSDavid du Colombier if(isalt(message, p->alt))
60080ee5cbfSDavid du Colombier return 0;
60180ee5cbfSDavid du Colombier return 1;
60280ee5cbfSDavid du Colombier }
60380ee5cbfSDavid du Colombier
60480ee5cbfSDavid du Colombier
60580ee5cbfSDavid du Colombier void
xprint(int fd,char * type,Resub * m)60680ee5cbfSDavid du Colombier xprint(int fd, char *type, Resub *m)
60780ee5cbfSDavid du Colombier {
60880ee5cbfSDavid du Colombier char *p, *q;
60980ee5cbfSDavid du Colombier int i;
61080ee5cbfSDavid du Colombier
61180ee5cbfSDavid du Colombier if(m->sp == 0 || m->ep == 0)
61280ee5cbfSDavid du Colombier return;
61380ee5cbfSDavid du Colombier
61480ee5cbfSDavid du Colombier /* back up approx 30 characters to whitespace */
61580ee5cbfSDavid du Colombier for(p = m->sp, i = 0; *p && i < 30; i++, p--)
61680ee5cbfSDavid du Colombier ;
61780ee5cbfSDavid du Colombier while(*p && *p != ' ')
61880ee5cbfSDavid du Colombier p--;
61980ee5cbfSDavid du Colombier p++;
62080ee5cbfSDavid du Colombier
62180ee5cbfSDavid du Colombier /* grab about 30 more chars beyond the end of the match */
62280ee5cbfSDavid du Colombier for(q = m->ep, i = 0; *q && i < 30; i++, q++)
62380ee5cbfSDavid du Colombier ;
62480ee5cbfSDavid du Colombier while(*q && *q != ' ')
62580ee5cbfSDavid du Colombier q++;
62680ee5cbfSDavid du Colombier
62780ee5cbfSDavid du Colombier fprint(fd, "%s %.*s~%.*s~%.*s\n", type, (int)(m->sp-p), p, (int)(m->ep-m->sp), m->sp, (int)(q-m->ep), m->ep);
62880ee5cbfSDavid du Colombier }
629*9a747e4fSDavid du Colombier
630*9a747e4fSDavid du Colombier enum {
631*9a747e4fSDavid du Colombier INVAL= 255
632*9a747e4fSDavid du Colombier };
633*9a747e4fSDavid du Colombier
634*9a747e4fSDavid du Colombier static uchar t64d[256] = {
635*9a747e4fSDavid du Colombier /*00 */ INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
636*9a747e4fSDavid du Colombier INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
637*9a747e4fSDavid du Colombier /*10*/ INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
638*9a747e4fSDavid du Colombier INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
639*9a747e4fSDavid du Colombier /*20*/ INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
640*9a747e4fSDavid du Colombier INVAL, INVAL, INVAL, 62, INVAL, INVAL, INVAL, 63,
641*9a747e4fSDavid du Colombier /*30*/ 52, 53, 54, 55, 56, 57, 58, 59,
642*9a747e4fSDavid du Colombier 60, 61, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
643*9a747e4fSDavid du Colombier /*40*/ INVAL, 0, 1, 2, 3, 4, 5, 6,
644*9a747e4fSDavid du Colombier 7, 8, 9, 10, 11, 12, 13, 14,
645*9a747e4fSDavid du Colombier /*50*/ 15, 16, 17, 18, 19, 20, 21, 22,
646*9a747e4fSDavid du Colombier 23, 24, 25, INVAL, INVAL, INVAL, INVAL, INVAL,
647*9a747e4fSDavid du Colombier /*60*/ INVAL, 26, 27, 28, 29, 30, 31, 32,
648*9a747e4fSDavid du Colombier 33, 34, 35, 36, 37, 38, 39, 40,
649*9a747e4fSDavid du Colombier /*70*/ 41, 42, 43, 44, 45, 46, 47, 48,
650*9a747e4fSDavid du Colombier 49, 50, 51, INVAL, INVAL, INVAL, INVAL, INVAL,
651*9a747e4fSDavid du Colombier /*80*/ INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
652*9a747e4fSDavid du Colombier INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
653*9a747e4fSDavid du Colombier /*90*/ INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
654*9a747e4fSDavid du Colombier INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
655*9a747e4fSDavid du Colombier /*A0*/ INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
656*9a747e4fSDavid du Colombier INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
657*9a747e4fSDavid du Colombier /*B0*/ INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
658*9a747e4fSDavid du Colombier INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
659*9a747e4fSDavid du Colombier /*C0*/ INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
660*9a747e4fSDavid du Colombier INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
661*9a747e4fSDavid du Colombier /*D0*/ INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
662*9a747e4fSDavid du Colombier INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
663*9a747e4fSDavid du Colombier /*E0*/ INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
664*9a747e4fSDavid du Colombier INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
665*9a747e4fSDavid du Colombier /*F0*/ INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
666*9a747e4fSDavid du Colombier INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL, INVAL,
667*9a747e4fSDavid du Colombier };
668