added program.html
[spider.git] / html / program.html
1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
2 <html>
3   <head>
4     <title>Programming New Commands</title>
5   </head>
6         <meta name="Keywords" content="DX Cluster, DXSpider, Spider, Packet Cluster, DXCluster, Pavillion Software, AK1A, AX25, AX.25, WWV, Packet Radio, Amateur Radio, Propagation, DX, DXing, G1TLH, GB7TLH, Dirk Koopman, Mailing list, Linux, RedHat, PERL">
7         <meta name="Description" content="Software and systems for realtime digital communications between amateur radio stations for the provision of information on propagation conditions and stations operating">
8         <meta name="Author" content="Dirk Koopman G1TLH">
9   </head>
10
11   <body TEXT="#000000" LINK="#0000ff" VLINK="#800080" BGCOLOR="#FFFFFF">
12         <FONT COLOR="#606060"> 
13           <hr>
14           <h2>Programming New Commands</h2>
15           <hr>
16         </font>
17         
18         
19         <address><a href="mailto:djk@tobit.co.uk">Dirk Koopman G1TLH</a></address>
20         <p>
21           <!-- Created: Sun Dec 13 20:25:14 GMT 1998 -->
22           <!-- hhmts start -->
23 Last modified: Wed Dec 23 18:27:06 GMT 1998
24 <!-- hhmts end -->
25         <h4>Introduction</h4>
26         
27         All the commands in the DXSpider system are 'soft', that is they are bits of
28         perl code that are put into specific places in the <tt>/spider</tt> directory tree. 
29         
30         <p>By putting them in a specific place and calling them &lt;command>.pl, they become
31           commands - in real time. Such is the magic of 
32           <a href="http://www.perl.com">perl</a>.
33
34         <h4>Directory Structure</h4>
35
36         The directory structure is very simple:-
37         <table border=2>
38           <tr><td>/spider</td><td>the main directory</td></tr>
39           <tr><td>/spider/data</td><td>where generated and/or reference data goes</td></tr>
40           <tr><td>/spider/data/spots/&lt;year>/&lt;day>.dat</td><td>one day's worth of spots</td></tr>
41           <tr><td>/spider/data/debug/&lt;year>/&lt;day>.dat</td><td>one day's worth of console debugging</td></tr>
42           <tr><td>/spider/data/log/&lt;year>/&lt;month>.dat</td><td>one month's worth of Logging info including things like rcmd, announces, talks etc</td></tr>
43           <tr><td>/spider/data/wwv/&lt;year>/&lt;month>.dat</td><td>one month's worth of WWV</td></tr>
44           <tr><td>/spider/msg</td><td>the messages directory</td></tr>
45           <tr><td>/spider/packclus/files</td><td>the files directory</td></tr>
46           <tr><td>/spider/packclus/bulletin</td><td>the bulletins directory</td></tr>
47           <tr><td>/spider/perl</td><td>where the issued program code lives</td></tr>
48           <tr><td>/spider/local</td><td>where your experimental/site specific programs go</td></tr>
49           <tr><td>/spider/cmd</td><td>where the issued command code lives</td></tr>
50           <tr><td>/spider/local_cmd</td><td>where your experimental command code goes</td></tr>
51         </table>
52
53         <p>A command is put in full as a file under the 'cmd' directory tree, for example, 
54           <tt>announce</tt> lives in <tt>/spider/cmd/announce.pl</tt> and <tt>show/dx</tt> lives
55           in <tt>/spider/cmd/show/dx.pl</tt>. 
56
57         <p>In general terms I don't like the habit of the standard packet cluster software has
58           of taking the DEC VMS command paradigm to the extreme that it has. So I have adopted
59           the convention of separating commands from arguments. So <tt>sh/dx/10 20</tt> is input
60           on the DXSpider system as <tt>sh/dx 10 on 20m</tt>. This is rather contentious.
61
62         <P>In order to maintain a larger level of compatibility, there is an <tt>Aliases</tt> which
63           lives in <tt>/spider/cmd</tt> (or can be overidden by one in <tt>local_cmd</tt>). This file
64           takes standard expressions, parses command lines and produces DXSpider compatible versions
65           of the old Packet Cluster commands. Currently, however, it doesn't do a 100% job because
66           the functionality of the new commands is different (and hopefully better).
67
68         <P>In addition, in the <tt>/spider/perl</tt> directory (overidden by ...) there is 
69           the <tt>Messages</tt> file. This is the file where all the system messages will be stored
70           (because of laziness on my part this isn't currently the case). You will see instances
71           of its use like <tt>$self->msg(&lt;string>&nbsp;[,$arg..])</tt>. This call uses
72           <tt>$self</tt> to determine what language you are in, to return you the correct message.
73           The way arguments are passed to the routine, mean that you can reorder the arguments
74           in your message to suit your language without changing the actual code.
75
76           <p>When you roll your own commands, put
77           your messages in your own copy of the <tt>Messages</tt> file and don't forget
78           to send me the patches for that as well the command itself.
79                             
80         <p>When I issue a new version or patches for an existing version then only files in
81           the <tt>/spider/cmd</tt> and <tt>/spider/perl</tt> directories will normally be altered.
82           Occasionally, one or two of the reference files in <tt>/spider/data</tt> may be altered.
83           The only files likely to be affected are <tt>bands.pl</tt> and <tt>prefix_data.pl</tt>.
84
85         <p>As it says in the next section, <b>PLEASE</b> experiment in the local directories! It will
86           save a lot of pain when patching code. Having said that, if you have been playing, then 
87           remember to remove or rename any files with new releases that claim to have incorporated 
88           your modifications, otherwise <EM>it will continue to use the old ones in your local 
89                 directories!</em>
90
91         <h4>Hints, Tips and Exhortations</h4>
92
93         <ol>
94
95                 <p><li>Every command that can used on the command line lives in either
96                 this directory ('cmd') or in a local version ('local_cmd'). You are
97                 cajoled or ordered not to and generally discouraged from altering the
98                 commands in the 'cmd' directory. You can put local copies in the
99                 'local_cmd' directory and they will override the standard ones.
100
101                 <p><li>If you want to play, do it in the 'local_cmd' directory. It's
102                 very easy and reasonably safe. You can override a command whilst the
103                 cluster is running.  Compilation errors will simply give you error
104                 messages, it won't stop the cluster running - this only happens if you
105                 mess with the internals to the extent that it gets confused...
106                 
107                 <p><li>A command is a piece of perl, it is simply a small snippet of
108                 program that is dynamically loaded into the cluster on invocation from
109                 the command line. The last modification time is used to determine
110                 whether to reload it.
111                 
112                 <p><li>New (or altered) commands are available for test the moment you
113                 save them.
114                 
115                 <p><li>A command is placed into the appropriate directory with a '.pl'
116                 appended to the end. So the 'show/qra' command lives in
117                 'cmd/show/qra.pl' (or a local version would be in
118                 'local_cmd/show/qra.pl'.
119                 
120                 <p><li>For the security conscious, potentially dubious
121                 characters command line args (i.e. not [A-Za-z0-9_/]) are
122                 converted to their hex equivalents. This will almost certainly
123                 mean that the user will get an error message (unless you have
124                 your secret squirrel hat on and have deliberately put such
125                 commands up [in 'local_cmd' of course]).
126
127                 <p><li>The snippets of program you put here are wrapped in an eval { }
128                 and are subroutines derived from the DXChannel class. They effectively
129                 the following declaration :-
130                 <p><pre>
131   sub Emb_<cmdname>($self, $args)
132   {
133      ...
134      your code here
135      ...
136   }
137                 </pre>
138
139                 <p><li>slash characters are replaced by '_' so the equivalent name for
140                 'show/qth' is 'Emb_show_qth'.
141
142                 <p><li>you would normally do a 'my ($self, $line) = @_;' as the first
143                 thing. There are a complete set of accessors for DXUser, DXCommandmode,
144                 DXChannel and most other classes and these are the recommended way of getting at
145                 the contents of these classes.  A fairly standard start might be:-
146                 <p><pre>
147   my ($self, $line) = @_;
148   my @args = split /\s+/, $line;
149   my $call = $self->call;
150   my $user = $self->user;
151   my @out;
152
153   # check privileges
154   return (1, $self->msg('e5')) if $self->priv < 5;
155
156   ....
157   ....
158   some perl code here
159   ....
160   ....
161   return (1, @out);
162                 </pre>
163
164                 <li>$line (in this example) is the rest of the line after the command (as a string).
165
166                 <p><li>You are responsible for maintaining user security. If you have
167                 a command that does something a normal system shouldn't be allowed to
168                 do or see, there is $self->priv (using the above example) which gives
169                 you the running privilege level of the channel. USE IT!
170
171                 <p><li>The privilege levels used in the standard code are:-
172
173                 <p>0 - is the normal user privilege.
174                 <p>1 - is the remote user privilage (you need to be at least 1 to get
175                   any output from an <tt>rcmd</tt>).
176                 <p>5 - is the normal external sysop privilege, give this to commands that
177                   you are prepared to let non-local sysops use.
178                 <p>8 - a <em>very</em> trusted, probably internet rather than radio connected
179                   remote sysop.
180                 <p>9 - the do anything console privilege. 
181                 
182                 <p>The sysop privilege is for things that you are prepared for remote
183                 sysops and clusters to do or see.
184                 
185                 <p>A console privilege can only be executed locally (at least if you have
186                 correctly installed the client program in inetd or ax25d).
187                 
188                 <p>The set/priv command can only be executed by a console privileged 
189                 session.
190
191                 <p><li>You must return a list with a 0 or 1 as the first element. 1
192                 means success and 0 means fail. Each element of the list which follows
193                 is assumed to be one line for output. Don't put \n characters at the
194                 end of an element (the client will put the correct one in if required
195                 [but see below]).
196                 
197                 <p><li><b>DO NOT</b>send output direct to the user unless you <em>really</em>
198                 mean it (i.e. it is never appropriate for this command to be used remotely
199                 as an <tt>rcmd</tt> or from some kind of batch or cron file.
200
201                 <p>What you do instead is create a list using
202                 <pre>
203 my @out;
204         </pre> 
205                 and then <tt>push</tt> stuff onto it. Each element on the list will
206                 become a line of output. For exmaple:-
207                 <pre>
208 #
209 # set a user's password
210 #
211 # Copyright (c) 1998 Iain Phillips G0RDI
212 # 21-Dec-1998
213 #
214 # Syntax:       set/pass &lt;password> &lt;callsign>
215 #
216   
217 my ($self, $line) = @_;
218 my @args = split /\s+/, $line;
219 my $call;
220 my $pass = shift @args;
221 my @out;
222 my $user;
223 my $ref;
224   
225 return (1, $self->msg('e5')) if $self->priv < 9;
226   
227 foreach $call (@args) {
228     $call = uc $call;
229     if ($ref = DXUser->get_current($call)) {
230         $ref->passwd($pass);
231             $ref->put();
232                 push @out, $self->msg("password", $call);
233         } else {
234                 push @out, $self->msg('e3', 'User record for', $call);
235         }
236 }
237 return (1, @out);
238             </pre>
239                 a more complicated example:-
240                 <pre>
241 #
242 # display the band data
243 #
244 # Copyright (c) 1998 - Dirk Koopman G1TLH
245 #
246 # $Id$
247 #
248
249 #$DB::single = 1;
250
251 my ($self, $line) = @_;
252 my @f = split /\s+/, $line;
253 my @bands;
254 my $band;
255 my @out;
256 my $i;
257
258 if (!$line) {
259         @bands = sort { Bands::get($a)->band->[0] &lt;=> Bands::get($b)->band->[0] } Bands::get_keys();
260         push @out, "Bands Available:-";
261         foreach $band (@bands) {
262                 my $ref = Bands::get($band)->band;
263                 my $s = sprintf "%10s: ", $band;
264                 for ($i = 0; $i &lt; $#{$ref}; $i += 2) {
265                         my $from = $ref->[$i];
266                         my $to = $ref->[$i+1];
267                         $s .= ", " if $i;
268                         $s .= "$from -> $to";
269                 }
270                 push @out, $s;
271         } 
272         push @out, "Regions Available:-";
273         @bands = Bands::get_region_keys();
274         foreach $band (@bands) {
275                 my $ref = Bands::get_region($band);
276                 my $s = sprintf("%10s: ", $band ) . join(' ', @{$ref}); 
277                 push @out, $s;
278         }
279 }
280
281 return (1, @out)
282         </pre>
283                 <p><li>As this is perl and it is very easy to alter stuff to get it
284                 correct, I would like to see some intelligent argument processing,
285                 e.g. if you can have one callsign, you can have several. Interpret
286                 your arguments; so for example:-
287
288                 <pre>
289   set/qra jo02lq       - sets your own locator to JO02LQ
290   set/qra g1tlh jo02lq - sets G1TLH's locator (if you are allowed)
291   or
292   show/qra in92jo      - displays the bearing and distance to 
293                          IN92JO using your lat/long or locator
294   show/qra jn56in in92jo  - bearing and distance between two
295                             locators
296         </pre>
297
298                 <p><li>It is important that you remember when you have tie
299                 hashes using MLDBM et al. If you do a
300                 <tt>DXUser->get($call)</tt> you will get a different (older)
301                 thing than the one in <tt>$self->user</tt>. This is almost
302                 certainly NOT what you want if want to modify a user that is
303                 currently connected. Either use <tt>$self->user</tt> or, if
304                 you want another user, use <tt>DXUser->get_current($call)</tt>
305
306                 <p><li>If you want to debug something, start the cluster.pl up thus:-
307                 <pre>
308   perl -d cluster.pl
309   dbg> r
310                 </pre>
311                 Then you can go into debug mode at anytime by using the command :-
312                 <pre> 
313   debug
314         </pre>
315   or you can put the line:-
316                 <pre>
317   $DB::single = 1;
318                 </pre>
319                 in an appropriate place in a command. This will only have an effect
320                 if you are running in perl debug mode.
321                 
322                 <p>If all else fails (actually it is very simple), just stick print
323                   commands in everywhere and the output will appear on the cluster.pl
324                   screen.
325
326                 <p><li>Anything you output with a > as the last character is taken to
327                 mean that this is a prompt and will not have a \r or \n appended to
328                 it in the client for telnet sessions (only).
329
330                 <p><li>help is kept in <tt>/spider/cmd/Command_<lang>.hlp</tt> files.
331                 The format of the help files should be self explanatory, but they are
332                 explained further in the files themselves.
333
334                 <p><li>PLEASE add your new commands to the Commands_*.hlp file so that
335                 people know about and how to use them!
336
337         </ol>
338
339 <!-- Standard Footer!! -->
340         <p>&nbsp;</p>
341         <p>
342           <FONT COLOR="#606060"><hr></font>
343         <font color="#FF0000" size=-2>
344           Copyright &copy; 1998 by Dirk Koopman G1TLH. All Rights Reserved<br>
345         </font>
346         <font color="#000000" size=-2>$Id$</font>
347   </body>
348 </html>