Prepare for git repository
[spider.git] / perl / Route / Node.pm
1 #
2 # Node routing routines
3 #
4 # Copyright (c) 2001 Dirk Koopman G1TLH
5 #
6 # $Id$
7
8
9 package Route::Node;
10
11 use DXDebug;
12 use Route;
13 use Route::User;
14
15 use strict;
16
17 use vars qw(%list %valid @ISA $max $filterdef);
18 @ISA = qw(Route);
19
20 %valid = (
21                   parent => '0,Parent Calls,parray',
22                   nodes => '0,Nodes,parray',
23                   users => '0,Users,parray',
24                   usercount => '0,User Count',
25                   version => '0,Version',
26                   handle_xml => '0,Using XML,yesno',
27                   lastmsg => '0,Last Route Msg,atime',
28                   lastid => '0,Last Route MsgID',
29 );
30
31 $filterdef = $Route::filterdef;
32 %list = ();
33 $max = 0;
34
35 sub count
36 {
37         my $n = scalar (keys %list);
38         $max = $n if $n > $max;
39         return $n;
40 }
41
42 sub max
43 {
44         count();
45         return $max;
46 }
47
48 #
49 # this routine handles the possible adding of an entry in the routing
50 # table. It will only add an entry if it is new. It may have all sorts of
51 # other side effects which may include fixing up other links.
52 #
53 # It will return a node object if (and only if) it is a completely new
54 # object with that callsign. The upper layers are expected to do something
55 # sensible with this!
56 #
57 # called as $parent->add(call, dxchan, version, flags) 
58 #
59
60 sub add
61 {
62         my $parent = shift;
63         my $call = uc shift;
64         confess "Route::add trying to add $call to myself" if $call eq $parent->{call};
65         my $self = get($call);
66         if ($self) {
67                 $self->_addparent($parent);
68                 $parent->_addnode($self);
69                 return undef;
70         }
71         $self = $parent->new($call, @_);
72         $parent->_addnode($self);
73         return $self;
74 }
75
76 #
77 # this routine is the opposite of 'add' above.
78 #
79 # It will return an object if (and only if) this 'del' will remove
80 # this object completely
81 #
82
83 sub del
84 {
85         my $self = shift;
86         my $pref = shift;
87
88         # delete parent from this call's parent list
89         $pref->_delnode($self);
90     $self->_delparent($pref);
91         my @nodes;
92         my $ncall = $self->{call};
93         
94         # is this the last connection, I have no parents anymore?
95         unless (@{$self->{parent}}) {
96                 foreach my $rcall (@{$self->{nodes}}) {
97                         next if grep $rcall eq $_, @_;
98                         my $r = Route::Node::get($rcall);
99                         push @nodes, $r->del($self, $ncall, @_) if $r;
100                 }
101                 $self->_del_users;
102                 delete $list{$self->{call}};
103                 push @nodes, $self;
104         }
105         return @nodes;
106 }
107
108 # this deletes this node completely by grabbing the parents
109 # and deleting me from them
110 sub delete
111 {
112         my $self = shift;
113         my @out;
114         
115         $self->_del_users;
116         foreach my $call (@{$self->{parent}}) {
117                 my $parent = Route::Node::get($call);
118                 push @out, $parent->del($self) if $parent;
119         }
120         return @out;
121 }
122
123 sub del_nodes
124 {
125         my $parent = shift;
126         my @out;
127         foreach my $rcall (@{$parent->{nodes}}) {
128                 my $r = get($rcall);
129                 push @out, $r->del($parent, $parent->{call}, @_) if $r;
130         }
131         return @out;
132 }
133
134 sub _del_users
135 {
136         my $self = shift;
137         for (@{$self->{users}}) {
138                 my $ref = Route::User::get($_);
139                 $ref->del($self) if $ref;
140         }
141         $self->{users} = [];
142 }
143
144 # add a user to this node
145 sub add_user
146 {
147         my $self = shift;
148         my $ucall = shift;
149
150         confess "Trying to add NULL User call to routing tables" unless $ucall;
151
152         my $uref = Route::User::get($ucall);
153         my @out;
154         if ($uref) {
155                 @out = $uref->addparent($self);
156         } else {
157                 $uref = Route::User->new($ucall, $self->{call}, @_);
158                 @out = $uref;
159         }
160         $self->_adduser($uref);
161         $self->{usercount} = scalar @{$self->{users}};
162
163         return @out;
164 }
165
166 # delete a user from this node
167 sub del_user
168 {
169         my $self = shift;
170         my $ref = shift;
171         my @out;
172         
173         if ($ref) {
174                 @out = $self->_deluser($ref);
175                 $ref->del($self);
176         } else {
177                 confess "tried to delete non-existant $ref->{call} from $self->{call}";
178         }
179         $self->{usercount} = scalar @{$self->{users}};
180         return @out;
181 }
182
183 sub usercount
184 {
185         my $self = shift;
186         if (@_ && @{$self->{users}} == 0) {
187                 $self->{usercount} = shift;
188         }
189         return $self->{usercount};
190 }
191
192 sub users
193 {
194         my $self = shift;
195         return @{$self->{users}};
196 }
197
198 sub nodes
199 {
200         my $self = shift;
201         return @{$self->{nodes}};
202 }
203
204 sub parents
205 {
206         my $self = shift;
207         return @{$self->{parent}};
208 }
209
210 sub rnodes
211 {
212         my $self = shift;
213         my @out;
214         foreach my $call (@{$self->{nodes}}) {
215                 next if grep $call eq $_, @_;
216                 push @out, $call;
217                 my $r = get($call);
218                 push @out, $r->rnodes($call, @_) if $r;
219         }
220         return @out;
221 }
222
223
224 sub new
225 {
226         my $pkg = shift;
227         my $call = uc shift;
228         
229         confess "already have $call in $pkg" if $list{$call};
230         
231         my $self = $pkg->SUPER::new($call);
232         $self->{parent} = ref $pkg ? [ $pkg->{call} ] : [ ];
233         $self->{version} = shift;
234         $self->{flags} = shift;
235         $self->{users} = [];
236         $self->{nodes} = [];
237         
238         $list{$call} = $self;
239         
240         return $self;
241 }
242
243 sub get
244 {
245         my $call = shift;
246         $call = shift if ref $call;
247         my $ref = $list{uc $call};
248         dbg("Failed to get Node $call" ) if !$ref && isdbg('routerr');
249         return $ref;
250 }
251
252 sub get_all
253 {
254         return values %list;
255 }
256
257 sub _addparent
258 {
259         my $self = shift;
260     return $self->_addlist('parent', @_);
261 }
262
263 sub _delparent
264 {
265         my $self = shift;
266     return $self->_dellist('parent', @_);
267 }
268
269
270 sub _addnode
271 {
272         my $self = shift;
273     return $self->_addlist('nodes', @_);
274 }
275
276 sub _delnode
277 {
278         my $self = shift;
279     return $self->_dellist('nodes', @_);
280 }
281
282
283 sub _adduser
284 {
285         my $self = shift;
286     return $self->_addlist('users', @_);
287 }
288
289 sub _deluser
290 {
291         my $self = shift;
292     return $self->_dellist('users', @_);
293 }
294
295 sub DESTROY
296 {
297         my $self = shift;
298         my $pkg = ref $self;
299         my $call = $self->{call} || "Unknown";
300         
301         dbg("destroying $pkg with $call") if isdbg('routelow');
302 }
303
304 #
305 # generic AUTOLOAD for accessors
306 #
307
308 sub AUTOLOAD
309 {
310         no strict;
311         my $name = $AUTOLOAD;
312         return if $name =~ /::DESTROY$/;
313         $name =~ s/^.*:://o;
314   
315         confess "Non-existant field '$AUTOLOAD'" unless $valid{$name} || $Route::valid{$name};
316
317         # this clever line of code creates a subroutine which takes over from autoload
318         # from OO Perl - Conway
319         *$AUTOLOAD = sub {$_[0]->{$name} = $_[1] if @_ > 1; return $_[0]->{$name}};
320         goto &$AUTOLOAD;
321 }
322
323 1;
324