]> source.dussan.org Git - rspamd.git/commitdiff
Rename main.h and main.c to `rspamd.X`
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 22 Sep 2015 17:17:24 +0000 (18:17 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Tue, 22 Sep 2015 17:17:24 +0000 (18:17 +0100)
78 files changed:
src/CMakeLists.txt
src/controller.c
src/fuzzy_storage.c
src/fuzzy_storage.h
src/http_proxy.c
src/libmime/filter.c
src/libmime/images.c
src/libmime/images.h
src/libmime/message.c
src/libmime/mime_expressions.c
src/libmime/smtp_proto.c
src/libmime/smtp_utils.c
src/libserver/buffer.c
src/libserver/cfg_rcl.c
src/libserver/cfg_utils.c
src/libserver/dkim.c
src/libserver/dns.c
src/libserver/dynamic_cfg.c
src/libserver/events.c
src/libserver/fuzzy_backend.c
src/libserver/html.c
src/libserver/protocol.c
src/libserver/proxy.c
src/libserver/roll_history.c
src/libserver/spf.c
src/libserver/symbols_cache.c
src/libserver/task.c
src/libserver/url.c
src/libserver/worker_util.c
src/libserver/worker_util.h
src/libstat/backends/mmaped_file.c
src/libstat/backends/redis.c
src/libstat/backends/sqlite3_backend.c
src/libstat/classifiers/bayes.c
src/libstat/learn_cache/sqlite3_cache.c
src/libstat/stat_config.c
src/libstat/stat_process.c
src/libstat/tokenizers/tokenizers.c
src/libstat/tokenizers/tokenizers.h
src/libutil/aio_event.c
src/libutil/keypairs_cache.c
src/libutil/logger.c
src/libutil/map.c
src/libutil/mem_pool.c
src/libutil/printf.c
src/libutil/radix.c
src/libutil/regexp.c
src/libutil/util.c
src/lua/lua_common.h
src/lua/lua_util.c
src/lua_worker.c
src/main.c [deleted file]
src/main.h [deleted file]
src/plugins/chartable.c
src/plugins/dkim_check.c
src/plugins/fuzzy_check.c
src/plugins/regexp.c
src/plugins/spf.c
src/plugins/surbl.c
src/plugins/surbl.h
src/rspamd.c [new file with mode: 0644]
src/rspamd.h [new file with mode: 0644]
src/smtp.h
src/smtp_proxy.c
src/worker.c
test/rspamd_async_test.c
test/rspamd_cryptobox_test.c
test/rspamd_dkim_test.c
test/rspamd_dns_test.c
test/rspamd_http_test.c
test/rspamd_lua_test.c
test/rspamd_radix_test.c
test/rspamd_rrd_test.c
test/rspamd_shingles_test.c
test/rspamd_statfile_test.c
test/rspamd_test_suite.c
test/rspamd_upstream_test.c
test/rspamd_url_test.c

index 494f5b6c0e88c861aa1dad7bcb69ea0b194d790e..f86c45b4057871a602b0b5f648c7a4a541da0763 100644 (file)
@@ -4,7 +4,7 @@ MACRO(_AddModulesForced MLIST)
        SET(MODULES_ID ${_MODULES_ID} CACHE INTERNAL "Modules ID" FORCE)
        SET(MODULES_C "${CMAKE_CURRENT_BINARY_DIR}/modules.c")
        FILE(WRITE "${MODULES_C}"
-               "/* ${MODULES_ID} */\n#include \"main.h\"\n")
+               "/* ${MODULES_ID} */\n#include \"rspamd.h\"\n")
        
        # Handle even old cmake
        LIST(LENGTH ${MLIST} MLIST_COUNT)
@@ -28,7 +28,7 @@ ENDMACRO(_AddModulesForced MLIST)
 MACRO(_AddWorkersForced WLIST)
        SET(WORKERS_C "${CMAKE_CURRENT_BINARY_DIR}/workers.c")
        FILE(WRITE "${WORKERS_C}"
-               "#include \"main.h\"\n")
+               "#include \"rspamd.h\"\n")
        
        # Handle even old cmake
        LIST(LENGTH ${WLIST} WLIST_COUNT)
@@ -74,7 +74,7 @@ ADD_SUBDIRECTORY(client)
 SET(RSPAMDSRC  controller.c
                                fuzzy_storage.c
                                lua_worker.c
-                               main.c
+               rspamd.c
                                smtp_proxy.c
                                worker.c
                                http_proxy.c)
index 0e729b886ea81b6e9bf8c5a319e1cf7ca7d20d6a..69132de70c869ccd76ca10b8f836b844c3c63cef 100644 (file)
@@ -27,7 +27,7 @@
 #include "libutil/rrd.h"
 #include "libutil/map.h"
 #include "libstat/stat_api.h"
-#include "main.h"
+#include "rspamd.h"
 #include "libserver/worker_util.h"
 #include "utlist.h"
 
index d41b922d28c9d1a36929a29129950a37d1eb574d..ebbff3365e3de38b5bf18ef01857ea1e65aec755 100644 (file)
@@ -28,7 +28,7 @@
 
 #include "config.h"
 #include "util.h"
-#include "main.h"
+#include "rspamd.h"
 #include "protocol.h"
 #include "upstream.h"
 #include "cfg_file.h"
index b9997da8ba601bb8ad9cfb043e3bfb07c1107f5b..57d7b5cc7a304bab492a6fd93bd858dbd6e980a2 100644 (file)
@@ -2,7 +2,7 @@
 #define RSPAMD_FUZZY_STORAGE_H
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "shingles.h"
 
 #define RSPAMD_FUZZY_VERSION 3
index 12b2373465055b7ee32a5f1696ce5d7ea9e11154..f71adc3f6d1fc04380a4107960d9b06a9c67495e 100644 (file)
@@ -31,7 +31,7 @@
 #include "libserver/url.h"
 #include "libserver/dns.h"
 #include "libmime/message.h"
-#include "main.h"
+#include "rspamd.h"
 #include "libserver/worker_util.h"
 #include "keypairs_cache.h"
 #include "ottery.h"
index 7efb8f82a21ae029a96d90e282d3c91166133494..ed50efafe9ef2f04b524323b75601ac27f40c40e 100644 (file)
@@ -25,7 +25,7 @@
 #include "config.h"
 #include "mem_pool.h"
 #include "filter.h"
-#include "main.h"
+#include "rspamd.h"
 #include "message.h"
 #include "cfg_file.h"
 #include "util.h"
index 419b6a2ca12c3255bb6b0a7e4ba962838547678e..f55e47d7a7952c1e7846fa0e01be0dfd57204732 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "config.h"
 #include "images.h"
-#include "main.h"
+#include "rspamd.h"
 #include "message.h"
 #include "html.h"
 
index 5d01e6f7501812ecdf318be4da32426cd5b70509..6d64ea5d13acdcddddf2a4a67d02924066a744bc 100644 (file)
@@ -2,7 +2,7 @@
 #define IMAGES_H_
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 
 struct html_image;
 
index 54c5ab59ebaae871dbfa706167b25652330c7f09..3537f70c0aa383d2fd8559754aca8c070b306054 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "config.h"
 #include "util.h"
-#include "main.h"
+#include "rspamd.h"
 #include "message.h"
 #include "cfg_file.h"
 #include "html.h"
index f5732c75ac3220346bd7d9e505dead2b24211877..6581b7362d9c72243b77925784847cd88cf1f447 100644 (file)
@@ -25,7 +25,7 @@
 #include "config.h"
 #include "util.h"
 #include "cfg_file.h"
-#include "main.h"
+#include "rspamd.h"
 #include "message.h"
 #include "mime_expressions.h"
 #include "html.h"
index 713efabac739564156cfb4a9fc60083116e006c7..988bd37af925afc92a2f0824e5101c80649306e3 100644 (file)
@@ -23,7 +23,7 @@
  */
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "cfg_file.h"
 #include "util.h"
 #include "smtp.h"
index b3abe03024cf991d841dc77a4dc9f4c23b443bcf..edc7f3b1465cf49b9237ac60aa4bf30625547dad 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "filter.h"
 #include "smtp.h"
 #include "smtp_proto.h"
index 4c6ee277693748a861383d3c977bb6f2a8f1e7ab..e4268863cdfe2ba2169f55752366ee6e3196bafa 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "config.h"
 #include "buffer.h"
-#include "main.h"
+#include "rspamd.h"
 #ifdef HAVE_SYS_SENDFILE_H
 #include <sys/sendfile.h>
 #endif
index 263ba9e409c4b2d31b3da79e397644d56a0ebb8f..efd57f715d164b2d3296376bfa682f0c3456f54e 100644 (file)
@@ -23,7 +23,7 @@
 
 #include <blake2.h>
 #include "cfg_rcl.h"
-#include "main.h"
+#include "rspamd.h"
 #include "uthash_strcase.h"
 #include "utlist.h"
 #include "cfg_file.h"
index 068ced265f470b48c19e9b2b85b71643889146c7..95c984b9c867adac63a8ee54a279e5a201708f9c 100644 (file)
@@ -26,7 +26,7 @@
 #include "config.h"
 
 #include "cfg_file.h"
-#include "main.h"
+#include "rspamd.h"
 #include "uthash_strcase.h"
 #include "filter.h"
 #include "lua/lua_common.h"
index dd4242393bcc32281813aeacc8b11268ce4ecf59..2cfa184a38f769363739c3db3916391d0f436b6c 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "message.h"
 #include "dkim.h"
 #include "dns.h"
index f808a4460da1002326808c0cbd456b4b5559f6af..0df6ddd918cbbaf494c380ae0103820aaca27d26 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "config.h"
 #include "dns.h"
-#include "main.h"
+#include "rspamd.h"
 #include "utlist.h"
 #include "uthash.h"
 #include "rdns_event.h"
index 97a9d72f2f1daf000e780ac7d768c75d66b878bc..eaa658b8bb0a237c79f6cade5123521ef92767ac 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "map.h"
 #include "filter.h"
 #include "dynamic_cfg.h"
index a50c122f3d7ee341adc85bb488f4d3be8d1e0752..b996f1559a46bfbb4fbab32ecba3de5b7f41cd9b 100644 (file)
@@ -23,7 +23,7 @@
  */
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "events.h"
 #include "xxhash.h"
 
index 3d1749aa78dd24826af9af3a69a1f61fdeb86719..ce6bd6a5acb74efa2f4b99afe56f7d3046dbd4f5 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "fuzzy_backend.h"
 
 #include <sqlite3.h>
index e68c73c8ccef09b573c65f6804619c0b91b498c6..0a46cef02ffbb0b858bf31d9c51f3949e4955df4 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "config.h"
 #include "util.h"
-#include "main.h"
+#include "rspamd.h"
 #include "message.h"
 #include "html.h"
 #include "url.h"
index d585f9ce632f7da784cb04e0985ce1f9b953938c..8cf6b771f84bb436a614fcb461fc35758c03d200 100644 (file)
@@ -23,7 +23,7 @@
  */
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "util.h"
 #include "cfg_file.h"
 #include "cfg_rcl.h"
index a4076954b5ffed5352c1a1bfe0982a9a7715816e..09171eeb940a6ce6f8ea80ef51ddf06e5fca2a05 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "proxy.h"
 
 static void rspamd_proxy_backend_handler (gint fd, gshort what, gpointer data);
index 52049cb5e9dee3a6b531afb191c56fc92652ecc4..74c7c8214f32e0ec311a74bb217ad0afc6d2693e 100644 (file)
@@ -24,7 +24,7 @@
 
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "roll_history.h"
 
 static const gchar rspamd_history_magic[] = {'r', 's', 'h', '1'};
index 479f22e935593e877991527761b5a19ccf66222b..d9b9a730f4b98be9ebe4d858b95b1348d246983f 100644 (file)
@@ -25,7 +25,7 @@
 #include "config.h"
 #include "dns.h"
 #include "spf.h"
-#include "main.h"
+#include "rspamd.h"
 #include "message.h"
 #include "filter.h"
 #include "utlist.h"
index 52b62fac5c030c9e364ee82208ee31e7cb4ca8fa..6564d9efe8a7d5818b49430ae9206bdd799a6a9d 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "config.h"
 #include "util.h"
-#include "main.h"
+#include "rspamd.h"
 #include "message.h"
 #include "symbols_cache.h"
 #include "cfg_file.h"
index ce765b8f0ac1dbf2ef3ab45a3c5fb265d81ebb8e..fc22f784f9833af86983541bf3008e0c209420ab 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 #include "task.h"
-#include "main.h"
+#include "rspamd.h"
 #include "filter.h"
 #include "protocol.h"
 #include "message.h"
index 3a99480cd55de293c16e19cdaa4ce04994c5a670..b2e5d691ce6b46834e338c6d5dbbc90e7ec4782a 100644 (file)
@@ -29,7 +29,7 @@
 #include "url.h"
 #include "util.h"
 #include "fstring.h"
-#include "main.h"
+#include "rspamd.h"
 #include "message.h"
 #include "http.h"
 #include "acism.h"
index 800fa9c01ef8611cde33017841d2c1a6c3b3f711..eee200a41834a7f934af326649588e60502f5719 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "message.h"
 #include "lua/lua_common.h"
 #include "worker_util.h"
index 04109b9b009c0638ca1be3d8fb0dd0190fb2bb27..8bc0ceaee914af1637574931c15adfbfa865cf48 100644 (file)
@@ -26,7 +26,7 @@
 #include "config.h"
 #include "util.h"
 #include "http.h"
-#include "main.h"
+#include "rspamd.h"
 
 #ifndef HAVE_SA_SIGINFO
 typedef void (*rspamd_sig_handler_t) (gint);
index 6bb5e0feb5954d7bee5b8de6c83b9b651eb4a874..41d6900cec90e0327ea3674f379e7c8800789d17 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "config.h"
 #include "stat_internal.h"
-#include "main.h"
+#include "rspamd.h"
 
 #define CHAIN_LENGTH 128
 
index 38d6c7a3a13f501e5aa1e3f05bb9e8cdad7a8193..39d7dc21a19b456326cfa6b47714c93ef2be5400 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "stat_internal.h"
 #include "upstream.h"
 
index 96eddea3e5f869799de607409dc63144de326afc..33aac049456048beca97c3025998e647b1b7b5f6 100644 (file)
@@ -23,7 +23,7 @@
  */
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "sqlite3.h"
 #include "libutil/sqlite_utils.h"
 #include "libstat/stat_internal.h"
index e248fd6e606e1a52f4515fb45a3fe9b27b72eaa6..67c2e31162b6e32fea8995adacfff0e6326b0f5b 100644 (file)
@@ -26,7 +26,7 @@
  * Bayesian classifier
  */
 #include "classifiers.h"
-#include "main.h"
+#include "rspamd.h"
 #include "filter.h"
 #include "cfg_file.h"
 #include "stat_internal.h"
index 745b8839cb2faf8f8a9a23f7d7a3ec79ef73b011..6eabaefda446fe5218d0693f2df86c98aa47d96b 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "config.h"
 #include "learn_cache.h"
-#include "main.h"
+#include "rspamd.h"
 #include "stat_api.h"
 #include "stat_internal.h"
 #include "blake2.h"
index 00baaa059d506122036d9df6e914b05fe8e82be7..dbfe16c27323d932c74d5438860c1eef6e6c34dc 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "config.h"
 #include "stat_api.h"
-#include "main.h"
+#include "rspamd.h"
 #include "cfg_rcl.h"
 #include "stat_internal.h"
 
index d1e23baf2cfc94355d1c9b8905292fd1a7b5ba91..a6f5d31aec7650114013f0820a72f8550308fe11 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "config.h"
 #include "stat_api.h"
-#include "main.h"
+#include "rspamd.h"
 #include "stat_internal.h"
 #include "libmime/message.h"
 #include "libmime/images.h"
index b54c890234397d1f93699978583baaf0d5371d49..07e7a1f45e06a238b4b2ce2747e3f223eb4b1892 100644 (file)
@@ -26,7 +26,7 @@
  * Common tokenization functions
  */
 
-#include "main.h"
+#include "rspamd.h"
 #include "tokenizers.h"
 #include "stat_internal.h"
 
index 050f6d7b1bbc006b44e20c94bf472a2b136acfd3..7b01d9fe8b8da5359bacd5f0bd800542a4bc2818 100644 (file)
@@ -4,7 +4,7 @@
 #include "config.h"
 #include "mem_pool.h"
 #include "fstring.h"
-#include "main.h"
+#include "rspamd.h"
 #include "stat_api.h"
 
 #define RSPAMD_DEFAULT_TOKENIZER "osb"
index ed257bab0139832644e1d5f62371f06587d1e706..0686bbd0db23c4207a1d3f95c7efbe33f04a36b3 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "config.h"
 #include "aio_event.h"
-#include "main.h"
+#include "rspamd.h"
 
 #ifdef HAVE_SYS_EVENTFD_H
 #include <sys/eventfd.h>
index 532eaa37302d83ad59cfb5aca20de8d9d88e22a2..1bedb704d3280b9643acb91ce2e1fb76bc983974 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "keypairs_cache.h"
 #include "keypair_private.h"
 #include "hash.h"
index 57410ad96f66a187223e813650543da14d0156bb..65cb67cdcb092c8330cb5df6241df1309f4da7c7 100644 (file)
@@ -26,7 +26,7 @@
 #include "config.h"
 #include "logger.h"
 #include "util.h"
-#include "main.h"
+#include "rspamd.h"
 #include "map.h"
 #include "xxhash.h"
 
index 2ef68302e7e8bdd4166eb4a1f2ff4f8bafedf4af..cba82ba418ccba75358a77349cf6c3ee53275ee8 100644 (file)
@@ -28,7 +28,7 @@
 #include "config.h"
 #include "map.h"
 #include "http.h"
-#include "main.h"
+#include "rspamd.h"
 #include "util.h"
 #include "mem_pool.h"
 #include "blake2.h"
index 8070e1c2bd5c687e9d17a9c354100a5a5296bf24..ea5fa0bd83c61a3d6f223a496b4feed0dc02055c 100644 (file)
@@ -27,7 +27,7 @@
 #include "fstring.h"
 #include "logger.h"
 #include "util.h"
-#include "main.h"
+#include "rspamd.h"
 #include "utlist.h"
 #include "ottery.h"
 
index 03b801041c11883b21dbd5acb0199b61df98b0b4..328173bd06d1f6edd6e7ce42940a9f5ffa920020 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "printf.h"
 #include "fstring.h"
-#include "main.h"
+#include "rspamd.h"
 
 /**
  * From FreeBSD libutil code
index a919691da016c42b0a4c4f9b6b69920a60e4adf1..bea96b14278ebf0573d181e6ea8bf2935e8ca011 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "config.h"
 #include "radix.h"
-#include "main.h"
+#include "rspamd.h"
 #include "mem_pool.h"
 
 #define msg_err_radix(...) rspamd_default_log_function (G_LOG_LEVEL_CRITICAL, \
index da9884ec11264f1b960c3690926ffa6d53f9ccd9..f713ca2f740e793e85923c6e22abe202b3a40ef9 100644 (file)
@@ -28,7 +28,7 @@
 #include "blake2.h"
 #include "ref.h"
 #include "util.h"
-#include "main.h"
+#include "rspamd.h"
 #include <pcre.h>
 
 typedef guchar regexp_id_t[BLAKE2B_OUTBYTES];
index 983accf62b96d5cb58eb1d9aa0791379dec0bf71..496bd0298b857e3b9e4fc096a13e2e8b16f2a2b6 100644 (file)
@@ -26,7 +26,7 @@
 #include "config.h"
 #include "util.h"
 #include "cfg_file.h"
-#include "main.h"
+#include "rspamd.h"
 #include "filter.h"
 #include "message.h"
 
index b2b2750b585d1e0e0cb859c9fa2d6cc500cb3332..3aee6ea52565806b9be4f5552b650c86b2fe4c20 100644 (file)
@@ -8,7 +8,7 @@
 #include <lauxlib.h>
 #include <lualib.h>
 
-#include "main.h"
+#include "rspamd.h"
 #include "ucl.h"
 #include "lua_ucl.h"
 
index f533434ce1ce0abca39d4a3323cf6a85f0343560..f9f71c532c73e812ec645507fd3ca255d3595d0d 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "lua_common.h"
 #include "task.h"
-#include "main.h"
+#include "rspamd.h"
 #include "html.h"
 #include "cfg_rcl.h"
 #include "tokenizers/tokenizers.h"
index 8e6aaa8fc5c2cdcc0ed53df66caceedebc0f5f48..c378ffc0b63789d4c3efe3bf4de116e4254d6f31 100644 (file)
@@ -24,7 +24,7 @@
 
 #include "config.h"
 #include "util.h"
-#include "main.h"
+#include "rspamd.h"
 #include "libserver/worker_util.h"
 #include "protocol.h"
 #include "upstream.h"
diff --git a/src/main.c b/src/main.c
deleted file mode 100644 (file)
index 87de76b..0000000
+++ /dev/null
@@ -1,1420 +0,0 @@
-/*
- * Copyright (c) 2009-2012, Vsevolod Stakhov
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *      * Redistributions of source code must retain the above copyright
- *        notice, this list of conditions and the following disclaimer.
- *      * Redistributions in binary form must reproduce the above copyright
- *        notice, this list of conditions and the following disclaimer in the
- *        documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "config.h"
-#include "main.h"
-#include "lmtp.h"
-#include "smtp.h"
-#include "libutil/map.h"
-#include "fuzzy_storage.h"
-#include "libserver/symbols_cache.h"
-#include "lua/lua_common.h"
-#include "libserver/worker_util.h"
-#include "ottery.h"
-#include "xxhash.h"
-#include "utlist.h"
-#include "libstat/stat_api.h"
-#include "cryptobox.h"
-#include "regexp.h"
-#ifdef HAVE_OPENSSL
-#include <openssl/rand.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/rsa.h>
-#include <openssl/pem.h>
-#endif
-#ifdef HAVE_LOCALE_H
-#include <locale.h>
-#define HAVE_SETLOCALE 1
-#endif
-
-#define msg_err_main(...) rspamd_default_log_function (G_LOG_LEVEL_CRITICAL, \
-        rspamd_main->server_pool->tag.tagname, rspamd_main->server_pool->tag.uid, \
-        G_STRFUNC, \
-        __VA_ARGS__)
-#define msg_warn_main(...)   rspamd_default_log_function (G_LOG_LEVEL_WARNING, \
-        rspamd_main->server_pool->tag.tagname, rspamd_main->server_pool->tag.uid, \
-        G_STRFUNC, \
-        __VA_ARGS__)
-#define msg_info_main(...)   rspamd_default_log_function (G_LOG_LEVEL_INFO, \
-        rspamd_main->server_pool->tag.tagname, rspamd_main->server_pool->tag.uid, \
-        G_STRFUNC, \
-        __VA_ARGS__)
-#define msg_debug_main(...)  rspamd_default_log_function (G_LOG_LEVEL_DEBUG, \
-        rspamd_main->server_pool->tag.tagname, rspamd_main->server_pool->tag.uid, \
-        G_STRFUNC, \
-        __VA_ARGS__)
-
-/* 2 seconds to fork new process in place of dead one */
-#define SOFT_FORK_TIME 2
-
-/* 10 seconds after getting termination signal to terminate all workers with SIGKILL */
-#define HARD_TERMINATION_TIME 10
-
-static struct rspamd_worker * fork_worker (struct rspamd_main *,
-       struct rspamd_worker_conf *, guint);
-static gboolean load_rspamd_config (struct rspamd_config *cfg,
-       gboolean init_modules);
-
-sig_atomic_t do_restart = 0;
-sig_atomic_t do_reopen_log = 0;
-sig_atomic_t do_terminate = 0;
-sig_atomic_t child_dead = 0;
-sig_atomic_t got_alarm = 0;
-
-#ifdef HAVE_SA_SIGINFO
-GQueue *signals_info = NULL;
-#endif
-
-static gboolean config_test = FALSE;
-static gboolean no_fork = FALSE;
-static gchar **cfg_names = NULL;
-static gchar **lua_tests = NULL;
-static gchar **sign_configs = NULL;
-static gchar *privkey = NULL;
-static gchar *rspamd_user = NULL;
-static gchar *rspamd_group = NULL;
-static gchar *rspamd_pidfile = NULL;
-static gboolean dump_cache = FALSE;
-static gboolean is_debug = FALSE;
-static gboolean is_insecure = FALSE;
-static gboolean gen_keypair = FALSE;
-static gboolean encrypt_password = FALSE;
-/* List of workers that are pending to start */
-static GList *workers_pending = NULL;
-static GHashTable *vars = NULL;
-
-#ifdef HAVE_SA_SIGINFO
-static siginfo_t static_sg[64];
-static sig_atomic_t cur_sg = 0;
-#endif
-
-/* List of unrelated forked processes */
-static GArray *other_workers = NULL;
-
-/* List of active listen sockets indexed by worker type */
-static GHashTable *listen_sockets = NULL;
-
-struct rspamd_main *rspamd_main;
-
-/* Defined in modules.c */
-extern module_t *modules[];
-extern worker_t *workers[];
-
-/* Commandline options */
-static GOptionEntry entries[] =
-{
-       { "config-test", 't', 0, G_OPTION_ARG_NONE, &config_test,
-         "Do config test and exit", NULL },
-       { "no-fork", 'f', 0, G_OPTION_ARG_NONE, &no_fork,
-         "Do not daemonize main process", NULL },
-       { "config", 'c', 0, G_OPTION_ARG_FILENAME_ARRAY, &cfg_names,
-         "Specify config file(s)", NULL },
-       { "user", 'u', 0, G_OPTION_ARG_STRING, &rspamd_user,
-         "User to run rspamd as", NULL },
-       { "group", 'g', 0, G_OPTION_ARG_STRING, &rspamd_group,
-         "Group to run rspamd as", NULL },
-       { "pid", 'p', 0, G_OPTION_ARG_STRING, &rspamd_pidfile, "Path to pidfile",
-         NULL },
-       { "dump-cache", 'C', 0, G_OPTION_ARG_NONE, &dump_cache,
-         "Dump symbols cache stats and exit", NULL },
-       { "debug", 'd', 0, G_OPTION_ARG_NONE, &is_debug, "Force debug output",
-         NULL },
-       { "insecure", 'i', 0, G_OPTION_ARG_NONE, &is_insecure,
-         "Ignore running workers as privileged users (insecure)", NULL },
-       { "test-lua", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &lua_tests,
-         "Specify lua file(s) to test", NULL },
-       { "sign-config", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &sign_configs,
-         "Specify config file(s) to sign", NULL },
-       { "private-key", 0, 0, G_OPTION_ARG_FILENAME, &privkey,
-         "Specify private key to sign", NULL },
-       { "gen-keypair", 0, 0, G_OPTION_ARG_NONE, &gen_keypair, "Generate new encryption "
-                       "keypair", NULL},
-       { "encrypt-password", 0, 0, G_OPTION_ARG_NONE, &encrypt_password, "Encrypt "
-                       "controller password to store in the configuration file", NULL },
-       { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
-};
-
-extern const struct rspamd_controller_pbkdf pbkdf_list[];
-
-#ifndef HAVE_SA_SIGINFO
-static void
-sig_handler (gint signo)
-#else
-static void
-sig_handler (gint signo, siginfo_t *info, void *unused)
-#endif
-{
-#ifdef HAVE_SA_SIGINFO
-       if (cur_sg < (sig_atomic_t)G_N_ELEMENTS (static_sg)) {
-               memcpy (&static_sg[cur_sg++], info, sizeof (siginfo_t));
-       }
-       /* XXX: discard more than 64 simultaneous signals */
-#endif
-
-       switch (signo) {
-       case SIGHUP:
-               do_restart = 1;
-               break;
-       case SIGINT:
-       case SIGTERM:
-               do_terminate = 1;
-               break;
-       case SIGCHLD:
-               child_dead = 1;
-               break;
-       case SIGUSR1:
-               do_reopen_log = 1;
-               break;
-       case SIGUSR2:
-               /* Do nothing */
-               break;
-       case SIGALRM:
-               got_alarm = 1;
-               break;
-       }
-}
-
-#ifdef HAVE_SA_SIGINFO
-
-static const gchar *
-chldsigcode (gint code) {
-       switch (code) {
-#ifdef CLD_EXITED
-       case CLD_EXITED:
-               return "Child exited normally";
-       case CLD_KILLED:
-               return "Child has terminated abnormally but did not create a core file";
-       case CLD_DUMPED:
-               return "Child has terminated abnormally and created a core file";
-       case CLD_TRAPPED:
-               return "Traced child has trapped";
-#endif
-       default:
-               return "Unknown reason";
-       }
-}
-
-/* Prints info about incoming signals by parsing siginfo structures */
-static void
-print_signals_info (void)
-{
-       siginfo_t *inf;
-
-       while ((inf = g_queue_pop_head (signals_info))) {
-               if (inf->si_signo == SIGCHLD) {
-                       msg_info_main ("got SIGCHLD from child: %P; reason: '%s'",
-                               inf->si_pid, chldsigcode (inf->si_code));
-               }
-               else {
-                       msg_info_main ("got signal: '%s'; received from pid: %P; uid: %ul",
-                               g_strsignal (inf->si_signo), inf->si_pid, (gulong)inf->si_uid);
-               }
-       }
-}
-#endif
-
-
-static void
-read_cmd_line (gint *argc, gchar ***argv, struct rspamd_config *cfg)
-{
-       GError *error = NULL;
-       GOptionContext *context;
-       guint i, cfg_num;
-       pid_t r;
-
-       context = g_option_context_new ("- run rspamd daemon");
-       g_option_context_set_summary (context,
-               "Summary:\n  Rspamd daemon version " RVERSION "\n  Release id: " RID);
-       g_option_context_add_main_entries (context, entries, NULL);
-
-       if (!g_option_context_parse (context, argc, argv, &error)) {
-               fprintf (stderr, "option parsing failed: %s\n", error->message);
-               exit (1);
-       }
-
-       cfg->no_fork = no_fork;
-       cfg->config_test = config_test;
-       cfg->rspamd_user = rspamd_user;
-       cfg->rspamd_group = rspamd_group;
-       cfg_num = cfg_names != NULL ? g_strv_length (cfg_names) : 0;
-       if (cfg_num == 0) {
-               cfg->cfg_name = FIXED_CONFIG_FILE;
-       }
-       else {
-               cfg->cfg_name = cfg_names[0];
-       }
-       for (i = 1; i < cfg_num; i++) {
-               r = fork ();
-               if (r == 0) {
-                       /* Spawning new main process */
-                       ottery_init (NULL);
-                       cfg->cfg_name = cfg_names[i];
-                       (void)setsid ();
-               }
-               else if (r == -1) {
-                       fprintf (stderr,
-                               "fork failed while spawning process for %s configuration file: %s\n",
-                               cfg_names[i],
-                               strerror (errno));
-               }
-               else {
-                       /* Save pid to the list of other main processes, we need it to ignore SIGCHLD from them */
-                       g_array_append_val (other_workers, r);
-               }
-       }
-       cfg->pid_file = rspamd_pidfile;
-}
-
-/* Detect privilleged mode */
-static void
-detect_priv (struct rspamd_main *rspamd)
-{
-       struct passwd *pwd;
-       struct group *grp;
-       uid_t euid;
-
-       euid = geteuid ();
-
-       if (euid == 0) {
-               if (!rspamd->cfg->rspamd_user && !is_insecure) {
-                       msg_err_main (
-                               "cannot run rspamd workers as root user, please add -u and -g options to select a proper unprivilleged user or specify --insecure flag");
-                       exit (EXIT_FAILURE);
-               }
-               else if (is_insecure) {
-                       rspamd->is_privilleged = TRUE;
-                       rspamd->workers_uid = 0;
-                       rspamd->workers_gid = 0;
-               }
-               else {
-                       rspamd->is_privilleged = TRUE;
-                       pwd = getpwnam (rspamd->cfg->rspamd_user);
-                       if (pwd == NULL) {
-                               msg_err_main ("user specified does not exists (%s), aborting",
-                                       strerror (errno));
-                               exit (-errno);
-                       }
-                       if (rspamd->cfg->rspamd_group) {
-                               grp = getgrnam (rspamd->cfg->rspamd_group);
-                               if (grp == NULL) {
-                                       msg_err_main ("group specified does not exists (%s), aborting",
-                                               strerror (errno));
-                                       exit (-errno);
-                               }
-                               rspamd->workers_gid = grp->gr_gid;
-                       }
-                       else {
-                               rspamd->workers_gid = -1;
-                       }
-                       rspamd->workers_uid = pwd->pw_uid;
-               }
-       }
-       else {
-               rspamd->is_privilleged = FALSE;
-               rspamd->workers_uid = -1;
-               rspamd->workers_gid = -1;
-       }
-}
-
-static void
-drop_priv (struct rspamd_main *rspamd)
-{
-       if (rspamd->is_privilleged) {
-               if (setgid (rspamd->workers_gid) == -1) {
-                       msg_err_main ("cannot setgid to %d (%s), aborting",
-                               (gint)rspamd->workers_gid,
-                               strerror (errno));
-                       exit (-errno);
-               }
-               if (rspamd->cfg->rspamd_user &&
-                       initgroups (rspamd->cfg->rspamd_user, rspamd->workers_gid) == -1) {
-                       msg_err_main ("initgroups failed (%s), aborting", strerror (errno));
-                       exit (-errno);
-               }
-               if (setuid (rspamd->workers_uid) == -1) {
-                       msg_err_main ("cannot setuid to %d (%s), aborting",
-                               (gint)rspamd->workers_uid,
-                               strerror (errno));
-                       exit (-errno);
-               }
-       }
-}
-
-static void
-config_logger (rspamd_mempool_t *pool, gpointer ud)
-{
-       struct rspamd_main *rm = ud;
-
-       if (config_test) {
-               /* Explicitly set logger type to console in case of config testing */
-               rm->cfg->log_type = RSPAMD_LOG_CONSOLE;
-       }
-
-       rspamd_set_logger (rm->cfg, g_quark_try_string ("main"), rm);
-       if (rspamd_log_open_priv (rm->logger, rm->workers_uid, rm->workers_gid) == -1) {
-               fprintf (stderr, "Fatal error, cannot open logfile, exiting\n");
-               exit (EXIT_FAILURE);
-       }
-}
-
-static void
-reread_config (struct rspamd_main *rspamd)
-{
-       struct rspamd_config *tmp_cfg;
-       gchar *cfg_file;
-
-       tmp_cfg = (struct rspamd_config *)g_malloc0 (sizeof (struct rspamd_config));
-       tmp_cfg->c_modules = g_hash_table_ref (rspamd->cfg->c_modules);
-       rspamd_set_logger (tmp_cfg,  g_quark_try_string ("main"), rspamd);
-       rspamd_init_cfg (tmp_cfg, TRUE);
-       cfg_file = rspamd_mempool_strdup (tmp_cfg->cfg_pool,
-                       rspamd->cfg->cfg_name);
-       tmp_cfg->cache = rspamd_symbols_cache_new (tmp_cfg);
-       /* Save some variables */
-       tmp_cfg->cfg_name = cfg_file;
-
-       if (!load_rspamd_config (tmp_cfg, FALSE)) {
-               rspamd_set_logger (rspamd_main->cfg, g_quark_try_string (
-                               "main"), rspamd_main);
-               msg_err_main ("cannot parse new config file, revert to old one");
-               rspamd_config_free (tmp_cfg);
-       }
-       else {
-               msg_debug_main ("replacing config");
-               rspamd_symbols_cache_destroy (rspamd_main->cfg->cache);
-               rspamd_config_free (rspamd->cfg);
-               g_free (rspamd->cfg);
-
-               rspamd->cfg = tmp_cfg;
-               rspamd_set_logger (tmp_cfg,  g_quark_try_string ("main"), rspamd);
-               /* Force debug log */
-               if (is_debug) {
-                       rspamd->cfg->log_level = G_LOG_LEVEL_DEBUG;
-               }
-
-               rspamd_init_filters (rspamd->cfg, TRUE);
-               rspamd_symbols_cache_init (rspamd->cfg->cache);
-               msg_info_main ("config has been reread successfully");
-       }
-}
-
-static void
-set_worker_limits (struct rspamd_worker_conf *cf)
-{
-       struct rlimit rlmt;
-
-       if (cf->rlimit_nofile != 0) {
-               rlmt.rlim_cur = (rlim_t) cf->rlimit_nofile;
-               rlmt.rlim_max = (rlim_t) cf->rlimit_nofile;
-
-               if (setrlimit (RLIMIT_NOFILE, &rlmt) == -1) {
-                       msg_warn_main ("cannot set files rlimit: %d, %s",
-                               cf->rlimit_nofile,
-                               strerror (errno));
-               }
-       }
-
-       if (cf->rlimit_maxcore != 0) {
-               rlmt.rlim_cur = (rlim_t) cf->rlimit_maxcore;
-               rlmt.rlim_max = (rlim_t) cf->rlimit_maxcore;
-
-               if (setrlimit (RLIMIT_CORE, &rlmt) == -1) {
-                       msg_warn_main ("cannot set max core rlimit: %d, %s",
-                               cf->rlimit_maxcore,
-                               strerror (errno));
-               }
-       }
-}
-
-static struct rspamd_worker *
-fork_worker (struct rspamd_main *rspamd, struct rspamd_worker_conf *cf,
-               guint index)
-{
-       struct rspamd_worker *cur;
-       /* Starting worker process */
-       cur = (struct rspamd_worker *)g_malloc (sizeof (struct rspamd_worker));
-       if (cur) {
-               bzero (cur, sizeof (struct rspamd_worker));
-               cur->srv = rspamd;
-               cur->type = cf->type;
-               cur->pid = fork ();
-               cur->cf = g_malloc (sizeof (struct rspamd_worker_conf));
-               memcpy (cur->cf, cf, sizeof (struct rspamd_worker_conf));
-               cur->index = index;
-               cur->ctx = cf->ctx;
-               switch (cur->pid) {
-               case 0:
-                       /* Update pid for logging */
-                       rspamd_log_update_pid (cf->type, rspamd->logger);
-                       /* Lock statfile pool if possible XXX */
-                       /* Init PRNG after fork */
-                       ottery_init (NULL);
-                       g_random_set_seed (ottery_rand_uint32 ());
-                       /* Drop privilleges */
-                       drop_priv (rspamd);
-                       /* Set limits */
-                       set_worker_limits (cf);
-                       setproctitle ("%s process", cf->worker->name);
-                       rspamd_pidfile_close (rspamd->pfh);
-                       /* Do silent log reopen to avoid collisions */
-                       rspamd_log_close (rspamd->logger);
-                       rspamd_log_open (rspamd->logger);
-#if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30))
-# if (GLIB_MINOR_VERSION > 20)
-                       /* Ugly hack for old glib */
-                       if (!g_thread_get_initialized ()) {
-                               g_thread_init (NULL);
-                       }
-# else
-                       g_thread_init (NULL);
-# endif
-#endif
-                       msg_info_main ("starting %s process %P", cf->worker->name, getpid ());
-                       cf->worker->worker_start_func (cur);
-                       break;
-               case -1:
-                       msg_err_main ("cannot fork main process. %s", strerror (errno));
-                       rspamd_pidfile_remove (rspamd->pfh);
-                       exit (-errno);
-                       break;
-               default:
-                       /* Insert worker into worker's table, pid is index */
-                       g_hash_table_insert (rspamd->workers, GSIZE_TO_POINTER (
-                                       cur->pid), cur);
-                       break;
-               }
-       }
-
-       return cur;
-}
-
-static void
-set_alarm (guint seconds)
-{
-#ifdef HAVE_SETITIMER
-       static struct itimerval itv;
-
-       itv.it_interval.tv_sec = 0;
-       itv.it_interval.tv_usec = 0;
-       itv.it_value.tv_sec = seconds;
-       itv.it_value.tv_usec = 0;
-
-       if (setitimer (ITIMER_REAL, &itv, NULL) == -1) {
-               msg_err_main ("set alarm failed: %s", strerror (errno));
-       }
-#else
-       (void)alarm (seconds);
-#endif
-}
-
-struct waiting_worker {
-       struct rspamd_worker_conf *cf;
-       guint oldindex;
-};
-
-static void
-delay_fork (struct rspamd_worker_conf *cf, guint index)
-{
-       struct waiting_worker *nw;
-
-       nw = g_slice_alloc (sizeof (*nw));
-       nw->cf = cf;
-       nw->oldindex = index;
-
-       workers_pending = g_list_prepend (workers_pending, nw);
-       set_alarm (SOFT_FORK_TIME);
-}
-
-static GList *
-create_listen_socket (GPtrArray *addrs, guint cnt, gint listen_type)
-{
-       GList *result = NULL;
-       gint fd;
-       guint i;
-
-       g_ptr_array_sort (addrs, rspamd_inet_address_compare_ptr);
-       for (i = 0; i < cnt; i ++) {
-               fd = rspamd_inet_address_listen (g_ptr_array_index (addrs, i),
-                               listen_type, TRUE);
-               if (fd != -1) {
-                       result = g_list_prepend (result, GINT_TO_POINTER (fd));
-               }
-       }
-
-       return result;
-}
-
-static GList *
-systemd_get_socket (gint number)
-{
-       int sock, num_passed, flags;
-       GList *result = NULL;
-       const gchar *e;
-       gchar *err;
-       struct stat st;
-       /* XXX: can we trust the current choice ? */
-       static const int sd_listen_fds_start = 3;
-
-       e = getenv ("LISTEN_FDS");
-       if (e != NULL) {
-               errno = 0;
-               num_passed = strtoul (e, &err, 10);
-               if ((err == NULL || *err == '\0') && num_passed > number) {
-                       sock = number + sd_listen_fds_start;
-                       if (fstat (sock, &st) == -1) {
-                               msg_warn_main ("cannot stat systemd descriptor %d", sock);
-                               return NULL;
-                       }
-                       if (!S_ISSOCK (st.st_mode)) {
-                               msg_warn_main ("systemd descriptor %d is not a socket", sock);
-                               errno = EINVAL;
-                               return NULL;
-                       }
-                       flags = fcntl (sock, F_GETFD);
-                       if (flags != -1) {
-                               (void)fcntl (sock, F_SETFD, flags | FD_CLOEXEC);
-                       }
-                       result = g_list_prepend (result, GINT_TO_POINTER (sock));
-               }
-               else if (num_passed <= number) {
-                       msg_warn_main ("systemd LISTEN_FDS does not contain the expected fd: %d",
-                                       num_passed);
-                       errno = EOVERFLOW;
-               }
-       }
-       else {
-               msg_warn_main ("cannot get systemd variable 'LISTEN_FDS'");
-               errno = ENOENT;
-       }
-
-       return result;
-}
-
-static void
-fork_delayed (struct rspamd_main *rspamd)
-{
-       GList *cur;
-       struct waiting_worker *w;
-
-       while (workers_pending != NULL) {
-               cur = workers_pending;
-               w = cur->data;
-
-               workers_pending = g_list_remove_link (workers_pending, cur);
-               fork_worker (rspamd, w->cf, w->oldindex);
-               g_list_free_1 (cur);
-               g_slice_free1 (sizeof (*w), w);
-       }
-}
-
-static inline uintptr_t
-make_listen_key (struct rspamd_worker_bind_conf *cf)
-{
-       XXH64_state_t st;
-       guint i, keylen;
-       guint8 *key;
-       rspamd_inet_addr_t *addr;
-       guint16 port;
-
-       XXH64_reset (&st, rspamd_hash_seed ());
-       if (cf->is_systemd) {
-               XXH64_update (&st, "systemd", sizeof ("systemd"));
-               XXH64_update (&st, &cf->cnt, sizeof (cf->cnt));
-       }
-       else {
-               XXH64_update (&st, cf->name, strlen (cf->name));
-               for (i = 0; i < cf->cnt; i ++) {
-                       addr = g_ptr_array_index (cf->addrs, i);
-                       key = rspamd_inet_address_get_radix_key (
-                                       addr, &keylen);
-                       XXH64_update (&st, key, keylen);
-                       port = rspamd_inet_address_get_port (addr);
-                       XXH64_update (&st, &port, sizeof (port));
-               }
-       }
-
-       return XXH64_digest (&st);
-}
-
-static void
-spawn_workers (struct rspamd_main *rspamd)
-{
-       GList *cur, *ls;
-       struct rspamd_worker_conf *cf;
-       gint i;
-       gpointer p;
-       guintptr key;
-       struct rspamd_worker_bind_conf *bcf;
-       gboolean listen_ok = FALSE;
-
-       cur = rspamd->cfg->workers;
-
-       while (cur) {
-               cf = cur->data;
-               listen_ok = FALSE;
-
-               if (cf->worker == NULL) {
-                       msg_err_main ("type of worker is unspecified, skip spawning");
-               }
-               else {
-                       if (cf->worker->has_socket) {
-                               LL_FOREACH (cf->bind_conf, bcf) {
-                                       key = make_listen_key (bcf);
-                                       if ((p =
-                                               g_hash_table_lookup (listen_sockets,
-                                               GINT_TO_POINTER (key))) == NULL) {
-                                               if (!bcf->is_systemd) {
-                                                       /* Create listen socket */
-                                                       ls = create_listen_socket (bcf->addrs, bcf->cnt,
-                                                                       cf->worker->listen_type);
-                                               }
-                                               else {
-                                                       ls = systemd_get_socket (bcf->cnt);
-                                               }
-                                               if (ls == NULL) {
-                                                       msg_err_main ("cannot listen on socket %s: %s",
-                                                               bcf->name,
-                                                               strerror (errno));
-                                               }
-                                               else {
-                                                       g_hash_table_insert (listen_sockets, (gpointer)key, ls);
-                                                       listen_ok = TRUE;
-                                               }
-                                       }
-                                       else {
-                                               /* We had socket for this type of worker */
-                                               ls = p;
-                                               listen_ok = TRUE;
-                                       }
-                                       /* Do not add existing lists as it causes loops */
-                                       if (g_list_position (cf->listen_socks, ls) == -1) {
-                                               cf->listen_socks = g_list_concat (cf->listen_socks, ls);
-                                       }
-                               }
-                       }
-
-                       if (listen_ok) {
-                               if (cf->worker->unique) {
-                                       if (cf->count > 1) {
-                                               msg_warn_main ("cannot spawn more than 1 %s worker, so spawn one",
-                                                               cf->worker->name);
-                                       }
-                                       fork_worker (rspamd, cf, 0);
-                               }
-                               else if (cf->worker->threaded) {
-                                       fork_worker (rspamd, cf, 0);
-                               }
-                               else {
-                                       for (i = 0; i < cf->count; i++) {
-                                               fork_worker (rspamd, cf, i);
-                                       }
-                               }
-                       }
-                       else {
-                               msg_err_main ("cannot create listen socket for %s at %s",
-                                               g_quark_to_string (cf->type), cf->bind_conf->name);
-
-                               exit (EXIT_FAILURE);
-                       }
-               }
-
-               cur = g_list_next (cur);
-       }
-}
-
-static void
-kill_old_workers (gpointer key, gpointer value, gpointer unused)
-{
-       struct rspamd_worker *w = value;
-
-       kill (w->pid, SIGUSR2);
-       msg_info_main ("send signal to worker %P", w->pid);
-}
-
-static gboolean
-wait_for_workers (gpointer key, gpointer value, gpointer unused)
-{
-       struct rspamd_worker *w = value;
-       gint res = 0;
-
-       if (got_alarm) {
-               got_alarm = 0;
-               /* Set alarm for hard termination but with less time */
-               set_alarm (HARD_TERMINATION_TIME / 10);
-       }
-
-       if (waitpid (w->pid, &res, 0) == -1) {
-               if (errno == EINTR) {
-                       got_alarm = 1;
-                       if (w->cf->worker->killable) {
-                               msg_info_main ("terminate worker %P with SIGKILL", w->pid);
-                               kill (w->pid, SIGKILL);
-                       }
-                       else {
-                               msg_info_main ("waiting for workers to sync");
-                               wait_for_workers (key, value, unused);
-                               return TRUE;
-                       }
-               }
-       }
-
-       msg_info_main ("%s process %P terminated %s", g_quark_to_string (
-                       w->type), w->pid,
-               got_alarm ? "hardly" : "softly");
-       g_free (w->cf);
-       g_free (w);
-
-       return TRUE;
-}
-
-static void
-reopen_log_handler (gpointer key, gpointer value, gpointer unused)
-{
-       struct rspamd_worker *w = value;
-
-       if (kill (w->pid, SIGUSR1) == -1) {
-               msg_err_main ("kill failed for pid %P: %s", w->pid, strerror (errno));
-       }
-}
-
-static gboolean
-load_rspamd_config (struct rspamd_config *cfg, gboolean init_modules)
-{
-       cfg->cache = rspamd_symbols_cache_new (cfg);
-       cfg->compiled_modules = modules;
-       cfg->compiled_workers = workers;
-
-       if (!rspamd_config_read (cfg, cfg->cfg_name, NULL,
-               config_logger, rspamd_main, vars)) {
-               return FALSE;
-       }
-
-       /* Strictly set temp dir */
-       if (!cfg->temp_dir) {
-               msg_warn_main ("tempdir is not set, trying to use $TMPDIR");
-               cfg->temp_dir =
-                       rspamd_mempool_strdup (cfg->cfg_pool, getenv ("TMPDIR"));
-
-               if (!cfg->temp_dir) {
-                       msg_warn_main ("$TMPDIR is empty too, using /tmp as default");
-                       cfg->temp_dir = rspamd_mempool_strdup (cfg->cfg_pool, "/tmp");
-               }
-       }
-
-       /* Do post-load actions */
-       rspamd_config_post_load (cfg);
-
-       if (init_modules) {
-               rspamd_init_filters (cfg, FALSE);
-       }
-
-       return TRUE;
-}
-
-static gint
-perform_lua_tests (struct rspamd_config *cfg)
-{
-       gint i, tests_num, res = EXIT_SUCCESS;
-       gchar *cur_script;
-       lua_State *L = cfg->lua_state;
-
-       tests_num = g_strv_length (lua_tests);
-
-       for (i = 0; i < tests_num; i++) {
-
-               if (luaL_loadfile (L, lua_tests[i]) != 0) {
-                       msg_err_main ("load of %s failed: %s", lua_tests[i],
-                               lua_tostring (L, -1));
-                       res = EXIT_FAILURE;
-                       continue;
-               }
-
-               cur_script = g_strdup (lua_tests[i]);
-               lua_pushstring (L, cur_script);
-               lua_setglobal (L, "test_script");
-               lua_pushstring (L, dirname (cur_script));
-               lua_setglobal (L, "test_dir");
-               g_free (cur_script);
-
-               /* do the call (0 arguments, N result) */
-               if (lua_pcall (L, 0, LUA_MULTRET, 0) != 0) {
-                       msg_info_main ("init of %s failed: %s", lua_tests[i], lua_tostring (L,
-                               -1));
-                       res = EXIT_FAILURE;
-                       continue;
-               }
-               if (lua_gettop (L) != 0) {
-                       if (lua_tonumber (L, -1) == -1) {
-                               msg_info_main ("%s returned -1 that indicates configuration error",
-                                       lua_tests[i]);
-                               res = EXIT_FAILURE;
-                               continue;
-                       }
-                       lua_pop (L, lua_gettop (L));
-               }
-       }
-
-       return res;
-}
-
-static gint
-perform_configs_sign (void)
-{
-#ifndef HAVE_OPENSSL
-       msg_err_main ("cannot sign files without openssl support");
-       return EXIT_FAILURE;
-#else
-# if (OPENSSL_VERSION_NUMBER < 0x10000000L)
-       msg_err_main ("must have openssl at least 1.0.0 to perform this action");
-       return EXIT_FAILURE;
-# else
-       gint i, tests_num, res = EXIT_SUCCESS, fd;
-       guint diglen;
-       gchar *cur_file, in_file[PATH_MAX],
-               out_file[PATH_MAX], dig[EVP_MAX_MD_SIZE];
-       gsize siglen;
-       struct stat st;
-       gpointer map, sig;
-       EVP_PKEY *key = NULL;
-       BIO *fbio;
-       EVP_PKEY_CTX *key_ctx = NULL;
-       EVP_MD_CTX *sign_ctx = NULL;
-
-       /* Load private key */
-       fbio = BIO_new_file (privkey, "r");
-       if (fbio == NULL) {
-               msg_err_main ("cannot open private key %s, %s", privkey,
-                       ERR_error_string (ERR_get_error (), NULL));
-               return ERR_get_error ();
-       }
-       if (!PEM_read_bio_PrivateKey (fbio, &key, rspamd_read_passphrase, NULL)) {
-               msg_err_main ("cannot read private key %s, %s", privkey,
-                       ERR_error_string (ERR_get_error (), NULL));
-               return ERR_get_error ();
-       }
-
-       key_ctx = EVP_PKEY_CTX_new (key, NULL);
-       if (key_ctx == NULL) {
-               msg_err_main ("cannot parse private key %s, %s", privkey,
-                       ERR_error_string (ERR_get_error (), NULL));
-               return ERR_get_error ();
-       }
-
-       if (EVP_PKEY_sign_init (key_ctx) <= 0) {
-               msg_err_main ("cannot parse private key %s, %s", privkey,
-                       ERR_error_string (ERR_get_error (), NULL));
-               return ERR_get_error ();
-       }
-       if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) {
-               msg_err_main ("cannot init private key %s, %s", privkey,
-                       ERR_error_string (ERR_get_error (), NULL));
-               return ERR_get_error ();
-       }
-       if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) {
-               msg_err_main ("cannot init signature private key %s, %s", privkey,
-                       ERR_error_string (ERR_get_error (), NULL));
-               return ERR_get_error ();
-       }
-
-       sign_ctx = EVP_MD_CTX_create ();
-
-       tests_num = g_strv_length (sign_configs);
-
-       for (i = 0; i < tests_num; i++) {
-               cur_file = sign_configs[i];
-               if (realpath (cur_file, in_file) == NULL) {
-                       msg_err_main ("cannot resolve %s: %s", cur_file, strerror (errno));
-                       continue;
-               }
-               if (stat (in_file, &st) == -1) {
-                       msg_err_main ("cannot stat %s: %s", in_file, strerror (errno));
-                       continue;
-               }
-               if ((fd = open (in_file, O_RDONLY)) == -1) {
-                       msg_err_main ("cannot open %s: %s", in_file, strerror (errno));
-                       continue;
-               }
-
-               if ((map =
-                       mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd,
-                       0)) == MAP_FAILED) {
-                       close (fd);
-                       msg_err_main ("cannot mmap %s: %s", in_file, strerror (errno));
-                       continue;
-               }
-
-               close (fd);
-               /* Now try to sign */
-               EVP_DigestInit (sign_ctx, EVP_sha256 ());
-               EVP_DigestUpdate (sign_ctx, map, st.st_size);
-               EVP_DigestFinal (sign_ctx, dig, &diglen);
-
-               munmap (map, st.st_size);
-
-               if (EVP_PKEY_sign (key_ctx, NULL, &siglen, dig, diglen) <= 0) {
-                       msg_err_main ("cannot sign %s using private key %s, %s",
-                               in_file,
-                               privkey,
-                               ERR_error_string (ERR_get_error (), NULL));
-                       continue;
-               }
-
-               sig = OPENSSL_malloc (siglen);
-               if (EVP_PKEY_sign (key_ctx, sig, &siglen, dig, diglen) <= 0) {
-                       msg_err_main ("cannot sign %s using private key %s, %s",
-                               in_file,
-                               privkey,
-                               ERR_error_string (ERR_get_error (), NULL));
-                       OPENSSL_free (sig);
-                       continue;
-               }
-
-               rspamd_snprintf (out_file, sizeof (out_file), "%s.sig", in_file);
-               fd = open (out_file, O_WRONLY | O_CREAT | O_TRUNC, 00644);
-               if (fd == -1) {
-                       msg_err_main ("cannot open output file %s: %s", out_file, strerror (
-                                       errno));
-                       OPENSSL_free (sig);
-                       continue;
-               }
-               if (write (fd, sig, siglen) == -1) {
-                       msg_err_main ("cannot write to output file %s: %s", out_file,
-                               strerror (errno));
-               }
-               OPENSSL_free (sig);
-               close (fd);
-       }
-
-       /* Cleanup */
-       EVP_MD_CTX_destroy (sign_ctx);
-       EVP_PKEY_CTX_free (key_ctx);
-       EVP_PKEY_free (key);
-       BIO_free (fbio);
-
-       return res;
-# endif
-#endif
-}
-
-static void
-do_encrypt_password (void)
-{
-       const struct rspamd_controller_pbkdf *pbkdf;
-       guchar *salt, *key;
-       gchar *encoded_salt, *encoded_key;
-       gchar password[BUFSIZ];
-       gsize plen;
-
-       pbkdf = &pbkdf_list[0];
-       g_assert (pbkdf != NULL);
-
-       plen = rspamd_read_passphrase (password, sizeof (password), 0, NULL);
-
-       if (plen == 0) {
-               fprintf (stderr, "Invalid password\n");
-               exit (EXIT_FAILURE);
-       }
-
-       salt = g_alloca (pbkdf->salt_len);
-       key = g_alloca (pbkdf->key_len);
-       ottery_rand_bytes (salt, pbkdf->salt_len);
-       /* Derive key */
-       rspamd_cryptobox_pbkdf (password, strlen (password),
-                       salt, pbkdf->salt_len, key, pbkdf->key_len, pbkdf->rounds);
-
-       encoded_salt = rspamd_encode_base32 (salt, pbkdf->salt_len);
-       encoded_key = rspamd_encode_base32 (key, pbkdf->key_len);
-
-       rspamd_printf ("$%d$%s$%s\n", pbkdf->id, encoded_salt,
-                       encoded_key);
-
-       g_free (encoded_salt);
-       g_free (encoded_key);
-       rspamd_explicit_memzero (password, sizeof (password));
-}
-
-static void
-rspamd_init_main (struct rspamd_main *rspamd)
-{
-       rspamd->server_pool = rspamd_mempool_new (rspamd_mempool_suggest_size (),
-                       "main");
-       rspamd_main->stat = rspamd_mempool_alloc0_shared (rspamd_main->server_pool,
-               sizeof (struct rspamd_stat));
-       /* Create rolling history */
-       rspamd_main->history = rspamd_roll_history_new (rspamd_main->server_pool);
-}
-
-gint
-main (gint argc, gchar **argv, gchar **env)
-{
-       gint res = 0, i;
-       struct sigaction signals;
-       struct rspamd_worker *cur;
-       pid_t wrk;
-       worker_t **pworker;
-       GQuark type;
-       gpointer keypair;
-       GString *keypair_out;
-
-#ifdef HAVE_SA_SIGINFO
-       signals_info = g_queue_new ();
-#endif
-#if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30))
-       g_thread_init (NULL);
-#endif
-       rspamd_main = (struct rspamd_main *)g_malloc0 (sizeof (struct rspamd_main));
-
-       rspamd_main->cfg =
-               (struct rspamd_config *)g_malloc0 (sizeof (struct rspamd_config));
-
-       if (!rspamd_main || !rspamd_main->cfg) {
-               fprintf (stderr, "Cannot allocate memory\n");
-               exit (-errno);
-       }
-
-#ifndef HAVE_SETPROCTITLE
-       init_title (argc, argv, env);
-#endif
-
-       rspamd_init_libs ();
-       rspamd_init_main (rspamd_main);
-       rspamd_init_cfg (rspamd_main->cfg, TRUE);
-
-       memset (&signals, 0, sizeof (struct sigaction));
-
-       other_workers = g_array_new (FALSE, TRUE, sizeof (pid_t));
-
-       read_cmd_line (&argc, &argv, rspamd_main->cfg);
-
-       if (argc > 0) {
-               /* Parse variables */
-               for (i = 0; i < argc; i ++) {
-                       if (strchr (argv[i], '=') != NULL) {
-                               gchar *k, *v, *t;
-
-                               k = g_strdup (argv[i]);
-                               t = strchr (k, '=');
-                               v = g_strdup (t + 1);
-                               *t = '\0';
-
-                               if (vars == NULL) {
-                                       vars = g_hash_table_new_full (rspamd_strcase_hash,
-                                                       rspamd_strcase_equal, g_free, g_free);
-                               }
-
-                               g_hash_table_insert (vars, k, v);
-                       }
-               }
-       }
-
-       if (rspamd_main->cfg->config_test || is_debug) {
-               rspamd_main->cfg->log_level = G_LOG_LEVEL_DEBUG;
-       }
-       else {
-               rspamd_main->cfg->log_level = G_LOG_LEVEL_WARNING;
-       }
-
-       type = g_quark_from_static_string ("main");
-
-       /* First set logger to console logger */
-       rspamd_main->cfg->log_type = RSPAMD_LOG_CONSOLE;
-       rspamd_set_logger (rspamd_main->cfg, type, rspamd_main);
-       (void)rspamd_log_open (rspamd_main->logger);
-       g_log_set_default_handler (rspamd_glib_log_function, rspamd_main->logger);
-       g_set_printerr_handler (rspamd_glib_printerr_function);
-
-       detect_priv (rspamd_main);
-
-       pworker = &workers[0];
-       while (*pworker) {
-               /* Init string quarks */
-               (void)g_quark_from_static_string ((*pworker)->name);
-               pworker++;
-       }
-
-       /* Init listen sockets hash */
-       listen_sockets = g_hash_table_new (g_direct_hash, g_direct_equal);
-
-       /* If we want to test lua skip everything except it */
-       if (lua_tests != NULL && lua_tests[0] != NULL) {
-               exit (perform_lua_tests (rspamd_main->cfg));
-       }
-
-       /* If we want to sign configs, just do it */
-       if (sign_configs != NULL && privkey != NULL) {
-               exit (perform_configs_sign ());
-       }
-
-       /* Same for keypair creation */
-       if (gen_keypair) {
-               keypair = rspamd_http_connection_gen_key ();
-               if (keypair == NULL) {
-                       exit (EXIT_FAILURE);
-               }
-               keypair_out = rspamd_http_connection_print_key (keypair,
-                               RSPAMD_KEYPAIR_PUBKEY|RSPAMD_KEYPAIR_PRIVKEY|RSPAMD_KEYPAIR_ID|
-                               RSPAMD_KEYPAIR_BASE32|RSPAMD_KEYPAIR_HUMAN);
-               rspamd_printf ("%V", keypair_out);
-               exit (EXIT_SUCCESS);
-       }
-
-       if (encrypt_password) {
-               do_encrypt_password ();
-               exit (EXIT_SUCCESS);
-       }
-
-       if (rspamd_main->cfg->config_test || dump_cache) {
-               if (!load_rspamd_config (rspamd_main->cfg, FALSE)) {
-                       exit (EXIT_FAILURE);
-               }
-
-               res = TRUE;
-
-               rspamd_symbols_cache_init (rspamd_main->cfg->cache);
-
-               if (!rspamd_init_filters (rspamd_main->cfg, FALSE)) {
-                       res = FALSE;
-               }
-
-               /* Insert classifiers symbols */
-               (void)rspamd_config_insert_classify_symbols (rspamd_main->cfg);
-
-               if (!rspamd_symbols_cache_validate (rspamd_main->cfg->cache, rspamd_main->cfg,
-                       FALSE)) {
-                       res = FALSE;
-               }
-               if (dump_cache) {
-                       msg_err_main ("Use rspamc counters for dumping cache");
-                       exit (EXIT_FAILURE);
-               }
-               fprintf (stderr, "syntax %s\n", res ? "OK" : "BAD");
-               return res ? EXIT_SUCCESS : EXIT_FAILURE;
-       }
-
-       /* Load config */
-       if (!load_rspamd_config (rspamd_main->cfg, TRUE)) {
-               exit (EXIT_FAILURE);
-       }
-
-       /* Override pidfile from configuration by command line argument */
-       if (rspamd_pidfile != NULL) {
-               rspamd_main->cfg->pid_file = rspamd_pidfile;
-       }
-
-       /* Force debug log */
-       if (is_debug) {
-               rspamd_main->cfg->log_level = G_LOG_LEVEL_DEBUG;
-       }
-
-       gperf_profiler_init (rspamd_main->cfg, "main");
-
-       msg_info_main ("rspamd " RVERSION " is starting, build id: " RID);
-       rspamd_main->cfg->cfg_name = rspamd_mempool_strdup (
-               rspamd_main->cfg->cfg_pool,
-               rspamd_main->cfg->cfg_name);
-
-       /* Daemonize */
-       if (!rspamd_main->cfg->no_fork && daemon (0, 0) == -1) {
-               fprintf (stderr, "Cannot daemonize\n");
-               exit (-errno);
-       }
-
-       /* Write info */
-       rspamd_main->pid = getpid ();
-       rspamd_main->type = type;
-
-       rspamd_signals_init (&signals, sig_handler);
-
-       if (rspamd_main->cfg->pid_file == NULL) {
-               msg_info("pid file is not specified, skipping writing it");
-       } else if (rspamd_write_pid (rspamd_main) == -1) {
-               msg_err_main ("cannot write pid file %s", rspamd_main->cfg->pid_file);
-               exit (-errno);
-       }
-
-       /* Block signals to use sigsuspend in future */
-       sigprocmask (SIG_BLOCK, &signals.sa_mask, NULL);
-
-       setproctitle ("main process");
-
-       /* Init config cache */
-       rspamd_symbols_cache_init (rspamd_main->cfg->cache);
-
-       /* Validate cache */
-       (void)rspamd_symbols_cache_validate (rspamd_main->cfg->cache, rspamd_main->cfg, FALSE);
-
-       /* Flush log */
-       rspamd_log_flush (rspamd_main->logger);
-
-       /* Maybe read roll history */
-       if (rspamd_main->cfg->history_file) {
-               rspamd_roll_history_load (rspamd_main->history,
-                       rspamd_main->cfg->history_file);
-       }
-
-#if defined(WITH_GPERF_TOOLS)
-       ProfilerStop ();
-#endif
-       /* Spawn workers */
-       rspamd_main->workers = g_hash_table_new (g_direct_hash, g_direct_equal);
-       spawn_workers (rspamd_main);
-
-       /* Signal processing cycle */
-       for (;; ) {
-               msg_debug_main ("calling sigsuspend");
-               sigemptyset (&signals.sa_mask);
-               sigsuspend (&signals.sa_mask);
-#ifdef HAVE_SA_SIGINFO
-               for (i = 0; i < cur_sg; i ++) {
-                       g_queue_push_head (signals_info, &static_sg[i]);
-               }
-               cur_sg = 0;
-               print_signals_info ();
-#endif
-               if (do_terminate) {
-                       do_terminate = 0;
-                       msg_info_main ("catch termination signal, waiting for children");
-                       rspamd_pass_signal (rspamd_main->workers, SIGTERM);
-                       break;
-               }
-               if (child_dead) {
-                       child_dead = 0;
-                       msg_debug_main ("catch SIGCHLD signal, finding terminated worker");
-                       /* Remove dead child form children list */
-                       wrk = waitpid (0, &res, 0);
-                       if ((cur =
-                               g_hash_table_lookup (rspamd_main->workers,
-                               GSIZE_TO_POINTER (wrk))) != NULL) {
-                               /* Unlink dead process from queue and hash table */
-
-                               g_hash_table_remove (rspamd_main->workers, GSIZE_TO_POINTER (
-                                               wrk));
-
-                               if (WIFEXITED (res) && WEXITSTATUS (res) == 0) {
-                                       /* Normal worker termination, do not fork one more */
-                                       msg_info_main ("%s process %P terminated normally",
-                                               g_quark_to_string (cur->type),
-                                               cur->pid);
-                               }
-                               else {
-                                       if (WIFSIGNALED (res)) {
-                                               msg_warn_main (
-                                                       "%s process %P terminated abnormally by signal: %d",
-                                                       g_quark_to_string (cur->type),
-                                                       cur->pid,
-                                                       WTERMSIG (res));
-                                       }
-                                       else {
-                                               msg_warn_main ("%s process %P terminated abnormally",
-                                                       g_quark_to_string (cur->type),
-                                                       cur->pid);
-                                       }
-                                       /* Fork another worker in replace of dead one */
-                                       delay_fork (cur->cf, cur->index);
-                               }
-
-                               g_free (cur);
-                       }
-                       else {
-                               for (i = 0; i < (gint)other_workers->len; i++) {
-                                       if (g_array_index (other_workers, pid_t, i) == wrk) {
-                                               g_array_remove_index_fast (other_workers, i);
-                                               msg_info_main ("related process %P terminated", wrk);
-                                       }
-                               }
-                       }
-               }
-               if (do_restart) {
-                       do_restart = 0;
-                       rspamd_log_reopen_priv (rspamd_main->logger,
-                               rspamd_main->workers_uid,
-                               rspamd_main->workers_gid);
-                       msg_info_main ("rspamd " RVERSION " is restarting");
-                       g_hash_table_foreach (rspamd_main->workers, kill_old_workers, NULL);
-                       rspamd_map_remove_all (rspamd_main->cfg);
-                       reread_config (rspamd_main);
-                       spawn_workers (rspamd_main);
-               }
-               if (do_reopen_log) {
-                       do_reopen_log = 0;
-                       rspamd_log_reopen_priv (rspamd_main->logger,
-                               rspamd_main->workers_uid,
-                               rspamd_main->workers_gid);
-                       g_hash_table_foreach (rspamd_main->workers, reopen_log_handler,
-                               NULL);
-               }
-               if (got_alarm) {
-                       got_alarm = 0;
-                       fork_delayed (rspamd_main);
-               }
-       }
-
-       /* Restore some signals */
-       sigemptyset (&signals.sa_mask);
-       sigaddset (&signals.sa_mask, SIGALRM);
-       sigaddset (&signals.sa_mask, SIGINT);
-       sigaddset (&signals.sa_mask, SIGTERM);
-       sigaction (SIGALRM, &signals, NULL);
-       sigaction (SIGTERM, &signals, NULL);
-       sigaction (SIGINT,      &signals, NULL);
-       sigprocmask (SIG_UNBLOCK, &signals.sa_mask, NULL);
-       /* Set alarm for hard termination */
-       if (getenv ("G_SLICE") != NULL) {
-               /* Special case if we are likely running with valgrind */
-               set_alarm (HARD_TERMINATION_TIME * 10);
-       }
-       else {
-               set_alarm (HARD_TERMINATION_TIME);
-       }
-
-       /* Wait for workers termination */
-       g_hash_table_foreach_remove (rspamd_main->workers, wait_for_workers, NULL);
-
-       /* Maybe save roll history */
-       if (rspamd_main->cfg->history_file) {
-               rspamd_roll_history_save (rspamd_main->history,
-                       rspamd_main->cfg->history_file);
-       }
-
-       msg_info_main ("terminating...");
-       rspamd_symbols_cache_destroy (rspamd_main->cfg->cache);
-       rspamd_log_close (rspamd_main->logger);
-       rspamd_config_free (rspamd_main->cfg);
-       g_free (rspamd_main->cfg);
-       g_free (rspamd_main);
-
-       g_mime_shutdown ();
-
-#ifdef HAVE_OPENSSL
-       EVP_cleanup ();
-       ERR_free_strings ();
-#endif
-
-       return (res);
-}
-
-/*
- * vi:ts=4
- */
diff --git a/src/main.h b/src/main.h
deleted file mode 100644 (file)
index 5104040..0000000
+++ /dev/null
@@ -1,231 +0,0 @@
-/**
- * @file main.h
- * Definitions for main rspamd structures
- */
-
-#ifndef RSPAMD_MAIN_H
-#define RSPAMD_MAIN_H
-
-#include "config.h"
-#include "libutil/fstring.h"
-#include "libutil/mem_pool.h"
-#include "libutil/util.h"
-#include "libutil/logger.h"
-#include "libutil/http.h"
-#include "libutil/upstream.h"
-#include "libserver/url.h"
-#include "libserver/protocol.h"
-#include "libserver/buffer.h"
-#include "libserver/events.h"
-#include "libserver/roll_history.h"
-#include "libserver/task.h"
-
-
-/* Default values */
-#define FIXED_CONFIG_FILE RSPAMD_CONFDIR "/rspamd.conf"
-/* Time in seconds to exit for old worker */
-#define SOFT_SHUTDOWN_TIME 10
-
-/* Spam subject */
-#define SPAM_SUBJECT "*** SPAM *** "
-
-#ifdef CRLF
-#undef CRLF
-#undef CR
-#undef LF
-#endif
-
-#define CRLF "\r\n"
-#define CR '\r'
-#define LF '\n'
-
-/**
- * Worker process structure
- */
-struct rspamd_worker {
-       pid_t pid;                                                  /**< pid of worker                                                                  */
-       guint index;                                                /**< index number                                                                   */
-       struct rspamd_main *srv;                                    /**< pointer to server structure                                    */
-       GQuark type;                                                /**< process type                                                                   */
-       GHashTable *signal_events;                                                                      /**< signal events                                                                      */
-       GList *accept_events;                                       /**< socket events                                                                  */
-       struct rspamd_worker_conf *cf;                                      /**< worker config data                                                             */
-       gpointer ctx;                                               /**< worker's specific data                                                 */
-};
-
-struct rspamd_worker_signal_handler {
-       gint signo;
-       gboolean enabled;
-       struct event ev;
-       struct event_base *base;
-       struct rspamd_worker *worker;
-       void (*post_handler)(void *ud);
-       void *handler_data;
-};
-
-struct rspamd_controller_pbkdf {
-       gint id;
-       guint rounds;
-       gsize salt_len;
-       gsize key_len;
-};
-
-/**
- * Common structure representing C module context
- */
-struct module_s;
-struct module_ctx {
-       gint (*filter)(struct rspamd_task *task);                   /**< pointer to headers process function                    */
-       struct module_s *mod;                                                                           /**< module pointer                                                                     */
-       gboolean enabled;                                                                                       /**< true if module is enabled in configuration         */
-};
-
-/**
- * Module
- */
-typedef struct module_s {
-       const gchar *name;
-       int (*module_init_func)(struct rspamd_config *cfg, struct module_ctx **ctx);
-       int (*module_config_func)(struct rspamd_config *cfg);
-       int (*module_reconfig_func)(struct rspamd_config *cfg);
-       int (*module_attach_controller_func)(struct module_ctx *ctx,
-               GHashTable *custom_commands);
-} module_t;
-
-typedef struct worker_s {
-       const gchar *name;
-       gpointer (*worker_init_func)(struct rspamd_config *cfg);
-       void (*worker_start_func)(struct rspamd_worker *worker);
-       gboolean has_socket;
-       gboolean unique;
-       gboolean threaded;
-       gboolean killable;
-       gint listen_type;
-} worker_t;
-
-struct pidfh;
-struct rspamd_config;
-struct tokenizer;
-struct rspamd_stat_classifier;
-struct rspamd_classifier_config;
-struct mime_part;
-struct rspamd_dns_resolver;
-struct rspamd_task;
-
-/**
- * The epoch of the fuzzy client
- */
-enum rspamd_fuzzy_epoch {
-       RSPAMD_FUZZY_EPOCH6 = 0, /**< pre 0.6.x */
-       RSPAMD_FUZZY_EPOCH8,     /**< 0.8 till 0.9 */
-       RSPAMD_FUZZY_EPOCH9,     /**< 0.9 + */
-       RSPAMD_FUZZY_EPOCH_MAX
-};
-
-/**
- * Server statistics
- */
-struct rspamd_stat {
-       guint messages_scanned;                             /**< total number of messages scanned                               */
-       guint actions_stat[METRIC_ACTION_NOACTION + 1];     /**< statistic for each action                                              */
-       guint connections_count;                            /**< total connections count                                                */
-       guint control_connections_count;                    /**< connections count to control interface                 */
-       guint messages_learned;                             /**< messages learned                                                               */
-       guint fuzzy_hashes;                                 /**< number of fuzzy hashes stored                                  */
-       guint fuzzy_hashes_expired;                         /**< number of fuzzy hashes expired                                 */
-       guint64 fuzzy_hashes_checked[RSPAMD_FUZZY_EPOCH_MAX]; /**< ammount of check requests for each epoch             */
-       guint64 fuzzy_hashes_found[RSPAMD_FUZZY_EPOCH_MAX]; /**< amount of hashes found by epoch                                */
-};
-
-/**
- * Struct that determine main server object (for logging purposes)
- */
-struct rspamd_main {
-       struct rspamd_config *cfg;                                  /**< pointer to config structure                                    */
-       pid_t pid;                                                  /**< main pid                                                                               */
-       /* Pid file structure */
-       rspamd_pidfh_t *pfh;                                        /**< struct pidfh for pidfile                                               */
-       GQuark type;                                                /**< process type                                                                   */
-       guint ev_initialized;                                       /**< is event system is initialized                                 */
-       struct rspamd_stat *stat;                                   /**< pointer to statistics                                                  */
-
-       rspamd_mempool_t *server_pool;                                  /**< server's memory pool                                                       */
-       GHashTable *workers;                                        /**< workers pool indexed by pid                    */
-       rspamd_logger_t *logger;
-       uid_t workers_uid;                                          /**< worker's uid running to                        */
-       gid_t workers_gid;                                          /**< worker's gid running to                                                */
-       gboolean is_privilleged;                                    /**< true if run in privilleged mode                */
-       struct roll_history *history;                               /**< rolling history                                                                */
-};
-
-/**
- * Structure to point exception in text from processing
- */
-struct process_exception {
-       gsize pos;
-       gsize len;
-};
-
-/**
- * Control session object
- */
-struct controller_command;
-struct controller_session;
-typedef gboolean (*controller_func_t)(gchar **args,
-       struct controller_session *session);
-
-struct controller_session {
-       struct rspamd_worker *worker;                               /**< pointer to worker structure (controller in fact) */
-       enum {
-               STATE_COMMAND,
-               STATE_HEADER,
-               STATE_LEARN,
-               STATE_LEARN_SPAM_PRE,
-               STATE_LEARN_SPAM,
-               STATE_REPLY,
-               STATE_QUIT,
-               STATE_OTHER,
-               STATE_WAIT,
-               STATE_WEIGHTS
-       } state;                                                    /**< current session state                                                  */
-       gint sock;                                                  /**< socket descriptor                                                              */
-       /* Access to authorized commands */
-       gboolean authorized;                                        /**< whether this session is authorized                             */
-       gboolean restful;                                           /**< whether this session is a restful session              */
-       GHashTable *kwargs;                                         /**< keyword arguments for restful command                  */
-       struct controller_command *cmd;                             /**< real command                                                                   */
-       rspamd_mempool_t *session_pool;                             /**< memory pool for session                        */
-       struct rspamd_config *cfg;                                  /**< pointer to config file                                                 */
-       gchar *learn_rcpt;                                          /**< recipient for learning                                                 */
-       gchar *learn_from;                                          /**< from address for learning                                              */
-       struct rspamd_classifier_config *learn_classifier;
-       gchar *learn_symbol;                                            /**< symbol to train                                                            */
-       double learn_multiplier;                                    /**< multiplier for learning                                                */
-       rspamd_io_dispatcher_t *dispatcher;                         /**< IO dispatcher object                                                   */
-       rspamd_fstring_t *learn_buf;                                         /**< learn input                                                                   */
-       GList *parts;                                               /**< extracted mime parts                                                   */
-       gint in_class;                                              /**< positive or negative learn                                             */
-       gboolean (*other_handler)(struct controller_session *session,
-               rspamd_fstring_t *in);                       /**< other command handler to execute at the end of processing */
-       void *other_data;                                           /**< and its data                                   */
-       controller_func_t custom_handler;                           /**< custom command handler                                                 */
-       struct rspamd_async_session * s;                             /**< async session object                                                  */
-       struct rspamd_task *learn_task;
-       struct rspamd_dns_resolver *resolver;                       /**< DNS resolver                                                                   */
-       struct event_base *ev_base;                                 /**< Event base                                                                             */
-};
-
-
-/**
- * Register custom controller function
- */
-void register_custom_controller_command (const gchar *name,
-       controller_func_t handler,
-       gboolean privilleged,
-       gboolean require_message);
-
-#endif
-
-/*
- * vi:ts=4
- */
index 9c7362b35e20d14beb88238c1e039ae0eaf975bc..b704e9238da5a947be482614bad7ac6e7f7e83a4 100644 (file)
@@ -33,7 +33,7 @@
 
 #include "config.h"
 #include "libmime/message.h"
-#include "main.h"
+#include "rspamd.h"
 
 #define DEFAULT_SYMBOL "R_CHARSET_MIXED"
 #define DEFAULT_THRESHOLD 0.1
index e6c88da52b9c5fb6d03841346f74ac963e35b222..7cf65f2a3d0f865d65ef04feb53ba1792289acc0 100644 (file)
@@ -42,7 +42,7 @@
 #include "libserver/dkim.h"
 #include "libutil/hash.h"
 #include "libutil/map.h"
-#include "main.h"
+#include "rspamd.h"
 #include "utlist.h"
 
 #define DEFAULT_SYMBOL_REJECT "R_DKIM_REJECT"
index 0b5cd97ed89c982d8a2570a570082848ba7f787b..37d5f261e46764f7246e236b683b01c7de1ef700 100644 (file)
@@ -46,7 +46,7 @@
 #include "libserver/worker_util.h"
 #include "fuzzy_storage.h"
 #include "utlist.h"
-#include "main.h"
+#include "rspamd.h"
 #include "blake2.h"
 #include "ottery.h"
 
index 16f941364c530f8674e4de4e9e53e14db71e2720..2fd267aa0d510fd566d62e75090580bb6b1ab2f0 100644 (file)
@@ -33,7 +33,7 @@
 #include "mime_expressions.h"
 #include "libutil/map.h"
 #include "lua/lua_common.h"
-#include "main.h"
+#include "rspamd.h"
 
 struct regexp_module_item {
        struct rspamd_expression *expr;
index 70c298a7da032d1d3c4138cf3d6fe4901c26f4f3..f19d2b50fbef084d084f103e9b6a1f8205122633 100644 (file)
@@ -37,7 +37,7 @@
 #include "libserver/spf.h"
 #include "libutil/hash.h"
 #include "libutil/map.h"
-#include "main.h"
+#include "rspamd.h"
 
 #define DEFAULT_SYMBOL_FAIL "R_SPF_FAIL"
 #define DEFAULT_SYMBOL_SOFTFAIL "R_SPF_SOFTFAIL"
index 8538e57a19e9aa172a0f385fcf1d715bfb94c558..882eed2d4bf1b42eeb5d52098df6f9a65a4ccf93 100644 (file)
@@ -45,7 +45,7 @@
 #include "libmime/message.h"
 #include "libutil/hash.h"
 #include "libutil/map.h"
-#include "main.h"
+#include "rspamd.h"
 #include "surbl.h"
 #include "regexp.h"
 #include "acism.h"
index 76f2bafb9d49879b074853a5dc05bd0fec6865d1..9eab930002966ef5119c98fb5f0620afc227308f 100644 (file)
@@ -3,7 +3,7 @@
 
 #include "config.h"
 #include "acism.h"
-#include "main.h"
+#include "rspamd.h"
 
 #define DEFAULT_REDIRECTOR_PORT 8080
 #define DEFAULT_SURBL_WEIGHT 10
diff --git a/src/rspamd.c b/src/rspamd.c
new file mode 100644 (file)
index 0000000..48874cf
--- /dev/null
@@ -0,0 +1,1418 @@
+/*
+ * Copyright (c) 2009-2012, Vsevolod Stakhov
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *      * Redistributions of source code must retain the above copyright
+ *        notice, this list of conditions and the following disclaimer.
+ *      * Redistributions in binary form must reproduce the above copyright
+ *        notice, this list of conditions and the following disclaimer in the
+ *        documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "rspamd.h"
+#include "libutil/map.h"
+#include "fuzzy_storage.h"
+#include "libserver/symbols_cache.h"
+#include "lua/lua_common.h"
+#include "libserver/worker_util.h"
+#include "ottery.h"
+#include "xxhash.h"
+#include "utlist.h"
+#include "libstat/stat_api.h"
+#include "cryptobox.h"
+#include "regexp.h"
+#ifdef HAVE_OPENSSL
+#include <openssl/rand.h>
+#include <openssl/err.h>
+#include <openssl/evp.h>
+#include <openssl/rsa.h>
+#include <openssl/pem.h>
+#endif
+#ifdef HAVE_LOCALE_H
+#include <locale.h>
+#define HAVE_SETLOCALE 1
+#endif
+
+#define msg_err_main(...) rspamd_default_log_function (G_LOG_LEVEL_CRITICAL, \
+        rspamd_main->server_pool->tag.tagname, rspamd_main->server_pool->tag.uid, \
+        G_STRFUNC, \
+        __VA_ARGS__)
+#define msg_warn_main(...)   rspamd_default_log_function (G_LOG_LEVEL_WARNING, \
+        rspamd_main->server_pool->tag.tagname, rspamd_main->server_pool->tag.uid, \
+        G_STRFUNC, \
+        __VA_ARGS__)
+#define msg_info_main(...)   rspamd_default_log_function (G_LOG_LEVEL_INFO, \
+        rspamd_main->server_pool->tag.tagname, rspamd_main->server_pool->tag.uid, \
+        G_STRFUNC, \
+        __VA_ARGS__)
+#define msg_debug_main(...)  rspamd_default_log_function (G_LOG_LEVEL_DEBUG, \
+        rspamd_main->server_pool->tag.tagname, rspamd_main->server_pool->tag.uid, \
+        G_STRFUNC, \
+        __VA_ARGS__)
+
+/* 2 seconds to fork new process in place of dead one */
+#define SOFT_FORK_TIME 2
+
+/* 10 seconds after getting termination signal to terminate all workers with SIGKILL */
+#define HARD_TERMINATION_TIME 10
+
+static struct rspamd_worker * fork_worker (struct rspamd_main *,
+       struct rspamd_worker_conf *, guint);
+static gboolean load_rspamd_config (struct rspamd_config *cfg,
+       gboolean init_modules);
+
+sig_atomic_t do_restart = 0;
+sig_atomic_t do_reopen_log = 0;
+sig_atomic_t do_terminate = 0;
+sig_atomic_t child_dead = 0;
+sig_atomic_t got_alarm = 0;
+
+#ifdef HAVE_SA_SIGINFO
+GQueue *signals_info = NULL;
+#endif
+
+static gboolean config_test = FALSE;
+static gboolean no_fork = FALSE;
+static gchar **cfg_names = NULL;
+static gchar **lua_tests = NULL;
+static gchar **sign_configs = NULL;
+static gchar *privkey = NULL;
+static gchar *rspamd_user = NULL;
+static gchar *rspamd_group = NULL;
+static gchar *rspamd_pidfile = NULL;
+static gboolean dump_cache = FALSE;
+static gboolean is_debug = FALSE;
+static gboolean is_insecure = FALSE;
+static gboolean gen_keypair = FALSE;
+static gboolean encrypt_password = FALSE;
+/* List of workers that are pending to start */
+static GList *workers_pending = NULL;
+static GHashTable *vars = NULL;
+
+#ifdef HAVE_SA_SIGINFO
+static siginfo_t static_sg[64];
+static sig_atomic_t cur_sg = 0;
+#endif
+
+/* List of unrelated forked processes */
+static GArray *other_workers = NULL;
+
+/* List of active listen sockets indexed by worker type */
+static GHashTable *listen_sockets = NULL;
+
+struct rspamd_main *rspamd_main;
+
+/* Defined in modules.c */
+extern module_t *modules[];
+extern worker_t *workers[];
+
+/* Commandline options */
+static GOptionEntry entries[] =
+{
+       { "config-test", 't', 0, G_OPTION_ARG_NONE, &config_test,
+         "Do config test and exit", NULL },
+       { "no-fork", 'f', 0, G_OPTION_ARG_NONE, &no_fork,
+         "Do not daemonize main process", NULL },
+       { "config", 'c', 0, G_OPTION_ARG_FILENAME_ARRAY, &cfg_names,
+         "Specify config file(s)", NULL },
+       { "user", 'u', 0, G_OPTION_ARG_STRING, &rspamd_user,
+         "User to run rspamd as", NULL },
+       { "group", 'g', 0, G_OPTION_ARG_STRING, &rspamd_group,
+         "Group to run rspamd as", NULL },
+       { "pid", 'p', 0, G_OPTION_ARG_STRING, &rspamd_pidfile, "Path to pidfile",
+         NULL },
+       { "dump-cache", 'C', 0, G_OPTION_ARG_NONE, &dump_cache,
+         "Dump symbols cache stats and exit", NULL },
+       { "debug", 'd', 0, G_OPTION_ARG_NONE, &is_debug, "Force debug output",
+         NULL },
+       { "insecure", 'i', 0, G_OPTION_ARG_NONE, &is_insecure,
+         "Ignore running workers as privileged users (insecure)", NULL },
+       { "test-lua", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &lua_tests,
+         "Specify lua file(s) to test", NULL },
+       { "sign-config", 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &sign_configs,
+         "Specify config file(s) to sign", NULL },
+       { "private-key", 0, 0, G_OPTION_ARG_FILENAME, &privkey,
+         "Specify private key to sign", NULL },
+       { "gen-keypair", 0, 0, G_OPTION_ARG_NONE, &gen_keypair, "Generate new encryption "
+                       "keypair", NULL},
+       { "encrypt-password", 0, 0, G_OPTION_ARG_NONE, &encrypt_password, "Encrypt "
+                       "controller password to store in the configuration file", NULL },
+       { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
+};
+
+extern const struct rspamd_controller_pbkdf pbkdf_list[];
+
+#ifndef HAVE_SA_SIGINFO
+static void
+sig_handler (gint signo)
+#else
+static void
+sig_handler (gint signo, siginfo_t *info, void *unused)
+#endif
+{
+#ifdef HAVE_SA_SIGINFO
+       if (cur_sg < (sig_atomic_t)G_N_ELEMENTS (static_sg)) {
+               memcpy (&static_sg[cur_sg++], info, sizeof (siginfo_t));
+       }
+       /* XXX: discard more than 64 simultaneous signals */
+#endif
+
+       switch (signo) {
+       case SIGHUP:
+               do_restart = 1;
+               break;
+       case SIGINT:
+       case SIGTERM:
+               do_terminate = 1;
+               break;
+       case SIGCHLD:
+               child_dead = 1;
+               break;
+       case SIGUSR1:
+               do_reopen_log = 1;
+               break;
+       case SIGUSR2:
+               /* Do nothing */
+               break;
+       case SIGALRM:
+               got_alarm = 1;
+               break;
+       }
+}
+
+#ifdef HAVE_SA_SIGINFO
+
+static const gchar *
+chldsigcode (gint code) {
+       switch (code) {
+#ifdef CLD_EXITED
+       case CLD_EXITED:
+               return "Child exited normally";
+       case CLD_KILLED:
+               return "Child has terminated abnormally but did not create a core file";
+       case CLD_DUMPED:
+               return "Child has terminated abnormally and created a core file";
+       case CLD_TRAPPED:
+               return "Traced child has trapped";
+#endif
+       default:
+               return "Unknown reason";
+       }
+}
+
+/* Prints info about incoming signals by parsing siginfo structures */
+static void
+print_signals_info (void)
+{
+       siginfo_t *inf;
+
+       while ((inf = g_queue_pop_head (signals_info))) {
+               if (inf->si_signo == SIGCHLD) {
+                       msg_info_main ("got SIGCHLD from child: %P; reason: '%s'",
+                               inf->si_pid, chldsigcode (inf->si_code));
+               }
+               else {
+                       msg_info_main ("got signal: '%s'; received from pid: %P; uid: %ul",
+                               g_strsignal (inf->si_signo), inf->si_pid, (gulong)inf->si_uid);
+               }
+       }
+}
+#endif
+
+
+static void
+read_cmd_line (gint *argc, gchar ***argv, struct rspamd_config *cfg)
+{
+       GError *error = NULL;
+       GOptionContext *context;
+       guint i, cfg_num;
+       pid_t r;
+
+       context = g_option_context_new ("- run rspamd daemon");
+       g_option_context_set_summary (context,
+               "Summary:\n  Rspamd daemon version " RVERSION "\n  Release id: " RID);
+       g_option_context_add_main_entries (context, entries, NULL);
+
+       if (!g_option_context_parse (context, argc, argv, &error)) {
+               fprintf (stderr, "option parsing failed: %s\n", error->message);
+               exit (1);
+       }
+
+       cfg->no_fork = no_fork;
+       cfg->config_test = config_test;
+       cfg->rspamd_user = rspamd_user;
+       cfg->rspamd_group = rspamd_group;
+       cfg_num = cfg_names != NULL ? g_strv_length (cfg_names) : 0;
+       if (cfg_num == 0) {
+               cfg->cfg_name = FIXED_CONFIG_FILE;
+       }
+       else {
+               cfg->cfg_name = cfg_names[0];
+       }
+       for (i = 1; i < cfg_num; i++) {
+               r = fork ();
+               if (r == 0) {
+                       /* Spawning new main process */
+                       ottery_init (NULL);
+                       cfg->cfg_name = cfg_names[i];
+                       (void)setsid ();
+               }
+               else if (r == -1) {
+                       fprintf (stderr,
+                               "fork failed while spawning process for %s configuration file: %s\n",
+                               cfg_names[i],
+                               strerror (errno));
+               }
+               else {
+                       /* Save pid to the list of other main processes, we need it to ignore SIGCHLD from them */
+                       g_array_append_val (other_workers, r);
+               }
+       }
+       cfg->pid_file = rspamd_pidfile;
+}
+
+/* Detect privilleged mode */
+static void
+detect_priv (struct rspamd_main *rspamd)
+{
+       struct passwd *pwd;
+       struct group *grp;
+       uid_t euid;
+
+       euid = geteuid ();
+
+       if (euid == 0) {
+               if (!rspamd->cfg->rspamd_user && !is_insecure) {
+                       msg_err_main (
+                               "cannot run rspamd workers as root user, please add -u and -g options to select a proper unprivilleged user or specify --insecure flag");
+                       exit (EXIT_FAILURE);
+               }
+               else if (is_insecure) {
+                       rspamd->is_privilleged = TRUE;
+                       rspamd->workers_uid = 0;
+                       rspamd->workers_gid = 0;
+               }
+               else {
+                       rspamd->is_privilleged = TRUE;
+                       pwd = getpwnam (rspamd->cfg->rspamd_user);
+                       if (pwd == NULL) {
+                               msg_err_main ("user specified does not exists (%s), aborting",
+                                       strerror (errno));
+                               exit (-errno);
+                       }
+                       if (rspamd->cfg->rspamd_group) {
+                               grp = getgrnam (rspamd->cfg->rspamd_group);
+                               if (grp == NULL) {
+                                       msg_err_main ("group specified does not exists (%s), aborting",
+                                               strerror (errno));
+                                       exit (-errno);
+                               }
+                               rspamd->workers_gid = grp->gr_gid;
+                       }
+                       else {
+                               rspamd->workers_gid = -1;
+                       }
+                       rspamd->workers_uid = pwd->pw_uid;
+               }
+       }
+       else {
+               rspamd->is_privilleged = FALSE;
+               rspamd->workers_uid = -1;
+               rspamd->workers_gid = -1;
+       }
+}
+
+static void
+drop_priv (struct rspamd_main *rspamd)
+{
+       if (rspamd->is_privilleged) {
+               if (setgid (rspamd->workers_gid) == -1) {
+                       msg_err_main ("cannot setgid to %d (%s), aborting",
+                               (gint)rspamd->workers_gid,
+                               strerror (errno));
+                       exit (-errno);
+               }
+               if (rspamd->cfg->rspamd_user &&
+                       initgroups (rspamd->cfg->rspamd_user, rspamd->workers_gid) == -1) {
+                       msg_err_main ("initgroups failed (%s), aborting", strerror (errno));
+                       exit (-errno);
+               }
+               if (setuid (rspamd->workers_uid) == -1) {
+                       msg_err_main ("cannot setuid to %d (%s), aborting",
+                               (gint)rspamd->workers_uid,
+                               strerror (errno));
+                       exit (-errno);
+               }
+       }
+}
+
+static void
+config_logger (rspamd_mempool_t *pool, gpointer ud)
+{
+       struct rspamd_main *rm = ud;
+
+       if (config_test) {
+               /* Explicitly set logger type to console in case of config testing */
+               rm->cfg->log_type = RSPAMD_LOG_CONSOLE;
+       }
+
+       rspamd_set_logger (rm->cfg, g_quark_try_string ("main"), rm);
+       if (rspamd_log_open_priv (rm->logger, rm->workers_uid, rm->workers_gid) == -1) {
+               fprintf (stderr, "Fatal error, cannot open logfile, exiting\n");
+               exit (EXIT_FAILURE);
+       }
+}
+
+static void
+reread_config (struct rspamd_main *rspamd)
+{
+       struct rspamd_config *tmp_cfg;
+       gchar *cfg_file;
+
+       tmp_cfg = (struct rspamd_config *)g_malloc0 (sizeof (struct rspamd_config));
+       tmp_cfg->c_modules = g_hash_table_ref (rspamd->cfg->c_modules);
+       rspamd_set_logger (tmp_cfg,  g_quark_try_string ("main"), rspamd);
+       rspamd_init_cfg (tmp_cfg, TRUE);
+       cfg_file = rspamd_mempool_strdup (tmp_cfg->cfg_pool,
+                       rspamd->cfg->cfg_name);
+       tmp_cfg->cache = rspamd_symbols_cache_new (tmp_cfg);
+       /* Save some variables */
+       tmp_cfg->cfg_name = cfg_file;
+
+       if (!load_rspamd_config (tmp_cfg, FALSE)) {
+               rspamd_set_logger (rspamd_main->cfg, g_quark_try_string (
+                               "main"), rspamd_main);
+               msg_err_main ("cannot parse new config file, revert to old one");
+               rspamd_config_free (tmp_cfg);
+       }
+       else {
+               msg_debug_main ("replacing config");
+               rspamd_symbols_cache_destroy (rspamd_main->cfg->cache);
+               rspamd_config_free (rspamd->cfg);
+               g_free (rspamd->cfg);
+
+               rspamd->cfg = tmp_cfg;
+               rspamd_set_logger (tmp_cfg,  g_quark_try_string ("main"), rspamd);
+               /* Force debug log */
+               if (is_debug) {
+                       rspamd->cfg->log_level = G_LOG_LEVEL_DEBUG;
+               }
+
+               rspamd_init_filters (rspamd->cfg, TRUE);
+               rspamd_symbols_cache_init (rspamd->cfg->cache);
+               msg_info_main ("config has been reread successfully");
+       }
+}
+
+static void
+set_worker_limits (struct rspamd_worker_conf *cf)
+{
+       struct rlimit rlmt;
+
+       if (cf->rlimit_nofile != 0) {
+               rlmt.rlim_cur = (rlim_t) cf->rlimit_nofile;
+               rlmt.rlim_max = (rlim_t) cf->rlimit_nofile;
+
+               if (setrlimit (RLIMIT_NOFILE, &rlmt) == -1) {
+                       msg_warn_main ("cannot set files rlimit: %d, %s",
+                               cf->rlimit_nofile,
+                               strerror (errno));
+               }
+       }
+
+       if (cf->rlimit_maxcore != 0) {
+               rlmt.rlim_cur = (rlim_t) cf->rlimit_maxcore;
+               rlmt.rlim_max = (rlim_t) cf->rlimit_maxcore;
+
+               if (setrlimit (RLIMIT_CORE, &rlmt) == -1) {
+                       msg_warn_main ("cannot set max core rlimit: %d, %s",
+                               cf->rlimit_maxcore,
+                               strerror (errno));
+               }
+       }
+}
+
+static struct rspamd_worker *
+fork_worker (struct rspamd_main *rspamd, struct rspamd_worker_conf *cf,
+               guint index)
+{
+       struct rspamd_worker *cur;
+       /* Starting worker process */
+       cur = (struct rspamd_worker *)g_malloc (sizeof (struct rspamd_worker));
+       if (cur) {
+               bzero (cur, sizeof (struct rspamd_worker));
+               cur->srv = rspamd;
+               cur->type = cf->type;
+               cur->pid = fork ();
+               cur->cf = g_malloc (sizeof (struct rspamd_worker_conf));
+               memcpy (cur->cf, cf, sizeof (struct rspamd_worker_conf));
+               cur->index = index;
+               cur->ctx = cf->ctx;
+               switch (cur->pid) {
+               case 0:
+                       /* Update pid for logging */
+                       rspamd_log_update_pid (cf->type, rspamd->logger);
+                       /* Lock statfile pool if possible XXX */
+                       /* Init PRNG after fork */
+                       ottery_init (NULL);
+                       g_random_set_seed (ottery_rand_uint32 ());
+                       /* Drop privilleges */
+                       drop_priv (rspamd);
+                       /* Set limits */
+                       set_worker_limits (cf);
+                       setproctitle ("%s process", cf->worker->name);
+                       rspamd_pidfile_close (rspamd->pfh);
+                       /* Do silent log reopen to avoid collisions */
+                       rspamd_log_close (rspamd->logger);
+                       rspamd_log_open (rspamd->logger);
+#if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30))
+# if (GLIB_MINOR_VERSION > 20)
+                       /* Ugly hack for old glib */
+                       if (!g_thread_get_initialized ()) {
+                               g_thread_init (NULL);
+                       }
+# else
+                       g_thread_init (NULL);
+# endif
+#endif
+                       msg_info_main ("starting %s process %P", cf->worker->name, getpid ());
+                       cf->worker->worker_start_func (cur);
+                       break;
+               case -1:
+                       msg_err_main ("cannot fork main process. %s", strerror (errno));
+                       rspamd_pidfile_remove (rspamd->pfh);
+                       exit (-errno);
+                       break;
+               default:
+                       /* Insert worker into worker's table, pid is index */
+                       g_hash_table_insert (rspamd->workers, GSIZE_TO_POINTER (
+                                       cur->pid), cur);
+                       break;
+               }
+       }
+
+       return cur;
+}
+
+static void
+set_alarm (guint seconds)
+{
+#ifdef HAVE_SETITIMER
+       static struct itimerval itv;
+
+       itv.it_interval.tv_sec = 0;
+       itv.it_interval.tv_usec = 0;
+       itv.it_value.tv_sec = seconds;
+       itv.it_value.tv_usec = 0;
+
+       if (setitimer (ITIMER_REAL, &itv, NULL) == -1) {
+               msg_err_main ("set alarm failed: %s", strerror (errno));
+       }
+#else
+       (void)alarm (seconds);
+#endif
+}
+
+struct waiting_worker {
+       struct rspamd_worker_conf *cf;
+       guint oldindex;
+};
+
+static void
+delay_fork (struct rspamd_worker_conf *cf, guint index)
+{
+       struct waiting_worker *nw;
+
+       nw = g_slice_alloc (sizeof (*nw));
+       nw->cf = cf;
+       nw->oldindex = index;
+
+       workers_pending = g_list_prepend (workers_pending, nw);
+       set_alarm (SOFT_FORK_TIME);
+}
+
+static GList *
+create_listen_socket (GPtrArray *addrs, guint cnt, gint listen_type)
+{
+       GList *result = NULL;
+       gint fd;
+       guint i;
+
+       g_ptr_array_sort (addrs, rspamd_inet_address_compare_ptr);
+       for (i = 0; i < cnt; i ++) {
+               fd = rspamd_inet_address_listen (g_ptr_array_index (addrs, i),
+                               listen_type, TRUE);
+               if (fd != -1) {
+                       result = g_list_prepend (result, GINT_TO_POINTER (fd));
+               }
+       }
+
+       return result;
+}
+
+static GList *
+systemd_get_socket (gint number)
+{
+       int sock, num_passed, flags;
+       GList *result = NULL;
+       const gchar *e;
+       gchar *err;
+       struct stat st;
+       /* XXX: can we trust the current choice ? */
+       static const int sd_listen_fds_start = 3;
+
+       e = getenv ("LISTEN_FDS");
+       if (e != NULL) {
+               errno = 0;
+               num_passed = strtoul (e, &err, 10);
+               if ((err == NULL || *err == '\0') && num_passed > number) {
+                       sock = number + sd_listen_fds_start;
+                       if (fstat (sock, &st) == -1) {
+                               msg_warn_main ("cannot stat systemd descriptor %d", sock);
+                               return NULL;
+                       }
+                       if (!S_ISSOCK (st.st_mode)) {
+                               msg_warn_main ("systemd descriptor %d is not a socket", sock);
+                               errno = EINVAL;
+                               return NULL;
+                       }
+                       flags = fcntl (sock, F_GETFD);
+                       if (flags != -1) {
+                               (void)fcntl (sock, F_SETFD, flags | FD_CLOEXEC);
+                       }
+                       result = g_list_prepend (result, GINT_TO_POINTER (sock));
+               }
+               else if (num_passed <= number) {
+                       msg_warn_main ("systemd LISTEN_FDS does not contain the expected fd: %d",
+                                       num_passed);
+                       errno = EOVERFLOW;
+               }
+       }
+       else {
+               msg_warn_main ("cannot get systemd variable 'LISTEN_FDS'");
+               errno = ENOENT;
+       }
+
+       return result;
+}
+
+static void
+fork_delayed (struct rspamd_main *rspamd)
+{
+       GList *cur;
+       struct waiting_worker *w;
+
+       while (workers_pending != NULL) {
+               cur = workers_pending;
+               w = cur->data;
+
+               workers_pending = g_list_remove_link (workers_pending, cur);
+               fork_worker (rspamd, w->cf, w->oldindex);
+               g_list_free_1 (cur);
+               g_slice_free1 (sizeof (*w), w);
+       }
+}
+
+static inline uintptr_t
+make_listen_key (struct rspamd_worker_bind_conf *cf)
+{
+       XXH64_state_t st;
+       guint i, keylen;
+       guint8 *key;
+       rspamd_inet_addr_t *addr;
+       guint16 port;
+
+       XXH64_reset (&st, rspamd_hash_seed ());
+       if (cf->is_systemd) {
+               XXH64_update (&st, "systemd", sizeof ("systemd"));
+               XXH64_update (&st, &cf->cnt, sizeof (cf->cnt));
+       }
+       else {
+               XXH64_update (&st, cf->name, strlen (cf->name));
+               for (i = 0; i < cf->cnt; i ++) {
+                       addr = g_ptr_array_index (cf->addrs, i);
+                       key = rspamd_inet_address_get_radix_key (
+                                       addr, &keylen);
+                       XXH64_update (&st, key, keylen);
+                       port = rspamd_inet_address_get_port (addr);
+                       XXH64_update (&st, &port, sizeof (port));
+               }
+       }
+
+       return XXH64_digest (&st);
+}
+
+static void
+spawn_workers (struct rspamd_main *rspamd)
+{
+       GList *cur, *ls;
+       struct rspamd_worker_conf *cf;
+       gint i;
+       gpointer p;
+       guintptr key;
+       struct rspamd_worker_bind_conf *bcf;
+       gboolean listen_ok = FALSE;
+
+       cur = rspamd->cfg->workers;
+
+       while (cur) {
+               cf = cur->data;
+               listen_ok = FALSE;
+
+               if (cf->worker == NULL) {
+                       msg_err_main ("type of worker is unspecified, skip spawning");
+               }
+               else {
+                       if (cf->worker->has_socket) {
+                               LL_FOREACH (cf->bind_conf, bcf) {
+                                       key = make_listen_key (bcf);
+                                       if ((p =
+                                               g_hash_table_lookup (listen_sockets,
+                                               GINT_TO_POINTER (key))) == NULL) {
+                                               if (!bcf->is_systemd) {
+                                                       /* Create listen socket */
+                                                       ls = create_listen_socket (bcf->addrs, bcf->cnt,
+                                                                       cf->worker->listen_type);
+                                               }
+                                               else {
+                                                       ls = systemd_get_socket (bcf->cnt);
+                                               }
+                                               if (ls == NULL) {
+                                                       msg_err_main ("cannot listen on socket %s: %s",
+                                                               bcf->name,
+                                                               strerror (errno));
+                                               }
+                                               else {
+                                                       g_hash_table_insert (listen_sockets, (gpointer)key, ls);
+                                                       listen_ok = TRUE;
+                                               }
+                                       }
+                                       else {
+                                               /* We had socket for this type of worker */
+                                               ls = p;
+                                               listen_ok = TRUE;
+                                       }
+                                       /* Do not add existing lists as it causes loops */
+                                       if (g_list_position (cf->listen_socks, ls) == -1) {
+                                               cf->listen_socks = g_list_concat (cf->listen_socks, ls);
+                                       }
+                               }
+                       }
+
+                       if (listen_ok) {
+                               if (cf->worker->unique) {
+                                       if (cf->count > 1) {
+                                               msg_warn_main ("cannot spawn more than 1 %s worker, so spawn one",
+                                                               cf->worker->name);
+                                       }
+                                       fork_worker (rspamd, cf, 0);
+                               }
+                               else if (cf->worker->threaded) {
+                                       fork_worker (rspamd, cf, 0);
+                               }
+                               else {
+                                       for (i = 0; i < cf->count; i++) {
+                                               fork_worker (rspamd, cf, i);
+                                       }
+                               }
+                       }
+                       else {
+                               msg_err_main ("cannot create listen socket for %s at %s",
+                                               g_quark_to_string (cf->type), cf->bind_conf->name);
+
+                               exit (EXIT_FAILURE);
+                       }
+               }
+
+               cur = g_list_next (cur);
+       }
+}
+
+static void
+kill_old_workers (gpointer key, gpointer value, gpointer unused)
+{
+       struct rspamd_worker *w = value;
+
+       kill (w->pid, SIGUSR2);
+       msg_info_main ("send signal to worker %P", w->pid);
+}
+
+static gboolean
+wait_for_workers (gpointer key, gpointer value, gpointer unused)
+{
+       struct rspamd_worker *w = value;
+       gint res = 0;
+
+       if (got_alarm) {
+               got_alarm = 0;
+               /* Set alarm for hard termination but with less time */
+               set_alarm (HARD_TERMINATION_TIME / 10);
+       }
+
+       if (waitpid (w->pid, &res, 0) == -1) {
+               if (errno == EINTR) {
+                       got_alarm = 1;
+                       if (w->cf->worker->killable) {
+                               msg_info_main ("terminate worker %P with SIGKILL", w->pid);
+                               kill (w->pid, SIGKILL);
+                       }
+                       else {
+                               msg_info_main ("waiting for workers to sync");
+                               wait_for_workers (key, value, unused);
+                               return TRUE;
+                       }
+               }
+       }
+
+       msg_info_main ("%s process %P terminated %s", g_quark_to_string (
+                       w->type), w->pid,
+               got_alarm ? "hardly" : "softly");
+       g_free (w->cf);
+       g_free (w);
+
+       return TRUE;
+}
+
+static void
+reopen_log_handler (gpointer key, gpointer value, gpointer unused)
+{
+       struct rspamd_worker *w = value;
+
+       if (kill (w->pid, SIGUSR1) == -1) {
+               msg_err_main ("kill failed for pid %P: %s", w->pid, strerror (errno));
+       }
+}
+
+static gboolean
+load_rspamd_config (struct rspamd_config *cfg, gboolean init_modules)
+{
+       cfg->cache = rspamd_symbols_cache_new (cfg);
+       cfg->compiled_modules = modules;
+       cfg->compiled_workers = workers;
+
+       if (!rspamd_config_read (cfg, cfg->cfg_name, NULL,
+               config_logger, rspamd_main, vars)) {
+               return FALSE;
+       }
+
+       /* Strictly set temp dir */
+       if (!cfg->temp_dir) {
+               msg_warn_main ("tempdir is not set, trying to use $TMPDIR");
+               cfg->temp_dir =
+                       rspamd_mempool_strdup (cfg->cfg_pool, getenv ("TMPDIR"));
+
+               if (!cfg->temp_dir) {
+                       msg_warn_main ("$TMPDIR is empty too, using /tmp as default");
+                       cfg->temp_dir = rspamd_mempool_strdup (cfg->cfg_pool, "/tmp");
+               }
+       }
+
+       /* Do post-load actions */
+       rspamd_config_post_load (cfg);
+
+       if (init_modules) {
+               rspamd_init_filters (cfg, FALSE);
+       }
+
+       return TRUE;
+}
+
+static gint
+perform_lua_tests (struct rspamd_config *cfg)
+{
+       gint i, tests_num, res = EXIT_SUCCESS;
+       gchar *cur_script;
+       lua_State *L = cfg->lua_state;
+
+       tests_num = g_strv_length (lua_tests);
+
+       for (i = 0; i < tests_num; i++) {
+
+               if (luaL_loadfile (L, lua_tests[i]) != 0) {
+                       msg_err_main ("load of %s failed: %s", lua_tests[i],
+                               lua_tostring (L, -1));
+                       res = EXIT_FAILURE;
+                       continue;
+               }
+
+               cur_script = g_strdup (lua_tests[i]);
+               lua_pushstring (L, cur_script);
+               lua_setglobal (L, "test_script");
+               lua_pushstring (L, dirname (cur_script));
+               lua_setglobal (L, "test_dir");
+               g_free (cur_script);
+
+               /* do the call (0 arguments, N result) */
+               if (lua_pcall (L, 0, LUA_MULTRET, 0) != 0) {
+                       msg_info_main ("init of %s failed: %s", lua_tests[i], lua_tostring (L,
+                               -1));
+                       res = EXIT_FAILURE;
+                       continue;
+               }
+               if (lua_gettop (L) != 0) {
+                       if (lua_tonumber (L, -1) == -1) {
+                               msg_info_main ("%s returned -1 that indicates configuration error",
+                                       lua_tests[i]);
+                               res = EXIT_FAILURE;
+                               continue;
+                       }
+                       lua_pop (L, lua_gettop (L));
+               }
+       }
+
+       return res;
+}
+
+static gint
+perform_configs_sign (void)
+{
+#ifndef HAVE_OPENSSL
+       msg_err_main ("cannot sign files without openssl support");
+       return EXIT_FAILURE;
+#else
+# if (OPENSSL_VERSION_NUMBER < 0x10000000L)
+       msg_err_main ("must have openssl at least 1.0.0 to perform this action");
+       return EXIT_FAILURE;
+# else
+       gint i, tests_num, res = EXIT_SUCCESS, fd;
+       guint diglen;
+       gchar *cur_file, in_file[PATH_MAX],
+               out_file[PATH_MAX], dig[EVP_MAX_MD_SIZE];
+       gsize siglen;
+       struct stat st;
+       gpointer map, sig;
+       EVP_PKEY *key = NULL;
+       BIO *fbio;
+       EVP_PKEY_CTX *key_ctx = NULL;
+       EVP_MD_CTX *sign_ctx = NULL;
+
+       /* Load private key */
+       fbio = BIO_new_file (privkey, "r");
+       if (fbio == NULL) {
+               msg_err_main ("cannot open private key %s, %s", privkey,
+                       ERR_error_string (ERR_get_error (), NULL));
+               return ERR_get_error ();
+       }
+       if (!PEM_read_bio_PrivateKey (fbio, &key, rspamd_read_passphrase, NULL)) {
+               msg_err_main ("cannot read private key %s, %s", privkey,
+                       ERR_error_string (ERR_get_error (), NULL));
+               return ERR_get_error ();
+       }
+
+       key_ctx = EVP_PKEY_CTX_new (key, NULL);
+       if (key_ctx == NULL) {
+               msg_err_main ("cannot parse private key %s, %s", privkey,
+                       ERR_error_string (ERR_get_error (), NULL));
+               return ERR_get_error ();
+       }
+
+       if (EVP_PKEY_sign_init (key_ctx) <= 0) {
+               msg_err_main ("cannot parse private key %s, %s", privkey,
+                       ERR_error_string (ERR_get_error (), NULL));
+               return ERR_get_error ();
+       }
+       if (EVP_PKEY_CTX_set_rsa_padding (key_ctx, RSA_PKCS1_PADDING) <= 0) {
+               msg_err_main ("cannot init private key %s, %s", privkey,
+                       ERR_error_string (ERR_get_error (), NULL));
+               return ERR_get_error ();
+       }
+       if (EVP_PKEY_CTX_set_signature_md (key_ctx, EVP_sha256 ()) <= 0) {
+               msg_err_main ("cannot init signature private key %s, %s", privkey,
+                       ERR_error_string (ERR_get_error (), NULL));
+               return ERR_get_error ();
+       }
+
+       sign_ctx = EVP_MD_CTX_create ();
+
+       tests_num = g_strv_length (sign_configs);
+
+       for (i = 0; i < tests_num; i++) {
+               cur_file = sign_configs[i];
+               if (realpath (cur_file, in_file) == NULL) {
+                       msg_err_main ("cannot resolve %s: %s", cur_file, strerror (errno));
+                       continue;
+               }
+               if (stat (in_file, &st) == -1) {
+                       msg_err_main ("cannot stat %s: %s", in_file, strerror (errno));
+                       continue;
+               }
+               if ((fd = open (in_file, O_RDONLY)) == -1) {
+                       msg_err_main ("cannot open %s: %s", in_file, strerror (errno));
+                       continue;
+               }
+
+               if ((map =
+                       mmap (NULL, st.st_size, PROT_READ, MAP_SHARED, fd,
+                       0)) == MAP_FAILED) {
+                       close (fd);
+                       msg_err_main ("cannot mmap %s: %s", in_file, strerror (errno));
+                       continue;
+               }
+
+               close (fd);
+               /* Now try to sign */
+               EVP_DigestInit (sign_ctx, EVP_sha256 ());
+               EVP_DigestUpdate (sign_ctx, map, st.st_size);
+               EVP_DigestFinal (sign_ctx, dig, &diglen);
+
+               munmap (map, st.st_size);
+
+               if (EVP_PKEY_sign (key_ctx, NULL, &siglen, dig, diglen) <= 0) {
+                       msg_err_main ("cannot sign %s using private key %s, %s",
+                               in_file,
+                               privkey,
+                               ERR_error_string (ERR_get_error (), NULL));
+                       continue;
+               }
+
+               sig = OPENSSL_malloc (siglen);
+               if (EVP_PKEY_sign (key_ctx, sig, &siglen, dig, diglen) <= 0) {
+                       msg_err_main ("cannot sign %s using private key %s, %s",
+                               in_file,
+                               privkey,
+                               ERR_error_string (ERR_get_error (), NULL));
+                       OPENSSL_free (sig);
+                       continue;
+               }
+
+               rspamd_snprintf (out_file, sizeof (out_file), "%s.sig", in_file);
+               fd = open (out_file, O_WRONLY | O_CREAT | O_TRUNC, 00644);
+               if (fd == -1) {
+                       msg_err_main ("cannot open output file %s: %s", out_file, strerror (
+                                       errno));
+                       OPENSSL_free (sig);
+                       continue;
+               }
+               if (write (fd, sig, siglen) == -1) {
+                       msg_err_main ("cannot write to output file %s: %s", out_file,
+                               strerror (errno));
+               }
+               OPENSSL_free (sig);
+               close (fd);
+       }
+
+       /* Cleanup */
+       EVP_MD_CTX_destroy (sign_ctx);
+       EVP_PKEY_CTX_free (key_ctx);
+       EVP_PKEY_free (key);
+       BIO_free (fbio);
+
+       return res;
+# endif
+#endif
+}
+
+static void
+do_encrypt_password (void)
+{
+       const struct rspamd_controller_pbkdf *pbkdf;
+       guchar *salt, *key;
+       gchar *encoded_salt, *encoded_key;
+       gchar password[BUFSIZ];
+       gsize plen;
+
+       pbkdf = &pbkdf_list[0];
+       g_assert (pbkdf != NULL);
+
+       plen = rspamd_read_passphrase (password, sizeof (password), 0, NULL);
+
+       if (plen == 0) {
+               fprintf (stderr, "Invalid password\n");
+               exit (EXIT_FAILURE);
+       }
+
+       salt = g_alloca (pbkdf->salt_len);
+       key = g_alloca (pbkdf->key_len);
+       ottery_rand_bytes (salt, pbkdf->salt_len);
+       /* Derive key */
+       rspamd_cryptobox_pbkdf (password, strlen (password),
+                       salt, pbkdf->salt_len, key, pbkdf->key_len, pbkdf->rounds);
+
+       encoded_salt = rspamd_encode_base32 (salt, pbkdf->salt_len);
+       encoded_key = rspamd_encode_base32 (key, pbkdf->key_len);
+
+       rspamd_printf ("$%d$%s$%s\n", pbkdf->id, encoded_salt,
+                       encoded_key);
+
+       g_free (encoded_salt);
+       g_free (encoded_key);
+       rspamd_explicit_memzero (password, sizeof (password));
+}
+
+static void
+rspamd_init_main (struct rspamd_main *rspamd)
+{
+       rspamd->server_pool = rspamd_mempool_new (rspamd_mempool_suggest_size (),
+                       "main");
+       rspamd_main->stat = rspamd_mempool_alloc0_shared (rspamd_main->server_pool,
+               sizeof (struct rspamd_stat));
+       /* Create rolling history */
+       rspamd_main->history = rspamd_roll_history_new (rspamd_main->server_pool);
+}
+
+gint
+main (gint argc, gchar **argv, gchar **env)
+{
+       gint res = 0, i;
+       struct sigaction signals;
+       struct rspamd_worker *cur;
+       pid_t wrk;
+       worker_t **pworker;
+       GQuark type;
+       gpointer keypair;
+       GString *keypair_out;
+
+#ifdef HAVE_SA_SIGINFO
+       signals_info = g_queue_new ();
+#endif
+#if ((GLIB_MAJOR_VERSION == 2) && (GLIB_MINOR_VERSION <= 30))
+       g_thread_init (NULL);
+#endif
+       rspamd_main = (struct rspamd_main *)g_malloc0 (sizeof (struct rspamd_main));
+
+       rspamd_main->cfg =
+               (struct rspamd_config *)g_malloc0 (sizeof (struct rspamd_config));
+
+       if (!rspamd_main || !rspamd_main->cfg) {
+               fprintf (stderr, "Cannot allocate memory\n");
+               exit (-errno);
+       }
+
+#ifndef HAVE_SETPROCTITLE
+       init_title (argc, argv, env);
+#endif
+
+       rspamd_init_libs ();
+       rspamd_init_main (rspamd_main);
+       rspamd_init_cfg (rspamd_main->cfg, TRUE);
+
+       memset (&signals, 0, sizeof (struct sigaction));
+
+       other_workers = g_array_new (FALSE, TRUE, sizeof (pid_t));
+
+       read_cmd_line (&argc, &argv, rspamd_main->cfg);
+
+       if (argc > 0) {
+               /* Parse variables */
+               for (i = 0; i < argc; i ++) {
+                       if (strchr (argv[i], '=') != NULL) {
+                               gchar *k, *v, *t;
+
+                               k = g_strdup (argv[i]);
+                               t = strchr (k, '=');
+                               v = g_strdup (t + 1);
+                               *t = '\0';
+
+                               if (vars == NULL) {
+                                       vars = g_hash_table_new_full (rspamd_strcase_hash,
+                                                       rspamd_strcase_equal, g_free, g_free);
+                               }
+
+                               g_hash_table_insert (vars, k, v);
+                       }
+               }
+       }
+
+       if (rspamd_main->cfg->config_test || is_debug) {
+               rspamd_main->cfg->log_level = G_LOG_LEVEL_DEBUG;
+       }
+       else {
+               rspamd_main->cfg->log_level = G_LOG_LEVEL_WARNING;
+       }
+
+       type = g_quark_from_static_string ("main");
+
+       /* First set logger to console logger */
+       rspamd_main->cfg->log_type = RSPAMD_LOG_CONSOLE;
+       rspamd_set_logger (rspamd_main->cfg, type, rspamd_main);
+       (void)rspamd_log_open (rspamd_main->logger);
+       g_log_set_default_handler (rspamd_glib_log_function, rspamd_main->logger);
+       g_set_printerr_handler (rspamd_glib_printerr_function);
+
+       detect_priv (rspamd_main);
+
+       pworker = &workers[0];
+       while (*pworker) {
+               /* Init string quarks */
+               (void)g_quark_from_static_string ((*pworker)->name);
+               pworker++;
+       }
+
+       /* Init listen sockets hash */
+       listen_sockets = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+       /* If we want to test lua skip everything except it */
+       if (lua_tests != NULL && lua_tests[0] != NULL) {
+               exit (perform_lua_tests (rspamd_main->cfg));
+       }
+
+       /* If we want to sign configs, just do it */
+       if (sign_configs != NULL && privkey != NULL) {
+               exit (perform_configs_sign ());
+       }
+
+       /* Same for keypair creation */
+       if (gen_keypair) {
+               keypair = rspamd_http_connection_gen_key ();
+               if (keypair == NULL) {
+                       exit (EXIT_FAILURE);
+               }
+               keypair_out = rspamd_http_connection_print_key (keypair,
+                               RSPAMD_KEYPAIR_PUBKEY|RSPAMD_KEYPAIR_PRIVKEY|RSPAMD_KEYPAIR_ID|
+                               RSPAMD_KEYPAIR_BASE32|RSPAMD_KEYPAIR_HUMAN);
+               rspamd_printf ("%V", keypair_out);
+               exit (EXIT_SUCCESS);
+       }
+
+       if (encrypt_password) {
+               do_encrypt_password ();
+               exit (EXIT_SUCCESS);
+       }
+
+       if (rspamd_main->cfg->config_test || dump_cache) {
+               if (!load_rspamd_config (rspamd_main->cfg, FALSE)) {
+                       exit (EXIT_FAILURE);
+               }
+
+               res = TRUE;
+
+               rspamd_symbols_cache_init (rspamd_main->cfg->cache);
+
+               if (!rspamd_init_filters (rspamd_main->cfg, FALSE)) {
+                       res = FALSE;
+               }
+
+               /* Insert classifiers symbols */
+               (void)rspamd_config_insert_classify_symbols (rspamd_main->cfg);
+
+               if (!rspamd_symbols_cache_validate (rspamd_main->cfg->cache, rspamd_main->cfg,
+                       FALSE)) {
+                       res = FALSE;
+               }
+               if (dump_cache) {
+                       msg_err_main ("Use rspamc counters for dumping cache");
+                       exit (EXIT_FAILURE);
+               }
+               fprintf (stderr, "syntax %s\n", res ? "OK" : "BAD");
+               return res ? EXIT_SUCCESS : EXIT_FAILURE;
+       }
+
+       /* Load config */
+       if (!load_rspamd_config (rspamd_main->cfg, TRUE)) {
+               exit (EXIT_FAILURE);
+       }
+
+       /* Override pidfile from configuration by command line argument */
+       if (rspamd_pidfile != NULL) {
+               rspamd_main->cfg->pid_file = rspamd_pidfile;
+       }
+
+       /* Force debug log */
+       if (is_debug) {
+               rspamd_main->cfg->log_level = G_LOG_LEVEL_DEBUG;
+       }
+
+       gperf_profiler_init (rspamd_main->cfg, "main");
+
+       msg_info_main ("rspamd " RVERSION " is starting, build id: " RID);
+       rspamd_main->cfg->cfg_name = rspamd_mempool_strdup (
+               rspamd_main->cfg->cfg_pool,
+               rspamd_main->cfg->cfg_name);
+
+       /* Daemonize */
+       if (!rspamd_main->cfg->no_fork && daemon (0, 0) == -1) {
+               fprintf (stderr, "Cannot daemonize\n");
+               exit (-errno);
+       }
+
+       /* Write info */
+       rspamd_main->pid = getpid ();
+       rspamd_main->type = type;
+
+       rspamd_signals_init (&signals, sig_handler);
+
+       if (rspamd_main->cfg->pid_file == NULL) {
+               msg_info("pid file is not specified, skipping writing it");
+       } else if (rspamd_write_pid (rspamd_main) == -1) {
+               msg_err_main ("cannot write pid file %s", rspamd_main->cfg->pid_file);
+               exit (-errno);
+       }
+
+       /* Block signals to use sigsuspend in future */
+       sigprocmask (SIG_BLOCK, &signals.sa_mask, NULL);
+
+       setproctitle ("main process");
+
+       /* Init config cache */
+       rspamd_symbols_cache_init (rspamd_main->cfg->cache);
+
+       /* Validate cache */
+       (void)rspamd_symbols_cache_validate (rspamd_main->cfg->cache, rspamd_main->cfg, FALSE);
+
+       /* Flush log */
+       rspamd_log_flush (rspamd_main->logger);
+
+       /* Maybe read roll history */
+       if (rspamd_main->cfg->history_file) {
+               rspamd_roll_history_load (rspamd_main->history,
+                       rspamd_main->cfg->history_file);
+       }
+
+#if defined(WITH_GPERF_TOOLS)
+       ProfilerStop ();
+#endif
+       /* Spawn workers */
+       rspamd_main->workers = g_hash_table_new (g_direct_hash, g_direct_equal);
+       spawn_workers (rspamd_main);
+
+       /* Signal processing cycle */
+       for (;; ) {
+               msg_debug_main ("calling sigsuspend");
+               sigemptyset (&signals.sa_mask);
+               sigsuspend (&signals.sa_mask);
+#ifdef HAVE_SA_SIGINFO
+               for (i = 0; i < cur_sg; i ++) {
+                       g_queue_push_head (signals_info, &static_sg[i]);
+               }
+               cur_sg = 0;
+               print_signals_info ();
+#endif
+               if (do_terminate) {
+                       do_terminate = 0;
+                       msg_info_main ("catch termination signal, waiting for children");
+                       rspamd_pass_signal (rspamd_main->workers, SIGTERM);
+                       break;
+               }
+               if (child_dead) {
+                       child_dead = 0;
+                       msg_debug_main ("catch SIGCHLD signal, finding terminated worker");
+                       /* Remove dead child form children list */
+                       wrk = waitpid (0, &res, 0);
+                       if ((cur =
+                               g_hash_table_lookup (rspamd_main->workers,
+                               GSIZE_TO_POINTER (wrk))) != NULL) {
+                               /* Unlink dead process from queue and hash table */
+
+                               g_hash_table_remove (rspamd_main->workers, GSIZE_TO_POINTER (
+                                               wrk));
+
+                               if (WIFEXITED (res) && WEXITSTATUS (res) == 0) {
+                                       /* Normal worker termination, do not fork one more */
+                                       msg_info_main ("%s process %P terminated normally",
+                                               g_quark_to_string (cur->type),
+                                               cur->pid);
+                               }
+                               else {
+                                       if (WIFSIGNALED (res)) {
+                                               msg_warn_main (
+                                                       "%s process %P terminated abnormally by signal: %d",
+                                                       g_quark_to_string (cur->type),
+                                                       cur->pid,
+                                                       WTERMSIG (res));
+                                       }
+                                       else {
+                                               msg_warn_main ("%s process %P terminated abnormally",
+                                                       g_quark_to_string (cur->type),
+                                                       cur->pid);
+                                       }
+                                       /* Fork another worker in replace of dead one */
+                                       delay_fork (cur->cf, cur->index);
+                               }
+
+                               g_free (cur);
+                       }
+                       else {
+                               for (i = 0; i < (gint)other_workers->len; i++) {
+                                       if (g_array_index (other_workers, pid_t, i) == wrk) {
+                                               g_array_remove_index_fast (other_workers, i);
+                                               msg_info_main ("related process %P terminated", wrk);
+                                       }
+                               }
+                       }
+               }
+               if (do_restart) {
+                       do_restart = 0;
+                       rspamd_log_reopen_priv (rspamd_main->logger,
+                               rspamd_main->workers_uid,
+                               rspamd_main->workers_gid);
+                       msg_info_main ("rspamd " RVERSION " is restarting");
+                       g_hash_table_foreach (rspamd_main->workers, kill_old_workers, NULL);
+                       rspamd_map_remove_all (rspamd_main->cfg);
+                       reread_config (rspamd_main);
+                       spawn_workers (rspamd_main);
+               }
+               if (do_reopen_log) {
+                       do_reopen_log = 0;
+                       rspamd_log_reopen_priv (rspamd_main->logger,
+                               rspamd_main->workers_uid,
+                               rspamd_main->workers_gid);
+                       g_hash_table_foreach (rspamd_main->workers, reopen_log_handler,
+                               NULL);
+               }
+               if (got_alarm) {
+                       got_alarm = 0;
+                       fork_delayed (rspamd_main);
+               }
+       }
+
+       /* Restore some signals */
+       sigemptyset (&signals.sa_mask);
+       sigaddset (&signals.sa_mask, SIGALRM);
+       sigaddset (&signals.sa_mask, SIGINT);
+       sigaddset (&signals.sa_mask, SIGTERM);
+       sigaction (SIGALRM, &signals, NULL);
+       sigaction (SIGTERM, &signals, NULL);
+       sigaction (SIGINT,      &signals, NULL);
+       sigprocmask (SIG_UNBLOCK, &signals.sa_mask, NULL);
+       /* Set alarm for hard termination */
+       if (getenv ("G_SLICE") != NULL) {
+               /* Special case if we are likely running with valgrind */
+               set_alarm (HARD_TERMINATION_TIME * 10);
+       }
+       else {
+               set_alarm (HARD_TERMINATION_TIME);
+       }
+
+       /* Wait for workers termination */
+       g_hash_table_foreach_remove (rspamd_main->workers, wait_for_workers, NULL);
+
+       /* Maybe save roll history */
+       if (rspamd_main->cfg->history_file) {
+               rspamd_roll_history_save (rspamd_main->history,
+                       rspamd_main->cfg->history_file);
+       }
+
+       msg_info_main ("terminating...");
+       rspamd_symbols_cache_destroy (rspamd_main->cfg->cache);
+       rspamd_log_close (rspamd_main->logger);
+       rspamd_config_free (rspamd_main->cfg);
+       g_free (rspamd_main->cfg);
+       g_free (rspamd_main);
+
+       g_mime_shutdown ();
+
+#ifdef HAVE_OPENSSL
+       EVP_cleanup ();
+       ERR_free_strings ();
+#endif
+
+       return (res);
+}
+
+/*
+ * vi:ts=4
+ */
diff --git a/src/rspamd.h b/src/rspamd.h
new file mode 100644 (file)
index 0000000..5104040
--- /dev/null
@@ -0,0 +1,231 @@
+/**
+ * @file main.h
+ * Definitions for main rspamd structures
+ */
+
+#ifndef RSPAMD_MAIN_H
+#define RSPAMD_MAIN_H
+
+#include "config.h"
+#include "libutil/fstring.h"
+#include "libutil/mem_pool.h"
+#include "libutil/util.h"
+#include "libutil/logger.h"
+#include "libutil/http.h"
+#include "libutil/upstream.h"
+#include "libserver/url.h"
+#include "libserver/protocol.h"
+#include "libserver/buffer.h"
+#include "libserver/events.h"
+#include "libserver/roll_history.h"
+#include "libserver/task.h"
+
+
+/* Default values */
+#define FIXED_CONFIG_FILE RSPAMD_CONFDIR "/rspamd.conf"
+/* Time in seconds to exit for old worker */
+#define SOFT_SHUTDOWN_TIME 10
+
+/* Spam subject */
+#define SPAM_SUBJECT "*** SPAM *** "
+
+#ifdef CRLF
+#undef CRLF
+#undef CR
+#undef LF
+#endif
+
+#define CRLF "\r\n"
+#define CR '\r'
+#define LF '\n'
+
+/**
+ * Worker process structure
+ */
+struct rspamd_worker {
+       pid_t pid;                                                  /**< pid of worker                                                                  */
+       guint index;                                                /**< index number                                                                   */
+       struct rspamd_main *srv;                                    /**< pointer to server structure                                    */
+       GQuark type;                                                /**< process type                                                                   */
+       GHashTable *signal_events;                                                                      /**< signal events                                                                      */
+       GList *accept_events;                                       /**< socket events                                                                  */
+       struct rspamd_worker_conf *cf;                                      /**< worker config data                                                             */
+       gpointer ctx;                                               /**< worker's specific data                                                 */
+};
+
+struct rspamd_worker_signal_handler {
+       gint signo;
+       gboolean enabled;
+       struct event ev;
+       struct event_base *base;
+       struct rspamd_worker *worker;
+       void (*post_handler)(void *ud);
+       void *handler_data;
+};
+
+struct rspamd_controller_pbkdf {
+       gint id;
+       guint rounds;
+       gsize salt_len;
+       gsize key_len;
+};
+
+/**
+ * Common structure representing C module context
+ */
+struct module_s;
+struct module_ctx {
+       gint (*filter)(struct rspamd_task *task);                   /**< pointer to headers process function                    */
+       struct module_s *mod;                                                                           /**< module pointer                                                                     */
+       gboolean enabled;                                                                                       /**< true if module is enabled in configuration         */
+};
+
+/**
+ * Module
+ */
+typedef struct module_s {
+       const gchar *name;
+       int (*module_init_func)(struct rspamd_config *cfg, struct module_ctx **ctx);
+       int (*module_config_func)(struct rspamd_config *cfg);
+       int (*module_reconfig_func)(struct rspamd_config *cfg);
+       int (*module_attach_controller_func)(struct module_ctx *ctx,
+               GHashTable *custom_commands);
+} module_t;
+
+typedef struct worker_s {
+       const gchar *name;
+       gpointer (*worker_init_func)(struct rspamd_config *cfg);
+       void (*worker_start_func)(struct rspamd_worker *worker);
+       gboolean has_socket;
+       gboolean unique;
+       gboolean threaded;
+       gboolean killable;
+       gint listen_type;
+} worker_t;
+
+struct pidfh;
+struct rspamd_config;
+struct tokenizer;
+struct rspamd_stat_classifier;
+struct rspamd_classifier_config;
+struct mime_part;
+struct rspamd_dns_resolver;
+struct rspamd_task;
+
+/**
+ * The epoch of the fuzzy client
+ */
+enum rspamd_fuzzy_epoch {
+       RSPAMD_FUZZY_EPOCH6 = 0, /**< pre 0.6.x */
+       RSPAMD_FUZZY_EPOCH8,     /**< 0.8 till 0.9 */
+       RSPAMD_FUZZY_EPOCH9,     /**< 0.9 + */
+       RSPAMD_FUZZY_EPOCH_MAX
+};
+
+/**
+ * Server statistics
+ */
+struct rspamd_stat {
+       guint messages_scanned;                             /**< total number of messages scanned                               */
+       guint actions_stat[METRIC_ACTION_NOACTION + 1];     /**< statistic for each action                                              */
+       guint connections_count;                            /**< total connections count                                                */
+       guint control_connections_count;                    /**< connections count to control interface                 */
+       guint messages_learned;                             /**< messages learned                                                               */
+       guint fuzzy_hashes;                                 /**< number of fuzzy hashes stored                                  */
+       guint fuzzy_hashes_expired;                         /**< number of fuzzy hashes expired                                 */
+       guint64 fuzzy_hashes_checked[RSPAMD_FUZZY_EPOCH_MAX]; /**< ammount of check requests for each epoch             */
+       guint64 fuzzy_hashes_found[RSPAMD_FUZZY_EPOCH_MAX]; /**< amount of hashes found by epoch                                */
+};
+
+/**
+ * Struct that determine main server object (for logging purposes)
+ */
+struct rspamd_main {
+       struct rspamd_config *cfg;                                  /**< pointer to config structure                                    */
+       pid_t pid;                                                  /**< main pid                                                                               */
+       /* Pid file structure */
+       rspamd_pidfh_t *pfh;                                        /**< struct pidfh for pidfile                                               */
+       GQuark type;                                                /**< process type                                                                   */
+       guint ev_initialized;                                       /**< is event system is initialized                                 */
+       struct rspamd_stat *stat;                                   /**< pointer to statistics                                                  */
+
+       rspamd_mempool_t *server_pool;                                  /**< server's memory pool                                                       */
+       GHashTable *workers;                                        /**< workers pool indexed by pid                    */
+       rspamd_logger_t *logger;
+       uid_t workers_uid;                                          /**< worker's uid running to                        */
+       gid_t workers_gid;                                          /**< worker's gid running to                                                */
+       gboolean is_privilleged;                                    /**< true if run in privilleged mode                */
+       struct roll_history *history;                               /**< rolling history                                                                */
+};
+
+/**
+ * Structure to point exception in text from processing
+ */
+struct process_exception {
+       gsize pos;
+       gsize len;
+};
+
+/**
+ * Control session object
+ */
+struct controller_command;
+struct controller_session;
+typedef gboolean (*controller_func_t)(gchar **args,
+       struct controller_session *session);
+
+struct controller_session {
+       struct rspamd_worker *worker;                               /**< pointer to worker structure (controller in fact) */
+       enum {
+               STATE_COMMAND,
+               STATE_HEADER,
+               STATE_LEARN,
+               STATE_LEARN_SPAM_PRE,
+               STATE_LEARN_SPAM,
+               STATE_REPLY,
+               STATE_QUIT,
+               STATE_OTHER,
+               STATE_WAIT,
+               STATE_WEIGHTS
+       } state;                                                    /**< current session state                                                  */
+       gint sock;                                                  /**< socket descriptor                                                              */
+       /* Access to authorized commands */
+       gboolean authorized;                                        /**< whether this session is authorized                             */
+       gboolean restful;                                           /**< whether this session is a restful session              */
+       GHashTable *kwargs;                                         /**< keyword arguments for restful command                  */
+       struct controller_command *cmd;                             /**< real command                                                                   */
+       rspamd_mempool_t *session_pool;                             /**< memory pool for session                        */
+       struct rspamd_config *cfg;                                  /**< pointer to config file                                                 */
+       gchar *learn_rcpt;                                          /**< recipient for learning                                                 */
+       gchar *learn_from;                                          /**< from address for learning                                              */
+       struct rspamd_classifier_config *learn_classifier;
+       gchar *learn_symbol;                                            /**< symbol to train                                                            */
+       double learn_multiplier;                                    /**< multiplier for learning                                                */
+       rspamd_io_dispatcher_t *dispatcher;                         /**< IO dispatcher object                                                   */
+       rspamd_fstring_t *learn_buf;                                         /**< learn input                                                                   */
+       GList *parts;                                               /**< extracted mime parts                                                   */
+       gint in_class;                                              /**< positive or negative learn                                             */
+       gboolean (*other_handler)(struct controller_session *session,
+               rspamd_fstring_t *in);                       /**< other command handler to execute at the end of processing */
+       void *other_data;                                           /**< and its data                                   */
+       controller_func_t custom_handler;                           /**< custom command handler                                                 */
+       struct rspamd_async_session * s;                             /**< async session object                                                  */
+       struct rspamd_task *learn_task;
+       struct rspamd_dns_resolver *resolver;                       /**< DNS resolver                                                                   */
+       struct event_base *ev_base;                                 /**< Event base                                                                             */
+};
+
+
+/**
+ * Register custom controller function
+ */
+void register_custom_controller_command (const gchar *name,
+       controller_func_t handler,
+       gboolean privilleged,
+       gboolean require_message);
+
+#endif
+
+/*
+ * vi:ts=4
+ */
index d6713eeb209b79816a263b5d37a9f9638f297a31..798e87a30b589bc8ebd433377e44820db97108f1 100644 (file)
@@ -5,7 +5,7 @@
 #include "libutil/upstream.h"
 #include "libmime/smtp_utils.h"
 #include "libmime/smtp_proto.h"
-#include "main.h"
+#include "rspamd.h"
 
 struct rspamd_dns_resolver;
 
index de9854a34f1861cf53b4be65bc6885613b614f49..b931a78909918fee41b1e462afd7c8134133e5fe 100644 (file)
@@ -24,7 +24,7 @@
 #include "config.h"
 #include "utlist.h"
 #include "libserver/proxy.h"
-#include "main.h"
+#include "rspamd.h"
 #include "smtp.h"
 #include "libserver/worker_util.h"
 
index 2d37c8b5f0098d7637d90a23847f64159dc99dc9..a127d14d882ba34632c413428301b37a38b9871a 100644 (file)
@@ -35,7 +35,7 @@
 #include "libserver/url.h"
 #include "libserver/dns.h"
 #include "libmime/message.h"
-#include "main.h"
+#include "rspamd.h"
 #include "keypairs_cache.h"
 #include "libstat/stat_api.h"
 #include "libserver/worker_util.h"
index 2308acc671000eaaad8a31a7016c38c38e8b0cb3..71eec712a078e5ad50ee78805fe6cec61d695966 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "config.h"
 #include "tests.h"
-#include "main.h"
+#include "rspamd.h"
 #include "aio_event.h"
 #include "mem_pool.h"
 
index 47eab183889e2a452ef25a8b158c6ded360cd62d..c7ad2921cea59637ddb976561ccd1f7145b9d806 100644 (file)
@@ -24,7 +24,7 @@
 
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "shingles.h"
 #include "fstring.h"
 #include "ottery.h"
index c0fca4ce5df1eaaf576c05e98a2bee199976ddb2..50dfae7daf8324b87587112633b5f81d33d3425c 100644 (file)
@@ -23,7 +23,7 @@
 
 #include "config.h"
 #include "tests.h"
-#include "main.h"
+#include "rspamd.h"
 #include "dkim.h"
 
 static const gchar test_dkim_sig[] = "v=1; a=rsa-sha256; c=relaxed/relaxed; "
index 31efdc827ab4f4200fb0441ee729f5037fa32a6d..c2383b61abd871a4191a90a193b920e603c60ea4 100644 (file)
@@ -3,7 +3,7 @@
 #include "tests.h"
 #include "dns.h"
 #include "logger.h"
-#include "main.h"
+#include "rspamd.h"
 #include "events.h"
 #include "cfg_file.h"
 
index ee6c49b2338614ea5787fe839afe7b58f63ebeb4..f4712b22436cbc7daca92dc10c1e677e504d4713 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "util.h"
 #include "http.h"
 #include "tests.h"
index b129f1b518216958cba06092269ebf46cf525073..caeb9814ef8bb862ba632bf49b5f5fc93fcde3d7 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "util.h"
 #include "lua/lua_common.h"
 
index 388f95a9a4c96b41d6e22c77b73d831c93af88e5..a46f4a3b11d2234249bced2b12f27a9ff9018a68 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "radix.h"
 #include "ottery.h"
 
index 4700be8b48c59e018c0be707307d7e82116d4505..7b3cd7a68a9dc94ce807322c43c9fe1b274161c4 100644 (file)
@@ -24,7 +24,7 @@
 #include "config.h"
 #include "tests.h"
 #include "rrd.h"
-#include "main.h"
+#include "rspamd.h"
 #include "ottery.h"
 
 const int rows_cnt = 20;
index 1a96b64bcd03cbe607bb69a027e82691d1ec476c..433fe8c679b1fddd8b16ff8cb4e6f91d946f8a9b 100644 (file)
@@ -22,7 +22,7 @@
  */
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "shingles.h"
 #include "fstring.h"
 #include "ottery.h"
index af18faa5e539a0436a328c498713d27048c9c5dd..2ee32ea48b12941a9026cebfb2aa085ffe765d7e 100644 (file)
@@ -1,5 +1,5 @@
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "tests.h"
 #include "ottery.h"
 
index 8e092fd8423e04f308315d6e8ce217b22b4f89bf..e10ebd88925831fc9cf79f1733317ef0207af018 100644 (file)
@@ -1,5 +1,5 @@
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "cfg_file.h"
 #include "regexp.h"
 #include "libstat/stat_api.h"
index 28c4bb7576896934c59606e2bfeea830a4e3eac3..9e04c4ddaab2e5400dfcda2d0555e168524e91f4 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "upstream.h"
 #include "ottery.h"
 
index 8acc6b3247144f98497e7a983774800ee86766d7..aadc18409f329d509ed205cdcb97a3f242fce78a 100644 (file)
@@ -1,5 +1,5 @@
 #include "config.h"
-#include "main.h"
+#include "rspamd.h"
 #include "cfg_file.h"
 #include "url.h"
 #include "tests.h"