//******************************************************************** // client.java //******************************************************************** // Implements the client side of a Java based client/server chat system. // // Version History: // 1.00 M. Ayers 2/3/97 // Base version, contains comments and 'looks nice' // // 1.01 M. Ayers 2/16/97 // Added colors, added labels for title, channel, user. // // 1.02 M. Ayers 2/25/97 // Added preferences for fonts and colors. // // 1.03 R. Ptashka 3/10/97 // Integrated and re-implemented word wrapping. // // 1.04 M. Ayers 4/20/97 // Added number of users per channel, and filtering status. //******************************************************************** import java.awt.*; import java.util.*; import java.applet.*; import java.io.*; import java.net.*; public class client extends Applet { TextArea messageDisplay; // AWT Declarations. TextField channel, user, message; List channelList, userList; Button goChannel, addChannel, filter, unfilter, status, clear; Label titleLabel, channelLabel, userLabel; Socket network_client; // Networking Declarations. DataInputStream net_input; PrintStream net_output; Font fnt; FontMetrics fm; Graphics g; String username, host, startchannel, fontname; //Input Parameters Integer temp; int fontsize; Color color1, color2, color3, color4, color5, color6, color7, color8; boolean connected = false; writer w; public Color stringColor(String name) { if (name.equals("black")) { return (Color.black); } if (name.equals("blue")) { return (Color.blue); } if (name.equals("cyan")) { return (Color.cyan); } if (name.equals("darkGrey")) { return (Color.darkGray); } if (name.equals("gray")) { return (Color.gray); } if (name.equals("green")) { return (Color.green); } if (name.equals("lightGray")) { return (Color.lightGray); } if (name.equals("magenta")) { return (Color.magenta); } if (name.equals("orange")) { return (Color.orange); } if (name.equals("pink")) { return (Color.pink); } if (name.equals("red")) { return (Color.red); } if (name.equals("white")) { return (Color.white); } if (name.equals("yellow")) { return (Color.yellow); } return (Color.black); } // AWT Constructors, using Gridbag placements. public Button makebutton(String name, GridBagLayout gridbag, GridBagConstraints c) { Button button = new Button(name); gridbag.setConstraints(button, c); add(button); return (button); } public TextArea maketextarea(String name, int rows, int columns, GridBagLayout gridbag, GridBagConstraints c) { TextArea textarea = new TextArea(name, rows, columns); gridbag.setConstraints(textarea, c); add(textarea); return (textarea); } public TextField maketextfield(String name, int columns, GridBagLayout gridbag, GridBagConstraints c) { TextField textfield = new TextField(name, columns); gridbag.setConstraints(textfield, c); add(textfield); return (textfield); } public List makelist(int rows, GridBagLayout gridbag, GridBagConstraints c) { List list = new List(rows, false); gridbag.setConstraints(list, c); add(list); return(list); } public Label makelabel(String name, GridBagLayout gridbag, GridBagConstraints c) { Label label = new Label(name); gridbag.setConstraints(label, c); add(label); return(label); } // Applet initialization. public void init() { fontname = getParameter("FONTNAME"); temp = new Integer (getParameter("FONTSIZE")); fontsize = temp.intValue(); color1 = stringColor(getParameter("COLOR1")); color2 = stringColor(getParameter("COLOR2")); color3 = stringColor(getParameter("COLOR3")); color4 = stringColor(getParameter("COLOR4")); color5 = stringColor(getParameter("COLOR5")); color6 = stringColor(getParameter("COLOR6")); color7 = stringColor(getParameter("COLOR7")); color8 = stringColor(getParameter("COLOR8")); GridBagLayout gridbag = new GridBagLayout(); //User Interface setup. GridBagConstraints c = new GridBagConstraints(); fnt = new Font(fontname, Font.PLAIN, fontsize); //Set font. setFont(fnt); setBackground (color2); setForeground (color1); setLayout(gridbag); c.weightx = 6.0; c.fill = GridBagConstraints.BOTH; c.gridwidth = 40; c.gridheight = 9; c.weighty = 1.0; c.insets.right = 5; c.insets.bottom = 5; c.insets.top = 5; c.insets.left = 5; messageDisplay = maketextarea("Message Display Area\n", 20, 40, gridbag, c); messageDisplay.setEditable (false); g = messageDisplay.getGraphics(); fm = g.getFontMetrics(fnt); messageDisplay.setBackground (color4); messageDisplay.setForeground (color3); c.weightx = 1.0; c.insets.right = 0; c.insets.bottom = 0; c.insets.top = 0; c.insets.left = 0; c.gridwidth = GridBagConstraints.REMAINDER; c.gridheight = 1; c.insets.right = 5; c.insets.top = 5; channelLabel = makelabel("Channel Information",gridbag, c); c.insets.top = 0; channel = maketextfield("Channel", 10, gridbag, c); channel.setBackground (color6); channel.setForeground (color5); channelList = makelist(6, gridbag, c); channelList.setBackground (color6); channelList.setForeground (color5); c.gridwidth = GridBagConstraints.RELATIVE; goChannel = makebutton("Go To Channel", gridbag, c); goChannel.setBackground (color8); goChannel.setForeground (color7); c.gridwidth = GridBagConstraints.REMAINDER; addChannel = makebutton("Add Channel", gridbag, c); addChannel.setBackground (color8); addChannel.setForeground (color7); c.insets.top = 5; userLabel = makelabel("User Information", gridbag, c); c.insets.top = 0; user = maketextfield("User", 10, gridbag, c); user.setBackground (color6); user.setForeground (color5); c.insets.top = 0; userList = makelist(6, gridbag, c); userList.setBackground (color6); userList.setForeground (color5); c.gridwidth = GridBagConstraints.RELATIVE; filter = makebutton("Filter User", gridbag, c); filter.setBackground (color8); filter.setForeground (color7); c.gridwidth = GridBagConstraints.REMAINDER; unfilter = makebutton("Unfilter User", gridbag, c); unfilter.setBackground (color8); unfilter.setForeground (color7); c.gridwidth = GridBagConstraints.REMAINDER; c.insets.top = 5; status = makebutton("Check Status", gridbag, c); status.setBackground (color8); status.setForeground (color7); c.insets.top = 0; c.gridwidth = 40; c.insets.bottom = 5; c.insets.left = 5; c.weightx = 6.0; message = maketextfield("Enter Text here", 40, gridbag, c); message.setBackground (color6); message.setForeground (color5); c.insets.left = 0; c.insets.bottom = 5; c.weightx = 1.0; clear = makebutton("Clear Text Area", gridbag, c); clear.setBackground (color8); clear.setForeground (color7); c.gridwidth = GridBagConstraints.REMAINDER; // Finished User Interface setup. // Get start parameters and set up initial state. host = getParameter("HOST"); username = getParameter("USERNAME"); userList.addItem(username); userList.select(0); startchannel = getParameter("STARTCHANNEL"); channelList.addItem(startchannel); channelList.select(0); } public void start() { if (connect()) //Check for connection creation. { connected = true; w = new writer(this); w.start(); } else { username = "* NOT CONNECTED *"; return; } } // End Init. boolean connect() //Create network connaction. { messageDisplay.appendText("<<<< Connecting user " + username + " to " + host + " >>>>\n"); messageDisplay.selectAll(); try { network_client = new Socket(host, 1111); } catch (IOException e) { messageDisplay.appendText("<<<< Error...could not connect to host " + e + " >>>>\n"); return false; } messageDisplay.appendText("<<<< Connected to server >>>>\n"); try { net_input = new DataInputStream(network_client.getInputStream()); net_output = new PrintStream (network_client.getOutputStream()); } catch (IOException e ) { messageDisplay.appendText("<<<< Server is NOT ready >>>>\n"); messageDisplay.selectAll(); return false; } write_net_output(username); write_net_output(startchannel); return true; } // End connect. String read_net_input() //Read input from network, one line at a time { try { return net_input.readLine(); } catch (IOException e) { return null; } } void write_net_output(String string) //Write output to network, one line at a time. { net_output.println(string); net_output.flush(); } void close_server() //Close network connection. { try { network_client.close(); } catch (Exception e) { messageDisplay.appendText("<<<< Unable to close server >>>>\n"); } } void word_wrap(String inputdata){ String outputdata=""; //Text to be printed String tempdata; //Temporary data for length counting int counter; Dimension dm=messageDisplay.size(); int area_width; //Width of output string in characters int current_width; int string_width; //Width of output string in pixels tempdata=inputdata; string_width = fm.stringWidth(tempdata); while (string_width > (dm.width-25)) { tempdata=tempdata.substring(0, tempdata.length()-1); string_width = fm.stringWidth(tempdata); } /* endwhile */ area_width = tempdata.length(); if (inputdata.length() > area_width) { tempdata = inputdata; while (inputdata.length() > area_width) { tempdata = inputdata.substring (0, area_width); current_width = tempdata.lastIndexOf(' ')+1; outputdata = inputdata.substring(0, current_width)+ "\n"; messageDisplay.appendText(outputdata); messageDisplay.selectAll(); inputdata = inputdata.substring(current_width); tempdata = inputdata; string_width = fm.stringWidth(tempdata); while (string_width > (dm.width-25)) { tempdata=tempdata.substring(0, tempdata.length()-1); string_width = fm.stringWidth(tempdata); area_width = tempdata.length(); } /* endwhile */ if (area_width > inputdata.length()) { messageDisplay.appendText(inputdata); messageDisplay.selectAll(); break; } /* endif */ } /* endwhile */ } else { messageDisplay.appendText(inputdata); messageDisplay.selectAll(); } } //end word_wrap public boolean handleEvent(Event e) //Handlers for all AWT events. { String string = "error"; switch (e.id) { case Event.KEY_RELEASE: if (e.target.equals(channel)) //Hilite matching entry in channel list. { for (int i = 0; i < channelList.countItems(); ++i) { if (channelList.getItem(i).startsWith( channel.getText())) { channelList.select(i); } } } if (e.target.equals(user)) //Hilite matching entry in user list. { for (int i = 0; i < userList.countItems(); ++i) { if (userList.getItem(i).startsWith( user.getText())) { userList.select(i); } } } break; case Event.LIST_SELECT: if (e.target.equals(channelList)) //Display selected item in channel box. { string = channelList.getSelectedItem(); if (string.indexOf(" ") != -1) { string = string.substring(0,string.indexOf(" ")); } channel.setText(string); } if (e.target.equals(userList)) //Display selected item in user box. { string = userList.getSelectedItem(); if (string.indexOf(" ") != -1) { string = string.substring(0,string.indexOf(" ")); } user.setText(string); } break; case Event.ACTION_EVENT: //Button handlers. if (e.target.equals(goChannel)) { if (connected) { string = channelList.getSelectedItem(); if (string.indexOf(" ") != -1) { string = string.substring(0,string.indexOf(" ")); } write_net_output("GO&" + string); } messageDisplay.appendText("<<<< Go to channel " + string + " >>>>\n"); messageDisplay.selectAll(); } if (e.target.equals(addChannel)) { int j = 0; for (int i = 0; i < channelList.countItems(); ++i) { string = channelList.getItem(i); if (string.indexOf(" ") != -1) { string = string.substring(0,string.indexOf(" ")); } if (string.equals( channel.getText() )) { j = 1; messageDisplay.appendText("<<<< Channel " + channel.getText() + " already exists. >>>>\n"); } } if (j == 0) { if (connected) { write_net_output("ADDCHANNEL&" + channel.getText()); } messageDisplay.appendText("<<<< Add channel " + channel.getText() + " >>>>\n"); messageDisplay.selectAll(); } } if (e.target.equals(filter)) { if (connected) { string = userList.getSelectedItem(); if (string.indexOf(" ") != -1) { string = string.substring(0,string.indexOf(" ")); } write_net_output("FILTER&" + string); } messageDisplay.appendText("<<<< Filter User " + string + " >>>>\n"); messageDisplay.selectAll(); } if (e.target.equals(unfilter)) { if (connected) { string = userList.getSelectedItem(); if (string.indexOf(" ") != -1) { string = string.substring(0,string.indexOf(" ")); } write_net_output("UNFILTER&" + string); } messageDisplay.appendText("<<<< Unfilter User " + string + " >>>>\n"); messageDisplay.selectAll(); } if (e.target.equals(status)) { if (connected) { write_net_output("STATUS&"); } messageDisplay.appendText("<<<< Server and User Status >>>>\n"); messageDisplay.selectAll(); } if (e.target.equals(clear)) { messageDisplay.setText(""); message.setText(""); } if (e.target.equals(message)) { String text= message.getText(); if (text.equals("")) //Check for empty message. { } else { if (connected) { write_net_output("TEXT&" + message.getText()); //Send message to server. word_wrap("You say: " + message.getText() + "\n"); } else { messageDisplay.appendText("<<<< No connection. Can't send message >>>>\n"); } message.setText(""); } } break; default: return false; } return false; } // End HandleEvent. public void display() //Update user interface based on network activity. { String string, channel, number; if (w.net_line.startsWith("TEXT&")) { word_wrap(w.net_line.substring(5) + "\n"); } if (w.net_line.startsWith("GO&")) { for (int i = 0; i < channelList.countItems(); ++i) { string = channelList.getItem(i); if (string.indexOf(" ") != -1) { string = string.substring(0,string.indexOf(" ")); } if (string.equals(w.net_line.substring(3))) { channelList.select(i); } } userList.clear(); userList.addItem(username); userList.select(0); } if (w.net_line.startsWith("ADDCHANNEL&")) { int j = 0; channel = w.net_line.substring(11); if (channel.indexOf("&") != -1) { number = channel.substring(channel.indexOf("&") + 1); channel = channel.substring(0,channel.indexOf("&")); } else { number = ""; } for (int i = 0; i < channelList.countItems(); ++i) { string = channelList.getItem(i); if (string.indexOf(" ") != -1) { string = string.substring(0,string.indexOf(" ")); } if (string.equals(channel)) { channelList.replaceItem(channel + " ( " + number + " )", i); j = 1; } } if (j == 0) { channelList.addItem(channel + " ( " + number + " )"); } } if (w.net_line.startsWith("ADDUSER&")) { int j = 0; for (int i = 0; i < userList.countItems(); ++i) { if (userList.getItem(i).equals( w.net_line.substring(8))) { j = 1; } } if (j == 0) { userList.addItem(w.net_line.substring(8)); } } if (w.net_line.startsWith("REMOVECHANNEL&")) { for (int i = 0; i < channelList.countItems(); ++i) { string = channelList.getItem(i); if (string.indexOf(" ") != -1) { string = string.substring(0,string.indexOf(" ")); } if (string.equals(w.net_line.substring(14))) { channelList.delItem(i); } } } if (w.net_line.startsWith("REMOVEUSER&")) { for (int i = 0; i < userList.countItems(); ++i) { string = userList.getItem(i); if (string.indexOf(" ") != -1) { string = string.substring(0,string.indexOf(" ")); } if (string.equals(w.net_line.substring(11))) { userList.delItem(i); } } } if (w.net_line.startsWith("FILTER&")) { for (int i = 0; i < userList.countItems(); ++i) { string = userList.getItem(i); if (string.indexOf(" ") != -1) { string = string.substring(0,string.indexOf(" ")); } if (string.equals(w.net_line.substring(7))) { userList.replaceItem(w.net_line.substring(7) + " - Filtered", i); } } messageDisplay.appendText("<<<< Filtering User " + w.net_line.substring(7) + " >>>>\n"); messageDisplay.selectAll(); } if (w.net_line.startsWith("UNFILTER&")) { for (int i = 0; i < userList.countItems(); ++i) { string = userList.getItem(i); if (string.indexOf(" ") != -1) { string = string.substring(0,string.indexOf(" ")); } if (string.equals(w.net_line.substring(9))) { userList.replaceItem(w.net_line.substring(9), i); } } messageDisplay.appendText("<<<< Stopped Filtering User " + w.net_line.substring(9) + " >>>>\n"); messageDisplay.selectAll(); } } // End display. public void stop() { close_server(); w.stop(); } } // End client. class writer extends Thread //Thread to read from network, prevents UI from blocking while reading from network. { String net_line = ""; client c; public writer(client c) { this.c = c; } public void run() { while (true) { String input = c.read_net_input(); //Read a line from the network net_line = input; c.display(); //Call code in UI to update display. System.out.println("String <" + input + ">"); } } } // End writer.