Blame


1 8f7f2f4a 2021-12-17 jrmu ================================================================================
2 8f7f2f4a 2021-12-17 jrmu
3 8f7f2f4a 2021-12-17 jrmu Log Bot Explained
4 8f7f2f4a 2021-12-17 jrmu
5 8f7f2f4a 2021-12-17 jrmu logbot.pl joins a channel and then logs activity to logbot.log:
6 8f7f2f4a 2021-12-17 jrmu
7 8f7f2f4a 2021-12-17 jrmu #!/usr/bin/perl
8 8f7f2f4a 2021-12-17 jrmu use strict;
9 8f7f2f4a 2021-12-17 jrmu use warnings;
10 8f7f2f4a 2021-12-17 jrmu
11 8f7f2f4a 2021-12-17 jrmu open(my $fh, ">>logbot.log") or die "Unable to write to logbot.log";
12 8f7f2f4a 2021-12-17 jrmu select((select($fh), $|=1)[0]);
13 8f7f2f4a 2021-12-17 jrmu
14 8f7f2f4a 2021-12-17 jrmu open() attempts to append to logbot.log (>> for append, > for write).
15 8f7f2f4a 2021-12-17 jrmu We append because we want to add new logs to the end of the file, not
16 8f7f2f4a 2021-12-17 jrmu overwrite an existing file.
17 8f7f2f4a 2021-12-17 jrmu
18 8f7f2f4a 2021-12-17 jrmu If open succeeds, the filehandle will be assigned to $fh.
19 8f7f2f4a 2021-12-17 jrmu If open() fails, it returns false, which means that perl to immediately
20 8f7f2f4a 2021-12-17 jrmu quit with the message "Unable to write to logbot.log".
21 8f7f2f4a 2021-12-17 jrmu
22 8f7f2f4a 2021-12-17 jrmu package LogBot;
23 8f7f2f4a 2021-12-17 jrmu use base qw(Bot::BasicBot);
24 8f7f2f4a 2021-12-17 jrmu
25 8f7f2f4a 2021-12-17 jrmu sub date {
26 8f7f2f4a 2021-12-17 jrmu my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime();
27 8f7f2f4a 2021-12-17 jrmu my $localtime = sprintf("%04d%02d%02d %02d:%02d", $year+1900, $mon+1, $mday, $hour, $min);
28 8f7f2f4a 2021-12-17 jrmu return $localtime;
29 8f7f2f4a 2021-12-17 jrmu }
30 8f7f2f4a 2021-12-17 jrmu
31 8f7f2f4a 2021-12-17 jrmu We define the subroutine date(). WHen it is called, it returns the date and time
32 8f7f2f4a 2021-12-17 jrmu as a string in YYYYMMDD HH:MM format, where YYYY is the year, MM is the month,
33 8f7f2f4a 2021-12-17 jrmu DD is the day, HH is the hour, and MM is the minute.
34 8f7f2f4a 2021-12-17 jrmu
35 8f7f2f4a 2021-12-17 jrmu If someone sends a message, we append this to the end of the log:
36 8f7f2f4a 2021-12-17 jrmu
37 8f7f2f4a 2021-12-17 jrmu sub said {
38 8f7f2f4a 2021-12-17 jrmu my $self = shift;
39 8f7f2f4a 2021-12-17 jrmu my $arguments = shift;
40 8f7f2f4a 2021-12-17 jrmu print $fh date()." <$arguments->{who}> $arguments->{body}\n";
41 8f7f2f4a 2021-12-17 jrmu return;
42 8f7f2f4a 2021-12-17 jrmu }
43 8f7f2f4a 2021-12-17 jrmu
44 8f7f2f4a 2021-12-17 jrmu To append, we simply print a string to $fh. The string starts with
45 8f7f2f4a 2021-12-17 jrmu the date and time, followed by the nickname of the sender of the message,
46 8f7f2f4a 2021-12-17 jrmu then the message itself.
47 8f7f2f4a 2021-12-17 jrmu
48 8f7f2f4a 2021-12-17 jrmu Emotes and notices are also appended with the date and time, nickname, and
49 8f7f2f4a 2021-12-17 jrmu message.
50 8f7f2f4a 2021-12-17 jrmu
51 8f7f2f4a 2021-12-17 jrmu sub emoted {
52 8f7f2f4a 2021-12-17 jrmu my $self = shift;
53 8f7f2f4a 2021-12-17 jrmu my $arguments = shift;
54 8f7f2f4a 2021-12-17 jrmu print $fh date()." *$arguments->{who} $arguments->{body}\n";
55 8f7f2f4a 2021-12-17 jrmu return;
56 8f7f2f4a 2021-12-17 jrmu }
57 8f7f2f4a 2021-12-17 jrmu
58 8f7f2f4a 2021-12-17 jrmu sub noticed {
59 8f7f2f4a 2021-12-17 jrmu my $self = shift;
60 8f7f2f4a 2021-12-17 jrmu my $arguments = shift;
61 8f7f2f4a 2021-12-17 jrmu print $fh date()." [$arguments->{who} notice]: $arguments->{body}\n";
62 8f7f2f4a 2021-12-17 jrmu return;
63 8f7f2f4a 2021-12-17 jrmu }
64 8f7f2f4a 2021-12-17 jrmu
65 8f7f2f4a 2021-12-17 jrmu If a user joins or parts a channel, we record their full hostmask (rather
66 8f7f2f4a 2021-12-17 jrmu than just the nickname) using $arguments->{raw_nick}:
67 8f7f2f4a 2021-12-17 jrmu
68 8f7f2f4a 2021-12-17 jrmu sub chanjoin {
69 8f7f2f4a 2021-12-17 jrmu my $self = shift;
70 8f7f2f4a 2021-12-17 jrmu my $arguments = shift;
71 8f7f2f4a 2021-12-17 jrmu print $fh date()." -!- $arguments->{raw_nick} has joined $arguments->{channel}\n";
72 8f7f2f4a 2021-12-17 jrmu return;
73 8f7f2f4a 2021-12-17 jrmu }
74 8f7f2f4a 2021-12-17 jrmu
75 8f7f2f4a 2021-12-17 jrmu sub chanpart {
76 8f7f2f4a 2021-12-17 jrmu my $self = shift;
77 8f7f2f4a 2021-12-17 jrmu my $arguments = shift;
78 8f7f2f4a 2021-12-17 jrmu print $fh date()." -!- $arguments->{raw_nick} has left $arguments->{channel} $arguments->{body}\n";
79 8f7f2f4a 2021-12-17 jrmu return;
80 8f7f2f4a 2021-12-17 jrmu }
81 8f7f2f4a 2021-12-17 jrmu
82 8f7f2f4a 2021-12-17 jrmu If the topic is changed, we first check if the sender's nickname is defined.
83 8f7f2f4a 2021-12-17 jrmu If so, we log the nickname, channel, and topic:
84 8f7f2f4a 2021-12-17 jrmu
85 8f7f2f4a 2021-12-17 jrmu sub topic {
86 8f7f2f4a 2021-12-17 jrmu my $self = shift;
87 8f7f2f4a 2021-12-17 jrmu my $arguments = shift;
88 8f7f2f4a 2021-12-17 jrmu my $who = $arguments->{who};
89 8f7f2f4a 2021-12-17 jrmu if (defined($who)) {
90 8f7f2f4a 2021-12-17 jrmu print $fh date()." -!- $who changed the topic of $arguments->{channel} to: $arguments->{topic}\n";
91 8f7f2f4a 2021-12-17 jrmu }
92 8f7f2f4a 2021-12-17 jrmu return;
93 8f7f2f4a 2021-12-17 jrmu }
94 8f7f2f4a 2021-12-17 jrmu
95 8f7f2f4a 2021-12-17 jrmu If the user changes nicks, we log both the old and new nick:
96 8f7f2f4a 2021-12-17 jrmu
97 8f7f2f4a 2021-12-17 jrmu sub nickchange {
98 8f7f2f4a 2021-12-17 jrmu my $self = shift;
99 8f7f2f4a 2021-12-17 jrmu my $oldnick = shift;
100 8f7f2f4a 2021-12-17 jrmu my $newnick = shift;
101 8f7f2f4a 2021-12-17 jrmu print $fh "$oldnick is now known as $newnick\n";
102 8f7f2f4a 2021-12-17 jrmu return;
103 8f7f2f4a 2021-12-17 jrmu }
104 8f7f2f4a 2021-12-17 jrmu
105 8f7f2f4a 2021-12-17 jrmu Mode changes are a bit more complex to log because each mode change can
106 8f7f2f4a 2021-12-17 jrmu have multiple operands. For example, a channel op can op two users with one
107 8f7f2f4a 2021-12-17 jrmu command.
108 8f7f2f4a 2021-12-17 jrmu
109 8f7f2f4a 2021-12-17 jrmu First, we check if the mode change came from a channel ($chan ne "msg"). Then,
110 8f7f2f4a 2021-12-17 jrmu we check to make sure there is at least one operand. If so, we append the date,
111 8f7f2f4a 2021-12-17 jrmu the changer's nick, the changes, and the operands. We use join(", ", @$operands)
112 8f7f2f4a 2021-12-17 jrmu to join all the operands together.
113 8f7f2f4a 2021-12-17 jrmu
114 8f7f2f4a 2021-12-17 jrmu sub mode_change {
115 8f7f2f4a 2021-12-17 jrmu my $self = shift;
116 8f7f2f4a 2021-12-17 jrmu my $arguments = shift;
117 8f7f2f4a 2021-12-17 jrmu my $chan = $arguments->{channel};
118 8f7f2f4a 2021-12-17 jrmu my $operands = $arguments->{mode_operands};
119 8f7f2f4a 2021-12-17 jrmu if (defined($chan) && $chan ne "msg" && scalar(@$operands)) {
120 8f7f2f4a 2021-12-17 jrmu print $fh date()." -!- mode/$chan $arguments->{who} [$arguments->{mode_changes}] ".join(", ", @$operands)."\n";
121 8f7f2f4a 2021-12-17 jrmu }
122 8f7f2f4a 2021-12-17 jrmu return;
123 8f7f2f4a 2021-12-17 jrmu }
124 8f7f2f4a 2021-12-17 jrmu
125 8f7f2f4a 2021-12-17 jrmu Finally, we log when a user is kicked or quits:
126 8f7f2f4a 2021-12-17 jrmu
127 8f7f2f4a 2021-12-17 jrmu sub kicked {
128 8f7f2f4a 2021-12-17 jrmu my $self = shift;
129 8f7f2f4a 2021-12-17 jrmu my $arguments = shift;
130 8f7f2f4a 2021-12-17 jrmu print $fh date()." -!- $arguments->{who} kicks $arguments->{kicked} [$arguments->{reason}]\n";
131 8f7f2f4a 2021-12-17 jrmu }
132 8f7f2f4a 2021-12-17 jrmu
133 8f7f2f4a 2021-12-17 jrmu sub userquit {
134 8f7f2f4a 2021-12-17 jrmu my $self = shift;
135 8f7f2f4a 2021-12-17 jrmu my $arguments = shift;
136 8f7f2f4a 2021-12-17 jrmu print $fh " -!- $arguments->{raw_nick} quits [$arguments->{body}]\n";
137 8f7f2f4a 2021-12-17 jrmu }
138 8f7f2f4a 2021-12-17 jrmu
139 8f7f2f4a 2021-12-17 jrmu package main;
140 8f7f2f4a 2021-12-17 jrmu
141 8f7f2f4a 2021-12-17 jrmu my $bot = LogBot->new(
142 8f7f2f4a 2021-12-17 jrmu server => 'irc.example.com',
143 8f7f2f4a 2021-12-17 jrmu port => '6667',
144 8f7f2f4a 2021-12-17 jrmu channels => ['#perl104'],
145 8f7f2f4a 2021-12-17 jrmu nick => 'nickname',
146 8f7f2f4a 2021-12-17 jrmu name => 'username',
147 8f7f2f4a 2021-12-17 jrmu );
148 8f7f2f4a 2021-12-17 jrmu
149 8f7f2f4a 2021-12-17 jrmu Because we opened a file descriptor, we also need to close it once we're
150 8f7f2f4a 2021-12-17 jrmu done with the program. To do this, we assign a subroutine to $SIG{INT}.
151 8f7f2f4a 2021-12-17 jrmu This subroutine will get called whenever the bot receives an INTerrupt
152 8f7f2f4a 2021-12-17 jrmu signal (ctrl+c). Inside the subroutine, we close the filehandle $fh
153 8f7f2f4a 2021-12-17 jrmu and then shut down the bot.
154 8f7f2f4a 2021-12-17 jrmu
155 8f7f2f4a 2021-12-17 jrmu local $SIG{INT} = sub {
156 8f7f2f4a 2021-12-17 jrmu close($fh);
157 8f7f2f4a 2021-12-17 jrmu print "Quitting program...\n";
158 8f7f2f4a 2021-12-17 jrmu $bot->shutdown("Quitting...");
159 8f7f2f4a 2021-12-17 jrmu };
160 8f7f2f4a 2021-12-17 jrmu
161 8f7f2f4a 2021-12-17 jrmu $bot->run();
162 8f7f2f4a 2021-12-17 jrmu
163 8f7f2f4a 2021-12-17 jrmu ================================================================================
164 8f7f2f4a 2021-12-17 jrmu
165 8f7f2f4a 2021-12-17 jrmu Further Reading
166 8f7f2f4a 2021-12-17 jrmu
167 8f7f2f4a 2021-12-17 jrmu XML::RSS::Parser module: https://metacpan.org/pod/XML::RSS::Parser
168 8f7f2f4a 2021-12-17 jrmu
169 8f7f2f4a 2021-12-17 jrmu ================================================================================
170 8f7f2f4a 2021-12-17 jrmu
171 8f7f2f4a 2021-12-17 jrmu Learn about Loops
172 8f7f2f4a 2021-12-17 jrmu
173 8f7f2f4a 2021-12-17 jrmu View the file ~/control to learn about control structures for perl.
174 8f7f2f4a 2021-12-17 jrmu
175 8f7f2f4a 2021-12-17 jrmu ================================================================================