What is nupop?
nupop is a GPL'd POP3 server designed for high-performance (read: large user) enviroments. In particular, it optimizes for the best case POP session, where a user has no new mail and is simply receiving the same UIDL/STAT information as before. It is RFC 1939 compliant and supports the optional "UIDL" command.
What is the current status of the project?
Currently all of the features work, and we are testing it with various mail clients. It works well with Netscape 6 and Outlook Express, but has yet to be tested on Eudora, etc. If you want to help with this effort, please do!
And, it's fast... It's really, really fast.
Why write yet another POP3 server?
Because there aren't really a lot of pop servers out there that are purely pop servers. Most are built on IMAP, and the IMAP back-ends have to do a lot more fooling around with message contents than a POP server does.
In addition, we can save a lot of resources by caching the information the server sends to the client, and only regenerating that information when needed. Say someone POPs every minute-- that's 1,440 POPs per day per user. That user probably isn't popular enough to justify that level of popping, but, of course, there's a nut for every tree. Most POP servers will go through the mailbox and inspect every mail to create a UIDL list every time the user POPs. nupop, however, only rebuilds its list when the user has new mail, and the rest of the time uses a cache file. This makes the average pop session very effecient in terms of system resources.
- Features
-
- RFC 1939 complaint
- Small code base (~2,500 lines)
- Small executable (around 27k stripped on Solaris)
- Supports Maildir format
- UIDL/STAT caching
- Can use a sendmail-like virtual user database to do message id (uid) rewrites
- Has built-in capability to do UID rewriting (i.e. "joe@mydomain.com" is an alias for unix user "superjoe")
- Does a setuid/setgid/chroot after authentication
- Uses GNU autoconf/automake
- Compiles on Solaris and Linux
- Limitations
-
- Only supports Maildir format
- Only supports PAM authentication
- Does not support RPOP/APOP
- Runs from tcpserver/inetd
Since it's GPL'd, please feel free to add whatever features you want. Patches would be appreciated. ;)
Long-term we'd like to see the port listener integrated into the mix (maybe an apache-style pre-forking model?) which would get rid of the ramp-up time required by inetd.
Obtaining the software
[1]Download the latest tarball.
Get a snapshot from CVS:
cvs -d:pserver:anonymous@cvs.nupop.sourceforge.net:/cvsroot/nupop login cvs -z3 -d:pserver:anonymous@cvs.nupop.sourceforge.net:/cvsroot/nupop co nupop
cd nupop && ./bootstrap
When prompted for a password, press the enter key.
Or [2]browse the CVS repository.
Building the executable
Note: If you have downloaded the software from CVS, you'll need to run ./bootstrap to make a configure script.
./configure takes the following options:
- --enable-rewrite-user turns on the user rewrite rules. You will need to have Berkeley DB 3.1 or greater installed to use this. You can obtain Berkeley DB from SleepyCat Software [3]here.
- --enable-fake-uids turns on the uid rewriting scheme. This is useful for transition users from a server that uses an alternate uid scheme to nupop.
- --enable-debug enable copious debugging output. Only good for testing!
- --with-db=[dir] specify what directory you installed Berkeley DB in when doing --enable-rewrite-user.
After initializing the build environment, you'll probably want to make some changes in the .h files. Sorry, but since it's a binary out of inetd, having it read and parse a configuration file seemed pretty wasteful. Here are the directives and files you may want to change:
< see http://nupop.sourceforge.net for table. >
Set what you want, then make and make install.
The mailbox format
nupop expects there to be MAILDIR_DIRECTORY/new and MAILDIR_DIRECTORY/cur directories within the user's home directory. So if the user is "john" with a home directory of "/home/john" then there should be (using the default MAILDIR_DIRECTORY) a "/home/john/Maildir/new" and a "/home/john/Maildir/cur".
How it works (Q&D)
main.c takes lines of input and splits them into argc, argv. argc[0] (i.e. the command issued) corresponds to an entry in a jumptable. The command handlers then do all the work. The states (i.e. AUTHORIZATION, TRANSACTION, UPDATE) are numbered so that a simple and'ing can tell you what commands are allowed in any particular state.
After a user is authenticated, nupop does a setuid, setgid, and a chroot. This makes the string manipulation a lot easier when the work is actually done.
Loading the emails: The MAILDIR_DIRECTORY/.statcache file is read if possible. If not, the calc_mail_stats stats all of the emails in new and cur, building the list of emails.
Retrieving an email: The file is mmapped, and crlf's are added as the mail is output. (see __send_file...)
Internal email storage: each email is in a struct email; a hunk is an array of struct emails of size HUNKSIZE; which are indexed in array of size MAXHUNKS of pointers to hunks. (Basically it's one big array of emails split up into segments.) The cusor_reset, cursor_next, and cursor_seek functions set a global cursor pointer that lets you access any email you want and not have to worry about these details. If you don't want to look at maildir.c, all you have to know is that MAXHUNKS
- HUNKSIZE = The maximum number of emails a user can have in their inbox. Larger hunk sizes are better because fewer malloc's occur.
