1 #line 982 "../../src/builtin/snarf.m4"
2 /* -*- buffer-read-only: t -*- vi: set ro:
3    THIS FILE IS GENERATED AUTOMATICALLY.  PLEASE DO NOT EDIT.
4 */
5 #line 982
6 #ifdef HAVE_CONFIG_H
7 #line 982
8 # include <config.h>
9 #line 982
10 #endif
11 #line 982
12 #include <sys/types.h>
13 #line 982
14 
15 #line 982
16 #include "mailfromd.h"
17 #line 982
18 #include "prog.h"
19 #line 982
20 #include "builtin.h"
21 #line 982
22 
23 #line 211 "db.bi"
24 static mu_debug_handle_t debug_handle;
25 #line 982 "../../src/builtin/snarf.m4"
26 
27 #line 1022 "../../src/builtin/snarf.m4"
28 
29 /* End of snarf.m4 */
30 #line 1 "db.bi"
31 /* This file is part of Mailfromd.             -*- c -*-
32    Copyright (C) 2006-2021 Sergey Poznyakoff
33 
34    This program is free software; you can redistribute it and/or modify
35    it under the terms of the GNU General Public License as published by
36    the Free Software Foundation; either version 3, or (at your option)
37    any later version.
38 
39    This program is distributed in the hope that it will be useful,
40    but WITHOUT ANY WARRANTY; without even the implied warranty of
41    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
42    GNU General Public License for more details.
43 
44    You should have received a copy of the GNU General Public License
45    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
46 
47 
48 #define DEFAULT_DB_MODE 0640
49 #include <fnmatch.h>
50 
51 struct db_prop {                /* Database properties */
52 	char *pat;              /* Database name pattern */
53 	mode_t mode;            /* File mode */
54 	int null;               /* Null byte */
55 	mu_url_t hint;          /* Hint to use instead of the default one */
56 };
57 
58 static mu_list_t db_prop_list;
59 
60 static int
db_prop_compare(const void * item,const void * data)61 db_prop_compare(const void *item, const void *data)
62 {
63 	const struct db_prop *prop = item;
64 	const char *name = data;
65 	return strcmp(prop->pat, name);
66 }
67 
68 static int
strtomode(char * str,mode_t * pmode)69 strtomode(char *str, mode_t *pmode)
70 {
71 	mode_t mode = 0;
72 	struct { char c; unsigned mask; } modetab[] = {
73 		{ 'r', S_IRUSR },
74 		{ 'w', S_IWUSR },
75 		{ 'x', S_IXUSR },
76 		{ 'r', S_IRGRP },
77 		{ 'w', S_IWGRP },
78 		{ 'x', S_IXGRP },
79 		{ 'r', S_IROTH },
80 		{ 'w', S_IWOTH },
81 		{ 'x', S_IXOTH },
82 		{ 0 }
83 	};
84 	int i;
85 
86 	for (i = 0; modetab[i].c; i++) {
87 		if (!str[i])
88 			return i + 1;
89 		if (str[i] == modetab[i].c)
90 			mode |= modetab[i].mask;
91 		else if (str[i] != '-')
92 			return i + 1;
93 	}
94 	if (str[i])
95 		return i + 1;
96 	*pmode = mode;
97 	return 0;
98 }
99 
100 static int
is_url(const char * p)101 is_url(const char *p)
102 {
103 	for (; *p && mu_isalnum(*p); p++)
104 		;
105 	return *p == ':';
106 }
107 
108 /* #pragma dbprop <name> [null] [mode] [hint]
109    At least one of the bracketed parameters must be present.  Two or more
110    parameters can be given in arbitrary order.
111  */
112 #line 82 "db.bi"
113 
114 #line 82
_pragma_dbprop(int argc,char ** argv,const char * text)115 static void _pragma_dbprop (int argc, char **argv, const char *text)
116 #line 82
117 
118 {
119 	int null = 0;
120 	mode_t mode = DEFAULT_DB_MODE;
121 	struct db_prop *prop;
122 	int rc;
123 	char *pat;
124 	mu_url_t hint = NULL;
125 
126 	--argc;
127 	pat = *++argv;
128 
129 	while (--argc) {
130 		char *p = *++argv;
131 
132 		if (strcmp(p, "null") == 0)
133 			null = 1;
134 		else if (mu_isdigit(*p)) {
135 			unsigned long n = strtoul(p, &p, 8);
136 			if (*p || (mode = n) != n) {
137 				parse_error(_("bad numeric file mode"));
138 				return;
139 			}
140 		} else if (is_url(p)) {
141 			rc = mu_url_create(&hint, p);
142 			if (rc) {
143 				parse_error(_("not a valid URL: %s"),
144 					    mu_strerror(rc));
145 				return;
146 			}
147 		} else if (rc = strtomode(p, &mode)) {
148 			parse_error(_("bad symbolic file mode (near %s)"),
149 				    p + rc - 1);
150 			return;
151 		}
152 	}
153 
154 	if (!db_prop_list) {
155 		rc = mu_list_create(&db_prop_list);
156 		if (rc) {
157 			parse_error(_("cannot create list: %s"),
158 				    mu_strerror(rc));
159 			return;
160 		}
161 		mu_list_set_comparator(db_prop_list, db_prop_compare);
162 	}
163 
164 	if (mu_list_locate(db_prop_list, pat, (void**) &prop)) {
165 		prop = mu_alloc(sizeof(*prop));
166 		prop->pat = mu_strdup(pat);
167 		rc = mu_list_append(db_prop_list, prop);
168 		if (rc) {
169 			parse_error(_("Cannot create list: %s"),
170 				    mu_strerror(rc));
171 			return;
172 		}
173 	}
174 	prop->mode = mode;
175 	prop->null = null;
176 	prop->hint = hint;
177 }
178 
179 const struct db_prop *
db_prop_lookup(const char * name)180 db_prop_lookup(const char *name)
181 {
182 	mu_iterator_t itr;
183 	const struct db_prop *found = NULL;
184 
185 	if (db_prop_list
186 	    && mu_list_get_iterator(db_prop_list, &itr) == 0) {
187 		for (mu_iterator_first(itr);
188 		     !mu_iterator_is_done(itr);
189 		     mu_iterator_next(itr)) {
190 			const struct db_prop *p;
191 			mu_iterator_current(itr, (void**)&p);
192 			if (strcmp(p->pat, name) == 0) {
193 				found = p;
194 				break;
195 			} else if (fnmatch(p->pat, name, 0) == 0)
196 				found = p;
197 		}
198 		mu_iterator_destroy(&itr);
199 	}
200 	return found;
201 }
202 
203 int
_open_dbm(mu_dbm_file_t * pdb,char * dbname,int access,int mode,mu_url_t hint)204 _open_dbm(mu_dbm_file_t *pdb, char *dbname, int access, int mode,
205 	  mu_url_t hint)
206 {
207 	mu_dbm_file_t db;
208 	int rc;
209 	mu_url_t url;
210 
211 	if (!hint)
212 		hint = mu_dbm_get_hint();
213 	rc = mu_url_create_hint(&url, dbname, 0, hint);
214 	if (rc) {
215 		mu_error(_("cannot create database URL for %s: %s"),
216 			 dbname, mu_strerror(rc));
217 		return rc;
218 	}
219 	rc = mu_dbm_create_from_url(url, &db,
220 				    mf_file_mode_to_safety_criteria(mode));
221 	mu_url_destroy(&url);
222 	if (rc)
223 		return rc;
224 
225 	rc = mu_dbm_safety_check(db);
226 	if (rc && rc != ENOENT) {
227 		mu_error(_("%s fails safety check: %s"),
228 			 dbname, mu_strerror(rc));
229 		mu_dbm_destroy(&db);
230 		return rc;
231 	}
232 
233 	rc = mu_dbm_open(db, access, mode);
234 	if (rc) {
235 		mu_dbm_destroy(&db);
236 		return rc;
237 	}
238 	*pdb = db;
239 	return rc;
240 }
241 
242 
243 #define LOOKUP_NULL_BYTE 0x1
244 #define LOOKUP_TEST_ONLY 0x2
245 
246 
247 #line 211
248 
249 #line 211
250 static int
251 #line 211
dbmap_lookup(eval_environ_t env,char * dbname,const char * keystr,const char * defval,const struct db_prop * prop,int flags)252 dbmap_lookup(eval_environ_t env, char *dbname, const char *keystr,
253 #line 211
254 	     const char *defval, const struct db_prop *prop, int flags)
255 #line 211
256 {
257 #line 211
258 	int rc;
259 #line 211
260 	mu_dbm_file_t db;
261 #line 211
262 	struct mu_dbm_datum key;
263 #line 211
264 	struct mu_dbm_datum contents;
265 #line 211
266 
267 #line 211
268 	if (!defval)
269 #line 211
270 		defval = "";
271 #line 211
272 	rc = _open_dbm(&db, dbname, MU_STREAM_READ,
273 #line 211
274 		       prop ? prop->mode : DEFAULT_DB_MODE,
275 #line 211
276 		       prop ? prop->hint : NULL);
277 #line 211
278 	if (rc)
279 #line 211
280 		(
281 #line 211
282 	env_throw_bi(env, mfe_dbfailure, NULL, _("mf_dbm_open(%s) failed: %s"),dbname,mu_strerror(rc))
283 #line 211
284 );
285 #line 211
286 
287 #line 211
288 	memset(&key, 0, sizeof key);
289 #line 211
290 	memset(&contents, 0, sizeof contents);
291 #line 211
292 	key.mu_dptr = (void*) keystr;
293 #line 211
294 	key.mu_dsize = strlen(keystr);
295 #line 211
296 	if (flags & LOOKUP_NULL_BYTE)
297 #line 211
298 		key.mu_dsize++;
299 #line 211
300 	rc = mu_dbm_fetch(db, &key, &contents);
301 #line 211
302 	if (rc && rc != MU_ERR_NOENT) {
303 #line 211
304 		mu_dbm_destroy(&db);
305 #line 211
306 		(
307 #line 211
308 	env_throw_bi(env, mfe_dbfailure, NULL, _("cannot fetch data: %s"),mu_dbm_strerror(db))
309 #line 211
310 );
311 #line 211
312 	}
313 #line 211
314 
315 #line 211 "db.bi"
316 
317 #line 211
318 mu_debug(debug_handle, MU_DEBUG_TRACE5,("Looking up %s: %s", keystr, rc ? "false" : "true"));
319 #line 211
320 	if (flags & LOOKUP_TEST_ONLY)
321 #line 211
322 		push(env, (STKVAL) (rc == 0));
323 #line 211
324 	else {
325 #line 211
326 		if (rc) {
327 #line 211
328 			if (defval)
329 #line 211
330 				pushs(env, defval);
331 #line 211
332 			else
333 #line 211
334 				push(env, (STKVAL) 0L);
335 #line 211
336 		} else if (((char*)contents.mu_dptr)[contents.mu_dsize-1]) {
337 #line 211
338 			size_t off;
339 #line 211
340 			size_t len = contents.mu_dsize;
341 #line 211
342 			char *s = (char*) env_data_ref(env, (off = heap_reserve(env, len + 1)));
343 #line 211
344 			memcpy(s, contents.mu_dptr, len);
345 #line 211
346 			s[len] = 0;
347 #line 211
348 			push(env, (STKVAL) off);
349 #line 211
350 		} else
351 #line 211
352 			pushs(env, contents.mu_dptr);
353 #line 211
354 	}
355 #line 211
356 	mu_dbm_datum_free(&contents);
357 #line 211
358 	mu_dbm_destroy(&db);
359 #line 211
360 	return rc;
361 #line 211
362 }
363 #line 211
364 
365 #line 211
366 
367 #line 211
368 
369 #line 269
370 
371 
372 
373 void
374 #line 272
bi_dbmap(eval_environ_t env)375 bi_dbmap(eval_environ_t env)
376 #line 272
377 
378 #line 272
379 
380 #line 272 "db.bi"
381 {
382 #line 272
383 
384 #line 272
385 
386 #line 272
387 long __bi_argcnt;
388 #line 272
389 char * MFL_DATASEG dbname;
390 #line 272
391         char * MFL_DATASEG key;
392 #line 272
393         long  null;
394 #line 272
395 
396 #line 272
397 get_string_arg(env, 1, &dbname);
398 #line 272
399         get_string_arg(env, 2, &key);
400 #line 272
401         get_numeric_arg(env, 3, &null);
402 #line 272
403 
404 #line 272
405 get_numeric_arg(env, 0, &__bi_argcnt);
406 #line 272
407         adjust_stack(env, __bi_argcnt + 1);
408 #line 272
409 
410 #line 272
411 
412 #line 272
413 	if (builtin_module_trace(BUILTIN_IDX_db))
414 #line 272
415 		prog_trace(env, "dbmap %s %s %lu",dbname, key, ((__bi_argcnt > 2) ? null : 0));;
416 #line 272
417 
418 {
419 	const struct db_prop *prop = db_prop_lookup(dbname);
420 
421 #line 275
422 dbmap_lookup(env,dbname,key,NULL,prop,LOOKUP_TEST_ONLY |
423 		         (((__bi_argcnt > 2) ? null : prop && prop->null)
424 			   ? LOOKUP_NULL_BYTE : 0));
425 #line 280
426 }
427 
428 #line 281
429         env_function_cleanup_flush(env, NULL);
430 #line 281
431 	return;
432 #line 281
433 }
434 
435 void
436 #line 283
bi_dbget(eval_environ_t env)437 bi_dbget(eval_environ_t env)
438 #line 283
439 
440 #line 283
441 
442 #line 283 "db.bi"
443 {
444 #line 283
445 
446 #line 283
447 
448 #line 283
449 long __bi_argcnt;
450 #line 283
451 char * MFL_DATASEG dbname;
452 #line 283
453         char * MFL_DATASEG key;
454 #line 283
455         char * MFL_DATASEG defval;
456 #line 283
457         long  null;
458 #line 283
459 
460 #line 283
461 get_string_arg(env, 1, &dbname);
462 #line 283
463         get_string_arg(env, 2, &key);
464 #line 283
465         get_string_arg(env, 3, &defval);
466 #line 283
467         get_numeric_arg(env, 4, &null);
468 #line 283
469 
470 #line 283
471 get_numeric_arg(env, 0, &__bi_argcnt);
472 #line 283
473         adjust_stack(env, __bi_argcnt + 1);
474 #line 283
475 
476 #line 283
477 
478 #line 283
479 	if (builtin_module_trace(BUILTIN_IDX_db))
480 #line 283
481 		prog_trace(env, "dbget %s %s %s %lu",dbname, key, ((__bi_argcnt > 2) ? defval : ""), ((__bi_argcnt > 3) ? null : 0));;
482 
483 {
484 	const struct db_prop *prop = db_prop_lookup(dbname);
485 
486 #line 287
487 dbmap_lookup(env,dbname,key,((__bi_argcnt > 2) ? defval : 0),prop,((__bi_argcnt > 3) ? null : prop && prop->null)
488 		      ? LOOKUP_NULL_BYTE : 0);
489 #line 292
490 }
491 
492 #line 293
493         env_function_cleanup_flush(env, NULL);
494 #line 293
495 	return;
496 #line 293
497 }
498 
499 void
500 #line 295
bi_dbput(eval_environ_t env)501 bi_dbput(eval_environ_t env)
502 #line 295
503 
504 #line 295
505 
506 #line 295 "db.bi"
507 {
508 #line 295
509 
510 #line 295
511 
512 #line 295
513 long __bi_argcnt;
514 #line 295
515 char *  dbname;
516 #line 295
517         char *  keystr;
518 #line 295
519         char *  value;
520 #line 295
521         long  null;
522 #line 295
523         long  mode;
524 #line 295
525 
526 #line 295
527 get_string_arg(env, 1, &dbname);
528 #line 295
529         get_string_arg(env, 2, &keystr);
530 #line 295
531         get_string_arg(env, 3, &value);
532 #line 295
533         get_numeric_arg(env, 4, &null);
534 #line 295
535         get_numeric_arg(env, 5, &mode);
536 #line 295
537 
538 #line 295
539 get_numeric_arg(env, 0, &__bi_argcnt);
540 #line 295
541         adjust_stack(env, __bi_argcnt + 1);
542 #line 295
543 
544 #line 295
545 
546 #line 295
547 	if (builtin_module_trace(BUILTIN_IDX_db))
548 #line 295
549 		prog_trace(env, "dbput %s %s %s %lu %lu",dbname, keystr, value, ((__bi_argcnt > 3) ? null : 0), ((__bi_argcnt > 4) ? mode : 0));;
550 
551 {
552 	int rc;
553 	mu_dbm_file_t db;
554 	struct mu_dbm_datum key;
555 	struct mu_dbm_datum contents;
556 	const struct db_prop *prop = db_prop_lookup(dbname);
557 
558 	rc = _open_dbm(&db, dbname, MU_STREAM_RDWR,
559 		       ((__bi_argcnt > 4) ? mode : (prop ? prop->mode : DEFAULT_DB_MODE)),
560 #line 307
561 		       prop ? prop->hint : NULL);
562 	if (rc)
563 		(
564 #line 309
565 	env_throw_bi(env, mfe_dbfailure, "dbput", _("mf_dbm_open(%s) failed: %s"),dbname,mu_strerror(rc))
566 #line 309
567 );
568 #line 313
569 	memset(&key, 0, sizeof key);
570 	key.mu_dptr = keystr;
571 	key.mu_dsize = strlen(keystr);
572 	if (((__bi_argcnt > 3) ? null : prop && prop->null))
573 		key.mu_dsize++;
574 
575 	memset(&contents, 0, sizeof contents);
576 	contents.mu_dptr = value;
577 	contents.mu_dsize = strlen(value) + 1;
578 
579 	rc = mu_dbm_store(db, &key, &contents, 1);
580 	if (rc) {
581 		const char *errstr = mu_dbm_strerror(db);
582 		mu_dbm_destroy(&db);
583 		(
584 #line 327
585 	env_throw_bi(env, mfe_dbfailure, "dbput", _("failed to insert data to %s: %s %s: %s"),dbname,keystr,value,errstr)
586 #line 327
587 );
588 #line 333
589 	}
590 	mu_dbm_destroy(&db);
591 }
592 
593 #line 336
594         env_function_cleanup_flush(env, NULL);
595 #line 336
596 	return;
597 #line 336
598 }
599 
600 void
601 #line 338
bi_dbinsert(eval_environ_t env)602 bi_dbinsert(eval_environ_t env)
603 #line 338
604 
605 #line 338
606 
607 #line 338 "db.bi"
608 {
609 #line 338
610 
611 #line 338
612 
613 #line 338
614 long __bi_argcnt;
615 #line 338
616 char *  dbname;
617 #line 338
618         char *  keystr;
619 #line 338
620         char *  value;
621 #line 338
622         long  replace;
623 #line 338
624         long  null;
625 #line 338
626         long  mode;
627 #line 338
628 
629 #line 338
630 get_string_arg(env, 1, &dbname);
631 #line 338
632         get_string_arg(env, 2, &keystr);
633 #line 338
634         get_string_arg(env, 3, &value);
635 #line 338
636         get_numeric_arg(env, 4, &replace);
637 #line 338
638         get_numeric_arg(env, 5, &null);
639 #line 338
640         get_numeric_arg(env, 6, &mode);
641 #line 338
642 
643 #line 338
644 get_numeric_arg(env, 0, &__bi_argcnt);
645 #line 338
646         adjust_stack(env, __bi_argcnt + 1);
647 #line 338
648 
649 #line 338
650 
651 #line 338
652 	if (builtin_module_trace(BUILTIN_IDX_db))
653 #line 338
654 		prog_trace(env, "dbinsert %s %s %s %lu %lu %lu",dbname, keystr, value, ((__bi_argcnt > 3) ? replace : 0), ((__bi_argcnt > 4) ? null : 0), ((__bi_argcnt > 5) ? mode : 0));;
655 
656 {
657 	int rc;
658 	mu_dbm_file_t db;
659 	struct mu_dbm_datum key;
660 	struct mu_dbm_datum contents;
661 	const struct db_prop *prop = db_prop_lookup(dbname);
662 	const char *errstr;
663 
664 	rc = _open_dbm(&db, dbname, MU_STREAM_RDWR,
665 		       ((__bi_argcnt > 5) ? mode : (prop ? prop->mode : DEFAULT_DB_MODE)),
666 #line 351
667 		       prop ? prop->hint : NULL);
668 	if (rc)
669 		(
670 #line 353
671 	env_throw_bi(env, mfe_dbfailure, "dbinsert", _("mf_dbm_open(%s) failed: %s"),dbname,mu_strerror(rc))
672 #line 353
673 );
674 #line 357
675 	memset(&key, 0, sizeof key);
676 	key.mu_dptr = keystr;
677 	key.mu_dsize = strlen(keystr);
678 	if (((__bi_argcnt > 4) ? null : prop && prop->null))
679 		key.mu_dsize++;
680 
681 	memset(&contents, 0, sizeof contents);
682 	contents.mu_dptr = value;
683 	contents.mu_dsize = strlen(value) + 1;
684 
685 	rc = mu_dbm_store(db, &key, &contents, ((__bi_argcnt > 3) ? replace : 0));
686 	if (rc && rc != MU_ERR_EXISTS)
687 		errstr = mu_dbm_strerror(db);
688 	mu_dbm_destroy(&db);
689 	if (rc == MU_ERR_EXISTS)
690 		(
691 #line 372
692 	env_throw_bi(env, mfe_exists, "dbinsert", _("record already exists"))
693 #line 372
694 );
695 
696 		if (!(rc == 0))
697 #line 374
698 		(
699 #line 374
700 	env_throw_bi(env, mfe_dbfailure, "dbinsert", _("failed to insert data to %s: %s %s: %s"),dbname,keystr,value,errstr)
701 #line 374
702 )
703 #line 380
704 ;
705 }
706 
707 #line 382
708         env_function_cleanup_flush(env, NULL);
709 #line 382
710 	return;
711 #line 382
712 }
713 
714 void
715 #line 384
bi_dbdel(eval_environ_t env)716 bi_dbdel(eval_environ_t env)
717 #line 384
718 
719 #line 384
720 
721 #line 384 "db.bi"
722 {
723 #line 384
724 
725 #line 384
726 
727 #line 384
728 long __bi_argcnt;
729 #line 384
730 char *  dbname;
731 #line 384
732         char *  keystr;
733 #line 384
734         long  null;
735 #line 384
736         long  mode;
737 #line 384
738 
739 #line 384
740 get_string_arg(env, 1, &dbname);
741 #line 384
742         get_string_arg(env, 2, &keystr);
743 #line 384
744         get_numeric_arg(env, 3, &null);
745 #line 384
746         get_numeric_arg(env, 4, &mode);
747 #line 384
748 
749 #line 384
750 get_numeric_arg(env, 0, &__bi_argcnt);
751 #line 384
752         adjust_stack(env, __bi_argcnt + 1);
753 #line 384
754 
755 #line 384
756 
757 #line 384
758 	if (builtin_module_trace(BUILTIN_IDX_db))
759 #line 384
760 		prog_trace(env, "dbdel %s %s %lu %lu",dbname, keystr, ((__bi_argcnt > 2) ? null : 0), ((__bi_argcnt > 3) ? mode : 0));;
761 
762 {
763 	mu_dbm_file_t db;
764 	struct mu_dbm_datum key;
765 	int rc;
766 	const struct db_prop *prop = db_prop_lookup(dbname);
767 
768 	rc = _open_dbm(&db, dbname, MU_STREAM_RDWR,
769 		       ((__bi_argcnt > 3) ? mode : (prop ? prop->mode : DEFAULT_DB_MODE)),
770 #line 395
771 		       prop ? prop->hint : NULL);
772 		if (!(rc == 0))
773 #line 396
774 		(
775 #line 396
776 	env_throw_bi(env, mfe_dbfailure, "dbdel", _("mf_dbm_open(%s) failed: %s"),dbname,mu_strerror(rc))
777 #line 396
778 )
779 #line 400
780 ;
781 	memset(&key, 0, sizeof key);
782 	key.mu_dptr = keystr;
783 	key.mu_dsize = strlen(keystr);
784 	if (((__bi_argcnt > 2) ? null : prop && prop->null))
785 		key.mu_dsize++;
786 	rc = mu_dbm_delete(db, &key);
787 	mu_dbm_destroy(&db);
788 		if (!(rc == 0 || rc == MU_ERR_NOENT))
789 #line 408
790 		(
791 #line 408
792 	env_throw_bi(env, mfe_dbfailure, "dbdel", _("failed to delete data `%s' from `%s': %s"),keystr,dbname,mu_strerror(rc))
793 #line 408
794 )
795 #line 413
796 ;
797 }
798 
799 #line 415
800         env_function_cleanup_flush(env, NULL);
801 #line 415
802 	return;
803 #line 415
804 }
805 
806 
807 #define NUMDB 128
808 
809 struct db_tab {
810 	int used;
811 	mu_dbm_file_t db;
812 	struct mu_dbm_datum key;
813 };
814 
815 static void *
alloc_db_tab()816 alloc_db_tab()
817 {
818 	return mu_calloc(NUMDB, sizeof(struct db_tab));
819 }
820 
821 static void
close_db_tab(struct db_tab * dbt)822 close_db_tab(struct db_tab *dbt)
823 {
824 	if (dbt->used) {
825 		mu_dbm_datum_free(&dbt->key);
826 		mu_dbm_destroy(&dbt->db);
827 		dbt->used = 0;
828 	}
829 }
830 
831 static void
destroy_db_tab(void * data)832 destroy_db_tab(void *data)
833 {
834 	int i;
835 	struct db_tab *db = data;
836 	for (i = 0; i < NUMDB; i++)
837 		close_db_tab(db + i);
838 	free(db);
839 }
840 
841 
842 #line 452
843 
844 #line 452
845 static int DBTAB_id;
846 #line 452 "db.bi"
847 ;
848 
849 static int
new_db_tab(struct db_tab * dbt)850 new_db_tab(struct db_tab *dbt)
851 {
852 	int i;
853 	for (i = 0; i < NUMDB; i++)
854 		if (!dbt[i].used) {
855 			dbt[i].used = 1;
856 			return i;
857 		}
858 	return -1;
859 }
860 
861 
862 
863 void
864 #line 468
bi_dbfirst(eval_environ_t env)865 bi_dbfirst(eval_environ_t env)
866 #line 468
867 
868 #line 468
869 
870 #line 468 "db.bi"
871 {
872 #line 468
873 
874 #line 468
875 
876 #line 468
877 
878 #line 468
879 char *  dbname;
880 #line 468
881 
882 #line 468
883 get_string_arg(env, 0, &dbname);
884 #line 468
885 
886 #line 468
887 
888 #line 468
889         adjust_stack(env, 1);
890 #line 468
891 
892 #line 468
893 
894 #line 468
895 	if (builtin_module_trace(BUILTIN_IDX_db))
896 #line 468
897 		prog_trace(env, "dbfirst %s",dbname);;
898 #line 468
899 
900 {
901 	int rc;
902 	int n;
903 	struct db_tab *dbt = env_get_builtin_priv(env,DBTAB_id);
904 	mu_dbm_file_t db;
905 	struct mu_dbm_datum key;
906 	const struct db_prop *prop = db_prop_lookup(dbname);
907 
908 	rc = _open_dbm(&db, dbname, MU_STREAM_READ,
909 		       prop ? prop->mode : DEFAULT_DB_MODE,
910 		       prop ? prop->hint : NULL);
911 		if (!(rc == 0))
912 #line 480
913 		(
914 #line 480
915 	env_throw_bi(env, mfe_dbfailure, "dbfirst", _("mf_dbm_open(%s) failed: %s"),dbname,mu_strerror(rc))
916 #line 480
917 )
918 #line 484
919 ;
920 	memset(&key, 0, sizeof key);
921 	rc = mu_dbm_firstkey(db, &key);
922 	if (rc) {
923 		if (rc == MU_ERR_NOENT) {
924 			mu_dbm_destroy(&db);
925 
926 #line 490
927 do {
928 #line 490
929   push(env, (STKVAL)(mft_number)(0));
930 #line 490
931   goto endlab;
932 #line 490
933 } while (0);
934 		} else if (rc) {
935 			mu_dbm_destroy(&db);
936 			(
937 #line 493
938 	env_throw_bi(env, mfe_dbfailure, "dbfirst", _("mf_dbm_firstkey failed: %s"),mu_strerror(rc))
939 #line 493
940 );
941 #line 496
942 		}
943 	}
944 	n = new_db_tab(dbt);
945 		if (!(n >= 0))
946 #line 499
947 		(
948 #line 499
949 	env_throw_bi(env, mfe_failure, "dbfirst", _("no more database entries available"))
950 #line 499
951 )
952 #line 501
953 ;
954 	dbt += n;
955 	dbt->db = db;
956 	dbt->key = key;
957 
958 #line 505
959 do {
960 #line 505
961   push(env, (STKVAL)(mft_number)(n));
962 #line 505
963   goto endlab;
964 #line 505
965 } while (0);
966 }
967 endlab:
968 #line 507
969         env_function_cleanup_flush(env, NULL);
970 #line 507
971 	return;
972 #line 507
973 }
974 
975 void
976 #line 509
bi_dbnext(eval_environ_t env)977 bi_dbnext(eval_environ_t env)
978 #line 509
979 
980 #line 509
981 
982 #line 509 "db.bi"
983 {
984 #line 509
985 
986 #line 509
987 
988 #line 509
989 
990 #line 509
991 long  dn;
992 #line 509
993 
994 #line 509
995 get_numeric_arg(env, 0, &dn);
996 #line 509
997 
998 #line 509
999 
1000 #line 509
1001         adjust_stack(env, 1);
1002 #line 509
1003 
1004 #line 509
1005 
1006 #line 509
1007 	if (builtin_module_trace(BUILTIN_IDX_db))
1008 #line 509
1009 		prog_trace(env, "dbnext %lu",dn);;
1010 #line 509
1011 
1012 {
1013 	struct db_tab *dbt = env_get_builtin_priv(env,DBTAB_id) + dn;
1014 	struct mu_dbm_datum nextkey;
1015 	int rc;
1016 
1017 		if (!(dn >= 0 && dn < NUMDB && dbt->used))
1018 #line 515
1019 		(
1020 #line 515
1021 	env_throw_bi(env, mfe_range, "dbnext", _("invalid database descriptor"))
1022 #line 515
1023 )
1024 #line 517
1025 ;
1026 
1027 	memset (&nextkey, 0, sizeof nextkey);
1028 	rc = mu_dbm_nextkey(dbt->db, &nextkey);
1029 	if (rc) {
1030 		if (rc == MU_ERR_FAILURE)
1031 			mu_error(_("mu_dbm_nextkey: %s"),
1032 				 mu_dbm_strerror(dbt->db));
1033 		close_db_tab(dbt);
1034 
1035 #line 526
1036 do {
1037 #line 526
1038   push(env, (STKVAL)(mft_number)(0));
1039 #line 526
1040   goto endlab;
1041 #line 526
1042 } while (0);
1043 	}
1044 	mu_dbm_datum_free(&nextkey);
1045 	dbt->key = nextkey;
1046 
1047 #line 530
1048 do {
1049 #line 530
1050   push(env, (STKVAL)(mft_number)(1));
1051 #line 530
1052   goto endlab;
1053 #line 530
1054 } while (0);
1055 }
1056 endlab:
1057 #line 532
1058         env_function_cleanup_flush(env, NULL);
1059 #line 532
1060 	return;
1061 #line 532
1062 }
1063 
1064 void
1065 #line 534
bi_dbkey(eval_environ_t env)1066 bi_dbkey(eval_environ_t env)
1067 #line 534
1068 
1069 #line 534
1070 
1071 #line 534 "db.bi"
1072 {
1073 #line 534
1074 
1075 #line 534
1076 
1077 #line 534
1078 
1079 #line 534
1080 long  dn;
1081 #line 534
1082 
1083 #line 534
1084 get_numeric_arg(env, 0, &dn);
1085 #line 534
1086 
1087 #line 534
1088 
1089 #line 534
1090         adjust_stack(env, 1);
1091 #line 534
1092 
1093 #line 534
1094 
1095 #line 534
1096 	if (builtin_module_trace(BUILTIN_IDX_db))
1097 #line 534
1098 		prog_trace(env, "dbkey %lu",dn);;
1099 #line 534
1100 
1101 {
1102 	size_t off, len;
1103 	char *s;
1104 	struct db_tab *dbt = env_get_builtin_priv(env,DBTAB_id) + dn;
1105 
1106 		if (!(dn >= 0 && dn < NUMDB && dbt->used))
1107 #line 540
1108 		(
1109 #line 540
1110 	env_throw_bi(env, mfe_range, "dbkey", _("invalid database descriptor"))
1111 #line 540
1112 )
1113 #line 542
1114 ;
1115 
1116 	len = dbt->key.mu_dsize;
1117 	s = (char*) env_data_ref(env, (off = heap_reserve(env, len + 1)));
1118 	memcpy(s, dbt->key.mu_dptr, len);
1119 	s[len] = 0;
1120 
1121 #line 548
1122 do {
1123 #line 548
1124   push(env, (STKVAL) (mft_size) (off));
1125 #line 548
1126   goto endlab;
1127 #line 548
1128 } while (0);
1129 }
1130 endlab:
1131 #line 550
1132         env_function_cleanup_flush(env, NULL);
1133 #line 550
1134 	return;
1135 #line 550
1136 }
1137 
1138 void
1139 #line 552
bi_dbvalue(eval_environ_t env)1140 bi_dbvalue(eval_environ_t env)
1141 #line 552
1142 
1143 #line 552
1144 
1145 #line 552 "db.bi"
1146 {
1147 #line 552
1148 
1149 #line 552
1150 
1151 #line 552
1152 
1153 #line 552
1154 long  dn;
1155 #line 552
1156 
1157 #line 552
1158 get_numeric_arg(env, 0, &dn);
1159 #line 552
1160 
1161 #line 552
1162 
1163 #line 552
1164         adjust_stack(env, 1);
1165 #line 552
1166 
1167 #line 552
1168 
1169 #line 552
1170 	if (builtin_module_trace(BUILTIN_IDX_db))
1171 #line 552
1172 		prog_trace(env, "dbvalue %lu",dn);;
1173 #line 552
1174 
1175 {
1176 	int rc;
1177 	size_t off, len;
1178 	char *s;
1179 	struct db_tab *dbt = env_get_builtin_priv(env,DBTAB_id) + dn;
1180 	struct mu_dbm_datum contents;
1181 
1182 		if (!(dn >= 0 && dn < NUMDB && dbt->used))
1183 #line 560
1184 		(
1185 #line 560
1186 	env_throw_bi(env, mfe_range, "dbvalue", _("invalid database descriptor"))
1187 #line 560
1188 )
1189 #line 562
1190 ;
1191 
1192 	memset(&contents, 0, sizeof contents);
1193 	rc = mu_dbm_fetch(dbt->db, &dbt->key, &contents);
1194 		if (!(rc == 0))
1195 #line 566
1196 		(
1197 #line 566
1198 	env_throw_bi(env, mfe_dbfailure, "dbvalue", _("cannot fetch key: %s"),rc == MU_ERR_FAILURE ?
1199 		   mu_dbm_strerror(dbt->db) : mu_strerror (rc))
1200 #line 566
1201 )
1202 #line 570
1203 ;
1204 
1205 	len = contents.mu_dsize;
1206 	s = (char*) env_data_ref(env, (off = heap_reserve(env, len + 1)));
1207 	memcpy(s, contents.mu_dptr, len);
1208 	s[len] = 0;
1209 	mu_dbm_datum_free(&contents);
1210 
1211 #line 577
1212 do {
1213 #line 577
1214   push(env, (STKVAL) (mft_size) (off));
1215 #line 577
1216   goto endlab;
1217 #line 577
1218 } while (0);
1219 }
1220 endlab:
1221 #line 579
1222         env_function_cleanup_flush(env, NULL);
1223 #line 579
1224 	return;
1225 #line 579
1226 }
1227 
1228 
1229 enum greylist_semantics
1230 {
1231 	greylist_traditional,
1232 	greylist_ct
1233 };
1234 
1235 static enum greylist_semantics greylist_semantics = greylist_traditional;
1236 
1237 /* #pragma greylist {traditional|gray|ct|con-tassios}*/
1238 #line 591 "db.bi"
1239 
1240 #line 591
_pragma_greylist(int argc,char ** argv,const char * text)1241 static void _pragma_greylist (int argc, char **argv, const char *text)
1242 #line 591
1243 
1244 {
1245 	if (strcmp(argv[1], "traditional") == 0
1246 	    || strcmp(argv[1], "gray") == 0)
1247 		greylist_semantics = greylist_traditional;
1248 	else if (strcmp(argv[1], "ct") == 0
1249 		 || strcmp(argv[1], "con-tassios") == 0)
1250 		greylist_semantics = greylist_ct;
1251 	else
1252 		/* TRANSLATORS: Do not translate keywords:
1253 		   traditional, gray, ct, con-tassios */
1254 		parse_error(_("unknown semantics; allowed values are: "
1255 			      "traditional (or gray) and "
1256 			      "ct (or con-tassios)"));
1257 }
1258 
1259 /* FIXME: Duplicated in lib/cache.c */
1260 static char *
format_timestr(time_t timestamp,char * timebuf,size_t bufsize)1261 format_timestr(time_t timestamp, char *timebuf, size_t bufsize)
1262 {
1263 	struct tm tm;
1264 	gmtime_r(&timestamp, &tm);
1265 	strftime(timebuf, bufsize, "%c", &tm);
1266 	return timebuf;
1267 }
1268 
1269 static size_t greylist_seconds_left_loc
1270 #line 617 "db.bi"
1271 ;
1272 
1273 /* The traditional (aka gray's) greylist implementation: the greylist
1274    database keeps the time the greylisting was activated.
1275  */
1276 static int
do_greylist_traditional(eval_environ_t env,char * email,long interval)1277 do_greylist_traditional(eval_environ_t env, char *email, long interval)
1278 {
1279 	int rc;
1280 	mu_dbm_file_t db;
1281 	struct mu_dbm_datum key;
1282 	struct mu_dbm_datum contents;
1283 	int readonly = 0;
1284 	time_t now;
1285 
1286 	rc = _open_dbm(&db, greylist_format->dbname, MU_STREAM_RDWR, 0600,
1287 		       NULL);
1288 	if (rc) {
1289 		rc = _open_dbm(&db, greylist_format->dbname,
1290 			       MU_STREAM_READ, 0600, NULL);
1291 		readonly = 1;
1292 	}
1293         	if (!(rc == 0))
1294 #line 639
1295 		(
1296 #line 639
1297 	env_throw_bi(env, mfe_dbfailure, NULL, _("mf_dbm_open(%s) failed: %s"),greylist_format->dbname,mu_strerror(rc))
1298 #line 639
1299 )
1300 ;
1301 
1302 	memset(&key, 0, sizeof key);
1303 	memset(&contents, 0, sizeof contents);
1304 	key.mu_dptr = email;
1305 	key.mu_dsize = strlen(email)+1;
1306 
1307 	time(&now);
1308 	rc = mu_dbm_fetch(db, &key, &contents);
1309 	if (rc == 0) {
1310 		time_t timestamp, diff;
1311 
1312 			if (!(contents.mu_dsize == sizeof timestamp))
1313 #line 652
1314 		(
1315 #line 652
1316 	env_throw_bi(env, mfe_dbfailure, NULL, _("greylist database %s has wrong data size"),greylist_format->dbname)
1317 #line 652
1318 )
1319 #line 655
1320 ;
1321 
1322 		timestamp = *(time_t*) contents.mu_dptr;
1323 		diff = now - timestamp;
1324 
1325 		if (mu_debug_level_p(debug_handle, MU_DEBUG_TRACE5)) {
1326 			char timebuf[32];
1327 			mu_debug_log("%s entered greylist database on %s, "
1328 				     "%ld seconds ago",
1329 				     email,
1330 				     format_timestr(timestamp, timebuf,
1331 						    sizeof timebuf),
1332 				     (long) diff);
1333 		}
1334 
1335 		if (diff < interval) {
1336 			diff = interval - diff;
1337 
1338 			mf_c_val(*env_data_ref(env, greylist_seconds_left_loc),ulong) = (diff);//FIXME
1339 
1340 
1341 #line 675
1342 
1343 #line 675
1344 mu_debug(debug_handle, MU_DEBUG_TRACE6,("%s still greylisted (for %lu sec.)",
1345 			          email,
1346 			          (unsigned long) diff));
1347 #line 679
1348 			rc = 1;
1349 		} else if (diff > greylist_format->expire_interval) {
1350 
1351 #line 681
1352 
1353 #line 681
1354 mu_debug(debug_handle, MU_DEBUG_TRACE6,("greylist record for %s expired", email));
1355 #line 683
1356 			mf_c_val(*env_data_ref(env, greylist_seconds_left_loc),long) = (interval);
1357 			if (!readonly) {
1358 				memcpy(contents.mu_dptr, &now, sizeof now);
1359 				rc = mu_dbm_store(db, &key, &contents, 1);
1360 				if (rc)
1361 					mu_error(_("cannot insert datum `%-.*s' in "
1362 						   "greylist database %s: %s"),
1363 			                         (int)key.mu_dsize,
1364 						 (char*)key.mu_dptr,
1365 						 greylist_format->dbname,
1366 						 rc == MU_ERR_FAILURE ?
1367 						  mu_dbm_strerror(db) :
1368 						  mu_strerror(rc));
1369 			} else
1370 
1371 #line 697
1372 
1373 #line 697
1374 mu_debug(debug_handle, MU_DEBUG_TRACE6,("database opened in readonly mode: "
1375 			  	          "not updating"));
1376 #line 700
1377 			rc = 1;
1378 		} else {
1379 
1380 #line 702
1381 
1382 #line 702
1383 mu_debug(debug_handle, MU_DEBUG_TRACE6,("%s finished greylisting period", email));
1384 #line 704
1385 			rc = 0;
1386 		}
1387 		mu_dbm_datum_free(&contents);
1388 	} else if (!readonly) {
1389 
1390 #line 708
1391 
1392 #line 708
1393 mu_debug(debug_handle, MU_DEBUG_TRACE6,("greylisting %s", email));
1394 		mf_c_val(*env_data_ref(env, greylist_seconds_left_loc),long) = (interval);
1395 		contents.mu_dptr = (void*)&now;
1396 		contents.mu_dsize = sizeof now;
1397 		rc = mu_dbm_store(db, &key, &contents, 1);
1398 		if (rc)
1399 			mu_error(_("Cannot insert datum `%-.*s' in greylist "
1400 				   "database %s: %s"),
1401 		                 (int)key.mu_dsize, (char*)key.mu_dptr,
1402 				 greylist_format->dbname,
1403 				 rc == MU_ERR_FAILURE ?
1404 				  mu_dbm_strerror(db) : mu_strerror(rc));
1405 		rc = 1;
1406 	} else
1407 		rc = 0;
1408 
1409 	mu_dbm_destroy(&db);
1410 
1411 	return rc;
1412 }
1413 
1414 /* Implementation of the is_greylisted predicate has no sense for
1415    traditional greylist databases, because greylisting interval is
1416    not known beforehand.
1417    FIXME: keep the reference below up to date.
1418  */
1419 static int
is_greylisted_traditional(eval_environ_t env,char * email)1420 is_greylisted_traditional(eval_environ_t env, char *email)
1421 {
1422 	(
1423 #line 737
1424 	env_throw_bi(env, mfe_failure, NULL, _("is_greylisted is not implemented for traditional greylist databases; "
1425 		   "see documentation, chapter %s %s for more info"),"5.30","Greylisting functions")
1426 #line 737
1427 );
1428 #line 741
1429 	return 0;
1430 }
1431 
1432 /* New greylist implementation (by Con Tassios): the database keeps
1433    the time the greylisting period is set to expire (`interval' seconds
1434    from now)
1435 */
1436 static int
do_greylist_ct(eval_environ_t env,char * email,long interval)1437 do_greylist_ct(eval_environ_t env, char *email, long interval)
1438 {
1439 	int rc;
1440 	mu_dbm_file_t db;
1441 	struct mu_dbm_datum key;
1442 	struct mu_dbm_datum contents;
1443 	int readonly = 0;
1444 	time_t now;
1445 
1446 	rc = _open_dbm(&db, greylist_format->dbname, MU_STREAM_RDWR, 0600,
1447 		       NULL);
1448 	if (rc) {
1449 		rc = _open_dbm(&db, greylist_format->dbname,
1450 			       MU_STREAM_READ, 0600, NULL);
1451 		readonly = 1;
1452 	}
1453         	if (!(rc == 0))
1454 #line 765
1455 		(
1456 #line 765
1457 	env_throw_bi(env, mfe_dbfailure, NULL, _("mf_dbm_open(%s) failed: %s"),greylist_format->dbname,mu_strerror(rc))
1458 #line 765
1459 )
1460 ;
1461 
1462 	memset(&key, 0, sizeof key);
1463 	memset(&contents, 0, sizeof contents);
1464 	key.mu_dptr = email;
1465 	key.mu_dsize = strlen(email) + 1;
1466 
1467 	time(&now);
1468 	rc = mu_dbm_fetch(db, &key, &contents);
1469 	if (rc == 0) {
1470 		time_t timestamp;
1471 
1472 			if (!(contents.mu_dsize == sizeof timestamp))
1473 #line 778
1474 		(
1475 #line 778
1476 	env_throw_bi(env, mfe_dbfailure, NULL, _("greylist database %s has wrong data size"),greylist_format->dbname)
1477 #line 778
1478 )
1479 #line 781
1480 ;
1481 
1482 		timestamp = *(time_t*) contents.mu_dptr;
1483 
1484 		if (now < timestamp) {
1485 			time_t diff = timestamp - now;
1486 			mf_c_val(*env_data_ref(env, greylist_seconds_left_loc),long) = (diff);
1487 
1488 
1489 #line 789
1490 
1491 #line 789
1492 mu_debug(debug_handle, MU_DEBUG_TRACE6,("%s still greylisted (for %lu sec.)",
1493 			          email,
1494                                   (unsigned long) diff));
1495 #line 793
1496 			rc = 1;
1497 		} else if (now - timestamp >
1498 			   greylist_format->expire_interval) {
1499 
1500 #line 796
1501 
1502 #line 796
1503 mu_debug(debug_handle, MU_DEBUG_TRACE6,("greylist record for %s expired", email));
1504 #line 798
1505 			mf_c_val(*env_data_ref(env, greylist_seconds_left_loc),long) = (interval);
1506 			if (!readonly) {
1507 				now += interval;
1508 				memcpy(contents.mu_dptr, &now, sizeof now);
1509 				rc = mu_dbm_store(db, &key, &contents, 1);
1510 				if (rc)
1511 					mu_error(_("Cannot insert datum "
1512 						   "`%-.*s' in greylist "
1513 						   "database %s: %s"),
1514 			                         (int)key.mu_dsize,
1515 						 (char*)key.mu_dptr,
1516 						 greylist_format->dbname,
1517 						 rc == MU_ERR_FAILURE ?
1518 						   mu_dbm_strerror(db) :
1519 						   mu_strerror(rc));
1520 			} else
1521 
1522 #line 814
1523 
1524 #line 814
1525 mu_debug(debug_handle, MU_DEBUG_TRACE6,("database opened in readonly mode: "
1526 				          "not updating"));
1527 #line 817
1528 			rc = 1;
1529 		} else {
1530 
1531 #line 819
1532 
1533 #line 819
1534 mu_debug(debug_handle, MU_DEBUG_TRACE6,("%s finished greylisting period", email));
1535 #line 821
1536 			rc = 0;
1537 		}
1538 		mu_dbm_datum_free(&contents);
1539 	} else if (!readonly) {
1540 
1541 #line 825
1542 
1543 #line 825
1544 mu_debug(debug_handle, MU_DEBUG_TRACE6,("greylisting %s", email));
1545 		mf_c_val(*env_data_ref(env, greylist_seconds_left_loc),long) = (interval);
1546 		now += interval;
1547 		contents.mu_dptr = (void*)&now;
1548 		contents.mu_dsize = sizeof now;
1549 		rc = mu_dbm_store(db, &key, &contents, 1);
1550 		if (rc)
1551 			mu_error(_("Cannot insert datum `%-.*s' in greylist "
1552 				   "database %s: %s"),
1553 		                 (int)key.mu_dsize, (char*)key.mu_dptr,
1554 				 greylist_format->dbname,
1555 				 rc == MU_ERR_FAILURE ?
1556 				  mu_dbm_strerror(db) : mu_strerror(rc));
1557 		rc = 1;
1558 	} else
1559 		rc = 0;
1560 
1561 	mu_dbm_destroy(&db);
1562 
1563 	return rc;
1564 }
1565 
1566 /* The `is_greylisted' predicate for new databases */
1567 static int
is_greylisted_ct(eval_environ_t env,char * email)1568 is_greylisted_ct(eval_environ_t env, char *email)
1569 {
1570 	int rc;
1571 	mu_dbm_file_t db;
1572 	struct mu_dbm_datum key;
1573 	struct mu_dbm_datum contents;
1574 	time_t now;
1575 
1576 	rc = _open_dbm(&db, greylist_format->dbname, MU_STREAM_RDWR, 0600,
1577 		       NULL);
1578 	if (rc)
1579 		rc = _open_dbm(&db, greylist_format->dbname,
1580 			       MU_STREAM_READ, 0600, NULL);
1581 		if (!(rc == 0))
1582 #line 862
1583 		(
1584 #line 862
1585 	env_throw_bi(env, mfe_dbfailure, NULL, _("mf_dbm_open(%s) failed: %s"),greylist_format->dbname,mu_strerror(rc))
1586 #line 862
1587 )
1588 ;
1589 
1590 	memset(&key, 0, sizeof key);
1591 	memset(&contents, 0, sizeof contents);
1592 	key.mu_dptr = email;
1593 	key.mu_dsize = strlen(email) + 1;
1594 
1595 	time(&now);
1596 	rc = mu_dbm_fetch(db, &key, &contents);
1597 	if (rc == 0) {
1598 		time_t timestamp;
1599 
1600 			if (!(contents.mu_dsize == sizeof timestamp))
1601 #line 875
1602 		(
1603 #line 875
1604 	env_throw_bi(env, mfe_dbfailure, NULL, _("greylist database %s has wrong data size"),greylist_format->dbname)
1605 #line 875
1606 )
1607 #line 878
1608 ;
1609 
1610 		timestamp = *(time_t*) contents.mu_dptr;
1611 
1612 		rc = timestamp > now;
1613                 if (rc)
1614 			mf_c_val(*env_data_ref(env, greylist_seconds_left_loc),long) = (timestamp - now);
1615 
1616 		mu_dbm_datum_free(&contents);
1617 	} else
1618 		rc = 0;
1619 
1620 	mu_dbm_destroy(&db);
1621 
1622 	return rc;
1623 }
1624 
1625 struct greylist_class {
1626 	int (*gl_fun)(eval_environ_t, char *, long);
1627 	int (*gl_pred)(eval_environ_t, char *);
1628 };
1629 
1630 struct greylist_class greylist_class[] = {
1631 	{ do_greylist_traditional, is_greylisted_traditional },
1632 	{ do_greylist_ct, is_greylisted_ct }
1633 };
1634 
1635 /* greylist(key, interval)
1636 
1637    Returns true if the key is greylisted, false if it's OK to
1638    deliver mail.
1639  */
1640 void
1641 #line 910
bi_greylist(eval_environ_t env)1642 bi_greylist(eval_environ_t env)
1643 #line 910
1644 
1645 #line 910
1646 
1647 #line 910 "db.bi"
1648 {
1649 #line 910
1650 
1651 #line 910
1652 
1653 #line 910
1654 
1655 #line 910
1656 char *  email;
1657 #line 910
1658         long  interval;
1659 #line 910
1660 
1661 #line 910
1662 get_string_arg(env, 0, &email);
1663 #line 910
1664         get_numeric_arg(env, 1, &interval);
1665 #line 910
1666 
1667 #line 910
1668 
1669 #line 910
1670         adjust_stack(env, 2);
1671 #line 910
1672 
1673 #line 910
1674 
1675 #line 910
1676 	if (builtin_module_trace(BUILTIN_IDX_db))
1677 #line 910
1678 		prog_trace(env, "greylist %s %lu",email, interval);;
1679 #line 910
1680 
1681 {
1682 
1683 #line 912
1684 do {
1685 #line 912
1686   push(env, (STKVAL)(mft_number)(greylist_class[greylist_semantics].gl_fun(env, email,
1687 #line 912
1688 							    interval)));
1689 #line 912
1690   goto endlab;
1691 #line 912
1692 } while (0);
1693 #line 914
1694 }
1695 endlab:
1696 #line 915
1697         env_function_cleanup_flush(env, NULL);
1698 #line 915
1699 	return;
1700 #line 915
1701 }
1702 
1703 /* is_greylisted(key)
1704 
1705    Returns true if the key is greylisted, otherwise false
1706 
1707 */
1708 void
1709 #line 922
bi_is_greylisted(eval_environ_t env)1710 bi_is_greylisted(eval_environ_t env)
1711 #line 922
1712 
1713 #line 922
1714 
1715 #line 922 "db.bi"
1716 {
1717 #line 922
1718 
1719 #line 922
1720 
1721 #line 922
1722 
1723 #line 922
1724 char *  email;
1725 #line 922
1726 
1727 #line 922
1728 get_string_arg(env, 0, &email);
1729 #line 922
1730 
1731 #line 922
1732 
1733 #line 922
1734         adjust_stack(env, 1);
1735 #line 922
1736 
1737 #line 922
1738 
1739 #line 922
1740 	if (builtin_module_trace(BUILTIN_IDX_db))
1741 #line 922
1742 		prog_trace(env, "is_greylisted %s",email);;
1743 #line 922
1744 
1745 {
1746 
1747 #line 924
1748 do {
1749 #line 924
1750   push(env, (STKVAL)(mft_number)(greylist_class[greylist_semantics].gl_pred(env, email)));
1751 #line 924
1752   goto endlab;
1753 #line 924
1754 } while (0);
1755 }
1756 endlab:
1757 #line 926
1758         env_function_cleanup_flush(env, NULL);
1759 #line 926
1760 	return;
1761 #line 926
1762 }
1763 
1764 void
1765 #line 928
bi_db_name(eval_environ_t env)1766 bi_db_name(eval_environ_t env)
1767 #line 928
1768 
1769 #line 928
1770 
1771 #line 928 "db.bi"
1772 {
1773 #line 928
1774 
1775 #line 928
1776 
1777 #line 928
1778 
1779 #line 928
1780 char * MFL_DATASEG fmtid;
1781 #line 928
1782 
1783 #line 928
1784 get_string_arg(env, 0, &fmtid);
1785 #line 928
1786 
1787 #line 928
1788 
1789 #line 928
1790         adjust_stack(env, 1);
1791 #line 928
1792 
1793 #line 928
1794 
1795 #line 928
1796 	if (builtin_module_trace(BUILTIN_IDX_db))
1797 #line 928
1798 		prog_trace(env, "db_name %s",fmtid);;
1799 #line 928
1800 
1801 {
1802 	struct db_format *fmt = db_format_lookup(fmtid);
1803 		if (!(fmt != NULL))
1804 #line 931
1805 		(
1806 #line 931
1807 	env_throw_bi(env, mfe_not_found, "db_name", _("no such db format: %s"),fmtid)
1808 #line 931
1809 )
1810 #line 933
1811 ;
1812 
1813 #line 934
1814 do {
1815 #line 934
1816   pushs(env, fmt->dbname);
1817 #line 934
1818   goto endlab;
1819 #line 934
1820 } while (0);
1821 }
1822 endlab:
1823 #line 936
1824         env_function_cleanup_flush(env, NULL);
1825 #line 936
1826 	return;
1827 #line 936
1828 }
1829 
1830 void
1831 #line 938
bi_db_get_active(eval_environ_t env)1832 bi_db_get_active(eval_environ_t env)
1833 #line 938
1834 
1835 #line 938
1836 
1837 #line 938 "db.bi"
1838 {
1839 #line 938
1840 
1841 #line 938
1842 
1843 #line 938
1844 
1845 #line 938
1846 char *  fmtid;
1847 #line 938
1848 
1849 #line 938
1850 get_string_arg(env, 0, &fmtid);
1851 #line 938
1852 
1853 #line 938
1854 
1855 #line 938
1856         adjust_stack(env, 1);
1857 #line 938
1858 
1859 #line 938
1860 
1861 #line 938
1862 	if (builtin_module_trace(BUILTIN_IDX_db))
1863 #line 938
1864 		prog_trace(env, "db_get_active %s",fmtid);;
1865 #line 938
1866 
1867 {
1868 	struct db_format *fmt = db_format_lookup(fmtid);
1869 		if (!(fmt != NULL))
1870 #line 941
1871 		(
1872 #line 941
1873 	env_throw_bi(env, mfe_not_found, "db_get_active", _("no such db format: %s"),fmtid)
1874 #line 941
1875 )
1876 #line 943
1877 ;
1878 
1879 #line 944
1880 do {
1881 #line 944
1882   push(env, (STKVAL)(mft_number)(fmt->enabled));
1883 #line 944
1884   goto endlab;
1885 #line 944
1886 } while (0);
1887 }
1888 endlab:
1889 #line 946
1890         env_function_cleanup_flush(env, NULL);
1891 #line 946
1892 	return;
1893 #line 946
1894 }
1895 
1896 void
1897 #line 948
bi_db_set_active(eval_environ_t env)1898 bi_db_set_active(eval_environ_t env)
1899 #line 948
1900 
1901 #line 948
1902 
1903 #line 948 "db.bi"
1904 {
1905 #line 948
1906 
1907 #line 948
1908 
1909 #line 948
1910 
1911 #line 948
1912 char *  fmtid;
1913 #line 948
1914         long  active;
1915 #line 948
1916 
1917 #line 948
1918 get_string_arg(env, 0, &fmtid);
1919 #line 948
1920         get_numeric_arg(env, 1, &active);
1921 #line 948
1922 
1923 #line 948
1924 
1925 #line 948
1926         adjust_stack(env, 2);
1927 #line 948
1928 
1929 #line 948
1930 
1931 #line 948
1932 	if (builtin_module_trace(BUILTIN_IDX_db))
1933 #line 948
1934 		prog_trace(env, "db_set_active %s %lu",fmtid, active);;
1935 #line 948
1936 
1937 {
1938 	struct db_format *fmt = db_format_lookup(fmtid);
1939 		if (!(fmt != NULL))
1940 #line 951
1941 		(
1942 #line 951
1943 	env_throw_bi(env, mfe_not_found, "db_set_active", _("no such db format: %s"),fmtid)
1944 #line 951
1945 )
1946 #line 953
1947 ;
1948 	fmt->enabled = active;
1949 }
1950 
1951 #line 956
1952         env_function_cleanup_flush(env, NULL);
1953 #line 956
1954 	return;
1955 #line 956
1956 }
1957 
1958 void
1959 #line 958
bi_db_expire_interval(eval_environ_t env)1960 bi_db_expire_interval(eval_environ_t env)
1961 #line 958
1962 
1963 #line 958
1964 
1965 #line 958 "db.bi"
1966 {
1967 #line 958
1968 
1969 #line 958
1970 
1971 #line 958
1972 
1973 #line 958
1974 char *  fmtid;
1975 #line 958
1976 
1977 #line 958
1978 get_string_arg(env, 0, &fmtid);
1979 #line 958
1980 
1981 #line 958
1982 
1983 #line 958
1984         adjust_stack(env, 1);
1985 #line 958
1986 
1987 #line 958
1988 
1989 #line 958
1990 	if (builtin_module_trace(BUILTIN_IDX_db))
1991 #line 958
1992 		prog_trace(env, "db_expire_interval %s",fmtid);;
1993 #line 958
1994 
1995 {
1996 	struct db_format *fmt = db_format_lookup(fmtid);
1997 		if (!(fmt != NULL))
1998 #line 961
1999 		(
2000 #line 961
2001 	env_throw_bi(env, mfe_not_found, "db_expire_interval", _("no such db format: %s"),fmtid)
2002 #line 961
2003 )
2004 #line 963
2005 ;
2006 
2007 #line 964
2008 do {
2009 #line 964
2010   push(env, (STKVAL)(mft_number)(fmt->expire_interval));
2011 #line 964
2012   goto endlab;
2013 #line 964
2014 } while (0);
2015 }
2016 endlab:
2017 #line 966
2018         env_function_cleanup_flush(env, NULL);
2019 #line 966
2020 	return;
2021 #line 966
2022 }
2023 
2024 #line 982 "../../src/builtin/snarf.m4"
2025 
2026 #line 982
2027 
2028 #line 982
2029 
2030 #line 982
2031 void
2032 #line 982
db_init_builtin(void)2033 db_init_builtin(void)
2034 #line 982
2035 {
2036 #line 982
2037 		debug_handle = mu_debug_register_category("bi_db");
2038 #line 982
2039 
2040 #line 982
2041 	#line 82 "db.bi"
2042 
2043 #line 82
2044 install_pragma("dbprop", 3, 5, _pragma_dbprop);
2045 #line 272 "db.bi"
2046 va_builtin_install_ex("dbmap", bi_dbmap, 0, dtype_number, 3, 1, 0|0, dtype_string, dtype_string, dtype_number);
2047 #line 283 "db.bi"
2048 va_builtin_install_ex("dbget", bi_dbget, 0, dtype_string, 4, 2, 0|0, dtype_string, dtype_string, dtype_string, dtype_number);
2049 #line 295 "db.bi"
2050 va_builtin_install_ex("dbput", bi_dbput, 0, dtype_unspecified, 5, 2, 0|0, dtype_string, dtype_string, dtype_string, dtype_number, dtype_number);
2051 #line 338 "db.bi"
2052 va_builtin_install_ex("dbinsert", bi_dbinsert, 0, dtype_unspecified, 6, 3, 0|0, dtype_string, dtype_string, dtype_string, dtype_number, dtype_number, dtype_number);
2053 #line 384 "db.bi"
2054 va_builtin_install_ex("dbdel", bi_dbdel, 0, dtype_unspecified, 4, 2, 0|0, dtype_string, dtype_string, dtype_number, dtype_number);
2055 #line 452 "db.bi"
2056 DBTAB_id = builtin_priv_register(alloc_db_tab, destroy_db_tab,
2057 #line 452
2058 NULL);
2059 #line 468 "db.bi"
2060 va_builtin_install_ex("dbfirst", bi_dbfirst, 0, dtype_number, 1, 0, 0|0, dtype_string);
2061 #line 509 "db.bi"
2062 va_builtin_install_ex("dbnext", bi_dbnext, 0, dtype_number, 1, 0, 0|0, dtype_number);
2063 #line 534 "db.bi"
2064 va_builtin_install_ex("dbkey", bi_dbkey, 0, dtype_string, 1, 0, 0|0, dtype_number);
2065 #line 552 "db.bi"
2066 va_builtin_install_ex("dbvalue", bi_dbvalue, 0, dtype_string, 1, 0, 0|0, dtype_number);
2067 #line 591 "db.bi"
2068 
2069 #line 591
2070 install_pragma("greylist", 2, 2, _pragma_greylist);
2071 #line 617 "db.bi"
2072 	builtin_variable_install("greylist_seconds_left", dtype_number, SYM_VOLATILE, &greylist_seconds_left_loc);
2073 #line 910 "db.bi"
2074 va_builtin_install_ex("greylist", bi_greylist, 0, dtype_number, 2, 0, 0|0, dtype_string, dtype_number);
2075 #line 922 "db.bi"
2076 va_builtin_install_ex("is_greylisted", bi_is_greylisted, 0, dtype_number, 1, 0, 0|0, dtype_string);
2077 #line 928 "db.bi"
2078 va_builtin_install_ex("db_name", bi_db_name, 0, dtype_string, 1, 0, 0|0, dtype_string);
2079 #line 938 "db.bi"
2080 va_builtin_install_ex("db_get_active", bi_db_get_active, 0, dtype_number, 1, 0, 0|0, dtype_string);
2081 #line 948 "db.bi"
2082 va_builtin_install_ex("db_set_active", bi_db_set_active, 0, dtype_unspecified, 2, 0, 0|0, dtype_string, dtype_number);
2083 #line 958 "db.bi"
2084 va_builtin_install_ex("db_expire_interval", bi_db_expire_interval, 0, dtype_number, 1, 0, 0|0, dtype_string);
2085 
2086 #line 982 "../../src/builtin/snarf.m4"
2087 
2088 #line 982
2089 }
2090 #line 982 "../../src/builtin/snarf.m4"
2091 
2092