package org.chartsy.chatsy.chat.ui.rooms; import java.awt.Color; import java.awt.event.ActionEvent; import java.text.DateFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; import java.util.TimerTask; import javax.swing.Icon; import javax.swing.SwingUtilities; import javax.swing.event.DocumentEvent; import org.jivesoftware.smack.Roster; import org.jivesoftware.smack.RosterEntry; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.filter.AndFilter; import org.jivesoftware.smack.filter.FromMatchesFilter; import org.jivesoftware.smack.filter.OrFilter; import org.jivesoftware.smack.filter.PacketFilter; import org.jivesoftware.smack.filter.PacketTypeFilter; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Packet; import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.StreamError; import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smackx.MessageEventManager; import org.jivesoftware.smackx.packet.MessageEvent; import org.chartsy.chatsy.chat.ChatManager; import org.chartsy.chatsy.chat.PresenceManager; import org.chartsy.chatsy.chat.ChatsyManager; import org.chartsy.chatsy.chat.ui.ChatRoom; import org.chartsy.chatsy.chat.ui.ContactItem; import org.chartsy.chatsy.chat.ui.ContactList; import org.chartsy.chatsy.chat.ui.MessageEventListener; import org.chartsy.chatsy.chat.util.ModelUtil; import org.chartsy.chatsy.chat.util.TaskEngine; public class ChatRoomImpl extends ChatRoom { private List<MessageEventListener> messageEventListeners = new ArrayList<MessageEventListener>(); private String roomname; private String roomTitle; private String tabTitle; private String participantJID; private String participantNickname; private String threadID; private Presence presence; private Roster roster; private TimerTask typingTimerTask; private Icon tabIcon; private long lastTypedCharTime; private long lastActivity; private boolean sendNotification = true; private boolean sendTypingNotification = true; private boolean offlineSent; private boolean active; public ChatRoomImpl(final String participantJID, String participantNickname, String title) { this.active = true; this.participantJID = participantJID; this.participantNickname = participantNickname; PacketFilter fromFilter = new FromMatchesFilter(participantJID); PacketFilter orFilter = new OrFilter(new PacketTypeFilter(Presence.class), new PacketTypeFilter(Message.class)); PacketFilter andFilter = new AndFilter(orFilter, fromFilter); ChatsyManager.getConnection().addPacketListener(this, andFilter); this.roomname = participantJID; this.tabTitle = title; this.roomTitle = participantNickname; this.getSplitPane().setRightComponent(null); getSplitPane().setDividerSize(0); presence = PresenceManager.getPresence(participantJID); roster = ChatsyManager.getConnection().getRoster(); tabIcon = PresenceManager.getIconFromPresence(presence); typingTimerTask = new TimerTask() { public void run() { if (!sendTypingNotification) return; long now = System.currentTimeMillis(); if (now - lastTypedCharTime > 2000) { if (!sendNotification) { ChatsyManager.getMessageEventManager().sendCancelledNotification(getParticipantJID(), threadID); sendNotification = true; } } } }; TaskEngine.getInstance().scheduleAtFixedRate(typingTimerTask, 2000, 2000); lastActivity = System.currentTimeMillis(); } public void closeChatRoom() { if (!active) return; super.closeChatRoom(); if (!sendNotification) { ChatsyManager.getMessageEventManager().sendCancelledNotification(getParticipantJID(), threadID); sendNotification = true; } ChatsyManager.getChatManager().removeChat(this); ChatsyManager.getConnection().removePacketListener(this); if (typingTimerTask != null) { TaskEngine.getInstance().cancelScheduledTask(typingTimerTask); typingTimerTask = null; } active = false; } public void sendMessage() { String text = getChatInputEditor().getText(); sendMessage(text); } public void sendMessage(String text) { final Message message = new Message(); if (threadID == null) threadID = StringUtils.randomString(6); message.setThread(threadID); message.setBody(text); if (!ModelUtil.hasLength(text)) return; ChatsyManager.getChatManager().filterOutgoingMessage(this, message); ChatsyManager.getChatManager().fireGlobalMessageSentListeners(this, message); sendMessage(message); sendNotification = true; } public void sendMessage(Message message) { lastActivity = System.currentTimeMillis(); try { getTranscriptWindow().insertMessage(getNickname(), message, ChatManager.TO_COLOR, Color.white); getChatInputEditor().selectAll(); getTranscriptWindow().validate(); getTranscriptWindow().repaint(); getChatInputEditor().clear(); } catch (Exception ex) { } message.setType(Message.Type.chat); message.setTo(participantJID); message.setFrom(ChatsyManager.getSessionManager().getJID()); fireMessageSent(message); addToTranscript(message, false); getChatInputEditor().setCaretPosition(0); getChatInputEditor().requestFocusInWindow(); scrollToBottom(); MessageEventManager.addNotificationsRequests(message, true, false, false, true); try { fireOutgoingMessageSending(message); ChatsyManager.getConnection().sendPacket(message); } catch (Exception ex) { } } public String getRoomname() { return roomname; } public Icon getTabIcon() { return tabIcon; } public void setTabIcon(Icon icon) { this.tabIcon = icon; } public String getTabTitle() { return tabTitle; } public void setTabTitle(String tabTitle) { this.tabTitle = tabTitle; } public void setRoomTitle(String roomTitle) { this.roomTitle = roomTitle; } public String getRoomTitle() { return roomTitle; } public Message.Type getChatType() { return Message.Type.chat; } public void leaveChatRoom() { } public boolean isActive() { return true; } public String getParticipantJID() { return participantJID; } public String getJID() { presence = PresenceManager.getPresence(getParticipantJID()); return presence.getFrom(); } public void processPacket(final Packet packet) { final Runnable runnable = new Runnable() { public void run() { if (packet instanceof Presence) { presence = (Presence)packet; final Presence presence = (Presence)packet; ContactList list = ChatsyManager.getWorkspace().getContactList(); ContactItem contactItem = list.getContactItemByJID(getParticipantJID()); String time = DateFormat.getTimeInstance(DateFormat.SHORT).format(new Date()); if (presence.getType() == Presence.Type.unavailable && contactItem != null) { if (!isOnline()) getTranscriptWindow().insertNotificationMessage("*** " + participantNickname + " went offline at " + time, ChatManager.NOTIFICATION_COLOR); } else if (presence.getType() == Presence.Type.available) { if (!isOnline()) getTranscriptWindow().insertNotificationMessage("*** " + participantNickname + " came online at " + time, ChatManager.NOTIFICATION_COLOR); } } else if (packet instanceof Message) { lastActivity = System.currentTimeMillis(); final Message message = (Message)packet; if (message.getError() != null) { if (message.getError().getCode() == 404) { RosterEntry entry = roster.getEntry(participantJID); if (!presence.isAvailable() && !offlineSent && entry != null) { getTranscriptWindow().insertNotificationMessage("The user will be unable to receive offline messages", ChatManager.ERROR_COLOR); offlineSent = true; } } return; } RosterEntry entry = roster.getEntry(participantJID); if (!presence.isAvailable() && !offlineSent && entry != null) { getTranscriptWindow().insertNotificationMessage("The user is offline and will receive the message on their next login", ChatManager.ERROR_COLOR); offlineSent = true; } if (threadID == null) { threadID = message.getThread(); if (threadID == null) threadID = StringUtils.randomString(6); } boolean broadcast = message.getProperty("broadcast") != null; if (message.getType() == Message.Type.groupchat || broadcast || message.getType() == Message.Type.normal || message.getType() == Message.Type.headline) return; final String host = ChatsyManager.getSessionManager().getServerAddress(); if (host.equals(message.getFrom())) return; if (message.getBody() != null) { participantJID = message.getFrom(); insertMessage(message); showTyping(false); } } } }; SwingUtilities.invokeLater(runnable); } public String getParticipantNickname() { return participantNickname; } public void insertUpdate(DocumentEvent e) { checkForText(e); if (!sendTypingNotification) return; lastTypedCharTime = System.currentTimeMillis(); if (sendNotification) { try { ChatsyManager.getMessageEventManager().sendComposingNotification(getParticipantJID(), threadID); sendNotification = false; } catch (Exception exception) { } } } public void insertMessage(Message message) { super.insertMessage(message); MessageEvent messageEvent = (MessageEvent)message.getExtension("x", "jabber:x:event"); if (messageEvent != null) checkEvents(message.getFrom(), message.getPacketID(), messageEvent); getTranscriptWindow().insertMessage(participantNickname, message, ChatManager.FROM_COLOR, Color.white); participantJID = message.getFrom(); } private void checkEvents(String from, String packetID, MessageEvent messageEvent) { if (messageEvent.isDelivered() || messageEvent.isDisplayed()) { Message msg = new Message(from); MessageEvent event = new MessageEvent(); if (messageEvent.isDelivered()) event.setDelivered(true); if (messageEvent.isDisplayed()) event.setDisplayed(true); event.setPacketID(packetID); msg.addExtension(event); ChatsyManager.getConnection().sendPacket(msg); } } public void addMessageEventListener(MessageEventListener listener) { messageEventListeners.add(listener); } public void removeMessageEventListener(MessageEventListener listener) { messageEventListeners.remove(listener); } public Collection<MessageEventListener> getMessageEventListeners() { return messageEventListeners; } public void fireOutgoingMessageSending(Message message) { for (MessageEventListener messageEventListener : new ArrayList<MessageEventListener>(messageEventListeners)) messageEventListener.sendingMessage(message); } public void fireReceivingIncomingMessage(Message message) { for (MessageEventListener messageEventListener : new ArrayList<MessageEventListener>(messageEventListeners)) messageEventListener.receivingMessage(message); } public void showTyping(boolean typing) { if (typing) { String isTypingText = participantNickname + " is typing a message..."; getNotificationLabel().setText(isTypingText); } else { getNotificationLabel().setText(""); } } public long getLastActivity() { return lastActivity; } public Presence getPresence() { return presence; } public void setSendTypingNotification(boolean isSendTypingNotification) { this.sendTypingNotification = isSendTypingNotification; } public void connectionClosed() { handleDisconnect(); String message = "Your connection was closed due to an error"; getTranscriptWindow().insertNotificationMessage(message, ChatManager.ERROR_COLOR); } public void connectionClosedOnError(Exception ex) { handleDisconnect(); String message = "Your connection was closed due to an error"; if (ex instanceof XMPPException) { XMPPException xmppEx = (XMPPException)ex; StreamError error = xmppEx.getStreamError(); String reason = error.getCode(); if ("conflict".equals(reason)) message = "Your connection was closed due to the same user logging in from another location"; } getTranscriptWindow().insertNotificationMessage(message, ChatManager.ERROR_COLOR); } public void reconnectionSuccessful() { Presence usersPresence = PresenceManager.getPresence(getParticipantJID()); if (usersPresence.isAvailable()) presence = usersPresence; ChatsyManager.getChatManager().getChatContainer().fireChatRoomStateUpdated(this); getChatInputEditor().setEnabled(true); getSendButton().setEnabled(true); } private void handleDisconnect() { presence = new Presence(Presence.Type.unavailable); getChatInputEditor().setEnabled(false); getSendButton().setEnabled(false); ChatsyManager.getChatManager().getChatContainer().fireChatRoomStateUpdated(this); } private boolean isOnline() { return roster.getPresence(getParticipantJID()).isAvailable(); } public void actionPerformed(ActionEvent e) { } }