+# New style routing handler
+sub handle_59
+{
+ my $self = shift;
+ my $pcno = shift;
+ my $line = shift;
+ my $origin = shift;
+
+ my ($sort, $hextime, $ncall) = @_[1,2,3];
+ if ($ncall eq $main::mycall) {
+ dbg("PCPROT: ignoring PC59 for me") if isdbg('chan');
+ return;
+ }
+
+ # do this once for filtering with a throwaway routing entry if a new node
+ my $fnode = Route::Node::get($ncall) || Route::new($ncall);
+ return unless $self->in_filter_route($fnode);
+
+ return if eph_dup($line);
+
+ # mark myself as NewRoute if I get a PC59
+ $self->{newroute} = 1 if $ncall eq $self->{call};
+
+ # now do it properly for actions
+ my $node = Route::Node::get($ncall) || Route::Node->new($ncall);
+ $node->newroute(1);
+
+ # find each of the entries (or create new ones)
+ my @refs;
+ for my $ent (@_[4..$#_]) {
+ next if $ent =~ /^H\d+$/;
+
+ my ($esort, $ehere, $ecall) = unpack "A A A*", $ent;
+ my $ref;
+
+ next unless $esort && defined $ehere && $ecall;
+
+ # create user, if required
+ my $user = DXUser->get_current($ecall);
+ unless ($user) {
+ $user = DXUser->new($ecall);
+ $user->sort();
+ $user->priv(1); # I have relented and defaulted nodes
+ $user->lockout(1);
+ $user->homenode($ncall);
+ $user->node($ncall);
+ }
+ if ($esort eq 'U') {
+ $ref = Route::User::get($ecall);
+ unless ($ref) {
+ # create user, if required
+ my $user = DXUser->get_current($ecall);
+ unless ($user) {
+ $user = DXUser->new($ecall);
+ $user->sort('U');
+ $user->homenode($ncall);
+ $user->node($ncall);
+ $user->put;
+ }
+ $ref = Route::User->new($ecall, 0);
+ }
+ } elsif ($esort eq 'N') {
+ $ref = Route::Node::get($ecall);
+ unless ($ref) {
+ # create user, if required
+ my $user = DXUser->get_current($ecall);
+ unless ($user) {
+ $user = DXUser->new($ecall);
+ $user->priv(1); # I have relented and defaulted nodes
+ $user->lockout(1);
+ $user->sort('A');
+ $user->homenode($ncall);
+ $user->node($ncall);
+ $user->put;
+ }
+ $ref = Route::Node->new($ecall, 0);
+ }
+ } else {
+ dbg("DXPROT: unknown entity type '$esort' on $ecall for node $ncall") if isdbg('chan');
+ next;
+ }
+ $ref->here($ehere); # might as well set this here
+ $ref->lastseen($main::systime);
+ push @refs, $ref;
+ }
+
+ # if it is a delete, disconnect all the entries mentioned
+ # from this node (which is a parent in this context).
+ my @delnode;
+ my @deluser;
+ if ($sort eq 'D') {
+ for my $ref (@refs) {
+ next if $ref->call eq $ncall;
+ next if $ref->call eq $main::mycall;
+ if ($ref->isa('Route::Node')) {
+ push @delnode, $node->unlink_node($ref, $self);
+ } elsif ($ref->isa('Route::User')) {
+ push @deluser, $node->del_user($ref);
+ }
+ }
+ }
+
+ # if it is an add, connect all the entries
+ my @addnode;
+ my @adduser;
+ if ($sort eq 'A') {
+ for my $ref (@refs) {
+ next if $ref->call eq $ncall;
+ next if $ref->call eq $main::mycall;
+ if ($ref->isa('Route::Node')) {
+ my $new = $node->link_node($ref, $self);
+ push @addnode, $new if $new;
+ } elsif ($ref->isa('Route::User')) {
+ push @adduser, $node->del_user($ref);
+ }
+ }
+ }
+
+ # if it is a configure, unlink all the nodes and users that
+ # are not in @refs but are in the node, then add all the
+ # nodes and users that are @refs but not in the node.
+ #
+ if ($sort eq 'C') {
+ my @dn;
+ my @du;
+ my @an;
+ my @au;
+ for my $r (map {Route::Node::get($_)} $node->nodes) {
+ next unless $r;
+ next if $r->call eq $ncall;
+ next if $r->call eq $main::mycall;
+ push @dn, $r unless grep $_->call eq $r->call, @refs;
+ }
+ for my $r (map {Route::User::get($_)} $node->users) {
+ next unless $r;
+ push @du, $r unless grep $_->call eq $r->call, @refs;
+ }
+ for my $r (@refs) {
+ next unless $r;
+ next if $r->call eq $ncall;
+ next if $r->call eq $main::mycall;
+ if ($r->isa('Route::Node')) {
+ push @an, $r unless grep $r->call eq $_, $node->nodes;
+ } elsif ($r->isa('Route::User')) {
+ push @au, $r unless grep $r->call eq $_, $node->users;
+ }
+ }
+ push @delnode, $node->unlink_node($_, $self) for @dn;
+ push @deluser, $node->del_user($_) for @du;
+ push @addnode, $node->link_node($_, $self) for @an;
+ push @adduser, $node->add_user($_) for @au;
+ }
+
+ $self->route_pc21($origin, $line, @delnode) if @delnode;
+ $self->route_pc19($origin, $line, @addnode) if @addnode;
+ $self->route_pc17($origin, $line, @deluser) if @deluser;
+ $self->route_pc16($origin, $line, @adduser) if @adduser;
+
+ $self->route_pc59($sort, $hextime, $ncall, @refs) if @refs;
+ $_->delete for @delnode, @deluser;
+}
+
+