9ba985a6773b0b1425a8d4bbf27b7ddd0fc33b45
[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 require Exporter;
29 @ISA = qw(DXCommandmode DXProt Exporter);
30
31 use Msg;
32 use DXUtil;
33 use DXM;
34
35 %channels = undef;
36
37 # create a new connection object [$obj = DXChannel->new($call, $msg_conn_obj, $user_obj)]
38 sub new
39 {
40   my ($pkg, $call, $conn, $user) = @_;
41   my $self = {};
42   
43   die "trying to create a duplicate channel for $call" if $channels{$call};
44   $self->{call} = $call;
45   $self->{conn} = $conn if defined $conn;   # if this isn't defined then it must be a list
46   $self->{user} = $user if defined $user; 
47   $self->{t} = time;
48   $self->{state} = 0;
49   $self->{oldstate} = 0;
50   bless $self, $pkg; 
51   return $channels{$call} = $self;
52 }
53
54 # obtain a connection object by callsign [$obj = DXChannel->get($call)]
55 sub get
56 {
57   my ($pkg, $call) = @_;
58   return $connect{$call};
59 }
60
61 # obtain all the connection objects
62 sub get_all
63 {
64   my ($pkg) = @_;
65   return values(%channels);
66 }
67
68 # obtain a connection object by searching for its connection reference
69 sub get_by_cnum
70 {
71   my ($pkg, $conn) = @_;
72   my $self;
73   
74   foreach $self (values(%channels)) {
75     return $self if ($self->{conn} == $conn);
76   }
77   return undef;
78 }
79
80 # get rid of a connection object [$obj->del()]
81 sub del
82 {
83   my $self = shift;
84   delete $channels{$self->{call}};
85 }
86
87
88 # handle out going messages, immediately without waiting for the select to drop
89 # this could, in theory, block
90 sub send_now
91 {
92   my $self = shift;
93   my $conn = $self->{conn};
94
95   # is this a list of channels ?
96   if (!defined $conn) {
97     die "tried to send_now to an invalid channel list" if !defined $self->{list};
98         my $lself;
99         foreach $lself (@$self->{list}) {
100           $lself->send_now(@_);             # it's recursive :-)
101         }
102   } else {
103     my $sort = shift;
104     my $call = $self->{call};
105     my $line;
106         
107     foreach $line (@_) {
108       my $t = atime;
109           chomp $line;
110       print main::DEBUG "$t -> $sort $call $line\n" if defined DEBUG;
111           print "-> $sort $call $line\n";
112       $conn->send_now("$sort$call|$line");
113         }
114   }
115 }
116
117 #
118 # the normal output routine
119 #
120 sub send              # this is always later and always data
121 {
122   my $self = shift;
123   my $conn = $self->{conn};
124  
125   # is this a list of channels ?
126   if (!defined $conn) {
127     die "tried to send to an invalid channel list" if !defined $self->{list};
128         my $lself;
129         foreach $lself (@$self->{list}) {
130           $lself->send(@_);                 # here as well :-) :-)
131         }
132   } else {
133     my $call = $self->{call};
134     my $line;
135
136     foreach $line (@_) {
137       my $t = atime;
138           chomp $line;
139           print main::DEBUG "$t -> D $call $line\n" if defined DEBUG;
140           print "-> D $call $line\n";
141           $conn->send_later("D$call|$line");
142         }
143   }
144 }
145
146 # send a file (always later)
147 sub send_file
148 {
149   my ($self, $fn) = @_;
150   my $call = $self->{call};
151   my $conn = $self->{conn};
152   my @buf;
153   
154   open(F, $fn) or die "can't open $fn for sending file ($!)";
155   @buf = <F>;
156   close(F);
157   $self->send(@buf);
158 }
159
160 # just a shortcut for $dxchan->send(msg(...));
161 sub msg
162 {
163   my $self = shift;
164   $self->send(DXM::msg(@_));
165 }
166
167 # change the state of the channel - lots of scope for debugging here :-)
168 sub state
169 {
170   my $self = shift;
171   $self->{oldstate} = $self->{state};
172   $self->{state} = shift;
173   print "Db   $self->{call} channel state $self->{oldstate} -> $self->{state}\n" if $main::debug;
174 }
175
176 1;
177 __END__;