http://qs321.pair.com?node_id=169265
Category: cgi programming
Author/Contact Info hagus
Description: This is some code I whipped up to automate the tedious process of using Vodafone.com.au's web2sms facility. Given an account on this site, you can use my script to send SMSs from the command line.

It might also serve as quick template code for anyone contemplating similar types of things. It fetches several URLs, stores cookies, handles redirects on POSTs, etc.

Required modules: LWP::UserAgent and friends, plus Crypt::SSLeay

Updated: Incensed by graff's critique, I raged through the house smashing crockery and garden gnomes. When the plaster dust had settled, I refactored the code into a nightmarish perl structure state machine. Muahahaha. (as opposed to the nightmarish if/then/else it was before).

Updated again: An exercise for the reader would be to introduce hooks that parse the HTML. At the moment if you don't successfully login, it silently fails. Hint: subclass HTML::Parse.

#!/usr/bin/perl

use warnings;
use strict;

package MyAgent;

use base 'LWP::UserAgent';

sub redirect_ok
{
    my ($self, $request) = @_;
    return 1;
}

package URLStateMachine;

use HTTP::Request::Common qw(POST);
use LWP::UserAgent;
use HTTP::Cookies;

sub new
{
    my $class = shift;
    my $args = shift;

    my $self = { states => $args };

    $self->{ua} = new MyAgent;
    $self->{cookieJar} = new HTTP::Cookies;
    $self->{ua}->cookie_jar($self->{cookieJar});

    return bless($self, $class);
}

sub run
{
    my $self = shift;

    my @stateList = @{$self->{states}};

    foreach my $state (@stateList)
    {
        my $res;
        $self->logmsg($state->{info});
        if ($state->{method} eq 'GET')
        {
            $res = $self->{ua}->request(new HTTP::Request(GET => $stat
+e->{url}));
            $res->is_success or $self->logerr($res->status_line);
        }
        elsif ($state->{method} eq 'POST')
        {
            $res = $self->{ua}->request(POST $state->{url},
                                           $state->{args});
            $res->is_success or $self->logerr($res->status_line);
        }
    }
}

sub logerr
{
    my $self = shift;
    my $msg = shift;
    print scalar localtime(time) . " ERROR: $msg\n";
}

sub logmsg
{
    my $self = shift;
    my $msg = shift;
    print scalar localtime(time) . " INFO: $msg\n";
}

package main;

my $config = {
    username => 'blah',
    password => 'foo',
    };

unless (@ARGV == 2)
{
    print "Arguments: [phone numbers] [message]\n";
    exit 1;
}

my @stateConfig
    = (
       { name   => 'get_homepage',
         method => 'GET',
         url     => "https://www1.myvodafone.com.au",
         info   => "Getting homepage ...", },

       { name   => 'login',
         method => 'POST',
         url     => "https://www1.myvodafone.com.au/userpages",
         info   => "Logging in ...",
         args   => [ login       => $config->{username},
                     password => $config->{password},
                     TYPE       => 'login' ] },
       
       { name   => 'get_form',
         method => 'GET',
         info   => "Getting SMS page ...",
         url     => "https://www1.myvodafone.com.au/userpages/web2txt.
+fcgi"
         },
       
       { name   => 'submit_form',
         method => 'POST',
         url     => "https://www1.myvodafone.com.au/userpages/web2txt.
+fcgi",
         info   => "Submitting form ...",
         args   => [ sendmsg => 1,
                     message => $ARGV[1],
                     min      => $ARGV[0] ]
                     },
       );

my $machine = new URLStateMachine(\@stateConfig);
$machine->run;