The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Mail::Maildir -- Maildir/Maildir++ filesystem implementation

SYNOPSIS

See the README for copyright information and prerequisites. See INSTALL_SOURCE/t/Maildir.t for useful use cases.

This program implements many of the common features of creating, managing, removing, and so on of Maildir and Maildir++ directories and files. Reference:

1. http://cr.yp.to/proto/maildir.html
2. http://www.inter7.com/courierimap/README.maildirquota.html

USAGE

my $maildirObj = new Mail::Maildir("/path/to/somewhere");

Path should *be* the Maildir (i.e. /path/Maildir, and not, /path, which HAS a Maildir). Initializes a new Maildir object, sets internal values for isvalid, isplusplus (that is, runs several validation functions on initialization). This never returns undef. It won't create a new Maildir if the path isn't a Maildir, (use create() for this) and it will open() it if it is a Maildir.

~~~~~

my $maildirObj = Mail::Maildir::Plusplus::open(PATH);

my $maildirObj = Mail::Maildir::open(PATH);

my $maildirObj = Mail::Maildir->open(PATH);

my $maildirObj = open Mail::Maildir(PATH);

Opens an existing Maildir, returns undef if it isn't a Maildir.

~~~~~

my $maildirObj = Mail::Maildir::Plusplus::create(PATH);

my $maildirObj = Mail::Maildir->create(PATH);

my $maildirObj = Mail::Maildir::create(PATH);

my $maildirObj = create Mail::Maildir(PATH);

Creates a Maildir, returns a Mail::Maildir on success or on already exists, returns undef if it failed. NOTE: The Maildir will be created right in PATH, as PATH/new, PATH/cur etc. Use this method to create Maildirs whose base paths are not .../Maildir/. Note also that you can shoot yourself in the foot here, by creating a Maildir in a directory that has existing files disallowed in a Maildir/++

~~~~~

my $success = $maildirObj->warnLogAt(filestring);

Say where you want the log to be. Returns 0 or 1, where 0 means that the log could not be written there, and 1 means that it can. Specify a full path. The default log location is /tmp/maildir.log

~~~~~

my $success = $maildirObj->enableWarnLog();

Returns 0 (log not successfully writable, warn logging not enabled) or 1 (log successfully writable, warn logging enabled); the default log location is /tmp/maildir.log.

~~~~~

my $ret = $maildirObj->createMaildir($optfolder);

Make a non-++ Maildir as ./Maildir at the directory you specified in new(), or as a subfolder named $optfolder if $optfolder is specified. Note: we use the .Folder convention for Maildir++ folders, but you do not specify the dot yourself, i.e. if you want a folder called 'Stuff', then say 'Stuff', not '.Stuff' in $optfolder. This method will not create subfolders automatically -- even if you are in a folder context after having used setFolder(), the Maildir that would be created with $optfolder will be in $optfolder, not $folder.$optfolder. A 0 return means failed to create the Maildir and 1 indicates success. Note: after creating a Maildir without the $optfolder, so making ./Maildir, the internal path is automatically adjusted to path/Maildir (hopefully for convenience), where path is whatever you said in new().

~~~~~

my $ret = $maildirObj->delete();

If maildirObj refers to a valid Maildir, this removes everything under dir/cur, dir/new, dir/tmp and dir/.Trash, as well as maildirsize and maildirfolder. If called in a folder context (after setFolder()), then 'dir' will be the folder directory. Returns 0 for any failures, and 1 for success.

~~~~~

my $ret = $maildirObj->isValidMaildir();

Is this a Maildir? Returns 0 or 1.

~~~~~

my $ret = $maildirObj->isPlusplusMaildir();

Is this a Maildir++? Returns 0 or 1. Note: the algorithm here is: it is a Maildir if, and only if, (1) at the time the object was instantiated, the instantiation folder had maildirsize, and either a .Trash or a subfolder with a maildirfolder file, OR (2) upgradeToPlusplus() was called on the object, and was successful.

~~~~~

my $ret = $maildirObj->upgradeToPlusplus(quotabytes, quotamsg);

If maildirObj is a Maildir but not a Maildir++, this will create a properly formatted quota file (maildirsize) with quota $quotabytes and $quotamsg, and a Trash folder, properly formatted. Returns 0 on any failure, and 1 on success.

~~~~~

my $ret = $maildirObj->setFolder(foldername);

If maildirObj is a Maildir++, sets the current folder context to 'foldername'. Note: the current folder context is used; so you can change to subfolders using this method by calling setFolder() into deeper folders. Returns 0 for any failure, 1 on success. Note: you can set subfolders directly, e.g. foldername = folder.subfolder.

~~~~~

my $ret = $maildirObj->createFolder(foldername);

If maildirObj is a Maildir++, creates a folder and sets context to 'foldername'. Note: the current folder context is used; so you can create subfolders using this method. The subfolder convention used is the 'dot' notation one; i.e. if you are in folder F and create a new folder D, D will be a subfolder of F, and the filesystem structure, under your root Maildir++, will have a directory called .F.D. Returns 0 for any failure, 1 on success.

~~~~~

my ($n, $fh) = $maildirObj->createNamedTmpMessage();

my ($n, $fh) = $maildirObj->createNamedTmpMessage(filenameString);

Put a message in tmp, optionally with the contents of the file specified as a full path with filenameString. Returns an empty array on failure, or $messagename (valid Maildir message name that was created, not a full path) and an OPEN, writable filehandle to the message file. Note: if you are in a folder context, the tmp directory used will be the one corresponding to that folder.

~~~~~

my $ret = $maildirObj->moveTmpToNew($messagename);

Moves messagename from tmp to new, respecting folder context. Returns 0 (failure) or 1 (success).

~~~~~

my $messagename = $maildirObj->moveNewToCur($messagename);

Moves messagename from new to cur, respecting folder context. Returns new message name (sets P flag) on success, 0 on failure.

~~~~~

my $ret = $maildirObj->trashMessage($messagename, $actuallyremove);

Trashes a message from cur; respects Maildir++ trashing convention if isPlusplus, creating .Trash if necessary. Folder context is respected (i.e. will trash folder/cur to base/.Trash). Returns 0 (failure) or messagename (with replaced 2,T info string, on success). If actuallyremove is specified, the messagename will be the true value returned from unlink().

~~~~~

my $ret = $maildirObj->getQuotaBytes();

Returns the quota in bytes for this account, -1 on error.

~~~~~

my $ret = $maildirObj->getQuotaMessages();

Returns the quota in messages for this account, -1 on error.

~~~~~

my $ret = $maildirObj->dirExists();

Returns 0 if the directory specified in new() does not exist, otherwise 1.

~~~~~

my $ret = $maildirObj->isInsecure();

Not terribly useful, but, if the directory specified in new() contains :, `, | or \, then those characters got stripped from the name, and this flag got set to 1. 0 otherwise.

~~~~~

my ($byte, $message) = $maildirObj->getMaildirUsage();

Returns the usage information (bytes, messages) deduced from the Maildir++ quota file (maildirsize). Returns -1, -1 if maildirObj is not a Maildir++.

~~~~~

my $ret = $maildir->setQuota(bytes, messages);

Sets the quota -- if an argument is set to '', the existing value will be used. Causes maildirsize to be rewritten. Returns 0 or 1.

~~~~~

my ($bytes, $messages) = $self->calculateMaildirsize();

Follows maildir++ procedure for calculating usage, and rewriting maildirsize, and returns the usage information calculated. Will return -1, -1 on any failure. Note that not much counts as a failure: basically file writes for maildirsize do count as failures, and nothing else does. These is probably a bug here somewhere.

~~~~~

my ($arrayref) = $self->listFolders();

Returns an array reference listing all the Maildir++ folders. Note: is independent of context, so will return a list of names that start with '.' and may have more '.'s in them.

~~~~~

my ($arrayref) = $self->listMessages();

Returns an array reference listing all the mail messages in the folder context set for $self (can be none, for base Maildir). The array structure is as follows: each item is a hash reference, whose dereferencers are SIZE (the size of the mail message), STATUS (new, read, passed, etc), FOLDER (the folder this message was found in), FULLPATH (the full path to the message) and NAME (the name of the message). STATUS can be anything in INFO_FLAGS, or N for new.

~~~~~

Internal API:

my $ret = $self->determineMaildirValidity($optdir);

0 for false, 1 for maildir, 2 for Maildir++.

~~~~~

my $ret = $self->loadMaildirsize();

Parse and set internal ($self) usage values from maildirsize.

~~~~~

my $ret = $self->writeDefaultMaildirsize();

Writes a default maildirsize file with $DEFAULT_QUOTA_BYTES and $DEFAULT_QUOTA_MESGS.

BUGS

I think the unique filename creator could be made better. The test suite could be fleshed out much more. The failure return values could be fleshed out in more detail with better codes for failures. Complex operations that have many steps should be able to rollback all changes on a failure. There is probably a bug somewhere in calculateMaildirsize().

I am sure there are other bugs; the fact that I cannot find them lends even more credence to this hypothesis.

FUTURE DEVELOPMENT

Plug this module into Mail::Box and create a nifty mail reader for Maildir/Maildir++ all in Perl. Create a web interface to the same.

AUTHOR

Edward L. Abrams <edward.abrams@corp.terralycos.com>.

Copyright (c) 2004 Edward Abrams, Lycos. All rights reserved. This program is free software: you can redistribute it and/or modify it under the same terms as Perl itself.

FIN

Fin.