]>
Commit | Line | Data |
---|---|---|
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 | ||
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; | |
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 | ||
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 | print "$agent is in $chan\n"; | |
67 | return 1; | |
68 | } else { | |
69 | return 0; | |
70 | } | |
71 | } | |
72 | ||
73 | sub 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 | ||
96 | sub 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 | ||
105 | sub 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 | ||
116 | sub 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 | ||
136 | sub agent_part($$$) { | |
137 | my ($agent, $chan, $reason) = @_; | |
138 | delete($agents{lc $agent}{CHANS}{lc $chan}); | |
139 | ircd::agent_dopart ($agent, $chan, $reason); | |
140 | } | |
141 | ||
142 | sub set_agent_umode($$) { | |
143 | my ($src, $modes) = @_; | |
144 | ||
145 | ircsend(":$src $tkn{UMODE2}[$tkn] $modes"); | |
146 | } | |
147 | sub agent_join($$) { | |
148 | my ($agent, $chan) = @_; | |
149 | ircd::agent_dojoin($agent,$chan); | |
150 | } | |
151 | sub 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 | ||
170 | sub 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 | ||
218 | sub 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 | ||
246 | 1; |