6 Replies - 1801 Views - Last Post: 19 April 2009 - 03:42 PM Rate Topic: -----

#1 pjpro  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 16-April 09

Chat Client and Server, save and delete messages

Posted 16 April 2009 - 02:15 PM

I have made a simple chat app using a client and server(code below). I have added in a second text area which i would like to use to save received messages.

It's basically a simple email type app. I'm not trying to multithread it yet i just want to learn the basics.

Client code
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Client2 extends JFrame {

   private static InetAddress host;   //........
   private JTextField enter;
   private JTextArea display, saved;
   ObjectOutputStream output;
   ObjectInputStream input;
   String message = "";
   JButton deleteBtn;

   public Client2()
   {
	  super( "Client" );

	  enter = new JTextField(400);
	  enter.setEnabled( false );
	  enter.addActionListener(
		 new ActionListener() {
			public void actionPerformed( ActionEvent e )
			{
			   sendData( e.getActionCommand() );
			}
		 }
	  );
	  add( enter, BorderLayout.NORTH );

	  display = new JTextArea();
	  add( new JScrollPane( display ),
			 BorderLayout.CENTER );

	  setSize( 600, 300 );
	  setVisible(true);
	  
	  
	  add( new JButton( "Delete"), BorderLayout.EAST);
	  
	  saved = new JTextArea();
	  add( new JScrollPane( display ),
			 BorderLayout.SOUTH );
	  
	  setSize( 600, 300 );
	  setVisible(true);
	  
   }
   
   public void runClient()
   {
	  Socket client;

	  try {
		 // Step 1: Create a Socket to make connection.
		 display.setText( "Attempting connection\n" );

		 host = InetAddress.getLocalHost();	//...............
		 client = new Socket(host, 50000 );

		 display.append( "Connected to: " +
			client.getInetAddress().getHostName() );

		 // Step 2: Get the input and output streams.
		 output = new ObjectOutputStream(
					  client.getOutputStream() );
		 output.flush();
		 input = new ObjectInputStream(
					 client.getInputStream() );
		 display.append( "\nGot I/O streams\n" );

		 // Step 3: Process connection.
		 enter.setEnabled( true );
		 do {
			try {
			   message = (String) input.readObject();
			   display.append( "\n" + message );
			   display.setCaretPosition(
				  display.getText().length() );
			}
			catch ( ClassNotFoundException cnfex ) {
			   display.append(
				  "\nUnknown object type received" );
			}
		 } while ( !message.equals( "SERVER>>> TERMINATE" ) );

		 // Step 4: Close connection.
		 display.append( "Closing connection.\n" );
		 output.close();
		 input.close();
		 client.close();
	  }
	  catch ( EOFException eof ) {
		 System.out.println( "Server terminated connection" );
	  }
	  catch ( IOException e ) {
		 e.printStackTrace();
	  }
   }

   private void sendData( String s )
   {
	  try {
		 message = s;
		 output.writeObject( "CLIENT1>>> " + s );
		 output.flush();
		 display.append( "\nCLIENT1>>>" + s );
	  }
	  catch ( IOException cnfex ) {
		 display.append(
			"\nError writing object" );
	  }
   }

   public static void main( String args[] )
   {
	  Client2 app = new Client2();
	  app.runClient();
   }
}// end of Client



Server code
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Server extends JFrame {
	
   private JTextField enter;
   private JTextArea display, saved;
   ObjectOutputStream output;
   ObjectInputStream input;

   public Server()
   {
	  super( "Client" );

	  enter = new JTextField();
	  enter.setEnabled( false );
	  enter.addActionListener(
		 new ActionListener() {
			public void actionPerformed( ActionEvent e )
			{
			   sendData( e.getActionCommand() );
			}
		 }
	  );
	  add( enter, BorderLayout.NORTH );

	  display = new JTextArea();
	  add( new JScrollPane( display ),
			 BorderLayout.CENTER );

	  setSize( 600, 300 );
	  setVisible(true);
   
   
	   add( new JButton( "Delete"), BorderLayout.EAST);
		  
		  saved = new JTextArea();
		  add( new JScrollPane( display ),
				 BorderLayout.SOUTH );
		  
		  setSize( 600, 300 );
		  setVisible(true);
   }

   public void runServer()
   {
	  ServerSocket server;
	  Socket connection;
	  int counter = 1;

	  try {
		 // Step 1: Create a ServerSocket.
		 server = new ServerSocket(50000 );

		 while ( true ) {
			// Step 2: Wait for a connection.
			display.setText( "Waiting for connection\n" );
			connection = server.accept();

			display.append( "Connection " + counter +
			   " received from: " +
			   connection.getInetAddress().getHostName() );

			// Step 3: Get input and output streams.
			output = new ObjectOutputStream(
						 connection.getOutputStream() );
			output.flush();
			input = new ObjectInputStream(
						connection.getInputStream() );
			display.append( "\nGot I/O streams\n" );

			// Step 4: Process connection.
			String message =
			   "SERVER>>> Connection successful";
			output.writeObject( message );
			output.flush();
			enter.setEnabled( true );

			do {
			   try {
				  message = (String) input.readObject();
				  display.append( "\n" + message );
				  display.setCaretPosition(
					 display.getText().length() );
			   }
			   catch ( ClassNotFoundException cnfex ) {
				  display.append(
					 "\nUnknown object type received" );
			   }
			} while ( !message.equals( "CLIENT>>> TERMINATE" ) );

			// Step 5: Close connection.
			display.append( "\nUser terminated connection" );
			enter.setEnabled( false );
			output.close();
			input.close();
			connection.close();

			++counter;
		 }
	  }
	  catch ( EOFException eof ) {
		 System.out.println( "Client terminated connection" );
	  }
	  catch ( IOException io ) {
		 io.printStackTrace();
	  }
   }

   private void sendData( String s )
   {
	  try {
		 output.writeObject( "CLIENT2>>> " + s );
		 output.flush();
		 display.append( "\nCLIENT2>>>" + s );
	  }
	  catch ( IOException cnfex ) {
		 display.append(
			"\nError writing object" );
	  }
   }

   public static void main( String args[] )
   {
	  Server app = new Server();

	  app.runServer();
   }
}//end of Server



Thanks in advance for any guidance.

PJ

Is This A Good Question/Topic? 0
  • +

Replies To: Chat Client and Server, save and delete messages

#2 pjpro  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 16-April 09

Re: Chat Client and Server, save and delete messages

Posted 19 April 2009 - 04:40 AM

I have tried to make a chat application that only saves the recieved messages which can then be deleted. I'm having some major problems with it.

Can anyone please point out or correct my coding. I have tried for ages to get this working but with no joy.

Client Code
import java.awt.*;
import java.awt.event.*;
import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.Socket;

import javax.swing.*;
import javax.swing.event.*;

public class Client extends JPanel
					  implements ListSelectionListener {
	private JList save;
	private DefaultListModel saveList;

	private static final String sendString = "Send";
	private static final String deleteString = "Delete";
	private JButton deleteBtn;
	private JTextField enterMsg;   
	private static InetAddress host;
	ObjectOutputStream output;
	ObjectInputStream input;
	String message = "";
	

	public Client() {
		super(new BorderLayout());

		saveList = new DefaultListModel();
		saveList.addElement("Hi How are you?");
		saveList.addElement("I'm ok. How are the kids?");
		saveList.addElement("Thats good to hear. I will have to give you a call for a meeting soon.");
		
		//Create the list and put it in a scroll pane.
		save = new JList(saveList);
		save.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		save.setSelectedIndex(0);
		save.addListSelectionListener(this);
		save.setVisibleRowCount(5);
		JScrollPane listScrollPane = new JScrollPane(save);

		JButton sendBtn = new JButton(sendString);
		SendListener sendListener = new SendListener(sendBtn);
		sendBtn.setActionCommand(sendString);
		sendBtn.addActionListener(sendListener);
		sendBtn.setEnabled(false);

		deleteBtn = new JButton(deleteString);
		deleteBtn.setActionCommand(deleteString);
		deleteBtn.addActionListener(new DeleteListener());

		enterMsg = new JTextField(100);
		enterMsg.addActionListener(sendListener);
		enterMsg.getDocument().addDocumentListener(sendListener);
		String name = saveList.getElementAt(
				save.getSelectedIndex()).toString();

		//Create a panel that uses BoxLayout.
		JPanel buttonPane = new JPanel();
		buttonPane.setLayout(new BoxLayout(buttonPane,
										   BoxLayout.LINE_AXIS));
		buttonPane.add(deleteBtn);
		buttonPane.add(Box.createHorizontalStrut(5));
		buttonPane.add(new JSeparator(SwingConstants.VERTICAL));
		buttonPane.add(Box.createHorizontalStrut(5));
		buttonPane.add(enterMsg);
		buttonPane.add(sendBtn);
		buttonPane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));

		add(listScrollPane, BorderLayout.CENTER);
		add(buttonPane, BorderLayout.PAGE_END);
		
	}

	class DeleteListener implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			//This method can be called only if
			//there's a valid selection
			//so go ahead and remove whatever's selected.
			int index = save.getSelectedIndex();
			saveList.remove(index);

			int size = saveList.getSize();

			if (size == 0) { //Nobody's left, disable firing.
				deleteBtn.setEnabled(false);

			} else { //Select an index.
				if (index == saveList.getSize()) {
					//removed item in last position
					index--;
				}

				save.setSelectedIndex(index);
				save.ensureIndexIsVisible(index);
			}
		}
	}

	//This listener is shared by the text field and the send button.
	class SendListener implements ActionListener, DocumentListener {
		private boolean alreadyEnabled = false;
		private JButton sendBtn;

		public SendListener(JButton button) {
			this.sendBtn = button;
		}

		//Required by ActionListener.
		public void actionPerformed(ActionEvent e) {
			String message = enterMsg.getText();

			//User didn't type in a unique name...
			if (message.equals("") || alreadyInList(message)) {
				Toolkit.getDefaultToolkit().beep();
				enterMsg.requestFocusInWindow();
				enterMsg.selectAll();
				return;
			}

			int index = save.getSelectedIndex(); //get selected index
			if (index == -1) { //no selection, so insert at beginning
				index = 0;
			} else {		   //add after the selected item
				index++;
			}

			saveList.insertElementAt(enterMsg.getText(), index);
			//If we just wanted to add to the end, we'd do this:
			//listModel.addElement(employeeName.getText());

			//Reset the text field.
			enterMsg.requestFocusInWindow();
			enterMsg.setText("");

			//Select the new item and make it visible.
			save.setSelectedIndex(index);
			save.ensureIndexIsVisible(index);
		}

		protected boolean alreadyInList(String name) {
			return saveList.contains(name);
		}

		//Required by DocumentListener.
		public void insertUpdate(DocumentEvent e) {
			enableButton();
		}

		//Required by DocumentListener.
		public void removeUpdate(DocumentEvent e) {
			handleEmptyTextField(e);
		}

		//Required by DocumentListener.
		public void changedUpdate(DocumentEvent e) {
			if (!handleEmptyTextField(e)) {
				enableButton();
			}
		}

		private void enableButton() {
			if (!alreadyEnabled) {
				sendBtn.setEnabled(true);
			}
		}

		private boolean handleEmptyTextField(DocumentEvent e) {
			if (e.getDocument().getLength() <= 0) {
				sendBtn.setEnabled(false);
				alreadyEnabled = false;
				return true;
			}
			return false;
		}
	}

	//This method is required by ListSelectionListener.
	public void valueChanged(ListSelectionEvent e) {
		if (e.getValueIsAdjusting() == false) {

			if (save.getSelectedIndex() == -1) {
			//No selection, disable delete button.
				deleteBtn.setEnabled(false);

			} else {
			//Selection, enable the delete button.
				deleteBtn.setEnabled(true);
			}
		}
	}


	private static void createAndShowGUI() {
		//Create and set up the window.
		JFrame frame = new JFrame("ListDemo");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		//Create and set up the content pane.
		JComponent newContentPane = new ListDemo();
		newContentPane.setOpaque(true); //content panes must be opaque
		frame.setContentPane(newContentPane);

		//Display the window.
		frame.pack();
		frame.setVisible(true);
	}
	
	public void runClient()
	{
	   Socket client;

	   try {
		  // Step 1: Create a Socket to make connection.

		  host = InetAddress.getLocalHost();	//...............
		  client = new Socket(host, 50000 );

		  // Step 2: Get the input and output streams.
		  output = new ObjectOutputStream(
					   client.getOutputStream() );
		  output.flush();
		  input = new ObjectInputStream(
					  client.getInputStream() );

		  // Step 3: Process connection.
		  enterMsg.setEnabled( true );
		  do {
			 try {
				message = (String) input.readObject();
				
				enterMsg.setCaretPosition(
				enterMsg.getText().length() );
			 }
			 catch ( ClassNotFoundException cnfex ) {
			 }
			 
		  } while ( !message.equals( "SERVER>>> TERMINATE" ) );

		  // Step 4: Close connection.
		  output.close();
		  input.close();
		  client.close();
	   }
	   catch ( EOFException eof ) {
		  System.out.println( "Server terminated connection" );
	   }
	   catch ( IOException e ) {
		  e.printStackTrace();
	   }
	}

	private void sendData( String s )
	{
	   try {
		  message = s;
		  output.writeObject( "CLIENT1>>> " + s );
		  output.flush();
	   }
	   catch ( IOException cnfex ) {

	   }

	}

	class FireListener implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			//This method can be called only if
			//there's a valid selection
			//so go ahead and remove whatever's selected.
			int index = save.getSelectedIndex();
			saveList.remove(index);

			int size = saveList.getSize();

			if (size == 0) { //Nobody's left, disable firing.
				deleteBtn.setEnabled(false);

			} else { //Select an index.
				if (index == saveList.getSize()) {
					//removed item in last position
					index--;
				}

				save.setSelectedIndex(index);
				save.ensureIndexIsVisible(index);
			}
		}
	}

	public static void main(String[] args) {
		javax.swing.SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				createAndShowGUI();
			}
		});
	}
}



Server Code
import java.awt.*;
import java.awt.event.*;
import java.io.EOFException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import javax.swing.*;
import javax.swing.event.*;

public class Server extends JPanel
					  implements ListSelectionListener {
	private JList save;
	private DefaultListModel saveList;

	private static final String sendString = "Send";
	private static final String deleteString = "Delete";
	private JButton deleteBtn;
	private JTextField enterMsg;   
	private static InetAddress host;
	ObjectOutputStream output;
	ObjectInputStream input;
	String message = "";
	

	public Server() {
		super(new BorderLayout());

		saveList = new DefaultListModel();
		saveList.addElement("Hi How are you?");
		saveList.addElement("I'm ok. How are the kids?");
		saveList.addElement("Thats good to hear. I will have to give you a call for a meeting soon.");
		
		//Create the list and put it in a scroll pane.
		save = new JList(saveList);
		save.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		save.setSelectedIndex(0);
		save.addListSelectionListener(this);
		save.setVisibleRowCount(5);
		JScrollPane listScrollPane = new JScrollPane(save);

		JButton sendBtn = new JButton(sendString);
		SendListener sendListener = new SendListener(sendBtn);
		sendBtn.setActionCommand(sendString);
		sendBtn.addActionListener(sendListener);
		sendBtn.setEnabled(false);

		deleteBtn = new JButton(deleteString);
		deleteBtn.setActionCommand(deleteString);
		deleteBtn.addActionListener(new DeleteListener());

		enterMsg = new JTextField(100);
		enterMsg.addActionListener(sendListener);
		enterMsg.getDocument().addDocumentListener(sendListener);
		String name = saveList.getElementAt(
				save.getSelectedIndex()).toString();

		//Create a panel that uses BoxLayout.
		JPanel buttonPane = new JPanel();
		buttonPane.setLayout(new BoxLayout(buttonPane,
										   BoxLayout.LINE_AXIS));
		buttonPane.add(deleteBtn);
		buttonPane.add(Box.createHorizontalStrut(5));
		buttonPane.add(new JSeparator(SwingConstants.VERTICAL));
		buttonPane.add(Box.createHorizontalStrut(5));
		buttonPane.add(enterMsg);
		buttonPane.add(sendBtn);
		buttonPane.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));

		add(listScrollPane, BorderLayout.CENTER);
		add(buttonPane, BorderLayout.PAGE_END);
		
	}

	class DeleteListener implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			//This method can be called only if
			//there's a valid selection
			//so go ahead and remove whatever's selected.
			int index = save.getSelectedIndex();
			saveList.remove(index);

			int size = saveList.getSize();

			if (size == 0) { //Nobody's left, disable firing.
				deleteBtn.setEnabled(false);

			} else { //Select an index.
				if (index == saveList.getSize()) {
					//removed item in last position
					index--;
				}

				save.setSelectedIndex(index);
				save.ensureIndexIsVisible(index);
			}
		}
	}

	//This listener is shared by the text field and the send button.
	class SendListener implements ActionListener, DocumentListener {
		private boolean alreadyEnabled = false;
		private JButton sendBtn;

		public SendListener(JButton button) {
			this.sendBtn = button;
		}

		//Required by ActionListener.
		public void actionPerformed(ActionEvent e) {
			String message = enterMsg.getText();

			//User didn't type in a unique name...
			if (message.equals("") || alreadyInList(message)) {
				Toolkit.getDefaultToolkit().beep();
				enterMsg.requestFocusInWindow();
				enterMsg.selectAll();
				return;
			}

			int index = save.getSelectedIndex(); //get selected index
			if (index == -1) { //no selection, so insert at beginning
				index = 0;
			} else {		   //add after the selected item
				index++;
			}

			saveList.insertElementAt(enterMsg.getText(), index);
			//If we just wanted to add to the end, we'd do this:
			//listModel.addElement(employeeName.getText());

			//Reset the text field.
			enterMsg.requestFocusInWindow();
			enterMsg.setText("");

			//Select the new item and make it visible.
			save.setSelectedIndex(index);
			save.ensureIndexIsVisible(index);
		}

		protected boolean alreadyInList(String name) {
			return saveList.contains(name);
		}

		//Required by DocumentListener.
		public void insertUpdate(DocumentEvent e) {
			enableButton();
		}

		//Required by DocumentListener.
		public void removeUpdate(DocumentEvent e) {
			handleEmptyTextField(e);
		}

		//Required by DocumentListener.
		public void changedUpdate(DocumentEvent e) {
			if (!handleEmptyTextField(e)) {
				enableButton();
			}
		}

		private void enableButton() {
			if (!alreadyEnabled) {
				sendBtn.setEnabled(true);
			}
		}

		private boolean handleEmptyTextField(DocumentEvent e) {
			if (e.getDocument().getLength() <= 0) {
				sendBtn.setEnabled(false);
				alreadyEnabled = false;
				return true;
			}
			return false;
		}
	}

	//This method is required by ListSelectionListener.
	public void valueChanged(ListSelectionEvent e) {
		if (e.getValueIsAdjusting() == false) {

			if (save.getSelectedIndex() == -1) {
			//No selection, disable delete button.
				deleteBtn.setEnabled(false);

			} else {
			//Selection, enable the delete button.
				deleteBtn.setEnabled(true);
			}
		}
	}


	private static void createAndShowGUI() {
		//Create and set up the window.
		JFrame frame = new JFrame("ListDemo");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		//Create and set up the content pane.
		JComponent newContentPane = new ListDemo();
		newContentPane.setOpaque(true); //content panes must be opaque
		frame.setContentPane(newContentPane);

		//Display the window.
		frame.pack();
		frame.setVisible(true);
 
	}
	
	public void runServer()
	{
	   ServerSocket server;
	   Socket connection;
	   int counter = 1;

	   try {
		  // Step 1: Create a ServerSocket.
		  server = new ServerSocket(50000 );

		  while ( true ) {
			 // Step 2: Wait for a connection.
			 display.setText( "Waiting for connection\n" );
			 connection = server.accept();

			 display.append( "Connection " + counter +
				" received from: " +
				connection.getInetAddress().getHostName() );

			 // Step 3: Get input and output streams.
			 output = new ObjectOutputStream(
						  connection.getOutputStream() );
			 output.flush();
			 input = new ObjectInputStream(
						 connection.getInputStream() );
			 display.append( "\nGot I/O streams\n" );

			 // Step 4: Process connection.
			 String message =
				"SERVER>>> Connection successful";
			 output.writeObject( message );
			 output.flush();
			 enter.setEnabled( true );

			 do {
				try {
				   message = (String) input.readObject();
				   display.append( "\n" + message );
				   display.setCaretPosition(
					  display.getText().length() );
				}
				catch ( ClassNotFoundException cnfex ) {
				   display.append(
					  "\nUnknown object type received" );
				}
			 } while ( !message.equals( "CLIENT>>> TERMINATE" ) );

			 // Step 5: Close connection.
			 display.append( "\nUser terminated connection" );
			 enter.setEnabled( false );
			 output.close();
			 input.close();
			 connection.close();

			 ++counter;
		  }
	   }
	   catch ( EOFException eof ) {
		  System.out.println( "Client terminated connection" );
	   }
	   catch ( IOException io ) {
		  io.printStackTrace();
	   }
	}

	private void sendData( String s )
	{
	   try {
		  output.writeObject( "CLIENT2>>> " + s );
		  output.flush();
		  display.append( "\nCLIENT2>>>" + s );
	   }
	   catch ( IOException cnfex ) {
		  display.append(
			 "\nError writing object" );
	   }
	}

	public static void main( String args[] )
	{
	   Server app = new Server();

	   app.runServer();
	}
 }//end of Server


Thanks in advance
Was This Post Helpful? 0
  • +
  • -

#3 smarty187  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 19-April 09

Re: Chat Client and Server, save and delete messages

Posted 19 April 2009 - 03:07 PM

One word: Hopeless.
I spent a while debugging, but it just doesn't work.
Was This Post Helpful? 0
  • +
  • -

#4 smarty187  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 2
  • Joined: 19-April 09

Re: Chat Client and Server, save and delete messages

Posted 19 April 2009 - 03:29 PM

So what's the problem?
It works fine.

PS- Why does the server act like a client sometimes?

This post has been edited by smarty187: 19 April 2009 - 03:35 PM

Was This Post Helpful? 0
  • +
  • -

#5 pjpro  Icon User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 3
  • Joined: 16-April 09

Re: Chat Client and Server, save and delete messages

Posted 19 April 2009 - 03:31 PM

i need to be able to save the recieved messages and then be able to select any of them to delete.
Was This Post Helpful? 0
  • +
  • -

#6 pbl  Icon User is online

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8019
  • View blog
  • Posts: 31,126
  • Joined: 06-March 08

Re: Chat Client and Server, save and delete messages

Posted 19 April 2009 - 03:36 PM

View Postpjpro, on 19 Apr, 2009 - 02:31 PM, said:

i need to be able to save the recieved messages and then be able to select any of them to delete.

And what is your criteria to decide to delete it ?
Was This Post Helpful? 0
  • +
  • -

#7 pbl  Icon User is online

  • There is nothing you can't do with a JTable
  • member icon

Reputation: 8019
  • View blog
  • Posts: 31,126
  • Joined: 06-March 08

Re: Chat Client and Server, save and delete messages

Posted 19 April 2009 - 03:42 PM

Topics merged
Avoid double posting :angry:
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1