~cybolic/Dotfiles

Dotfiles/imapfilter/.imapfilter/_rules.lua -rw-r--r-- 5.5 KiB
1e622b91 — Christian Dannie Storgaard Added dunst config 2 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
local verbose = true
local methods = {}

function methods.run_filter_method_per_value(messages, method, values)
  if #messages == 0 then return Set({}) end
  local result = Set({})
  local _messages = Set(messages)

  for _, value in ipairs(values) do
    local method_result = methods.run_filter_method(_messages, method, value)
    -- On first loop, set to result
    if result == nil then
      result = method_result
    -- On subsequent loops, AND the result list down
    else
      result = result * method_result
    end
    -- Limit any further message filters to sub-results
    _messages = Set(result)
  end

  return result
end

function methods.run_filter_method(messages, method, value)
  if messages == nil then error("messages can't be nil", 2) end
  if type(messages) ~= 'table' then error("messages should be a table", 2) end
  if #messages == 0 then return Set({}) end

  if type(value) == 'table' then
    if method == 'contain_field' or method == 'match_field' then
      if not messages[method] then error(("Unknown filter method: %s"):format(method), 2) end
      return messages[method](messages, unpack(value))
    elseif method == 'match_utf8_field' then
      return shared.match_utf8_field(messages, unpack(value))
    else
      return methods.run_filter_method_per_value(messages, method, value)
    end
  else
    if method == 'match_utf8_body' then
      return shared.match_utf8_body(messages, value)
    else
      if not messages[method] then error(("unknown filter method: %s"):format(method), 2) end
      return messages[method](messages, value)
    end
  end
end

function methods.run_filter(messages, filters)
  if #messages == 0 then return Set({}) end
  local result
  for method, value in pairs(filters) do
    local filter_result = methods.run_filter_method(messages, method, value)
    if verbose and #filter_result then print(('    Filter "%s" gave %i results'):format(method, #filter_result)) end
    -- On first loop, set to result
    if result == nil then
      result = filter_result
    -- On subsequent loops, AND the result list down
    else
      result = result * filter_result
    end
  end
  return result or Set({})
end

function methods.run_rule(messages, rule, destination_mailbox)
  local from_filter
  local rule_name
  local rule_filters
  local move_to
  local flag = false
  local delete = false

  for key, value in pairs(rule) do
    if key == 'from' then
      from_filter = value
    elseif key == 'move_to' then
      move_to = value
    elseif key == 'flag' then
      flag = true
    elseif key == 'delete' then
      delete = true
    else
      rule_name = key
    end
  end

  local _messages
  if from_filter and next(from_filter) then
    _messages = methods.run_filter(messages, from_filter)
      if #_messages == 0 then return Set({}) end
    -- local from_values = {}
    -- for k,v in pairs(from_filter) do table.insert(from_values, v) end
    -- print(("Limited search to %i from %s, out of the original %i"):format(
    --   #_messages, table.concat(from_values, ', '),
    --   #_messages
    -- ))
  else
    -- Make sure we're not operating on a reference to the total messages
    _messages = Set(messages)
    -- print(("Searching %i messages"):format(#_messages))
  end

  io.write(("%s..."):format(rule_name))
  if verbose then io.write("\n") end

  local rule_results = Set({})
  -- No rules? Just use the given messages / `from` filtered ones
  if next(rule[rule_name]) == nil then
    if verbose then print("  No rules defined, returning input/from") end
    rule_results = _messages
  else
    for i, filters in ipairs(rule[rule_name]) do
      local subresult = methods.run_filter(_messages, filters)
      if verbose then print(("  Found %i messages from %i"):format(#subresult, #_messages)) end
      rule_results = rule_results + subresult
      -- Limit any further message filters to sub-results
      _messages = _messages - subresult
      if verbose then print(("  Remaining messages count is now %i"):format(#_messages)) end
    end
  end

  if #rule_results > 0 then
    io.write(("\tfound %i\n"):format(#rule_results))
    -- print(("%s...\tfound %i\n"):format(rule_name, #rule_results))
  else
    io.write("\n")
  end

  if #rule_results > 0 then
    if flag == true then
      if dry_run then
        print(('%s:mark_flagged()\n'):format(rule_name))
      else
        print("  Marking messages as flagged (important)")
        rule_results:mark_flagged()
        shared.mark_processed(rule_results)
      end
    end
    if move_to and destination_mailbox then
      if dry_run then
        print(('%s:move_messages("%s")\n'):format(rule_name, move_to))
      else
        print(("  Moving messages to %s"):format(move_to))
        rule_results:move_messages(destination_mailbox[move_to])
      end
    elseif delete == true then
      if dry_run then
        print(('%s:mark_deleted()\n'):format(rule_name))
      else
        print("  Marking messages for deletion")
        rule_results:mark_deleted()
      end
    end
    shared.printMessages(rule_results)
  end
  return rule_results
end

function methods.run_rules(messages, rules, destination_mailbox)
  if type(messages) ~= 'table' then error("messages should be a table", 2) end
  if #messages == 0 then return Set({}) end

  local all_results = Set({})
  for rule_index, rule in ipairs(rules) do
    -- Don't re-process previous matches
    local _messages = messages - all_results
    local rule_results = methods.run_rule(_messages, rule, destination_mailbox)
    all_results = all_results + rule_results
  end
  return all_results
end

return methods