]> jfr.im git - irc/SurrealServices/srsv.git/blame - branches/erry-devel/SrSv/Agent.pm
My work on this so far....
[irc/SurrealServices/srsv.git] / branches / erry-devel / SrSv / Agent.pm
CommitLineData
5975999e 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
17package SrSv::Agent;
18
19use strict;
20
21use Exporter 'import';
22BEGIN { 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
29use 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
36use SrSv::Conf2Consts qw(main);
37
38use SrSv::Debug;
39use SrSv::Unreal::Tokens;
40use SrSv::Unreal::Base64 qw(itob64);
41use SrSv::IRCd::State qw(synced $ircd_ready %IRCd_capabilities);
42use SrSv::IRCd::IO qw(ircsend ircsendimm );
43use SrSv::IRCd::Event qw(addhandler);
44use SrSv::IRCd::Validate qw(valid_nick);
45use SrSv::RunLevel 'main_shutdown';
46use SrSv::IRCd::Send;
47# FIXME
48BEGIN { *SJB64 = \&ircd::SJB64 }
49
50our %agents;
51our @defer_join;
52
53addhandler('WHOIS', undef(), undef(), 'whois_callback', 1);
54addhandler('KILL', undef(), undef(), 'kill_callback', 1);
55
56sub is_agent($) {
57 my ($nick) = @_;
58 return (defined($agents{lc $nick}));
59}
60
61sub 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 print "$agent is in $chan\n";
67 return 1;
68 } else {
69 return 0;
70 }
71}
72
73sub agent_connect($$$$$) {
5975999e 74 my ($nick, $ident, $host, $modes, $gecos) = @_;
75 my $time = time();
76
77 my @chans;
78 if(defined($agents{lc $nick}) and ref($agents{lc $nick}{CHANS})) {
79 @chans = keys(%{$agents{lc $nick}{CHANS}});
80 }
81
82 $agents{lc $nick}{PARMS} = [ @_ ];
83 $host = main_conf_local unless $host;
84 ircd::agent_doconn ($nick, $ident, $host, $modes, $gecos);
85 #$host = main_conf_local unless $host;
86 #ircsend($tkn{NICK}[$tkn]." $nick 1 $time $ident $host ".
87 # (SJB64 ? itob64(main_conf_numeric) : main_conf_local).
88 # " 1 $modes * :$gecos");
89
90 #foreach my $chan (@chans) {
91 #ircsend(":$nick ".$tkn{JOIN}[$tkn]." $chan");
92 # If we tracked chanmodes for agents, that would go here as well.
93 #}
94}
95
96sub agent_quit($$) {
97 my ($nick, $msg) = @_;
98
99 delete($agents{lc $nick}{CHANS});
100 delete($agents{lc $nick});
101
102 ircsendimm(":$nick ".$tkn{QUIT}[$tkn]." :$msg");
103}
104
105sub agent_quit_all($) {
106 my ($msg) = @_;
107
108 my @agents;
109 @agents = keys(%agents);
110
111 foreach my $a (@agents) {
112 agent_quit($a, $msg);
113 }
114}
115
116sub is_invalid_agentname($$$) {
117 my ($botnick, $botident, $bothost) = @_;
118
119 unless(valid_nick($botnick)) {
120 return "Invalid nickname.";
121 }
122 unless($botident =~ /^[[:alnum:]_]+$/) {
123 return "Invalid ident.";
124 }
125 unless($bothost =~ /^[[:alnum:].-]+$/) {
126 return "Invalid vhost.";
127 }
128 unless($bothost =~ /\./) {
129 return "A vhost must contain at least one dot.";
130 }
131 return undef;
132}
133
134
135
136sub agent_part($$$) {
137 my ($agent, $chan, $reason) = @_;
138 delete($agents{lc $agent}{CHANS}{lc $chan});
139 ircd::agent_dopart ($agent, $chan, $reason);
140}
141
142sub set_agent_umode($$) {
143 my ($src, $modes) = @_;
144
145 ircsend(":$src $tkn{UMODE2}[$tkn] $modes");
146}
147sub agent_join($$) {
148 my ($agent, $chan) = @_;
149 ircd::agent_dojoin($agent,$chan);
150}
151sub agent_sync() {
152 foreach my $j (@defer_join) {
153 print "Processing join: $j\n" if DEBUG;
154 my ($agent, $chan) = split(/ /, $j);
155 if($agents{lc $agent}) {
156 $agents{lc $agent}{CHANS}{lc $chan} = 1;
2eef9154 157 agent_join($agents{lc $agent}, $chan);
5975999e 158 } else {
159 if($ircd_ready) {
160 print "Tried to make nonexistent agent ($agent) join channel ($chan)" if DEBUG;
161 } else {
162 print "Deferred join: $agent $chan\n" if DEBUG;
163 push @defer_join, "$agent $chan";
164 }
165 }
166 }
167 undef(@defer_join);
168}
169
170sub whois_callback {
171#:wyvern.surrealchat.net 311 blah2 tabris northman SCnet-E5870F84.dsl.klmzmi.ameritech.net * :Sponsored by Skuld
172#:wyvern.surrealchat.net 307 blah2 tabris :is a registered nick
173#:wyvern.surrealchat.net 312 blah2 tabris wyvern.surrealchat.net :SurrealChat - aphrodite.wcshells.com - Chicago.IL
174#:wyvern.surrealchat.net 671 blah2 tabris :is using a Secure Connection
175#:wyvern.surrealchat.net 317 blah2 tabris 54 1118217330 :seconds idle, signon time
176#:wyvern.surrealchat.net 401 blah2 nikanoru :No such nick/channel
177#:wyvern.surrealchat.net 311 blah2 somebot bot SCnet-DA158DBF.hsd1.nh.comcast.net * :Some sort of bot
178#:wyvern.surrealchat.net 312 blah2 somebot nascent.surrealchat.net :SurrealChat - Hub
179#:wyvern.surrealchat.net 335 blah2 somebot :is a Bot on SurrealChat.net
180#:wyvern.surrealchat.net 318 blah2 tabris,nikanoru,somebot :End of /WHOIS list.
181
182# Also reference http://www.alien.net.au/irc/irc2numerics.html
183
184 my ($src, $nicklist) = @_;
185
186 my @nicks = split(/\,/, $nicklist);
187 my @reply;
188 foreach my $nick (@nicks) {
189 if (is_agent($nick)) {
190 my ($nick, $ident, $host, $modes, $gecos) = @{$agents{lc $nick}{PARMS}};
191 $host = main_conf_local unless $host;
192 push @reply, ':'.main_conf_local." 311 $src $nick $ident $host * :$gecos";
193 push @reply, ':'.main_conf_local." 312 $src $nick ".main_conf_local.' :'.main_conf_info;
194 foreach my $mode (split(//, $modes)) {
195 if ($mode eq 'z') {
196 push @reply, ':'.main_conf_local." 671 $src $nick :is using a Secure Connection";
197 }
198 elsif($mode eq 'S') {
199 #313 tab ChanServ :is a Network Service
200 push @reply, ':'.main_conf_local." 313 $src $nick :is a Network Service";
201 }
202 elsif($mode eq 'B') {
203 #335 blah2 TriviaBot :is a Bot on SurrealChat.net
204 push @reply, ':'.main_conf_local.
205 " 335 $src $nick :is a \002Bot\002 on ".$IRCd_capabilities{NETWORK};
206 }
207 }
208 }
209 else {
210 push @reply, ':'.main_conf_local." 401 $src $nick :No such service";
211 }
212
213 }
214 push @reply, ':'.main_conf_local." 318 $src $nicklist :End of /WHOIS list.";
215 ircsend(@reply);
216}
217
218sub kill_callback($$$$) {
219 my ($src, $dst, $path, $reason) = @_;
220 if (defined($agents{lc $dst})) {
221 if (defined ($agents{lc $dst}{KILLED}) and ($agents{lc $dst}{KILLED} == time())) {
222 if ($agents{lc $dst}{KILLCOUNT} > 3) {
223 ircd::debug("Caught in a kill loop for $dst, dying now.");
224 main_shutdown;
225 } else {
226 $agents{lc $dst}{KILLCOUNT}++;
227 }
228 } else {
229 $agents{lc $dst}{KILLED} = time();
230 $agents{lc $dst}{KILLCOUNT} = 1;
231 }
232
233 if($src =~ /\./) {
234 # let's NOT loopback this event
235 ircsendimm(':'.main_conf_local.' '.$tkn{KILL}[$tkn]." $dst :Nick Collision");
236 } elsif (defined($agents{lc $src})) {
237 # Do Nothing.
238 } else {
239 ircd::irckill($main::rsnick, $src, "Do not kill services agents.");
240 }
241
242 &agent_connect(@{$agents{lc $dst}{PARMS}}) if synced();
243 }
244}
245
2461;