os = require "os" socket = require "socket" ------------------------------------------------------------------------------ -- config and handling -- ------------------------------------------------------------------------------ function shortname() -- -- Short hostname -- local long = socket.dns.gethostname() return string.gmatch(long, '[^.]+')() end function file_exists(name) -- -- True if file *name* exists -- local f = io.open(name,"r") if f ~= nil then io.close(f) return true else return false end end function init_host(session) -- -- Do host-specific init, if exists -- local init = session.dirs.host .. "/init.lua" if file_exists(init) then dofile(init) return end end function handle(session) -- -- Look for action handler in session dirs; do first one that exists -- local valid = { newmail = true, rewind = true, cleanup = true, migrate = true } if not valid[session.action] then error("invalid action: " .. session.action) return nil end init_host(session) for k,v in ipairs({session.dirs.host, session.dirs.default}) do attempt = v .. "/handlers/" .. session.action .. ".lua" if file_exists(attempt) then dofile(attempt) return end end end ------------------------------------------------------------------------------ -- mail getters -- ------------------------------------------------------------------------------ function get_queue(acct, mbox) -- -- Get queue from *mbox* from *acct* or nil (no messages) -- -- If mbox is not specified, "FILTER_QUEUE" is used -- mbox = mbox or "FILTER_QUEUE" local exist, unread, unseen, uidnext = acct[mbox]:check_status() if exist > 0 then return acct[mbox]:select_all() end return nil end function _notifirc1(subj, from, body) -- -- notify about message using (pre-configured) notifirc -- local fd = assert(io.popen('notifirc -c mail -f - "message preview:"', "w")) local fmt = "> %s\n> %s\n> BODY: %s" fd:write(fmt:format(subj, from, body)) fd:close() end function notifirc_all(seq) -- -- Send notifications about all messages in *seq* -- for _, mesg in ipairs(seq) do mbox, uid = table.unpack(mesg) subj = mbox[uid]:fetch_field('Subject') from = mbox[uid]:fetch_field('From') body = mbox[uid]:fetch_body() _notifirc1(subj, from, body) end end function _partinf_compare(a, b) if not type(a) == type(b) then return false end if type(a) == 'number' then return a == b elseif type(a) == 'string' then return a:lower() == b:lower() end end function has_part_like(query, structure) -- -- True if structure has MIME part matching *query* -- if structure == nil then return false end for partid, partinf in pairs(structure) do local part_answer = true -- check all query parts for qkey, qvalue in pairs(query) do value = partinf[qkey] if not _partinf_compare(value, qvalue) then part_answer = false break end end if part_answer then return true end end return false end function save_header(mesg, name) -- -- Append header from *mesg* to file named *name* -- -- File will be placed under directory specified by IMAPDOMO_HEADERS -- environment variable. -- local dest = os.getenv("IMAPDOMO_HEADERS") .. '/' .. name local cmd = ('cat >>"%q"'):format(dest) mbox, uid = table.unpack(mesg) header = mbox[uid]:fetch_header() if pipe_to(cmd, header) == 0 then return true else return false end end function filter_header_saved(seq, name) -- -- Save headers from sequence -- -- Append header of each message in sequence *seq* to file names -- *name* and return new sequence with those messages where save was -- successful. -- result = Set {} for _, mesg in ipairs(seq) do if save_header(mesg, name) then table.insert(result, mesg) end end return result end function filter_part_like(query, seq) -- -- Run MIME part query on *seq* sequence of messages -- result = Set {} for _, mesg in ipairs(seq) do mbox, uid = table.unpack(mesg) structure = mbox[uid]:fetch_structure() if has_part_like(query, structure) then table.insert(result, mesg) end end return result end