aboutsummaryrefslogtreecommitdiffstats
path: root/src/net
diff options
context:
space:
mode:
authorYana Stamcheva <yana@jitsi.org>2012-07-12 17:00:53 +0000
committerYana Stamcheva <yana@jitsi.org>2012-07-12 17:00:53 +0000
commit2a5e9c4895f6e04c15645c5898a9ab7537b8ffb2 (patch)
tree62756bba2293d47b2ddab54a02b63147751050dd /src/net
parent99a732d5f448270181b48edcae7960854052939b (diff)
downloadjitsi-2a5e9c4895f6e04c15645c5898a9ab7537b8ffb2.zip
jitsi-2a5e9c4895f6e04c15645c5898a9ab7537b8ffb2.tar.gz
jitsi-2a5e9c4895f6e04c15645c5898a9ab7537b8ffb2.tar.bz2
Adds last message correction functionality. Implementation provided by Ivan Vergiliev.
Diffstat (limited to 'src/net')
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java153
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/ChatMessage.java48
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java172
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/ChatTransport.java23
-rwxr-xr-xsrc/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java32
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/MetaContactChatTransport.java70
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/conference/AdHocConferenceChatTransport.java27
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatTransport.java27
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/chat/history/HistoryWindow.java10
-rw-r--r--src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPane.java23
-rwxr-xr-xsrc/net/java/sip/communicator/impl/protocol/jabber/MessageJabberImpl.java17
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java113
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/OperationSetContactCapabilitiesJabberImpl.java9
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java5
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/messagecorrection/MessageCorrectionExtension.java109
-rw-r--r--src/net/java/sip/communicator/impl/protocol/jabber/extensions/messagecorrection/MessageCorrectionExtensionProvider.java46
-rw-r--r--src/net/java/sip/communicator/service/protocol/AbstractMessage.java2
-rw-r--r--src/net/java/sip/communicator/service/protocol/OperationSetMessageCorrection.java27
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/MessageDeliveredEvent.java43
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/MessageDeliveryFailedEvent.java33
-rw-r--r--src/net/java/sip/communicator/service/protocol/event/MessageReceivedEvent.java39
21 files changed, 959 insertions, 69 deletions
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java
index 678a71f..4e98ef8 100755
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java
@@ -20,6 +20,7 @@ import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.text.html.*;
+import javax.swing.text.html.HTML.*;
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.impl.gui.customcontrols.*;
@@ -364,6 +365,68 @@ public class ChatConversationPanel
// }
/**
+ * Retrieves the contents of the sent message with the given ID.
+ *
+ * @param messageUID The ID of the message to retrieve.
+ * @return The contents of the message, or null if the message is not found.
+ */
+ public String getMessageContents(String messageUID)
+ {
+ Element root = document.getDefaultRootElement();
+ Element e = document.getElement(root, Attribute.ID, messageUID);
+ if (e == null)
+ {
+ logger.warn("Could not find message with ID" + messageUID);
+ return null;
+ }
+
+ int elemLen = e.getEndOffset() - e.getStartOffset();
+ String res = null;
+ try
+ {
+ res = document.getText(e.getStartOffset(), elemLen);
+ }
+ catch (BadLocationException exc)
+ {
+ logger.warn("Could not get message contents for message "
+ + "with ID" + messageUID, exc);
+ }
+ return res;
+ }
+
+ /**
+ * Creates a tag that shows the last edit time of a message, in the format
+ * (Edited at ...).
+ * If <tt>date < 0</tt>, returns an empty tag that serves as a placeholder
+ * for future corrections of this message.
+ *
+ * @param messageUID The ID of the edited message.
+ * @param date The date when the message was last edited, or -1 to generate
+ * an empty tag.
+ * @return The string representation of the tag.
+ */
+ private String generateEditedAtTag(String messageUID, long date)
+ {
+ StringBuilder res = new StringBuilder();
+ // Use a <cite /> tag here as most of the other inline tags (e.g. h1-7,
+ // b, i) cause different problems when used in setOuterHTML.
+ res.append("<cite id='");
+ res.append(messageUID);
+ res.append("-editedAt'> ");
+ if (date > 0)
+ {
+ res.append("&nbsp;");
+ String contents = GuiActivator.getResources().getI18NString(
+ "service.gui.EDITED_AT",
+ new String[] { GuiUtils.formatTime(date) }
+ );
+ res.append(contents);
+ }
+ res.append("</cite>");
+ return res.toString();
+ }
+
+ /**
* Processes the message given by the parameters.
*
* @param chatMessage the message
@@ -384,14 +447,18 @@ public class ChatConversationPanel
String messageType = chatMessage.getMessageType();
String messageTitle = chatMessage.getMessageTitle();
String message = chatMessage.getMessage();
+ String messageUID = chatMessage.getMessageUID();
String msgID = "message";
String msgHeaderID = "messageHeader";
String chatString = "";
String endHeaderTag = "";
String dateString = getDateString(date);
+ String idAttr = messageUID == null ? "" : " id='" + messageUID + "'";
+ String dateAttr = " date='" + date + "'";
+ String editedAtTag = generateEditedAtTag(messageUID, -1);
- String startDivTag = "<DIV identifier=\"" + msgID + "\">";
+ String startDivTag = "<DIV identifier=\"" + msgID + "\"" + idAttr + ">";
String startHistoryDivTag
= "<DIV identifier=\"" + msgID + "\" style=\"color:#707070;\">";
String startSystemDivTag
@@ -417,7 +484,7 @@ public class ChatConversationPanel
this.lastIncomingMsgTimestamp = System.currentTimeMillis();
chatString = "<h2 identifier=\"" + msgHeaderID + "\""
- + " date=\"" + date + "\">"
+ + dateAttr + ">"
+ "<a style=\"color:#ef7b1e;"
+ "font-weight:bold;"
+ "text-decoration:none;\" "
@@ -427,8 +494,8 @@ public class ChatConversationPanel
chatString
+= dateString + contactDisplayName + " at "
- + GuiUtils.formatTime(date)
- + endHeaderTag + startDivTag + startPlainTextTag
+ + GuiUtils.formatTime(date) + editedAtTag + endHeaderTag
+ + startDivTag + startPlainTextTag
+ formatMessage(message, contentType, keyword)
+ endPlainTextTag + endDivTag;
}
@@ -451,7 +518,7 @@ public class ChatConversationPanel
else if (messageType.equals(Chat.OUTGOING_MESSAGE))
{
chatString = "<h3 identifier=\"" + msgHeaderID + "\""
- + " date=\"" + date + "\">"
+ + dateAttr + ">"
+ "<a style=\"color:#2e538b;"
+ "font-weight:bold;"
+ "text-decoration:none;\" "
@@ -461,7 +528,7 @@ public class ChatConversationPanel
chatString
+= dateString + contactDisplayName + " at "
- + GuiUtils.formatTime(date) + endHeaderTag
+ + GuiUtils.formatTime(date) + editedAtTag + endHeaderTag
+ startDivTag + startPlainTextTag
+ formatMessage(message, contentType, keyword)
+ endPlainTextTag + endDivTag;
@@ -514,7 +581,7 @@ public class ChatConversationPanel
else if (messageType.equals(Chat.HISTORY_INCOMING_MESSAGE))
{
chatString = "<h2 identifier=\"" + msgHeaderID + "\""
- + " date=\"" + date + "\">"
+ + dateAttr + ">"
+ "<a style=\"color:#ef7b1e;"
+ "font-weight:bold;"
+ "text-decoration:none;\" "
@@ -524,15 +591,15 @@ public class ChatConversationPanel
chatString
+= dateString + contactDisplayName
- + " at " + GuiUtils.formatTime(date)
- + endHeaderTag + startHistoryDivTag + startPlainTextTag
+ + " at " + GuiUtils.formatTime(date) + endHeaderTag
+ + editedAtTag + startHistoryDivTag + startPlainTextTag
+ formatMessage(message, contentType, keyword)
+ endPlainTextTag + endDivTag;
}
else if (messageType.equals(Chat.HISTORY_OUTGOING_MESSAGE))
{
chatString = "<h3 identifier=\"" + msgHeaderID + "\""
- + " date=\"" + date + "\">"
+ + dateAttr + ">"
+ "<a style=\"color:#2e538b;"
+ "font-weight:bold;"
+ "text-decoration:none;\" "
@@ -542,8 +609,8 @@ public class ChatConversationPanel
chatString
+= dateString
- + contactDisplayName
- + " at " + GuiUtils.formatTime(date) + endHeaderTag
+ + contactDisplayName + " at " + GuiUtils.formatTime(date)
+ + editedAtTag + endHeaderTag
+ startHistoryDivTag + startPlainTextTag
+ formatMessage(message, contentType, keyword)
+ endPlainTextTag + endDivTag;
@@ -564,6 +631,68 @@ public class ChatConversationPanel
}
/**
+ * Replaces the contents of the message with ID of the corrected message
+ * specified in chatMessage, with this message.
+ *
+ * @param chatMessage A <tt>ChatMessage</tt> that contains all the required
+ * information to correct the old message.
+ */
+ public void correctMessage(ChatMessage chatMessage)
+ {
+ String correctedUID = chatMessage.getCorrectedMessageUID();
+ Element root = document.getDefaultRootElement();
+ Element e = document.getElement(root, Attribute.ID, correctedUID);
+ if (e == null)
+ {
+ logger.warn("Could not find message with ID " + correctedUID);
+ return;
+ }
+ int len = e.getEndOffset() - e.getStartOffset();
+
+ StringBuilder newContents = new StringBuilder();
+ String bgColor = GuiActivator.getResources().getColorString(
+ "service.gui.CHAT_EDIT_MESSAGE_BACKGROUND");
+ newContents.append("<div identifier='message' id='");
+ newContents.append(chatMessage.getMessageUID());
+ newContents.append("' bgcolor='");
+ newContents.append(bgColor);
+ newContents.append("'>");
+ if (chatMessage.getContentType().equals(TEXT_CONTENT_TYPE))
+ {
+ newContents.append(START_PLAINTEXT_TAG);
+ newContents.append(chatMessage.getMessage());
+ newContents.append(END_PLAINTEXT_TAG);
+ }
+ else
+ {
+ newContents.append(chatMessage.getMessage());
+ }
+ newContents.append("</div>");
+
+ Element header = document.getElement(root, Attribute.ID,
+ correctedUID + "-editedAt");
+
+ try
+ {
+ if (header != null)
+ {
+ String newHeaderContents = generateEditedAtTag(
+ chatMessage.getMessageUID(), chatMessage.getDate());
+ document.setOuterHTML(header, newHeaderContents);
+ }
+ document.setOuterHTML(e, newContents.toString());
+ }
+ catch (BadLocationException ex)
+ {
+ logger.error("Could not replace chat message", ex);
+ }
+ catch (IOException ex)
+ {
+ logger.error("Could not replace chat message", ex);
+ }
+ }
+
+ /**
* Appends the given string at the end of the contained in this panel
* document.
*
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatMessage.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatMessage.java
index ca48a06..98e006a 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatMessage.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatMessage.java
@@ -49,6 +49,17 @@ public class ChatMessage
* The content type of the message.
*/
private final String contentType;
+
+ /**
+ * A unique identifier for this message.
+ */
+ private String messageUID;
+
+ /**
+ * The unique identifier of the message that this message should replace,
+ * or <tt>null</tt> if this is a new message.
+ */
+ private String correctedMessageUID;
/**
* Creates a <tt>ChatMessage</tt> by specifying all parameters of the
@@ -65,7 +76,8 @@ public class ChatMessage
String message,
String contentType)
{
- this(contactName, null, date, messageType, null, message, contentType);
+ this(contactName, null, date, messageType,
+ null, message, contentType, null, null);
}
/**
@@ -86,7 +98,7 @@ public class ChatMessage
String contentType)
{
this(contactName, null, date, messageType,
- messageTitle, message, contentType);
+ messageTitle, message, contentType, null, null);
}
/**
@@ -107,7 +119,7 @@ public class ChatMessage
String contentType)
{
this(contactName, contactDisplayName, date, messageType,
- null, message, contentType);
+ null, message, contentType, null, null);
}
/**
@@ -119,6 +131,8 @@ public class ChatMessage
* @param messageType the type (INCOMING or OUTGOING)
* @param message the content
* @param contentType the content type (e.g. "text", "text/html", etc.)
+ * @param messageUID The ID of the message.
+ * @param correctedMessageUID The ID of the message being replaced.
*/
public ChatMessage( String contactName,
String contactDisplayName,
@@ -126,7 +140,9 @@ public class ChatMessage
String messageType,
String messageTitle,
String message,
- String contentType)
+ String contentType,
+ String messageUID,
+ String correctedMessageUID)
{
this.contactName = contactName;
this.contactDisplayName = contactDisplayName;
@@ -135,6 +151,8 @@ public class ChatMessage
this.messageTitle = messageTitle;
this.message = message;
this.contentType = contentType;
+ this.messageUID = messageUID;
+ this.correctedMessageUID = correctedMessageUID;
}
/**
@@ -216,4 +234,26 @@ public class ChatMessage
{
return contentType;
}
+
+ /**
+ * Returns the UID of this message.
+ *
+ * @return the UID of this message.
+ */
+ public String getMessageUID()
+ {
+ return messageUID;
+ }
+
+ /**
+ * Returns the UID of the message that this message replaces, or
+ * <tt>null</tt> if this is a new message.
+ *
+ * @return the UID of the message that this message replaces, or
+ * <tt>null</tt> if this is a new message.
+ */
+ public String getCorrectedMessageUID()
+ {
+ return correctedMessageUID;
+ }
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java
index 70a8ab9..9cf6f62 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatPanel.java
@@ -138,6 +138,17 @@ public class ChatPanel
*/
private final Hashtable<String, Object> activeFileTransfers
= new Hashtable<String, Object>();
+
+ /**
+ * The ID of the message being corrected, or <tt>null</tt> if
+ * not correcting any message.
+ */
+ private String correctedMessageUID = null;
+
+ /**
+ * The ID of the last sent message in this chat.
+ */
+ private String lastSentMessageUID = null;
/**
* Creates a <tt>ChatPanel</tt> which is added to the given chat window.
@@ -490,6 +501,17 @@ public class ChatPanel
}
/**
+ * Returns the ID of the last message sent in this chat, or <tt>null</tt>
+ * if no messages have been sent yet.
+ *
+ * @return the ID of the last message sent in this chat, or <tt>null</tt>
+ * if no messages have been sent yet.
+ */
+ public String getLastSentMessageUID() {
+ return lastSentMessageUID;
+ }
+
+ /**
* Every time the chat panel is shown we set it as a current chat panel.
* This is done here and not in the Tab selection listener, because the tab
* change event is not fired when the user clicks on the close tab button
@@ -589,7 +611,8 @@ public class ChatPanel
evt.getTimestamp(),
messageType,
evt.getSourceMessage().getContent(),
- evt.getSourceMessage().getContentType());
+ evt.getSourceMessage().getContentType(),
+ evt.getSourceMessage().getMessageUID());
}
else if(o instanceof MessageReceivedEvent)
{
@@ -612,7 +635,8 @@ public class ChatPanel
evt.getTimestamp(),
messageType,
evt.getSourceMessage().getContent(),
- evt.getSourceMessage().getContentType());
+ evt.getSourceMessage().getContentType(),
+ evt.getSourceMessage().getMessageUID());
}
}
else if(o instanceof ChatRoomMessageDeliveredEvent)
@@ -684,7 +708,8 @@ public class ChatPanel
public void addMessage(String contactName, long date,
String messageType, String message, String contentType)
{
- addMessage(contactName, null, date, messageType, message, contentType);
+ addMessage(contactName, null, date, messageType, message, contentType,
+ null, null);
}
/**
@@ -701,11 +726,12 @@ public class ChatPanel
* @param contentType the content type
*/
public void addMessage(String contactName, String displayName, long date,
- String messageType, String message, String contentType)
+ String messageType, String message, String contentType,
+ String messageUID, String correctedMessageUID)
{
- ChatMessage chatMessage
- = new ChatMessage(contactName, displayName, date,
- messageType, message, contentType);
+ ChatMessage chatMessage = new ChatMessage(contactName, displayName,
+ date, messageType, null, message, contentType,
+ messageUID, correctedMessageUID);
this.addChatMessage(chatMessage);
@@ -769,11 +795,15 @@ public class ChatPanel
}
else
{
- appendChatMessage(chatMessage);
+ displayChatMessage(chatMessage);
}
// change the last history message timestamp after we add one.
this.lastHistoryMsgTimestamp = chatMessage.getDate();
+ if (chatMessage.getMessageType().equals(Chat.OUTGOING_MESSAGE))
+ {
+ this.lastSentMessageUID = chatMessage.getMessageUID();
+ }
}
/**
@@ -809,6 +839,20 @@ public class ChatPanel
message, "text");
}
+ private void displayChatMessage(ChatMessage chatMessage)
+ {
+ if (chatMessage.getCorrectedMessageUID() != null
+ && conversationPanel.getMessageContents(
+ chatMessage.getCorrectedMessageUID()) != null)
+ {
+ applyMessageCorrection(chatMessage);
+ }
+ else
+ {
+ appendChatMessage(chatMessage);
+ }
+ }
+
/**
* Passes the message to the contained <code>ChatConversationPanel</code>
* for processing and appends it at the end of the conversationPanel
@@ -855,6 +899,17 @@ public class ChatPanel
/**
* Passes the message to the contained <code>ChatConversationPanel</code>
+ * for processing and replaces the specified message with this one.
+ *
+ * @param chatMessage The message used as a correction.
+ */
+ private void applyMessageCorrection(ChatMessage message)
+ {
+ conversationPanel.correctMessage(message);
+ }
+
+ /**
+ * Passes the message to the contained <code>ChatConversationPanel</code>
* for processing.
*
* @param contactName The name of the contact sending the message.
@@ -875,9 +930,37 @@ public class ChatPanel
String message,
String contentType)
{
+ return processHistoryMessage(contactName, contactDisplayName,
+ date, messageType, message, contentType, null);
+ }
+
+ /**
+ * Passes the message to the contained <code>ChatConversationPanel</code>
+ * for processing.
+ *
+ * @param contactName The name of the contact sending the message.
+ * @param contactDisplayName the display name of the contact sending the
+ * message
+ * @param date The time at which the message is sent or received.
+ * @param messageType The type of the message. One of OUTGOING_MESSAGE
+ * or INCOMING_MESSAGE.
+ * @param message The message text.
+ * @param contentType the content type of the message (html or plain text)
+ * @param messageId The ID of the message.
+ *
+ * @return a string containing the processed message.
+ */
+ private String processHistoryMessage(String contactName,
+ String contactDisplayName,
+ long date,
+ String messageType,
+ String message,
+ String contentType,
+ String messageId)
+ {
ChatMessage chatMessage = new ChatMessage(
contactName, contactDisplayName, date,
- messageType, null, message, contentType);
+ messageType, null, message, contentType, messageId, null);
String processedMessage =
this.conversationPanel.processMessage(chatMessage);
@@ -1372,7 +1455,7 @@ public class ChatPanel
OperationSetBasicInstantMessaging.HTML_MIME_TYPE).trim();
plainText = getTextFromWriteArea(
- OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE);
+ OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE).trim();
// clear the message earlier
// to avoid as much as possible to not sending it twice (double enter)
@@ -1399,8 +1482,19 @@ public class ChatPanel
try
{
- chatSession.getCurrentChatTransport()
- .sendInstantMessage(messageText, mimeType);
+ if (isMessageCorrectionActive()
+ && chatSession.getCurrentChatTransport()
+ .allowsMessageCorrections())
+ {
+ chatSession.getCurrentChatTransport().correctInstantMessage(
+ messageText, mimeType, correctedMessageUID);
+ }
+ else
+ {
+ chatSession.getCurrentChatTransport().sendInstantMessage(
+ messageText, mimeType);
+ }
+ stopMessageCorrection();
}
catch (IllegalStateException ex)
{
@@ -1459,6 +1553,58 @@ public class ChatPanel
}
/**
+ * Enters editing mode for the last sent message in this chat.
+ */
+ public void startLastMessageCorrection()
+ {
+ startMessageCorrection(lastSentMessageUID);
+ }
+
+ /**
+ * Enters editing mode for the message with the specified id - puts the
+ * message contents in the write panel and changes the background.
+ *
+ * @param correctedMessageUID The ID of the message being corrected.
+ */
+ public void startMessageCorrection(String correctedMessageUID)
+ {
+ this.correctedMessageUID = correctedMessageUID;
+ this.refreshWriteArea();
+ String messageContents
+ = conversationPanel.getMessageContents(correctedMessageUID);
+ if (messageContents == null)
+ {
+ this.stopMessageCorrection();
+ return;
+ }
+ Color bgColor = new Color(GuiActivator.getResources()
+ .getColor("service.gui.CHAT_EDIT_MESSAGE_BACKGROUND"));
+ this.writeMessagePanel.setEditorPaneBackground(bgColor);
+ this.setMessage(messageContents);
+ }
+
+ /**
+ * Exits editing mode, clears the write panel and the background.
+ */
+ public void stopMessageCorrection()
+ {
+ this.correctedMessageUID = null;
+ this.writeMessagePanel.setEditorPaneBackground(Color.WHITE);
+ this.refreshWriteArea();
+ }
+
+ /**
+ * Returns whether a message is currently being edited.
+ *
+ * @return <tt>true</tt> if a message is currently being edited,
+ * <tt>false</tt> otherwise.
+ */
+ public boolean isMessageCorrectionActive()
+ {
+ return correctedMessageUID != null;
+ }
+
+ /**
* Listens for SMS messages and shows them in the chat.
*/
private class SmsMessageListener implements MessageListener
@@ -2358,7 +2504,7 @@ public class ChatPanel
if (incomingEvent instanceof ChatMessage)
{
- this.appendChatMessage((ChatMessage) incomingEvent);
+ this.displayChatMessage((ChatMessage) incomingEvent);
}
else if (incomingEvent instanceof ChatConversationComponent)
{
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransport.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransport.java
index ba13dbc..12aeedd 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransport.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatTransport.java
@@ -35,6 +35,15 @@ public interface ChatTransport
* messaging, otherwise returns <code>false</code>
*/
public boolean allowsInstantMessage();
+
+ /**
+ * Returns <tt>true</tt> if this chat transport supports message
+ * corrections and false otherwise.
+ *
+ * @return <code>true</code> if this chat transport supports message
+ * corrections and false otherwise.
+ */
+ public boolean allowsMessageCorrections();
/**
* Returns <code>true</code> if this chat transport supports sms
@@ -100,6 +109,20 @@ public interface ChatTransport
public void sendInstantMessage( String message,
String mimeType)
throws Exception;
+
+ /**
+ * Sends <tt>message</tt> as a message correction through this transport,
+ * specifying the mime type (html or plain text) and the id of the
+ * message to replace.
+ *
+ * @param message The message to send.
+ * @param mimeType The mime type of the message to send: text/html or
+ * text/plain.
+ * @param correctedMessageUID The ID of the message being corrected by
+ * this message.
+ */
+ public void correctInstantMessage(String message, String mimeType,
+ String correctedMessageUID);
/**
* Determines whether this chat transport supports the supplied content type
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java
index a93cedb..855dd77 100755
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java
@@ -674,6 +674,27 @@ public class ChatWritePanel
ex.printStackTrace();
}
}
+ else if (e.getKeyCode() == KeyEvent.VK_UP)
+ {
+ // Only enters editing mode if the write panel is empty in
+ // order not to lose the current message contents, if any.
+ if (this.chatPanel.getLastSentMessageUID() != null
+ && this.chatPanel.isWriteAreaEmpty())
+ {
+ this.chatPanel.startLastMessageCorrection();
+ }
+ }
+ else if (e.getKeyCode() == KeyEvent.VK_DOWN)
+ {
+ if (chatPanel.isMessageCorrectionActive())
+ {
+ Document doc = editorPane.getDocument();
+ if (editorPane.getCaretPosition() == doc.getLength())
+ {
+ chatPanel.stopMessageCorrection();
+ }
+ }
+ }
}
public void keyReleased(KeyEvent e) {}
@@ -1297,4 +1318,15 @@ public class ChatWritePanel
smsNumberLabel.setText(String.valueOf(smsNumberCount));
}
}
+
+ /**
+ * Sets the background of the write area to the specified color.
+ *
+ * @param color The color to set the background to.
+ */
+ public void setEditorPaneBackground(Color color)
+ {
+ this.centerPanel.setBackground(color);
+ this.editorPane.setBackground(color);
+ }
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/MetaContactChatTransport.java b/src/net/java/sip/communicator/impl/gui/main/chat/MetaContactChatTransport.java
index e3e0b83..73a8ae9 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/MetaContactChatTransport.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/MetaContactChatTransport.java
@@ -110,9 +110,6 @@ public class MetaContactChatTransport
}
}
-
-
-
/**
* Returns the contact associated with this transport.
* @return the contact associated with this transport
@@ -194,6 +191,30 @@ public class MetaContactChatTransport
}
/**
+ * Returns <code>true</code> if this chat transport supports message
+ * corrections and false otherwise.
+ *
+ * @return <code>true</code> if this chat transport supports message
+ * corrections and false otherwise.
+ */
+ public boolean allowsMessageCorrections()
+ {
+ OperationSetContactCapabilities capOpSet = getProtocolProvider()
+ .getOperationSet(OperationSetContactCapabilities.class);
+
+ if (capOpSet != null)
+ {
+ return capOpSet.getOperationSet(
+ contact, OperationSetMessageCorrection.class) != null;
+ }
+ else
+ {
+ return contact.getProtocolProvider().getOperationSet(
+ OperationSetMessageCorrection.class) != null;
+ }
+ }
+
+ /**
* Returns <code>true</code> if this chat transport supports sms
* messaging, otherwise returns <code>false</code>.
*
@@ -260,8 +281,8 @@ public class MetaContactChatTransport
}
/**
- * Sends the given instant message trough this chat transport, by specifying
- * the mime type (html or plain text).
+ * Sends the given instant message through this chat transport,
+ * by specifying the mime type (html or plain text).
*
* @param message The message to send.
* @param mimeType The mime type of the message to send: text/html or
@@ -299,6 +320,45 @@ public class MetaContactChatTransport
}
/**
+ * Sends <tt>message</tt> as a message correction through this transport,
+ * specifying the mime type (html or plain text) and the id of the
+ * message to replace.
+ *
+ * @param message The message to send.
+ * @param mimeType The mime type of the message to send: text/html or
+ * text/plain.
+ * @param correctedMessageUID The ID of the message being corrected by
+ * this message.
+ */
+ public void correctInstantMessage(String message, String mimeType,
+ String correctedMessageUID)
+ {
+ if (!allowsMessageCorrections())
+ {
+ return;
+ }
+
+ OperationSetMessageCorrection mcOpSet = contact.getProtocolProvider()
+ .getOperationSet(OperationSetMessageCorrection.class);
+
+ Message msg;
+ if (mimeType.equals(OperationSetBasicInstantMessaging.HTML_MIME_TYPE)
+ && mcOpSet.isContentTypeSupported(
+ OperationSetBasicInstantMessaging.HTML_MIME_TYPE))
+ {
+ msg = mcOpSet.createMessage(message,
+ OperationSetBasicInstantMessaging.HTML_MIME_TYPE,
+ "utf-8", "");
+ }
+ else
+ {
+ msg = mcOpSet.createMessage(message);
+ }
+
+ mcOpSet.correctMessage(contact, msg, correctedMessageUID);
+ }
+
+ /**
* Determines whether this chat transport supports the supplied content type
*
* @param contentType the type we want to check
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/conference/AdHocConferenceChatTransport.java b/src/net/java/sip/communicator/impl/gui/main/chat/conference/AdHocConferenceChatTransport.java
index 195ea78..48a27dd 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/conference/AdHocConferenceChatTransport.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/conference/AdHocConferenceChatTransport.java
@@ -316,4 +316,31 @@ public class AdHocConferenceChatTransport
// TODO Auto-generated method stub
return 0;
}
+
+ /**
+ * Returns <tt>true</tt> if this chat transport supports message
+ * corrections and false otherwise.
+ *
+ * @return <tt>true</tt> if this chat transport supports message
+ * corrections and false otherwise.
+ */
+ public boolean allowsMessageCorrections()
+ {
+ return false;
+ }
+
+ /**
+ * Sends <tt>message</tt> as a message correction through this transport,
+ * specifying the mime type (html or plain text) and the id of the
+ * message to replace.
+ *
+ * @param message The message to send.
+ * @param mimeType The mime type of the message to send: text/html or
+ * text/plain.
+ * @param correctedMessageUID The ID of the message being corrected by
+ * this message.
+ */
+ public void correctInstantMessage(String message, String mimeType,
+ String correctedMessageUID)
+ {}
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatTransport.java b/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatTransport.java
index d4f196a..e2bd0e5 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatTransport.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/conference/ConferenceChatTransport.java
@@ -318,4 +318,31 @@ public class ConferenceChatTransport
{
return chatRoom;
}
+
+ /**
+ * Sends <tt>message</tt> as a message correction through this transport,
+ * specifying the mime type (html or plain text) and the id of the
+ * message to replace.
+ *
+ * @param message The message to send.
+ * @param mimeType The mime type of the message to send: text/html or
+ * text/plain.
+ * @param correctedMessageUID The ID of the message being corrected by
+ * this message.
+ */
+ public void correctInstantMessage(String message, String mimeType,
+ String correctedMessageUID)
+ {}
+
+ /**
+ * Returns <code>true</code> if this chat transport supports message
+ * corrections and false otherwise.
+ *
+ * @return <code>true</code> if this chat transport supports message
+ * corrections and false otherwise.
+ */
+ public boolean allowsMessageCorrections()
+ {
+ return false;
+ }
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/history/HistoryWindow.java b/src/net/java/sip/communicator/impl/gui/main/chat/history/HistoryWindow.java
index 0a109b6..2c2b216 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/history/HistoryWindow.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/history/HistoryWindow.java
@@ -278,8 +278,11 @@ public class HistoryWindow
.getAccountDisplayName(protocolProvider),
evt.getTimestamp(),
Chat.OUTGOING_MESSAGE,
+ null,
evt.getSourceMessage().getContent(),
- evt.getSourceMessage().getContentType());
+ evt.getSourceMessage().getContentType(),
+ evt.getSourceMessage().getMessageUID(),
+ null);
}
else if(o instanceof MessageReceivedEvent)
{
@@ -290,8 +293,11 @@ public class HistoryWindow
evt.getSourceContact().getDisplayName(),
evt.getTimestamp(),
Chat.INCOMING_MESSAGE,
+ null,
evt.getSourceMessage().getContent(),
- evt.getSourceMessage().getContentType());
+ evt.getSourceMessage().getContentType(),
+ evt.getSourceMessage().getMessageUID(),
+ null);
}
else if(o instanceof ChatRoomMessageReceivedEvent)
{
diff --git a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPane.java b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPane.java
index 2f9e23b..9243cb9 100644
--- a/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPane.java
+++ b/src/net/java/sip/communicator/impl/gui/main/contactlist/ContactListPane.java
@@ -238,8 +238,8 @@ public class ContactListPane
if(metaContact != null)
{
- messageReceived(protocolContact,
- metaContact, message, eventType, evt.getTimestamp());
+ messageReceived(protocolContact, metaContact, message, eventType,
+ evt.getTimestamp(), evt.getCorrectedMessageUID());
}
else
{
@@ -266,7 +266,8 @@ public class ContactListPane
final MetaContact metaContact,
final Message message,
final int eventType,
- final long timestamp)
+ final long timestamp,
+ final String correctedMessageUID)
{
if(!SwingUtilities.isEventDispatchThread())
{
@@ -274,8 +275,8 @@ public class ContactListPane
{
public void run()
{
- messageReceived(protocolContact,
- metaContact, message, eventType, timestamp);
+ messageReceived(protocolContact, metaContact, message,
+ eventType, timestamp, correctedMessageUID);
}
});
return;
@@ -315,7 +316,9 @@ public class ContactListPane
timestamp,
messageType,
message.getContent(),
- message.getContentType());
+ message.getContentType(),
+ message.getMessageUID(),
+ correctedMessageUID);
chatWindowManager.openChat(chatPanel, false);
@@ -361,7 +364,9 @@ public class ContactListPane
evt.getTimestamp(),
Chat.OUTGOING_MESSAGE,
msg.getContent(),
- msg.getContentType());
+ msg.getContentType(),
+ msg.getMessageUID(),
+ evt.getCorrectedMessageUID());
}
}
@@ -429,7 +434,9 @@ public class ContactListPane
System.currentTimeMillis(),
Chat.OUTGOING_MESSAGE,
sourceMessage.getContent(),
- sourceMessage.getContentType());
+ sourceMessage.getContentType(),
+ sourceMessage.getMessageUID(),
+ evt.getCorrectedMessageUID());
chatPanel.addErrorMessage(
metaContact.getDisplayName(),
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/MessageJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/MessageJabberImpl.java
index f502d2b..d417ebc 100755
--- a/src/net/java/sip/communicator/impl/protocol/jabber/MessageJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/MessageJabberImpl.java
@@ -33,4 +33,21 @@ public class MessageJabberImpl
{
super(content, contentType, contentEncoding, subject);
}
+
+ /**
+ * Creates an instance of this Message with the specified parameters.
+ *
+ * @param content the text content of the message.
+ * @param contentType a MIME string indicating the content type of the
+ * <tt>content</tt> String.
+ * @param contentEncoding a MIME String indicating the content encoding of
+ * the <tt>content</tt> String.
+ * @param subject the subject of the message or null for empty.
+ * @param
+ */
+ public MessageJabberImpl(String content, String contentType,
+ String contentEncoding, String subject, String messageUID)
+ {
+ super(content, contentType, contentEncoding, subject, messageUID);
+ }
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java
index 3b14c28..ff7763a 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetBasicInstantMessagingJabberImpl.java
@@ -9,6 +9,7 @@ package net.java.sip.communicator.impl.protocol.jabber;
import java.util.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.mailnotification.*;
+import net.java.sip.communicator.impl.protocol.jabber.extensions.messagecorrection.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.Message;
import net.java.sip.communicator.service.protocol.event.*;
@@ -34,6 +35,7 @@ import org.jivesoftware.smackx.packet.*;
*/
public class OperationSetBasicInstantMessagingJabberImpl
extends AbstractOperationSetBasicInstantMessaging
+ implements OperationSetMessageCorrection
{
/**
* Our class logger
@@ -129,6 +131,13 @@ public class OperationSetBasicInstantMessagingJabberImpl
this.jabberProvider = provider;
provider.addRegistrationStateChangeListener(
new RegistrationStateListener());
+
+ ProviderManager man = ProviderManager.getInstance();
+ MessageCorrectionExtensionProvider extProvider =
+ new MessageCorrectionExtensionProvider();
+ man.addExtensionProvider(MessageCorrectionExtension.ELEMENT_NAME,
+ MessageCorrectionExtension.NAMESPACE,
+ extProvider);
}
/**
@@ -159,6 +168,13 @@ public class OperationSetBasicInstantMessagingJabberImpl
return new MessageJabberImpl(content, contentType, encoding, subject);
}
+ private Message createMessage(String content, String contentType,
+ String messageUID)
+ {
+ return new MessageJabberImpl(content, contentType,
+ DEFAULT_MIME_ENCODING, null, messageUID);
+ }
+
/**
* Determines wheter the protocol provider (or the protocol itself) support
* sending and receiving offline messages. Most often this method would
@@ -350,18 +366,18 @@ public class OperationSetBasicInstantMessagingJabberImpl
}
/**
- * Sends the <tt>message</tt> to the destination indicated by the
- * <tt>to</tt> contact.
- *
- * @param to the <tt>Contact</tt> to send <tt>message</tt> to
- * @param message the <tt>Message</tt> to send.
- * @throws java.lang.IllegalStateException if the underlying stack is
- * not registered and initialized.
- * @throws java.lang.IllegalArgumentException if <tt>to</tt> is not an
- * instance of ContactImpl.
+ * Helper function used to send a message to a contact, with the given
+ * extensions attached.
+ *
+ * @param to The contact to send the message to.
+ * @param message The message to send.
+ * @param extensions The XMPP extensions that should be attached to the
+ * message before sending.
+ * @return The MessageDeliveryEvent that resulted after attempting to
+ * send this message, so the calling function can modify it if needed.
*/
- public void sendInstantMessage(Contact to, Message message)
- throws IllegalStateException, IllegalArgumentException
+ private MessageDeliveredEvent sendMessage(Contact to, Message message,
+ PacketExtension[] extensions)
{
if( !(to instanceof ContactJabberImpl) )
throw new IllegalArgumentException(
@@ -382,8 +398,14 @@ public class OperationSetBasicInstantMessagingJabberImpl
Chat chat = obtainChatInstance(toJID);
+ msg.setPacketID(message.getMessageUID());
msg.setTo(toJID);
+ for (PacketExtension ext : extensions)
+ {
+ msg.addExtension(ext);
+ }
+
if (logger.isTraceEnabled())
logger.trace("Will send a message to:" + toJID
+ " chat.jid=" + chat.getParticipant()
@@ -396,7 +418,7 @@ public class OperationSetBasicInstantMessagingJabberImpl
= messageDeliveryPendingTransform(msgDeliveryPendingEvt);
if (msgDeliveryPendingEvt == null)
- return;
+ return null;
String content = msgDeliveryPendingEvt
.getSourceMessage().getContent();
@@ -421,7 +443,7 @@ public class OperationSetBasicInstantMessagingJabberImpl
// this is plain text so keep it as it is.
msg.setBody(content);
}
-
+
//msg.addExtension(new Version());
MessageEventManager.
@@ -434,16 +456,53 @@ public class OperationSetBasicInstantMessagingJabberImpl
// msgDeliveredEvt = messageDeliveredTransform(msgDeliveredEvt);
- if (msgDeliveredEvt != null)
- fireMessageEvent(msgDeliveredEvt);
+ return msgDeliveredEvt;
}
catch (XMPPException ex)
{
- logger.error("message not send", ex);
+ logger.error("message not sent", ex);
+ return null;
}
}
/**
+ * Sends the <tt>message</tt> to the destination indicated by the
+ * <tt>to</tt> contact.
+ *
+ * @param to the <tt>Contact</tt> to send <tt>message</tt> to
+ * @param message the <tt>Message</tt> to send.
+ * @throws java.lang.IllegalStateException if the underlying stack is
+ * not registered and initialized.
+ * @throws java.lang.IllegalArgumentException if <tt>to</tt> is not an
+ * instance of ContactImpl.
+ */
+ public void sendInstantMessage(Contact to, Message message)
+ throws IllegalStateException, IllegalArgumentException
+ {
+ MessageDeliveredEvent msgDelivered =
+ sendMessage(to, message, new PacketExtension[0]);
+ fireMessageEvent(msgDelivered);
+ }
+
+ /**
+ * Replaces the message with ID <tt>correctedMessageUID</tt> sent to
+ * the contact <tt>to</tt> with the message <tt>message</tt>
+ *
+ * @param to The contact to send the message to.
+ * @param message The new message.
+ * @param correctedMessageUID The ID of the message being replaced.
+ */
+ public void correctMessage(Contact to, Message message,
+ String correctedMessageUID)
+ {
+ PacketExtension[] exts = new PacketExtension[1];
+ exts[0] = new MessageCorrectionExtension(correctedMessageUID);
+ MessageDeliveredEvent msgDelivered = sendMessage(to, message, exts);
+ msgDelivered.setCorrectedMessageUID(correctedMessageUID);
+ fireMessageEvent(msgDelivered);
+ }
+
+ /**
* Utility method throwing an exception if the stack is not properly
* initialized.
*
@@ -581,7 +640,8 @@ public class OperationSetBasicInstantMessagingJabberImpl
+ msg.toXML());
}
- Message newMessage = createMessage(msg.getBody());
+ Message newMessage = createMessage(msg.getBody(),
+ DEFAULT_MIME_TYPE, msg.getPacketID());
//check if the message is available in xhtml
PacketExtension ext = msg.getExtension(
@@ -619,11 +679,20 @@ public class OperationSetBasicInstantMessagingJabberImpl
receivedMessage =
receivedMessage.replaceAll("&apos;", "&#39;");
- newMessage =
- createMessage(receivedMessage, HTML_MIME_TYPE);
+ newMessage = createMessage(receivedMessage,
+ HTML_MIME_TYPE, msg.getPacketID());
}
}
+ PacketExtension correctionExtension =
+ msg.getExtension(MessageCorrectionExtension.NAMESPACE);
+ String correctedMessageUID = null;
+ if (correctionExtension != null)
+ {
+ correctedMessageUID = ((MessageCorrectionExtension)
+ correctionExtension).getCorrectedMessageUID();
+ }
+
Contact sourceContact
= opSetPersPresence.findContactByID(fromUserID);
@@ -652,6 +721,7 @@ public class OperationSetBasicInstantMessagingJabberImpl
MessageDeliveryFailedEvent ev
= new MessageDeliveryFailedEvent(newMessage,
sourceContact,
+ correctedMessageUID,
errorResultCode);
// ev = messageDeliveryFailedTransform(ev);
@@ -681,9 +751,8 @@ public class OperationSetBasicInstantMessagingJabberImpl
.createVolatileContact(fromUserID);
}
- MessageReceivedEvent msgReceivedEvt
- = new MessageReceivedEvent(
- newMessage, sourceContact , System.currentTimeMillis() );
+ MessageReceivedEvent msgReceivedEvt = new MessageReceivedEvent(
+ newMessage, sourceContact, correctedMessageUID);
// msgReceivedEvt = messageReceivedTransform(msgReceivedEvt);
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetContactCapabilitiesJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetContactCapabilitiesJabberImpl.java
index b030dfb..35d7f83 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetContactCapabilitiesJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/OperationSetContactCapabilitiesJabberImpl.java
@@ -9,6 +9,7 @@ package net.java.sip.communicator.impl.protocol.jabber;
import java.util.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.caps.*;
+import net.java.sip.communicator.impl.protocol.jabber.extensions.messagecorrection.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
@@ -70,6 +71,7 @@ public class OperationSetContactCapabilitiesJabberImpl
static
{
OFFLINE_OPERATION_SETS.add(OperationSetBasicInstantMessaging.class);
+ OFFLINE_OPERATION_SETS.add(OperationSetMessageCorrection.class);
OPERATION_SETS_TO_FEATURES.put(
OperationSetBasicTelephony.class,
@@ -98,6 +100,13 @@ public class OperationSetContactCapabilitiesJabberImpl
ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_RTP_VIDEO
});
+ OPERATION_SETS_TO_FEATURES.put(
+ OperationSetMessageCorrection.class,
+ new String[]
+ {
+ MessageCorrectionExtension.NAMESPACE
+ });
+
CAPS_OPERATION_SETS_TO_FEATURES.put(
OperationSetBasicTelephony.class,
new String[]
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
index 4a2c4c6..3a8197d 100644
--- a/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/ProtocolProviderServiceJabberImpl.java
@@ -25,6 +25,7 @@ import net.java.sip.communicator.impl.protocol.jabber.extensions.inputevt.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingle.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.jingleinfo.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.keepalive.*;
+import net.java.sip.communicator.impl.protocol.jabber.extensions.messagecorrection.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.version.*;
import net.java.sip.communicator.impl.protocol.jabber.sasl.*;
import net.java.sip.communicator.service.certificate.*;
@@ -1787,6 +1788,10 @@ public class ProtocolProviderServiceJabberImpl
if(versionManager == null)
versionManager = new VersionManager(this);
+ supportedFeatures.add(MessageCorrectionExtension.NAMESPACE);
+ addSupportedOperationSet(OperationSetMessageCorrection.class,
+ basicInstantMessaging);
+
isInitialized = true;
}
}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/messagecorrection/MessageCorrectionExtension.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/messagecorrection/MessageCorrectionExtension.java
new file mode 100644
index 0000000..12e3c4a
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/messagecorrection/MessageCorrectionExtension.java
@@ -0,0 +1,109 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.jabber.extensions.messagecorrection;
+
+import org.jivesoftware.smack.packet.*;
+
+/**
+ * Represents an XMPP Message correction extension, as defined in XEP-308.
+ *
+ * @author Ivan Vergiliev
+ */
+public class MessageCorrectionExtension
+ implements PacketExtension
+{
+ /**
+ * The XMPP namespace that this extension belongs to.
+ */
+ public static final String NAMESPACE = "urn:xmpp:message-correct:0";
+
+ /**
+ * The XMPP namespace that Swift IM use to send message corrections.
+ * Temporary until they start using the standard one.
+ */
+ public static final String SWIFT_NAMESPACE =
+ "http://swift.im/protocol/replace";
+
+ /**
+ * The XML element name of this extension.
+ */
+ public static final String ELEMENT_NAME = "replace";
+
+ /**
+ * Name of the attribute that specifies the ID of the message
+ * being corrected.
+ */
+ public static final String ID_ATTRIBUTE_NAME = "id";
+
+ /**
+ * The ID of the message being corrected.
+ */
+ private String correctedMessageUID;
+
+ /**
+ * Creates a new message correction extension that corrects the
+ * message specified by the passed ID.
+ *
+ * @param correctedMessageUID The ID of the message being corrected.
+ */
+ public MessageCorrectionExtension(String correctedMessageUID)
+ {
+ this.correctedMessageUID = correctedMessageUID;
+ }
+
+ /**
+ * Returns the XML element name of this extension.
+ *
+ * @return The XML element name of this extension.
+ */
+ public String getElementName()
+ {
+ return ELEMENT_NAME;
+ }
+
+ /**
+ * Returns the XML namespace this extension belongs to.
+ *
+ * @return The XML namespace this extension belongs to.
+ */
+ public String getNamespace()
+ {
+ return NAMESPACE;
+ }
+
+ /**
+ * Construct an XML element representing this extension;
+ * has the form '<replace id="..." xmlns="...">'.
+ *
+ * @return An XML representation of this extension.
+ */
+ public String toXML()
+ {
+ return "<" + ELEMENT_NAME + " id='" + correctedMessageUID
+ + "' xmlns='" + NAMESPACE + "' />";
+ }
+
+ /**
+ * Returns the correctedMessageUID The UID of the message being corrected.
+ *
+ * @return the correctedMessageUID The UID of the message being corrected.
+ */
+ public String getCorrectedMessageUID()
+ {
+ return correctedMessageUID;
+ }
+
+ /**
+ * Sets the UID of the message being corrected.
+ *
+ * @param correctedMessageUID The UID of the message being corrected.
+ */
+ public void setCorrectedMessageUID(String correctedMessageUID)
+ {
+ this.correctedMessageUID = correctedMessageUID;
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/jabber/extensions/messagecorrection/MessageCorrectionExtensionProvider.java b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/messagecorrection/MessageCorrectionExtensionProvider.java
new file mode 100644
index 0000000..81ac147
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/jabber/extensions/messagecorrection/MessageCorrectionExtensionProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.jabber.extensions.messagecorrection;
+
+import org.jivesoftware.smack.packet.*;
+import org.jivesoftware.smack.provider.*;
+import org.xmlpull.v1.*;
+
+/**
+ * Creates Smack packet extensions by parsing <replace /> tags
+ * from incoming XMPP packets.
+ *
+ * @author Ivan Vergiliev
+ */
+public class MessageCorrectionExtensionProvider
+ implements PacketExtensionProvider
+{
+
+ /**
+ * Creates a new correction extension by parsing an XML element.
+ *
+ * @param parser An XML parser.
+ * @return A new MesssageCorrectionExtension parsed from the XML.
+ * @throws Exception if an error occurs parsing the XML.
+ */
+ public PacketExtension parseExtension(XmlPullParser parser) throws Exception
+ {
+ MessageCorrectionExtension res = new MessageCorrectionExtension(null);
+
+ do
+ {
+ if (parser.getEventType() == XmlPullParser.START_TAG)
+ {
+ res.setCorrectedMessageUID(parser.getAttributeValue(
+ null, MessageCorrectionExtension.ID_ATTRIBUTE_NAME));
+ }
+ }
+ while (parser.next() != XmlPullParser.END_TAG);
+
+ return res;
+ }
+}
diff --git a/src/net/java/sip/communicator/service/protocol/AbstractMessage.java b/src/net/java/sip/communicator/service/protocol/AbstractMessage.java
index a623dd0..620bf78 100644
--- a/src/net/java/sip/communicator/service/protocol/AbstractMessage.java
+++ b/src/net/java/sip/communicator/service/protocol/AbstractMessage.java
@@ -68,7 +68,7 @@ public abstract class AbstractMessage
setEncoding(encoding);
setContent(content);
- this.messageUID = messageUID;
+ this.messageUID = messageUID == null ? createMessageUID() : messageUID;
}
protected String createMessageUID()
diff --git a/src/net/java/sip/communicator/service/protocol/OperationSetMessageCorrection.java b/src/net/java/sip/communicator/service/protocol/OperationSetMessageCorrection.java
new file mode 100644
index 0000000..01c095f
--- /dev/null
+++ b/src/net/java/sip/communicator/service/protocol/OperationSetMessageCorrection.java
@@ -0,0 +1,27 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.service.protocol;
+
+/**
+ * Provides functionality for correcting instant messages.
+ *
+ * @author Ivan Vergiliev
+ */
+public interface OperationSetMessageCorrection
+ extends OperationSetBasicInstantMessaging
+{
+ /**
+ * Replaces the message with ID <tt>correctedMessageUID</tt> sent to
+ * the contact <tt>to</tt> with the message <tt>message</tt>
+ *
+ * @param to The contact to send the message to.
+ * @param message The new message.
+ * @param correctedMessageUID The ID of the message being replaced.
+ */
+ public void correctMessage(Contact to, Message message,
+ String correctedMessageUID);
+}
diff --git a/src/net/java/sip/communicator/service/protocol/event/MessageDeliveredEvent.java b/src/net/java/sip/communicator/service/protocol/event/MessageDeliveredEvent.java
index 0ffc91b..17a6e0a 100644
--- a/src/net/java/sip/communicator/service/protocol/event/MessageDeliveredEvent.java
+++ b/src/net/java/sip/communicator/service/protocol/event/MessageDeliveredEvent.java
@@ -33,6 +33,12 @@ public class MessageDeliveredEvent
* A timestamp indicating the exact date when the event occurred.
*/
private final long timestamp;
+
+ /**
+ * The ID of the message being corrected, or null if this was a new message
+ * and not a message correction.
+ */
+ private String correctedMessageUID;
/**
* Constructor.
@@ -44,6 +50,21 @@ public class MessageDeliveredEvent
{
this(source, to, System.currentTimeMillis());
}
+
+ /**
+ * Creates a <tt>MessageDeliveredEvent</tt> representing delivery of the
+ * <tt>source</tt> message to the specified <tt>to</tt> contact.
+ *
+ * @param source the <tt>Message</tt> whose delivery this event represents.
+ * @param to the <tt>Contact</tt> that this message was sent to.
+ * @param correctedMessageUID The ID of the message being corrected.
+ */
+ public MessageDeliveredEvent(Message source, Contact to,
+ String correctedMessageUID)
+ {
+ this(source, to, System.currentTimeMillis());
+ this.correctedMessageUID = correctedMessageUID;
+ }
/**
* Creates a <tt>MessageDeliveredEvent</tt> representing delivery of the
@@ -93,4 +114,26 @@ public class MessageDeliveredEvent
return timestamp;
}
+ /**
+ * Returns the ID of the message being corrected, or null if this was a
+ * new message and not a message correction.
+ *
+ * @return the ID of the message being corrected, or null if this was a
+ * new message and not a message correction.
+ */
+ public String getCorrectedMessageUID()
+ {
+ return correctedMessageUID;
+ }
+
+ /**
+ * Sets the ID of the message being corrected to the passed ID.
+ *
+ * @param correctedMessageUID The ID of the message being corrected.
+ */
+ public void setCorrectedMessageUID(String correctedMessageUID)
+ {
+ this.correctedMessageUID = correctedMessageUID;
+ }
+
}
diff --git a/src/net/java/sip/communicator/service/protocol/event/MessageDeliveryFailedEvent.java b/src/net/java/sip/communicator/service/protocol/event/MessageDeliveryFailedEvent.java
index cba4101..e0f60a3 100644
--- a/src/net/java/sip/communicator/service/protocol/event/MessageDeliveryFailedEvent.java
+++ b/src/net/java/sip/communicator/service/protocol/event/MessageDeliveryFailedEvent.java
@@ -75,6 +75,12 @@ public class MessageDeliveryFailedEvent
private final long timestamp;
/**
+ * The ID of the message being corrected, or null if this was a new message
+ * and not a message correction.
+ */
+ private String correctedMessageUID;
+
+ /**
* Constructor.
*
* @param source the message
@@ -87,6 +93,23 @@ public class MessageDeliveryFailedEvent
{
this(source, to, errorCode, System.currentTimeMillis(), null);
}
+
+ /**
+ * Constructor.
+ *
+ * @param source the message
+ * @param to the "to" contact
+ * @param correctedMessageUID The ID of the message being corrected.
+ * @param errorCode error code
+ */
+ public MessageDeliveryFailedEvent(Message source,
+ Contact to,
+ String correctedMessageUID,
+ int errorCode)
+ {
+ this(source, to, errorCode, System.currentTimeMillis(), null);
+ this.correctedMessageUID = correctedMessageUID;
+ }
/**
* Creates a <tt>MessageDeliveryFailedEvent</tt> indicating failure of
@@ -190,4 +213,14 @@ public class MessageDeliveryFailedEvent
{
return reasonPhrase;
}
+
+ /**
+ * Sets the ID of the message being corrected to the passed ID.
+ *
+ * @param correctedMessageUID The ID of the message being corrected.
+ */
+ public String getCorrectedMessageUID()
+ {
+ return correctedMessageUID;
+ }
}
diff --git a/src/net/java/sip/communicator/service/protocol/event/MessageReceivedEvent.java b/src/net/java/sip/communicator/service/protocol/event/MessageReceivedEvent.java
index 959101b..cd15cf6 100644
--- a/src/net/java/sip/communicator/service/protocol/event/MessageReceivedEvent.java
+++ b/src/net/java/sip/communicator/service/protocol/event/MessageReceivedEvent.java
@@ -55,6 +55,12 @@ public class MessageReceivedEvent
* The type of message event that this instance represents.
*/
private int eventType = -1;
+
+ /**
+ * The ID of the message being corrected, or null if this is a new message
+ * and not a correction.
+ */
+ private String correctedMessageUID = null;
/**
* Creates a <tt>MessageReceivedEvent</tt> representing reception of the
@@ -77,6 +83,23 @@ public class MessageReceivedEvent
*
* @param source the <tt>Message</tt> whose reception this event represents.
* @param from the <tt>Contact</tt> that has sent this message.
+ * @param timestamp the exact date when the event ocurred.
+ */
+ public MessageReceivedEvent(Message source, Contact from,
+ String correctedMessageUID)
+ {
+ this(source, from, System.currentTimeMillis(),
+ CONVERSATION_MESSAGE_RECEIVED);
+ this.correctedMessageUID = correctedMessageUID;
+ }
+
+ /**
+ * Creates a <tt>MessageReceivedEvent</tt> representing reception of the
+ * <tt>source</tt> message received from the specified <tt>from</tt>
+ * contact.
+ *
+ * @param source the <tt>Message</tt> whose reception this event represents.
+ * @param from the <tt>Contact</tt> that has sent this message.
* @param timestamp the exact date when the event occurred.
* @param eventType the type of message event that this instance represents
* (one of the XXX_MESSAGE_RECEIVED static fields).
@@ -92,10 +115,10 @@ public class MessageReceivedEvent
}
/**
- * Returns a reference to the <tt>Contact</tt> that has send the
+ * Returns a reference to the <tt>Contact</tt> that has sent the
* <tt>Message</tt> whose reception this event represents.
*
- * @return a reference to the <tt>Contact</tt> that has send the
+ * @return a reference to the <tt>Contact</tt> that has sent the
* <tt>Message</tt> whose reception this event represents.
*/
public Contact getSourceContact()
@@ -135,4 +158,16 @@ public class MessageReceivedEvent
{
return eventType;
}
+
+ /**
+ * Returns the correctedMessageUID The ID of the message being corrected,
+ * or null if this is a new message and not a correction.
+ *
+ * @return the correctedMessageUID The ID of the message being corrected,
+ * or null if this is a new message and not a correction.
+ */
+ public String getCorrectedMessageUID()
+ {
+ return correctedMessageUID;
+ }
}