|
@@ -0,0 +1,149 @@
|
|
1
|
+os = require "os"
|
|
2
|
+socket = require "socket"
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+------------------------------------------------------------------------------
|
|
6
|
+-- config and handling --
|
|
7
|
+------------------------------------------------------------------------------
|
|
8
|
+
|
|
9
|
+function shortname()
|
|
10
|
+ --
|
|
11
|
+ -- Short hostname
|
|
12
|
+ --
|
|
13
|
+ local long = socket.dns.gethostname()
|
|
14
|
+ return string.gmatch(long, '[^.]+')()
|
|
15
|
+end
|
|
16
|
+
|
|
17
|
+function file_exists(name)
|
|
18
|
+ --
|
|
19
|
+ -- True if file *name* exists
|
|
20
|
+ --
|
|
21
|
+ local f=io.open(name,"r")
|
|
22
|
+ if f~=nil then io.close(f) return true else return false end
|
|
23
|
+end
|
|
24
|
+
|
|
25
|
+function init_host()
|
|
26
|
+ --
|
|
27
|
+ -- Look for action handler in basepaths; do first one
|
|
28
|
+ --
|
|
29
|
+ local init = imapdomo.dirs.host .. "/init.lua"
|
|
30
|
+ if file_exists(init) then
|
|
31
|
+ dofile(init)
|
|
32
|
+ return
|
|
33
|
+ end
|
|
34
|
+end
|
|
35
|
+
|
|
36
|
+function handle(action, basepaths)
|
|
37
|
+ --
|
|
38
|
+ -- Look for action handler in basepaths; do first one
|
|
39
|
+ --
|
|
40
|
+ local valid = {
|
|
41
|
+ newmail = true,
|
|
42
|
+ rewind = true,
|
|
43
|
+ cleanup = true
|
|
44
|
+ }
|
|
45
|
+ if not valid[action] then
|
|
46
|
+ error("invalid action: " .. action)
|
|
47
|
+ return nil
|
|
48
|
+ end
|
|
49
|
+ init_host()
|
|
50
|
+ for k,v in ipairs({imapdomo.dirs.host, imapdomo.dirs.default}) do
|
|
51
|
+ attempt = v .. "/handlers/" .. action .. ".lua"
|
|
52
|
+ if file_exists(attempt) then
|
|
53
|
+ dofile(attempt)
|
|
54
|
+ return
|
|
55
|
+ end
|
|
56
|
+ end
|
|
57
|
+end
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+------------------------------------------------------------------------------
|
|
61
|
+-- mail getters --
|
|
62
|
+------------------------------------------------------------------------------
|
|
63
|
+
|
|
64
|
+function get_queue(acct, mbox)
|
|
65
|
+ --
|
|
66
|
+ -- Get queue from *mbox* from *acct* or nil (no messages)
|
|
67
|
+ --
|
|
68
|
+ -- If mbox is not specified, "FILTER_QUEUE" is used
|
|
69
|
+ --
|
|
70
|
+ mbox = mbox or "FILTER_QUEUE"
|
|
71
|
+ local exist, unread, unseen, uidnext = acct[mbox]:check_status()
|
|
72
|
+ if exist > 0 then
|
|
73
|
+ return acct[mbox]:select_all()
|
|
74
|
+ end
|
|
75
|
+ return nil
|
|
76
|
+end
|
|
77
|
+
|
|
78
|
+function _notifirc1(subj, from, body)
|
|
79
|
+ --
|
|
80
|
+ -- notify about message using (pre-configured) notifirc
|
|
81
|
+ --
|
|
82
|
+ local fd = assert(io.popen('notifirc -c mail -f - "message preview:"', "w"))
|
|
83
|
+ local fmt = "> %s\n> %s\n> BODY: %s"
|
|
84
|
+ fd:write(fmt:format(subj, from, body))
|
|
85
|
+ fd:close()
|
|
86
|
+end
|
|
87
|
+
|
|
88
|
+function notifirc_all(seq)
|
|
89
|
+ --
|
|
90
|
+ -- Send notifications about all messages in *seq*
|
|
91
|
+ --
|
|
92
|
+ for _, mesg in ipairs(seq) do
|
|
93
|
+ mbox, uid = table.unpack(mesg)
|
|
94
|
+ subj = mbox[uid]:fetch_field('Subject')
|
|
95
|
+ from = mbox[uid]:fetch_field('From')
|
|
96
|
+ body = mbox[uid]:fetch_body()
|
|
97
|
+ _notifirc1(subj, from, body)
|
|
98
|
+ end
|
|
99
|
+end
|
|
100
|
+
|
|
101
|
+function _partinf_compare(a, b)
|
|
102
|
+ if not type(a) == type(b) then
|
|
103
|
+ return false
|
|
104
|
+ end
|
|
105
|
+ if type(a) == 'number' then
|
|
106
|
+ return a == b
|
|
107
|
+ elseif type(a) == 'string' then
|
|
108
|
+ return a:lower() == b:lower()
|
|
109
|
+ end
|
|
110
|
+end
|
|
111
|
+
|
|
112
|
+function has_part_like(query, structure)
|
|
113
|
+ --
|
|
114
|
+ -- True if structure has MIME part matching *query*
|
|
115
|
+ --
|
|
116
|
+ if structure == nil then
|
|
117
|
+ return false
|
|
118
|
+ end
|
|
119
|
+ for partid, partinf in pairs(structure) do
|
|
120
|
+ local part_answer = true
|
|
121
|
+ -- check all query parts
|
|
122
|
+ for qkey, qvalue in pairs(query) do
|
|
123
|
+ value = partinf[qkey]
|
|
124
|
+ if not _partinf_compare(value, qvalue) then
|
|
125
|
+ part_answer = false
|
|
126
|
+ break
|
|
127
|
+ end
|
|
128
|
+ end
|
|
129
|
+ if part_answer then
|
|
130
|
+ return true
|
|
131
|
+ end
|
|
132
|
+ end
|
|
133
|
+ return false
|
|
134
|
+end
|
|
135
|
+
|
|
136
|
+function filter_part_like(query, seq)
|
|
137
|
+ --
|
|
138
|
+ -- Run MIME part query on *seq* sequence of messages
|
|
139
|
+ --
|
|
140
|
+ result = Set {}
|
|
141
|
+ for _, mesg in ipairs(seq) do
|
|
142
|
+ mbox, uid = table.unpack(mesg)
|
|
143
|
+ structure = mbox[uid]:fetch_structure()
|
|
144
|
+ if has_part_like(query, structure) then
|
|
145
|
+ table.insert(result, mesg)
|
|
146
|
+ end
|
|
147
|
+ end
|
|
148
|
+ return result
|
|
149
|
+end
|