A cool little feature I just came across with lua is that the
require function can be used as part of the actual working code. For instance, an optional piece of functionality can be required based on an option flag. The benefit is unnecessary code is only loaded when it’s wanted.
I just wrote an IMAP4rev1 parser to help with making sure imap commands generated by luaimap are syntactically correct. The idea was to eliminate a potential point of confusion when working with the library. Of course, the checker is pretty green at this stage, so it may give a false negative. But at least is give a starting point to the would be developer.
Typically, I’d just
require the module at the top of my code, like so:
local chksyntax = require("parser")
And then the parsing function can be invoked in the usual way.
But in this case, I figured the checker should really be part of the IMAP object that luaimap creates. Then I thought, wouldn’t it be nice if I only loaded the module when syntax checking was desired? That way, after a debug and proving out phase, syntax checking could equally be turned off resulting in fast execution. So I added an
options table to the
new method and then inserted the following lines of code:
. . . if options then if options.syntaxchecking then o.__checksyntax = require("parser").parse end end
The other cool thing here is that lua allows for grabbing the
parse function reference inside the module. In other words, since
require returns a table, I can immediately add the
parse element for the assignment without generating a syntax error. This is also because lua treats functions as first class values, so they can be assigned just like other variables.
Now, elsewhere in the IMAP object, I can use the parser like so:
if self.__checksyntax and not self.__checksyntax(cmd) then error("I can't in good conscience send this command to the server: "..cmd) end
Anyway, I thought this a somewhat novel (for me) insight into lua usage, and figured I’d pass it along.
My spam filter of choice has been bogofilter for many a year now. For the mail I receive it got to be very accurate quickly and it has remained so ever since. It is one of the Bayesian variety of spam filters and requires “training” to keep it properly classifying email.
I use an IMAP server for working with my mail so integrating bogofilter with the server is less than ideal, which would be to use a keystroke and immediately reclassify the mail. Instead, I’ve assigned a couple of training folders that I then farm out to a script run as a cron job. Specifically, for misclassified spam (i.e. mail that’s actually good but was misclassified as spam) I created a
spam2mail folder and for misclassified good mail (i.e. mail that’s actually spam but is classified as good) I use the
Junk folder. The script, using IMAP, interrogates the mail folders, retrains bogofilter on the mail, and then places the mail in the appropriate final destination, either my
spam folder or my
Originally, I wrote the script in question using perl and IMAPtalk. Since I wrote an IMAP library in lua, I figured it appropriate to rewrite the script in lua using my library.
After the break is the code.
I’m starting to look into how to add pipelined or asynchronous support to my luaimap4 project. It had been awhile since I’d looked at the code so I started the task of refreshing my understanding of the code. In the course of doing so, I opted to take the original source file and break out some of the functionality into separate support modules. After doing so, I didn’t like that I now had multiple source files directly in my install directory, so I opted to create an
imap4 subdirectory and put all the related modules under that directory.
And that’s when the fun began.
The name really does lend itself to abuse. Regardless, I leveraged some previous lua code to create a nice little email widget that checks my email account for new mail and, if so, creates a menu of the mailboxes which have new mail that I can select and launches
mutt with that folder open.
Code and explanation after the jump.
I just created a repository on Gitorious for a client-side IMAP4 library. The project is luaimap and I’ve published it under the MIT license. The project consists of two files:
imap4.lua is the actual library and
checker.lua is a sample program that checks an IMAP account for new mail using the library. The library minimally requires luasocket to establish a basic connection. To establish a TLS connection luasec is also required.
The library implements all IMAP commands except ‘AUTHENTICATE.’ I’ve only tested it against a Dovecot server, so consider it very green. For now, it is a synchronous implementation: commands are sent and return a response from the server for the command. Going forward, I intend to add support for the AUTHENTICATE command and look at trying to take advantage of command pipelining.
Anyone intending to use it should read RFC3501, the document on which the library is based. The intention of the library is to handle the protocol related details of IMAP4rev1, not to enforce IMAP4 client side design practices.
To use it, simply install the file in a project directory and use a line like:
local imap = require("imap4")
To make it available on the system, copy the file in a path that exists in lua’s
package.path variable. On my system, a debian/testing setup, I’ve installed it to
I’ve been working on a lua library to support IMAP4Rev1 command exchanges with an IMAP server. Towards that end, I’ve created a lua object. Now, I’d known a little about using lua and the flexibility of lua table since my window manager uses it as a configuration language. Until this project; however, there has been no reason for me to delve into the deeper depths of lua tables.
Now that I have, I’m not sorry as I’ve learned quite a bit of interesting techniques. Below the fold is a rather simple trick to make lua methods case insensitive.