home *** CD-ROM | disk | FTP | other *** search
/ The Net: Ultimate Internet Guide / WWLCD1.ISO / pc / java / in4wjcxu / src / como / irc / serverirc.java < prev   
Encoding:
Java Source  |  1996-08-14  |  26.9 KB  |  1,145 lines

  1. /*
  2. * @(#)ServerIRC.java    1.0 96/03/03 Ulrich Gall & Jan Kautz
  3. *
  4. * Copyright (c) 1996 Ulrich Gall & Jan Kautz 
  5. * uhgall@cip.informatik.uni-erlangen.de
  6. * jnkautz@cip.informatik.uni-erlangen.de
  7. * Hofmannstr. 48, D-91052 Erlangen, Germany, Fax: +49-9131-201358
  8. *
  9. *
  10. * Server-IRC - it is used to do connections and receive invitations.
  11. * This Server-Implementation uses the IRC-protocoll
  12. *
  13. */
  14.  
  15. package como.irc;
  16.  
  17. import java.io.*;
  18. import java.net.*;
  19. import java.util.*;
  20. import java.applet.Applet;
  21. import como.sys.*;
  22. import como.awt.*;
  23. import como.io.*;
  24. import como.commlet.*;
  25. import como.commlet.draw.*;
  26. import como.commlet.chat.*;
  27. import como.commlet.nicnacnoe.*;
  28. import como.commlet.superchat.*;
  29. import como.commlet.scheduler.*;
  30. import como.commlet.classroom.*;
  31. import como.util.*;
  32.  
  33. public class ServerIRC extends Thread {
  34.     static String PATH_COMO="como/";
  35.     static String PATH_COMMLET=PATH_COMO+"commlets/";
  36.     static String PATH_COMMLET_LIST = PATH_COMMLET + "commlets.txt";
  37.     static String PATH_COMMLET_ICONS = PATH_COMMLET + "icons/";
  38.  
  39.     private IrcServerSocket waitSocket = null;
  40.     private User ego;
  41.     private Hashtable commlist;
  42.     private ConstantsIRC constantsirc = new ConstantsIRC();
  43.  
  44.     CubbyHole UsersCubbyHole = new CubbyHole();
  45.     CubbyHole ChannelsCubbyHole = new CubbyHole();
  46.  
  47.     ServerIRC( User e, String proxyhost, int port, ComoIRCFrontEnd cclient ) throws IOException {
  48.         String localhost;
  49.  
  50.         try {
  51.             localhost = (InetAddress.getLocalHost()).getHostName();
  52.         } catch( Exception ex ) {
  53.             Debug.msg( 20, "Server(): Couldn't get local host Name: "+ex.toString() );
  54.             localhost = "localhost";
  55.         }
  56.  
  57.         ego = e;
  58.         commlist = new Hashtable();
  59.  
  60.         getConstantsIRC().setEgo( ego );
  61.         getConstantsIRC().setLocalHost( localhost );
  62.         getConstantsIRC().setProxyHost( proxyhost );
  63.         getConstantsIRC().setProxyIRCPort( port );
  64.         getConstantsIRC().setComoClient( cclient );        
  65.  
  66.         waitSocket = new IrcServerSocket( this );
  67.         // exception must be caught from outside!
  68.  
  69.         // let's start our Thread
  70.         start();
  71.     }
  72.  
  73.     ConstantsIRC getConstantsIRC() {
  74.         return constantsirc;
  75.     }
  76.  
  77.     public void run() {
  78.         Msg msg;
  79.         boolean stopped = false;
  80.  
  81.         while( stopped == false )
  82.         {
  83.             msg = waitSocket.readMsg();
  84.  
  85.             if( msg.type == Msg.PING || msg.type == Msg.NO_DATA )
  86.                 continue;
  87.  
  88.             stopped = handleMsg( msg );
  89.         }
  90.     }
  91.  
  92.     public boolean handleMsg( Msg msg )
  93.     {
  94.         switch( msg.type )
  95.         {
  96.             case Msg.INVITATION:
  97.                 Hashtable inv = (Hashtable)msg.arg;
  98.                 IrcChan ch = (IrcChan)inv.get( "channel" );
  99.                 User from = (User)inv.get( "from" );
  100.                 String name = (String)from.get( User.NAME );
  101.  
  102.                 getConstantsIRC().getComoClient().log( "Invitation for "+ch.commletname+" '"+ch.topic+"' from "+name );
  103.  
  104.                 // ask user if user wants to accept invitation;
  105.                 getConstantsIRC().getComoClient().handleInvitation( from, ch );
  106.                 break;
  107.  
  108.             case Msg.ADD_USER:
  109.                 // someone joined #como-main
  110.                 Thread add = new UpdateThread( this, Msg.ADD_USER, (String)((User)msg.arg).get( User.NICK ) );
  111.                 add.start();
  112.                 break;
  113.  
  114.             case Msg.USER_LEFT:
  115.                 // someone left #como-main
  116.                 Thread left = new UpdateThread( this, Msg.USER_LEFT, (String)msg.arg );
  117.                 left.start();
  118.                 break;
  119.  
  120.             case Msg.LINE_DROPPED:
  121.                 new SmartFrame( "Sorry, line to Server dropped." );
  122.                 stopComObjs();
  123.                 try {
  124.                     waitSocket.close();
  125.                 } catch( Exception e ) { }
  126.  
  127.                 // now show the login.
  128.                 getConstantsIRC().getComoClient().noConnection();
  129.  
  130.                 return true;
  131.             
  132.             default:
  133.                 Debug.msg( 43, "ServerIRC.handleMsg(): Unknown Message-Type: " + msg.type );
  134.                 break;
  135.         }
  136.  
  137.         return false;
  138.     }
  139.  
  140.     /**
  141.      * startCommunication() starts a new commlet and invites the users[]
  142.      * 
  143.      */
  144.     void startCommunication(String commletname, User users[], String topic ) {
  145.         IrcChan chan = new IrcChan( commletname, topic );
  146.  
  147.         ConnectThreadIRC c = new ConnectThreadIRC( chan, this, ego, commlist, users );
  148.         c.start();
  149.  
  150.         return;
  151.     }
  152.  
  153.     /**
  154.      * This here is a bad thing. We wanted to avoid it, but we
  155.      * can't instantiate a ClassLoader! Therefore we have to
  156.      * instantiate the Commlets by hand!
  157.      */
  158.     static Commlet loadCommlet( String commletname ) {
  159.         if( commletname.compareTo("Draw") == 0 )
  160.             return new Draw();
  161.  
  162.         if( commletname.compareTo("NicNacNoe") == 0 )
  163.             return new NicNacNoe();
  164.         
  165.         if( commletname.compareTo("Chat") == 0 )
  166.             return new Chat();
  167.  
  168.         if( commletname.compareTo("SuperChat") == 0 )
  169.             return new SuperChat();
  170.  
  171.         if( commletname.compareTo("Scheduler") == 0 )
  172.             return new Scheduler();
  173.  
  174.         if( commletname.compareTo("ClassRoom") == 0 )
  175.             return new ClassRoom();
  176.  
  177.         Debug.msg( 98, "ServerIRC.loadCommlet(): "+commletname+" not found!" );
  178.  
  179.         return null;
  180.     }
  181.  
  182.     /**
  183.      * Send an invitation for a specific channel to the user 'who'.
  184.      */
  185.     public void sendInvitation( IrcChan chan, User who )
  186.     {
  187.         Hashtable inv = new Hashtable();
  188.  
  189.         inv.put( "channel", chan );
  190.         inv.put( "from", getConstantsIRC().ego );
  191.  
  192.         waitSocket.writePrivMsg( who, new Msg( Msg.INVITATION, (Object)inv ) );
  193.     }
  194.  
  195.     /** 
  196.      * Join the Channel 'chan'. Done asynchronously with a new thread.
  197.      */
  198.     void joinChannel( IrcChan chan ) {
  199.         ConnectThreadIRC c = new ConnectThreadIRC( chan, this, ego, commlist );
  200.         c.start();
  201.     }
  202.  
  203.     /* Called from ComoIRCFrontEnd. It stopps all ComObjs and
  204.      * closes the Socket to the ircd.
  205.      * This is called if the user presses "log out from como"
  206.      */
  207.     public void logout() {
  208.         // let's stop the main thread
  209.  
  210.         try {
  211.             this.stop();
  212.             waitSocket.close();
  213.         } catch( Exception e ) {
  214.             // noone cares here anymore
  215.         }
  216.  
  217.         // now stop all commlets/comobjs
  218.         stopComObjs();
  219.     }
  220.  
  221.     /**
  222.      * Stops all ComObjs and their commlets.
  223.      */
  224.     private void stopComObjs() {
  225.         Enumeration e = commlist.keys();
  226.  
  227.         while( e.hasMoreElements() ) {
  228.             ComObjIRC c = (ComObjIRC)e.nextElement();
  229.  
  230.             c.destroy();
  231.             // will be removed from the list by commlet.destroy();
  232.             // which calls server.loggedout( comobj, channel )
  233.         }
  234.     }
  235.  
  236.     /**
  237.      * Called by a ComObjIRC that quitted (user closed it).
  238.      * It just tells this the ServerIRC (me).
  239.      */
  240.     public void loggedout( ComObjIRC c, IrcChan chan ) {
  241.         if( commlist.get( c ) != null )
  242.         {
  243.             commlist.remove( c );
  244.             getConstantsIRC().getComoClient().leftChannel( chan );
  245.         }
  246.         else
  247.             Debug.msg( 33, "ServerIRC().loggedout(): Commlet #"+chan.ircName()+" already stopped." );
  248.     }
  249.  
  250.     /**
  251.      * Return all users using our Programm, i.e. all that are connected
  252.      * to the IRCServer and who are in "pattern"
  253.      */
  254.     synchronized User[] getUsers( String pattern, boolean como_only ) {
  255.         Vector users;
  256.  
  257.         waitSocket.send( "WHO "+pattern, true );
  258.         users = (Vector)UsersCubbyHole.get();
  259.  
  260.         User u[] = new User[users.size()];
  261.         Enumeration e = users.elements();
  262.         int i = 0;
  263.         
  264.         while( e.hasMoreElements() ) {
  265.             u[i] = (User)e.nextElement();
  266.  
  267.             if( ((String)u[i].get( User.NAME )).startsWith( IrcSocket.NICK_PREFIX ) )
  268.                 u[i].put( User.COMOUSER, new Boolean(true) );
  269.  
  270.             i++;
  271.         }
  272.         
  273.         return u;
  274.     }
  275.  
  276.     /**
  277.      * Return all users on the specified channel
  278.      */
  279.     User[] getUsersOnChannel( IrcChan ch ) {
  280.         return getUsers( "#"+ch.ircName(), false );
  281.     }
  282.  
  283.     /**
  284.      * Return all the channels (matching pattern)
  285.      */
  286.     synchronized IrcChan[] getChannels( String pattern, boolean como_only ) {
  287.         Vector channels;
  288.  
  289.         waitSocket.send( "LIST ", true );
  290.         channels = (Vector)ChannelsCubbyHole.get();
  291.         
  292.         IrcChan c[] = new IrcChan[channels.size()];
  293.         Enumeration e = channels.elements();
  294.         int i = 0;
  295.         
  296.         while( e.hasMoreElements() ) {
  297.             c[i] = (IrcChan)e.nextElement();
  298.             i++;
  299.         }
  300.         
  301.         return c;
  302.     }
  303.  
  304.     /**
  305.      * Let's see if a user is on a channel.
  306.      */
  307.     synchronized public boolean isUserOnChannel( User user, IrcChan channel ) {
  308.         Enumeration e = commlist.elements();
  309.  
  310.         while( e.hasMoreElements() ) {
  311.             IrcChan c = (IrcChan)e.nextElement();
  312.  
  313.             if( channel.ircName().equals( c.ircName() ) )
  314.                 return true;
  315.         }
  316.  
  317.         return false;
  318.     }
  319.  
  320.     /**
  321.      * Return the Applet, that started all. This is necessary,
  322.      * because the ComObj wants to load pictures and sound.
  323.      */
  324.     Applet getApplet() {
  325.         return getConstantsIRC().getComoClient().getApplet();
  326.     }
  327. }
  328.  
  329. /**
  330.  * Update the display of ComoIRCClient.
  331.  */
  332. class UpdateThread extends Thread {
  333.     int type;
  334.     String what;
  335.     ServerIRC server;
  336.  
  337.     public UpdateThread( ServerIRC s, int t, String w ) {
  338.         type = t;
  339.         what = w;
  340.         server = s;
  341.     }
  342.  
  343.     public void run() {
  344.         switch( type )
  345.         {
  346.             case Msg.ADD_USER:
  347.                 server.getConstantsIRC().getComoClient().addUser( what );
  348.                 break;
  349.             case Msg.USER_LEFT:
  350.                 server.getConstantsIRC().getComoClient().userLeft( what );
  351.                 break;
  352.         }
  353.     }
  354. }
  355.  
  356.  
  357. /**
  358.  * Connect myself to an existing or a new channel.
  359.  */
  360. class ConnectThreadIRC extends Thread {
  361.     private IrcChan chan;
  362.     private User ego;
  363.     private Hashtable commlist;
  364.     private ServerIRC server;
  365.     private User users[];
  366.     private boolean connecttoexisting = true;
  367.  
  368.     ConnectThreadIRC( IrcChan c, ServerIRC s, User e, Hashtable cl ) {
  369.         chan = c;
  370.         ego = e;
  371.         commlist = cl;
  372.         server = s;
  373.  
  374.         connecttoexisting = true;
  375.     }
  376.  
  377.     ConnectThreadIRC( IrcChan c, ServerIRC s, User e, Hashtable cl, User u[] ) {
  378.         chan = c;
  379.         ego = e;
  380.         commlist = cl;
  381.         server = s;
  382.         users = u;
  383.  
  384.         connecttoexisting = false;
  385.     }
  386.  
  387.     public void run()
  388.     {
  389.         IrcSocket socket;
  390.         Commlet newcommlet;
  391.         ComObjIRC com;
  392.         User[] list = null;
  393.         Msg msg;
  394.  
  395.         try {
  396.             com = new ComObjIRC( server, chan, (User)server.getConstantsIRC().ego.clone(), !connecttoexisting );
  397.         } catch( IOException e ) {
  398.             // oops no connection to Server
  399.  
  400.             new SmartFrame( "Couldn't connect to server, try again later!" );
  401.  
  402.             server.getConstantsIRC().getComoClient().log( "Couldn't start Communication!" );
  403.             return;
  404.         }
  405.  
  406.         if( connecttoexisting )
  407.             list = server.getUsersOnChannel( chan );
  408.  
  409.         server.getConstantsIRC().getComoClient().log( "Starting Commlet "+chan.commletname );
  410.  
  411.         /* AAAARGH: SECURITYMANAGER
  412.          *
  413.          * Is it really necessary to forbid an applet to create
  414.          * a ClassLoader. Netscape doesn't allow to read/write files
  415.          * to make sockets etc. No Class can do anything harmful.
  416.          * Then why can't I load a class over the net.
  417.          * I mean nothing else does netscape!!!! Why can't I???
  418.          * The whole advantage of JAVA is given away. Everybody
  419.          * says you just have to load those parts, that are needed.
  420.          * NICE IDEA. But this does not work. Neither with the
  421.          * appletviewer nor with Netscape!!!!
  422.          *
  423.          * Well then let's load some more Kb over the net just for fun!
  424.          */
  425.         /*
  426.         try {
  427.             IRCClassLoader icl = new IRCClassLoader();
  428.            newcommlet = (Commlet)(new IRCClassLoader()).loadClass( chan.commletname, true ).newInstance();
  429.         }
  430.         catch( Exception e )
  431.         {
  432.             Debug.msg( 50, "ServerIRC.ConnectThread: Could not load Class over Net" );
  433.             return;
  434.         }
  435.         */
  436.     
  437.  
  438.         // First load the Commlet
  439.         // then set the corresponding com-Obj in the commlet
  440.         // Then init() it. This sould work fine now. in
  441.         // init() the ego-user is already known. The ComObj
  442.         // does not deliver any messages before com.setCommlet()
  443.         // is done. -> During the init() now other method from
  444.         // the commlet will be called!
  445.  
  446.         newcommlet = ServerIRC.loadCommlet( chan.commletname );
  447.         newcommlet.setCom( com );
  448.         com.setCommletName( chan.commletname );
  449.         newcommlet.init();
  450.         com.setCommlet( newcommlet );
  451.         newcommlet.showCommlet();
  452.  
  453.         commlist.put( com, chan );
  454.         com.addMe( (User)server.getConstantsIRC().ego.clone() );
  455.  
  456.         if( connecttoexisting == true )
  457.         {
  458.             if( list.length == 1 ) {
  459.                 Msg newmastermsg = new Msg( Msg.NEW_MASTER, com.getMyID(), com.getMyID(),
  460.                                             new Integer(com.getMyID()) );
  461.  
  462.                 // tell comobj and commlet, that he is master then!
  463.                 com.preHandleMsg( newmastermsg );
  464.                 newcommlet.handleMsg( newmastermsg );
  465.             }
  466.             else
  467.             {
  468.                 Vector users = com.getUsers();
  469.                 boolean adduser;
  470.  
  471.                 // now add everyone who is already in this channel
  472.                 // and leave those who are already in the ComObj (via ADD_USER-Msg)
  473.                 for( int i = 0; i < list.length; i++ )
  474.                 {
  475.                     int id;
  476.  
  477.                     adduser = true;
  478.                 
  479.                     Enumeration e = users.elements();
  480.                     while( e.hasMoreElements() )
  481.                     {
  482.                         User test = (User)e.nextElement();
  483.                         if( test.get(User.NICK).equals(list[i].get(User.NICK)) )
  484.                         {
  485.                             adduser = false;
  486.                             break;
  487.                         }
  488.                     }
  489.  
  490.                     if( adduser == false )
  491.                         continue;
  492.  
  493.                     id = com.loginUser( list[i] );
  494.                     if( id > 0 )                // only if user is allowed
  495.                         com.addUser( id );    // also tells commlet
  496.                 }
  497.             }
  498.         }
  499.         else
  500.         {
  501.             // i am the master -> i may set the topic -> i will set the topic
  502.             newcommlet.handleMsg( new Msg( Msg.NEW_TOPIC, com.getMyID(), com.getMyID(), chan.topic ) );
  503.      
  504.               // invite the users[]
  505.             for( int i = 0; i < users.length; i++ )
  506.                 server.sendInvitation( chan, users[i] );
  507.         }
  508.     }
  509. }
  510.  
  511.  
  512. /*-----------------------------------------------------------------------
  513.     HELP Classes used in Server.java
  514. -----------------------------------------------------------------------*/
  515.  
  516. /**
  517.  * This class does the main job here. It opens a connection back to the
  518.  * irc-server then joins a channel. Then it reads message from that channel
  519.  * and may write messages to that channel.
  520.  */
  521. class IrcSocket {
  522.     final static int RPL_WHOREPLY   = 352;
  523.     final static int RPL_ENDOFWHO   = 315;
  524.     final static int RPL_NAMREPLY   = 353;
  525.     final static int RPL_ENDOFNAMES = 366;
  526.     final static int RPL_LIST       = 322;
  527.     final static int RPL_LISTEND    = 323;
  528.  
  529.     final static int RPL_MOTDSTART = 375;
  530.     final static int RPL_ENDOFMOTD = 376;
  531.  
  532.     final static int ERR_ERRONEUSNICKNAME = 432;
  533.     final static int ERR_NICKNAMEINUSE = 433;
  534.     final static int ERR_NICKCOLLISION = 436;
  535.  
  536.     final static int NO_MESSAGE = -1;
  537.     final static int CMD_JOIN = 10001;
  538.     final static int CMD_PART = 10002;
  539.     final static int CMD_QUIT = 10003;
  540.     final static int CMD_PRIVMSG = 10004;
  541.  
  542.     final static String NICK_PREFIX = "c_";
  543.  
  544.     String ret_user, ret_cmd, ret_msg, ret_channel, ret_address;
  545.     protected Socket socket;
  546.     DataInputStream input;
  547.     DataOutputStream output;
  548.     IrcChan chan;
  549.     String nick;        // Someone must know the local nick name!
  550.  
  551.     ServerIRC server = null;
  552.  
  553.     /**
  554.      * Constructor for IrcSocket.
  555.      * Go to the main Channel.
  556.      */
  557.     IrcSocket( ServerIRC s ) throws IOException {
  558.         boolean ok;
  559.  
  560.         server = s;
  561.  
  562.         ok = Login( server.getConstantsIRC().proxyhost, server.getConstantsIRC().proxyircport,
  563.                      chan = new IrcChan( "como-main", "none", "Como Main Channel" ) );
  564.  
  565.         if( !ok ) throw new IOException();
  566.         else {
  567.             // This is the NICK he finally got!
  568.             server.getConstantsIRC().ego.put( User.NICK, nick );
  569.         }
  570.     }
  571.                          
  572.     /**
  573.      * Constructor for IrcSocket. Go to the the channel 'c'.
  574.      */
  575.     IrcSocket( ServerIRC s, IrcChan c ) throws IOException {
  576.         boolean ok;
  577.  
  578.         server = s;
  579.         chan = c;
  580.  
  581.         ok = Login( server.getConstantsIRC().proxyhost, server.getConstantsIRC().proxyircport, c );
  582.  
  583.         if( !ok ) throw new IOException();
  584.         else
  585.             server.getConstantsIRC().ego.put( User.NICK, nick );
  586.     }
  587.  
  588.  
  589.     /**
  590.      * Connect myself to the IRC-Server and join a channel.
  591.      */
  592.     private boolean Login( String host, int port, IrcChan chan ) {
  593.         String name = (String)server.getConstantsIRC().ego.get( User.NAME );
  594.         Socket s;
  595.         int number = 1;
  596.  
  597.         number = ((int)(Math.random()*9000));
  598.         nick = NICK_PREFIX + number;
  599.  
  600.         try {
  601.             socket = new Socket( host, port );
  602.             input  = new DataInputStream( socket.getInputStream() );
  603.             output = new DataOutputStream( socket.getOutputStream() );
  604.         } catch( Exception e ) {
  605.             Debug.msg( 100, "IrcSocket(): " + e.toString() );
  606.             return false;
  607.         }
  608.  
  609.         send( "USER "+nick+" "+host+" "+host+" :"+name, true );
  610.         send( "NICK "+nick, true );
  611.  
  612.         server.getConstantsIRC().getComoClient().log( "Waiting for Connection to Server." );
  613.  
  614.         while( true )
  615.         {
  616.             String line;
  617.             int command;
  618.  
  619.             try {
  620.                 line = input.readLine();
  621.  
  622.                 // oh line dropped
  623.                 if( line == null ) return false;
  624.             } catch( Exception e ) {
  625.                 Debug.msg( 100, "IrcSocket.Login(): " + e.toString() );
  626.                 return false;
  627.             }
  628.  
  629.             command = parseIrcMessage( line );
  630.  
  631.             if( command == ERR_ERRONEUSNICKNAME || command == ERR_NICKNAMEINUSE ||
  632.                      command == ERR_NICKCOLLISION )
  633.             {
  634.                 // oh did not work let's try another one
  635.                 number++;
  636.                 nick = NICK_PREFIX + number;
  637.                 send( "NICK "+nick, true );
  638.             }
  639.             else if( command == RPL_ENDOFMOTD ) break;
  640.         }
  641.  
  642.         // All User visible please!!!
  643.         send( "MODE "+nick+" -i", true );
  644.         send( "JOIN #"+chan.ircName(), true );
  645.  
  646.         while( true )
  647.         {
  648.             String line;
  649.             try {
  650.                 line = input.readLine();
  651.  
  652.                 // this here seems to be a "LINE_DROPPED"
  653.                 // message. *NO* IOException occures if the
  654.                 // connection drops!!!!
  655.                 if( line == null ) {
  656.                     return false;
  657.                 }
  658.             } catch( Exception e ) {
  659.                 return false;
  660.             }
  661.             int command = parseIrcMessage( line );
  662.  
  663.             if( command == RPL_ENDOFNAMES ) // OK, I joined the channel
  664.                 break;
  665.         }
  666.  
  667.         server.getConstantsIRC().getComoClient().log( "Connected." );
  668.         return true;
  669.     }
  670.  
  671.  
  672.     /**
  673.      * Read a message from the channel belonging to that IrcSocket.
  674.      * Handles also those IRC-specific messages and tells the server
  675.      * or comobj, if they are of interest (like user added/left...).
  676.      */
  677.     Msg readMsg() {
  678.         int from, to, type, len;
  679.         Object o;
  680.         boolean stoploop = false;
  681.  
  682.         if( input == null ) return new Msg( Msg.NO_DATA );
  683.  
  684.         try {
  685.             Vector users = new Vector();
  686.             Vector channels = new Vector();
  687.  
  688.             while( !stoploop )
  689.             {
  690.                   String line = input.readLine();
  691.                 int command;
  692.  
  693.                 // ahh this means: Line Dropped!
  694.                 // well then throw an Exception, that i will
  695.                 // catch myself (see catch....)
  696.                 if( line == null ) throw new IOException();
  697.  
  698.                   command = parseIrcMessage( line );
  699.  
  700.                 // read as long as I get a message that is usefull for me.
  701.                   if( command == NO_MESSAGE ) continue;
  702.  
  703.                 switch( command ) 
  704.                 {
  705.                   case CMD_PART:
  706.                       return new Msg( Msg.USER_LEFT, ret_user );
  707.  
  708.                   case CMD_QUIT:
  709.                     return new Msg( Msg.USER_LEFT, ret_user );
  710.  
  711.                   case CMD_JOIN:
  712.                     User user = new User();
  713.                     user.put( User.NICK, ret_user );
  714.  
  715.                     // TODO:
  716.                     // well it's a little bit ugly perhaps.
  717.                     // but it works quite well
  718.  
  719.                     user.put( User.NAME, "User nicknamed "+ret_user );
  720.                     return new Msg( Msg.ADD_USER, user );
  721.  
  722.                 case RPL_WHOREPLY:
  723.                     {
  724.                         User u = new User();
  725.                         ret_msg = ret_msg.substring( 2, ret_msg.length() );
  726.                         u.put( User.NICK, ret_user );  // is nick
  727.                         u.put( User.NAME, ret_msg );
  728.                         u.put( User.ADDRESS, ret_address );
  729.                         users.addElement( u );
  730.                     }
  731.                     break;
  732.  
  733.                 case RPL_ENDOFWHO:
  734.                     server.UsersCubbyHole.put( users );
  735.                     users = new Vector();
  736.                     break;
  737.  
  738.                 case RPL_LIST:
  739.                     IrcChan ch = null;
  740.                     
  741.                     // TODO: Perhaps permit non-Como-Channels here
  742.                     // If yes: then uncomment this!
  743.                     // Otherwise: Every channel is a como-channel
  744.                     // if( ret_channel.startsWith( "como" ) ) { // ok is a como-channel
  745.  
  746.                     if( true ) { // ok is a como-channel
  747.                         if( ret_channel.charAt(4) == '-' )    // ok this is como-main
  748.                         {
  749.                             // Do not show the como-main-channel where everybody
  750.                             // is in there! It is only for internal use!
  751.                             // ch = new IrcChan( ret_channel, "none", " " );
  752.                         }
  753.                         else
  754.                         {
  755.                             ch = new IrcChan();
  756.                             ch.fromString( ret_channel );
  757.                             ch.topic = ret_msg;
  758.                         }
  759.                     }
  760.                     else {
  761.                         ch = new IrcChan( ret_channel, "IRC", " " );
  762.                     }
  763.                     
  764.                     if( ch != null ) channels.addElement( ch );
  765.                     break;
  766.  
  767.                 case RPL_LISTEND:
  768.                     server.ChannelsCubbyHole.put( channels );
  769.                     channels = new Vector();
  770.                     break;
  771.  
  772.                 case CMD_PRIVMSG:
  773.                     if( ret_msg.startsWith( "COMO_" ) )
  774.                     {
  775.                         ret_msg = ret_msg.substring( 5, ret_msg.length() );
  776.                         stoploop = true;
  777.                     }
  778.                     else
  779.                     {
  780.                         // TODO: Use as chat message!!!
  781.                         // This is only necessary if non-Como-Channels
  782.                         // are allowed!
  783.                         Debug.msg( 30, "IrcSocket.readMsg(): got a irc-chat-message: "+ret_msg );
  784.                     }
  785.                     break;
  786.                 }
  787.             }
  788.         } catch( IOException e ) {
  789.             // server.getConstantsIRC().getComoClient().log( "Connection to Server dropped." );
  790.             Debug.msg( 1, "Exception: "+e );
  791.             return new Msg( Msg.LINE_DROPPED, e.toString() );
  792.         }
  793.  
  794.         StringTokenizer st = new StringTokenizer( ret_msg, "!" );
  795.         from = (new Integer(st.nextToken())).intValue();
  796.         to = (new Integer(st.nextToken())).intValue();
  797.         type = (new Integer(st.nextToken())).intValue();
  798.  
  799.         if( st.nextToken().compareTo( "Y" ) == 0 )
  800.         {
  801.             ObjectInputStream ois = null;
  802.             StringBufferInputStream stringstream = null;
  803.             String s;
  804.             Object object;
  805.  
  806.             s = st.nextToken( "\n" ); // Till the end of line!
  807.             s = s.substring( 1, s.length() );
  808.  
  809.             stringstream = new StringBufferInputStream( s );
  810.             ois = new ObjectInputStream( new IRCInputStream( stringstream ) );
  811.  
  812.             try {
  813.                 object = ois.readObject();
  814.             }
  815.             catch( Exception e ) {
  816.                 Debug.msg( 50, "IrcSocket.readMsg(): could not convert Object! Printing Trace: "+e.toString() );
  817.                 e.printStackTrace(System.out);
  818.                 return new Msg( Msg.NO_DATA );
  819.             }
  820.  
  821.             if( object == null )
  822.                 Debug.msg( 70, "IrcSocket.readMsg(): read null-Object as arg!" );    
  823.  
  824.             return new Msg( type, from, to, object );
  825.         }
  826.         else
  827.             return new Msg( type, from, to, null );
  828.     }
  829.  
  830.  
  831.     /**
  832.      * Write a message to all on that channel.
  833.      */
  834.     boolean writeMsg( Msg msg ) {
  835.         return writeMsg( msg, "#"+chan.ircName() );
  836.     }
  837.  
  838.  
  839.     /**
  840.      * Write a message to one user on that channel.
  841.      */
  842.     boolean writePrivMsg( User to, Msg msg ) {
  843.         return writeMsg( msg, (String)to.get( User.NICK ) );
  844.     }
  845.  
  846.  
  847.     /**
  848.      * Write a message to a user/all on that channel.
  849.      */
  850.     synchronized private boolean writeMsg( Msg msg, String to ) {
  851.         if( output == null ) return false;
  852.         
  853.         try {
  854.             StringBuffer message = new StringBuffer( "PRIVMSG "+to+" :COMO_" );
  855.  
  856.             message.append( msg.from );
  857.             message.append( "!" );
  858.             message.append( msg.to );
  859.             message.append( "!" );
  860.             message.append( msg.type );
  861.             message.append( "!" );
  862.             if( msg.arg != null )
  863.             {
  864.                 ObjectOutputStream oos = new ObjectOutputStream( new IRCOutputStream( output ) );
  865.  
  866.                 message.append( "Y!" );
  867.                 output.writeBytes( message.toString() );
  868.                 oos.writeObject( msg.arg );
  869.             }
  870.             else {
  871.                 message.append( "N!" );
  872.                 output.writeBytes( message.toString() );
  873.             }
  874.             output.writeBytes( "\n" );
  875.  
  876.             return true;
  877.         } catch( Exception e ) {
  878.             Debug.msg( 98, "writeMsg(): " + e.toString() );
  879.             return false;
  880.         }
  881.     }
  882.  
  883.     /**
  884.      * Parse a irc-message, but only parse those things that interest!
  885.      */
  886.     synchronized int parseIrcMessage( String line ) {
  887.         int colon, space, ex, pos, pos2;
  888.         int commandnumber = NO_MESSAGE;
  889.         int len;
  890.         char ch;
  891.         
  892.         if( line.length() == 0 ) 
  893.         {
  894.             return NO_MESSAGE;
  895.         }
  896.  
  897.         ch = line.charAt( 0 );
  898.         if( ch != ':' ) {
  899.             if( line.startsWith( "PING" ) ) {
  900.                 String out = "PONG "+server.getConstantsIRC().localhost;
  901.                 send( out.toString(), true );
  902.             }
  903.             return NO_MESSAGE;
  904.         }
  905.         
  906.         // OK: Now it starts with ':'
  907.         
  908.         len = line.length();
  909.         
  910.         ex = line.indexOf( '!' );
  911.         colon = line.indexOf( ':', 1 );
  912.         space = line.indexOf( ' ' );
  913.         
  914.         if( space < 0 ) return NO_MESSAGE;
  915.         
  916.         pos = space+1;
  917.         ch = line.charAt( pos );
  918.         if( ch >= '0' && ch <= '9' ) {
  919.             // Numeric Message
  920.             
  921.             pos2 = line.indexOf( ' ', pos );
  922.             commandnumber = Integer.parseInt(line.substring(pos,pos2));
  923.             
  924.             pos = line.indexOf( ' ', pos2+1 );
  925.             ret_user = line.substring( pos2+1, pos );
  926.  
  927.             if( commandnumber == RPL_WHOREPLY ) {
  928.                 StringTokenizer st = new StringTokenizer( line, " " );
  929.                 int i;
  930.                 for( i = 0; i < 8; i++ )
  931.                 {
  932.                     String str = st.nextToken();
  933.                     if( i == 5 ) ret_address = str;
  934.                     if( i == 7 ) ret_user = str;
  935.                 }
  936.             }
  937.             if( commandnumber == RPL_LIST ) {
  938.                 pos2 = line.indexOf( ' ', pos+1 );
  939.                 ret_channel = line.substring( pos+2, pos2 );
  940.             }
  941.         }
  942.         else {
  943.             // Has to be a message without numbers!!
  944.             
  945.             if( ex > 0 )
  946.                 ret_user = line.substring( 1, ex );
  947.             else
  948.                 ret_user = line.substring( 1, pos );
  949.  
  950.             pos2 = line.indexOf(' ',pos);
  951.             if( pos2 < 0 )
  952.                 return NO_MESSAGE;
  953.                 
  954.             ret_cmd = line.substring( pos, pos2 );
  955.  
  956.             if( ret_cmd.equalsIgnoreCase( "JOIN" ) )
  957.                 commandnumber = CMD_JOIN;
  958.             else if( ret_cmd.equalsIgnoreCase( "PART" ) )
  959.                 commandnumber = CMD_PART;
  960.             else if( ret_cmd.equalsIgnoreCase( "QUIT" ) )
  961.                 commandnumber = CMD_QUIT;
  962.             else if( ret_cmd.equalsIgnoreCase( "PRIVMSG" ) )
  963.                 commandnumber = CMD_PRIVMSG;
  964.         }
  965.  
  966.         ret_msg = line.substring( colon+1, len );
  967.  
  968.         return commandnumber;
  969.     }
  970.  
  971.     /**
  972.      * Send a String to this channel/IRC-Server.
  973.      * Used to send IRC-Commands.
  974.      */
  975.     synchronized void send( String out ) {
  976.         if( output == null ) return;
  977.  
  978.         try {
  979.             output.writeBytes( out );
  980.         } catch( Exception e ) {
  981.             Debug.msg( 98, "IrcSocket.send(): Exception: "+e.toString() );
  982.         }
  983.     }
  984.     
  985.     /**
  986.      * Send a String to this channel/IRC-Server.
  987.      * Used to send IRC-Commands.
  988.      */
  989.     void send( String out, boolean cr ) {
  990.         if( cr == true )
  991.             send( out+"\n" );
  992.         else
  993.             send( out );
  994.     }
  995.     
  996.     /**
  997.      * Close the connection.
  998.      */
  999.     void close() {
  1000.  
  1001.         try {
  1002.             output.flush();
  1003.         } catch( IOException e ) {
  1004.             Debug.msg( 98, "IrcSocket.close() output.flush(): "+e.toString() );
  1005.         }
  1006.  
  1007.         try {
  1008.             // wait a little bit!
  1009.             // Sometimes the last message wasn't sent, when
  1010.             // the socket was closed !!!
  1011.  
  1012.             Thread.sleep( 150 );
  1013.         } catch( Exception e ) {}
  1014.     
  1015.         try {
  1016.             socket.close();
  1017.         } catch( Exception e ) {
  1018.             Debug.msg( 98, "IrcSocket.close() socket: "+e.toString() );
  1019.         }
  1020.  
  1021.         try {
  1022.             input.close();
  1023.         } catch( Exception e ) {
  1024.             Debug.msg( 98, "IrcSocket.close() input: "+e.toString() );
  1025.         }
  1026.  
  1027.         try {
  1028.             output.close();
  1029.         } catch( Exception e ) {
  1030.             Debug.msg( 98, "IrcSocket.close() output: "+e.toString() );
  1031.         }
  1032.  
  1033.         input = null;
  1034.         output = null;
  1035.         socket = null;
  1036.     }
  1037. }
  1038.  
  1039. /**
  1040.  * Do as if this would be a ServerSocket :-)
  1041.  */
  1042. class IrcServerSocket extends IrcSocket {
  1043.     IrcServerSocket( ServerIRC server ) throws IOException {
  1044.         super( server );
  1045.     }
  1046. }
  1047.  
  1048. /**
  1049.  * I use many Constants in this file. I don't want/can hardcode
  1050.  * everything.
  1051.  */
  1052. class ConstantsIRC {
  1053.     User ego = new User();
  1054.     String proxyhost = "proxyhost";
  1055.     String localhost = "localhost";
  1056.     int proxyircport = 6667;
  1057.     ComoIRCFrontEnd comoclient = null;
  1058.  
  1059.     void setEgo( User e ) {
  1060.         ego = e;
  1061.     }
  1062.     
  1063.     void setProxyHost( String name ) {
  1064.         proxyhost = name;
  1065.     }
  1066.     
  1067.     void setLocalHost( String name ) {
  1068.         localhost = name;
  1069.     }
  1070.     
  1071.     void setProxyIRCPort( int p ) {
  1072.         proxyircport = p;
  1073.     }
  1074.     
  1075.     void setComoClient( ComoIRCFrontEnd c ) {
  1076.         comoclient = c;
  1077.     }
  1078.  
  1079.     ComoIRCFrontEnd getComoClient() {
  1080.         return comoclient;
  1081.     }
  1082. }
  1083.  
  1084. /* Does not work because of the SecurityManager
  1085. class IRCClassLoader extends ClassLoader {
  1086.     Hashtable cache = new Hashtable();
  1087.  
  1088.     IRCClassLoader() { }
  1089.  
  1090.     private byte loadClassData(String name)[] {
  1091.         byte b[];
  1092.         
  1093.         b = ProxyDataLoader.load( ConstantsIRC.proxyhost, ServerIRC.PATH_COMMLET, name );
  1094.  
  1095.         return b;
  1096.     }
  1097.     
  1098.     public synchronized Class loadClass( String name, boolean b ) {
  1099.         Class c = (Class)cache.get(name);
  1100.  
  1101.         if (c != null) return c;
  1102.         try {
  1103.             if ((c = findSystemClass(name)) != null) return c;
  1104.         }
  1105.         catch (Exception e) {
  1106.             c = null;
  1107.         }
  1108.  
  1109.         byte data[] = loadClassData(name);
  1110.         if( data == null ) return null;
  1111.  
  1112.         cache.put(name, c = defineClass(data, 0, data.length));
  1113.         return c;
  1114.     }
  1115. }
  1116.  
  1117. class ProxyDataLoader {
  1118.     ProxyDataLoader() {
  1119.     }
  1120.     
  1121.     static byte[] load( String host, String pfad, String name ) {
  1122.         URL url;
  1123.         
  1124.         try {
  1125.             InputStream input;
  1126.             byte b[];
  1127.             int len;
  1128.             
  1129.             url = new URL( "http:", host, pfad + name );
  1130.             input = url.openStream();
  1131.             len = input.available();
  1132.             b = new byte[len];
  1133.             if( input.read(b) != len )
  1134.                 Debug.msg(90,"ProxyDataLoader().load(): loaded less than "+len+" bytes!" );
  1135.                 
  1136.             return b;
  1137.         }
  1138.         catch( Exception e ) {
  1139.             Debug.msg(90,"ProxyDataLoader().load("+name+"): " + e.toString() );
  1140.             return null;
  1141.         }
  1142.     }
  1143. }
  1144. */
  1145.