imapfilter convenience wrapper

imapdomo.lua 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. local pkg = {}
  2. ------------------------------------------------------------------------------
  3. -- config and handling --
  4. ------------------------------------------------------------------------------
  5. pkg.load_mailboxes = function()
  6. --
  7. -- Load mailboxes from $IMAPDOMO_CFGDIR/mailboxes.lua
  8. --
  9. local fname = os.getenv("IMAPDOMO_CFGDIR") .. '/mailboxes.lua'
  10. assert(pkg.file_exists(fname))
  11. return dofile(fname)
  12. end
  13. pkg.file_exists = function(name)
  14. --
  15. -- True if file *name* exists
  16. --
  17. local f = io.open(name,"r")
  18. if f ~= nil then
  19. io.close(f)
  20. return true
  21. else
  22. return false
  23. end
  24. end
  25. pkg.do_if_exists = function (filename)
  26. --
  27. -- Do file from home, if exists
  28. --
  29. local file = os.getenv("IMAPFILTER_HOME") .. "/" .. filename
  30. if pkg.file_exists(file) then
  31. dofile(file)
  32. return
  33. end
  34. end
  35. pkg.handle = function()
  36. --
  37. -- Handle action if it's valid
  38. --
  39. local action = os.getenv("IMAPDOMO_ACTION")
  40. local file = os.getenv("IMAPFILTER_HOME") .. "/handlers/" .. action .. ".lua"
  41. if pkg.file_exists(file) then
  42. pkg.do_if_exists("init.lua")
  43. dofile(file)
  44. else
  45. error("no handler for action: " .. action)
  46. return nil
  47. end
  48. end
  49. ------------------------------------------------------------------------------
  50. -- mail getters --
  51. ------------------------------------------------------------------------------
  52. pkg.get_queue = function(acct, mbox)
  53. --
  54. -- Get queue from *mbox* from *acct* or nil (no messages)
  55. --
  56. -- If mbox is not specified, "FILTER_QUEUE" is used
  57. --
  58. mbox = mbox or "FILTER_QUEUE"
  59. local exist = acct[mbox]:check_status()
  60. if exist > 0 then
  61. return acct[mbox]:select_all()
  62. end
  63. return nil
  64. end
  65. pkg._notifirc1 = function(subj, from, body)
  66. --
  67. -- notify about message using (pre-configured) notifirc
  68. --
  69. local fd = assert(io.popen('notifirc -c mail -f - "message preview:"', "w"))
  70. local fmt = "> %s\n> %s\n> BODY: %s"
  71. fd:write(fmt:format(subj, from, body))
  72. fd:close()
  73. end
  74. pkg.notifirc_all = function(seq)
  75. --
  76. -- Send notifications about all messages in *seq*
  77. --
  78. for _, mesg in ipairs(seq) do
  79. local mbox, uid, subj, from, body
  80. mbox, uid = table.unpack(mesg)
  81. subj = mbox[uid]:fetch_field('Subject')
  82. from = mbox[uid]:fetch_field('From')
  83. body = mbox[uid]:fetch_body()
  84. pkg._notifirc1(subj, from, body)
  85. end
  86. end
  87. pkg.hook_all = function(seq, hname, ...)
  88. --
  89. -- Call hook hname for all messages in seq
  90. --
  91. local hfile = os.getenv("IMAPFILTER_HOME") .. "/hooks/" .. hname
  92. local hargs = {...}
  93. local hcmd = hfile
  94. local fmt = ' %q'
  95. if pkg.file_exists(hfile) then
  96. for _, harg in pairs(hargs) do
  97. hcmd = hcmd .. fmt:format(harg)
  98. end
  99. for _, mesg in ipairs(seq) do
  100. local mbox, uid, subj, body, from, to, date
  101. mbox, uid = table.unpack(mesg)
  102. subj = mbox[uid]:fetch_field('Subject')
  103. from = mbox[uid]:fetch_field('From')
  104. to = mbox[uid]:fetch_field('To')
  105. date = mbox[uid]:fetch_field('Date')
  106. body = mbox[uid]:fetch_body()
  107. pkg._hook1(hcmd, subj, from, to, date, body)
  108. end
  109. else
  110. error("no such hook: " .. hname)
  111. return nil
  112. end
  113. end
  114. pkg._hook1 = function(hcmd, subj, from, to, date, body)
  115. --
  116. -- push message through hook script
  117. --
  118. local fd = assert(io.popen(hcmd, "w"))
  119. local fmt = "subj=%s\nfrom=%s\nto=%s\ndate=%s\n%s"
  120. fd:write(fmt:format(subj, from, to, date, body))
  121. fd:close()
  122. end
  123. pkg._partinf_compare = function(a, b)
  124. if not type(a) == type(b) then
  125. return false
  126. end
  127. if type(a) == 'number' then
  128. return a == b
  129. elseif type(a) == 'string' then
  130. return a:lower() == b:lower()
  131. end
  132. end
  133. pkg.has_part_like = function(query, structure)
  134. --
  135. -- True if structure has MIME part matching *query*
  136. --
  137. if structure == nil then
  138. return false
  139. end
  140. for partid, partinf in pairs(structure) do
  141. local part_answer = true
  142. -- check all query parts
  143. for qkey, qvalue in pairs(query) do
  144. local value = partinf[qkey]
  145. if not pkg._partinf_compare(value, qvalue) then
  146. part_answer = false
  147. break
  148. end
  149. end
  150. if part_answer then
  151. return true
  152. end
  153. end
  154. return false
  155. end
  156. pkg.save_header = function(mesg, name)
  157. --
  158. -- Append header from *mesg* to file named *name*
  159. --
  160. -- File will be placed under directory specified by IMAPDOMO_HEADERS
  161. -- environment variable.
  162. --
  163. local dest = os.getenv("IMAPDOMO_HEADERS") .. '/' .. name
  164. local cmd = ('cat >>"%q"'):format(dest)
  165. local mbox, uid = table.unpack(mesg)
  166. local header = mbox[uid]:fetch_header()
  167. if pkg.pipe_to(cmd, header) == 0 then
  168. return true
  169. else
  170. return false
  171. end
  172. end
  173. pkg.filter_header_saved = function(seq, name)
  174. --
  175. -- Save headers from sequence
  176. --
  177. -- Append header of each message in sequence *seq* to file names
  178. -- *name* and return new sequence with those messages where save was
  179. -- successful.
  180. --
  181. local result = {}
  182. for _, mesg in ipairs(seq) do
  183. if pkg.save_header(mesg, name) then
  184. table.insert(result, mesg)
  185. end
  186. end
  187. return result
  188. end
  189. pkg.filter_part_like = function(query, seq)
  190. --
  191. -- Run MIME part query on *seq* sequence of messages
  192. --
  193. local result = {}
  194. for _, mesg in ipairs(seq) do
  195. local mbox, uid = table.unpack(mesg)
  196. local structure = mbox[uid]:fetch_structure()
  197. if pkg.has_part_like(query, structure) then
  198. table.insert(result, mesg)
  199. end
  200. end
  201. return result
  202. end
  203. return pkg