imapfilter convenience wrapper

common.lua 5.4KB

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