3 # A thing that implements dxcluster 'protocol'
5 # This is a perl module/program that sits on the end of a dxcluster
6 # 'protocol' connection and deals with anything that might come along.
8 # this program is called by ax25d or inetd and gets raw ax25 text on its input
9 # It can also be launched into the ether by the cluster program itself for outgoing
14 # client.pl [callsign] [telnet|ax25|local] [[connect] [program name and args ...]]
16 # if the callsign isn't given then the sysop callsign in DXVars.pm is assumed
18 # if there is no connection type then 'local' is assumed
20 # if there is a 'connect' keyword then it will try to launch the following program
21 # and any arguments and connect the stdin & stdout of both the program and the
24 # Copyright (c) 1998 Dirk Koopman G1TLH
30 # search local then perl directories
32 # root of directory tree for this system
34 $root = $ENV{'DXSPIDER_ROOT'} if $ENV{'DXSPIDER_ROOT'};
36 unshift @INC, "$root/perl"; # this IS the right way round!
37 unshift @INC, "$root/local";
44 $mode = 2; # 1 - \n = \r as EOL, 2 - \n = \n, 0 - transparent
45 $call = ""; # the callsign being used
46 @stdoutq = (); # the queue of stuff to send out to the user
47 $conn = 0; # the connection object for the cluster
48 $lastbit = ""; # the last bit of an incomplete input line
49 $mynl = "\n"; # standard terminator
50 $lasttime = time; # lasttime something happened on the interface
51 $outqueue = ""; # the output queue length
52 $buffered = 1; # buffer output
53 $savenl = ""; # an NL that has been saved from last time
55 # cease communications
59 if (defined $conn && $sendz) {
60 $conn->send_now("Z$call|bye...\n");
67 # terminate program from signal
76 $SIG{CHLD} = \&sig_chld;
91 # handle incoming messages
94 my ($con, $msg, $err) = @_;
95 if (defined $err && $err) {
99 my ($sort, $call, $line) = $msg =~ /^(\w)(\S+)\|(.*)$/;
104 $snl = "" if $mode == 0;
105 if ($mode && $line =~ />$/) {
109 $line =~ s/\n/\r/og if $mode == 1;
110 #my $p = qq($line$snl);
112 if (length $outqueue >= 128) {
116 $outqueue .= "$savenl$line$snl";
119 print $savenl, $line, $snl;;
121 $savenl = $newsavenl;
122 } elsif ($sort eq 'M') {
123 $mode = $line; # set new mode from cluster
125 } elsif ($sort eq 'B') {
126 if ($buffered && $outqueue) {
130 $buffered = $line; # set buffered or unbuffered
131 } elsif ($sort eq 'Z') { # end, disconnect, go, away .....
147 $r = sysread($fh, $buf, 1024);
148 # print "sys: $r $buf";
151 $buf =~ s/\r/\n/og if $mode == 1;
152 $dangle = !($buf =~ /\n$/);
156 @lines = split /\n/, $buf;
158 if ($dangle) { # pull off any dangly bits
163 $first = shift @lines;
164 unshift @lines, ($lastbit . $first) if ($first);
165 foreach $first (@lines) {
166 $conn->send_now("D$call|$first");
169 $savenl = ""; # reset savenl 'cos we will have done a newline on input
171 $conn->send_now("D$call|$buf");
179 $call = uc shift @ARGV;
180 $call = uc $myalias if !$call;
181 $connsort = lc shift @ARGV;
182 $connsort = 'local' if !$connsort;
183 $mode = ($connsort =~ /^ax/o) ? 1 : 2;
185 # is this an out going connection?
186 if ($ARGV[0] eq "connect") {
187 shift @ARGV; # lose the keyword
192 if ($call eq $mycall) {
193 print "You cannot connect as your cluster callsign ($mycall)", $nl;
197 #select STDOUT; $| = 1;
198 STDOUT->autoflush(1);
200 $SIG{'INT'} = \&sig_term;
201 $SIG{'TERM'} = \&sig_term;
202 $SIG{'HUP'} = \&sig_term;
203 $SIG{'CHLD'} = \&sig_chld;
205 $conn = Msg->connect("$clusteraddr", $clusterport, \&rec_socket);
207 if (-r "$data/offline") {
208 open IN, "$data/offline" or die;
210 s/\n/\r/og if $mode == 1;
215 print "Sorry, the cluster $mycall is currently off-line", $mynl;
220 $conn->send_now("A$call|$connsort");
221 Msg->set_event_handler(\*STDIN, "read" => \&rec_stdin);
225 Msg->event_loop(1, 0.010);
227 if ($t > $lasttime) {