You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

lua_classifier.c 10KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444
  1. /*
  2. * Copyright (c) 2009-2012, Vsevolod Stakhov
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. *
  13. * THIS SOFTWARE IS PROVIDED BY AUTHOR ''AS IS'' AND ANY
  14. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  15. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  16. * DISCLAIMED. IN NO EVENT SHALL AUTHOR BE LIABLE FOR ANY
  17. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  18. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  19. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  20. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  21. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  22. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  23. */
  24. #include "lua_common.h"
  25. #include "cfg_file.h"
  26. #include "classifiers/classifiers.h"
  27. /* Classifier methods */
  28. LUA_FUNCTION_DEF (classifier, register_pre_callback);
  29. LUA_FUNCTION_DEF (classifier, register_post_callback);
  30. LUA_FUNCTION_DEF (classifier, get_statfiles);
  31. LUA_FUNCTION_DEF (classifier, get_statfile_by_label);
  32. static const struct luaL_reg classifierlib_m[] = {
  33. LUA_INTERFACE_DEF (classifier, register_pre_callback),
  34. LUA_INTERFACE_DEF (classifier, register_post_callback),
  35. LUA_INTERFACE_DEF (classifier, get_statfiles),
  36. LUA_INTERFACE_DEF (classifier, get_statfile_by_label),
  37. {"__tostring", rspamd_lua_class_tostring},
  38. {NULL, NULL}
  39. };
  40. LUA_FUNCTION_DEF (statfile, get_symbol);
  41. LUA_FUNCTION_DEF (statfile, get_label);
  42. LUA_FUNCTION_DEF (statfile, get_path);
  43. LUA_FUNCTION_DEF (statfile, get_size);
  44. LUA_FUNCTION_DEF (statfile, is_spam);
  45. LUA_FUNCTION_DEF (statfile, get_param);
  46. static const struct luaL_reg statfilelib_m[] = {
  47. LUA_INTERFACE_DEF (statfile, get_symbol),
  48. LUA_INTERFACE_DEF (statfile, get_label),
  49. LUA_INTERFACE_DEF (statfile, get_path),
  50. LUA_INTERFACE_DEF (statfile, get_size),
  51. LUA_INTERFACE_DEF (statfile, is_spam),
  52. LUA_INTERFACE_DEF (statfile, get_param),
  53. {"__tostring", rspamd_lua_class_tostring},
  54. {NULL, NULL}
  55. };
  56. struct classifier_callback_data {
  57. lua_State *L;
  58. const gchar *name;
  59. };
  60. static struct rspamd_statfile_config * lua_check_statfile (lua_State * L);
  61. /* Classifier implementation */
  62. static struct rspamd_classifier_config *
  63. lua_check_classifier (lua_State * L)
  64. {
  65. void *ud = luaL_checkudata (L, 1, "rspamd{classifier}");
  66. luaL_argcheck (L, ud != NULL, 1, "'classifier' expected");
  67. return ud ? *((struct rspamd_classifier_config **)ud) : NULL;
  68. }
  69. static GList *
  70. call_classifier_pre_callback (struct rspamd_classifier_config *ccf,
  71. struct rspamd_task *task,
  72. lua_State *L,
  73. gboolean is_learn,
  74. gboolean is_spam)
  75. {
  76. struct rspamd_classifier_config **pccf;
  77. struct rspamd_task **ptask;
  78. struct rspamd_statfile_config **pst;
  79. GList *res = NULL;
  80. pccf = lua_newuserdata (L, sizeof (struct rspamd_classifier_config *));
  81. rspamd_lua_setclass (L, "rspamd{classifier}", -1);
  82. *pccf = ccf;
  83. ptask = lua_newuserdata (L, sizeof (struct rspamd_task *));
  84. rspamd_lua_setclass (L, "rspamd{task}", -1);
  85. *ptask = task;
  86. lua_pushboolean (L, is_learn);
  87. lua_pushboolean (L, is_spam);
  88. if (lua_pcall (L, 4, 1, 0) != 0) {
  89. msg_warn ("error running pre classifier callback %s",
  90. lua_tostring (L, -1));
  91. }
  92. else {
  93. if (lua_istable (L, -1)) {
  94. lua_pushnil (L);
  95. while (lua_next (L, -2)) {
  96. pst = luaL_checkudata (L, -1, "rspamd{statfile}");
  97. if (pst) {
  98. res = g_list_prepend (res, *pst);
  99. }
  100. lua_pop (L, 1);
  101. }
  102. }
  103. }
  104. return res;
  105. }
  106. /* Return list of statfiles that should be checked for this message */
  107. GList *
  108. rspamd_lua_call_cls_pre_callbacks (struct rspamd_classifier_config *ccf,
  109. struct rspamd_task *task,
  110. gboolean is_learn,
  111. gboolean is_spam,
  112. lua_State *L)
  113. {
  114. GList *res = NULL, *cur;
  115. struct classifier_callback_data *cd;
  116. /* Go throught all callbacks and call them, appending results to list */
  117. cur = g_list_first (ccf->pre_callbacks);
  118. while (cur) {
  119. cd = cur->data;
  120. lua_getglobal (L, cd->name);
  121. res =
  122. g_list_concat (res,
  123. call_classifier_pre_callback (ccf, task, L, is_learn, is_spam));
  124. cur = g_list_next (cur);
  125. }
  126. if (res == NULL) {
  127. /* Check function from global table 'classifiers' */
  128. lua_getglobal (L, "classifiers");
  129. if (lua_istable (L, -1)) {
  130. lua_pushstring (L, ccf->classifier->name);
  131. lua_gettable (L, -2);
  132. /* Function is now on top */
  133. if (lua_isfunction (L, -1)) {
  134. res = call_classifier_pre_callback (ccf,
  135. task,
  136. L,
  137. is_learn,
  138. is_spam);
  139. }
  140. lua_pop (L, 1);
  141. }
  142. lua_pop (L, 1);
  143. }
  144. return res;
  145. }
  146. /* Return result mark for statfile */
  147. double
  148. rspamd_lua_call_cls_post_callbacks (struct rspamd_classifier_config *ccf,
  149. struct rspamd_task *task,
  150. double in,
  151. lua_State *L)
  152. {
  153. struct classifier_callback_data *cd;
  154. struct rspamd_classifier_config **pccf;
  155. struct rspamd_task **ptask;
  156. double out = in;
  157. GList *cur;
  158. /* Go throught all callbacks and call them, appending results to list */
  159. cur = g_list_first (ccf->pre_callbacks);
  160. while (cur) {
  161. cd = cur->data;
  162. lua_getglobal (L, cd->name);
  163. pccf = lua_newuserdata (L, sizeof (struct rspamd_classifier_config *));
  164. rspamd_lua_setclass (L, "rspamd{classifier}", -1);
  165. *pccf = ccf;
  166. ptask = lua_newuserdata (L, sizeof (struct rspamd_task *));
  167. rspamd_lua_setclass (L, "rspamd{task}", -1);
  168. *ptask = task;
  169. lua_pushnumber (L, out);
  170. if (lua_pcall (L, 3, 1, 0) != 0) {
  171. msg_warn ("error running function %s: %s", cd->name,
  172. lua_tostring (L, -1));
  173. }
  174. else {
  175. if (lua_isnumber (L, 1)) {
  176. out = lua_tonumber (L, 1);
  177. }
  178. lua_pop (L, 1);
  179. }
  180. cur = g_list_next (cur);
  181. }
  182. return out;
  183. }
  184. static gint
  185. lua_classifier_register_pre_callback (lua_State *L)
  186. {
  187. struct rspamd_classifier_config *ccf = lua_check_classifier (L);
  188. struct classifier_callback_data *cd;
  189. const gchar *name;
  190. if (ccf) {
  191. name = luaL_checkstring (L, 2);
  192. if (name) {
  193. cd = g_malloc (sizeof (struct classifier_callback_data));
  194. cd->name = g_strdup (name);
  195. cd->L = L;
  196. ccf->pre_callbacks = g_list_prepend (ccf->pre_callbacks, cd);
  197. }
  198. }
  199. return 0;
  200. }
  201. static gint
  202. lua_classifier_register_post_callback (lua_State *L)
  203. {
  204. struct rspamd_classifier_config *ccf = lua_check_classifier (L);
  205. struct classifier_callback_data *cd;
  206. const gchar *name;
  207. if (ccf) {
  208. name = luaL_checkstring (L, 2);
  209. if (name) {
  210. cd = g_malloc (sizeof (struct classifier_callback_data));
  211. cd->name = g_strdup (name);
  212. cd->L = L;
  213. ccf->pre_callbacks = g_list_prepend (ccf->pre_callbacks, cd);
  214. }
  215. }
  216. return 0;
  217. }
  218. /* Return table of statfiles indexed by name */
  219. static gint
  220. lua_classifier_get_statfiles (lua_State *L)
  221. {
  222. struct rspamd_classifier_config *ccf = lua_check_classifier (L);
  223. GList *cur;
  224. struct rspamd_statfile_config *st, **pst;
  225. gint i;
  226. if (ccf) {
  227. lua_newtable (L);
  228. cur = g_list_first (ccf->statfiles);
  229. i = 1;
  230. while (cur) {
  231. st = cur->data;
  232. pst = lua_newuserdata (L, sizeof (struct rspamd_statfile_config *));
  233. rspamd_lua_setclass (L, "rspamd{statfile}", -1);
  234. *pst = st;
  235. lua_rawseti (L, -2, i++);
  236. cur = g_list_next (cur);
  237. }
  238. }
  239. else {
  240. lua_pushnil (L);
  241. }
  242. return 1;
  243. }
  244. /* Get statfile with specified label */
  245. static gint
  246. lua_classifier_get_statfile_by_label (lua_State *L)
  247. {
  248. struct rspamd_classifier_config *ccf = lua_check_classifier (L);
  249. struct rspamd_statfile_config *st, **pst;
  250. const gchar *label;
  251. GList *cur;
  252. gint i;
  253. label = luaL_checkstring (L, 2);
  254. if (ccf && label) {
  255. cur = g_hash_table_lookup (ccf->labels, label);
  256. if (cur) {
  257. lua_newtable (L);
  258. i = 1;
  259. while (cur) {
  260. st = cur->data;
  261. pst =
  262. lua_newuserdata (L,
  263. sizeof (struct rspamd_statfile_config *));
  264. rspamd_lua_setclass (L, "rspamd{statfile}", -1);
  265. *pst = st;
  266. lua_rawseti (L, -2, i++);
  267. cur = g_list_next (cur);
  268. }
  269. return 1;
  270. }
  271. }
  272. lua_pushnil (L);
  273. return 1;
  274. }
  275. /* Statfile functions */
  276. static gint
  277. lua_statfile_get_symbol (lua_State *L)
  278. {
  279. struct rspamd_statfile_config *st = lua_check_statfile (L);
  280. if (st != NULL) {
  281. lua_pushstring (L, st->symbol);
  282. }
  283. else {
  284. lua_pushnil (L);
  285. }
  286. return 1;
  287. }
  288. static gint
  289. lua_statfile_get_label (lua_State *L)
  290. {
  291. struct rspamd_statfile_config *st = lua_check_statfile (L);
  292. if (st != NULL && st->label != NULL) {
  293. lua_pushstring (L, st->label);
  294. }
  295. else {
  296. lua_pushnil (L);
  297. }
  298. return 1;
  299. }
  300. static gint
  301. lua_statfile_get_path (lua_State *L)
  302. {
  303. struct rspamd_statfile_config *st = lua_check_statfile (L);
  304. if (st != NULL) {
  305. lua_pushstring (L, st->path);
  306. }
  307. else {
  308. lua_pushnil (L);
  309. }
  310. return 1;
  311. }
  312. static gint
  313. lua_statfile_get_size (lua_State *L)
  314. {
  315. struct rspamd_statfile_config *st = lua_check_statfile (L);
  316. if (st != NULL) {
  317. lua_pushinteger (L, st->size);
  318. }
  319. else {
  320. lua_pushnil (L);
  321. }
  322. return 1;
  323. }
  324. static gint
  325. lua_statfile_is_spam (lua_State *L)
  326. {
  327. struct rspamd_statfile_config *st = lua_check_statfile (L);
  328. if (st != NULL) {
  329. lua_pushboolean (L, st->is_spam);
  330. }
  331. else {
  332. lua_pushnil (L);
  333. }
  334. return 1;
  335. }
  336. static gint
  337. lua_statfile_get_param (lua_State *L)
  338. {
  339. struct rspamd_statfile_config *st = lua_check_statfile (L);
  340. const gchar *param;
  341. const ucl_object_t *value;
  342. param = luaL_checkstring (L, 2);
  343. if (st != NULL && param != NULL) {
  344. value = ucl_object_find_key (st->opts, param);
  345. if (value != NULL) {
  346. lua_pushstring (L, ucl_object_tostring_forced (value));
  347. return 1;
  348. }
  349. }
  350. lua_pushnil (L);
  351. return 1;
  352. }
  353. static struct rspamd_statfile_config *
  354. lua_check_statfile (lua_State * L)
  355. {
  356. void *ud = luaL_checkudata (L, 1, "rspamd{statfile}");
  357. luaL_argcheck (L, ud != NULL, 1, "'statfile' expected");
  358. return ud ? *((struct rspamd_statfile_config **)ud) : NULL;
  359. }
  360. /* Open functions */
  361. void
  362. luaopen_classifier (lua_State * L)
  363. {
  364. rspamd_lua_new_class (L, "rspamd{classifier}", classifierlib_m);
  365. lua_pop (L, 1); /* remove metatable from stack */
  366. }
  367. void
  368. luaopen_statfile (lua_State * L)
  369. {
  370. rspamd_lua_new_class (L, "rspamd{statfile}", statfilelib_m);
  371. lua_pop (L, 1); /* remove metatable from stack */
  372. }