]> dxcluster.net Git - spider.git/commitdiff
add the Java Client from M0AZM
authorminima <minima>
Wed, 18 Apr 2001 16:11:46 +0000 (16:11 +0000)
committerminima <minima>
Wed, 18 Apr 2001 16:11:46 +0000 (16:11 +0000)
35 files changed:
Changes
SpiderConsole/docs/COPYING [new file with mode: 0755]
SpiderConsole/docs/INSTALL [new file with mode: 0644]
SpiderConsole/docs/bugs.txt [new file with mode: 0644]
SpiderConsole/docs/spider-proto [new file with mode: 0644]
SpiderConsole/src/Cluster.java [new file with mode: 0644]
SpiderConsole/src/CommandBuffer.class [new file with mode: 0644]
SpiderConsole/src/CommandBuffer.java [new file with mode: 0644]
SpiderConsole/src/Connection.class [new file with mode: 0644]
SpiderConsole/src/Connection.java [new file with mode: 0644]
SpiderConsole/src/ConnectionInput.class [new file with mode: 0644]
SpiderConsole/src/ConnectionInput.java [new file with mode: 0644]
SpiderConsole/src/ConnectionOutput.class [new file with mode: 0644]
SpiderConsole/src/ConnectionOutput.java [new file with mode: 0644]
SpiderConsole/src/Console$1.class [new file with mode: 0644]
SpiderConsole/src/Console$2.class [new file with mode: 0644]
SpiderConsole/src/Console$3.class [new file with mode: 0644]
SpiderConsole/src/Console$4.class [new file with mode: 0644]
SpiderConsole/src/Console$5.class [new file with mode: 0644]
SpiderConsole/src/Console$6.class [new file with mode: 0644]
SpiderConsole/src/Console.class [new file with mode: 0644]
SpiderConsole/src/Console.java [new file with mode: 0755]
SpiderConsole/src/LimitedStyledDocument.class [new file with mode: 0644]
SpiderConsole/src/LimitedStyledDocument.java [new file with mode: 0644]
SpiderConsole/src/PipedInputMUX.class [new file with mode: 0644]
SpiderConsole/src/PipedInputMUX.java [new file with mode: 0644]
SpiderConsole/src/PipedOutputMUX.class [new file with mode: 0644]
SpiderConsole/src/PipedOutputMUX.java [new file with mode: 0644]
SpiderConsole/src/Plugin.class [new file with mode: 0644]
SpiderConsole/src/Plugin.java [new file with mode: 0644]
SpiderConsole/src/SpiderCluster$1.class [new file with mode: 0644]
SpiderConsole/src/SpiderCluster$2.class [new file with mode: 0644]
SpiderConsole/src/SpiderCluster$3.class [new file with mode: 0644]
SpiderConsole/src/SpiderCluster.class [new file with mode: 0644]
SpiderConsole/src/SpiderCluster.java [new file with mode: 0644]

diff --git a/Changes b/Changes
index b6ee32869fa01bb175da44ff4ed682bbf848c6fd..1181d36fc603c92702fe6809dfb68ae7b4781c12 100644 (file)
--- a/Changes
+++ b/Changes
@@ -1,3 +1,7 @@
+18Apr01=======================================================================
+1. added Ian M0AZM's Java Client (SpiderConsole)
+17Apr01=======================================================================
+1. made a slight speedup on write in Msg.pm (about doubled it)
 16Apr01=======================================================================
 1. make the correct error messages come out on reject/accept when people
 leave out keywords like 'on'.
diff --git a/SpiderConsole/docs/COPYING b/SpiderConsole/docs/COPYING
new file mode 100755 (executable)
index 0000000..d3744a4
--- /dev/null
@@ -0,0 +1,367 @@
+*******************************************************************************
+
+                            NO WARRANTY
+
+      BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+      IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+
+*******************************************************************************
+
+
+                   GNU GENERAL PUBLIC LICENSE
+                      Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                   GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                           NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+
+       Appendix: How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/SpiderConsole/docs/INSTALL b/SpiderConsole/docs/INSTALL
new file mode 100644 (file)
index 0000000..d1dd6fe
--- /dev/null
@@ -0,0 +1,79 @@
+RadioConsole (Possibly referred to as SpiderConsole)
+by (C) 2001 Ian Norton, i.norton@lancaster.ac.uk
+First Release v1.0, 20010418 (18th April 2001).
+
+1.  Introduction
+
+ This document assumes that you have the JDK or JRE already installed and
+working on your machine.  I have no intention of providing a HOWTO on this,
+there are plenty out there already. <http://www.blackdown.org> has a list of
+JDK/JRE mirror sites for Linux if you don't have it.
+ If you install the JRE (Java Runtime Environment) you will not be able to
+compile the source code, you will only be able to interpret the code that
+has already been compiled (Java works by compiling source into byte code,
+and then using an interpreter to run the byte code, this is why you must
+install some Java stuff, but this is also how it is platform independent).
+ If you don't intend to modify or recompile the source code, skip the
+programming section, it won't be of any interest to you.
+ This version of JCAdmin has been tested with the Blackdown port for linux
+of the Java Development Kit version 1.3.0 <http://www.blackdown.org/>.          
+
+1.1.  Acknowledgements
+
+ Some time ago I created JCAdmin for my good friends Ian (G0VGS) and Linda 
+(G0YLM) Maude.  JCAdmin was designed to be an admin interface to the CLX 
+cluster software (http://www.clx.muc.de/).  It was written with the expressed
+purpose of performing certain tasks on Ian's cluster and never really intended
+to be anything marvelous.  After about a year of using this, Ian decided that
+CLX was no longer the software he wanted to use and switched to Dx Spider
+(http://www.dxcluster.org).  After much wailing and gnashing of teeth he
+persuaded me that perhaps I might like to write a new console for Spider.
+After experiencing a brief sense of flashback and "I've been here before" I
+decided that it would be a good challenge to write not only a new console but
+a framework on which to build future consoles.
+
+This is the approach I have taken with this console.
+
+1.2.  So how do I get this console to talk to something then?
+
+ The console works on the principle that whatever specific task you want to
+perform can be done with a plugin.  The console provides a framework for adding
+and removing plugins that provide menu items, toolbar buttons and so on.
+(Some of these features are planned but havn't yet been implemented fully).
+
+ To take the previously mentioned example, the SpiderCluster plugin can talk
+directly to the DX Spider internal protocol engine, thus allowing the user
+administrative rights on the cluster whilst they are using the console.
+
+ All sections SPECIFIC to spider are written into the SpiderCluster plugin.
+Generic communication modules are then used to get everything to talk.
+The next logical addition to the SpiderCluster plugin is a standard Cluster
+plugin that allows a user to connect to a spider cluster via IP (Although this
+requires some more work before it's actually useful).
+
+ So using the generic framework should make just about anything possible.
+Want a graph of WWV/WCY?  Just write a new plugin for it then!
+
+1.3.  Getting it to run.
+
+ Compile all the java files in the src directory simply with javac *.java.
+ You should now be able to start the console with java Console.
+ By default the SpiderCluster plugin is used and a connect made to
+        127.0.0.1:27754.
+
+1.4.  New versions / updates.
+ New versions of RadioConsole and it's documentation will be made available
+ through the DX Spider homepage <http://www.dxcluster.org/>.
+
+1.5.  Feedback
+ Please mail me your comments, observations and suggestions for features or
+improvements and in the unlikely event (!) of bugs.  I will do my best to give
+you a prompt reply and request number!
+Ian Norton
+i.norton@lancaster.ac.uk
diff --git a/SpiderConsole/docs/bugs.txt b/SpiderConsole/docs/bugs.txt
new file mode 100644 (file)
index 0000000..d621983
--- /dev/null
@@ -0,0 +1,13 @@
+Bug #1 20010403 - reporter Ian, G0VGS.
+
+    Error on typing in a long command.
+
+    java.lang.IndexOutOfBoundsException
+            at java.io.PipedInputStream.read(PipedInputStream.java:271)
+            at PipedInputMUX.run(PipedInputMUX.java:79)
+            at java.lang.Thread.run(Thread.java:484)
+    ConnectionOutput: IOException reading data.
+                
+    IDN 20010403 - Fixed 
+        PipedInputMUX was trying to read all the input into a 16 byte array.
+        Put an if > 16 line in that tells it to only read 16 bytes.
diff --git a/SpiderConsole/docs/spider-proto b/SpiderConsole/docs/spider-proto
new file mode 100644 (file)
index 0000000..a1a4bfd
--- /dev/null
@@ -0,0 +1,256 @@
+<ea1dav> supose two ports in tnc3
+<Stephan> never tried the 2nd port Jesus
+<ea1dav> oh,ok
+<Stephan> but it is mentioned in the ax25-howto (not tnc3, but multiport tnc´s)
+<ea1dav> yes i have an kpc4 in my node and use mkis
+<ea1dav> but go to change by an tnc3 1k2/9k6
+<Stephan> should be easy anyway
+<ea1dav> how many RAM you have in tnc3 ?
+<Stephan> at db0sue-4(db0sue-7) 256Kb
+<ea1dav> it seem the standard when attached to an PC, then a buy with 256K also
+<Stephan> It isd tnc3/xnet and just have 2 links (one local to db0sue-7 wire and one to db0sue on 2.4GHz 80m distance)
+<ea1dav> ah, Xnet inside tnc..No i have xnet run in pc.
+<ea1dav> a radio link off 80 m the shortest I know :-)
+<Stephan> a kiss link, with Siemens GIGA SET M101DATA (virtuell rs232)
+<ea1dav> how  much power (mW).. it is very interesant
+<Stephan> 100mW, but not sure - have to search for the manual
+<ea1dav> are usual (easy to find ) that equipment..?
+<Stephan> look for M101DATA
+<Stephan> 115k2 (real 57k6)
+<ea1dav> very good,only need an external antena to increase distance.
+<Stephan> max 6.5Km we have tested
+<ea1dav> with external...or with built in antena.?
+<Stephan> external
+<ea1dav> ah, very good solution,I like it.
+<Stephan> since 1 1/2 year we have that link up without any error
+<ea1dav> and is an rs-232 transparent or need some software.?
+<ea1dav> all info that fint is in german :-(
+<ea1dav> find
+<Stephan> yep, needs windows to setup the master and slave - just for initial
+<ea1dav> and then store the info and act like a cable.?
+<Stephan> it is stored in the memory of the master/slave rx/tx
+<-- pa3ezl has quit (EOF From client)
+<-- Dirk-home has quit ([x]chat)
+<ea1dav> go home....by
+<ea7wa> bye
+<-- ea1dav (ea1dav@212.51.60.18) has left #9000 (ea1dav)
+<-- oz1lqh (~nospam@cpe.atm0-0-0-130143.arcnxx2.customer.tele.dk) has left #9000 (oz1lqh)
+<ea7wa> check your mail Stephan
+<g0vgs> is it fixed Angel?
+<ea7wa> which thing Ian ?
+<Stephan> ok
+<g0vgs> the mail
+<g0vgs> and ge all
+<ea7wa> no, I'm talking with Ben, but maybe I'm loosing my english and I'm not able
+<ea7wa> to explain myself in this language
+<g0vgs> I was reading your comments and it seems ok to me
+<g0vgs> although to my knowledge, Spider and AK1A treat mail in the same way.  I cannot be sure about DXNet
+<ea7wa> I think Olivier will be also using that style for dxnet
+<g0vgs> The diff with Spider is that it treats mail as simply as possible
+<g0vgs> that is.. it can only ever deal with one message at a time
+<g0vgs> and if it receives a message for another node/user it simply says...
+<g0vgs> is that node/user on the network?  Ok, send the message.  There is no delay at all
+<ea7wa> yes, that's understood bye Ben, it will be fixed it seems in next release
+<ea7wa> so, send the message as soon as it arrives.
+<g0vgs> good, it would be nice to see it finally fixed
+<ea7wa> <dl6rai-1>: b) trigger it whenever an outgoing message is created
+<g0vgs> only send it if the user is seen on the network
+<Stephan> got it - finally :)
+<g0vgs> if the user cannot be seen on the network then hold the message until they are
+<g0vgs> pointless sending mail when we do not know where the user will appear
+<g0vgs> the time is a day out on that example Angel!
+<g0vgs> sorry, I thought it was the same message, it is not
+<g0vgs> well I am going to bed folks, I have work in the morning :-(
+<g0vgs> at least I will be working at home!
+<Stephan> nite Ian
+<g0vgs> g'night all
+* g0vgs  is away: Zzzzzzzzzz
+<ea7wa> Bye Ian, all stuff on clx is being sent with that PC28 synyax
+<ea7wa> synyax = syntax
+<Stephan> Im off for to bed, goodnight
+--- Stephan is now known as dk8lv-Zzz
+<ea7wa> did you get the mail ?
+<dk8lv-Zzz> yes, I told you
+<ea7wa> ah, sorry
+<dk8lv-Zzz> will try that one tomorrow
+<ea7wa> ok, sleep well
+<dk8lv-Zzz> goodnight Angel
+<dk8lv-Zzz> btw
+<dk8lv-Zzz> need someone looking for sue-7 the next weeks
+--> pa4ab (~pa4ab@212.163.193.2) has joined #9000
+<Amanda> [pa4ab] [pa4ab] Arnold, qth: Ede joins channel #9000 Hello to all!
+--- Amanda gives channel operator status to pa4ab
+<dk8lv-Zzz> Hello Arnold, merry christmas for the rest
+--- dk8lv-Zzz is now known as Stephan
+<pa4ab> Hello Stephan also a Merry Christmas for next year :-0
+<Stephan> still sun, beach and girls ?
+<Stephan> :))
+<pa4ab> Nope rain and rain and rain
+<Stephan> too bad - but here it is/was cold - not too much snow yet
+<pa4ab> no snow here still ten degrees at night
+--> pa3ezl (^aurelio@pa3goj.ampr.org) has joined #9000
+<pa3ezl> GA!
+<pa4ab> Hello Aurelio
+<Stephan> thought that channel ops are able to give op to other
+<pa3ezl> nice to see you ARnold!
+<Stephan> but Amanda do not like that
+<Stephan> hi Aurelio
+<pa3ezl> how have you been?
+<pa3ezl> GA Stephan
+<pa4ab> Who needs to be operator here?
+<pa4ab> I am doing well Aurelio although very busy :-)
+<pa4ab> how are things in PA country?
+<Stephan> Ian (0AZM), Jesus, Rene
+<pa4ab> Do we all need to be operator?
+<Stephan> don´t know :)
+<pa3ezl> snow..
+<pa4ab> I better can ask Amanda to put auto-operator on!
+<pa3ezl> but slowly melting
+<pa4ab> SNOW????????????????????????????????????
+<pa3ezl> yes!
+<pa3ezl> 2cm
+<pa3ezl> I was just outside putting some 'karton' in from of the 'radiateur'
+<pa3ezl> it feels cold
+<pa4ab> Mhh we are better of here it seems
+<pa3ezl> other than that, all is fine. Another 'attach' by that Molukse actiegroep
+<pa3ezl> attach=attack
+<Stephan> Arnold, is there a command to put lilo into MBR (not with yast)?
+<pa3ezl> so, how is your work progressing?
+<pa4ab> another? I have not heard about that do we have ETA now in Holland too?
+<pa4ab> Well work is not progressing too well, waiting for the lines (for internet)
+<pa4ab> Telefonica is not that fast
+<pa3ezl> well, they claimed the action of putting a sack of rocks on a rail track
+<pa4ab> oh dear
+<pa3ezl> all and all it was nice, white Xmas
+<pa3ezl> can you operate HF?
+<pa4ab> No not right away I have stuff with me but at 'home'
+<pa4ab> not at work
+<pa4ab> I think it must be defined in /etc/lilo.conf Stephan
+<pa3ezl> I will be in EHV this friday, would be nice working you
+<pa4ab> Well I can try but friday is a transport day here I will go back to our house in Asturias
+<pa4ab> for the celebration of the end of the year
+<Stephan> looked there, but it foes not tell how to install lilo into mbr
+<pa3ezl> -rr- next time then
+<pa4ab> and what's wrong with yast?
+<Stephan> if, for some reason, I have to fdisk /mbr (overwrite lilo), I have to re-install the whole linux
+<Stephan> coz yast just can install lilo to hda and yast2 to hde (only once)
+<pa4ab> lilo has an uninstall
+<Stephan> and I don´t have hda as my first HD
+<pa4ab> lilo -u
+<pa3ezl> Bem-vindo ao PY5UFP-11 Cluster CLX (r) v4.06 - Voce se logou de 200.17.209.10
+<Stephan> that is un-install?!
+<pa3ezl> is that version still with user links?
+<pa4ab> yes Stephan
+<pa4ab> yes Aurelio
+<pa4ab> sorry have to run
+<pa4ab> cu l8ter
+<pa3ezl> bye
+<Stephan> I want the other way - install to mbr on /dev/hde
+<Stephan> cul Arnold
+<-- pa4ab has quit (Connection reset by peer)
+<ea7wa> Hola
+<Stephan> Hola Angel
+<-- pa3ezl has quit (Leaving)
+--> dk8lv-Zzz (~dk8lv@pD903B746.dip.t-dialin.net) has joined #9000
+<Amanda> [dk8lv-Zzz] Stephan - Groß Rheide
+--- Amanda gives channel operator status to dk8lv-Zzz
+<-- Stephan has quit (Ping timeout)
+<-- ea7wa has quit (Leaving)
+--> pa4ab (~pa4ab@212.163.193.2) has joined #9000
+<Amanda> [pa4ab] [pa4ab] Arnold, qth: Ede joins channel #9000 Hello to all!
+--- Amanda gives channel operator status to pa4ab
+<-- pa4ab has quit (Connection reset by peer)
+--> Dirk-home (~djk@gate.tobit.co.uk) has joined #9000
+--- Amanda gives channel operator status to Dirk-home
+<Dirk-home> Greetings to this IRC channel
+<m0azm> Evening
+<Dirk-home> LO
+<Dirk-home> ?
+<m0azm> Been looking at a java based telnet interface today Dirk.  It supports an applet front end and plug in modules.
+<m0azm> Built in support for IO stream plug in filters too...
+<m0azm> Looks like an ideal start for a front end.
+<Dirk-home> I am just in the process of thinking about making some small changes to the 'internal' protocol so that it is possible to distinguish talks from announces from dx from logging info from the rest
+<Dirk-home> But I really need to get the latest 'version' out the door so IAN are you there?
+<Dirk-home> IAN
+<m0azm> Havn't had chance to look at that yet.  How does that work in terms of actually connecting to the cluster?  Does it connect as a normal user and then do some kind of negotiaton?
+<Dirk-home> The internal protocol is very simple:-
+<Dirk-home> <letter><callsign>|<data>\n
+<Dirk-home> when you connect you send:
+<Dirk-home> AG1TLH|telnet
+<Dirk-home> (if you are telnetting in)
+<Dirk-home> to send a 'normal' line to the node:
+<Dirk-home> IG1TLH|t m0azm hello sailor
+<Dirk-home> it replies to you (for normal data)
+<Dirk-home> DM0AZM|M0AZM de G1TLH: Hello sailor
+--> ea1dav (jesus@180-CORU-X5.libre.retevision.es) has joined #9000
+<Dirk-home> there are a few control letters like:-
+<Dirk-home> BG1TLH|0
+<Dirk-home> EG1TLH|0
+<Dirk-home> which means don't buffer and don't echo respectively and are sent to the client by the node
+<Dirk-home> and 
+<Dirk-home> ZG1TLH|Bye
+<Dirk-home> should be self evident
+--> pa3ezl (pa3ezl@c71057.upc-c.chello.nl) has joined #9000
+--- Amanda gives channel operator status to pa3ezl
+<Dirk-home> no binary (all such are encoded over the link as %07, %FF etc)
+<pa3ezl> GE all
+<Dirk-home> GE
+<m0azm> Ge.
+<ea1dav> Ge all
+<Dirk-home> as default the node only listens to localhost port 27754
+<m0azm> Where abouts do the new protocol bits live?
+<Dirk-home> what I will do is make talk output 'TG1TLH|', DX broadcasts 'XG1TLH|' and announce broadcasts 'NG1TLH|' so you can stick them into different colours/windows easily also have 'LG1TLH|' for logging info which currently comes out on the stdout of the node program
+<Dirk-home> new protocol is inter cluster protocol and that has not been designed in detail yet, I thought you wanted to do a sysop interface in java?
+<m0azm> Yes, I thought this was the internode protocol though?  Or do you have a separate proto for the console?
+<Dirk-home> separate protocol for console and clients. 
+--> aurelio (pa3ezl@c71057.upc-c.chello.nl) has joined #9000
+<Dirk-home> It is a client/server architecture.
+--- Amanda gives channel operator status to aurelio
+<Dirk-home> this is the simple internal protocol that you have to interpret.
+<m0azm> Ok, I think I'm confused now.  Will this be a connect to localhost port 27754 or a connect to the standard port?
+<Dirk-home> Of course there in nothing to stop me sending you either full or bastardised PC protocol but that may a bit too much for starters.
+<-- aurelio has quit (EOF From client)
+<Dirk-home> OK
+<m0azm> :)
+<Dirk-home> What happens is this:
+<Dirk-home> There is a node (cluster.pl) which is a server which sits there listening on localhost port 27754
+<m0azm> Ok.
+<Dirk-home> then either it or some other process starts a 'client' who's sole job in life is to normalise 'input' and 'output' to and from this server
+<m0azm> Right, ok I'm with you now.
+<m0azm> So I could manually telnet to the port and issue these commands?
+<m0azm> Same idea as sendmail etc..
+<Dirk-home> for a 'normal' user this amounts to dealing with line ending conventions and coping with 'binary characters'
+<Dirk-home> yes.
+<m0azm> Sorry, I seem to be a little slow on the uptake today :-)
+<Dirk-home> The callsign that you use determines whether you see 'user' or 'node' data - but the data is always framed in the way I described earlier. 
+<m0azm> Ok.  That seems fairly straight forward.
+<Dirk-home> It isn't wonderfully secure, which is why the node only listens to localhost.
+<Dirk-home> If you look at console.pl it should show you the sort of thing that happens. It is very simple.
+<Dirk-home> what it doesn't currently do is distinguish the various broadcast things from 'interactive' traffic which is what I want to do next. If I also allow log info onto that 'channel' then you can split out a window with that on. 
+<m0azm> Ok, I've just given it an initial glance today.  Trying to work out how the Java Telnet application works.
+<m0azm> It seems to do everything that we need, it just needs tweeking.
+<Dirk-home> My personal view is that you might be better to start again. A lot of these 'applets' have been written by erm... less experienced people.
+<Dirk-home> send us a copy and let me look at (just out of curiosity).
+<m0azm> It looks to be written how I had initially thought about writing it.
+<m0azm> Hang on, I'll grab the URL.
+<m0azm> http://www.mud.de/se/jta/html/download.html
+<m0azm> It'll need a bit of a re-work to get the GUI to look a bit nicer, but other than that it seems a good way to start.
+<m0azm> Or, as you say I might steal some of the better ideas and start afresh.
+<Dirk-home> It's erm.. big isn't it? it's bigger than a normal telnet session!
+<m0azm> Yes, it's a bit bloated.  But then there's no telnet implementation for Java, you have to write your own from scratch.
+<m0azm> It has lots of extra rubbish we don't need such as ssh support.
+<Dirk-home> I was sort of thinking that this might be a stand alone thingie rather than a 'use a browser' thingie.
+<Dirk-home> You shouldn't need any of the telent protocol stuff (%ff%xx) pairs. I assume a 'noecho' connection
+<m0azm> Yes, that's what it does.  There's an applet there too, but it's just a front end plug in.
+<m0azm> So you think I should be able to open a raw connection to it?
+<Dirk-home> basically you don't need anything other than a basic socket connection plus the 'internal' protocol engine together with a really funky 'swing' interface (:-)
+<Dirk-home> That's what I do.
+<m0azm> I'm just looking at funky swing stuff atm
+<m0azm> !
+<m0azm> Ok, I'll have a re-think.
+<Dirk-home> have a look at the perl/C clients you will see they are very simple.
+<m0azm> I thought I had to deal with the telnet stuff from the RFC.
+<Dirk-home> Of course once you have done that then we can look at the 'remote' user version that implements the multicast protocol (that I haven't defined properly yet) and start to make this all really good...
+<m0azm> <Throws a thick book out of the window>
+<Dirk-home> and with that thought I shall leave for a moment or five and search for a nice glass of wine...
+<m0azm> Ok, thanks for the pointers :-)
diff --git a/SpiderConsole/src/Cluster.java b/SpiderConsole/src/Cluster.java
new file mode 100644 (file)
index 0000000..2bd1240
--- /dev/null
@@ -0,0 +1,358 @@
+/**
+ * Cluster - Cluster console plugin.
+ * @author Ian Norton
+ * @verison 0.1 - 28/12/00.
+ * @see JPanel
+ * 
+ * RadioConsole.
+ *
+ * Copyright (C) 2001 Ian Norton.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public Licence as published by
+ * the Free Software Foundation; either version 2 of the Licence, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public Licence
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.                     *
+ * Contacting the author :
+ * Ian Norton
+ * i.norton@lancaster.ac.uk
+ * http://www.lancs.ac.uk/~norton/
+ **/
+
+import javax.swing.*;
+import javax.swing.text.*;
+import javax.swing.event.*;
+import java.awt.*;
+import java.io.*;
+import java.awt.event.*;
+import java.util.Hashtable ;
+import java.util.Enumeration ;
+
+// public class Cluster extends Plugin implements Runnable
+class Cluster extends Plugin implements Runnable
+    {
+    // Name and tip used when creating the tabbed pane.
+    public static final String NAME = "Cluster" ;   
+    public static final String TIP = "DX Cluster Console" ;   
+    
+    // Number of commands to buffer.
+    public static final int CMDBUFFERLINES = 30 ;
+
+    // Number of lines of scrollback to buffer.
+    public static final int SCROLLBUFFERLINES = 100 ;
+
+    public static final boolean DEBUG = false ;
+
+    // Input and output streams for the plugin.
+    // private PipedInputStream pin ;
+    private BufferedReader bir ;
+    private PipedOutputStream pos ;
+
+    // User input field.
+    private JTextField tf ;
+
+    private JTextPane jtp ;
+    private Thread t ;
+    private SimpleAttributeSet attr ;
+    private LimitedStyledDocument doc ;
+
+    // Input line scrollback buffer.
+    private CommandBuffer cbuf ;
+
+    private static final String encoding = "latin1"; // "ISO8859_1";
+
+    /**
+     * Class initialiser.
+     **/
+    public Cluster()
+        {
+        super() ;
+        }   
+
+    /**
+     * Plugin initialiser.
+     * @param PipedInputStream i - Stream to read data from
+     * @param PipedOutputStream o - Stream to write data to
+     **/
+    public void init(PipedInputStream i, PipedOutputStream o)
+        {
+        // Initialise the plugin IO.
+        bir = new BufferedReader(new InputStreamReader(i)) ;
+        pos = o ;
+
+        // Initialise the ScrollingTextArea.
+        // ScrollingTextArea sta = new ScrollingTextArea(pin, SCROLLBUFFERLINES, doc) ;
+        // sta.setFont(new Font("Courier", Font.PLAIN, 10)) ;
+        // sta.setFont(new Font("Monospaced", Font.PLAIN, 10)) ;
+        // System.out.println(sta.getFont()) ;
+
+        doc = new LimitedStyledDocument(SCROLLBUFFERLINES) ;
+        jtp = new JTextPane(doc) ;
+        jtp.setEditable(false) ;
+        attr = new SimpleAttributeSet() ;
+        StyleConstants.setFontFamily(attr, "Monospaced") ;
+        StyleConstants.setFontSize(attr, 10) ;
+        jtp.setBackground(Color.black) ;
+
+        doc.addDocumentListener(new DocumentListener() {
+            public void insertUpdate(DocumentEvent e) {
+                jtp.setCaretPosition(doc.getLength()) ;
+                // tf.requestFocus() ;
+                }
+            public void removeUpdate(DocumentEvent e) {
+                }
+            public void changedUpdate(DocumentEvent e) {
+                }
+            });
+
+        // Initialise the TextField for user input.
+        tf = new JTextField() ;
+        tf.setFont(new Font("Courier", Font.PLAIN, 10)) ;
+        Insets inset = tf.getMargin() ;
+        inset.top = inset.top + 1 ;
+        inset.bottom = inset.bottom + 1 ;
+        tf.setMargin(inset) ;
+        tf.setForeground(Color.white) ;
+        tf.setBackground(Color.black) ;
+
+        // Set the layout manager.
+        this.setLayout(new BorderLayout()) ;
+
+        // Scrollbars for scrolling text area.
+        // JScrollPane scrollpane = new JScrollPane(sta);
+        JScrollPane scrollpane = new JScrollPane(jtp);
+
+        // Add the bits to the panel.
+        this.add(scrollpane, BorderLayout.CENTER);
+        this.add(tf, BorderLayout.SOUTH);
+
+        // Initialise the command buffer.
+        cbuf = new CommandBuffer(CMDBUFFERLINES) ;
+
+        // Action listener stuff.
+        tf.addKeyListener(new KeyAdapter()
+            {
+            public void keyTyped(KeyEvent e)
+                {
+                // Enter key
+                if((e.getID() == KeyEvent.KEY_TYPED) && (e.getKeyChar() == KeyEvent.VK_ENTER))
+                    {
+                    // System.out.println("Enter Event") ;
+                    send(tf.getText() + '\n') ;
+                    cbuf.addCommand(tf.getText()) ;
+                    tf.setText("") ;
+                    }
+                }
+            public void keyPressed(KeyEvent e)
+                {
+                // UP Arrow
+                if((e.getID() == KeyEvent.KEY_PRESSED) && (e.getKeyCode() == KeyEvent.VK_UP))
+                    {
+                    // System.out.println("UP Event") ;
+                    tf.setText(cbuf.getPreviousCommand()) ;
+                    tf.setCaretPosition(tf.getText().length()) ;
+                    }
+                // DOWN Arrow
+                if((e.getID() == KeyEvent.KEY_PRESSED) && (e.getKeyCode() == KeyEvent.VK_DOWN))
+                    {
+                    // System.out.println("DOWN Event") ;
+                    tf.setText(cbuf.getNextCommand()) ;
+                    tf.setCaretPosition(tf.getText().length()) ;
+                    }
+                // Escape key
+                if((e.getID() == KeyEvent.KEY_PRESSED) && (e.getKeyCode() == KeyEvent.VK_ESCAPE))
+                    {
+                    // System.out.println("ESCAPE Event") ;
+                    tf.setText("") ;                                                                }
+                }
+            }) ;
+        // Add component listener to focus text field.
+        this.addComponentListener(new ComponentAdapter() {
+            public void componentShown(ComponentEvent e) {
+                tf.setVisible(true) ;
+                tf.requestFocus() ;
+                }
+            });
+        
+        // Init the scrolling thread.
+        t = new Thread(this, "Scrolling thread") ;
+        t.start() ;
+        } // End of init
+    /**
+     * getTabName - Get the name that this component should show on it's tab
+     * @returns String s - Tab name
+     **/
+    public String getTabName()
+        {                                                                               return NAME ;
+        }
+    /**
+     * getTabTip - Get the tip that this component should show on it's tab
+     * @returns String s - Tab tip
+     **/
+    public String getTabTip()
+        {
+        return TIP ;
+        }
+    /**
+     * getMenu - get the menu to add to the main menu bar.
+     * @returns JMenu
+     **/
+    public JMenu getMenu()
+        {
+        return null ;
+        }                                                                        
+    /**
+     * send - Helper function to send data out to the PipedOutputMUX
+     * @param String s - data to send.
+     **/
+    private void send(String s)
+        {
+        // System.out.println("Cluster: send got : " + s) ;
+        try
+            {
+            // Write the data to the stream.
+            for(int i=0;i<s.length();i++)
+                {
+                pos.write(s.charAt(i)) ;
+                }
+            }
+        catch(IOException ex)
+            {
+            System.out.println("Cluster: IOException on destination stream.") ;
+            System.out.println(ex) ;
+            }
+        }
+    /**
+     * Loop continually checking to see if anything has been written to the
+     * file that is being monitored.
+     */
+    public void run()
+        {
+        String output = new String() ;
+        // Loop continually reading from the input stream
+        while(true)                                                          
+            {
+            
+            try
+                {
+                //while(n >= 0)
+                //    {
+                //    n = pin.read(b);
+                //    if(n > 0)
+                //        {
+                //        output = new String(b, 0, n, encoding) ;
+                //        display(output) ;
+                //        // System.out.println("Read : " + output) ;
+                //        }
+                //    }
+                output = bir.readLine() ;
+                if(output != null) display(output) ;
+
+                if(DEBUG) System.out.println("After reading a line.") ;
+                }
+            catch(IOException ex)
+                {
+                System.out.println("ScrollingTextArea: IOException trying to read.") ;
+                }
+            } // End of infinate loop.
+        } // End of run.                                                        
+
+    private void display(String s)
+        {
+        // System.out.println(s) ;
+        // Ignore Ctrl-G.
+        // s = s.replace('\r', ' ') ;
+        s = s.replace('\a', ' ') ;                                              
+
+        attr = getAttributes(s) ;
+        doc.append(s + "\n", attr) ;
+        }
+
+    private SimpleAttributeSet getAttributes(String s)
+        {
+        SimpleAttributeSet sas = attr ;
+
+        /**
+         # 0 - $foreground, $background
+         # 1 - RED, $background
+         # 2 - BROWN, $background
+         # 3 - GREEN, $background
+         # 4 - CYAN, $background
+         # 5 - BLUE, $background
+         # 6 - MAGENTA, $background
+
+        VHF DX SPOT
+         [ '^DX de [\-A-Z0-9]+:\s+([57][01]\d\d\d\.|\d\d\d\d\d\d+.)', COLOR_PAIR(1) ],
+        PROMPT
+         [ '^G0VGS de GB7MBC', COLOR_PAIR(6) ],
+        DUNNO!
+         [ '^G0VGS de', A_BOLD|COLOR_PAIR(2) ],
+        HF DX SPOT
+         [ '^DX', COLOR_PAIR(5) ],
+        ANNOUNCE
+         [ '^To', COLOR_PAIR(3) ],
+        WWV SPOT
+         [ '^WWV', COLOR_PAIR(4) ],
+        DUNNO! 
+         [ '^[-A-Z0-9]+ de [-A-Z0-9]+ \d\d-\w\w\w-\d\d\d\d \d\d\d\dZ', COLOR_PAIR(0) ],
+        DUNNO! - PROBABLY A TALK
+         [ '^[-A-Z0-9]+ de [-A-Z0-9]+ ', COLOR_PAIR(6) ],
+        WX SPOT
+         [ '^WX', COLOR_PAIR(3) ],
+        NEW MAIL
+         [ '^New mail', A_BOLD|COLOR_PAIR(4) ],
+        USER LOGIN?
+         [ '^User', COLOR_PAIR(2) ],
+        NODE LOGIN?
+         [ '^Node', COLOR_PAIR(2) ],                                  
+         **/
+
+        Hashtable h = new Hashtable() ;
+        h.put("DX de", Color.red) ;
+        h.put("M0AZM de GB7MBC", Color.magenta) ;
+        h.put("G0VGS de GB7MBC", Color.magenta) ;
+        h.put("G0VGS2 de GB7MBC", Color.magenta) ;
+        // h.put("DX", Color.blue) ;
+        h.put("To", Color.green) ;
+        h.put("WWV", Color.cyan) ;
+        h.put("WCY", Color.cyan) ;
+        // h.put("", Color.) ;
+        // h.put("", Color.) ;
+        h.put("WX", Color.green) ;
+        h.put("New mail", Color.cyan) ;
+        //h.put("User", Color.brown) ;
+        //h.put("Node", Color.brown) ;
+        h.put("User", Color.yellow) ;
+        h.put("Node", Color.orange) ;
+        
+        Enumeration e = h.keys() ;
+        
+        while(e.hasMoreElements())
+            {
+            String prefix = (String)e.nextElement() ;
+            if(s.startsWith(prefix))
+                {
+                StyleConstants.setForeground(sas, (Color)h.get(prefix)) ;
+                return sas ;
+                }
+            }
+
+        StyleConstants.setForeground(sas, Color.white) ;
+        return sas ;
+        }
+    }
diff --git a/SpiderConsole/src/CommandBuffer.class b/SpiderConsole/src/CommandBuffer.class
new file mode 100644 (file)
index 0000000..9551161
Binary files /dev/null and b/SpiderConsole/src/CommandBuffer.class differ
diff --git a/SpiderConsole/src/CommandBuffer.java b/SpiderConsole/src/CommandBuffer.java
new file mode 100644 (file)
index 0000000..e8f4151
--- /dev/null
@@ -0,0 +1,110 @@
+/**
+ * Command Buffer for the cluster window of the spider GUI.
+ * @author Ian Norton
+ * @version 1.00 - 20010418.
+ *
+ * Copyright (C) 2001 Ian Norton.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public Licence as published by
+ * the Free Software Foundation; either version 2 of the Licence, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public Licence
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Contacting the author :
+ * Ian Norton
+ * i.norton@lancaster.ac.uk
+ * http://www.lancs.ac.uk/~norton/                                               **/
+
+import java.util.Vector ;
+
+class CommandBuffer
+    {
+    private int top, bottom, pointer, size ;
+    private Vector buffer ;
+    private boolean rolled ;
+
+    /**
+     * main - testing purposes only.
+     **/
+    public static void main(String[] args)
+        {
+        CommandBuffer c = new CommandBuffer(5) ;
+        c.addCommand("1") ;
+        System.out.println(c.getPreviousCommand()) ;
+        System.out.println(c.getNextCommand()) ;
+        }
+
+    /**
+     * CommandBuffer
+     * @param int - Number of lines of buffer.
+     **/
+     public CommandBuffer(int i)
+        {
+        // Size of the buffer.
+        size = i ;
+
+        // "Pointers"
+        bottom = 0 ;
+        pointer = 0 ;
+
+        top = size - 1 ;
+
+        // Vector that does that actual storage.
+        buffer = new Vector(size) ;
+        }
+
+    /**
+     * addCommand
+     * @param String - command to add to the buffer
+     **/
+    public void addCommand(String s)
+        {
+        // Is it an empty string
+        if(s.length() == 0) return ;
+        
+        // Add the command to the buffer
+        buffer.addElement(s) ;
+
+        // Check the buffer remains the correct size.
+        while(buffer.size() > size) buffer.removeElementAt(0) ;
+        
+        // Pointer to the last command
+        pointer = buffer.indexOf(s) ;
+        }
+
+    /**
+     * getPreviousCommand - get the previous command (recursive)
+     * @returns String - previous command
+     **/
+    public String getPreviousCommand()
+        {
+        String output = (String)buffer.elementAt(pointer) ;
+        if(pointer != 0) pointer-- ;
+        return output ;
+        }
+
+    /**
+     * getNextCommand - get the next command (recursive)
+     * @returns String - next command
+     **/
+    public String getNextCommand()
+        {
+        pointer++ ;
+        if(pointer == buffer.size())
+            {
+            pointer-- ;
+            return "" ;
+            }
+        String output = (String)buffer.elementAt(pointer) ;
+        return output ;
+        }
+    } // End of class.
diff --git a/SpiderConsole/src/Connection.class b/SpiderConsole/src/Connection.class
new file mode 100644 (file)
index 0000000..bb3c898
Binary files /dev/null and b/SpiderConsole/src/Connection.class differ
diff --git a/SpiderConsole/src/Connection.java b/SpiderConsole/src/Connection.java
new file mode 100644 (file)
index 0000000..8f183a3
--- /dev/null
@@ -0,0 +1,193 @@
+/**
+ * Ian's attempt at writing a socket module for the Spider GUI.
+ * @author Ian Norton
+ * @version 1.00 - 20010418.
+ *
+ * Copyright (C) 2001 Ian Norton.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public Licence as published by
+ * the Free Software Foundation; either version 2 of the Licence, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public Licence
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Contacting the author :
+ * Ian Norton
+ * i.norton@lancaster.ac.uk
+ * http://www.lancs.ac.uk/~norton/
+ **/
+
+import java.io.* ;
+import java.net.* ;
+
+public class Connection
+    {
+    // Host information.
+    private String host ;
+    private int port ;
+
+    // Socket.
+    private Socket socket ;
+    
+    // Socket input and output streams.
+    private InputStream is ;
+    private OutputStream os ;
+    
+    // Piped IO back up the chain.
+    private PipedInputStream pin ;
+    private PipedOutputStream pos ;
+
+    // IO readers.
+    private ConnectionInput conin ;
+    private ConnectionOutput conout ;
+
+    // Encoding String.
+    public static final String encoding = "latin1"; // "ISO8859_1";   
+
+    // Connection status.
+    private boolean disconnected ;
+
+    // Default port to use if one isn't specified.
+    // private static final int DEFAULTPORT = 8000 ; // Use this for user client
+    private static final int DEFAULTPORT = 27754 ;
+
+    /**
+     * Connection
+     * @param PipedInputStream - Stream to read from
+     * @param PipedOutputStream - Stream to send data to
+     * @param Console - Where to send status alerts to.
+     **/
+    public Connection(PipedInputStream i, PipedOutputStream o, Console c)
+        {
+        // Initialise the IO pipes.
+        pin = i ;
+        pos = o ;
+
+        // Yep, we're definately disconnected.
+        disconnected = false ;
+
+        // Initialise the Input and Output readers.
+        conin = new ConnectionInput(pos, this) ;
+        conout = new ConnectionOutput(pin, this) ;
+        }
+
+    /**
+     * connect
+     * @param String - host to connect to.  Port after a ':'.
+     **/
+    public void connect(String s)
+        {
+        // Has the socket been initialised?
+        if(socket != null)
+            disconnect() ;
+        
+        // Work out the hostname and port.
+        if(s.indexOf(":") > - 1)
+            {
+            try
+                {
+                port = Integer.valueOf(s.substring(s.indexOf(":") + 1, s.length())).intValue() ;
+                }
+            catch(NumberFormatException ex)
+                {
+                System.out.println("Number format exception - bad int in String.") ;
+                }
+
+            s = s.substring(0, s.indexOf(":")) ;
+            }
+        else
+            {
+            port = DEFAULTPORT ;
+            }
+
+        host = s ;
+
+        // Try and make the connection.
+        try
+            {
+            socket = new Socket(host, port) ;
+            }
+        catch(UnknownHostException ex)
+            {
+            System.out.println("Connection: UnknownHostException") ;
+            System.out.println(ex) ;
+            }
+        catch(IOException ex)
+            {
+            System.out.println("Connection: IOException") ;
+            System.out.println(ex) ;
+            }
+
+        // Get the streams from the connection.
+        try
+            {
+            is = socket.getInputStream() ;
+            os = socket.getOutputStream() ;
+            }
+        catch(IOException ex)
+            {
+            System.out.println("Connection: IOException getting the connection streams") ;
+            System.out.println(ex) ;
+            }
+
+        // Start the readers.
+        conin.start(is) ;
+        conout.start(os) ;
+
+        // Write a "Connected to " message to the multiplexor.
+        try
+            {
+            // Write disconnected to the PipedOutputStream.
+            String output = "\nConnected to " + host + ":" + port + "\n" ;
+            for(int i=0;i<output.length();i++)
+                {
+                pos.write(output.charAt(i)) ;
+                }
+            }
+        catch(IOException ex)
+            {
+
+            }
+            
+        disconnected = false ;
+        }
+
+    /**
+     * disconnect - disconnect the current connection.
+     **/
+    public void disconnect()
+        {
+        try
+            {
+            if(!disconnected)
+                {
+                disconnected = true ;
+                conin.disconnect() ;
+                conout.disconnect() ;
+
+                // Write disconnected to the PipedOutputStream.
+                String output = "\nDisconnected from " + host + ":" + port + "\n" ;
+                for(int i=0;i<output.length();i++)
+                    {
+                    pos.write(output.charAt(i)) ;
+                    }
+                }
+
+
+            if(socket != null) socket.close() ;
+            }
+        catch(IOException ex)
+            {
+            System.out.println("Connection: IOException closing socket") ;
+            System.out.println(ex) ;
+            }
+        }
+    } // End of class
diff --git a/SpiderConsole/src/ConnectionInput.class b/SpiderConsole/src/ConnectionInput.class
new file mode 100644 (file)
index 0000000..f82e6a2
Binary files /dev/null and b/SpiderConsole/src/ConnectionInput.class differ
diff --git a/SpiderConsole/src/ConnectionInput.java b/SpiderConsole/src/ConnectionInput.java
new file mode 100644 (file)
index 0000000..67f982c
--- /dev/null
@@ -0,0 +1,157 @@
+/**
+ * ConnectionInput - reads from the socket and writes data to the pipe.
+ * @author Ian Norton
+ * @version 1.00 - 20010418.
+ *
+ * Copyright (C) 2001 Ian Norton.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public Licence as published by
+ * the Free Software Foundation; either version 2 of the Licence, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public Licence
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Contacting the author :
+ * Ian Norton
+ * i.norton@lancaster.ac.uk
+ * http://www.lancs.ac.uk/~norton/
+ **/
+
+import java.io.* ;
+import java.net.* ;
+
+class ConnectionInput implements Runnable
+    {
+    // Debug me bugs
+    public static final boolean DEBUG = false ;
+    
+    // Data streams.
+    private InputStream is ;
+    private PipedOutputStream pos ;
+
+    // Connection object that created us.
+    private Connection connection ;
+
+    // Connection status.
+    private boolean disconnected ;
+    
+    // Thread to run the read code in.
+    private Thread t ;
+
+    // Encoding string.
+    public static final String encoding = "latin1"; // "ISO8859_1";   
+
+    /**
+     * ConnectionInput
+     * @param InputStream - InputStream from the socket to read from
+     * @param PipedOutputStream - Write the data out to here
+     * @param Connection - the object that created us
+     **/
+    public ConnectionInput(PipedOutputStream p, Connection c)
+        {
+        // Initialise the streams & connection
+        pos = p ;
+        connection = c ;
+
+        disconnected = true ;
+        }
+
+    /**
+     * disconnect - disconnect the current connection.
+     **/
+    public void disconnect()
+        {
+        if(!disconnected)
+            {
+            if(DEBUG) System.out.println("ConnectionInput: disconnect()") ;
+
+            try { pos.flush() ; }
+            catch(IOException ex) { }
+
+            disconnected = true ;
+            connection.disconnect() ;
+            }
+        }
+
+    /**
+     * start - begin reading.  Called when a connect has been achieved.
+     **/
+    public void start(InputStream i)
+        {
+        is = i ;
+
+        disconnected = false ;
+
+        // Initialise the thread to read data & start it.
+        t = new Thread(this, "ConnectionInput") ;
+        t.start() ;
+        }
+
+    /**
+     * Thread run method.
+     **/
+    public void run()
+        {
+        byte[] b = new byte[16];   
+
+        // Loop reading data.
+        while(!disconnected)
+            {
+            try
+                {
+                // Read from InputStream and write to PipedOutputStream
+                int n = 0;
+
+                n = is.read(b) ;
+                if(n > 0)
+                    {
+                    String output = new String(b, 0, n, encoding) ;
+                    send(output) ;
+                    }                                                   
+                else if(n == -1)
+                    {
+                    this.disconnect() ;
+                    }
+                }
+            catch(IOException ex)
+                {
+                if(disconnected)
+                    return ;
+
+                System.out.println("ConnectionInput: IOException reading data.") ;
+                this.disconnect() ;
+                }
+            } // End while(true)
+        } // End run()
+
+    /**
+     * send
+     * @param String s - string to send to destination stream.
+     **/
+    private void send(String s)
+        {
+        try
+            {
+            // Write the data to the stream.
+            for(int i=0;i<s.length();i++)
+                {
+                pos.write(s.charAt(i)) ;
+                pos.flush() ;
+                }
+            }
+        catch(IOException ex)
+            {
+            System.out.println("ConnectionInput:  IOException writing to multiplexor.") ;
+            System.exit(1) ;
+            }
+        } // End of send(String s)
+    } // End class
+
diff --git a/SpiderConsole/src/ConnectionOutput.class b/SpiderConsole/src/ConnectionOutput.class
new file mode 100644 (file)
index 0000000..3e5babc
Binary files /dev/null and b/SpiderConsole/src/ConnectionOutput.class differ
diff --git a/SpiderConsole/src/ConnectionOutput.java b/SpiderConsole/src/ConnectionOutput.java
new file mode 100644 (file)
index 0000000..fcf4f0d
--- /dev/null
@@ -0,0 +1,157 @@
+/**
+ * ConnectionOutput - reads from the pipe and writes data to the socket.
+ * @author Ian Norton
+ * @version 1.00 - 20010418.
+ *
+ * Copyright (C) 2001 Ian Norton.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public Licence as published by
+ * the Free Software Foundation; either version 2 of the Licence, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public Licence
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Contacting the author :
+ * Ian Norton
+ * i.norton@lancaster.ac.uk
+ * http://www.lancs.ac.uk/~norton/
+ **/
+
+import java.io.* ;
+import java.net.* ;
+
+class ConnectionOutput implements Runnable
+    {
+    // Debug me bugs
+    public static final boolean DEBUG = false ;
+    
+    // Data streams.
+    private OutputStream os ;
+    private PipedInputStream pin ;
+
+    // Connection object that created us.
+    private Connection connection ;
+
+    // Connection status.
+    private boolean disconnected ;
+    
+    // Thread to run the read code in.
+    private Thread t ;
+
+    // Encoding string.
+    public static final String encoding = "latin1"; // "ISO8859_1";   
+
+    /**
+     * ConnectionOutput
+     * @param OutputStream - OutputStream to the socket to write to
+     * @param PipedInputStream - Read data from here
+     * @param Connection - the object that created us                           
+     **/
+    public ConnectionOutput(PipedInputStream p, Connection c)
+        {
+        // Initialise the streams & connection
+        pin = p ;
+        connection = c ;
+
+        disconnected = true ;
+        }
+
+    /**
+     * disconnect - disconnect the current connection.
+     **/                                                                        
+    public void disconnect()
+        {
+        if(!disconnected)
+            {
+            if(DEBUG) System.out.println("ConnectionOutput: disconnect()") ;
+
+            disconnected = true ;
+            connection.disconnect() ;
+            }
+        }
+
+    /**
+     * start - begin reading.  Called when a connect has been achieved.
+     **/
+    public void start(OutputStream o)
+        {
+        os = o ;
+
+        disconnected = false ;
+
+        // Test to see if the thread has been inititialised.
+        if(t == null) ;
+            {
+            if(DEBUG) System.out.println("ConnectionOutput: Creating thread.") ;
+
+            // Initialise the thread to read data & start it.
+            t = new Thread(this, "Connection") ;
+            t.start() ;
+            }
+        }
+
+    /**
+     * Thread run method.
+     **/
+    public void run()
+        {
+        byte[] b = new byte[16];
+
+        // Loop reading data.
+        while(true)
+            {
+            try
+                {
+                // Read from PipedInputStream and write to OutputStream
+                int n = 0;
+
+                // Read that many bytes and return.
+                n = pin.read(b);
+
+                // If disconnected read and disguard data or the MUX dies.
+                if(n > 0 && !disconnected)
+                    {
+                    String output = new String(b, 0, n, encoding) ;
+                    send(output) ;
+                    }                                                   
+                }
+            catch(IOException ex)
+                {
+                System.out.println("ConnectionOutput: IOException reading data from multiplexor.") ;
+                System.exit(1) ;
+                }
+            } // End while(true)
+        } // End run()
+
+    /**
+     * send
+     * @param String s - string to send to destination stream.
+     **/
+    private void send(String s)
+        {
+        if(DEBUG) System.out.println("ConnectionOutput: Send called : " + s) ;
+        try
+            {
+            // Write the data to the stream.
+            for(int i=0;i<s.length();i++)
+                {
+                os.write(s.charAt(i)) ;
+                os.flush() ;
+                }
+            }
+        catch(IOException ex)
+            {
+            System.out.println("ConnectionOutput:  IOException writing to socket.") ;
+            System.exit(1) ;
+            }                                                                   
+        }
+    } // End class
+
diff --git a/SpiderConsole/src/Console$1.class b/SpiderConsole/src/Console$1.class
new file mode 100644 (file)
index 0000000..2067e83
Binary files /dev/null and b/SpiderConsole/src/Console$1.class differ
diff --git a/SpiderConsole/src/Console$2.class b/SpiderConsole/src/Console$2.class
new file mode 100644 (file)
index 0000000..64f3d3a
Binary files /dev/null and b/SpiderConsole/src/Console$2.class differ
diff --git a/SpiderConsole/src/Console$3.class b/SpiderConsole/src/Console$3.class
new file mode 100644 (file)
index 0000000..86851a7
Binary files /dev/null and b/SpiderConsole/src/Console$3.class differ
diff --git a/SpiderConsole/src/Console$4.class b/SpiderConsole/src/Console$4.class
new file mode 100644 (file)
index 0000000..f01cfc6
Binary files /dev/null and b/SpiderConsole/src/Console$4.class differ
diff --git a/SpiderConsole/src/Console$5.class b/SpiderConsole/src/Console$5.class
new file mode 100644 (file)
index 0000000..78c1313
Binary files /dev/null and b/SpiderConsole/src/Console$5.class differ
diff --git a/SpiderConsole/src/Console$6.class b/SpiderConsole/src/Console$6.class
new file mode 100644 (file)
index 0000000..bac922a
Binary files /dev/null and b/SpiderConsole/src/Console$6.class differ
diff --git a/SpiderConsole/src/Console.class b/SpiderConsole/src/Console.class
new file mode 100644 (file)
index 0000000..4d3f32f
Binary files /dev/null and b/SpiderConsole/src/Console.class differ
diff --git a/SpiderConsole/src/Console.java b/SpiderConsole/src/Console.java
new file mode 100755 (executable)
index 0000000..587fe26
--- /dev/null
@@ -0,0 +1,303 @@
+/**
+ * Console - modular Amateur Radio console for clusters and converse.
+ * @author Ian Norton
+ * @version 1.00 - 20010418.
+ *
+ * Copyright (C) 2001 Ian Norton.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public Licence as published by
+ * the Free Software Foundation; either version 2 of the Licence, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public Licence
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Contacting the author :
+ * Ian Norton
+ * i.norton@lancaster.ac.uk
+ * http://www.lancs.ac.uk/~norton/
+ **/
+
+import javax.swing.*;
+import java.awt.*;
+import java.awt.event.*;
+import java.util.*;
+import java.io.*;
+
+public class Console
+    {
+    private JFrame frame ;
+    private JPanel buttonpanel ;
+    private JTabbedPane tabbedpane ;
+
+    // Static variables.
+    public static final int WIDTH  = 620 ;
+    public static final int HEIGHT = 350 ;
+    public static final String VERSION = "1.0" ;
+    public static final String INFO = "RadioConsole Version " + VERSION +
+                                      "\nWritten By Ian Norton (M0AZM)\n" +
+                                      "i.norton@lancaster.ac.uk" ;
+
+    // IO Multiplexors
+    private PipedInputMUX inmux ;
+    private PipedOutputMUX outmux ;
+    
+    // Vector to store plugins
+    private Vector plugins ;
+
+    private int plugnumber ;
+
+    // Connection object.
+    private Connection connection ;
+
+    // Host that we connected to (May include port number).
+    private String host ;
+
+    /**
+     * main
+     **/
+    public static void main(String[] args)
+        {
+        // Start the console.
+        Console c = new Console("DX Cluster Console " + VERSION) ;
+        }
+
+    /**
+     * Console init method.
+     * @param String title
+     **/
+    public Console(String s)
+        {
+        // Default host and port to connect to.
+        host = "127.0.0.1:27754" ;
+
+        // Initialise the frame for the whole thing.
+        frame = new JFrame(s) ;
+
+        // Build connection here.
+        PipedInputStream pincon = new PipedInputStream() ;
+        PipedOutputStream poscon = new PipedOutputStream() ;
+        connection = new Connection(pincon, poscon, this) ;
+
+        // Build protocol here.
+        /**
+        PipedInputStream pinprot ;
+        PipedOutputStream posprot ;
+        try
+            {
+            pinprot = new PipedInputStream(poscon) ;
+            posprot = new PipedOutputStream(pincon) ;
+            Protocol protocol = new Protocol(pinprot, posprot, this) ;
+            }
+        catch(IOException ex)
+            {
+            System.out.println("Console: IOException creating protocol.") ;
+            System.exit(1) ;
+            }
+        **/
+        
+        // Build input/output MUX's here.
+        PipedInputStream pinmux ;
+        PipedOutputStream posmux ;
+
+        try
+            {
+            // Initialise pipes.
+            pinmux = new PipedInputStream(poscon) ;
+            posmux = new PipedOutputStream(pincon) ;
+
+            // Initialise the MUX's
+            inmux = new PipedInputMUX(posmux) ;
+            outmux = new PipedOutputMUX(pinmux) ;
+            }
+        catch(IOException ex)
+            {
+            System.out.println("Console: IOException creating MUXes.") ;
+            System.out.println(ex) ;
+            System.exit(1) ;
+            }
+
+        // Initialise the plugin stuff.
+        plugins = new Vector() ;
+        plugnumber = 0 ;
+        
+        // Build tabbed panes from the plugins.
+        buildTabs() ;
+
+        // Build menu bars.
+        buildMenus() ;
+
+        // Build the button bar.
+        // buildToolbar() ;
+
+        // Add action listener to close the window.
+        frame.addWindowListener(new WindowAdapter() {
+            public void windowClosing(WindowEvent e) {
+            System.exit(0) ; }
+            });
+
+        // Set initial size.
+        frame.setSize(WIDTH, HEIGHT) ;
+                                                                                
+        frame.getContentPane().add(tabbedpane, BorderLayout.CENTER);
+        frame.show();
+
+        // Pop a connection dialog or use saved hostname or something here.
+        connection.connect(host) ;
+        }
+
+    /**
+     * buildTabs - build the tabbed panes with the plugins.
+     **/
+    public void buildTabs()
+        {
+        tabbedpane = new JTabbedPane() ;
+        tabbedpane.setTabPlacement(JTabbedPane.BOTTOM);
+
+        // The first plugin should always be the cluster plugin.
+        // addPlugin("Cluster") ;
+        addPlugin("SpiderCluster") ;
+        
+        // Call insert plugins method here. **AZM**
+
+        }
+
+    /**
+     * buildMenus - build the Menus with the plugins.
+     **/
+    public void buildMenus()
+        {
+        // Create a menu bar and add it to the frame.
+        JMenuBar mbar = new JMenuBar() ;
+        frame.setJMenuBar(mbar) ;
+        // Create the file menu stuff.
+        JMenu filemenu = new JMenu("File") ;
+
+        JMenuItem item ;
+        filemenu.add(item = new JMenuItem("Connect")) ;
+        item.setMnemonic(KeyEvent.VK_C) ;
+        item.setAccelerator(KeyStroke.getKeyStroke(
+                KeyEvent.VK_C, ActionEvent.ALT_MASK));
+        item.addActionListener(new ActionListener() { 
+        public void actionPerformed(ActionEvent e) { 
+                connection.connect(host);
+        }});
+
+        filemenu.add(item = new JMenuItem("Connect To")) ;
+        // item.setMnemonic(KeyEvent.VK_C) ;
+        // item.setAccelerator(KeyStroke.getKeyStroke(
+        //           KeyEvent.VK_C, ActionEvent.ALT_MASK));
+        item.addActionListener(new ActionListener() { 
+        public void actionPerformed(ActionEvent e) { 
+            // Connection dialog.
+            String ho = JOptionPane.showInputDialog("Enter the host to connect to") ;
+            if(ho == null || ho.indexOf(" ") > -1)
+                return ;
+
+            if(ho != null && ho.length() > 0)
+                {
+                // connection.disconnect() ;
+                connection.connect(ho);
+                }
+        }});
+
+        filemenu.add(item = new JMenuItem("Disconnect")) ;
+        item.addActionListener(new ActionListener() {
+        public void actionPerformed(ActionEvent e) 
+            { connection.disconnect() ; }});
+
+        filemenu.add(item = new JMenuItem("About")) ;
+        item.addActionListener(new ActionListener() {
+        public void actionPerformed(ActionEvent e) 
+            { JOptionPane.showMessageDialog(frame, INFO) ; }});
+
+        filemenu.addSeparator() ;
+
+        filemenu.add(item = new JMenuItem("Quit")) ;
+        item.addActionListener(new ActionListener() { // Quit.
+        public void actionPerformed(ActionEvent e) { System.exit(0) ; }});
+
+        // Add the menus onto the menu bar.
+        mbar.add(filemenu) ;
+        }
+
+    /**
+     * buildToolbar - build the Toolbar with the plugins.
+     **/
+    public void buildToolbar()
+        {
+        
+        }
+
+    /**
+     * addPlugin
+     * @param String - name of the plugin to insert.
+     **/
+    private void addPlugin(String p)
+        {
+        Plugin pl = null ;
+        
+        try
+            {
+            Class c = Class.forName(p) ;
+            pl = (Plugin)c.newInstance();
+            }
+        catch(ClassNotFoundException ex)
+            {
+            System.out.println("Exceptional!\n"+ex) ;
+            }
+        catch(InstantiationException ex)
+            {
+            System.out.println("Exceptional!\n"+ex) ;
+            }
+        catch(IllegalAccessException ex)
+            {
+            System.out.println("Exceptional!\n"+ex) ;
+            }
+
+        PipedOutputStream plugoutstr = new PipedOutputStream() ;
+        PipedInputStream pluginstr = new PipedInputStream() ;
+
+        // Insert the object into the vector.
+        plugins.addElement(pl) ;
+
+        // Add the plug in to the tabbedpane.
+        tabbedpane.addTab(pl.getTabName(), null, pl, pl.getTabTip()) ;
+
+        PipedInputStream pinmux = null ;
+        PipedOutputStream posmux = null ;
+
+        try
+            {
+            pinmux = new PipedInputStream(plugoutstr) ;
+            posmux = new PipedOutputStream(pluginstr) ;
+            }
+        catch(IOException ex)
+            {
+            System.out.println("Console: IOException creating plugin pipes.") ;
+            System.out.println(ex) ;
+            }
+
+        // Add the streams to the multiplexors.
+        inmux.addInputStream(pinmux) ;
+        outmux.addOutputStream(posmux) ;
+
+        // Initialise the plugin.
+        pl.init(pluginstr, plugoutstr) ;
+
+        plugnumber++ ;
+
+        // Menus?
+
+        // Toolbars?
+        }
+    }
+
diff --git a/SpiderConsole/src/LimitedStyledDocument.class b/SpiderConsole/src/LimitedStyledDocument.class
new file mode 100644 (file)
index 0000000..689deec
Binary files /dev/null and b/SpiderConsole/src/LimitedStyledDocument.class differ
diff --git a/SpiderConsole/src/LimitedStyledDocument.java b/SpiderConsole/src/LimitedStyledDocument.java
new file mode 100644 (file)
index 0000000..79aca45
--- /dev/null
@@ -0,0 +1,100 @@
+/**
+ * LimitedStyledDocument
+ * @author Ian Norton
+ * @version 1.0 20010418.
+ *
+ * Copyright (C) 2001 Ian Norton.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public Licence as published by
+ * the Free Software Foundation; either version 2 of the Licence, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public Licence
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Contacting the author :
+ * Ian Norton
+ * i.norton@lancaster.ac.uk
+ * http://www.lancs.ac.uk/~norton/
+ **/
+
+import java.awt.* ;
+import javax.swing.*; 
+import javax.swing.text.*; 
+import java.awt.Toolkit;
+import java.util.* ;
+
+public class LimitedStyledDocument extends DefaultStyledDocument 
+    {
+    int scrollbufferlines ;
+    SimpleAttributeSet attr ;
+    int num ;
+
+    public LimitedStyledDocument(int i) 
+        {
+        scrollbufferlines = i ;
+        attr = new SimpleAttributeSet() ;
+        num = 0 ;
+        }
+
+    /**
+     * append - append a string to the end of the document keeping the
+     *          number of lines in the document at or below maxscrollbuffer.
+     * @param String s - String to append.
+     * @param AttributeSet a - Attributes of the string to append.
+     **/
+    public void append(String s, AttributeSet a)
+        {
+        // Try and append the string to the document.
+        try
+            {
+            super.insertString(super.getLength(), s, a) ;
+            }
+        catch(BadLocationException ex)
+            {
+            }
+
+        StringTokenizer st = null ;
+
+        // Split the document into tokens delimited by '\n'.
+        try
+            {
+            // Need to do clever stuff here to chop the top off the buffer.
+            st = new StringTokenizer(super.getText(0, super.getLength()), "\n") ;
+            }
+        catch(BadLocationException ex)
+            {
+            }
+        int i = 0;
+
+        // Are there more lines than there should be?
+        if(st.countTokens() > scrollbufferlines)
+            {
+            // How many lines too many?
+            i = st.countTokens() - scrollbufferlines ;
+            }
+        // For each line too many
+        for(;i>0;i--)
+            {
+            String tmp = st.nextToken() ;
+
+            try
+                {
+                // Remove the line.
+                super.remove(0, super.getText(0, super.getLength()).indexOf(tmp) + tmp.length()) ;
+                }
+            catch(BadLocationException ex)
+                {
+                }
+            } // End of for(;i>0;i--)
+        } // End of append
+    } // End of class.
diff --git a/SpiderConsole/src/PipedInputMUX.class b/SpiderConsole/src/PipedInputMUX.class
new file mode 100644 (file)
index 0000000..4d0d553
Binary files /dev/null and b/SpiderConsole/src/PipedInputMUX.class differ
diff --git a/SpiderConsole/src/PipedInputMUX.java b/SpiderConsole/src/PipedInputMUX.java
new file mode 100644 (file)
index 0000000..0fa0d60
--- /dev/null
@@ -0,0 +1,145 @@
+/**
+ * InputStreamMultiplexor 
+ * This takes multiple input streams and sends them to one input stream.
+ * @author Ian Norton
+ * @version 1.00 - 20010418.
+ *
+ * Copyright (C) 2001 Ian Norton.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public Licence as published by
+ * the Free Software Foundation; either version 2 of the Licence, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public Licence
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Contacting the author :
+ * Ian Norton
+ * i.norton@lancaster.ac.uk
+ * http://www.lancs.ac.uk/~norton/
+ **/
+
+import java.io.* ;
+import java.util.Vector ;
+import java.util.Enumeration ;
+import java.util.Calendar ;
+
+class PipedInputMUX implements Runnable
+    {
+    public static final boolean DEBUG = false ;
+    public static final String encoding = "latin1"; // "ISO8859_1";
+
+    private PipedOutputStream pos ;
+    private Vector streams ;
+
+    private Thread t ;
+    
+    /**
+     * PipedInputMUX initialiser.
+     * @param PipedOutputStream - target stream.
+     **/
+    public PipedInputMUX(PipedOutputStream o)
+        {
+        pos = o ;
+
+        // Streams Vector holds all the InputStreams we know about.
+        streams = new Vector() ;
+
+        // Initialise and start the thread.
+        t = new Thread(this, "InputMultiplexor") ;
+        t.start() ;
+        }
+
+    /**
+     * addInputStream
+     * @param PipedInputStream pi - add a stream get input from.
+     **/
+    public void addInputStream(PipedInputStream pi)
+        {
+        // Add the supplied stream to the vector of streams.
+        streams.addElement(pi) ;
+        }
+
+    /**
+     * run - Thread run method.
+     **/
+    public void run()
+        {
+        // Loop continually reading from the input streams
+        while(true)
+            {
+            // Enumeration thing here.
+            Enumeration e = streams.elements() ;
+            byte[] b = new byte[16];
+
+            while(e.hasMoreElements())
+                {
+                PipedInputStream is = (PipedInputStream)e.nextElement() ;
+                
+                try
+                    {
+                    // Read a line and see if it has any data in it.
+                    int n = 0;
+
+                    // While there is non-blocking data available to read
+                    while(is.available() > 0)
+                        {
+                        // find out how many bytes we can read without blocking
+                        int rdb = is.available() ;
+                        if(rdb > 16) rdb = 16 ;
+                        
+                        // Read that many bytes and return.
+                        n = is.read(b, 0, rdb);
+                        if(n > 0)
+                            {
+                            String output = new String(b, 0, n, encoding) ;
+                            send(output) ;
+                            }
+                        }
+     
+                    if(DEBUG) System.out.println("After reading a line.") ;
+                    }
+                catch(IOException ex)
+                    {
+                    // If we get an IO exception, then the other end of the pipe
+                    // has been closed.  We need to remove this stream.
+                    streams.removeElement(is) ;
+                    System.out.println("IOException - stream removed.") ;
+                    }
+                                                                                
+                } // End of while(e.hasMoreElements())
+            } // End of while(true)
+        } // End of run()
+
+    /**
+     * send
+     * @param String s - string to send to destination stream.
+     **/
+    private void send(String s)
+        {
+        // Calendar cal = Calendar.getInstance() ;
+        // if(DEBUG) System.out.println("PipedInputMUX: " + cal.getTime() + " Send called with : " + s) ;
+
+        try
+            {
+            // Write the data to the stream.
+            for(int i=0;i<s.length();i++)
+                {
+                pos.write(s.charAt(i)) ;
+                pos.flush() ;
+                }
+            }
+        catch(IOException ex)
+            {
+            System.out.println("PipedInputMUX: IOException on destination stream.") ;
+            }
+        }
+    } // End of class.
diff --git a/SpiderConsole/src/PipedOutputMUX.class b/SpiderConsole/src/PipedOutputMUX.class
new file mode 100644 (file)
index 0000000..798fa30
Binary files /dev/null and b/SpiderConsole/src/PipedOutputMUX.class differ
diff --git a/SpiderConsole/src/PipedOutputMUX.java b/SpiderConsole/src/PipedOutputMUX.java
new file mode 100644 (file)
index 0000000..9bb2c14
--- /dev/null
@@ -0,0 +1,148 @@
+/**
+ * OutputStreamMultiplexor 
+ * Takes one output stream and sends it to multiple output streams.
+ * @author Ian Norton
+ * @version 1.0 - 20010418.
+ *
+ * Copyright (C) 2001 Ian Norton.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public Licence as published by
+ * the Free Software Foundation; either version 2 of the Licence, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public Licence
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Contacting the author :
+ * Ian Norton
+ * i.norton@lancaster.ac.uk
+ * http://www.lancs.ac.uk/~norton/
+ **/
+
+import java.io.* ;
+import java.util.Vector ;
+import java.util.Enumeration ;
+import java.util.Calendar ;
+
+class PipedOutputMUX implements Runnable
+    {
+    public static final boolean DEBUG = false ;
+    public static final String encoding = "latin1"; // "ISO8859_1";
+    
+    private PipedInputStream pin ;
+    private Vector streams ;
+
+    private Thread t ;
+    
+    /**
+     * PipedOutputMUX initialiser
+     * @param PipedOutputStream i - Source stream
+     **/
+    public PipedOutputMUX(PipedInputStream i)
+        {
+        pin = i ;
+         
+        // Streams Vector holds all the OutputStreams we know about.
+        streams = new Vector() ;
+
+        // Initialise and start the thread.
+        t = new Thread(this, "OutputMultiplexor") ;
+        t.start() ;
+        }
+
+    /**
+     * addOutputStream
+     * @param PipedOutputStream po - add a stream to send output to.
+     **/
+    public void addOutputStream(PipedOutputStream po)
+        {
+        // Add the supplied stream to the vector of streams.
+        streams.addElement(po) ;
+        }
+
+    /**
+     * run - Thread run method.
+     **/
+    public void run()
+        {
+        // Loop continually reading the input stream.
+        while(true)
+            {
+            try
+                {
+                byte[] b = new byte[16];
+
+                // Read a line and see if it has any data in it.
+                int n = 0;
+
+                // Trying to read
+                while(pin.available() > 0)
+                    {
+                    int rdb = pin.available() ;
+                    if(rdb > 16) rdb = 16 ;
+                    n = pin.read(b, 0, rdb);
+
+                    if(n > 0)
+                        {
+                        // Convert the output to a string and send it.
+                        String output = new String(b, 0, n, encoding) ;
+                        if(DEBUG) System.out.println(output) ;
+                        send(output) ;
+                        }
+                    }
+                }
+            catch(IOException ex)
+                {
+                System.out.println("PipedOutputMUX: IOException trying to read.") ;
+                System.exit(1) ;
+                }
+            } // End of loop
+        } // End of run()
+
+    /**
+     * send
+     * @param String s - string to send to all streams.
+     **/
+    private void send(String s)
+        {
+        // Calendar cal = Calendar.getInstance() ;
+        // if(DEBUG) System.out.println("PipedOutputMUX: " + cal.getTime() + " Send called with :" + s) ;
+
+        // If we have no streams, then we can't do anything.
+        if(streams.size() == 0) return ;
+        
+        // Create Enumeration object to enumerate with :-)
+        Enumeration e = streams.elements() ;
+
+        // Go through the enumeration and send the string to each stream.
+        while(e.hasMoreElements())
+            {
+            PipedOutputStream os = (PipedOutputStream)e.nextElement() ;
+
+            try
+                {
+                // Write the data to the stream.
+                for(int i=0;i<s.length();i++)
+                    {
+                    os.write(s.charAt(i)) ;
+                    os.flush() ;
+                    }
+                }
+            catch(IOException ex)
+                {
+                // If we get an IO exception, then the other end of the pipe
+                // has been closed.  We need to remove this stream.
+                streams.removeElement(os) ;
+                System.out.println("IOException - stream removed.") ;
+                }
+            }
+        }
+
+    } // End of class.
diff --git a/SpiderConsole/src/Plugin.class b/SpiderConsole/src/Plugin.class
new file mode 100644 (file)
index 0000000..3b9aa25
Binary files /dev/null and b/SpiderConsole/src/Plugin.class differ
diff --git a/SpiderConsole/src/Plugin.java b/SpiderConsole/src/Plugin.java
new file mode 100644 (file)
index 0000000..7d991ac
--- /dev/null
@@ -0,0 +1,39 @@
+/**
+ * Plugin - abstract plugin class.
+ * We need this so that when we compile Console, it knows what methods to
+ * expect in plugin modules.  If we don't use this it will complain.
+ * Any methods added to plugins need to be added to ALL plugins and here.
+ * @author Ian Norton
+ * @version 1.0 - 20010418.
+ *
+ * Copyright (C) 2001 Ian Norton.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public Licence as published by
+ * the Free Software Foundation; either version 2 of the Licence, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public Licence
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Contacting the author :
+ * Ian Norton
+ * i.norton@lancaster.ac.uk
+ * http://www.lancs.ac.uk/~norton/                                              
+ **/
+
+import javax.swing.*;
+import java.io.PipedInputStream ;
+import java.io.PipedOutputStream ;
+
+public abstract class Plugin extends JPanel{
+    public abstract void init(PipedInputStream i, PipedOutputStream o) ;
+    public abstract String getTabName() ;
+    public abstract String getTabTip() ;
+    }
diff --git a/SpiderConsole/src/SpiderCluster$1.class b/SpiderConsole/src/SpiderCluster$1.class
new file mode 100644 (file)
index 0000000..5a96e1f
Binary files /dev/null and b/SpiderConsole/src/SpiderCluster$1.class differ
diff --git a/SpiderConsole/src/SpiderCluster$2.class b/SpiderConsole/src/SpiderCluster$2.class
new file mode 100644 (file)
index 0000000..3b2d081
Binary files /dev/null and b/SpiderConsole/src/SpiderCluster$2.class differ
diff --git a/SpiderConsole/src/SpiderCluster$3.class b/SpiderConsole/src/SpiderCluster$3.class
new file mode 100644 (file)
index 0000000..86462e5
Binary files /dev/null and b/SpiderConsole/src/SpiderCluster$3.class differ
diff --git a/SpiderConsole/src/SpiderCluster.class b/SpiderConsole/src/SpiderCluster.class
new file mode 100644 (file)
index 0000000..60e1e7e
Binary files /dev/null and b/SpiderConsole/src/SpiderCluster.class differ
diff --git a/SpiderConsole/src/SpiderCluster.java b/SpiderConsole/src/SpiderCluster.java
new file mode 100644 (file)
index 0000000..d046687
--- /dev/null
@@ -0,0 +1,375 @@
+/**
+ * SpiderCluster - SpiderCluster console plugin.
+ * @author Ian Norton
+ * @verison 1.0 - 20010418.
+ * @see JPanel
+ *
+ * Copyright (C) 2001 Ian Norton.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public Licence as published by
+ * the Free Software Foundation; either version 2 of the Licence, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public Licence for more details.
+ *
+ * You should have received a copy of the GNU General Public Licence
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Contacting the author :
+ * Ian Norton
+ * i.norton@lancaster.ac.uk
+ * http://www.lancs.ac.uk/~norton/
+ **/
+
+import javax.swing.*;
+import javax.swing.text.*;
+import javax.swing.event.*;
+import java.awt.*;
+import java.io.*;
+import java.awt.event.*;
+import java.util.Hashtable ;
+import java.util.Enumeration ;
+
+// public class Cluster extends Plugin implements Runnable
+class SpiderCluster extends Plugin implements Runnable
+    {
+    // Name and tip used when creating the tabbed pane.
+    public static final String NAME = "SpiderCluster" ;   
+    public static final String TIP = "Spider DX Cluster Console" ;   
+    
+    // Number of commands to buffer.
+    public static final int CMDBUFFERLINES = 30 ;
+
+    // Number of lines of scrollback to buffer.
+    public static final int SCROLLBUFFERLINES = 100 ;
+
+    public static final boolean DEBUG = false ;
+
+    // Input and output streams for the plugin.
+    private BufferedReader bir ;
+    private PipedOutputStream pos ;
+
+    // User input field.
+    private JTextField tf ;
+
+    private JTextPane jtp ;
+    private Thread t ;
+    private SimpleAttributeSet attr ;
+    private LimitedStyledDocument doc ;
+
+    // Input line scrollback buffer.
+    private CommandBuffer cbuf ;
+
+    // Callsign of the connecting user.
+    private String call ;
+
+    private static final String encoding = "latin1"; // "ISO8859_1";
+
+    /**
+     * Class initialiser.
+     **/
+    public SpiderCluster()
+        {
+        super() ;
+        }   
+
+    /**
+     * Plugin initialiser.
+     * @param PipedInputStream i - Stream to read data from
+     * @param PipedOutputStream o - Stream to write data to
+     **/
+    public void init(PipedInputStream i, PipedOutputStream o)
+        {
+        // Initialise the plugin IO.
+        bir = new BufferedReader(new InputStreamReader(i)) ;
+        pos = o ;
+
+        // Initialise the Scrolling output area.
+        doc = new LimitedStyledDocument(SCROLLBUFFERLINES) ;
+        jtp = new JTextPane(doc) ;
+        jtp.setEditable(false) ;
+        attr = new SimpleAttributeSet() ;
+        StyleConstants.setFontFamily(attr, "Monospaced") ;
+        StyleConstants.setFontSize(attr, 10) ;
+        jtp.setBackground(Color.black) ;
+
+        doc.addDocumentListener(new DocumentListener() {
+            public void insertUpdate(DocumentEvent e) {
+                jtp.setCaretPosition(doc.getLength()) ;
+                }
+            public void removeUpdate(DocumentEvent e) { }
+            public void changedUpdate(DocumentEvent e) { }
+            });
+
+        // Initialise the TextField for user input.
+        tf = new JTextField() ;
+        tf.setFont(new Font("Courier", Font.PLAIN, 10)) ;
+        Insets inset = tf.getMargin() ;
+        inset.top = inset.top + 1 ;
+        inset.bottom = inset.bottom + 1 ;
+        tf.setMargin(inset) ;
+        tf.setForeground(Color.white) ;
+        tf.setBackground(Color.black) ;
+        tf.setCaretColor(Color.white) ;
+    
+        // Set the layout manager.
+        this.setLayout(new BorderLayout()) ;
+
+        // Scrollbars for scrolling text area.
+        JScrollPane scrollpane = new JScrollPane(jtp);
+
+        // Add the bits to the panel.
+        this.add(scrollpane, BorderLayout.CENTER);
+        this.add(tf, BorderLayout.SOUTH);
+
+        // Initialise the command buffer.
+        cbuf = new CommandBuffer(CMDBUFFERLINES) ;
+
+        // Action listener stuff.
+        tf.addKeyListener(new KeyAdapter()
+            {
+            public void keyTyped(KeyEvent e)
+                {
+                // Enter key
+                if((e.getID() == KeyEvent.KEY_TYPED) && (e.getKeyChar() == KeyEvent.VK_ENTER))
+                    {
+                    if(DEBUG) System.out.println("Enter Event") ;
+                    send(tf.getText() + '\n') ;
+                    cbuf.addCommand(tf.getText()) ;
+                    tf.setText("") ;
+                    }
+                }
+            public void keyPressed(KeyEvent e)
+                {
+                // UP Arrow
+                if((e.getID() == KeyEvent.KEY_PRESSED) && (e.getKeyCode() == KeyEvent.VK_UP))
+                    {
+                    if(DEBUG) System.out.println("UP Event") ;
+                    tf.setText(cbuf.getPreviousCommand()) ;
+                    tf.setCaretPosition(tf.getText().length()) ;
+                    }
+                // DOWN Arrow
+                if((e.getID() == KeyEvent.KEY_PRESSED) && (e.getKeyCode() == KeyEvent.VK_DOWN))
+                    {
+                    if(DEBUG) System.out.println("DOWN Event") ;
+                    tf.setText(cbuf.getNextCommand()) ;
+                    tf.setCaretPosition(tf.getText().length()) ;
+                    }
+                // Escape key
+                if((e.getID() == KeyEvent.KEY_PRESSED) && (e.getKeyCode() == KeyEvent.VK_ESCAPE))
+                    {
+                    if(DEBUG) System.out.println("ESCAPE Event") ;
+                    tf.setText("") ;                                                                }
+                }
+            }) ;
+        // Add component listener to focus text field.
+        this.addComponentListener(new ComponentAdapter() {
+            public void componentShown(ComponentEvent e) {
+                tf.setVisible(true) ;
+                tf.requestFocus() ;
+                }
+            });
+        
+        // Init the scrolling thread.
+        t = new Thread(this, "Scrolling thread") ;
+        t.start() ;
+
+        // Prompt for callsign to connect with.
+        while(call == null || call.indexOf(" ") > -1)
+             {
+             call = JOptionPane.showInputDialog("Enter your callsign") ;
+             }
+
+        call = call.toUpperCase() ;
+        } // End of init
+    /**
+     * getTabName - Get the name that this component should show on it's tab
+     * @returns String s - Tab name
+     **/
+    public String getTabName()
+        {                                                                               return NAME ;
+        }
+    /**
+     * getTabTip - Get the tip that this component should show on it's tab
+     * @returns String s - Tab tip
+     **/
+    public String getTabTip()
+        {
+        return TIP ;
+        }
+    /**
+     * getMenu - get the menu to add to the main menu bar.
+     * @returns JMenu
+     **/
+    public JMenu getMenu()
+        {
+        return null ;
+        }                                                                        
+    /**
+     * send - Helper function to send data out to the PipedOutputMUX
+     * @param String s - data to send.
+     **/
+    private void send(String s)
+        {
+        if(DEBUG) System.out.println("Cluster: send got : " + s) ;
+        // If the input has no | in it, prefix I<CALLSIGN>| and send it.
+        if(s.indexOf("|") == -1)
+            {
+            s = "I" + call + "|" + s ;
+            }                                                                    
+        try
+            {
+            // Write the data to the stream.
+            for(int i=0;i<s.length();i++)
+                {
+                pos.write(s.charAt(i)) ;
+                }
+            }
+        catch(IOException ex)
+            {
+            System.out.println("Cluster: IOException on destination stream.") ;
+            System.out.println(ex) ;
+            }
+        }
+    /**
+     * Loop continually checking to see if anything has been written to the
+     * file that is being monitored.
+     */
+    public void run()
+        {
+        String output = new String() ;
+        // Loop continually reading from the input stream
+        while(true)                                                          
+            {
+            
+            try
+                {
+                // Read in a line of data (This screws up prompts with no /n)
+                output = bir.readLine() ;
+                if(output != null) display(output) ;
+
+                if(DEBUG) System.out.println("After reading a line.") ;
+                }
+            catch(IOException ex)
+                {
+                System.out.println("SpiderCluster: IOException trying to read.") ;
+                }
+            } // End of infinate loop.
+        } // End of run.                                                        
+
+    private void display(String s)
+        {
+        // Automatic login - when we see "Conneted to" send the login string.
+        if(s.startsWith("Connected to")) { send("A" + call + "|local\n") ; }
+        
+        // s = s.replace('\a', ' ') ;
+
+        // Get rid of Ctrl-G's in UNICODE.
+        while(s.indexOf("%07") > -1)
+            {
+            StringBuffer sb = new StringBuffer(s) ;
+            sb.delete(s.indexOf("%07"), s.indexOf("%07") + 3) ;
+
+            s = sb.toString() ;
+            }
+
+        // If the line has a | and starts with D, strip off upto and inc the |.
+        if(s.indexOf("|") != -1 && s.charAt(0) == 'D')
+            {
+            s = s.substring(s.indexOf("|") + 1, s.length()) ;
+            }
+        
+        // Find out what colour this needs to be.
+        attr = getAttributes(s) ;
+
+        // Display it in the doc.
+        doc.append(s + "\n", attr) ;
+        }
+
+    /**
+     * getAttributes(String s) - get attributes (i.e. colour) given a string.
+     * @param String s
+     **/
+    private SimpleAttributeSet getAttributes(String s)
+        {
+        SimpleAttributeSet sas = attr ;
+
+        /**
+         # 0 - $foreground, $background
+         # 1 - RED, $background
+         # 2 - BROWN, $background
+         # 3 - GREEN, $background
+         # 4 - CYAN, $background
+         # 5 - BLUE, $background
+         # 6 - MAGENTA, $background
+
+        VHF DX SPOT
+         [ '^DX de [\-A-Z0-9]+:\s+([57][01]\d\d\d\.|\d\d\d\d\d\d+.)', COLOR_PAIR(1) ],
+        PROMPT
+         [ '^G0VGS de GB7MBC', COLOR_PAIR(6) ],
+        DUNNO!
+         [ '^G0VGS de', A_BOLD|COLOR_PAIR(2) ],
+        HF DX SPOT
+         [ '^DX', COLOR_PAIR(5) ],
+        ANNOUNCE
+         [ '^To', COLOR_PAIR(3) ],
+        WWV SPOT
+         [ '^WWV', COLOR_PAIR(4) ],
+        DUNNO! 
+         [ '^[-A-Z0-9]+ de [-A-Z0-9]+ \d\d-\w\w\w-\d\d\d\d \d\d\d\dZ', COLOR_PAIR(0) ],
+        DUNNO! - PROBABLY A TALK
+         [ '^[-A-Z0-9]+ de [-A-Z0-9]+ ', COLOR_PAIR(6) ],
+        WX SPOT
+         [ '^WX', COLOR_PAIR(3) ],
+        NEW MAIL
+         [ '^New mail', A_BOLD|COLOR_PAIR(4) ],
+        USER LOGIN?
+         [ '^User', COLOR_PAIR(2) ],
+        NODE LOGIN?
+         [ '^Node', COLOR_PAIR(2) ],                                  
+         **/
+
+        Hashtable h = new Hashtable() ;
+        h.put("DX de", Color.red) ;  // HF DX
+        h.put(call + " de ", Color.magenta) ;
+        // h.put("DX", Color.blue) ; // VHF/UHF DX
+        h.put("To", Color.green) ;
+        h.put("WWV", Color.cyan) ;
+        h.put("WCY", Color.cyan) ;
+        // h.put("", Color.) ;
+        // h.put("", Color.) ;
+        h.put("WX", Color.green) ;
+        h.put("New mail", Color.cyan) ;
+        //h.put("User", Color.brown) ;
+        //h.put("Node", Color.brown) ;
+        h.put("User", Color.yellow) ;
+        h.put("Node", Color.orange) ;
+        
+        Enumeration e = h.keys() ;
+        
+        while(e.hasMoreElements())
+            {
+            String prefix = (String)e.nextElement() ;
+            if(s.startsWith(prefix))
+                {
+                StyleConstants.setForeground(sas, (Color)h.get(prefix)) ;
+                return sas ;
+                }
+            }
+
+        StyleConstants.setForeground(sas, Color.white) ;
+        return sas ;
+        }
+    } // End of class.