#!/usr/bin/perl -w
#
# $Revision: 1.10 $ $Date: 2012-07-26 17:11:47-04 $
# $Source: /home/vogelke/bin/RCS/blog,v $
# $Host: sys7.com $
# $UUID: 10660176-87a5-39c5-887a-484d295e8af3 $
#
# Original by Simon Cozens
# http://simon-cozens.org/programmer/releases/secret/blog
#
#<blog: store a blog entry from STDIN or a file.
# Optional first arg is subject; default is 'New post'.
# Changing the "Date:" line will change the post timestamp.

use strict;
use File::Temp qw/tempfile/;
use English;

$ENV{'PATH'} = "/bin:/usr/bin:/usr/local/bin:$ENV{'HOME'}/bin";
umask(022);

my ($in, $fh, $entry);
my $editor = $ENV{'EDITOR'} || 'vim';

($fh, $entry) = tempfile();
my $subject = join(' ', @ARGV) || "New post";
my $date = scalar localtime(time);

print $fh "To: vogelke-blog\n";
print $fh "Subject: $subject\n";
print $fh "Date: $date\n\n";
print $fh "Posting starts here.\n";

# If anything is coming in via STDIN, use it.
if (!interactive()) {
    open($in, "<&STDIN") or die "can't read stdin: $!\n";
    print $fh while <$in>;
    close($in);
}

close($fh);
system($editor, $entry);

# If the file is empty, dump it.
my $size = -s $entry;

if (defined($size) && $size <= 1) {
    unlink($entry) if defined($size) && $size <= 1;
    print "discarding\n";
}
else {
    unlink($entry) if sendmail($entry);
}

exit(0);

#---------------------------------------------------------------------
# Test for STDIN being something other than a TTY.
# Taken from "Perl Best Practices", p219.  There's a CPAN module
# to do this, but Scalar::Util comes standard with perl.

sub interactive {
    use Scalar::Util qw(openhandle);

    # Not interactive if output is not to terminal...
    return 0 if not -t *STDOUT;

    # If *ARGV is opened, we're interactive if...
    if (openhandle * ARGV) {

        # ...it's currently opened to the magic '-' file
        return -t *STDIN if $ARGV eq '-';

        # ...it's at end-of-file and the next file is the
        # magic '-' file
        return @ARGV > 0 && $ARGV[0] eq '-' && -t *STDIN if eof *ARGV;

        # ...it's directly attached to the terminal
        return -t *ARGV;
    }

    # If *ARGV isn't opened, it will be interactive if *STDIN is
    # attached to a terminal and either there are no files specified
    # on the command line or if there are one or more files and the
    # first is the magic '-' file.
    return -t *STDIN && (@ARGV == 0 || $ARGV[0] eq '-');
}

#---------------------------------------------------------------------
# Send file via mail.

sub sendmail {
    my ($file) = @_;

    my @command     = ("/usr/lib/sendmail", "-t");
    my $sleep_count = 0;
    my $sleep_time  = 3;
    my $pid;

    do {
        $pid = open(KID_TO_WRITE, "|-");
        unless (defined $pid) {
            warn "cannot fork: $!";
            die "bailing out" if $sleep_count++ > 6;
            sleep $sleep_time;
        }
    } until defined $pid;

    $SIG{ALRM} = sub { die "whoops, $command[0] pipe broke" };

    if ($pid) {    # parent
        my $ofh;

        open($ofh, "< $file") or die "can't read $file: $!\n";
        print KID_TO_WRITE while <$ofh>;
        close($ofh);

        if (close(KID_TO_WRITE)) {
            return (1);
        }
        else {
            warn "kid exited $?";
            return (0);
        }
    }
    else {    # child
        ($EUID, $EGID) = ($UID, $GID);
        my $program = shift(@command);
        exec($program, @command) || die "can't exec $program: $!";

        # NOTREACHED
    }
}
