|
|
| version 1.1, 2025/02/03 04:22:49 | version 1.6, 2025/02/05 01:03:18 |
|---|---|
| Line 9 | Line 9 |
| # Licensed AGPL-3.0 | # Licensed AGPL-3.0 |
| # | # |
| # $Log$ | # $Log$ |
| # Revision 1.1 2025/02/03 04:22:49 snw | # Revision 1.6 2025/02/05 01:03:18 snw |
| # Initial revision | # Fix invite and seen commands to support screen names with spaces |
| # | |
| # Revision 1.5 2025/02/03 18:14:15 snw | |
| # Further work on bot | |
| # | |
| # Revision 1.4 2025/02/03 17:31:28 snw | |
| # Further MySQL work | |
| # | |
| # Revision 1.3 2025/02/03 15:38:12 snw | |
| # Begin SQL work | |
| # | |
| # Revision 1.2 2025/02/03 04:28:34 snw | |
| # Fix syntax message | |
| # | |
| # Revision 1.1.1.1 2025/02/03 04:22:49 snw | |
| # Initial Commit | |
| # | # |
| # | # |
| # | # |
| Line 19 use Net::OSCAR; | Line 34 use Net::OSCAR; |
| use Getopt::Long; | use Getopt::Long; |
| use Data::Dumper; | use Data::Dumper; |
| use HTML::Strip; | use HTML::Strip; |
| use DBI; | |
| my $idlemax = 1800; | my $idlemax = 1800; |
| my $botsn = ''; | my $botsn = ''; |
| my $botsrv = ''; | my $botsrv = ''; |
| my $botpw = ''; | my $botpw = ''; |
| my $rasurl = ''; | my $rasurl = ''; |
| my $dbhost = ''; | |
| my $dbname = ''; | |
| my $dbusername = ''; | |
| my $dbpw = ''; | |
| my $dbconn = ''; | |
| my $autogreet = 'off'; | |
| my $chatroom = ''; | my $chatroom = ''; |
| my $online = 0; | my $online = 0; |
| my $chat_idle_seconds = 0; | my $chat_idle_seconds = 0; |
| my $last_chat_received = time(); | my $last_chat_received = time(); |
| my $start_time = time(); | my $start_time = time(); |
| my $dbh = ''; | |
| my $dsn = ''; | |
| my @congregants = (); | my @congregants = (); |
| my %seen = (); | |
| GetOptions("aimsn=s" => \$botsn, | $oscar = Net::OSCAR->new(); |
| "aimhost=s" => \$botsrv, | |
| "aimpw=s" => \$botpw, | |
| "idlemax=s" => \$idlemax, | |
| "chatroom=s" => \$chatroom) | |
| or die("error in command line arguments"); | |
| %signon = ( | sub get_seen_status { |
| screenname => $botsn, | my($sn, $chat) = @_; |
| password => $botpw, | |
| host => $botsrv, | |
| ); | |
| $oscar = Net::OSCAR->new(); | my $sth = $dbh->prepare("SELECT * FROM seen WHERE aim_server=? AND aim_sn=? AND aim_chatroom=? AND sn=?"); |
| #$room = Net::OSCAR::Connection::Chat; | $sth->execute($botsrv, $botsn, $chatroom, $sn); |
| if($sth->rows > 0) { | |
| my $hashref = $sth->fetchrow_hashref(); | |
| $chat->chat_send("I last saw <strong>$sn</strong> on $hashref->{seen_time}."); | |
| } | |
| else { | |
| $chat->chat_send("I have never seen <strong>$sn</strong>."); | |
| } | |
| } | |
| sub update_seen_status { | |
| my($sn) = @_; | |
| my $del = $dbh->prepare("DELETE FROM seen WHERE aim_server=? AND aim_sn=? AND aim_chatroom=? AND sn=?"); | |
| $del->execute($botsrv, $botsn, $chatroom, $sn) or die "error DBI->errstr()"; | |
| my $ins = $dbh->prepare("INSERT INTO seen (aim_server, aim_sn, aim_chatroom, sn, seen_time) VALUES (?, ?, ?, ?, ?)"); | |
| my $seentime = localtime(); | |
| $ins->execute($botsrv, $botsn, $chatroom, $sn, $seentime) or die "error DBI->errstr()"; | |
| } | |
| sub signon_done { | sub signon_done { |
| print "[OK]\n"; | print "[OK]\n"; |
| print "convobot: joining $chatroom..."; | |
| $oscar->chat_join($chatroom, 5); | $oscar->chat_join($chatroom, 5); |
| print "[OK]\n"; | |
| $online = 1; | $online = 1; |
| } | } |
| sub oscar_error { | |
| my($oscar, $connection, $error, $description, $fatal) = @_; | |
| if($fatal != 0) { | |
| die "\nconvobot: fatal OSCAR error: $description\n"; | |
| } | |
| else { | |
| print "\nconvobot: recoverable OSCAR error: $description\n"; | |
| } | |
| } | |
| sub chat_joined { | sub chat_joined { |
| my($oscar, $chatname, $chat) = @_; | my($oscar, $chatname, $chat) = @_; |
| print "bot: chat joined [$chatname]\n"; | |
| $room = $chat; | $room = $chat; |
| bless $room, "Net::OSCAR::Connection::Chat"; | bless $room, "Net::OSCAR::Connection::Chat"; |
| print "convobot: connecting to database $dbname\@$dbhost..."; | |
| $dsn = "DBI:mysql:database=$dbname;host=$dbhost;port=3306;mysql_connect_timeout=5;"; | |
| $dbh = DBI->connect($dsn, $dbusername, $dbpw, {RaiseError => 1}); | |
| die "convobot: failed to connect to MySQL database: DBI->errstr()" unless $dbh; | |
| print "[OK]\n"; | |
| $oscar->set_callback_chat_buddy_in(\&chat_buddy_in); | |
| $oscar->set_callback_chat_buddy_out(\&chat_buddy_out); | |
| } | } |
| sub chat_buddy_in { | sub chat_buddy_in { |
| my ($oscar, $who, $chat, $buddy) = @_; | my ($oscar, $who, $chat, $buddy) = @_; |
| $seen{$who} = localtime(); | update_seen_status($who); |
| if($who ne $botsn) { | if($who ne $botsn) { |
| push(@congregants, $who); | push(@congregants, $who); |
| print "[$who] has joined\n"; | print "convobot: [$who] has joined\n"; |
| } | } |
| else { | else { |
| print "[$who] has joined (ignoring bot)\n"; | print "convobot: [$who] has joined (ignoring bot)\n"; |
| } | } |
| if(time() - $start_time > 2) { | |
| my @phrases = ('Welcome to [room], [user]! :-)', | if($autogreet eq "on") { |
| 'How\'s it going, [user]?', | if(time() - $start_time > 2) { |
| 'Hey [user]! Bring any snacks?', | my @phrases = ('Welcome to [room], [user]! :-)', |
| 'Heya [user]! Hope your day is going well!', | 'How\'s it going, [user]?', |
| 'Ooo, [user] has joined [room]! Now the party can start!'); | 'Hey [user]! Bring any snacks?', |
| 'Heya [user]! Hope your day is going well!', | |
| my $phrase = $phrases[rand @phrases]; | 'Ooo, [user] has joined [room]! Now the party can start!'); |
| $phrase =~ s/\[user\]/$who/g; | |
| $phrase =~ s/\[room\]/$chatroom/g; | my $phrase = $phrases[rand @phrases]; |
| my $phrasefix = "<div id=convobot></div>$phrase"; | $phrase =~ s/\[user\]/$who/g; |
| $chat->chat_send($phrasefix); | $phrase =~ s/\[room\]/$chatroom/g; |
| } | my $phrasefix = "<div id=convobot></div>$phrase"; |
| else { | $chat->chat_send($phrasefix); |
| print "Not sending greeting for 2 seconds after startup\n"; | } |
| else { | |
| print "convobot: not sending greeting for 2 seconds after startup\n"; | |
| } | |
| } | } |
| } | } |
| Line 101 sub chat_buddy_out { | Line 169 sub chat_buddy_out { |
| $index++ until $congregants[$index] eq $who; | $index++ until $congregants[$index] eq $who; |
| splice(@congregants, $index, 1); | splice(@congregants, $index, 1); |
| print "$who has left\n"; | print "convobot: $who has left\n"; |
| } | } |
| sub chat_im_in { | sub chat_im_in { |
| Line 111 sub chat_im_in { | Line 179 sub chat_im_in { |
| my $rawcmd = $hs->parse($message); | my $rawcmd = $hs->parse($message); |
| my @cmd = split(' ', $rawcmd); | my @cmd = split(' ', $rawcmd); |
| $seen{$who} = localtime(); | update_seen_status($who); |
| if($cmd[0] eq "!seen") { | if($who ne $botsn) { |
| if(exists($cmd[1])) { | if($cmd[0] eq "!seen") { |
| if(exists($seen{$cmd[1]})) { | if(exists($cmd[1])) { |
| $chat->chat_send("I last saw $cmd[1] at $seen{$cmd[1]}"); | my @sna = @cmd[1..$#cmd]; |
| } | my $ssn = join(' ', @sna); |
| else { | get_seen_status($ssn, $chat); |
| $chat->chat_send("I've never seen $cmd[1]"); | } |
| } | else { |
| } | $chat->chat_send("Syntax: !seen <em>screenname</em>"); |
| else { | } |
| $chat->chat_send("Syntax: !seen <screenname>"); | } |
| } | elsif($cmd[0] eq "!speak") { |
| send_idle_message(); | |
| } | |
| elsif($cmd[0] eq "!quote") { | |
| my $fortune = `/usr/games/fortune`; | |
| $room->chat_send($fortune); | |
| } | |
| elsif($cmd[0] eq "!invite") { | |
| if(exists($cmd[1])) { | |
| my @sna = @cmd[1..$#cmd]; | |
| my $ssn = join(' ', @sna); | |
| $chat->invite($ssn, "Please join us in $chatroom! <br><em>Requested by $who</em>"); | |
| } | |
| } | |
| elsif($cmd[0] eq "!help") { | |
| $room->chat_send("You can enter the following commands:"); | |
| $room->chat_send(" <code>!seen <em>screenname</em></code> (find out when <em>screenname</em> was last in the chat)"); | |
| $room->chat_send(" <code>!invite <em>screenname</em></code> (invite <em>screenname</em> to the chat)"); | |
| $room->chat_send(" <code>!speak</code> (send a random message)"); | |
| $room->chat_send(" <code>!quote</code> (send a quote)"); | |
| } | |
| } | } |
| $last_chat_received = time(); | $last_chat_received = time(); |
| print "chat received from $who; resetting idle counter\n"; | print "convobot: chat received from $who; resetting idle counter\n"; |
| } | } |
| Line 156 sub send_idle_message { | Line 243 sub send_idle_message { |
| $room->chat_send($phrasefix); | $room->chat_send($phrasefix); |
| $last_chat_received = time(); | $last_chat_received = time(); |
| } | } |
| } | } |
| $oscar->set_callback_signon_done(\&signon_done); | $oscar->set_callback_signon_done(\&signon_done); |
| $oscar->set_callback_chat_joined(\&chat_joined); | $oscar->set_callback_chat_joined(\&chat_joined); |
| $oscar->set_callback_chat_buddy_in(\&chat_buddy_in); | |
| $oscar->set_callback_chat_buddy_out(\&chat_buddy_out); | |
| $oscar->set_callback_chat_im_in(\&chat_im_in); | $oscar->set_callback_chat_im_in(\&chat_im_in); |
| $oscar->set_callback_error(\&oscar_error); | |
| print "ChivaNet Conversation Bot v0.0.1\n"; | print "ChivaNet Conversation Bot v0.0.1\n"; |
| print " Copyright (C) 2025 Coherent Logic Development LLC\n\n"; | print " Copyright (C) 2025 Coherent Logic Development LLC\n\n"; |
| print "bot: attempting to sign in... "; | GetOptions("aimsn=s" => \$botsn, |
| "aimhost=s" => \$botsrv, | |
| "aimpw=s" => \$botpw, | |
| "idlemax=s" => \$idlemax, | |
| "chatroom=s" => \$chatroom, | |
| "dbhost=s" => \$dbhost, | |
| "dbname=s" => \$dbname, | |
| "dbusername=s" => \$dbusername, | |
| "dbpw=s" => \$dbpw, | |
| "autogreet=s" => \$autogreet) | |
| or die("error in command line arguments"); | |
| %signon = ( | |
| screenname => $botsn, | |
| password => $botpw, | |
| host => $botsrv, | |
| ); | |
| print "AIM Server: $botsrv\n"; | |
| print "AIM Screen Name: $botsn\n"; | |
| print "Chat Room: $chatroom\n"; | |
| print "DB Host: $dbhost\n"; | |
| print "DB Name: $dbname\n"; | |
| print "DB Username: $dbusername\n"; | |
| print "Idle before ping: $idlemax\n"; | |
| print "Auto-Greet: $autogreet\n\n"; | |
| print "convobot: attempting to sign in..."; | |
| $oscar->signon(%signon); | $oscar->signon(%signon); |
| while(1) { | while(1) { |