Commit Diff


commit - 1eb65f132eae3f020aec86b81dd5dd762c771e60
commit + 6be16d90c2213d61bf83fc1306d62ea0917d5845
blob - e3f95c126844123d2a48346fcaf8d02cd15b0186
blob + 37959c6e810c6e626b717ec160ca5eac51091798
--- lib/IRCNOW/IO/IRC.pm
+++ lib/IRCNOW/IO/IRC.pm
@@ -196,5 +196,314 @@ sub isstaff {
 	}
 	return 0;
 }
+
+sub parse_response {
+		my ($self, $bot, $response) = @_;
+		my $staff=$self->{staff};
+		my $nick=$self->{nick};
+		my $pass=$self->{pass};
+		my $expires=$self->{expires};
+		my $chans=$self->{chans};
+		my $teamchans=$self->{teamchans};
+
+		if ($response =~ /^PING :(.*)\r\n$/i) {
+			$self->putserv($bot, "PONG :$1");
+		} elsif ($response =~ /^:irc.znc.in (.*) (.*) :(.*)\r\n$/) {
+			my ($type, $target, $text) = ($1, $2, $3);
+			if ($type eq "464" && $target =~ /^$nick.?$/ && $text eq "Password required") {
+				$self->putserv($bot, "PASS $nick/$bot->{name}:$pass");
+				if ($bot->{name} =~ /^$localnet$/i) {
+					$self->putserv($bot, "OPER $nick $pass");
+					$self->putserv($bot, "PRIVMSG *status :LoadMod --type=user controlpanel");
+					$self->putserv($bot, "PRIVMSG *controlpanel :get Admin $nick");
+					$self->putserv($bot, "PRIVMSG *controlpanel :get Nick cloneuser");
+					foreach my $chan (@$teamchans) {
+						$self->putserv($bot, "JOIN $chan");
+					}
+				}
+				if ($bot->{name} !~ /^$localnet$/i) {
+					foreach my $chan (@$chans) {
+						$self->putserv($bot, "JOIN $chan");
+					}
+				}
+			} elsif ($type eq "464" && $target =~ /^$nick.?$/ && $text eq "Invalid Password") {
+				die "ERROR: Wrong Username/Password: $bot->{name}";
+			} else {
+				debug(ALL, "Debug type: $type, target: $target, text: $text");
+			}
+		} elsif($response =~ /^:(([^!]+)!([^@]+@[^@ ]+)) PRIVMSG ([^ ]+) :(.*)\r\n$/i) {
+			chomp($response);
+			debug(ALL, "-->COMMAND--> $response");
+			my ($hostmask, $sendnick, $host, $target, $text) = ($1, $2, $3, $4, $5);
+			if ($hostmask eq '*status!znc@znc.in' && $target =~ /^$nick.?$/) {
+				if ($text =~ /Network ([[:ascii:]]+) doesn't exist./) {
+					debug(ERRORS, "ERROR: nonexistent: $1");
+				} elsif ($text eq "You are currently disconnected from IRC. Use 'connect' to reconnect.") {
+					debug(ERRORS, "ERROR: disconnected: $bot->{name}");
+				} elsif ($text =~ /Unable to load module (.*): Module (.*) already loaded./) {
+					debug(ALL, "Module $1 already loaded\n");
+				} elsif ($text =~ /^Disconnected from IRC.*$/) {
+					debug(ERRORS, "ERROR: $bot->{name}: $text");
+				} elsif ($text =~ /^|/) {
+					debug(ERRORS, "ERROR: $bot->{name}: $text");
+				} else {
+					debug(ERRORS, "ERROR: Unexpected: $response");
+				}
+			} elsif ($text =~ /^!([[:graph:]]+)\s*(.*)/) {
+				my ($cmd, $text) = ($1, $2);
+				debug(ALL, qq{<<COMMAND: $cmd; TEXT: $text>>});
+				my $hand = $staff; # TODO fix later
+				if ($target =~ /^#/) {
+					foreach my $c (@{$call->{pub}}) {
+						if ($cmd eq $c->{cmd}) {
+							my $proc = $c->{proc};
+							$proc->($bot, $sendnick, $host, $hand, $target, $text);
+						}
+					}
+				} else {
+					foreach my $c (@{$call->{msg}}) {
+						if ($cmd eq $c->{cmd}) {
+							my $proc = $c->{proc};
+							$proc->($bot, $sendnick, $host, $hand, $text);
+						}
+					}
+				}
+			} else {
+				my $hand = $staff; # TODO fix later
+				if ($target =~ /^#/) {
+					foreach my $c (@{$call->{pubm}}) {
+						my $proc = $c->{proc};
+						$proc->($bot, $sendnick, $host, $hand, $target, $text);
+					}
+				} else {
+					foreach my $c (@{$call->{msgm}}) {
+						my $proc = $c->{proc};
+						$proc->($bot, $sendnick, $host, $hand, $text);
+					}
+				}
+			}
+			debug(ALL, "$hostmask $target $text");
+		} elsif($response =~ /^:([^ ]+) NOTICE ([^ ]+) :(.*)\r\n$/i) {
+			my ($hostmask, $target, $text) = ($1, $2, $3);
+			if ($hostmask =~ /([^!]+)!([^@]+@[^@ ]+)/) {
+				my ($sendnick, $host) = ($1, $2);
+				my $hand = $staff; # TODO fix later
+				foreach my $c (@{$call->{notc}}) {
+					#	if ($text eq $c->{mask}) { # TODO fix later
+					my $proc = $c->{proc};
+					$proc->($bot, $sendnick, $host, $hand, $text, $target);
+					#	}
+				}
 
+				# CTCP replies
+				if ($hostmask ne '*status!znc@znc.in') {
+					if ($text =~ /^(PING|VERSION|TIME|USERINFO) (.*)$/i) {
+						my ($key, $val) = ($1, $2);
+						my $id = BotNow::SQLite::id("irc", "nick", $sendnick, $expires);
+						BotNow::SQLite::set("irc", "id", $id, "ctcp".lc($key), $val);
+						BotNow::SQLite::set("irc", "id", $id, "localtime", time());
+					}
+				}
+			}
+			debug(ALL, "$hostmask NOTICE $target $text");
+#:portlane.se.quakenet.org NOTICE guava :Highest connection count: 1541 (1540 clients)
+#:portlane.se.quakenet.org NOTICE guava :on 2 ca 2(4) ft 20(20) tr
+		} elsif($response =~ /^:([^ ]+) MODE ([^ ]+) ([^ ]+)\s*(.*)\r\n$/i) {
+			my ($hostmask, $chan, $change, $targets) = ($1, $2, $3, $4);
+			if ($hostmask =~ /([^!]+)!([^@]+@[^@ ]+)/) {
+				my ($sendnick, $host) = ($1, $2);
+				my $hand = $staff; # TODO fix later
+				foreach my $c (@{$call->{mode}}) {
+					# TODO filter by mask
+					my $proc = $c->{proc};
+					$proc->($bot, $sendnick, $host, $hand, $chan, $change, $targets);
+				}
+			}
+			debug(ALL, "$hostmask MODE $chan $change $targets");
+#:guava!guava@guava.guava.ircnow.org MODE guava :+Ci
+#:ChanServ!services@services.irc.ircnow.org MODE #testing +q jrmu
+#:jrmu!jrmu@jrmu.staff.ircnow.org MODE #testing +o jrmu
+#Unexpected bncnow.pl 460: :irc.guava.ircnow.org MODE guava :+o
+		} elsif($response =~ /^:(([^!]+)!([^@]+@[^@ ]+)) JOIN :?(.*)\r\n$/i) {
+			my ($hostmask, $sendnick, $host, $chan) = ($1, $2, $3, $4);
+			my $hand = $staff; # TODO fix later
+			foreach my $c (@{$call->{join}}) {
+				my $proc = $c->{proc};
+				$proc->($bot, $sendnick, $host, $hand, $chan);
+			}
+			debug(ALL, "$hostmask JOIN $chan");
+#:jrmu!jrmu@jrmu.staff.ircnow.org JOIN :#testing
+		} elsif($response =~ /^:(([^!]+)!([^@]+@[^@ ]+)) PART ([^ ]+) :(.*)\r\n$/i) {
+			my ($hostmask, $sendnick, $host, $chan, $text) = ($1, $2, $3, $4, $5);
+			my $hand = $staff; # TODO fix later
+			foreach my $c (@{$call->{part}}) {
+				#	if ($text eq $c->{mask}) { # TODO fix later
+				my $proc = $c->{proc};
+				$proc->($bot, $sendnick, $host, $hand, $chan, $text);
+				#	}
+			}
+			debug(ALL, "$hostmask PART $chan :$text");
+#:jrmu!jrmu@jrmu.staff.ircnow.org PART #testing :
+		} elsif($response =~ /^:(([^!]+)!([^@]+@[^@ ]+)) KICK (#[^ ]+) ([^ ]+) :(.*)\r\n$/i) {
+			my ($hostmask, $sendnick, $host, $chan, $kicked, $text) = ($1, $2, $3, $4, $5, $6);
+			my $hand = $staff; # TODO fix later
+			foreach my $c (@{$call->{kick}}) {
+				#	if ($text eq $c->{mask}) { # TODO fix later
+				my $proc = $c->{proc};
+				$proc->($bot, $sendnick, $host, $hand, $chan, $text);
+				#	}
+			}
+			debug(ALL, "$hostmask KICK $chan $kicked :$text");
+#jrmu!jrmu@jrmu.users.undernet.org KICK #ircnow guava :this is a test
+		} elsif($response =~ /^:(([^!]+)!([^@]+@[^@ ]+)) NICK :?(.*)\r\n$/i) {
+			my ($hostmask, $sendnick, $host, $text) = ($1, $2, $3, $4);
+			debug(ALL, "$hostmask NICK $text");
+#:Fly0nDaWaLL|dal!psybnc@do.not.h4ck.me NICK :nec|dal
+		} elsif($response =~ /^:(([^!]+)!([^@]+@[^@ ]+)) QUIT :(.*)\r\n$/i) {
+			my ($hostmask, $sendnick, $host, $text) = ($1, $2, $3, $4);
+			debug(ALL, "$hostmask QUIT :$text");
+#:Testah!~sid268081@aa38a510 QUIT :Client closed connection
+		} elsif($response =~ /^NOTICE AUTH :(.*)\r\n$/i) {
+			my ($text) = ($1);
+			debug(ALL, "NOTICE AUTH: $text");
+#NOTICE AUTH :*** Looking up your hostname
+#NOTICE AUTH: *** Looking up your hostname
+#NOTICE AUTH: *** Checking Ident
+#NOTICE AUTH: *** Got ident response
+#NOTICE AUTH: *** Found your hostname
+		} elsif ($response =~ /^:([[:graph:]]+) (\d\d\d) $nick.? :?(.*)\r?\n?\r$/i) {
+			my ($server, $code, $text) = ($1, $2, $3);
+			if ($code =~ /^001$/) { # Server Info
+				debug(ERRORS, "connected: $bot->{name}");
+			} elsif ($code =~ /^0\d\d$/) { # Server Info
+				debug(ALL, "$server $code $text");
+			} elsif ($code =~ /^2\d\d$/) { # Server Stats
+				debug(ALL, "$server $code $text");
+			} elsif ($code == 301 && $text =~ /^([-_\|`a-zA-Z0-9]+) :([[:graph:]]+)/) {
+				debug(ALL, "$text");
+			} elsif ($code == 307 && $text =~ /^([-_\|`a-zA-Z0-9]+) (.*)/) {
+				my ($sender, $key) = ($1, "registered");
+				my $val = $2 eq ":is a registered nick" ? "True" : "$2";
+				my $id = BotNow::SQLite::id("irc", "nick", $sender, $expires);
+				BotNow::SQLite::set("irc", "id", $id, "identified", $val);
+				debug(ALL, "$key: $val");
+			} elsif ($code == 311 && $text =~ /^([-_\|`a-zA-Z0-9]+) ([^:]+)\s+([^:]+) \* :([^:]*)/) {
+				my ($sender, $key, $val) = ($1, "hostmask", "$1\!$2\@$3");
+				my $id = BotNow::SQLite::id("irc", "nick", $sender, $expires);
+				BotNow::SQLite::set("irc", "id", $id, $key, $val);
+				debug(ALL, "$key: $val");
+			} elsif ($code == 312 && $text =~ /^([-_\|`a-zA-Z0-9]+) ([^:]+) :([^:]+)/) {
+				my ($sender, $key, $val) = ($1, "server", $2);
+				my $id = BotNow::SQLite::id("irc", "nick", $sender, $expires);
+				BotNow::SQLite::set("irc", "id", $id, $key, $val);
+				debug(ALL, "$key: $val");
+			} elsif ($code == 313 && $text =~ /^([-_\|`a-zA-Z0-9]+) :?(.*)/) {
+				my ($sender, $key, $val) = ($1, "oper", ($2 eq "is an IRC operator" ? "True" : "$2"));
+				my $id = BotNow::SQLite::id("irc", "nick", $sender, $expires);
+				BotNow::SQLite::set("irc", "id", $id, $key, $val);
+				debug(ALL, "$key: $val");
+			} elsif ($code == 315 && $text =~ /^([-_\|`a-zA-Z0-9]+) :End of \/?WHO(IS)? list/) {
+				debug(ALL, "End of WHOIS");
+			} elsif ($code == 317 && $text =~ /^([-_\|`a-zA-Z0-9]+) (\d+) (\d+) :?(.*)/) {
+				my ($sender, $idle, $epochtime) = ($1, $2, $3);
+				my $id = BotNow::SQLite::id("irc", "nick", $sender, $expires);
+				BotNow::SQLite::set("irc", "id", $id, "idle", $idle);
+#				BotNow::SQLite::set("irc", "id", $id, "epochtime", time());
+				debug(ALL, "idle: $idle, epochtime: $epochtime");
+			} elsif ($code == 318 && $text =~ /^([-_\|`a-zA-Z0-9]+) :End of \/?WHOIS list/) {
+				debug(ALL, "End of WHOIS");
+			} elsif ($code == 319 && $text =~ /^([-_\|`a-zA-Z0-9]+) :(.*)/) {
+				my ($sender, $key, $val) = ($1, "chans", $2);
+				my $id = BotNow::SQLite::id("irc", "nick", $sender, $expires);
+				BotNow::SQLite::set("irc", "id", $id, $key, $val);
+				debug(ALL, "$key: $val");
+			} elsif ($code == 330 && $text =~ /^([-_\|`a-zA-Z0-9]+) ([-_\|`a-zA-Z0-9]+) :?(.*)/) {
+				my ($sender, $key, $val) = ($1, "identified", ($3 eq "is logged in as" ? "True" : $2));
+				my $id = BotNow::SQLite::id("irc", "nick", $sender, $expires);
+				BotNow::SQLite::set("irc", "id", $id, $key, $val);
+				debug(ALL, "$key: $val");
+			} elsif ($code == 338 && $text =~ /^([-_\|`a-zA-Z0-9]+) ([0-9a-fA-F:.]+) :actually using host/) {
+				my ($sender, $key, $val) = ($1, "ip", $2);
+				my $id = BotNow::SQLite::id("irc", "nick", $sender, $expires);
+				BotNow::SQLite::set("irc", "id", $id, $key, $val);
+				debug(ALL, "$key: $val");
+	#Unexpected: efnet.port80.se 338 jrmu 206.253.167.44 :actually using host
+			} elsif ($code == 378 && $text =~ /^([-_\|`a-zA-Z0-9]+) :is connecting from ([^ ]+)\s*([0-9a-fA-F:.]+)?/) {
+				my ($sender, $key, $val) = ($1, "ip", $3);
+				my $id = BotNow::SQLite::id("irc", "nick", $sender, $expires);
+				BotNow::SQLite::set("irc", "id", $id, $key, $val);
+				debug(ALL, "$key: $val");
+			} elsif ($code == 671 && $text =~ /^([-_\|`a-zA-Z0-9]+) :is using a secure connection/) {
+				my ($sender, $key, $val) = ($1, "ssl", "True");
+				my $id = BotNow::SQLite::id("irc", "nick", $sender, $expires);
+				BotNow::SQLite::set("irc", "id", $id, $key, $val);
+				debug(ALL, "$key: $val");
+			} elsif ($code =~ /^332$/) { # Topic
+		#		print "$text\r\n";
+			} elsif ($code =~ /^333$/) { #
+		#		print "$server $text\r\n";
+		#karatkievich.freenode.net 333 #ircnow jrmu!znc@206.253.167.44 1579277253
+			} elsif ($code =~ /^352$/) { # Hostmask
+#:datapacket.hk.quakenet.org 352 * znc guava.guava.ircnow.org *.quakenet.org guava H :0 guava
+		#		print "$server $code $text\r\n";
+			} elsif ($code =~ /^353$/) { # Names
+		#		print "$server $code $text\r\n";
+			} elsif ($code =~ /^366$/) { # End of names
+		#		print "$server $code $text\r\n";
+			} elsif ($code =~ /^37\d$/) { # MOTD
+		#		print "$server $code $text\r\n";
+			} elsif ($code =~ /^381$/) { # IRC Operator Verified
+		#		print "IRC Oper Verified\r\n";
+			} elsif ($code =~ /^401$/) { # IRC Operator Verified
+		#		print "IRC Oper Verified\r\n";
+			} elsif ($code =~ /^403$/) { # No such channel
+		#		debug(ERRORS, "$text");
+			} elsif ($code =~ /^422$/) { # MOTD missing
+		#		print "$server $code $text\r\n";
+			} elsif ($code =~ /^396$/) { # Display hostname
+		#		print "$server $code $text\r\n";
+#Unexpected bncnow.pl 454: irc.guava.ircnow.org 396 guava.guava.ircnow.org :is your displayed hostname now
+			} elsif ($code =~ /^464$/) { # Invalid password for oper
+				foreach my $chan (@$teamchans) {
+					$self->putserv($bot, "PRIVMSG $chan :$nick oper password failed; the bot will be unable to view uncloaked IP addresses");
+				}
+			} elsif ($code =~ /^477$/) { # Can't join channel
+				foreach my $chan (@$teamchans) {
+					$self->putserv($bot, "PRIVMSG $chan :ERROR: $nick on $server: $text");
+				}
+			} elsif ($code == 716 && $text =~ /^([-_\|`a-zA-Z0-9]+) :is in \+g mode \(server-side ignore.\)/) {
+				debug(ALL, "$text");
+			} else {
+				debug(ERRORS, "Unexpected bncnow.pl 454: $server $code $text");
+			}
+		} else {
+			chomp($response);
+			debug(ERRORS, "--> $response");
+		}
+}
+
+sub run {
+	my $self=shift;
+	my $bots=$self->{bots};
+	my $call=$self->{call};
+	my $sel = $self->{sockets};
+	while(my @ready = $sel->can_read) {
+		my ($bot, $response);
+		foreach my $socket (@ready) {
+			foreach my $b (@$bots) {
+				if($socket == $b->{sock}) {
+					$bot = $b;
+					last;
+				}
+			}
+			if (!defined($response = <$socket>)) {
+				debug(ERRORS, "ERROR ".$bot->{name}." has no response:");
+				next;
+			}
+			$self->parse_response($bot,$response);
+		}
+	}
+}
+
+
 1;