Skip to content

Instantly share code, notes, and snippets.

@fermino
Last active May 29, 2026 22:35
Show Gist options
  • Select an option

  • Save fermino/7d0aedcdde282153730b796b4b1401b3 to your computer and use it in GitHub Desktop.

Select an option

Save fermino/7d0aedcdde282153730b796b4b1401b3 to your computer and use it in GitHub Desktop.
PCRE2 matching for UTF-8 encoded fields on imapfilter
-- This requires the base64 module from https://github.com/iskolbin/lbase64
-- Other base64 modules had issues working from within IMAPFilter
-- Modified to use lrexlib-pcre2
-- See https://github.com/lefcha/imapfilter/issues/127
rex = require 'rex_pcre2'
base64 = require 'base64'
local methods = {}
-- Decode a field value that might be base64 encoded utf-8 (like Gmail returns)
function methods.decode_utf8_field(value, field_name)
if value then
local field_prefix = ''
if field_name then
field_prefix = ('%s: '):format(field_name)
end
local return_value = ''
local value_start = value:sub(1 + field_prefix:len(), 8 + field_prefix:len())
if value_start == '=?UTF-8?' or value_start == '=?utf-8?' then
value = value:sub(field_prefix:len(), value:len())
for part in string.gmatch(value, ' ?=[?][Uu][Tt][Ff][-]8[?]([BbQq][?].-)[?]=') do
local part_type = part:sub(1, 1)
local part_value = part:sub(3)
if (part_type == 'B' or part_type == 'b') then
part_value = base64.decode(part_value)
end
if (part_type == 'Q' or part_type == 'q') then
part_value = part_value:gsub('_', ' ')
part_value = part_value:gsub('=(%x%x)', function(hex)
return string.char(tonumber(hex, 16))
end)
end
return_value = return_value .. part_value
end
else
return_value = value:sub(field_prefix:len(), value:len())
end
return return_value
end
end
-- Return messages that match `pattern` in the `field` header field.
-- Unlike the standard `match_field`, this one works with base64 encoded UTF-8 fields
function methods.match_utf8_field(messages, field, pattern)
local results = {}
local regexp = rex.new(pattern)
for m, message in ipairs(messages) do
local mailbox, uid = table.unpack(message)
value = mailbox[uid]:fetch_field(field)
value = methods.decode_utf8_field(value, field)
if (regexp:match(value)) then
table.insert(results, { mailbox, uid })
end
end
return Set(results)
end
return methods
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment