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