Skip to content

Usefull Lua code snippets for configurations

Doron Behar edited this page Jun 22, 2019 · 2 revisions

This page, is meant for users of imapfilter to add Lua code snippets which may come useful for everyone when writing their config.lua.

Getting all messages in a thread

Say you are running imapfilter with something along the lines of:

my_message = account["my-folder"]:contain_from("my@email.com")
for _, message in ipairs(my_messages) do
    local mailbox, uid = table.unpack(message)
    if mailbox[uid]:fetch_field("X-my-header") == "something" then
        -- do something
    end
end

You might find yourself in a need to fetch all messages which are linked to the thread of this message. To do that, you'll need to recursively search for all messages with a In-Reply-To header identical to this message Message-ID header and for every message hit with any of those headers' values, you'll need to do the same to make sure you've hit the whole thread - That's why it's recursive.

A request for such a function to be included in the standard library was made in #177 but since it's rather complicated and since it'd probably be hard to maintain, the request was rejected.

However, @doronbehar who is the initial writer of this WiKi page :), has implemented this function and commented with an example usage of it in #177. Here's the most updated version of this function:

local function get_message_id(msg)
	local id = msg:fetch_field("Message-ID"):gsub("[Mm]essage%-[Ii][Dd]: ", "")
	return id
end
local function get_reply_id(msg)
	local id = msg:fetch_field("In-Reply-To"):gsub("[Ii]n%-[Rr]eply%-[Tt]o: ", "")
	return id
end
function thread_messages(msg, mbox, related_messages, examined_ids)
	-- initilize examined_ids in case it's the first call of this function
	if not examined_ids then examined_ids = {} end
	-- This message
	local this_msgid = get_message_id(msg)
	table.insert(examined_ids, this_msgid)
	local this_message = mbox:match_field("Message-ID", this_msgid)
	-- The messages directly replyed to our `msg`
	local currently_related_messages = mbox:match_field("In-Reply-To", this_msgid)
	if related_messages then
		related_messages = related_messages + currently_related_messages
	else
		related_messages = currently_related_messages
	end
	-- The messages our `msg` was replyed to
	local prev_msgid = get_reply_id(msg)
	if string.len(prev_msgid) > 1 then
		related_messages = related_messages + mbox:match_field("Message-ID", prev_msgid)
	end
	-- Recursively add up messages related in the same way to the related_messages
	for _, related_msg in ipairs(related_messages) do
		local mailbox_related, uid_related = table.unpack(related_msg)
		local related_msgid = get_message_id(mailbox_related[uid_related])
		-- will check for every known related message if the messages replyed to `related_msgid` have been examined
		local skip = false
		for i=1,#examined_ids do
			if related_msgid == examined_ids[i] then
				skip = true
			end
		end
		if not skip then
			related_messages = related_messages + thread_messages(mailbox_related[uid_related], mbox, related_messages, examined_ids)
		end
	end
	return related_messages + this_message
end

You can use it as so:

local mbox = account[mailbox_name]
local my_messages = mbox:contain_from("my@email.com")
for _, message in ipairs(my_messages) do
    local mailbox, uid = table.unpack(message)
    local my_related_messages = thread_messages(mailbox[uid], mbox)
    my_related_messages:copy_messages(account[another_mailbox_name])
end