]> jfr.im git - irc/SurrealServices/srsv.git/blob - branches/0.5.0/SrSv/Agent.pm
Remove some debug lines
[irc/SurrealServices/srsv.git] / branches / 0.5.0 / SrSv / Agent.pm
1 # This file is part of SurrealServices.
2 #
3 # SurrealServices is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
7 #
8 # SurrealServices is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with SurrealServices; if not, write to the Free Software
15 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
17 package SrSv::Agent;
18
19 use strict;
20
21 use Exporter 'import';
22 BEGIN { our @EXPORT = qw(
23 is_agent is_agent_in_chan
24 agent_connect agent_quit agent_quit_all
25 agent_join agent_part set_agent_umode
26 agent_sync is_invalid_agentname
27 ); }
28
29 use SrSv::Process::InParent qw(
30 is_agent is_agent_in_chan
31 agent_connect agent_quit agent_quit_all
32 agent_join agent_part agent_sync
33 whois_callback kill_callback
34 );
35
36 use SrSv::Conf2Consts qw(main);
37
38 use SrSv::Debug;
39 use SrSv::Unreal::Tokens qw( :tokens );
40 use SrSv::Unreal::Base64 qw(itob64);
41 use SrSv::IRCd::State qw(synced $ircd_ready %IRCd_capabilities);
42 use SrSv::IRCd::IO qw(ircsend ircsendimm );
43 use SrSv::IRCd::Event qw(addhandler);
44 use SrSv::IRCd::Validate qw(valid_nick);
45 use SrSv::RunLevel 'main_shutdown';
46 use SrSv::IRCd::Send;
47 # FIXME
48 BEGIN { *SJB64 = \&ircd::SJB64 }
49 use Data::Dumper;
50 our %agents;
51 our @defer_join;
52
53 addhandler('WHOIS', undef(), undef(), 'whois_callback', 1);
54 addhandler('KILL', undef(), undef(), 'kill_callback', 1);
55
56 sub is_agent($) {
57 my ($nick) = @_;
58 return (defined($agents{lc $nick}));
59 }
60
61 sub is_agent_in_chan($$) {
62 my ($agent, $chan) = @_;
63 $agent = lc $agent; $chan = lc $chan;
64
65 if($agents{$agent} and $agents{$agent}{CHANS} and $agents{$agent}{CHANS}{$chan}) {
66 return 1;
67 } else {
68 return 0;
69 }
70 }
71 sub agent_connect($$$$$) {
72 my ($nick, $ident, $host, $modes, $gecos) = @_;
73 my $time = time();
74
75 my @chans;
76 if(defined($agents{lc $nick}) and ref($agents{lc $nick}{CHANS})) {
77 @chans = keys(%{$agents{lc $nick}{CHANS}});
78 }
79
80 $agents{lc $nick}{PARMS} = [ @_ ];
81
82 $host = main_conf_local unless $host;
83 #ircsend("@{[TOK_NICK]} $nick 1 $time $ident $host ".
84 #(SJB64 ? itob64(main_conf_numeric) : main_conf_local).
85 #" 1 $modes * :$gecos");
86 ircd::agent_doconn ($nick, $ident, $host, $modes, $gecos);
87 foreach my $chan (@chans) {
88 ircsend(":$nick @{[TOK_JOIN]} $chan");
89 # If we tracked chanmodes for agents, that would go here as well.
90 }
91 }
92
93 sub agent_quit($$) {
94 my ($nick, $msg) = @_;
95
96 delete($agents{lc $nick}{CHANS});
97 delete($agents{lc $nick});
98
99 ircsendimm(":$nick @{[TOK_QUIT]} :$msg");
100 }
101
102 sub agent_quit_all($) {
103 my ($msg) = @_;
104
105 my @agents;
106 @agents = keys(%agents);
107
108 foreach my $a (@agents) {
109 agent_quit($a, $msg);
110 }
111 }
112
113 sub is_invalid_agentname($$$) {
114 my ($botnick, $botident, $bothost) = @_;
115
116 unless(valid_nick($botnick)) {
117 return "Invalid nickname.";
118 }
119 unless($botident =~ /^[[:alnum:]_]+$/) {
120 return "Invalid ident.";
121 }
122 unless($bothost =~ /^[[:alnum:].-]+$/) {
123 return "Invalid vhost.";
124 }
125 unless($bothost =~ /\./) {
126 return "A vhost must contain at least one dot.";
127 }
128 return undef;
129 }
130
131
132 sub agent_part($$$) {
133 my ($agent, $chan, $reason) = @_;
134 delete($agents{lc $agent}{CHANS}{lc $chan});
135 ircd::agent_dopart ($agent, $chan, $reason);
136 }
137
138 sub set_agent_umode($$) {
139 my ($src, $modes) = @_;
140
141 ircsend(":$src @{[TOK_UMODE2]} $modes");
142 }
143 sub agent_join($$) {
144 my ($agent, $chan) = @_;
145 my $anick;
146 if (ref ($agent) eq "HASH") {
147 $anick = $agent->{NICK};
148 }
149 else { $anick = $agent; }
150 if($agents{lc $anick}) {
151 $agents{lc $anick}{CHANS}{lc $chan} = 1;
152 ircd::agent_dojoin($agent,$chan);
153 }
154 }
155 sub agent_sync() {
156 foreach my $j (@defer_join) {
157 my ($agent, $chan) = split(/ /, $j);
158 if($agents{lc $agent}) {
159 $agents{lc $agent}{CHANS}{lc $chan} = 1;
160 agent_join($agents{lc $agent}, $chan);
161 } else {
162 if($ircd_ready) {
163 print "Tried to make nonexistent agent ($agent) join channel ($chan)" if DEBUG;
164 } else {
165 print "Deferred join: $agent $chan\n" if DEBUG;
166 push @defer_join, "$agent $chan";
167 }
168 }
169 }
170 undef(@defer_join);
171 }
172
173 sub whois_callback {
174 #:wyvern.surrealchat.net 311 blah2 tabris northman SCnet-E5870F84.dsl.klmzmi.ameritech.net * :Sponsored by Skuld
175 #:wyvern.surrealchat.net 307 blah2 tabris :is a registered nick
176 #:wyvern.surrealchat.net 312 blah2 tabris wyvern.surrealchat.net :SurrealChat - aphrodite.wcshells.com - Chicago.IL
177 #:wyvern.surrealchat.net 671 blah2 tabris :is using a Secure Connection
178 #:wyvern.surrealchat.net 317 blah2 tabris 54 1118217330 :seconds idle, signon time
179 #:wyvern.surrealchat.net 401 blah2 nikanoru :No such nick/channel
180 #:wyvern.surrealchat.net 311 blah2 somebot bot SCnet-DA158DBF.hsd1.nh.comcast.net * :Some sort of bot
181 #:wyvern.surrealchat.net 312 blah2 somebot nascent.surrealchat.net :SurrealChat - Hub
182 #:wyvern.surrealchat.net 335 blah2 somebot :is a Bot on SurrealChat.net
183 #:wyvern.surrealchat.net 318 blah2 tabris,nikanoru,somebot :End of /WHOIS list.
184
185 # Also reference http://www.alien.net.au/irc/irc2numerics.html
186
187 my ($src, $nicklist) = @_;
188
189 my @nicks = split(/\,/, $nicklist);
190 my @reply;
191 foreach my $nick (@nicks) {
192 if (is_agent($nick)) {
193 my ($nick, $ident, $host, $modes, $gecos) = @{$agents{lc $nick}{PARMS}};
194 $host = main_conf_local unless $host;
195 push @reply, ':'.main_conf_local." 311 $src $nick $ident $host * :$gecos";
196 push @reply, ':'.main_conf_local." 312 $src $nick ".main_conf_local.' :'.main_conf_info;
197 foreach my $mode (split(//, $modes)) {
198 if ($mode eq 'z') {
199 push @reply, ':'.main_conf_local." 671 $src $nick :is using a Secure Connection";
200 }
201 elsif($mode eq 'S') {
202 #313 tab ChanServ :is a Network Service
203 push @reply, ':'.main_conf_local." 313 $src $nick :is a Network Service";
204 }
205 elsif($mode eq 'B') {
206 #335 blah2 TriviaBot :is a Bot on SurrealChat.net
207 push @reply, ':'.main_conf_local.
208 " 335 $src $nick :is a \002Bot\002 on ".$IRCd_capabilities{NETWORK};
209 }
210 }
211 }
212 else {
213 push @reply, ':'.main_conf_local." 401 $src $nick :No such service";
214 }
215
216 }
217 push @reply, ':'.main_conf_local." 318 $src $nicklist :End of /WHOIS list.";
218 ircsend(@reply);
219 }
220
221 sub kill_callback($$$$) {
222 my ($srcUser, $dstUser, $path, $reason) = @_;
223 my $src = $srcUser->{NICK};
224 my $dst = $dstUser->{NICK};
225 if (defined($agents{lc $dst})) {
226 if (defined ($agents{lc $dst}{KILLED}) and ($agents{lc $dst}{KILLED} == time())) {
227 if ($agents{lc $dst}{KILLCOUNT} > 3) {
228 ircd::debug("Caught in a kill loop for $dst, dying now.");
229 main_shutdown;
230 } else {
231 $agents{lc $dst}{KILLCOUNT}++;
232 }
233 } else {
234 $agents{lc $dst}{KILLED} = time();
235 $agents{lc $dst}{KILLCOUNT} = 1;
236 }
237
238 if($src =~ /\./) {
239 # let's NOT loopback this event
240 ircsendimm(':'.main_conf_local.' '."@{[TOK_KILL]} $dst :Nick Collision");
241 } elsif (defined($agents{lc $src})) {
242 # Do Nothing.
243 } else {
244 my $rsUser = {NICK=>$main::rsnick,ID=>"123AAAAAA"}; #FIXME - erry
245 ircd::irckill($rsUser, $srcUser, "Do not kill services agents.");
246 #ftr they can't if the bots have +k in insp.
247 }
248
249 &agent_connect(@{$agents{lc $dst}{PARMS}}) if synced();
250 }
251 }
252
253 1;