diff options
Diffstat (limited to 'src/net/java/sip/communicator/impl/protocol/zeroconf/ClientThread.java')
-rw-r--r-- | src/net/java/sip/communicator/impl/protocol/zeroconf/ClientThread.java | 499 |
1 files changed, 0 insertions, 499 deletions
diff --git a/src/net/java/sip/communicator/impl/protocol/zeroconf/ClientThread.java b/src/net/java/sip/communicator/impl/protocol/zeroconf/ClientThread.java deleted file mode 100644 index 4367eed..0000000 --- a/src/net/java/sip/communicator/impl/protocol/zeroconf/ClientThread.java +++ /dev/null @@ -1,499 +0,0 @@ -/* - * Jitsi, the OpenSource Java VoIP and Instant Messaging client. - * - * Copyright @ 2015 Atlassian Pty Ltd - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package net.java.sip.communicator.impl.protocol.zeroconf; - -import java.io.*; -import java.net.*; - -import net.java.sip.communicator.service.protocol.*; -import net.java.sip.communicator.util.*; - -/** - * Class creating a thread responsible for handling the chat - * with the remote user on the other end of the socket - * - * @author Christian Vincenot - */ -public class ClientThread - extends Thread -{ - private static final Logger logger = Logger.getLogger(ClientThread.class); - - private OperationSetBasicInstantMessagingZeroconfImpl opSetBasicIM; - private OperationSetTypingNotificationsZeroconfImpl opSetTyping; - private Socket sock; - private InetAddress remoteIPAddress; - private OutputStream out; - private DataInputStream in; - private BonjourService bonjourService; - private ContactZeroconfImpl contact=null; - private boolean streamState = false; - - private String messagesQueue=null; - - /** - * Sets the contact with which we're chatting in this ClientThread - * @param contact Zeroconf contact with which we're chatting - */ - protected void setContact(ContactZeroconfImpl contact) - { - this.contact = contact; - } - - /** - * Set the stream as opened. This means that the - * conversation with the client is really opened - * from now on (the XML greetings are over) - */ - protected void setStreamOpen() - { - synchronized(this) - { - this.streamState = true; - } - } - - /** - * Says if the stream between the local user and the remote user - * is in an opened state (greetings are over and we can chat) - * @return Returns true if the stream is "opened" (ie, ready for chat) - */ - protected boolean isStreamOpened() - { - synchronized(this) - { - return this.streamState; - } - } - - /** - * Creates a new instance of ClientThread reponsible - * for handling the conversation with the remote user. - * @param sock Socket created for chatting - * @param bonjourService BonjourService which spawned this ClientThread - */ - public ClientThread(Socket sock, BonjourService bonjourService) - { - this.sock = sock; - this.remoteIPAddress = sock.getInetAddress(); - this.bonjourService = bonjourService; - this.opSetBasicIM = - (OperationSetBasicInstantMessagingZeroconfImpl) bonjourService - .getPPS().getOperationSet( - OperationSetBasicInstantMessaging.class); - - this.opSetTyping = - (OperationSetTypingNotificationsZeroconfImpl) bonjourService - .getPPS() - .getOperationSet(OperationSetTypingNotifications.class); - this.setDaemon(true); - - try - { - out = sock.getOutputStream(); - in = new DataInputStream(sock.getInputStream()); - } - catch (IOException e) - { - logger.error("Creating ClientThread: Couldn't get I/O for " - +"the connection", e); - //System.exit(1); - return; - } - - this.start(); - } - - /* - * Read a message from the socket. - * TODO: clean the code a bit and optimize it. - */ - private String readMessage() - { - String line; - byte[] bytes = new byte[10]; - - try - { - int i=0; - - while (i < 9) - { - i += in.read(bytes,0,9-i); - } - - line = new String(bytes); - bytes = new byte[1]; - if ((line.getBytes())[0] == '\n') - line = line.substring(1); - - if (line.startsWith("<message")) - { - while (true) - { - bytes[0] = in.readByte(); - line += new String(bytes); - - if ((line.endsWith("</message>")) - || (line.endsWith("stream>"))) - return line; - } - } - else - { - while (true) - { - bytes[0] = in.readByte(); - line += new String(bytes); - if ( ">".compareTo(new String(bytes)) == 0 ) - return line; - } - } - } - catch (IOException e) - { - logger.error("Couldn't get I/O for the connection", e); - //System.exit(1); - } - - return null; - } - - /* - * Parse the payload and extract the information. - * TODO: If needed, fill in the remaining fields of MessageZeroconfImpl - * like the baloon icon color, color/size/font of the text. - */ - private MessageZeroconfImpl parseMessage(String str) - { - if (str.startsWith("<?xml") || str.startsWith("<stream")) - return new MessageZeroconfImpl - (null, null, MessageZeroconfImpl.STREAM_OPEN); - - if (str.endsWith("stream>")) - return new MessageZeroconfImpl - (null, null, MessageZeroconfImpl.STREAM_CLOSE); - - if ((str.indexOf("<delivered/>") > 0) && (str.indexOf("<body>") < 0)) - return new MessageZeroconfImpl - (null, null, MessageZeroconfImpl.DELIVERED); - - if (!str.startsWith("<message")) - return new MessageZeroconfImpl - (null, null, MessageZeroconfImpl.UNDEF); - - /* TODO: Parse Enconding (& contact id to be able to double-check - * the source of a message) - * - * TODO: Check that the fields are outside of <body>..</body> - */ - - if ((str.indexOf("<body>") < 0) || (str.indexOf("</body>") < 0)) - return new MessageZeroconfImpl - (null, null, MessageZeroconfImpl.UNDEF); - - String temp = - str.substring(str.indexOf("<body>")+6, str.indexOf("</body>")); - - if (logger.isDebugEnabled()) - logger.debug("ZEROCONF: received message ["+temp+"]"); - - int messageType = MessageZeroconfImpl.MESSAGE; - - if ((str.indexOf("<id>") >= 0) && (str.indexOf("</id>") >= 0)) - messageType = MessageZeroconfImpl.TYPING; - - MessageZeroconfImpl msg = - new MessageZeroconfImpl( - temp, - null, - OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE, - messageType); - - return msg; - } - - private int handleMessage(MessageZeroconfImpl msg) - { - - switch(msg.getType()) - { - /* STREAM INIT */ - case MessageZeroconfImpl.STREAM_OPEN: - if (contact == null) - contact = bonjourService.getContact(null, remoteIPAddress); - if (!isStreamOpened()) - { - sendHello(); - setStreamOpen(); - } - if (messagesQueue != null) - { - write(messagesQueue); - messagesQueue = null; - } - break; - - /* ACK */ - case MessageZeroconfImpl.DELIVERED : break; - - /* NORMAL MESSAGE */ - case MessageZeroconfImpl.MESSAGE: - if (!isStreamOpened()) - if (logger.isDebugEnabled()) - logger.debug("ZEROCONF: client on the other side " - +"isn't polite (sending messages without " - +"saying hello :P"); - if (contact == null) - //TODO: Parse contact id to double-check - contact = bonjourService.getContact(null, remoteIPAddress); - - /* TODO: If we want to implement invisible status, we'll have to - * make this test less restrictive to handle messages from - * unannounced clients. - */ - if (contact == null) - { - logger.error("ZEROCONF: ERROR - Couldn't identify " - +"contact. Closing socket."); - return -1; - } - else if (contact.getClientThread() == null) - contact.setClientThread(this); - - opSetBasicIM.fireMessageReceived(msg, contact); - - opSetTyping.fireTypingNotificationsEvent(contact, - OperationSetTypingNotificationsZeroconfImpl.STATE_STOPPED); - break; - - case MessageZeroconfImpl.TYPING: - if (!isStreamOpened()) - if (logger.isDebugEnabled()) - logger.debug("ZEROCONF: client on the other side " - +"isn't polite (sending messages without " - +"saying hello :P"); - if (contact == null) - //TODO: Parse contact id to double-check - contact = bonjourService.getContact(null, remoteIPAddress); - opSetTyping.fireTypingNotificationsEvent(contact, - OperationSetTypingNotificationsZeroconfImpl.STATE_TYPING); - - /* TODO: code a private runnable class to be used as timeout - * to set the typing state to STATE_PAUSED when a few seconds - * without news have passed. - */ - - break; - - case MessageZeroconfImpl.STREAM_CLOSE: - sendBye(); - contact.setClientThread(null); - return 1; - - case MessageZeroconfImpl.UNDEF: - logger.error("ZEROCONF: received strange message. SKIPPING!"); - break; - } - - //System.out.println("RECEIVED MESSAGE "+ msg.getContent()+ - //" from "+contact.getAddress() + "!!!!!!!!!!!!!!"); - return 0; - } - - - private void write(String string) - { - //System.out.println("Writing " + string + "!!!!!!!!!"); - byte[] bytes = string.getBytes(); - try - { - out.write(bytes); - out.flush(); - } - catch (IOException e) - { - logger.error("Couldn't get I/O for the connection"); - if (contact != null) - { - contact.setClientThread(null); - } - - try - { - sock.close(); - } - catch (IOException ex) - { - logger.error(ex); - } - - } - } - - /** - * Say hello :) - */ - protected void sendHello() - { - switch(contact.getClientType()) - { - case ContactZeroconfImpl.GAIM: - case ContactZeroconfImpl.ICHAT: - case ContactZeroconfImpl.SIPCOM: - write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); - write("<stream:stream xmlns=\"jabber:client\" " - +"xmlns:stream=\"http://etherx.jabber.org/streams\">"); - break; - case ContactZeroconfImpl.XMPP: - write("<stream:stream" - +"xmlns='jabber:client'" - +"xmlns:stream='http://etherx.jabber.org/streams'" - +"from='"+bonjourService.getID()+"'" - +"to='"+contact.getAddress()+"'" - +"version='1.0'>\n"); - break; - } - - /* Legacy: OLD XMPP (XEP-0174 Draft) */ - //write("<stream:stream to='"+sock.getInetAddress().getHostAddress() - //+"' xmlns='jabber:client' stream='http://etherx.jabber.org/streams'>"); - } - - private void sendBye() - { - write("</stream:stream>\n"); - } - - private String toXHTML(MessageZeroconfImpl msg) - { - switch(contact.getClientType()) - { - case ContactZeroconfImpl.XMPP: - return new String("<message to='" - +contact.getAddress()+"' from='" - +bonjourService.getID()+"'>" - + "<body>"+msg.getContent()+"</body>" - + "</message>\n"); - - case ContactZeroconfImpl.SIPCOM: - - case ContactZeroconfImpl.ICHAT: - return new String( - "<message to='"+sock.getInetAddress().getHostAddress() - +"' type='chat' id='"+bonjourService.getID()+"'>" - + "<body>"+msg.getContent()+"</body>" - + "<html xmlns='http://www.w3.org/1999/xhtml'>" - + "<body ichatballooncolor='#7BB5EE' " - + "ichattextcolor='#000000'>" - + "<font face='Helvetica' ABSZ='12' color='#000000'>" - + msg.getContent() - + "</font>" - + "</body>" - + "</html>" - + "<x xmlns='jabber:x:event'>" - + "<offline/>" - + "<delivered/>" - + "<composing/>" - + (msg.getType()==MessageZeroconfImpl.TYPING?"<id></id>":"") - + "</x>" - + "</message>"); - - case ContactZeroconfImpl.GAIM: - default: - return new String( - "<message to='"+contact.getAddress() - +"' from='"+bonjourService.getID() - + "' type='chat'><body>"+msg.getContent()+"</body>" - + "<html xmlns='http://www.w3.org/1999/xhtml'><body><font>" - + msg.getContent() - + "</font></body></html><x xmlns='jabber:x:event'><composing/>" - + (msg.getType()==MessageZeroconfImpl.TYPING?"<id></id>":"") - + "</x></message>\n"); - } - } - - - /** - * Send a message to the remote user - * @param msg Message to send - */ - public void sendMessage(MessageZeroconfImpl msg) - { - if (logger.isDebugEnabled()) - logger.debug("ZEROCONF: Sending messag [" - +msg.getContent()+"] to " - + contact.getDisplayName()); - if (!isStreamOpened()) - { - if (logger.isDebugEnabled()) - logger.debug("ZEROCONF: Stream not opened... " - +"will send the message later"); - messagesQueue += toXHTML(msg); - } - else write(toXHTML(msg)); - } - - /** - * Walk? - */ - @Override - public void run() - { - if (logger.isDebugEnabled()) - logger.debug("Bonjour: NEW CONNEXION from " - + sock.getInetAddress().getCanonicalHostName() - +" / "+sock.getInetAddress().getHostAddress()); - String input; - MessageZeroconfImpl msg=null; - - - input = readMessage(); - msg = parseMessage(input); - - while (handleMessage(msg) == 0 && !sock.isClosed()) - { - input = readMessage(); - msg = parseMessage(input); - } - - if (logger.isDebugEnabled()) - logger.debug("ZEROCONF : OUT OF LOOP !! Closed chat."); - cleanThread(); - } - - /** - * Clean-up the thread to exit - */ - public void cleanThread() - { - /* I wonder if that's ok... */ - if (sock != null && sock.isClosed() == false) - { - sendBye(); - try - { - sock.close(); - } - catch (IOException ex) - { - logger.error(ex); - } - } - } -} |