-
Notifications
You must be signed in to change notification settings - Fork 3
/
plugin-patterns.c
155 lines (145 loc) · 3.48 KB
/
plugin-patterns.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <stdlib.h>
#include <string.h>
#include <bglibs/iobuf.h>
#include <bglibs/msg.h>
#include <bglibs/wrap.h>
#include <bglibs/str.h>
#include "mailfront.h"
struct pattern
{
int mode;
str s;
const char* message;
};
#define T_AFTER_BLANK ('\\')
#define T_RESPONSE ('=')
#define T_COMMENT ('#')
#define T_HEADER (':')
#define T_NORMAL (0)
static response resp_patmatch = { 554, 0 };
static struct pattern* pattern_list;
static str responses;
static unsigned pattern_count;
static int linemode;
static unsigned linepos;
static unsigned linemax = 256;
static char* linebuf;
static int patterns_read(const char* filename)
{
ibuf in;
int mode;
unsigned i;
unsigned count;
str line = {0,0,0};
const char* currmsg = "This message contains prohibited content";
if (!ibuf_open(&in, filename, 0)) return 0;
count = 0;
/* Count the number of non-comment lines. */
while (ibuf_getstr(&in, &line, LF)) {
str_rstrip(&line);
if (line.len > 0 && line.s[0] != T_COMMENT) {
if (line.s[0] == T_RESPONSE)
/* Pre-allocate room for the responses */
wrap_str(str_catb(&responses, line.s+1, line.len));
else
++count;
}
}
responses.len = 0;
/* Allocate the lines. */
if ((pattern_list = malloc(count * sizeof *pattern_list)) == 0)
die_oom(111);
if (!ibuf_rewind(&in))
die1sys(111, "Could not rewind patterns file");
memset(pattern_list, 0, count * sizeof *pattern_list);
for (i = 0; i < count && ibuf_getstr(&in, &line, LF); ) {
str_rstrip(&line);
if (line.len > 0) {
switch (mode = line.s[0]) {
case T_COMMENT:
continue;
case T_RESPONSE:
currmsg = responses.s + responses.len;
str_catb(&responses, line.s+1, line.len);
continue;
case T_AFTER_BLANK:
case T_HEADER:
break;
default:
mode = T_NORMAL;
}
pattern_list[i].mode = mode;
wrap_str(str_copyb(&pattern_list[i].s, line.s+1, line.len-1));
pattern_list[i].message = currmsg;
++i;
}
}
pattern_count = i;
ibuf_close(&in);
str_free(&line);
return 1;
}
static const response* init(int fd)
{
const char* tmp;
unsigned u;
if ((tmp = session_getenv("PATTERNS")) != 0)
if (!patterns_read(tmp))
warn3sys("Could not read patterns file '", tmp, "'");
if ((tmp = session_getenv("PATTERNS_LINEMAX")) != 0)
if ((u = strtoul(tmp, (char**)&tmp, 10)) > 0 && *tmp == 0)
linemax = u;
if ((linebuf = malloc(linemax+1)) == 0)
die_oom(111);
linemode = T_HEADER;
linepos = 0;
return 0;
(void)fd;
}
static const response* check_line(void)
{
unsigned i;
struct pattern* p;
const str fakeline = { linebuf, linepos, 0 };
linebuf[linepos] = 0;
for (p = pattern_list, i = 0; i < pattern_count; ++i, ++p) {
if ((p->mode == T_NORMAL
|| p->mode == linemode)
&& str_glob(&fakeline, &p->s)) {
resp_patmatch.message = p->message;
return &resp_patmatch;
}
}
return 0;
}
static const response* check(const char* bytes, unsigned long len)
{
const char* p;
const char* const end = bytes + len;
const response* r;
if (linebuf == 0) return 0;
for (p = bytes; p < end; ++p) {
const char ch = *p;
if (ch == LF) {
if (linepos > 0) {
if ((r = check_line()) != 0)
return r;
if (linemode != T_HEADER)
linemode = T_NORMAL;
}
else
linemode = T_AFTER_BLANK;
linepos = 0;
}
else {
if (linepos < linemax)
linebuf[linepos++] = ch;
}
}
return 0;
}
struct plugin plugin = {
.version = PLUGIN_VERSION,
.data_start = init,
.data_block = check,
};