Some answers to my questions, a first version of my script and more questions ;)

Am 03.08.20 um 18:15 schrieb Ralf Becker:

Currently looking into the following questions:

- can I get the rfc 5423 type of event somehow (obviously I can set it on the event myself depending of the function called)
event.name
- looking at the example code, it looks like it can be called for multiple messages, when does that happen (LMTP send more then one)

still no idea, maybe Ake?

I noticed that some events have the same uid-validity, are the from a single transaction, eg. I delete my Trash?

- why is the mailbox status put into an other structure and send with a different notifiction
- does anyone have a code snippet to send a JSON encoded message (probably easy to figure out looking at Lua docu)

these two I managed to solve im my current version of the script, which also support now all message event types:

-- To use
--
-- plugin {
--  push_notification_driver = lua:file=/etc/dovecot/dovecot-push.lua
--  push_lua_url = http://push.notification.server/handler
-- }
--
-- server is sent a PUT message with JSON body like push_notification_driver = ox:url=<push_lua_url> user_from_metadata
--

local http = require "socket.http"
local ltn12 = require "ltn12"
-- luarocks install json-lua
local json = require "JSON"

function table_get(t, k, d)
  return t[k] or d
end

function script_init()
  return 0
end

function dovecot_lua_notify_begin_txn(user)
    local meta = user:metadata_get("/private/vendor/vendor.dovecot/http-notify")
    return {user=user, event=dovecot.event(), ep=user:plugin_getenv("push_lua_url"), messages={}, meta=meta}
end

function dovecot_lua_notify_event_message_new(ctx, event)
    -- check if there is a push token registered
    if (ctx.meta == nil or ctx.meta == '') then
    return
    end
    -- get mailbox status
    local mbox = ctx.user:mailbox(event.mailbox)
    mbox:sync()
    local status = mbox:status(dovecot.storage.STATUS_RECENT, dovecot.storage.STATUS_UNSEEN, dovecot.storage.STATUS_MESSAGES)
    mbox:free()
    table.insert(ctx.messages, {
      user = ctx.meta,
      ["imap-uidvalidity"] = event.uid_validity,
      ["imap-uid"] = event.uid,
      folder = event.mailbox,
      event = event.name,
      from = event.from,
      subject = event.subject,
      snippet = event.snippet,
      unseen = status.unseen
    })
end

function dovecot_lua_notify_event_message_append(ctx, event)
  dovecot_lua_notify_event_message_new(ctx, event)
end

function dovecot_lua_notify_event_message_read(ctx, event)
    -- check if there is a push token registered
    if (ctx.meta == nil or ctx.meta == '') then
        return
    end
    -- get mailbox status
    local mbox = ctx.user:mailbox(event.mailbox)
    mbox:sync()
    local status = mbox:status(dovecot.storage.STATUS_RECENT, dovecot.storage.STATUS_UNSEEN, dovecot.storage.STATUS_MESSAGES)
    mbox:free()
    table.insert(ctx.messages, {
        user = ctx.meta,
        ["imap-uidvalidity"] = event.uid_validity,
        ["imap-uid"] = event.uid,
        folder = event.mailbox,
        event = event.name,
        unseen = status.unseen
    })
end

function dovecot_lua_notify_event_message_trash(ctx, event)
    dovecot_lua_notify_event_message_read(ctx, event)
end

function dovecot_lua_notify_event_message_expunge(ctx, event)
    dovecot_lua_notify_event_message_read(ctx, event)
end

function dovecot_lua_notify_event_flags_set(ctx, event)
    -- check if there is a push token registered
    if (ctx.meta == nil or ctx.meta == '') then
        return
    end
    table.insert(ctx.messages, {
        user = ctx.meta,
        ["imap-uidvalidity"] = event.uid_validity,
        ["imap-uid"] = event.uid,
        folder = event.mailbox,
        event = event.name,
        flags = event.flags,
        ["keywords-set"] = event.keywords_set
    })
end

function dovecot_lua_notify_event_flags_clear(ctx, event)
    -- check if there is a push token registered
    if (ctx.meta == nil or ctx.meta == '') then
        return
    end
    table.insert(ctx.messages, {
        user = ctx.meta,
        ["imap-uidvalidity"] = event.uid_validity,
        ["imap-uid"] = event.uid,
        folder = event.mailbox,
        event = event.name,
        flags = event.flags,
        ["keywords-clear"] = event.keywords_clear,
        ["keywords-old"] = event.keywords_old
    })
end

function dovecot_lua_notify_end_txn(ctx)
    -- report all states
    for i,msg in ipairs(ctx.messages) do
    local e = dovecot.event(ctx.event)
    e:set_name("lua_notify_mail_finished")
    reqbody = json:encode(msg)
    e:log_debug(ctx.ep .. " - sending " .. reqbody)
    res, code = http.request({
        method = "PUT",
        url = ctx.ep,
        source = ltn12.source.string(reqbody),
        headers={
            ["content-type"] = "application/json; charset=utf-8",
            ["content-length"] = tostring(#reqbody)
        }
    })
    e:add_int("result_code", code)
    e:log_info("Mail notify status " .. tostring(code))
    end
end


This leads to a couple more questions ;)

- is there a way (eg. return value) to stop event processing already in dovecot_lua_notify_begin_txn

- sometimes multiple events are generated, eg. when I read an email:

{"event":"FlagsClear","flags":[],"folder":"INBOX/eGroupWare/calconnect","imap-uid":2275,"imap-uidvalidity":1499767470,"keywords-old":[],"user":"user=5::42;***"}
{"event":"FlagsSet","flags":["\\Seen"],"folder":"INBOX/eGroupWare/calconnect","imap-uid":2275,"imap-uidvalidity":1499767470,"user":"user=5::42;***"}
{"event":"MessageRead","folder":"INBOX/eGroupWare/calconnect","imap-uid":2275,"imap-uidvalidity":1499767470,"unseen":0,"user":"user=5::42;***"}

Ralf

-- 
Ralf Becker
EGroupware GmbH [www.egroupware.org]
Handelsregister HRB Kaiserslautern 3587
Geschäftsführer Birgit und Ralf Becker
Leibnizstr. 17, 67663 Kaiserslautern, Germany
Telefon +49 631 31657-0