Wednesday, August 8, 2012

Conky Perl Script (gmail.pl)

Here's the script to parse the gmail feed. You'll have to change USERNAME and PASSWORD to your own. I couldn't find a simple XML parser for any language other than perl (I didn't really want to use Java, Lua doesn't seem to have a proper parser at all). The perl one is actually pretty awesome. It just makes a tree out of the XML data and you can navigate it easily. You can see what the data structure looks like with Dumper and adjust the arguments to XMLin accordingly.

#!/usr/bin/perl

# use module
use XML::Simple; # needs libxml-simple-perl
# use Data::Dumper;
use WWW::Curl::Easy; # needs libwww-curl-perl
use Time::Piece;
use POSIX;

# NOTE: compared to C, %ARGV == argv + 1 (i.e. no program name)
# $#ARGV == argc - 2; (-1 for no program, -1 because perl is retarded)

$timeout = ($#ARGV >= 0 and isdigit $ARGV[0]) ? $ARGV[0] : 5;

$checktime = localtime->time; 

# grab the XML data
my $curl = WWW::Curl::Easy->new;
        
$curl->setopt(CURLOPT_HEADER, 0);
$curl->setopt(CURLOPT_USERPWD, 'USERNAME@gmail.com:PASSWORD');
$curl->setopt(CURLOPT_URL, 'https://mail.google.com/mail/feed/atom');
$curl->setopt(CURLOPT_VERBOSE, 0);
$curl->setopt(CURLOPT_TIMEOUT, $timeout);

my $response_body; # write raw data here
$curl->setopt(CURLOPT_WRITEDATA,\$response_body);

@colors = ('${color darkgreen}', '${color blue}');
$white = '${color white}';
$red = '${color red}';
$grey = '${color grey}';

my $retcode = $curl->perform; # Starts the actual request
if ($retcode != 0) { print "${red}Gmail: Couldn't retrieve XML data!\n"; exit 1; }

# read XML file
$xml = new XML::Simple;
$data = $xml->XMLin($response_body, ForceArray => [ 'contributor', 'entry' ]);
# print Dumper($data);

# exit on bad credentials 
if ($data->{HEAD}->{TITLE} eq "Unauthorized") { print "${red}Gmail credentials invalid!\n"; exit; }

print "Gmail (${white}$data->{fullcount} ${grey}new messages at ${white}${checktime}${grey}):\n";
# if ($data->{fullcount} > 0) { print '${color white}'."$data->{tagline}\n"; }

if ($data->{fullcount} == 0) { exit; }

my $i = 0;
while (($message, $elems) = each($data->{entry}))
{
 my $subject = ref($elems->{title}) eq "" ? $elems->{title} : "(no subject)";
 my $summary = ref($elems->{summary}) eq "" ? $elems->{summary} : "(no body)";
 my $utctime = $elems->{modified};
 
 my $time = Time::Piece->strptime($utctime, "%Y-%m-%dT%H:%M:%SZ");
 $time += $time->localtime->tzoffset;
 
 # print "$elems->{author}->{name} ($elems->{author}->{email}) at ".$time->time." on ".$time->date."\n";
 print  "$colors[$i]from: ${white}$elems->{author}->{name}".
  "$colors[$i] at ${white}".$time->time.
  "$colors[$i] on ${white}".$time->date."\n";
 
 my $cntr = $elems->{contributor};
 my $count = keys(%$cntr);
 if ($count > 0)
 {
  print "$colors[$i]".'and:  ';

  while (($name, $props) = each(%$cntr))
  {
   # print "$name ($props->{email}), ";
   print "${white}$name$colors[$i], ";
  }
  print "\n";
 }
 
 print "$colors[$i]subj: ${white}$subject\n";
 print "$colors[$i]body: ${white}$summary\n";
 $i = ($i + 1) & 1;
}

1 comment:

  1. Hi,

    I was wondering if there was a way to have the output sorted by time as in the atom feed (most recent at the top ideally). Right now the output seems to be sorted randomly and changes upon every run. I have it set to run every minute in conky and the constant reordering is distracting.

    Thanks,
    Mat

    ReplyDelete