b9cf952cb497a553d4fed6aa0069f09d7d20e2f5
[spider.git] / perl / QXProt.pm
1 #
2 # This module impliments the new protocal mode for a dx cluster
3 #
4 # Copyright (c) 2001 Dirk Koopman G1TLH
5 #
6 # $Id$
7
8
9 package QXProt;
10
11 @ISA = qw(DXChannel DXProt);
12
13 use DXUtil;
14 use DXChannel;
15 use DXUser;
16 use DXM;
17 use DXLog;
18 use Spot;
19 use DXDebug;
20 use Filter;
21 use DXDb;
22 use AnnTalk;
23 use Geomag;
24 use WCY;
25 use Time::HiRes qw(gettimeofday tv_interval);
26 use BadWords;
27 use DXHash;
28 use Route;
29 use Route::Node;
30 use Script;
31 use DXProt;
32 use Verify;
33
34 use strict;
35
36 use vars qw($VERSION $BRANCH);
37 $VERSION = sprintf( "%d.%03d", q$Revision$ =~ /(\d+)\.(\d+)/ );
38 $BRANCH = sprintf( "%d.%03d", q$Revision$ =~ /\d+\.\d+\.(\d+)\.(\d+)/  || (0,0));
39 $main::build += $VERSION;
40 $main::branch += $BRANCH;
41
42 sub init
43 {
44         my $user = DXUser->get($main::mycall);
45         $DXProt::myprot_version += $main::version*100;
46         $main::me = QXProt->new($main::mycall, 0, $user); 
47         $main::me->{here} = 1;
48         $main::me->{state} = "indifferent";
49         $main::me->{sort} = 'S';    # S for spider
50         $main::me->{priv} = 9;
51         $main::me->{metric} = 0;
52         $main::me->{pingave} = 0;
53         $main::me->{registered} = 1;
54         $main::me->{version} = $main::version;
55         $main::me->{build} = $main::build;
56                 
57 #       $Route::Node::me->adddxchan($main::me);
58 }
59
60 sub start
61 {
62         my $self = shift;
63         $self->SUPER::start(@_);
64 }
65
66 sub sendinit
67 {
68         my $self = shift;
69         
70         $self->send($self->genI);
71 }
72
73 sub normal
74 {
75         if ($_[1] =~ /^PC\d\d\^/) {
76                 DXProt::normal(@_);
77                 return;
78         }
79         my ($sort, $tonode, $fromnode, $msgid, $incs);
80         return unless ($sort, $tonode, $fromnode, $msgid, $incs) = $_[1] =~ /^QX([A-Z])\^(\*|[-A-Z0-9]+)\^([-A-Z0-9]+)\^([0-9A-F]{1,4})\^.*\^([0-9A-F]{2})$/;
81
82         $msgid = hex $msgid;
83         my $noderef = Route::Node::get($fromnode);
84         $noderef = Route::Node::new($fromnode) unless $noderef;
85
86         my $il = length $incs; 
87         my $cs = sprintf("%02X", unpack("%32C*", substr($_[1], 0, length($_[1]) - ($il+1))) & 255);
88         if ($incs ne $cs) {
89                 dbg("QXPROT: Checksum fail in: $incs ne calc: $cs" ) if isdbg('chanerr');
90                 return;
91         }
92
93         return unless $noderef->newid($msgid);
94
95         $_[0]->handle($sort, $tonode, $fromnode, $msgid, $_[1]);
96         return;
97 }
98
99 sub handle
100 {
101         no strict 'subs';
102         my $self = shift;
103         my $sort = shift;
104         my $sub = "handle$sort";
105         $self->$sub(@_) if $self->can($sub);
106         return;
107 }
108
109 sub gen
110 {
111         no strict 'subs';
112         my $self = shift;
113         my $sort = shift;
114         my $sub = "gen$sort";
115         $self->$sub(@_) if $self->can($sub);
116         return;
117 }
118
119 my $last_node_update = 0;
120 my $node_update_interval = 60*15;
121
122 sub process
123 {
124         if ($main::systime >= $last_node_update+$node_update_interval) {
125 #               sendallnodes();
126 #               sendallusers();
127                 $last_node_update = $main::systime;
128         }
129 }
130
131 sub disconnect
132 {
133         my $self = shift;
134         $self->DXProt::disconnect(@_);
135 }
136
137 my $msgid = 1;
138
139 sub frame
140 {
141         my $sort = shift;
142         my $to = shift || "*";
143         my $ht;
144         
145         $ht = sprintf "%X", $msgid;
146         my $line = join '^', "QX$sort", $to, $main::mycall, $ht, @_;
147         my $cs = sprintf "%02X", unpack("%32C*", $line) & 255;
148         $msgid = 1 if ++$msgid > 0xffff;
149         return "$line^$cs";
150 }
151
152 sub handleI
153 {
154         my $self = shift;
155         
156         my @f = split /\^/, $_[3];
157         if ($self->passphrase && $f[7] && $f[8]) {
158                 my $inv = Verify->new($f[7]);
159                 unless ($inv->verify($f[8], $main::me->user->passphrase, $main::mycall, $self->call)) {
160                         $self->sendnow('D','Sorry...');
161                         $self->disconnect;
162                 }
163                 $self->{verified} = 1;
164         } else {
165                 $self->{verified} = 0;
166         }
167         if ($self->{outbound}) {
168                 $self->send($self->genI);
169         } 
170         if ($self->{sort} ne 'S' && $f[4] eq 'DXSpider') {
171                 $self->{user}->{sort} = $self->{sort} = 'S';
172                 $self->{user}->{priv} = $self->{priv} = 1 unless $self->{priv};
173         }
174         $self->{version} = $f[5];
175         $self->{build} = $f[6];
176         $self->state('init1');
177         $self->{lastping} = 0;
178 }
179
180 sub genI
181 {
182         my $self = shift;
183         my @out = ('I', $self->call, "DXSpider", ($main::version + 53) * 100, $main::build);
184         if (my $pass = $self->user->passphrase) {
185                 my $inp = Verify->new;
186                 push @out, $inp->challenge, $inp->response($pass, $self->call, $main::mycall);
187         }
188         return frame(@out);
189 }
190
191 sub handleR
192 {
193
194 }
195
196 sub genR
197 {
198
199 }
200
201 sub handleP
202 {
203
204 }
205
206 sub genP
207 {
208
209 }
210
211 sub gen2
212 {
213         my $self = shift;
214         
215         my $node = shift;
216         my $sort = shift;
217         my @out;
218         my $dxchan;
219         
220         while (@_) {
221                 my $str = '';
222                 for (; @_ && length $str <= 230;) {
223                         my $ref = shift;
224                         my $call = $ref->call;
225                         my $flag = 0;
226                         
227                         $flag += 1 if $ref->here;
228                         $flag += 2 if $ref->conf;
229                         if ($ref->is_node) {
230                                 my $ping = int($ref->pingave * 10);
231                                 $str .= "^N$flag$call,$ping";
232                                 my $v = $ref->build || $ref->version;
233                                 $str .= ",$v" if defined $v;
234                         } else {
235                                 $str .= "^U$flag$call";
236                         }
237                 }
238                 push @out, $str if $str;
239         }
240         my $n = @out;
241         my $h = get_hops(90);
242         @out = map { sprintf "PC90^%s^%X^%s%d%s^%s^", $node->call, $main::systime, $sort, --$n, $_, $h } @out;
243         return @out;
244 }
245
246 1;