NAME
flail - a hacker's mailer in Perl
SYNOPSIS
# 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
DESCRIPTION
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.
COMMAND-LINE OPTIONS
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.
- -c ($NoDefaultCC)
-
Do not ask for Cc: addresses by default in the composer
- -q ($AskBeforeSending)
-
Confirm with user before sending message
- -o ($AllowCommandOverrides)
-
Allow the alias command to override built-in commands.
- -Q ($Quiet)
-
Be Vewy Quiet: Only produce error messages and explicitly request output (e.g. ls)
- -l ($RemoveFromServer)
-
Remove messages from server during
get
processing. - -h
-
When by itself, display usage message. When specified with -v, display this POD.
- -s ($SyncImmediately)
-
Automatically sync the current folder after operations that change it, e.g. mv, rm, ...
- -p ($PipeStdin)
-
Read message from stdin; really only useful in conjunction with <-1>. Implies
-c
. - -1
-
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.
- -v ($Verbose)
-
Make ourselves verbose.
- -r rcfile
-
Specify an alternate rc file. The default is
~/.flailrc
- -d folderdir ($FolderDir)
-
Specify an alternative directory for mail folders. The default is
~/mail
- -i incfolder ($IncomingFolder)
-
Specify an alterntive incoming mail folder name. The default is
INCOMING
- -P pop3info
- -I imapinfo
-
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
, whereuser
andport
are both optional, and given the obvious default values if left unspecified. - -F fromaddr ($FromAddress)
- -D domain ($Domain)
- -S smtphost ($SMTPHost)
-
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. - -T tempdir ($TempDir)
-
Set the temp dir used for e.g. message composition.
- -e editor ($Editor)
-
Set the external editor used from the composer. Defaults to your
$EDITOR
environment variable. - -C fccfolder ($FCCFolder)
-
Set the folder name in which to automatically file outgoing messages.
- -R pop3|imap ($CheckType)
-
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. - -A abook ($AddressBook)
-
File containing your addressbook as a dbm file.
- -n ($NoAddressBook)
-
Do not use an addressbook.
- -a ($AutoAddressBook)
-
Automatically try to look up all outgoing addresses in our addressbook.
- -k ($AskAddressBook)
-
Interactively prompt the user for address book matches before sending.
- -E ($ExactHostMatch)
-
Only match two addresses if the hostnames are identical.
- -b ($QuietAddressBook)
-
Make addressbook functionality quiet.
- -N newlabel ($NewLabel)
-
Label all incoming messages with
newlabel
by default. - -g dot.sig.dir ($SignatureDir)
-
Look for dot.sigs in dot.sig.dir
- -G ($Debug)
-
Turn on debugging output. Not useful for ordinary use.
- -u defaultsubj ($DefaultSubject)
-
Set the default subject for outgoing email. None by default
- -U ($HeadersFromStdin)
-
If
-p
is specified, then-U
says that the entire message, including headers, is coming in on stdin.
COMMAND LANGUAGE
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:
- !cmd
-
Execute Unix command
cmd
and display results on stdout - |cmd
-
Pipe the current message through
cmd
and display the results on stdout - ,code
-
Evaluate the perl code
code
. Does not display results by default, if you want them, use theprint
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
1:3
Messages 1 through 3
3:$
Messages 3 through the end of the folder.
$-3:$
The last three messages in a folder
1,3,5,$-3:$-1
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.
Checking and Retrieving Mail
Commands to query and fetch mail from mail spools.
check: check pop3, imap or local spool mailbox
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
.
get: download mail from a remote mailbox
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.
Navigating and Managing Messages
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.
next: goto next message
Move to the next message.
prev: goto previous message
Move to the previous message.
goto: goto arbitrary message by number
Go to a message by number, e.g.
goto 3
moves to the message numbered 3 in the output of ls
cat: display message contents
Displays the current message, or one by number if specified. Output is paginated if we know how to do that on your terminal.
headers: display message headers in detail
The cat
command normally shows abbreviated headers. The headers
command shows only the headers for a message, and it shows them all.
decode: decode a MIME message
Not yet implemented.
cp: copy a message to another folder
Copy a message to another folder, e.g.
cp 3 spam
copies message 3 to the folder named SPAM
mv: move a message to another folder
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
rm: delete a message
Delete a message or messages, e.g.
rm 1:$
deletes all messages in the current folder.
Folder-Related Commands
flail uses Mail::Folder, 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.
cd: enter a folder
Change the object of your affections to another folder, e.g.
cd INCOMING
pwd: display current folder
Show the current folder and your state in it.
ls: list folder contents
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.
mkdir: create a folder
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...).
Sending Messages
Things that call the composer. See MESSAGE COMPOSITION INTERFACE, below, for details.
send: send a new message
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 Net::SMTP 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.
reply: reply to a message
Like send
, but replies to the sender of a previous message.
forward: forward a message to a new recipient
Like send
, but forwards an existing message to a third party.
resend: resend a bounced message
Like send
, but resends a message that was bounced.
The Address Book
address: interface to the address book
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 nickname email
-
Add a new entry. Nickname must be unique in your addressbook.
- show nickname
-
Show the address associated with the given nickname.
- list [regexp]
-
Search the addressbook by regexp, or list the whole thing if no regexp specified
- del nickname
-
Remove an entry by nickname
- import filename
-
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
. - take [label]
-
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.
Marking, Mapping and Other Fun Stuff
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.
mark: add a label to a message
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 Mail::Internet 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: remove a label from a message
Unmark takes the same argumentology as mark, but removes the marked
label instead.
map: map a piece of code over some messages
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:
- $N the message number in the folder
- $M a Mail::Internet object that represents the message
- $F the Mail::Folder object corresponding to the folder
- $H the Mail::Header object associated with $M
If there are no curly braces, the command should be a legal flail command. In both cases, two additional substitutions take place:
- %n is substituted with the message number
- %* is substituted for any arguments that appear
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
.
count: count labeled messages
Given a label, count the messages that match it. If no label is specified, marked
is assumed.
run: run message hooks for label
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.
State Management
sync: flush changes to the current folder
Flush any changes to the current folder to disk. This includes expunging messages labeled deleted
.
reset: reset various bits of state
Resets the password cache and/or the connection cache.
Crypto
decrypt: decrypt a PGP-encrypted message
This needs a rewrite, as my crypto fu relies on outdated modules and must be rewritten.
Other Commands
alias: create a new command
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
unalias: remove an alias
Remove an alias.
help: get help
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
- pod
-
spit out the flail manual (thanks to Pod::Usage)
- version
-
show our version information
- license
-
show our full license
- warranty
-
show our warranty
quit: exit flail
Bug out, flushing all changes.
If you want to bug out without saving anything, use Perl:
,exit
MESSAGE COMPOSITION INTERFACE
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.
CONFIGURATION
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.
Your .flailrc
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.
Managing Multiple Identities and Mailboxes
Passwords and the Pipe Trick
Hacking Flail
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.
Alphabetical Listing of All Configuration Variables
BUGS / TODO
Too many bugs to count at the moment...
- Finish the OO/modular rewrite
- Get rid of all I/O in signal handlers
- Move main into a MAIN: { } block
- Re-write this turkey so it's not so fugly
- Just finally stop reading email already, everybody is already so over email.
CREDITS
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".
VERSION HISTORY
Alice: Well I must say I've never heard it that way before...
Caterpillar: I know, I have improved it.
0.2.5 06 Sep 08 attila found some lost hacks from a source
tree recovered from a dead laptop:
semi-colon-separated commands,
send_via_program, a couple other things.
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 AND LICENSE
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.
4 POD Errors
The following errors were encountered while parsing the POD:
- Around line 3951:
Expected '=item 2'
- Around line 3955:
Expected '=item 3'
- Around line 3959:
Expected '=item 4'
- Around line 3963:
Expected '=item 5'