App::Tweet - tweet on twitter from the command line


App-Tweet documentation Contained in the App-Tweet distribution.

Index


Code Index:

NAME

Top

App::Tweet - tweet on twitter from the command line

SYNOPSIS

Top

  use App::Tweet;

  App::Tweet->run('tell this to twitter');

  App::Tweet->reconfigure;

DESCRIPTION

Top

App::Tweet is a simple wrapper around Net::Twitter that allows for you to easily send messages (tweets) to twitter.com as a specific user. You should use the 'tweet' command to interface with this module.

The first time you run the application it will prompt you for a user name and password. This information is stored in a configuration file in your system's application data store. The password is stored in a somewhat encrypted state, but the cipher key for the encryption is stored right beside the configuration file, so it's not super-security. The permissions on the file are set to read/write only by the file owner, but that is only relevant on some systems.

If you ever need to reset or change the username or password perminantely, you can use the reconfigure method. If the change is just temporary, pass in the new username and password when running the application.

METHODS

Top

run( message => 'x', [ username => 'x', password => 'x' ] )

Runs the application and attempts to send a message to twitter using a configured username and password or the one provided as an argument to this command.

reconfigure

Forces re-prompting for the stored username and password.

AUTHOR

Top

Josh McAdams, <josh dot mcadams at gmail dot com>

BUGS

Top

Please report any bugs or feature requests to bug-file-mover at rt.cpan.org, or through the web interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=App-Tweet. I will be notified, and then you'll automatically be notified of progress on your bug as I make changes.

SUPPORT

Top

You can find documentation for this module with the perldoc command.

    perldoc App::Tweet

You can also look for information at:

* AnnoCPAN: Annotated CPAN documentation

http://annocpan.org/dist/App-Tweet

* CPAN Ratings

http://cpanratings.perl.org/d/App-Tweet

* RT: CPAN's request tracker

http://rt.cpan.org/NoAuth/Bugs.html?Dist=App-Tweet

* Search CPAN

http://search.cpan.org/dist/App-Tweet

COPYRIGHT & LICENSE

Top


App-Tweet documentation Contained in the App-Tweet distribution.

package App::Tweet;

use warnings;
use strict;

use Config::YAML;
use Crypt::CBC;
use File::HomeDir;
use File::Slurp;
use File::Spec;
use File::Touch;
use IO::Interactive qw(is_interactive);
use Log::Log4perl qw(:easy);
use Net::Twitter;
use String::Random;
use Term::Prompt;

Log::Log4perl->easy_init($ERROR);

use constant TWEET_CONFIG_FILE => '.tweet';
use constant TWEET_CIPHER_FILE => '.teewt';

our $VERSION = '1.02';

sub run {
    my ( $class, %args ) = @_;

    DEBUG "$_ => [$args{$_}]" for keys %args;

    die ERROR "message is a required argument" unless exists $args{message};

    _send_message( $args{message}, _get_configuration( \%args ) );
}

sub reconfigure {
    unlink File::Spec->join( File::HomeDir->my_data(), TWEET_CONFIG_FILE );
    _get_configuration();
}

sub _get_configuration {
    my ($args) = @_;
    my $conf = _read_configuration_file(
        File::Spec->join( File::HomeDir->my_data(), TWEET_CONFIG_FILE ),
        $args );
    return $conf;
}

sub _read_configuration_file {
    my ( $config_file, $args ) = @_;

    DEBUG "trying to read config file [$config_file]";

    my $cipher_key = _get_cipher_key();

    DEBUG "using cipher [$cipher_key]";

    my $cipher = Crypt::CBC->new( -key => $cipher_key, -cipher => 'Blowfish' );

    if ( not -e $config_file ) {
        DEBUG "creating config file [$config_file]";
        touch $config_file if not -e $config_file;
        chmod oct(600), $config_file;
    }

    my $config = Config::YAML->new( config => $config_file, );

    $config->{username} = $args->{username} if exists $args->{username};
    $config->{password} = $cipher->encrypt( $args->{password} )
      if exists $args->{password};

    if ( not defined $config->{username} ) {

        DEBUG "unable to find user name in configuration file";

        die ERROR
          "can't prompt for config file values in non-interactive environment"
          unless is_interactive();

        $config->{username} =
          prompt( 'x', 'Username: ', 'from twitter.com', qw{} );
        $config->write();
    }
    if ( not defined $config->{password} ) {

        DEBUG "unable to find password in configuration file";
        $config->{password} = $cipher->encrypt(
            prompt( 'p', 'Password: ', 'from twitter.com', qw{} ) );

        $config->write();
    }

    DEBUG "password [$config->{password}]";

    $config->{password} = $cipher->decrypt( $config->{password} );

    DEBUG "password [$config->{password}]";

    return $config;
}

sub _get_cipher_key {
    my $cipher_file =
      File::Spec->join( File::HomeDir->my_data(), TWEET_CIPHER_FILE );

    if ( not -e $cipher_file ) {

        DEBUG "cipher file not found, creating it [$cipher_file]";

        my $cipher_key = String::Random->new()->randpattern( '.' x 56 );

        DEBUG "created new cipher key [$cipher_key]";

        write_file( $cipher_file, $cipher_key );
        chmod oct(600), $cipher_file;

        return $cipher_key;
    }

    DEBUG "reading cipher file [$cipher_file]";

    return read_file($cipher_file);
}

sub _send_message {
    my ( $message, $config ) = @_;

    DEBUG "accessing twitter as [$config->{username}]";

    my $twitter = Net::Twitter->new(
        username => $config->{username},
        password => $config->{password},
    );

    DEBUG "sending message to twitter [$message]";

    $twitter->update($message)
      or ERROR
"something bad happened and I couldn't sent your message.  you might not be able to connect to twitter (try visiting twitter.com in your browser) or you might be using the wrong user name or password.";

    return;
}

1;

__END__