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_html.c 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  1. /*-
  2. * Copyright 2016 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include <src/libserver/html.h>
  17. #include "lua_common.h"
  18. #include "message.h"
  19. #include "html.h"
  20. #include "html_tags.h"
  21. #include "images.h"
  22. #include "contrib/mumhash/mum.h"
  23. /***
  24. * @module rspamd_html
  25. * This module provides different methods to access HTML tags. To get HTML context
  26. * from an HTML part you could use method `part:get_html()`
  27. * @example
  28. rspamd_config.R_EMPTY_IMAGE = function(task)
  29. local tp = task:get_text_parts() -- get text parts in a message
  30. for _,p in ipairs(tp) do -- iterate over text parts array using `ipairs`
  31. if p:is_html() then -- if the current part is html part
  32. local hc = p:get_html() -- we get HTML context
  33. local len = p:get_length() -- and part's length
  34. if len < 50 then -- if we have a part that has less than 50 bytes of text
  35. local images = hc:get_images() -- then we check for HTML images
  36. if images then -- if there are images
  37. for _,i in ipairs(images) do -- then iterate over images in the part
  38. if i['height'] + i['width'] >= 400 then -- if we have a large image
  39. return true -- add symbol
  40. end
  41. end
  42. end
  43. end
  44. end
  45. end
  46. end
  47. */
  48. /***
  49. * @method html:has_tag(name)
  50. * Checks if a specified tag `name` is presented in a part
  51. * @param {string} name name of tag to check
  52. * @return {boolean} `true` if the tag exists in HTML tree
  53. */
  54. LUA_FUNCTION_DEF (html, has_tag);
  55. /***
  56. * @method html:check_property(name)
  57. * Checks if the HTML has a specific property. Here is the list of available properties:
  58. *
  59. * - `no_html` - no html tag presented
  60. * - `bad_element` - part has some broken elements
  61. * - `xml` - part is xhtml
  62. * - `unknown_element` - part has some unknown elements
  63. * - `duplicate_element` - part has some duplicate elements that should be unique (namely, `title` tag)
  64. * - `unbalanced` - part has unbalanced tags
  65. * @param {string} name name of property
  66. * @return {boolean} true if the part has the specified property
  67. */
  68. LUA_FUNCTION_DEF (html, has_property);
  69. /***
  70. * @method html:get_images()
  71. * Returns a table of images found in html. Each image is, in turn, a table with the following fields:
  72. *
  73. * - `src` - link to the source
  74. * - `height` - height in pixels
  75. * - `width` - width in pixels
  76. * - `embedded` - `true` if an image is embedded in a message
  77. * @return {table} table of images in html part
  78. */
  79. LUA_FUNCTION_DEF (html, get_images);
  80. /***
  81. * @method html:get_blocks()
  82. * Returns a table of html blocks. Each block provides the following data:
  83. *
  84. * `tag` - corresponding tag
  85. * `color` - a triplet (r g b) for font color
  86. * `bgcolor` - a triplet (r g b) for background color
  87. * `style` - rspamd{text} with the full style description
  88. * `font_size` - font size
  89. * @return {table} table of blocks in html part
  90. */
  91. LUA_FUNCTION_DEF (html, get_blocks);
  92. /***
  93. * @method html:foreach_tag(tagname, callback)
  94. * Processes HTML tree calling the specified callback for each tag of the specified
  95. * type.
  96. *
  97. * Callback is called with the following attributes:
  98. *
  99. * - `tag`: html tag structure
  100. * - `content_length`: length of content within a tag
  101. *
  102. * Callback function should return `true` to **stop** processing and `false` to continue
  103. * @return nothing
  104. */
  105. LUA_FUNCTION_DEF (html, foreach_tag);
  106. static const struct luaL_reg htmllib_m[] = {
  107. LUA_INTERFACE_DEF (html, has_tag),
  108. LUA_INTERFACE_DEF (html, has_property),
  109. LUA_INTERFACE_DEF (html, get_images),
  110. LUA_INTERFACE_DEF (html, get_blocks),
  111. LUA_INTERFACE_DEF (html, foreach_tag),
  112. {"__tostring", rspamd_lua_class_tostring},
  113. {NULL, NULL}
  114. };
  115. /***
  116. * @method html_tag:get_type()
  117. * Returns string representation of HTML type for a tag
  118. * @return {string} type of tag
  119. */
  120. LUA_FUNCTION_DEF (html_tag, get_type);
  121. /***
  122. * @method html_tag:get_extra()
  123. * Returns extra data associated with the tag
  124. * @return {url|image|nil} extra data associated with the tag
  125. */
  126. LUA_FUNCTION_DEF (html_tag, get_extra);
  127. /***
  128. * @method html_tag:get_parent()
  129. * Returns parent node for a specified tag
  130. * @return {html_tag} parent object for a specified tag
  131. */
  132. LUA_FUNCTION_DEF (html_tag, get_parent);
  133. /***
  134. * @method html_tag:get_flags()
  135. * Returns flags a specified tag:
  136. *
  137. * - `closed`: tag is properly closed
  138. * - `closing`: tag is a closing tag
  139. * - `broken`: tag is somehow broken
  140. * - `unbalanced`: tag is unbalanced
  141. * - `xml`: tag is xml tag
  142. * @return {table} table of flags
  143. */
  144. LUA_FUNCTION_DEF (html_tag, get_flags);
  145. /***
  146. * @method html_tag:get_content()
  147. * Returns content of tag (approximate for some cases)
  148. * @return {rspamd_text} rspamd text with tag's content
  149. */
  150. LUA_FUNCTION_DEF (html_tag, get_content);
  151. /***
  152. * @method html_tag:get_content_length()
  153. * Returns length of a tag's content
  154. * @return {number} size of content enclosed within a tag
  155. */
  156. LUA_FUNCTION_DEF (html_tag, get_content_length);
  157. static const struct luaL_reg taglib_m[] = {
  158. LUA_INTERFACE_DEF (html_tag, get_type),
  159. LUA_INTERFACE_DEF (html_tag, get_extra),
  160. LUA_INTERFACE_DEF (html_tag, get_parent),
  161. LUA_INTERFACE_DEF (html_tag, get_flags),
  162. LUA_INTERFACE_DEF (html_tag, get_content),
  163. LUA_INTERFACE_DEF (html_tag, get_content_length),
  164. {"__tostring", rspamd_lua_class_tostring},
  165. {NULL, NULL}
  166. };
  167. static struct html_content *
  168. lua_check_html (lua_State * L, gint pos)
  169. {
  170. void *ud = rspamd_lua_check_udata (L, pos, "rspamd{html}");
  171. luaL_argcheck (L, ud != NULL, pos, "'html' expected");
  172. return ud ? *((struct html_content **)ud) : NULL;
  173. }
  174. static struct html_tag *
  175. lua_check_html_tag (lua_State * L, gint pos)
  176. {
  177. void *ud = rspamd_lua_check_udata (L, pos, "rspamd{html_tag}");
  178. luaL_argcheck (L, ud != NULL, pos, "'html_tag' expected");
  179. return ud ? *((struct html_tag **)ud) : NULL;
  180. }
  181. static gint
  182. lua_html_has_tag (lua_State *L)
  183. {
  184. LUA_TRACE_POINT;
  185. struct html_content *hc = lua_check_html (L, 1);
  186. const gchar *tagname = luaL_checkstring (L, 2);
  187. gboolean ret = FALSE;
  188. if (hc && tagname) {
  189. if (rspamd_html_tag_seen (hc, tagname)) {
  190. ret = TRUE;
  191. }
  192. }
  193. lua_pushboolean (L, ret);
  194. return 1;
  195. }
  196. static gint
  197. lua_html_has_property (lua_State *L)
  198. {
  199. LUA_TRACE_POINT;
  200. struct html_content *hc = lua_check_html (L, 1);
  201. const gchar *propname = luaL_checkstring (L, 2);
  202. gboolean ret = FALSE;
  203. if (hc && propname) {
  204. /*
  205. * - `no_html`
  206. * - `bad_element`
  207. * - `xml`
  208. * - `unknown_element`
  209. * - `duplicate_element`
  210. * - `unbalanced`
  211. * - `data_urls`
  212. */
  213. if (strcmp (propname, "no_html") == 0) {
  214. ret = hc->flags & RSPAMD_HTML_FLAG_BAD_START;
  215. }
  216. else if (strcmp (propname, "bad_element") == 0) {
  217. ret = hc->flags & RSPAMD_HTML_FLAG_BAD_ELEMENTS;
  218. }
  219. else if (strcmp (propname, "xml") == 0) {
  220. ret = hc->flags & RSPAMD_HTML_FLAG_XML;
  221. }
  222. else if (strcmp (propname, "unknown_element") == 0) {
  223. ret = hc->flags & RSPAMD_HTML_FLAG_UNKNOWN_ELEMENTS;
  224. }
  225. else if (strcmp (propname, "duplicate_element") == 0) {
  226. ret = hc->flags & RSPAMD_HTML_FLAG_DUPLICATE_ELEMENTS;
  227. }
  228. else if (strcmp (propname, "unbalanced") == 0) {
  229. ret = hc->flags & RSPAMD_HTML_FLAG_UNBALANCED;
  230. }
  231. else if (strcmp (propname, "data_urls") == 0) {
  232. ret = hc->flags & RSPAMD_HTML_FLAG_HAS_DATA_URLS;
  233. }
  234. }
  235. lua_pushboolean (L, ret);
  236. return 1;
  237. }
  238. static void
  239. lua_html_push_image (lua_State *L, struct html_image *img)
  240. {
  241. LUA_TRACE_POINT;
  242. struct html_tag **ptag;
  243. struct rspamd_url **purl;
  244. lua_newtable (L);
  245. if (img->src) {
  246. lua_pushstring (L, "src");
  247. if (img->flags & RSPAMD_HTML_FLAG_IMAGE_DATA) {
  248. struct rspamd_lua_text *t;
  249. t = lua_newuserdata (L, sizeof (*t));
  250. t->start = img->src;
  251. t->len = strlen (img->src);
  252. t->flags = 0;
  253. rspamd_lua_setclass (L, "rspamd{text}", -1);
  254. }
  255. else {
  256. lua_pushstring (L, img->src);
  257. }
  258. lua_settable (L, -3);
  259. }
  260. if (img->url) {
  261. lua_pushstring (L, "url");
  262. purl = lua_newuserdata (L, sizeof (gpointer));
  263. *purl = img->url;
  264. rspamd_lua_setclass (L, "rspamd{url}", -1);
  265. lua_settable (L, -3);
  266. }
  267. if (img->tag) {
  268. lua_pushstring (L, "tag");
  269. ptag = lua_newuserdata (L, sizeof (gpointer));
  270. *ptag = img->tag;
  271. rspamd_lua_setclass (L, "rspamd{html_tag}", -1);
  272. lua_settable (L, -3);
  273. }
  274. lua_pushstring (L, "height");
  275. lua_pushinteger (L, img->height);
  276. lua_settable (L, -3);
  277. lua_pushstring (L, "width");
  278. lua_pushinteger (L, img->width);
  279. lua_settable (L, -3);
  280. lua_pushstring (L, "embedded");
  281. lua_pushboolean (L, img->flags & RSPAMD_HTML_FLAG_IMAGE_EMBEDDED);
  282. lua_settable (L, -3);
  283. lua_pushstring (L, "data");
  284. lua_pushboolean (L, img->flags & RSPAMD_HTML_FLAG_IMAGE_DATA);
  285. lua_settable (L, -3);
  286. }
  287. static gint
  288. lua_html_get_images (lua_State *L)
  289. {
  290. LUA_TRACE_POINT;
  291. struct html_content *hc = lua_check_html (L, 1);
  292. struct html_image *img;
  293. guint i;
  294. if (hc != NULL) {
  295. lua_newtable (L);
  296. if (hc->images && hc->images->len > 0) {
  297. for (i = 0; i < hc->images->len; i ++) {
  298. img = g_ptr_array_index (hc->images, i);
  299. lua_html_push_image (L, img);
  300. lua_rawseti (L, -2, i + 1);
  301. }
  302. }
  303. else {
  304. lua_pushnil (L);
  305. }
  306. }
  307. else {
  308. lua_pushnil (L);
  309. }
  310. return 1;
  311. }
  312. static void
  313. lua_html_push_block (lua_State *L, struct html_block *bl)
  314. {
  315. LUA_TRACE_POINT;
  316. struct rspamd_lua_text *t;
  317. lua_createtable (L, 0, 6);
  318. if (bl->tag) {
  319. lua_pushstring (L, "tag");
  320. lua_pushlstring (L, bl->tag->name.start, bl->tag->name.len);
  321. lua_settable (L, -3);
  322. }
  323. if (bl->font_color.valid) {
  324. lua_pushstring (L, "color");
  325. lua_createtable (L, 4, 0);
  326. lua_pushinteger (L, bl->font_color.d.comp.r);
  327. lua_rawseti (L, -2, 1);
  328. lua_pushinteger (L, bl->font_color.d.comp.g);
  329. lua_rawseti (L, -2, 2);
  330. lua_pushinteger (L, bl->font_color.d.comp.b);
  331. lua_rawseti (L, -2, 3);
  332. lua_pushinteger (L, bl->font_color.d.comp.alpha);
  333. lua_rawseti (L, -2, 4);
  334. lua_settable (L, -3);
  335. }
  336. if (bl->background_color.valid) {
  337. lua_pushstring (L, "bgcolor");
  338. lua_createtable (L, 4, 0);
  339. lua_pushinteger (L, bl->background_color.d.comp.r);
  340. lua_rawseti (L, -2, 1);
  341. lua_pushinteger (L, bl->background_color.d.comp.g);
  342. lua_rawseti (L, -2, 2);
  343. lua_pushinteger (L, bl->background_color.d.comp.b);
  344. lua_rawseti (L, -2, 3);
  345. lua_pushinteger (L, bl->background_color.d.comp.alpha);
  346. lua_rawseti (L, -2, 4);
  347. lua_settable (L, -3);
  348. }
  349. if (bl->style.len > 0) {
  350. lua_pushstring (L, "style");
  351. t = lua_newuserdata (L, sizeof (*t));
  352. rspamd_lua_setclass (L, "rspamd{text}", -1);
  353. t->start = bl->style.start;
  354. t->len = bl->style.len;
  355. t->flags = 0;
  356. lua_settable (L, -3);
  357. }
  358. lua_pushstring (L, "visible");
  359. lua_pushboolean (L, bl->visible);
  360. lua_settable (L, -3);
  361. lua_pushstring (L, "font_size");
  362. lua_pushinteger (L, bl->font_size);
  363. lua_settable (L, -3);
  364. }
  365. static gint
  366. lua_html_get_blocks (lua_State *L)
  367. {
  368. LUA_TRACE_POINT;
  369. struct html_content *hc = lua_check_html (L, 1);
  370. struct html_block *bl;
  371. guint i;
  372. if (hc != NULL) {
  373. if (hc->blocks && hc->blocks->len > 0) {
  374. lua_createtable (L, hc->blocks->len, 0);
  375. for (i = 0; i < hc->blocks->len; i ++) {
  376. bl = g_ptr_array_index (hc->blocks, i);
  377. lua_html_push_block (L, bl);
  378. lua_rawseti (L, -2, i + 1);
  379. }
  380. }
  381. else {
  382. lua_pushnil (L);
  383. }
  384. }
  385. else {
  386. return luaL_error (L, "invalid arguments");
  387. }
  388. return 1;
  389. }
  390. struct lua_html_traverse_ud {
  391. lua_State *L;
  392. gint cbref;
  393. GHashTable *tags;
  394. gboolean any;
  395. };
  396. static gboolean
  397. lua_html_node_foreach_cb (GNode *n, gpointer d)
  398. {
  399. struct lua_html_traverse_ud *ud = d;
  400. struct html_tag *tag = n->data, **ptag;
  401. if (tag && (ud->any || g_hash_table_lookup (ud->tags,
  402. GSIZE_TO_POINTER (mum_hash64 (tag->id, 0))))) {
  403. lua_rawgeti (ud->L, LUA_REGISTRYINDEX, ud->cbref);
  404. ptag = lua_newuserdata (ud->L, sizeof (*ptag));
  405. *ptag = tag;
  406. rspamd_lua_setclass (ud->L, "rspamd{html_tag}", -1);
  407. lua_pushinteger (ud->L, tag->content_length);
  408. if (lua_pcall (ud->L, 2, 1, 0) != 0) {
  409. msg_err ("error in foreach_tag callback: %s", lua_tostring (ud->L, -1));
  410. lua_pop (ud->L, 1);
  411. return TRUE;
  412. }
  413. if (lua_toboolean (ud->L, -1)) {
  414. lua_pop (ud->L, 1);
  415. return TRUE;
  416. }
  417. lua_pop (ud->L, 1);
  418. }
  419. return FALSE;
  420. }
  421. static gint
  422. lua_html_foreach_tag (lua_State *L)
  423. {
  424. LUA_TRACE_POINT;
  425. struct html_content *hc = lua_check_html (L, 1);
  426. struct lua_html_traverse_ud ud;
  427. const gchar *tagname;
  428. gint id;
  429. ud.tags = g_hash_table_new (g_direct_hash, g_direct_equal);
  430. ud.any = FALSE;
  431. if (lua_type (L, 2) == LUA_TSTRING) {
  432. tagname = luaL_checkstring (L, 2);
  433. if (strcmp (tagname, "any") == 0) {
  434. ud.any = TRUE;
  435. }
  436. else {
  437. id = rspamd_html_tag_by_name (tagname);
  438. if (id == -1) {
  439. g_hash_table_unref (ud.tags);
  440. return luaL_error (L, "invalid tagname: %s", tagname);
  441. }
  442. g_hash_table_insert (ud.tags, GSIZE_TO_POINTER (mum_hash64 (id, 0)),
  443. "1");
  444. }
  445. }
  446. else if (lua_type (L, 2) == LUA_TTABLE) {
  447. lua_pushvalue (L, 2);
  448. for (lua_pushnil (L); lua_next (L, -2); lua_pop (L, 1)) {
  449. tagname = luaL_checkstring (L, -1);
  450. if (strcmp (tagname, "any") == 0) {
  451. ud.any = TRUE;
  452. }
  453. else {
  454. id = rspamd_html_tag_by_name (tagname);
  455. if (id == -1) {
  456. g_hash_table_unref (ud.tags);
  457. return luaL_error (L, "invalid tagname: %s", tagname);
  458. }
  459. g_hash_table_insert (ud.tags,
  460. GSIZE_TO_POINTER (mum_hash64 (id, 0)), "1");
  461. }
  462. }
  463. lua_pop (L, 1);
  464. }
  465. if (hc && (ud.any || g_hash_table_size (ud.tags) > 0) && lua_isfunction (L, 3)) {
  466. if (hc->html_tags) {
  467. lua_pushvalue (L, 3);
  468. ud.cbref = luaL_ref (L, LUA_REGISTRYINDEX);
  469. ud.L = L;
  470. g_node_traverse (hc->html_tags, G_PRE_ORDER, G_TRAVERSE_ALL, -1,
  471. lua_html_node_foreach_cb, &ud);
  472. luaL_unref (L, LUA_REGISTRYINDEX, ud.cbref);
  473. }
  474. }
  475. else {
  476. g_hash_table_unref (ud.tags);
  477. return luaL_error (L, "invalid arguments");
  478. }
  479. g_hash_table_unref (ud.tags);
  480. return 0;
  481. }
  482. static gint
  483. lua_html_tag_get_type (lua_State *L)
  484. {
  485. LUA_TRACE_POINT;
  486. struct html_tag *tag = lua_check_html_tag (L, 1);
  487. const gchar *tagname;
  488. if (tag != NULL) {
  489. tagname = rspamd_html_tag_by_id (tag->id);
  490. if (tagname) {
  491. lua_pushstring (L, tagname);
  492. }
  493. else {
  494. lua_pushnil (L);
  495. }
  496. }
  497. else {
  498. return luaL_error (L, "invalid arguments");
  499. }
  500. return 1;
  501. }
  502. static gint
  503. lua_html_tag_get_parent (lua_State *L)
  504. {
  505. LUA_TRACE_POINT;
  506. struct html_tag *tag = lua_check_html_tag (L, 1), **ptag;
  507. GNode *node;
  508. if (tag != NULL) {
  509. node = tag->parent;
  510. if (node && node->data) {
  511. ptag = lua_newuserdata (L, sizeof (gpointer));
  512. *ptag = node->data;
  513. rspamd_lua_setclass (L, "rspamd{html_tag}", -1);
  514. }
  515. else {
  516. lua_pushnil (L);
  517. }
  518. }
  519. else {
  520. return luaL_error (L, "invalid arguments");
  521. }
  522. return 1;
  523. }
  524. static gint
  525. lua_html_tag_get_flags (lua_State *L)
  526. {
  527. LUA_TRACE_POINT;
  528. struct html_tag *tag = lua_check_html_tag (L, 1);
  529. gint i = 1;
  530. if (tag) {
  531. /* Push flags */
  532. lua_createtable (L, 4, 0);
  533. if (tag->flags & FL_CLOSING) {
  534. lua_pushstring (L, "closing");
  535. lua_rawseti (L, -2, i++);
  536. }
  537. if (tag->flags & FL_CLOSED) {
  538. lua_pushstring (L, "closed");
  539. lua_rawseti (L, -2, i++);
  540. }
  541. if (tag->flags & FL_BROKEN) {
  542. lua_pushstring (L, "broken");
  543. lua_rawseti (L, -2, i++);
  544. }
  545. if (tag->flags & FL_XML) {
  546. lua_pushstring (L, "xml");
  547. lua_rawseti (L, -2, i++);
  548. }
  549. if (tag->flags & RSPAMD_HTML_FLAG_UNBALANCED) {
  550. lua_pushstring (L, "unbalanced");
  551. lua_rawseti (L, -2, i++);
  552. }
  553. }
  554. else {
  555. return luaL_error (L, "invalid arguments");
  556. }
  557. return 1;
  558. }
  559. static gint
  560. lua_html_tag_get_content (lua_State *L)
  561. {
  562. LUA_TRACE_POINT;
  563. struct html_tag *tag = lua_check_html_tag (L, 1);
  564. struct rspamd_lua_text *t;
  565. if (tag) {
  566. if (tag->content && tag->content_length) {
  567. t = lua_newuserdata (L, sizeof (*t));
  568. rspamd_lua_setclass (L, "rspamd{text}", -1);
  569. t->start = tag->content;
  570. t->len = tag->content_length;
  571. t->flags = 0;
  572. }
  573. else {
  574. lua_pushnil (L);
  575. }
  576. }
  577. else {
  578. return luaL_error (L, "invalid arguments");
  579. }
  580. return 1;
  581. }
  582. static gint
  583. lua_html_tag_get_content_length (lua_State *L)
  584. {
  585. LUA_TRACE_POINT;
  586. struct html_tag *tag = lua_check_html_tag (L, 1);
  587. if (tag) {
  588. lua_pushinteger (L, tag->content_length);
  589. }
  590. else {
  591. return luaL_error (L, "invalid arguments");
  592. }
  593. return 1;
  594. }
  595. static gint
  596. lua_html_tag_get_extra (lua_State *L)
  597. {
  598. LUA_TRACE_POINT;
  599. struct html_tag *tag = lua_check_html_tag (L, 1);
  600. struct html_image *img;
  601. struct rspamd_url **purl;
  602. if (tag) {
  603. if (tag->extra) {
  604. if (tag->id == Tag_A || tag->id == Tag_IFRAME || tag->id == Tag_LINK) {
  605. /* For A that's URL */
  606. purl = lua_newuserdata (L, sizeof (gpointer));
  607. *purl = tag->extra;
  608. rspamd_lua_setclass (L, "rspamd{url}", -1);
  609. }
  610. else if (tag->id == Tag_IMG) {
  611. img = tag->extra;
  612. lua_html_push_image (L, img);
  613. }
  614. else if (tag->flags & FL_BLOCK) {
  615. lua_html_push_block (L, tag->extra);
  616. }
  617. else {
  618. /* Unknown extra ? */
  619. lua_pushnil (L);
  620. }
  621. }
  622. else {
  623. lua_pushnil (L);
  624. }
  625. }
  626. else {
  627. return luaL_error (L, "invalid arguments");
  628. }
  629. return 1;
  630. }
  631. void
  632. luaopen_html (lua_State * L)
  633. {
  634. rspamd_lua_new_class (L, "rspamd{html}", htmllib_m);
  635. lua_pop (L, 1);
  636. rspamd_lua_new_class (L, "rspamd{html_tag}", taglib_m);
  637. lua_pop (L, 1);
  638. }