/* * By Dave Makower * Copyright © 1996 by Pencom Web Works, a business unit of Pencom Systems, Inc. * Send inquiries to */ import java.applet.Applet; import java.awt.*; import java.io.*; import java.net.*; import java.util.Vector; import java.util.StringTokenizer; interface EntryObserver { public void sendMessage(String s); } class UserNameDialog extends Frame { Panel topPanel; Label nameLabel; TextField nameEntry; Panel buttonPanel; Button okButton; String name = null; boolean done = false; public UserNameDialog() { super("Enter User Name"); synchronized (this) done = false; name = null; setLayout(new BorderLayout(20, 20)); // The top panel topPanel = new Panel(); topPanel.setLayout(new BorderLayout()); nameLabel = new Label("Enter User Name "); nameEntry = new TextField(25); topPanel.add("West", nameLabel); topPanel.add("East", nameEntry); this.add("North", topPanel); // The bottom panel buttonPanel = new Panel(); okButton = new Button("OK"); buttonPanel.add(okButton); this.add("South", buttonPanel); pack(); // layout(); show(); } public boolean action(Event evt, Object what) { if (evt.target.equals(okButton) || evt.target.equals(nameEntry)) { name = nameEntry.getText(); synchronized (this) done = true; this.hide(); this.dispose(); return true; } else { return super.action(evt, what); } } public boolean handleEvent(Event evt) { switch (evt.id) { case (Event.WINDOW_DESTROY): { this.hide(); this.dispose(); return true; } default: { return super.handleEvent(evt); } } } synchronized boolean isDone() { return done; } synchronized String getResult() { return (name != null)? name : null; } } class EntryPanel extends Panel { TextArea inputArea; Button sendButton; EntryObserver observer; public EntryPanel(EntryObserver obs) { observer = obs; setLayout(new BorderLayout()); inputArea = new TextArea(5, 50); sendButton = new Button("Send"); this.add("North", inputArea); this.add("South", sendButton); } public boolean action(Event e, Object what) { if (e.target.equals(sendButton)) { observer.sendMessage(inputArea.getText()); inputArea.setText(""); return true; } else { return super.action(e, what); } } public boolean keyDown(Event evt, int key) { if (key == '\n') { observer.sendMessage(inputArea.getText()); inputArea.setText(""); return true; } else { return super.keyDown(evt, key); } } public boolean gotFocus(Event evt, Object what) { inputArea.requestFocus(); return super.gotFocus(evt, what); } } class UserList extends List { Vector users; public UserList() { users = new Vector(); } synchronized public void createList(String delimitedNames) { delItems(0, countItems() - 1); users = new Vector(); StringTokenizer st = new StringTokenizer(delimitedNames, "|", false); while(st.hasMoreTokens()) { String name = st.nextToken(); users.addElement(name); addItem(name); } } synchronized public void addUser(String name) { users.addElement(name); addItem(name); } synchronized public void removeUser(String name) { while (users.contains(name)) { int i = users.indexOf(name); delItem(i); users.removeElement(name); } } } public class LittleChat extends Applet implements EntryObserver, Runnable, ChatCodes { Panel topPanel; Button enterButton; Button leaveButton; TextArea conversationArea; EntryPanel entryPanel; Panel userPanel; UserList userList; Label userLabel; String userName = null; Socket socket = null; int port; String host; int DEFAULT_PORT = 6789; boolean connected = false; PipedInputStream receivePipeIn; PipedOutputStream receivePipeOut; PipedOutputStream transmitPipeOut; PipedInputStream transmitPipeIn; PrintStream out; DataInputStream in; StreamPump transmitPump; StreamPump receivePump; Thread myThread; public void init() { socket = null; setLayout(new BorderLayout()); topPanel = new Panel(); enterButton = new Button("Connect"); leaveButton = new Button("Disconnect"); topPanel.add(enterButton); topPanel.add(leaveButton); this.add("North", topPanel); conversationArea = new TextArea(15, 50); conversationArea.setEditable(false); userList = new UserList(); userPanel = new Panel(); userLabel = new Label("User List"); userPanel.setLayout(new BorderLayout()); userPanel.add("North", userLabel); userPanel.add("Center", userList); entryPanel = new EntryPanel(this); this.add("Center", conversationArea); this.add("West", userPanel); this.add("South", entryPanel); this.layout(); entryPanel.requestFocus(); this.show(); } public void start() { myThread = new Thread(this); myThread.start(); } public void run() { String line; if (!connected) { openConnection(); } if (connected) { enterButton.disable(); leaveButton.enable(); } if (connected && (userName == null)) { userName = setUserName(); if (userName == null) { return; } else { sendMessage(_SET_USER_NAME, userName); sendMessage(_REQUEST_USER_LIST, userName); } } try { while (connected && (myThread != null)) { // block until there is input line = in.readLine(); if (line == null) { connected = false; } else { receiveMessage(line); // conversationArea.appendText(line); // conversationArea.appendText("\n"); } } } catch (IOException e4) { disconnect(); } } void receiveMessage(String s) { // parse the string into a message object Message msg = new Message(s, null); switch (msg.getCode()) { case (_NORMAL_MESSAGE): { conversationArea.appendText(msg.getUser() + ": "); conversationArea.appendText(msg.getText()); conversationArea.appendText("\n"); return; } case (_ADD_NEW_USER): { // Not Yet Implemented userList.addUser(msg.getText()); return; } case (_REMOVE_USER): { // Not Yet Implemented userList.removeUser(msg.getText()); return; } case (_USER_LIST): { userList.createList(msg.getText()); return; } default: { // XXX: not needed? return; } } } private protected String setUserName() { UserNameDialog dialog = new UserNameDialog(); String name; while (! dialog.isDone()) { try { myThread.sleep(250); } catch (InterruptedException e) { return null; } } name = dialog.getResult(); // FOR DEBUGGING try { System.err.println("LittleChat client got user name: " + name); } catch (NullPointerException npe) { System.err.println("Error getting user name: got null."); } return name; } synchronized void openConnection() { // Where do we connect to? try { port = Integer.parseInt(getParameter("port")); } catch (Exception e1) { port = DEFAULT_PORT; } host = getCodeBase().getHost(); try { // Create the socket socket = new Socket(host, port); connected = true; // Set up the pipes to and from the pumps receivePipeIn = new PipedInputStream(); receivePipeOut = new PipedOutputStream(receivePipeIn); transmitPipeOut = new PipedOutputStream(); transmitPipeIn = new PipedInputStream(transmitPipeOut); // These are the higher-level streams we'll use out = new PrintStream(transmitPipeOut); in = new DataInputStream(receivePipeIn); // Create transmit and receive pumps // (they start automatically on construction) receivePump = new StreamPump(socket.getInputStream(), receivePipeOut, myThread); transmitPump = new StreamPump(transmitPipeIn, socket.getOutputStream(), myThread); return; } catch (IOException e4) { disconnect(); } } public void sendMessage(String text) { sendMessage(_NORMAL_MESSAGE, text); } public void sendMessage(int code, String text) { Message m = new Message(code, userName, text, null); out.println(m.toString()); } public synchronized void stop() { myThread = null; } public void destroy() { disconnect(); } public synchronized void disconnect() { try { sendMessage(_CLOSE_CONNECTION, " "); wait(1000); socket.close(); in.close(); out.close(); } catch (Exception e); // ignore any exceptions from closing streams finally { enterButton.enable(); leaveButton.disable(); userList.createList(" "); // clear the user list connected = false; myThread = null; receivePump = null; transmitPump = null; userName = null; } } public boolean action(Event e, Object what) { if (e.target.equals(enterButton)) { myThread = new Thread(this); myThread.start(); return true; } else if (e.target.equals(leaveButton)) { disconnect(); return true; } else { return super.action(e, what); } } }