added more routing code
[spider.git] / perl / Thingy / Rt.pm
1 #
2 # Route Thingy handling
3 #
4 # $Id$
5 #
6 # Copyright (c) 2005 Dirk Koopman G1TLH
7 #
8
9 use strict;
10
11 package Thingy::Rt;
12
13 use vars qw($VERSION $BRANCH);
14
15 main::mkver($VERSION = q$Revision$);
16
17 use DXChannel;
18 use DXDebug;
19 use DXUtil;
20 use Thingy;
21 use Spot;
22
23 use vars qw(@ISA);
24 @ISA = qw(Thingy);
25
26 sub gen_Aranea
27 {
28         my $thing = shift;
29         unless ($thing->{Aranea}) {
30                 my @items;
31                 push @items, 's', $thing->{'s'} if $thing->{'s'};
32                 push @items, 'n', $thing->{n} if $thing->{n};
33                 push @items, 'v', $thing->{v} if $thing->{v};
34                 push @items, 'u', $thing->{u} if $thing->{u};
35                 $thing->{Aranea} = Aranea::genmsg($thing, 'RT', @items) if @items;
36         }
37         return $thing->{Aranea};
38 }
39
40 sub from_Aranea
41 {
42         my $thing = shift;
43         return unless $thing;
44         return $thing;
45 }
46
47 sub gen_DXProt
48 {
49         my $thing = shift;
50         my $dxchan = shift;
51         my $s = $thing->{'s'};
52         if ($s eq 'au') {
53                 my $n = $thing->{n} || $thing->{user};
54                 my @out;
55                 if ($n && (my $u = $thing->{u})) {
56                         my $s = '';
57                         for (split /:/, $u) {
58                                 my ($here, $call) = unpack "A1 A*", $_;
59                                 my $str = sprintf "^%s * %d", $call, $here;
60                                 if (length($s) + length($str) > $DXProt::sentencelth) {
61                                         push @out, "PC16^$n" . $s . sprintf "^%s^", DXProt::get_hops(16);
62                                         $s = '';
63                                 }
64                                 $s .= $str;
65                         }
66                         push @out, "PC16^$n" . $s . sprintf "^%s^", DXProt::get_hops(16);
67                         $thing->{DXProt} = @out > 1 ? \@out : $out[0];
68                 }
69         } elsif ($s eq 'du') {
70                 my $n = $thing->{n} || $thing->{user};
71                 my $hops = DXProt::get_hops(17);
72                 if ($n && (my $u = $thing->{u})) {
73                         $thing->{DXProt} = "PC17^$u^$n^$hops^"; 
74                 }
75         } elsif ($s eq 'an') {
76         } elsif ($s eq 'dn') {
77         }
78         return $thing->{DXProt};
79 }
80
81 #sub gen_DXCommandmode
82 #{
83 #       my $thing = shift;
84 #       my $dxchan = shift;
85 #       my $buf;
86 #
87 #       return $buf;
88 #}
89
90 sub from_DXProt
91 {
92         my $thing = shift;
93         while (@_) {
94                 my $k = shift;
95                 $thing->{$k} = shift;
96         }
97         ($thing->{hops}) = $thing->{DXProt} =~ /\^H(\d+)\^?~?$/ if exists $thing->{DXProt};
98         return $thing;
99 }
100
101 sub handle
102 {
103         my $thing = shift;
104         my $dxchan = shift;
105
106         if ($thing->{t}) {
107                 my $sub = "handle_$thing->{t}";
108                 if ($thing->can($sub)) {
109                         no strict 'refs';
110                         $thing = $thing->$sub($dxchan);
111                 }
112
113                 $thing->broadcast($dxchan) if $thing;
114         }
115 }
116
117 # these contain users and either a node (for externals) or the from address 
118 sub handle_au
119 {
120         my $thing = shift;
121         my $dxchan = shift;
122
123         my $node = $thing->{n} || $thing->{user};
124         my $nref = Route::Node::get($node);
125
126         if ($nref) {
127                 if (my $u = $thing->{u}) {
128                         for (split /:/, $u) {
129                                 my ($here, $call) = unpack "A1 A*", $_;
130                                 add_user($nref, $call, $here);
131                                 my $h = $dxchan->{call} eq $nref->{call} ? 3 : ($thing->{hops} || 99);
132                                 RouteDB::update($call, $dxchan->{call}, $h);
133                         }
134                 }
135         } else {
136                 dbg("Thingy::Rt::au: $node not found") if isdbg('chanerr');
137                 return;
138         }
139         return $thing;
140 }
141
142 sub handle_du
143 {
144         my $thing = shift;
145         my $dxchan = shift;
146
147         my $node = $thing->{n} || $thing->{user};
148         my $nref = Route::Node::get($node);
149
150         if ($nref) {
151                 if (my $u = $thing->{u}) {
152                         for (split /:/, $u) {
153                                 my ($here, $call) = unpack "A1 A*", $_;
154                                 my $uref = Route::User::get($call);
155                                 unless ($uref) {
156                                         dbg("Thingy::Rt::du $call not a user") if isdbg('chanerr');
157                                         next;
158                                 }
159                                 $nref->del_user($uref);
160                                 RouteDB::delete($call, $dxchan->{call});
161                         }
162                         RouteDB::update($nref->{call}, $dxchan->{call}, $dxchan->{call} eq $nref->{call} ? 2 : ($thing->{hops} || 99));
163                 }
164         } else {
165                 dbg("Thingy::Rt::du: $node not found") if isdbg('chanerr');
166                 return;
167         }
168
169         return $thing;
170 }
171
172 sub in_filter
173 {
174         my $thing = shift;
175         my $dxchan = shift;
176         
177         # global route filtering on INPUT
178         if ($dxchan->{inroutefilter}) {
179                 my $r = Route::Node::get($thing->{origin});
180                 my ($filter, $hops) = $dxchan->{inroutefilter}->it($dxchan->{call}, $dxchan->{dxcc}, $dxchan->{itu}, $dxchan->{cq}, $r->{call}, $r->{dxcc}, $r->{itu}, $r->{cq}, $dxchan->{state}, $r->{state});
181                 unless ($filter) {
182                         dbg("PCPROT: Rejected by input route filter") if isdbg('chanerr');
183                         return;
184                 }
185         }
186         return 1;
187 }
188
189 sub out_filter
190 {
191         my $thing = shift;
192         my $dxchan = shift;
193         
194         # global route filtering on OUTPUT
195         if ($dxchan->{routefilter}) {
196                 my $r = Route::Node::get($thing->{origin});
197                 my ($filter, $hops) = $dxchan->{routefilter}->it($dxchan->{call}, $dxchan->{dxcc}, $dxchan->{itu}, $dxchan->{cq}, $r->{call}, $r->{dxcc}, $r->{itu}, $r->{cq}, $dxchan->{state}, $r->{state});          
198                 unless ($filter) {
199                         dbg("PCPROT: Rejected by output route filter") if isdbg('chanerr');
200                         return;
201                 }
202                 $thing->{hops} = $hops if $hops;
203         } elsif ($dxchan->{isolate}) {
204                 return;
205         }
206         return 1;
207 }
208
209 sub add_user
210 {
211         my $node = shift;
212         my $user = shift;
213         my $flag = shift;
214         
215         $node->add_user($user, $flag);
216         my $ur = upd_user_rec($user, $node);
217         $ur->put;
218 }
219
220 sub upd_user_rec
221 {
222         my $call = shift;
223         my $parentcall = shift;
224         
225         # add this station to the user database, if required
226         $call =~ s/-\d+$//o;    # remove ssid for users
227         my $user = DXUser->get_current($call);
228         $user = DXUser->new($call) if !$user;
229         $user->homenode($parentcall) if !$user->homenode;
230         $user->node($parentcall);
231         $user->lastin($main::systime) unless DXChannel->get($call);
232         return $user;
233 }
234 1;