/* Wirc is an IRC client written in Java, designed to be easily          *//* implemented as an application or an applet.                           *//*                                                                       *//* Copyright (C) 1999 Michael Stern. stern@wheels.org.                   *//* 222 West 23rd Street, #507, New York City 10011                       *//*                                                                       *//* This program is free software; you can redistribute it and/or modify  *//* it under the terms of version 2 of the GNU General Public License as  *//* published by the Free Software Foundation.                            *//*                                                                       *//* 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.             */import java.io.*;import java.net.*;import java.awt.*;import java.awt.event.*;          // fun with JDK 1.1import java.applet.*;public class wirc extends Applet  implements ActionListener,KeyListener{  static final int DEFAULT_PORT = 6667;  static final String DEFAULT_HOST = "irc.sprynet.com";  static final String DEFAULT_NICK = "Stern_a";  static final String DEFAULT_USERNAME = "stern";    // username of the user on the client  static final String DEFAULT_REALNAME = "Michael J. Stern";  static final String DEFAULT_CHANNEL = "#macintosh";  static Socket socket = null;  static outgoingMesg sout = null;  static MsgReader msgReader = null;  static BufferedReader sin = null;  static int port = DEFAULT_PORT;  static String host = DEFAULT_HOST;   // used to be null  static String password = null;  static String nickname = DEFAULT_NICK;  static String username = DEFAULT_USERNAME;  static String realname = DEFAULT_REALNAME;  static String channel = DEFAULT_CHANNEL;  static void Usage () {        System.out.println (" Usage: ");        System.out.println ("    java wirc <host> <port> <channel>");        System.exit(0);  }  static void closeall() {        try {          if (wirc.sout != null)                wirc.sout.close();          if (wirc.socket != null)                wirc.socket.close();        }        catch (IOException e1) { }  }  public static void main (String[] args) {        if (args.length != 3) {          //      System.out.println("you gave me " + args.length + " args.\n");          Usage ();        }        host = args[0];        try { port = Integer.parseInt(args[1]); }        catch (NumberFormatException e) { Usage(); } // I need to include some way for the defaults to be used        channel = "#" + args[2];        Frame frame= new Frame();        frame.setTitle("Stern's IRC client");        wirc gui = new wirc();        gui.init();        frame.add("Center", gui);        frame.pack();        frame.show();  }                // end main  public void textValueChanged(TextEvent e) {}  public void actionPerformed(ActionEvent evt)    {          if (evt.getSource() == commButton)                commButton.connectORsend();          if (evt.getSource() == quitButton)                quitButton.actionQuit(evt);          if (evt.getSource() == usernamefield)                commButton.connectORsend();    }  public void keyPressed(KeyEvent e)        {          char x;          if((x = e.getKeyChar()) == e.VK_ENTER) {                e.consume();                commButton.connectORsend();          }        }  public void keyTyped(KeyEvent e)        {        }  public void keyReleased(KeyEvent e)        {        }  //  // Para la interfaz grafica  //  static TextArea outgoingText = null;  Label nicknameLabel = new Label("your nickname: ", Label.RIGHT);  static TextArea incomingText = new TextArea(10, 20);  TextField usernamefield = new TextField(10);  static CommButton commButton = null;  QuitButton quitButton = null;  static Label statusLabel = new Label ("not connected.", Label.LEFT);  public void init () {        setLayout(new BorderLayout());        outgoingText = new TextArea( 4, 20);        outgoingText.addKeyListener(this);        commButton = new CommButton("Connect", outgoingText, usernamefield,statusLabel);        commButton.addActionListener(this);        quitButton = new QuitButton("Quit");        quitButton.addActionListener(this);        usernamefield.addActionListener(this);        // Crear paneles        Panel topPanel    = new Panel();        Panel centerPanel = new Panel();        Panel bottomPanel = new Panel();        topPanel.setLayout        (new BorderLayout());        centerPanel.setLayout (new BorderLayout());        bottomPanel.setLayout (new BorderLayout());        Label discussionLabel = new Label ("Discussion Area:", Label.LEFT);        Label postLabel = new Label ("Post Area:", Label.LEFT);        Label padLabel = new Label ("                    ", Label.LEFT);        // Agregar componentes al panel superior        //      topPanel.add ("North", titleLabel);        topPanel.add ("Center", discussionLabel);        // Agregar componentes al panel central        centerPanel.add ("North", incomingText );        centerPanel.add ("Center", postLabel);        centerPanel.add ("South", outgoingText );        // incoming no es editable pero outgoing si (en start())        incomingText.setEditable(false);        //      Font f = new Font("Courier",Font.PLAIN,12);        //    incomingText.setFont(f);        disableOutgoingText();        Panel usernameAndButton = new Panel();        usernameAndButton.add (usernamefield);        usernameAndButton.add (commButton);        usernameAndButton.add (quitButton);        // Agregar componentes al panel inferior        bottomPanel.add("West", nicknameLabel);        bottomPanel.add("Center", usernameAndButton);        bottomPanel.add("East", padLabel);        bottomPanel.add("South", statusLabel);        // Agregar artefactos y paneles        add("North", topPanel);        add("Center", centerPanel);        add("South", bottomPanel);        // Partimos el lector de mensajes        msgReader = new MsgReader (incomingText, statusLabel, commButton);        msgReader.start();        resize (getMinimumSize());  }  public void start()        {          // Donde ?          host = getCodeBase().getHost();  // what the fuck is this?        }  static void disableOutgoingText ()        {          outgoingText.setEditable(false);        }  static void enableOutgoingText ()        {          outgoingText.setEditable(true);        }  public void destroy()        {          msgReader.stop();          closeall();        }  public Dimension getMinimumSize()        {          return new Dimension(370,430);        }  public Dimension getPreferredSize()        {          return getMinimumSize();        }} // end of wirc appletclass parser // maybe make this a thread{  String toParse = null;   // that which we will be parsing  String toSend = null;  String toShow = null;  parser(String s)        {          toParse = s;        }  parser()        {        }  String whatShouldISend()        {          return toSend;        }  String whatShouldIShow()        {          return toShow;        }  // the following has to be run on parsed text  String breakLines(TextArea fitHere, Font usedFont,String breakThis)        {          int fragwidth = 0;          int thisSpace = 0;          int previousSpace = 0;          String brokenText = "";          String goodFragment = "";          String previousFragment = "";          String theRest = "";          String padding = "  ";          Dimension d = fitHere.getSize();          int useWidth = d.width - 25; // 25 for scrollerspace          FontMetrics fm = fitHere.getFontMetrics(usedFont);          // if the line is longer than the space available and there's a place we could break it,          String firstWord = breakThis.substring(0,breakThis.indexOf(' '));          if (fm.stringWidth(breakThis) > useWidth && fm.stringWidth(firstWord) <useWidth) {                while (fragwidth < useWidth) {                  previousSpace = thisSpace;                  thisSpace = 1+ breakThis.indexOf(' ',previousSpace);                  if (thisSpace == 0  || thisSpace ==breakThis.length()  ) // debugging                        return breakThis;                  while (breakThis.charAt(thisSpace) == ' ') {                        thisSpace++;                  }                  previousFragment = goodFragment;                  goodFragment = breakThis.substring(0,thisSpace).trim();                  fragwidth = fm.stringWidth(goodFragment);                }                theRest = breakThis.substring(previousSpace);                brokenText = previousFragment + "\n"+ padding + breakLines(fitHere,usedFont,padding + theRest);          }          else {                //              System.out.println ("done!");                brokenText = breakThis;          }          return brokenText.trim();        }  // finds the TIMEth appearance of string SEEKING  startstop minigrep(String seeking,int time)        {          startstop answer = new startstop(0,0);          int seekSize = seeking.length();          int baseSize = toParse.length();          int j = 1;          String test = null;          for (int i = 0; i < baseSize-seekSize ; i++) {                test = toParse.substring(i,i+seekSize);                if (test.equals(seeking))                  {                        if (j == time)                          {                                answer.start = i;                                answer.stop = i+seekSize;                                return(answer);                          }                        else                          j++;                  }          }          // the following is probably not ever needed          return(answer);        }  class startstop  {        int start = 0;        int stop = 0;        startstop()          {          }        startstop(int strt, int stp)          {                start = strt;                stop = stp;          }        void reset()          {                start = 0;                stop = 0;          }  }}class incomingParse  extends parser{  incomingParse(String s)        {          toParse = s;          int j=0;          String test = null;          startstop answer = new startstop(0,0);          boolean done = false;          // start PING check          test = toParse.substring(0,4);          if (test.equals("PING"))                {                  wirc.sout.send("PONG " + wirc.host + "\r\n");                  wirc.statusLabel.setText("I have been pinged. " + toParse);                  toShow = "* You have been pinged.";                }  // ends ping test          // start PRIVMSG test          answer = minigrep("PRIVMSG",1);          if (answer.start > 0) {                answer.reset();                answer = minigrep(":",2);                int meatstart = answer.start;                String meat = toParse.substring(meatstart+1,toParse.length());                answer.reset();                answer = minigrep("!",1);                String talker = toParse.substring(1,answer.start);                answer.reset();                answer = minigrep("ACTION",1);                if (answer.start > 0)                  toShow = "* " + talker + meat.substring(7,meat.length());                else                  toShow = "<" + talker + "> " + meat;                done = true;          }          // start JOIN test          if (!done) {                answer = minigrep("JOIN",1);                if (answer.stop > 0) {                  answer.reset();                  answer = minigrep("!",1);                  String talker = toParse.substring(1,answer.start);                  toShow =  "* " + talker + " has joined channel " + wirc.channel + ".";                  done = true;                }          }          // start NICK test          if (!done) {                answer = minigrep("NICK",1);                if (answer.stop > 0) {                  answer.reset();                  answer = minigrep("!",1);                  String talker = toParse.substring(1,answer.start);                  int meatstart = toParse.lastIndexOf(':');                  String meat = toParse.substring(meatstart+1,toParse.length());                  toShow =  "* " + talker + " is now known as " + meat + ".";                  done = true;                }          }          // start PART test          if (!done) {                answer = minigrep("PART",1);                if (answer.stop > 0) {                  answer.reset();                  answer = minigrep("!",1);                  String talker = toParse.substring(1,answer.start);                  toShow =  "* " + talker + " has left the channel.";                  done = true;                }          }          // start QUIT test          if (!done) {                answer = minigrep("QUIT",1);                if (answer.stop > 0) {                  answer.reset();                  answer = minigrep("!",1);                  String talker = toParse.substring(1,answer.start);                  int meatstart = toParse.lastIndexOf(':');                  String meat = toParse.substring(meatstart+1,toParse.length());                  toShow =  "* " + talker + " has quit. " + meat;                  done = true;                }          }          // start MODE test          if (!done) {                answer = minigrep("MODE",1);                if (answer.stop > 0) {                  String meat = new String("");                  int meatstart = 0;                  String modechanger = new String("");                  int modewordend = answer.stop;                  answer.reset();                  answer = minigrep("!",1);                  if (answer.stop > 0) { // it's somebody else changing the mode                        modechanger = toParse.substring(1,answer.start);                        meatstart = modewordend+ wirc.channel.length()+2;                        meat = toParse.substring(meatstart,toParse.length());                  }                  else {   // I changed the mode                        modechanger = wirc.nickname;                        meatstart = 2*wirc.nickname.length()+8;                        meat = toParse.substring(meatstart,toParse.length());                  }                  toShow =  "* " + modechanger + " has changed the mode of the channel " + meat;                  done = true;                }          }          // start KICK test          if (!done) {                answer = minigrep("KICK",1);                if (answer.stop > 0) {                  String kickee = new String("");                  int kickwordend = answer.stop;                  answer.reset();                  answer = minigrep("!",1);                  String kicker = toParse.substring(1,answer.start);                  int meatstart = toParse.lastIndexOf(':');                  String meat = toParse.substring(meatstart+1,toParse.length());                  kickee = toParse.substring(kickwordend+wirc.channel.length()+2,meatstart);                  toShow =  "* " + kicker + " has kicked " + kickee + " from the channel.  " + meat;                  done = true;                }          }          // start initial topic test          if (!done) {                startstop smTest = new startstop(0,0);                answer = minigrep("332",1);                smTest = minigrep(":",1);                if (smTest.start == 0 && answer.stop > 0) {                  answer.reset();                  answer = minigrep(":",2);                  String meat = toParse.substring(answer.stop,toParse.length());                  toShow =  "* Our topic is \"" + meat + "\"";                  done = true;                }          }          // parse found nothing to deal with          if (!done)                toShow = toParse;        } // end of the crazy long constructor}class outgoingParse  extends parser{  // a very long and elaborate constructor  boolean isServerCommand = false;  outgoingParse(String s)        {          toParse = s;          String whatItyped = toParse;          String test = whatItyped.substring(0,1);          if (test.equals("/"))                {                  // I have a control message to worry about                  // msg                  test = whatItyped.substring(1,4);                  if (test.equals("MSG") || test.equals("msg"))                          {                                String submeat = whatItyped.substring(5,whatItyped.length());                                int namemark = submeat.indexOf(' ');                                String target = submeat.substring(0,namemark);                                String subsubmeat = submeat.substring(namemark,submeat.length());                                toSend = "PRIVMSG " + target + " :" + subsubmeat + "\r\n";                                toShow =  "-> *" + target + "* " + subsubmeat + "\n";                          }                  // kick                  test = whatItyped.substring(1,5);                  if (test.equals("kick") || test.equals("KICK"))                          {                                String target = null;                                String reason = "";                                String submeat = whatItyped.substring(6,whatItyped.length());                                int namemark = submeat.indexOf(' ');                                if (namemark == -1)                                  {                                        target = submeat;                                  }                                else                                  {                                  target = submeat.substring(0,namemark);                                  reason = submeat.substring(namemark+1,submeat.length());                                  }                                toSend = "KICK " + wirc.channel + " " + target + " :" + reason + "\r\n";                                toShow = "";                          }                  // join   (PART and JOIN, since this is a single-channel client)                  if (test.equals("join") || test.equals("JOIN"))                        {                          String newChannel = null;                          String meatyBit = whatItyped.substring(6,whatItyped.length());                          int endChannel = meatyBit.indexOf(' ');                          if (endChannel == -1)                                {                                  newChannel = meatyBit;                                }                          else                                {                                  newChannel = meatyBit.substring(0,endChannel);                                  //                              comment = meatyBit.substring(endChannel+1,meatyBit.length());                                }                          String oldChannel = wirc.channel;                          wirc.channel = newChannel;                          toSend = "PART " + oldChannel + "\r\n" + "JOIN " + newChannel + "\r\n";                          toShow = "";                        }                  //me   (ACTION)                  test = whatItyped.substring(1,3);                  if (test.equals("ME") || test.equals("me"))                        {                          String submeat = whatItyped.substring(4,whatItyped.length());                          String marker = "\u0001";                          toSend = "PRIVMSG " + wirc.channel + " :" + marker + "ACTION " + submeat + marker + "\r\n";                          toShow = "* " + wirc.nickname + " " + submeat + "\n";                          }                  isServerCommand = true;                }          else                {                  isServerCommand = false;                  toSend = "PRIVMSG " + wirc.channel + " :" + whatItyped + "\r\n";                  toShow = "> " + whatItyped + "\n";                }        }  // end of constructor  boolean isCommand()        {          return isServerCommand;        }} // ends outgoingParseclass MsgReader extends Thread{  TextArea Output = null;  Label statusLabel = null;  CommButton commButton = null;  MsgReader (TextArea output, Label _statusLabel, CommButton _commButton)        {          Output = output;          statusLabel = _statusLabel;          commButton = _commButton;        }  public void run() {        for (;;)          {                suspend();   // suspends the thread                try {                  // Leemos el mensaje                  for (;;) {                        String line = wirc.sin.readLine();                        if (line == null) break;                        incomingParse readParser = new incomingParse(line);                        String printLine = readParser.breakLines(wirc.incomingText,wirc.incomingText.getFont(),readParser.whatShouldIShow());                        // if a VERSION or something came in that I need to deal with, I probably want to deal with                        // it out here. PONGs too.                        if (printLine == null) break;                        Output.append (printLine + "\n");                        yield();  // causes the currently executing thread to yield                  }                } catch (IOException e) {                  System.out.println ("Error reading message.");                  System.out.println (e);                } finally {                  statusLabel.setText (" Server died, please restart it.");                  commButton.disconnect();                }          }  } // ends run  static void exit () {        System.out.println (" Server terminated. Connection closed.");        System.exit(0);  }}class outgoingMesg extends PrintWriter{  //  String message = null;  outgoingMesg(OutputStream ostream) {        super(ostream);        //      message = s;        //      out = ostream;  }  void send (String s) {        println(s);        flush();  }}class QuitButton extends Button{  QuitButton(String label) {        super(label);  }  void actionQuit(ActionEvent evt,String adiosMesg)        {          if (adiosMesg == "") {                adiosMesg = "adios";          }          String msg_toSend = "QUIT :" + adiosMesg + "\r\n";          wirc.sout.send(msg_toSend);          wirc.msgReader.stop();          wirc.closeall();          //      wirc.quit();        }  // this is the only one that's getting used right now  void actionQuit(ActionEvent evt)        {          if (wirc.commButton.IsConnected() == true) {                String adiosMesg = "adios";                String msg_toSend = "QUIT :" + adiosMesg + "\r\n";                wirc.sout.send(msg_toSend);                wirc.msgReader.stop();                wirc.closeall();                wirc.commButton.connected = false;                //        wirc.quit();          }        }}class CommButton extends Button                                                 //implements ActionListener{  TextArea outgoingText = null;  TextField usernameField = null;  Label statusLabel = null;  boolean connected = false;  CommButton (String label, TextArea textArea, TextField _usernameField, Label _statusLabel) {        super (label);        outgoingText = textArea;        usernameField = _usernameField;        statusLabel = _statusLabel;  }  synchronized boolean IsConnected()        {          return (connected);        }  synchronized void disconnect()        {          connected = false;          statusLabel.setText ("Connection Lost.");          setLabel ("Connect");          wirc.disableOutgoingText();        }  void connectORsend()        {          if (!IsConnected())                {                  actionConnect();                }          else           {                 actionSend();           }        }  //  void actionSend (ActionEvent evt)  void actionSend()        {          wirc.nickname = usernameField.getText();          String message = outgoingText.getText();          outgoingText.setText("");          // Enviamos el mensaje final.          outgoingParse outParser = new outgoingParse(message);          String msg_shown = new String();          if (outParser.isCommand() == true)                msg_shown = outParser.whatShouldIShow();          else                msg_shown = outParser.breakLines(wirc.incomingText,wirc.incomingText.getFont(),outParser.whatShouldIShow());          wirc.incomingText.append(msg_shown+"\n");          String msg_toSend = outParser.whatShouldISend();          wirc.sout.send(msg_toSend);          if (IsConnected())                statusLabel.setText ("Message sent.");        }  //  void actionConnect (ActionEvent evt)  void actionConnect ()        {          //      System.out.println("actionConnect\n");          wirc.nickname = usernameField.getText();          if ( !wirc.nickname.equals("") )                {                  // Conectamos                  try {                        // Creamos el socket                        wirc.socket = new Socket (wirc.host, wirc.port);                        // Creamos stream de escritura sobre el socket                        wirc.sout = new outgoingMesg(wirc.socket.getOutputStream());                        // Creamos stream de lectura sobre el socket                        wirc.sin = new                          BufferedReader ( new InputStreamReader(wirc.socket.getInputStream()) );                        // do we have some kind of error message if this doesn't work?                        statusLabel.setText(" Connected to " + wirc.socket.getInetAddress() + ":" + wirc.socket.getPort() );                        // As dictated by RFC1459...                        // first, we send the PASS message                        wirc.sout.send("PASS " + wirc.password + "\r\n");                        // then we send the NICK message                        wirc.sout.send("NICK " + wirc.nickname + "\r\n");                        // finally, we send the USER message                        wirc.sout.send ("USER " + wirc.username + " localhost " + wirc.host + ":" + wirc.realname + "\r\n");                        //as a temporary kludge                        wirc.sout.send("JOIN " + wirc.channel + "\r\n");                        // partimos (puede ser de nuevo) el thread de lectura de mensajes                        wirc.msgReader.resume();                        connected = true;                        setLabel ("Send");                        // Habilita para escribir...                        wirc.enableOutgoingText();                  } catch (IOException e) {                        System.err.println (e);                        statusLabel.setText(" Server not running. Start it first.");                  }                } // if name != ""          else                {                  statusLabel.setText ("Please set your nickname first");                }        } // actionConnect} // Class CommButton