093bfb003ca2ae6e9b824f0e097d8e8f4eb48d6a
[spider.git] / perl / DXChannel.pm
1 #
2 # module to manage channel lists & data
3 #
4 # This is the base class for all channel operations, which is everything to do 
5 # with input and output really.
6 #
7 # The instance variable in the outside world will be generally be called $dxchann
8 #
9 # This class is 'inherited' (if that is the goobledegook for what I am doing)
10 # by various other modules. The point to understand is that the 'instance variable'
11 # is in fact what normal people would call the state vector and all useful info
12 # about a connection goes in there.
13 #
14 # Another point to note is that a vector may contain a list of other vectors. 
15 # I have simply added another variable to the vector for 'simplicity' (or laziness
16 # as it is more commonly called)
17 #
18 # PLEASE NOTE - I am a C programmer using this as a method of learning perl
19 # firstly and OO about ninthly (if you don't like the design and you can't 
20 # improve it with better OO by make it smaller and more efficient, then tough). 
21 #
22 # Copyright (c) 1998 - Dirk Koopman G1TLH
23 #
24 # $Id$
25 #
26 package DXChannel;
27
28 use Msg;
29 use DXUtil;
30 use DXM;
31
32 %channels = undef;
33
34 %valid = (
35   call => 'Callsign',
36   conn => 'Msg Connection ref',
37   user => 'DXUser ref',
38   t => 'Time',
39   priv => 'Privilege',
40   state => 'Current State',
41   oldstate => 'Last State',
42   list => 'Dependant DXChannels list',
43   name => 'User Name',
44 );
45
46
47 # create a new connection object [$obj = DXChannel->new($call, $msg_conn_obj, $user_obj)]
48 sub new
49 {
50   my ($pkg, $call, $conn, $user) = @_;
51   my $self = {};
52   
53   die "trying to create a duplicate channel for $call" if $channels{$call};
54   $self->{call} = $call;
55   $self->{conn} = $conn if defined $conn;   # if this isn't defined then it must be a list
56   $self->{user} = $user if defined $user; 
57   $self->{t} = time;
58   $self->{state} = 0;
59   $self->{oldstate} = 0;
60   bless $self, $pkg; 
61   return $channels{$call} = $self;
62 }
63
64 # obtain a connection object by callsign [$obj = DXChannel->get($call)]
65 sub get
66 {
67   my ($pkg, $call) = @_;
68   return $connect{$call};
69 }
70
71 # obtain all the connection objects
72 sub get_all
73 {
74   my ($pkg) = @_;
75   return values(%channels);
76 }
77
78 # obtain a connection object by searching for its connection reference
79 sub get_by_cnum
80 {
81   my ($pkg, $conn) = @_;
82   my $self;
83   
84   foreach $self (values(%channels)) {
85     return $self if ($self->{conn} == $conn);
86   }
87   return undef;
88 }
89
90 # get rid of a connection object [$obj->del()]
91 sub del
92 {
93   my $self = shift;
94   delete $channels{$self->{call}};
95 }
96
97
98 # handle out going messages, immediately without waiting for the select to drop
99 # this could, in theory, block
100 sub send_now
101 {
102   my $self = shift;
103   my $conn = $self->{conn};
104
105   # is this a list of channels ?
106   if (!defined $conn) {
107     die "tried to send_now to an invalid channel list" if !defined $self->{list};
108         my $lself;
109         foreach $lself (@$self->{list}) {
110           $lself->send_now(@_);             # it's recursive :-)
111         }
112   } else {
113     my $sort = shift;
114     my $call = $self->{call};
115     my $line;
116         
117     foreach $line (@_) {
118       my $t = atime;
119           chomp $line;
120       print main::DEBUG "$t -> $sort $call $line\n" if defined DEBUG;
121           print "-> $sort $call $line\n";
122       $conn->send_now("$sort$call|$line");
123         }
124   }
125 }
126
127 #
128 # the normal output routine
129 #
130 sub send              # this is always later and always data
131 {
132   my $self = shift;
133   my $conn = $self->{conn};
134  
135   # is this a list of channels ?
136   if (!defined $conn) {
137     die "tried to send to an invalid channel list" if !defined $self->{list};
138         my $lself;
139         foreach $lself (@$self->{list}) {
140           $lself->send(@_);                 # here as well :-) :-)
141         }
142   } else {
143     my $call = $self->{call};
144     my $line;
145
146     foreach $line (@_) {
147       my $t = atime;
148           chomp $line;
149           print main::DEBUG "$t -> D $call $line\n" if defined DEBUG;
150           print "-> D $call $line\n";
151           $conn->send_later("D$call|$line");
152         }
153   }
154 }
155
156 # send a file (always later)
157 sub send_file
158 {
159   my ($self, $fn) = @_;
160   my $call = $self->{call};
161   my $conn = $self->{conn};
162   my @buf;
163   
164   open(F, $fn) or die "can't open $fn for sending file ($!)";
165   @buf = <F>;
166   close(F);
167   $self->send(@buf);
168 }
169
170 # just a shortcut for $dxchan->send(msg(...));
171 sub msg
172 {
173   my $self = shift;
174   $self->send(DXM::msg(@_));
175 }
176
177 # change the state of the channel - lots of scope for debugging here :-)
178 sub state
179 {
180   my $self = shift;
181   $self->{oldstate} = $self->{state};
182   $self->{state} = shift;
183   print "Db   $self->{call} channel state $self->{oldstate} -> $self->{state}\n" if $main::debug;
184 }
185
186 # various access routines
187 sub AUTOLOAD
188 {
189   my $self = shift;
190   my $name = $AUTOLOAD;
191   
192   return if $name =~ /::DESTROY$/;
193   $name =~ s/.*:://o;
194   
195   die "Non-existant field '$AUTOLOAD'" if !$valid{$name};
196   @_ ? $self->{$name} = shift : $self->{$name} ;
197 }
198
199 1;
200 __END__;