imapfilter convenience wrapper

common.lua 5.4KB

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