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.

ical.lua 2.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. --[[
  2. Copyright (c) 2022, Vsevolod Stakhov <vsevolod@rspamd.com>
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ]]--
  13. local l = require 'lpeg'
  14. local lua_util = require "lua_util"
  15. local N = "lua_content"
  16. local ical_grammar
  17. local function gen_grammar()
  18. if not ical_grammar then
  19. local wsp = l.S(" \t\v\f")
  20. local crlf = (l.P"\r"^-1 * l.P"\n") + l.P"\r"
  21. local eol = (crlf * #crlf) + (crlf - (crlf^-1 * wsp))
  22. local name = l.C((l.P(1) - (l.P":"))^1) / function(v) return (v:gsub("[\n\r]+%s","")) end
  23. local value = l.C((l.P(1) - eol)^0) / function(v) return (v:gsub("[\n\r]+%s","")) end
  24. ical_grammar = name * ":" * wsp^0 * value * eol^-1
  25. end
  26. return ical_grammar
  27. end
  28. local exports = {}
  29. local function extract_text_data(specific)
  30. local fun = require "fun"
  31. local tbl = fun.totable(fun.map(function(e) return e[2]:lower() end, specific.elts))
  32. return table.concat(tbl, '\n')
  33. end
  34. -- Keys that can have visible urls
  35. local url_keys = lua_util.list_to_hash{
  36. 'description',
  37. 'location',
  38. 'summary',
  39. 'organizer',
  40. 'organiser',
  41. 'attendee',
  42. 'url'
  43. }
  44. local function process_ical(input, mpart, task)
  45. local control={n='\n', r=''}
  46. local rspamd_url = require "rspamd_url"
  47. local escaper = l.Ct((gen_grammar() / function(key, value)
  48. value = value:gsub("\\(.)", control)
  49. key = key:lower():match('^([^;]+)')
  50. if key and url_keys[key] then
  51. local local_urls = rspamd_url.all(task:get_mempool(), value)
  52. if local_urls and #local_urls > 0 then
  53. for _,u in ipairs(local_urls) do
  54. lua_util.debugm(N, task, 'ical: found URL in ical key "%s": %s',
  55. key, tostring(u))
  56. task:inject_url(u, mpart)
  57. end
  58. end
  59. end
  60. lua_util.debugm(N, task, 'ical: ical key %s = "%s"',
  61. key, value)
  62. return {key, value}
  63. end)^1)
  64. local elts = escaper:match(input)
  65. if not elts then
  66. return nil
  67. end
  68. return {
  69. tag = 'ical',
  70. extract_text = extract_text_data,
  71. elts = elts
  72. }
  73. end
  74. --[[[
  75. -- @function lua_ical.process(input)
  76. -- Returns all values from ical as a plain text. Names are completely ignored.
  77. --]]
  78. exports.process = process_ical
  79. return exports