[imapfilter-devel] Re: Imapfilter sometimes doesn't filter
David DeSimone
fox at verio.net
Sat Aug 21 09:35:31 EEST 2004
David DeSimone <fox at verio.net> wrote:
>
> What would be really nice, I think, is if the Lua language had some
> sort of support for performing intersections or merges of lists.
I have since learned enough Lua to realize that this capability can be
invented within the language.
In case anyone is interested in this problem, let me repeat it here.
If you write some simple Lua code like this:
results = match(acct, inbox, some_query)
move(acct, inbox, acct, some_mbox, results)
results = match(acct, inbox, {})
move(acct, inbox, acct, outbox, results)
The intent of this code is that all messages matching "some_query" get
moved into "some_mbox", and all remaining messages get move to "outbox".
However, this code sometimes fails, due to race conditions. If a
message happens to be delivered to INBOX between the first move and the
second, that message will end up in outbox, even if it would have
matched the previous filtering criteria.
I have found what I believe to be a solution to this problem. At the
start of the code, generate a list of all messages, and then as messages
are moved to other folders, remove those id's from the master list.
Then, only move the messages that remain in this list.
With this scheme, any new messages that arrive that are not filtered
into specific boxes will simply be left in INBOX until the next time
imapfilter runs. I find this to be acceptable, since I run imapfilter
in daemon mode with a 45-second timer.
Here is the code that I wrote to make this work. First, some support
functions are needed:
function remove_from(list, item)
if (list == nil or item == nil)
then
return
end
local pos
for k, v in pairs(list)
do
if (v == item)
then
pos = k
break
end
end
if (pos ~= nil)
then
table.remove(list, pos)
end
end
The above routine searches for an item in a list, and removes it if
found.
function remove_list(master, remove)
if ((master == nil) or (remove == nil))
then
return
end
for k, v in pairs(remove)
do
remove_from(master, v)
end
end
The routine above removes elements collected in one list, from another
list. With these tools, it's now possible to write some code:
exists, recent, unseen = check(account, "INBOX")
if (exists == 0)
then
return
end
This is an optimization, so that we don't waste time looking for
messages if there are none.
all = match(account, "INBOX", {})
We get a list of all messages in the inbox here, and call it "all".
query =
{
'smaller 8000',
{
'header "List-Id" "unix-admin"',
'header "List-Id" "itops-maintenance"',
'header "List-Id" "it-serverops"'
},
}
results = match(account, "INBOX", query)
if (results ~= nil and table.getn(results) > 0)
then
move(account, "INBOX", account, "unix", results)
remove_list(all, results)
end
This is a basic query block. As you can see, after moving the messages,
all message id's that were moved are removed from the "all" list.
query =
{
'header "List-Id" "imapfilter-devel.lists.hellug.gr"'
}
results = match(account, "INBOX", query)
if (results ~= nil and table.getn(results) > 0)
then
move(account, "INBOX", account, "imapfilter", results)
remove_list(all, results)
end
The basic query block repeats several times, for each folder that I want
to move messages to.
if (all ~= nil and table.getn(all) > 0)
then
move(account, "INBOX", account, "Default", all)
end
Finally, after all the queries have been run, we move any remaining
messages into the default folder. My, that looks so simple now! I
guess I am getting the hang of this Lua-nguage. :)
--
David DeSimone || Network Admin || fox at verio.net
"It took me fifteen years to discover that I had no
talent for writing, but I couldn't give it up because
by that time I was too famous. -- Robert Benchley
More information about the Imapfilter-devel
mailing list