source: trunk/athena/bin/mitmailutils/mitmailappend.pl @ 24300

Revision 24300, 4.4 KB checked in by geofft, 14 years ago (diff)
In mitmailutils: * Switch from Hesiod to using *.mail.mit.edu so we can use GSSAPI authentication (Trac: #403). * Because of a Cyrus SASL bug (documented in that ticket) regarding parsing long encrypted responses, set maxssf to zero to send mail in the clear. This isn't as terrible as it sounds because mail travels in the clear on the public Internet anyway, and a bunch of client programs (Pine on Athena 9, for instance) don't use encryption, and the major use of mitmailutils is `from` and `mailquota` anyway. Patch based on one from Jonathan Reed <jdreed@mit.edu>.
Line 
1#!/usr/bin/perl -w
2
3# $Id: mitmailappend.pl,v 1.1 2004-09-03 20:44:43 rbasch Exp $
4
5# Append a message to an IMAP folder.
6
7use strict;
8use warnings FATAL => 'all';
9use Cyrus::IMAP;
10use Getopt::Long;
11
12sub usage(;$);
13sub read_file($);
14sub send_command(@);
15sub close_and_errorout($);
16sub close_connection();
17sub errorout($);
18
19my $prog = $0;
20
21sub usage(;$) {
22    print STDERR "$prog: $_[0]\n" if ($_[0] && $_[0] ne "help");
23    print STDERR <<EOF;
24Usage: $prog [<options>]
25  Options:
26    --debug                turn on debugging
27    --file=<path>          read message from <path> instead of standard input
28    --help                 print this usage information
29    --host=<name>          query host <name> instead of default POBOX server
30    --mailbox=<name>       access mailbox <name> instead of INBOX
31    --no-create            do not create the target mailbox automatically
32EOF
33    exit 1;
34}
35
36# Parse the command line arguments.
37use vars qw($opt_debug $opt_file $opt_host $opt_mailbox $opt_no_create);
38
39GetOptions("debug",
40           "file=s",
41           "help" => \&usage,
42           "host=s",
43           "mailbox=s",
44           "no-create") || usage;
45
46usage unless @ARGV == 0;
47
48$opt_mailbox = "INBOX" unless $opt_mailbox;
49
50# By default we read the message from standard input.
51$opt_file = "-" unless $opt_file;
52
53my $username = $ENV{'ATHENA_USER'} || $ENV{'USER'} || getlogin || (getpwuid($<))[0] ||
54    errorout "Cannot determine user name";
55
56unless ($opt_host) {
57    $opt_host = (gethostbyname("$username.mail.mit.edu"))[0];
58    errorout "Cannot find Post Office server for $username" unless $opt_host;
59}
60errorout "Exchange accounts are not supported yet. Try http://owa.mit.edu/." if $opt_host =~ /EXCHANGE/;
61
62# Read the entire message file into a string.
63my $msg = read_file($opt_file);
64
65# Convert LF -> CRLF if necessary.
66unless ($msg =~ m/\r\n/os) {
67    print "Converting LF to CRLF...\n" if $opt_debug;
68    $msg =~ s/\n/\r\n/gos;
69}
70
71# Connect to the IMAP server, and authenticate.
72my $client = Cyrus::IMAP->new($opt_host) ||
73    errorout "Cannot connect to IMAP server on $opt_host";
74$client->authenticate(-authz => $username, -maxssf => 0) ||
75    close_and_errorout "Cannot authenticate to $opt_host";
76
77# Try the APPEND command.  If the server returns an error,
78# check for "TRYCREATE" in the response text; this is a hint that
79# the target mailbox does not exist, but that it can be created.
80my ($status, $text) = send_command("APPEND %s %s", $opt_mailbox, $msg);
81if ($status ne 'OK') {
82    if ($text =~ m/\bTRYCREATE\b/io) {
83        close_and_errorout "Mailbox $opt_mailbox does not exist"
84            if $opt_no_create;
85        print "Creating $opt_mailbox\n" if $opt_debug;
86        # send_command will error out if the CREATE fails.
87        send_command("CREATE %s", $opt_mailbox);
88        ($status, $text) = send_command("APPEND %s %s", $opt_mailbox, $msg);
89    }
90    close_and_errorout "IMAP error from $opt_host: $text"
91        if ($status ne 'OK');
92}
93
94# We are done talking to the IMAP server, close down the connection.
95close_connection();
96
97exit 0;
98
99# Read the given file's entire contents, returning it as a scalar.
100sub read_file($) {
101    my $file = $_[0];
102    local $/ = undef;
103    open(FILE, $file) || errorout "Cannot open $file: $!";
104    my $contents = <FILE>;
105    close(FILE);
106    return $contents;
107}
108
109# Subroutine to send a command to the IMAP server, and wait for the
110# response.  If the response status indicates failure (i.e. is not
111# "OK"), we error out.
112sub send_command(@) {
113    my ($fmt, @args) = @_;
114    printf("Sending: $fmt\n", @args) if $opt_debug;
115    my ($status, $text) = $client->send('', '', $fmt, @args);
116    errorout "Premature end-of-file on IMAP connection to $opt_host"
117        if $status eq 'EOF';
118    print "Response: status $status, text $text\n" if $opt_debug;
119    return ($status, $text) if wantarray;
120    close_and_errorout "IMAP error from $opt_host: $text"
121        if $status ne 'OK';
122}
123
124# Close the connection to the IMAP server, and error out.
125sub close_and_errorout($) {
126    close_connection();
127    errorout $_[0];
128}
129
130# Logout from the IMAP server, and close the connection.
131sub close_connection() {
132    $client->send('', '', "LOGOUT");
133    # Set the client reference to undef, so that perl invokes the
134    # destructor, which closes the connection.  Note that if we invoke
135    # the destructor explicitly here, then perl will still invoke it
136    # again when the program exits, thus touching memory which has
137    # already been freed.
138    $client = undef;
139}
140
141sub errorout($) {
142    print STDERR "$prog: $_[0]\n";
143    exit 1;
144}
Note: See TracBrowser for help on using the repository browser.