/[imapfilter]/imapfilter/file.c
ViewVC logotype

Contents of /imapfilter/file.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.11 - (show annotations)
Sun Aug 26 19:37:45 2001 UTC (22 years, 7 months ago) by lefcha
Branch: MAIN
Changes since 1.10: +73 -31 lines
File MIME type: text/plain
New options and a bug fix  related to parsing of config file.

1 #include <stdio.h>
2 #include <errno.h>
3 #include <sys/types.h>
4 #include <regex.h>
5 #include <string.h>
6 #include <stdlib.h>
7 #include <limits.h>
8 #include <sys/stat.h>
9
10 #include "config.h"
11 #include "imapfilter.h"
12 #include "file.h"
13 #include "log.h"
14
15
16 extern char logfile[PATH_MAX];
17 extern unsigned int options;
18
19 account_t *accounts = NULL; /* All accounts. */
20
21 filter_t *dfilters = NULL; /* Filters of DENY type. */
22 filter_t *afilters = NULL; /* Filters of ALLOW type. */
23
24 unsigned int dlimit = 0;
25 unsigned int alimit = 0; /* DENY and ALLOW message size limits. */
26
27
28 /*
29 * Finds path to configuration file, opens it and calls parse_config().
30 */
31 int read_config(char *cfg)
32 {
33 int r;
34 FILE *fp;
35 char *home = NULL;
36
37 if (!cfg) {
38 cfg = (char *) malloc(PATH_MAX * sizeof(char));
39
40
41 home = getenv("HOME");
42
43 snprintf(cfg, PATH_MAX, "%s/%s", home, ".imapfilterrc");
44 }
45 #ifdef DEBUG
46 printf("debug: configuration file: '%s'\n", cfg);
47 #endif
48
49 check_permissions(cfg);
50
51 fp = fopen(cfg, "r");
52
53 if (!fp) {
54 error("imapfilter: opening config file %s; %s\n",
55 cfg, strerror(errno));
56 return 1;
57 }
58
59 r = parse_config(fp);
60
61 fclose(fp);
62
63 #ifdef DEBUG
64 printf("debug: options: %0#10x\n", options);
65 #endif
66
67 return r;
68 }
69
70
71 /*
72 * Checks the permissions of the configuration file.
73 */
74 int check_permissions(char *cfg)
75 {
76 struct stat fs;
77
78 if (stat(cfg, &fs)) {
79 error("imapfilter: getting file %s status; %s\n", cfg,
80 strerror(errno));
81 return 1;
82 }
83
84 if (!S_ISREG(fs.st_mode)) {
85 error("imapfilter: file %s not a regular file\n", cfg);
86 return 1;
87 }
88
89 if ((fs.st_mode & 00777) != (S_IRUSR | S_IWUSR)) {
90 fprintf(stderr,
91 "imapfilter: warning: bad config file %s permissions\n"
92 "imapfilter: warning: file's mode should be 600 not %o\n",
93 cfg, fs.st_mode & 00777);
94 return 1;
95 }
96
97 return 0;
98 }
99
100
101 /*
102 * Parses configuration file.
103 */
104 int parse_config(FILE * fp)
105 {
106 int i;
107 unsigned int row = 0;
108 char line[LINE_MAX];
109 regex_t creg[7];
110 regmatch_t match[4];
111 const char *reg[7] = {
112 "^[[:blank:]]*(SERVER|PORT|USERNAME|PASSWORD)[[:blank:]]*=[[:blank:]]*([[:graph:]]*)[[:blank:]]*\n$",
113 "^[[:blank:]]*(DENY|ALLOW)[[:blank:]]*=[[:blank:]]*(FROM|CC|BCC|SUBJECT|TO):? ([[:print:]]*)\n$",
114 "^[[:blank:]]*(DENY|ALLOW)[[:blank:]]*=[[:blank:]]*([[:graph:]]+):? ([[:print:]]*)\n$",
115 "^[[:blank:]]*(DENY_LIMIT|ALLOW_LIMIT)[[:blank:]]*=[[:blank:]]*([[:digit:]]*)[[:blank:]]*\n$",
116 "^[[:blank:]]*(LOGFILE)[[:blank:]]*=[[:blank:]]*([[:graph:]]*)[[:blank:]]*\n$",
117 "^[[:blank:]]*(TEST_MODE|SHOW_HEADERS|UNSEEN_ONLY)[[:blank:]]*=[[:blank:]]*(yes|no)[[:blank:]]*\n$",
118 "^([[:blank:]]*\n|#.*\n)$"
119 };
120
121 for (i = 0; i < 7; i++)
122 regcomp(&creg[i], reg[i], REG_EXTENDED);
123
124 while (fgets(line, LINE_MAX - 1, fp)) {
125 row++;
126 if (!regexec(&creg[0], line, 3, match, 0)) {
127 if (set_account(line, match))
128 return 1;
129 continue;
130 } else if (!regexec(&creg[1], line, 4, match, 0)) {
131 if (standard_filter(line, match))
132 return 1;
133 continue;
134 } else if (!regexec(&creg[2], line, 4, match, 0)) {
135 if (custom_filter(line, match))
136 return 1;
137 continue;
138 } else if (!regexec(&creg[3], line, 3, match, 0)) {
139 set_limits(line, match);
140 continue;
141 } else if (!regexec(&creg[4], line, 3, match, 0) ||
142 !regexec(&creg[5], line, 3, match, 0)) {
143 set_options(line, match);
144 continue;
145 } else if (!regexec(&creg[6], line, 0, match, 0)) {
146 continue;
147 } else {
148 error("imapfilter: parse error in config file at row %d\n",
149 row);
150 return 1;
151 }
152 }
153
154 /* Fail if no accounts were defined. */
155 if (!accounts) {
156 fprintf(stderr,
157 "imapfilter: no accounts defined in config file\n");
158 return 1;
159 }
160
161 /* Fail if no filters were defined. */
162 if (!dfilters && !afilters) {
163 error("imapfilter: no filters defined in config file\n");
164 return 1;
165 }
166
167 return 0;
168 }
169
170
171 /*
172 * Allocates memory for accounts, builds linked list, and NULL terminates
173 * account settings.
174 */
175 account_t *prepare_account(void)
176 {
177 static account_t *ca; /* Current account. */
178
179 if (!accounts) {
180 accounts = (account_t *) malloc(sizeof(account_t));
181 if (!accounts) {
182 error("imapfilter: allocating memory; %s\n", strerror(errno));
183 return NULL;
184 }
185 ca = accounts;
186 } else {
187 ca->next = (account_t *) malloc(sizeof(account_t));
188 if (!ca->next) {
189 error("imapfilter: allocating memory; %s\n", strerror(errno));
190 return NULL;
191 }
192 ca = ca->next;
193 }
194
195 ca->next = NULL;
196
197 ca->server[0] = 0;
198 ca->port = 143;
199 ca->userid[0] = 0;
200 ca->passwd[0] = 0;
201
202 return ca;
203 }
204
205
206 /*
207 * An account setting was found from parse_config(), changes the
208 * apropriate variable.
209 */
210 int set_account(char *line, regmatch_t * match)
211 {
212 int s;
213 char p[6];
214 static account_t *ca;
215
216 if (!strncmp(line + match[1].rm_so, "SERVER", 6)) {
217 if (!(ca = prepare_account()))
218 return 1;
219 s = min((match[2].rm_eo - match[2].rm_so), SERVER_MAX - 1);
220 strncpy(ca->server, line + match[2].rm_so, s);
221 ca->server[s] = 0;
222 #ifdef DEBUG
223 printf("debug: account setting SERVER: '%s'\n", ca->server);
224 #endif
225 } else if (accounts) {
226 if (!strncmp(line + match[1].rm_so, "PORT", 4)) {
227 s = min((match[2].rm_eo - match[2].rm_so), sizeof(p));
228 strncpy(p, line + match[2].rm_so, s);
229 p[s] = 0;
230 ca->port = strtoul(p, NULL, 0);
231 #ifdef DEBUG
232 printf("debug: account setting PORT: %d\n", ca->port);
233 #endif
234 } else if (!strncmp(line + match[1].rm_so, "USERNAME", 8)) {
235 s = min((match[2].rm_eo - match[2].rm_so), USERID_MAX - 1);
236 strncpy(ca->userid, line + match[2].rm_so, s);
237 ca->userid[s] = 0;
238 #ifdef DEBUG
239 printf("debug: account setting USERNAME: '%s'\n", ca->userid);
240 #endif
241 } else if (!strncmp(line + match[1].rm_so, "PASSWORD", 8)) {
242 s = min((match[2].rm_eo - match[2].rm_so), PASSWD_MAX - 1);
243 strncpy(ca->passwd, line + match[2].rm_so, s);
244 ca->passwd[s] = 0;
245 #ifdef DEBUG
246 printf("debug: account setting PASSWORD: '%s'\n", ca->passwd);
247 #endif
248 }
249 }
250
251 return 0;
252 }
253
254
255 /*
256 * A filter entry was found from parse_config() processes it and saves it.
257 */
258 int set_filters(char *line, regmatch_t * match, int csm)
259 {
260 int s;
261 static filter_t *cdf, *caf;
262 filter_t **cf;
263 filter_t **fl;
264
265 if (!(strncmp(line + match[1].rm_so, "DENY", 4))) {
266 #ifdef DEBUG
267 printf("debug: filter entry DENY:");
268 #endif
269 cf = &cdf;
270 fl = &dfilters;
271 } else {
272 #ifdef DEBUG
273 printf("debug: filter entry ALLOW:");
274 #endif
275 cf = &caf;
276 fl = &afilters;
277 }
278
279 /*
280 * Allocate memory for filter entry and build linked list.
281 */
282
283 if (!(*fl)) {
284 *fl = (filter_t *) malloc(sizeof(filter_t));
285 if (!(*fl)) {
286 error("imapfilter: allocating memory; %s\n", strerror(errno));
287 return 1;
288 }
289 *cf = *fl;
290 } else {
291 (*cf)->next = (filter_t *) malloc(sizeof(filter_t));
292 if (!((*cf)->next)) {
293 error("imapfilter: allocating memory; %s\n", strerror(errno));
294 return 1;
295 }
296 *cf = (*cf)->next;
297 }
298
299 (*cf)->next = NULL;
300
301 (*cf)->custom = csm;
302
303 s = min((match[2].rm_eo - match[2].rm_so), FIELD_NAME_MAX - 1);
304 strncpy((*cf)->name, line + match[2].rm_so, s);
305 (*cf)->name[s] = 0;
306
307 s = min((match[3].rm_eo - match[3].rm_so), FIELD_BODY_MAX - 1);
308 strncpy((*cf)->body, line + match[3].rm_so, s);
309 (*cf)->body[s] = 0;
310
311 #ifdef DEBUG
312 printf(" '%s' '%s'\n", (*cf)->name, (*cf)->body);
313 #endif
314 return 0;
315 }
316
317
318 /*
319 * Sets the DENY and ALLOW limits from the values found in config file.
320 */
321 void set_limits(char *line, regmatch_t * match)
322 {
323 int s;
324 char lim[10];
325
326 s = min((match[2].rm_eo - match[2].rm_so), sizeof(lim));
327 strncpy(lim, line + match[2].rm_so, s);
328 lim[s] = 0;
329
330 if (!strncmp(line + match[1].rm_so, "DENY_LIMIT", 10)) {
331 dlimit = strtoul(lim, NULL, 0);
332 #ifdef DEBUG
333 printf("debug: size filter DENY_LIMIT: %d\n", dlimit);
334 #endif
335 } else {
336 alimit = strtoul(lim, NULL, 0);
337 #ifdef DEBUG
338 printf("debug: size filter ALLOW_LIMIT: %d\n", alimit);
339 #endif
340 }
341 }
342
343
344 /*
345 * Sets other options found in config file.
346 */
347 void set_options(char *line, regmatch_t * match)
348 {
349 int s;
350
351 if (!logfile[0] && !strncmp(line + match[1].rm_so, "LOGFILE", 7)) {
352 s = min((match[2].rm_eo - match[2].rm_so), PATH_MAX - 1);
353 strncpy(logfile, line + match[2].rm_so, s);
354 logfile[s] = 0;
355 } else if (!strncmp(line + match[1].rm_so, "TEST_MODE", 9) &&
356 !(options & OPT_TEST_MODE_STICKY)) {
357 if (!strncmp(line + match[2].rm_so, "yes", 3))
358 options |= OPT_TEST_MODE;
359 else if (options & OPT_TEST_MODE)
360 options ^= OPT_TEST_MODE;
361 } else if (!strncmp(line + match[1].rm_so, "SHOW_HEADERS", 12)) {
362 if (!strncmp(line + match[2].rm_so, "yes", 3))
363 options |= OPT_SHOW_HEADERS;
364 else if (options & OPT_UNSEEN_ONLY)
365 options ^= OPT_SHOW_HEADERS;
366 } else if (!strncmp(line + match[1].rm_so, "UNSEEN_ONLY", 11)) {
367 if (!strncmp(line + match[2].rm_so, "yes", 3))
368 options |= OPT_UNSEEN_ONLY;
369 else if (options & OPT_UNSEEN_ONLY)
370 options ^= OPT_UNSEEN_ONLY;
371 }
372 }

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26