flail - a hacker's mailer in Perl
# to run a single flail command: $ flail -1 -other_options [cmd ... args ...]
# to get into the interactive command loop $ flail
# to get a usage message: $ flail -h
# to get the whole manual $ flail -hv
flail is a hacker's mailer, written in Perl, and sporting a command-line interface. It currently supports pop3 and imap for access to remote maildrops, as well as regular old Unix mail spool files for local maildrops (e.g. because you use fetchmail).
The commands are vaguely Unix-like (rm, cp, mv, cat, ls). There are facilities for mapping bits of perl code over some subset of the messages in a folder, crypto, external editors, and user-defined commands.
You naturally invoke flail on the command-line. It takes single-letter options, just like Pan intended. Where it makes sense, we note the name of the config variable corresponding to each option in parentheses.
Do not ask for Cc: addresses by default in the composer
Confirm with user before sending message
Allow the alias command to override built-in commands.
Be Vewy Quiet: Only produce error messages and explicitly request output (e.g. ls)
Remove messages from server during get
processing.
When by itself, display usage message. When specified with -v, display this POD.
Automatically sync the current folder after operations that change it, e.g. mv, rm, ...
Read message from stdin; really only useful in conjunction with <-1>.
Implies -c
.
Run a single flail command, specified as arguments on the command line. For instance
$ flail -1 send rms@mit.edu
can be used to send a single message to someone famous.
Make ourselves verbose.
Specify an alternate rc file. The default is ~/.flailrc
Specify an alternative directory for mail folders. The default
is ~/mail
Specify an alterntive incoming mail folder name. The default
is INCOMING
These options are largely outdated, but can still be useful, especially
in conjunction with -1
.
In both cases, a string of the form user@server:port
, where
user
and port
are both optional, and given the obvious
default values if left unspecified.
These are also probably only really useful with -1
, since your
~/.flailrc
will probably arrange to set them in less obvious ways.
These options set the From address, domain, and SMTP relay used to
send a message.
Set the temp dir used for e.g. message composition.
Set the external editor used from the composer. Defaults
to your $EDITOR
environment variable.
Set the folder name in which to automatically file outgoing messages.
Outdated: specify default message check method, pop3 or imap. Since you
can have more than one account of each kind, sort of silly. If you do
not specify any arguments to check
, we use $CheckType
as the default.
File containing your addressbook as a dbm file.
Do not use an addressbook.
Automatically try to look up all outgoing addresses in our addressbook.
Interactively prompt the user for address book matches before sending.
Only match two addresses if the hostnames are identical.
Make addressbook functionality quiet.
Label all incoming messages with newlabel
by default.
Look for dot.sigs in dot.sig.dir
Turn on debugging output. Not useful for ordinary use.
Set the default subject for outgoing email. None by default
If -p
is specified, then -U
says that the entire message,
including headers, is coming in on stdin.
The command language is vaguely Unixy. Commands look like:
word [arg arg...]
Some commands take slash-style options, ala TOPS-20:
send/as:someone@somewhere ...
Many (most?) commands at least will pay attention to options
named debug
, verbose
and quiet
. For instance, to
turn on SMTP debugging when you send an email:
send/debug to@some.one
The first character of a command might specify another action than a normal command:
Execute Unix command cmd
and display results on stdout
Pipe the current message through cmd
and display the results on stdout
Evaluate the perl code code
. Does not display results by default,
if you want them, use the print
statement, e.g.
,print $Editor
Other than those special cases, we look at our first word and dispatched based on it. The complete list of built-in commands follows, grouped by function. For information on adding your own commands, see the section on CONFIGURATION, below.
Message Sequences (also called ``Range Expressions'') are an important part of the flail command language. The following are all valid range expressions:
Message 1
Messages 1 through 3
Messages 3 through the end of the folder.
The last three messages in a folder
The first, third, and fifth messages, as well as the second two from the end (not including the last one)
In addition, you can specify -label
to include all messages tagged
with the given label, so the range expression -marked
expands to
all marked messages.
Many commands take message sequences in place of single message numbers. Some do not. Hopefully, I'll do a good job of telling you which is which.
Commands to query and fetch mail from mail spools.
Check a mailbox for mail. The full syntax is
check type user server
e.g.
check pop3 attila mailserver
looks for mail using pop3 on mailserver as the user attila. You will
be prompted for a password, unless flail remembers what it is. The
remember_password
internal function can be useful in your
configuration file to keep you from having to type your password all
the time. If you insist, you can specify your password as the final
argument on the command line, but we don't recommend it.
To check a local spool file, use
check spool /path/to/spool
The default spool is /var/mail/yourusername
, so if this is correct
you can just
do
check spool
to check your local mail spool. You can override both the file name
and directory with the $SpoolFile
and $SpoolDir
configuration
variables in your ~/.flailrc
.
Just like the check
command, except that we fetch the mail and
incorporate it into the incoming folder. It takes the same type
parameter as its first argument, e.g.
get spool
grabs (and expunges) your local mail spool.
These commands are for stumbling around in the folder tree and looking at messages.
If you have a folder selected, flail shows you what it is in your prompt. If your prompt is simply
flail>
then you are not in any folder, and many of these commands will fail with an error.
Move to the next message.
Move to the previous message.
Go to a message by number, e.g.
goto 3
moves to the message numbered 3 in the output of ls
Displays the current message, or one by number if specified. Output is paginated if we know how to do that on your terminal.
The cat
command normally shows abbreviated headers.
The headers
command shows only the headers for a message,
and it shows them all.
Not yet implemented.
Copy a message to another folder, e.g.
cp 3 spam
copies message 3 to the folder named SPAM
Like cp
, but removes the message from the current folder
after it is copied. If $SyncImmediately
is true, we
sync the folder afterwards. Otherwise, the message appears
with the D
(Deleted) flag turned on until you sync
.
A message sequence can be specified, e.g.
mv 1,2,$-3:$ odd_folder
Delete a message or messages, e.g.
rm 1:$
deletes all messages in the current folder.
flail uses the Mail::Folder manpage, and can thus support any type of mail folder that it supports. Generally, we use mbox folders, which are single files containing multiple messages. None the less, we treat ``folders'' as if they were directories from the command language, for consistency.
Change the object of your affections to another folder, e.g.
cd INCOMING
Show the current folder and your state in it.
List the contents of the folder, one message per line. If
$PlainOutput
is not true, we try to color it nicely for ttys that
support ANSI color sequences, like xterm
. If a message sequence is
specified, we only show those messages. Output is paginated.
If you are not in a folder, then ls shows you the subfolders in whatever part of the folder tree you happen to be in. If you are at top level, this is all of the top-level folders under the root.
You can specify an arbitrary range expression to ls, as you can with many other commands. For instance,
ls -marked
will list all marked messages.
Not yet implemented. For now, use the following idiom
!touch foldername
to create a new blank folder (remember: we chdir to your
$FolderDir
on startup...).
Things that call the composer. See MESSAGE COMPOSITION INTERFACE, below, for details.
Send a message to the addresses given as arguments. The From
address can be set explicitly with the as
option, e.g.
send/as:bozo@clown.com gosper@mathematicians.org
If there is a problem, you might re-trying the send
command with
the debug
option, which turns on the Net::SMTP manpage debugging and will
produce a large amount of output.
We invoke the external editor of your choice for composition, which should return a valid status code. You will generally have a chance to go over it, re-edit it, abort, cryptosign, attach .sig, etc. after you're done editing.
Like send
, but replies to the sender of a previous message.
Like send
, but forwards an existing message to a third party.
Like send
, but resends a message that was bounced.
The address
command has several subcommands to help you
manage your addresses. Flail stores these in a dbm file,
typically called ~/.flail_addressbook
.
Subcommands:
Add a new entry. Nickname must be unique in your addressbook.
Show the address associated with the given nickname.
Search the addressbook by regexp, or list the whole thing if no regexp specified
Remove an entry by nickname
Import address book data stored in a file. The two kinds of files we
currently support are LDIF and CSV; files should have extensions that
reflect their type, e.g .ldif
or .csv
.
Extract email addresses from one or more messages and import them into your addressbook. If no label is specified, the current message is examined; otherwise, all messages in the current folder with the specified label are examined.
Messages can have an arbitrary set of labels associated with them.
Some, such as deleted
and filed
, have meaning to flail itself.
Some, such as marked
or whatever other string you might use, are
just for your own purposes. Marking messages lets you apply code to
them, so flail users do it alot.
In the absence of any arguments, applies the marked
label to
the current message.
If a message sequence is specified, then all messages in that sequence
get the marked
label. If the word all
is specified, then all
messages get marked
.
If the first character of our first argument is a comma, then the rest
of the arguments are treated as a bit of perl code that is invoked for
every message in the folder. The token %m
will be substituted for
a variable that is bound to an the Mail::Internet manpage object representing
each message in the folder on subsequence calls.
For instance, if we have in our configuration
sub is_blue { shift->get("Subject") =~ /\[blue\]/; }
Then we can do
mark ,is_blue(%m)
to mark all messages whose Subject
headers contain the string
[blue]
.
Unmark takes the same argumentology as mark, but removes the marked
label instead.
map label ...
Run a command or piece of code over a set of messages, specified by
a label. If the label is all
, then all messages have the action
applied to them. The action can be a flail command, or a piece of
random Perl code. In the latter case, the first character of
the code should be a curly brace, and the code should end with
one as well, e.g.
map marked { grep_msg('Foo'); }
Runs the given code for each message. The code is called in a
context where the following globals are available in the main
namespace:
If there are no curly braces, the command should be a legal flail command. In both cases, two additional substitutions take place:
after
the command
This last substitution is a bit odd, and requires explaining.
Supposing we have our hypothetical sub grep_msg
(which does in fact
come with the dot.flailrc
in the distribution). It wants a regexp as
its argument. It uses $M
, etc. to get at the message it is
grepping. Supposing we want to be able to type
mgrep pattern
to run grep_msg("pattern")
over each message. How do we do it?
alias mgrep map all { grep_msg("%*"); }
Now, when we type
mgrep pattern
The %*
is substituted with pattern
. This is why map
is
useful even when operating on a single message.
Another enlightening example:
alias mmv map marked mv %n %*
This creates an alias, mmv
, which can be used thusly:
# arrange to mark the messages that are spam, # either by hand ... mark 1,3,5
# or by some automated oracle mark ,is_spam(%m)
# now, move it all to a folder named spam mmv spam
Of course this is just a contrived example, since you can accomplish the same thing with labels, e.g.
mv -marked spam
will move all marked messages to the folder named spam
.
Given a label, count the messages that match it. If no label is specified,
marked
is assumed.
Given a label, run all of the message hooks associated with that label over every message that has that label in the current folder. See the discussion on message hooks in Hacking Flail, below.
Flush any changes to the current folder to disk. This includes
expunging messages labeled deleted
.
Resets the password cache and/or the connection cache.
This needs a rewrite, as my crypto fu relies on outdated modules and must be rewritten.
Create a new command. You cannot overwrite existing command table entries this way; use Perl code in your config file instead.
Example:
alias mvspam map marked mv %n spam
Remove an alias.
You can ask for help on any specific command or alias by using it as an argument, e.g.
help ls
Invoking help with no arguments produces a list of commands.
In addition to commands, you can ask for help on the following subjects
spit out the flail manual (thanks to Pod::Usage)
show our version information
show our full license
show our warranty
Bug out, flushing all changes.
If you want to bug out without saving anything, use Perl:
,exit
When you are sending a message, you will be generally be prompted before it goes out. The prompt allows you to perform some fairly complex sequences of actions with a few keystrokes, and is usually called the composer.
XXX Write more.
flail is a hacker's mailer. Configuring flail means writing Perl code. If this does not fill you with joy, you're in the wrong bar.
Flail loads ~/.flailrc
upon startup. An extensive example comes
with the distribution (dot.flailrc). You can specify another file
with the -c
command-line option.
Command-line options will already have been parsed by the time your rc
file is loaded. This means you can check for the value of
e.g. $SingleCommand
to see if -1
was specified on the command
line, etc.
Flail is ultimately just a bunch of Perl subs. It currently all lives
in the main
package, which is where your flailrc is loaded as well.
This means you can write code that calls any flail primitive, add new
primitives, or extend the command set using the same API (if you want
to diginfy it with that name) that I use.
WARNING: I will be rewriting flail to use OO techniques in the very
near future. You should get on the flail-dev
mailing list if you
are interested.
Too many bugs to count at the moment...
Sean Levy <snl@cluefactory.com> wrote this thing, sometime in or around 2000 most likely, although he can't quite remember the exact year. It started out as a pile of hacks and has matured and blossomed into a GREAT FREAKING HUGE PILE OF HACKS.
Sean is also known as attila <attila@stalphonsos.com>, for historical reasons almost entirely under his control. That's ``Saint Alphonsos''.
Alice: Well I must say I've never heard it that way before...
Caterpillar: I know, I have improved it.
0.2.4 05 Aug 08 attila revived from the dead AGAIN after t-bird screwed me hard. 0.2.3 30 Jun 06 attila released on freshmeat 0.2.2 26 Jun 06 attila wrote pod, use strict, blah blah added local spools 0.2.1 25 Jun 06 attila fixed horrible bug in get_imap 0.2.0 24 Jun 06 attila resurrected after i got sick of VM 0.1.28 26 Feb 03 attila 0.1.28 released 0.1.? ?? ??? 02 attila Somewhere around 2002 I found myself using flail everyday and thought perhaps I should release it or something 0.0.0 ?? ??? 00 attila Sometime in y2k I had a brain schizm and decided to write an MUA in perl
Copyright (C) 1999,2000 St. Alphonsos. Copyright (C) 2000-2008 by Sean Levy <snl@cluefactory.com>. All Rights Reserved. Redistribution and use in any form, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. The names "St. Alphonsos", "The Clue Factory", and "Sean Levy" must not be used to endorse or promote products derived from this software without prior written permission. To obtain permission, contact info@stalphonsos.com or snl@cluefactory.com 3. Redistributions of any form whatsoever must retain the following acknowledgment: "This product includes software developed by St. Alphonsos http://www.stalphonsos.com/ and Sean Levy <snl@cluefactory.com>" THIS SOFTWARE IS PROVIDED BY ST. ALPHONSOS, THE CLUE FACTORY AND SEAN LEVY ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ST. ALPHONSOS NOR ITS EMPLOYEES, THE CLUE FACTORY NOR ITS EMPLOYEES, OR SEAN LEVY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.