/* This file is part of mailfrom filter. -*- c -*- Copyright (C) 2006 Sergey Poznyakoff This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifdef USE_DBM static int dbmap_lookup_p(eval_environ_t env, char *dbname, const char *email) { int rc; char *name; DBM_FILE db; DBM_DATUM key; DBM_DATUM contents; if (mu_dbm_open(dbname, &db, MU_STREAM_READ, 0, NULL)) { if (env_catch(env, mf_dbfailure) == 0) return -1; else runtime_error(env, "mu_dbm_open(%s) failed: %s", dbname, mu_strerror(errno)); } name = strdup(email); memset (&key, 0, sizeof key); memset (&contents, 0, sizeof contents); MU_DATUM_PTR (key) = name; MU_DATUM_SIZE (key) = strlen(name)+1; rc = mu_dbm_fetch(&db, key, &contents) == 0; debug2(10, "Checking alias %s: %s", name, rc ? "true" : "false"); mu_dbm_datum_free(&contents); mu_dbm_close(&db); return rc; } MF_DEFUN(dbmap, NUMBER, STRING dbname, STRING key) { push(env, (STKVAL) dbmap_lookup_p(env, dbname, key)); } END static void greylist_print_item(const char *key, size_t size, const void *content) { time_t timestamp = *(time_t*) content; size--; /* Size includes the trailing nul */ printf("%*.*s ", size, size, key); format_time_str(stdout, timestamp); putchar('\n'); } static int greylist_expire_item(const void *content) { time_t timestamp = *(time_t*) content; return greylist_format->expire_interval && time(NULL) - timestamp > greylist_format->expire_interval; } static struct db_format greylist_format_struct = { "greylist", DEFAULT_GREYLIST_DATABASE, DEFAULT_EXPIRE_INTERVAL, greylist_print_item, greylist_expire_item }; struct db_format *greylist_format = &greylist_format_struct; size_t greylist_seconds_left_loc; /* greylist(key, interval) Returns true if the key is greylisted, false if it's OK to deliver mail. */ MF_DEFUN(greylist, NUMBER, STRING email, NUMBER interval) { int rc; DBM_FILE db; DBM_DATUM key; DBM_DATUM contents; int readonly; time_t now; if (prog_trace_option) prog_trace(env, "GREYLIST %s %ld %ld", email, interval); if (mu_dbm_open(greylist_format->dbname, &db, MU_STREAM_RDWR, 0600, &readonly)) { if (env_catch(env, mf_dbfailure) == 0) return; runtime_error(env, "mu_dbm_open(%s) failed: %s", greylist_format->dbname, mu_strerror(errno)); } memset(&key, 0, sizeof key); memset(&contents, 0, sizeof contents); MU_DATUM_PTR(key) = email; MU_DATUM_SIZE(key) = strlen(email)+1; time(&now); if (mu_dbm_fetch(&db, key, &contents) == 0) { time_t timestamp, diff; if (MU_DATUM_SIZE(contents) != sizeof timestamp) { if (env_catch(env, mf_dbfailure) == 0) return; runtime_error(env, "greylist database %s has wrong data size", greylist_format->dbname); } timestamp = *(time_t*) MU_DATUM_PTR(contents); diff = now - timestamp; __DBG(20) { char timebuf[32]; debug_log("%s entered greylist database on %s, " "%ld seconds ago", email, mailfromd_timestr(timestamp, timebuf, sizeof timebuf), (long) diff); } if (diff < interval) { diff = interval - diff; *env_var_ref(env, greylist_seconds_left_loc) = (STKVAL) diff; debug2(20, "%s still greylisted (for %lu sec.)", email, (unsigned long) diff); rc = 1; } else if (diff > greylist_format->expire_interval) { debug1(20, "greylist record for %s expired", email); if (!readonly) { memcpy(MU_DATUM_PTR(contents), &now, sizeof now); if (mu_dbm_insert(&db, key, contents, 1)) mu_error("Cannot insert datum in " "greylist database %s", greylist_format->dbname); } else debug(20, "database opened in readonly mode: " "not updating"); rc = 1; } else { debug1(20, "%s finished greylisting period", email); rc = 0; } mu_dbm_datum_free(&contents); } else if (!readonly) { debug1(20, "greylisting %s", email); *env_var_ref(env, greylist_seconds_left_loc) = (STKVAL) interval; MU_DATUM_PTR(contents) = (void*)&now; MU_DATUM_SIZE(contents) = sizeof now; if (mu_dbm_insert(&db, key, contents, 1)) mu_error("Cannot insert datum in greylist " "database %s", greylist_format->dbname); rc = 1; } else rc = 0; mu_dbm_close(&db); push(env, (STKVAL) rc); } END MF_INIT(db, greylist_seconds_left_loc = builtin_variable_install("greylist_seconds_left", rettype_number)->off; ) #endif