1#!/opt/local/bin/perl
2
3use warnings;
4use strict;
5
6use Net::Twitter;
7use DNSCheck;
8use SDBM_File;
9use Fcntl;
10
11my $dc   = DNSCheck->new;
12my $conf = $dc->config->get("twitterbot");
13my %db;
14
15tie %db, 'SDBM_File', $conf->{datafile}, O_RDWR | O_CREAT, 0666
16  or die "Failed to tie database: $!\n";
17
18my $twitter = Net::Twitter->new(
19    username   => $conf->{username},
20    password   => $conf->{password},
21    clientname => 'DNSCheck TwitterBot',
22    clientver  => '1.0',
23    clienturl  => 'http://dnscheck.iis.se/',
24) or die;
25
26unless (defined($db{since_id})) {
27    $db{since_id} = 1;
28}
29
30sub update {
31    my ($name, $text) = @_;
32
33    my $tmp = substr('@' . $name . ' ' . $text, 0, 140);
34    $twitter->update($tmp);
35
36    # print "$tmp\n";
37}
38
39sub process {
40    my ($name, $text) = @_;
41
42    my ($domain) = $text =~ m/
43        (
44            (?:\w+\.)+\w+
45        )
46    /x;
47
48    if (!defined($domain)) {
49        update($name,
50'Tweet me with a domain name, and I will reply with an assessment of its DNS correctness.'
51        );
52    } elsif ($dc->dns->preflight_check($domain)) {
53        $dc->zone->test($domain);
54        my $l = $dc->logger;
55        my $msg;
56        if ($l->count_critical > 0) {
57            $msg =
58                $l->count_critical
59              . ' critical error'
60              . ($l->count_critical == 1 ? '' : 's');
61        } elsif ($l->count_error > 0) {
62            $msg =
63              $l->count_error . ' error' . ($l->count_error == 1 ? '' : 's');
64        } elsif ($l->count_warning > 0) {
65            $msg =
66                $l->count_warning
67              . ' warning'
68              . ($l->count_warning == 1 ? '' : 's');
69        } else {
70            $msg = 'No problems';
71        }
72        update($name, sprintf('%s for %s', $msg, $domain));
73    } else {
74        update($name, sprintf('%s not found', $domain));
75    }
76}
77
78my $mentions = $twitter->mentions(
79    {
80        since_id => $db{since_id},
81        count    => 200,
82    }
83);
84
85foreach my $t (@$mentions) {
86    process($t->{user}{screen_name}, $t->{text});
87    $db{since_id} = $t->{id} if $t->{id} >= $db{since_id};
88}
89
90untie(%db);
91
92=head1 NAME
93
94twitterbot
95
96=head1 SYNOPSIS
97
98Check Twitter for mentions of a given username, look for a domain name in the
99returned tweets, test those domains and post reply tweets with (very)
100abbreviated test results.
101
102=head1 DESCRIPTION
103
104This script gets all its configuration data via the DNSCheck configuration
105system. It will look for three keys under the
106top-level key C<twitterbot>:
107
108=over
109
110=item datafile
111
112Where to store persistent data. As of this writing this is only the ID number
113of the last tweet responded to, but this may change in the future. Will
114actually write two files: the given name with suffixes .dir and .pag.
115
116=item username
117
118The Twitter username to use.
119
120=item password
121
122The password to go with the given Twitter username.
123
124=back
125
126Given a correct setup of those keys, it should work fine running the script
127regularly from L<cron>.
128
129=cut
130