imapfilter convenience wrapper

common.lua 4.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  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 = "handlers/" .. action .. ".lua"
  33. local valid = {
  34. newmail = true,
  35. rewind = true,
  36. cleanup = true,
  37. migrate = true
  38. }
  39. if file_exists(file) then
  40. do_if_exists("init.lua")
  41. dofile(file)
  42. else
  43. error("no handler for action: " .. action)
  44. return nil
  45. end
  46. end
  47. ------------------------------------------------------------------------------
  48. -- mail getters --
  49. ------------------------------------------------------------------------------
  50. function get_queue(acct, mbox)
  51. --
  52. -- Get queue from *mbox* from *acct* or nil (no messages)
  53. --
  54. -- If mbox is not specified, "FILTER_QUEUE" is used
  55. --
  56. mbox = mbox or "FILTER_QUEUE"
  57. local exist, unread, unseen, uidnext = acct[mbox]:check_status()
  58. if exist > 0 then
  59. return acct[mbox]:select_all()
  60. end
  61. return nil
  62. end
  63. function _notifirc1(subj, from, body)
  64. --
  65. -- notify about message using (pre-configured) notifirc
  66. --
  67. local fd = assert(io.popen('notifirc -c mail -f - "message preview:"', "w"))
  68. local fmt = "> %s\n> %s\n> BODY: %s"
  69. fd:write(fmt:format(subj, from, body))
  70. fd:close()
  71. end
  72. function notifirc_all(seq)
  73. --
  74. -- Send notifications about all messages in *seq*
  75. --
  76. for _, mesg in ipairs(seq) do
  77. mbox, uid = table.unpack(mesg)
  78. subj = mbox[uid]:fetch_field('Subject')
  79. from = mbox[uid]:fetch_field('From')
  80. body = mbox[uid]:fetch_body()
  81. _notifirc1(subj, from, body)
  82. end
  83. end
  84. function _partinf_compare(a, b)
  85. if not type(a) == type(b) then
  86. return false
  87. end
  88. if type(a) == 'number' then
  89. return a == b
  90. elseif type(a) == 'string' then
  91. return a:lower() == b:lower()
  92. end
  93. end
  94. function has_part_like(query, structure)
  95. --
  96. -- True if structure has MIME part matching *query*
  97. --
  98. if structure == nil then
  99. return false
  100. end
  101. for partid, partinf in pairs(structure) do
  102. local part_answer = true
  103. -- check all query parts
  104. for qkey, qvalue in pairs(query) do
  105. value = partinf[qkey]
  106. if not _partinf_compare(value, qvalue) then
  107. part_answer = false
  108. break
  109. end
  110. end
  111. if part_answer then
  112. return true
  113. end
  114. end
  115. return false
  116. end
  117. function save_header(mesg, name)
  118. --
  119. -- Append header from *mesg* to file named *name*
  120. --
  121. -- File will be placed under directory specified by IMAPDOMO_HEADERS
  122. -- environment variable.
  123. --
  124. local dest = os.getenv("IMAPDOMO_HEADERS") .. '/' .. name
  125. local cmd = ('cat >>"%q"'):format(dest)
  126. mbox, uid = table.unpack(mesg)
  127. header = mbox[uid]:fetch_header()
  128. if pipe_to(cmd, header) == 0 then
  129. return true
  130. else
  131. return false
  132. end
  133. end
  134. function filter_header_saved(seq, name)
  135. --
  136. -- Save headers from sequence
  137. --
  138. -- Append header of each message in sequence *seq* to file names
  139. -- *name* and return new sequence with those messages where save was
  140. -- successful.
  141. --
  142. result = Set {}
  143. for _, mesg in ipairs(seq) do
  144. if save_header(mesg, name) then
  145. table.insert(result, mesg)
  146. end
  147. end
  148. return result
  149. end
  150. function filter_part_like(query, seq)
  151. --
  152. -- Run MIME part query on *seq* sequence of messages
  153. --
  154. result = Set {}
  155. for _, mesg in ipairs(seq) do
  156. mbox, uid = table.unpack(mesg)
  157. structure = mbox[uid]:fetch_structure()
  158. if has_part_like(query, structure) then
  159. table.insert(result, mesg)
  160. end
  161. end
  162. return result
  163. end