+ dbg("PCPROT: pc92 call entry '$_' not decoded, ignored") if isdbg('chanerr');
+ }
+ }
+
+ my ($dnodes, $dusers, $nnodes, $nusers) = $parent->calc_config_changes(\@nodes, \@users);
+
+ # add users here
+ foreach my $r (@nent) {
+ my $call = $r->[0];
+ if ($call) {
+ push @radd,_add_thingy($parent, $r, $self, $hops) if grep $call eq $_, (@$nnodes, @$nusers);
+ }
+ }
+ # del users here
+ foreach my $r (@$dnodes) {
+ push @rdel,_del_thingy($parent, [$r, 1]);
+ }
+ foreach my $r (@$dusers) {
+ push @rdel,_del_thingy($parent, [$r, 0]);
+ }
+
+ # remember this last PC92C for rebroadcast on demand
+ $parent->last_PC92C($line);
+ } else {
+ dbg("PCPROT: unknown action '$sort', ignored") if isdbg('chanerr');
+ return;
+ }
+
+ foreach my $r (@rdel) {
+ next unless $r;
+
+ $self->route_pc21($pcall, undef, $r) if $r->isa('Route::Node');
+ $self->route_pc17($pcall, undef, $parent, $r) if $r->isa('Route::User');
+ }
+ my @pc19 = grep { $_ && $_->isa('Route::Node') } @radd;
+ my @pc16 = grep { $_ && $_->isa('Route::User') } @radd;
+ unshift @pc19, $parent if $self->{state} eq 'init92' && $oparent == $parent;
+ $self->route_pc19($pcall, undef, @pc19) if @pc19;
+ $self->route_pc16($pcall, undef, $parent, @pc16) if @pc16;
+ }
+
+ # broadcast it if we get here
+ $self->broadcast_route_pc9x($pcall, undef, $line, 0);
+}
+
+
+sub handle_93
+{
+ my $self = shift;
+ my $pcno = shift;
+ my $line = shift;
+ my $origin = shift;
+
+# $self->{do_pc9x} ||= 1;
+
+ my $pcall = $_[1]; # this is now checked earlier
+
+ # remember that we are converting PC10->PC93 and self will be $main::me if it
+ # comes from us
+ unless ($self->{do_pc9x}) {
+ dbg("PCPROT: PC9x come in from non-PC9x node, ignored") if isdbg('chanerr');
+ return;
+ }
+
+ my $t = $_[2];
+ my $parent = check_pc9x_t($pcall, $t, 93, 1) || return;
+
+ my $to = uc $_[3];
+ my $from = uc $_[4];
+ my $via = uc $_[5];
+ my $text = $_[6];
+ my $onode = uc $_[7];
+ $onode = $pcall if @_ <= 8;
+
+ # this is catch loops caused by bad software ...
+ if (eph_dup("PC93|$from|$text|$onode", $pc10_dupe_age)) {
+ return;
+ }
+
+ # will we allow it at all?
+ if ($censorpc) {
+ my @bad;
+ if (@bad = BadWords::check($text)) {
+ dbg("PCPROT: Bad words: @bad, dropped") if isdbg('chanerr');
+ return;
+ }
+ }
+
+ # if this is a 'bad spotter' user then ignore it
+ my $nossid = $from;
+ $nossid =~ s/-\d+$//;
+ if ($badspotter->in($nossid)) {
+ dbg("PCPROT: Bad Spotter, dropped") if isdbg('chanerr');
+ return;
+ }
+
+ # ignore PC93 coming in from outside this node with a target of local
+ if ($to eq 'LOCAL' && $self != $main::me) {
+ dbg("PCPROT: incoming LOCAL chat not from local node, ignored") if isdbg('chanerr');
+ return;
+ }
+
+ # if it is routeable then then treat it like a talk
+ my $ref = Route::get($to);
+ if ($ref) {
+ # local talks
+ my $dxchan;
+ $dxchan = DXChannel::get($main::myalias) if $to eq $main::mycall;
+ $dxchan = DXChannel::get($to) unless $dxchan;
+ # check it...
+ if ($dxchan) {
+ if (ref $dxchan && $dxchan->isa('DXChannel')) {
+ if ($dxchan->is_user) {
+ $dxchan->talk($from, $to, $via, $text, $onode);
+ return;