diff --git a/build.xml b/build.xml
index 0c6927996..11db75c8a 100644
--- a/build.xml
+++ b/build.xml
@@ -1734,7 +1734,7 @@ javax.swing.event, javax.swing.border"/>
-
+
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 016a576b2..64afad228 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatConversationPanel.java
@@ -13,16 +13,14 @@
import java.net.*;
import java.text.*;
import java.util.*;
+import java.util.Map;
import java.util.regex.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import javax.swing.text.html.*;
-import javax.swing.text.html.HTML.*;
-
-import org.jitsi.service.configuration.*;
-import org.jitsi.service.fileaccess.FileCategory;
+import javax.swing.text.html.HTML.Attribute;
import net.java.sip.communicator.impl.gui.*;
import net.java.sip.communicator.impl.gui.main.chat.history.*;
@@ -40,8 +38,11 @@
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.Logger;
import net.java.sip.communicator.util.skin.*;
-import org.jitsi.util.*;
+import org.apache.commons.lang3.*;
+import org.jitsi.service.configuration.*;
+import org.jitsi.service.fileaccess.*;
+import org.jitsi.util.StringUtils;
import org.osgi.framework.*;
/**
@@ -92,16 +93,15 @@ public class ChatConversationPanel
Pattern.compile("(]*>)(.*)(
)", Pattern.DOTALL);
/**
- * Extracting text from plaintext tags or content of anchors,
- * text to be replaced.
+ * A regular expression for searching all pieces of plain text within a blob
+ * of HTML text. This expression assumes that the plain text part is
+ * correctly escaped, such that there is no occurrence of the symbols <
+ * and >.
+ *
+ * The first group matches any piece of text outside of HTML tags.
*/
- private static final Pattern TEXT_TO_REPLACE_PATTERN =
- Pattern.compile(
- ChatHtmlUtils.START_PLAINTEXT_TAG
- + "(.*?)" +
- ChatHtmlUtils.END_PLAINTEXT_TAG
- + "|]+>(.+?)",
- Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
+ public static final Pattern TEXT_TO_REPLACE_PATTERN = Pattern.compile(
+ "([^<]*+)(?:<[^>]*+>)?", Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
/**
* List for observing text messages.
@@ -466,16 +466,16 @@ public String processMessage( ChatMessage chatMessage,
ProtocolProviderService protocolProvider,
String contactAddress)
{
- String contentType = chatMessage.getContentType();
-
// If this is a consecutive message don't go through the initiation
// and just append it.
if (isConsecutiveMessage(chatMessage))
{
- appendConsecutiveMessage(chatMessage, keyword, contentType);
+ appendConsecutiveMessage(chatMessage, keyword);
return null;
}
+ String contentType = chatMessage.getContentType();
+
lastMessageTimestamp = chatMessage.getDate();
String contactName = chatMessage.getContactName();
@@ -510,8 +510,8 @@ public String processMessage( ChatMessage chatMessage,
contactDisplayName,
getContactAvatar(protocolProvider, contactAddress),
date,
- formatMessage(message, contentType, keyword),
- contentType,
+ formatMessageAsHTML(message, contentType, keyword),
+ ChatHtmlUtils.HTML_CONTENT_TYPE,
false,
isSimpleTheme);
}
@@ -523,8 +523,8 @@ else if (messageType.equals(Chat.OUTGOING_MESSAGE))
contactDisplayName,
getContactAvatar(protocolProvider),
date,
- formatMessage(message, contentType, keyword),
- contentType,
+ formatMessageAsHTML(message, contentType, keyword),
+ ChatHtmlUtils.HTML_CONTENT_TYPE,
false,
isSimpleTheme);
}
@@ -536,8 +536,8 @@ else if (messageType.equals(Chat.HISTORY_INCOMING_MESSAGE))
contactDisplayName,
getContactAvatar(protocolProvider, contactAddress),
date,
- formatMessage(message, contentType, keyword),
- contentType,
+ formatMessageAsHTML(message, contentType, keyword),
+ ChatHtmlUtils.HTML_CONTENT_TYPE,
true,
isSimpleTheme);
}
@@ -549,8 +549,8 @@ else if (messageType.equals(Chat.HISTORY_OUTGOING_MESSAGE))
contactDisplayName,
getContactAvatar(protocolProvider),
date,
- formatMessage(message, contentType, keyword),
- contentType,
+ formatMessageAsHTML(message, contentType, keyword),
+ ChatHtmlUtils.HTML_CONTENT_TYPE,
true,
isSimpleTheme);
}
@@ -563,20 +563,23 @@ else if (messageType.equals(Chat.SMS_MESSAGE))
getContactAvatar(protocolProvider, contactAddress),
date,
ConfigurationUtils.isSmsNotifyTextDisabled() ?
- formatMessage(message, contentType, keyword)
- : formatMessage("SMS: " + message, contentType, keyword),
- contentType,
+ formatMessageAsHTML(message, contentType, keyword)
+ : formatMessageAsHTML("SMS: " + message, contentType, keyword),
+ ChatHtmlUtils.HTML_CONTENT_TYPE,
false,
isSimpleTheme);
}
else if (messageType.equals(Chat.STATUS_MESSAGE))
{
- chatString = "";
+ chatString = "";
endHeaderTag = "
";
- chatString
- += GuiUtils.formatTime(date) + " " + contactName + " " + message
+ chatString +=
+ GuiUtils.formatTime(date)
+ + " "
+ + processLinksAndHTMLChars(contactName, true,
+ ChatHtmlUtils.TEXT_CONTENT_TYPE) + " "
+ + formatMessageAsHTML(message, contentType, keyword)
+ endHeaderTag;
}
else if (messageType.equals(Chat.ACTION_MESSAGE))
@@ -586,24 +589,21 @@ else if (messageType.equals(Chat.ACTION_MESSAGE))
endHeaderTag = "
";
chatString += "* " + GuiUtils.formatTime(date)
- + " " + contactName + " "
- + message
+ + " " + processLinksAndHTMLChars(contactName, true,
+ ChatHtmlUtils.TEXT_CONTENT_TYPE) + " "
+ + formatMessageAsHTML(message, contentType, keyword)
+ endHeaderTag;
}
else if (messageType.equals(Chat.SYSTEM_MESSAGE))
{
- String startSystemDivTag
- = "";
+ String startSystemDivTag =
+ "
";
String endDivTag = "
";
- String startPlainTextTag
- = ChatHtmlUtils.createStartPlainTextTag(contentType);
- String endPlainTextTag
- = ChatHtmlUtils.createEndPlainTextTag(contentType);
- chatString
- += startSystemDivTag + startPlainTextTag
- + formatMessage(message, contentType, keyword)
- + endPlainTextTag + endDivTag;
+ chatString +=
+ startSystemDivTag
+ + formatMessageAsHTML(message, contentType, keyword)
+ + endDivTag;
}
else if (messageType.equals(Chat.ERROR_MESSAGE))
{
@@ -621,11 +621,22 @@ else if (messageType.equals(Chat.ERROR_MESSAGE))
// If the message title is null do not show it and show the error
// icon on the same line as the actual error message.
if (messageTitle != null)
- chatString += errorIcon + messageTitle + endHeaderTag
- + "
" + message + "
";
+ {
+ chatString +=
+ errorIcon
+ + processLinksAndHTMLChars(messageTitle, true,
+ ChatHtmlUtils.TEXT_CONTENT_TYPE) + endHeaderTag
+ + "
"
+ + formatMessageAsHTML(message, contentType, keyword)
+ + "
";
+ }
else
- chatString += endHeaderTag
- + "
" + errorIcon + " " + message + "
";
+ {
+ chatString +=
+ endHeaderTag + "
" + errorIcon + " "
+ + formatMessageAsHTML(message, contentType, keyword)
+ + "
";
+ }
}
return chatString;
@@ -651,11 +662,10 @@ public String processMessage( ChatMessage chatMessage,
* Appends a consecutive message to the document.
*
* @param chatMessage the message to append
- * @return
true if the append succeeded,
false - otherwise
+ * @param keyword the keywords to highlight
*/
- public void appendConsecutiveMessage( final ChatMessage chatMessage,
- final String keyword,
- final String contentType)
+ public void appendConsecutiveMessage(final ChatMessage chatMessage,
+ final String keyword)
{
String previousMessageUID = lastMessageUID;
lastMessageUID = chatMessage.getMessageUID();
@@ -666,9 +676,7 @@ public void appendConsecutiveMessage( final ChatMessage chatMessage,
{
public void run()
{
- appendConsecutiveMessage( chatMessage,
- keyword,
- contentType);
+ appendConsecutiveMessage(chatMessage, keyword);
}
});
return;
@@ -691,10 +699,11 @@ public void run()
String newMessage = ChatHtmlUtils.createMessageTag(
chatMessage.getMessageUID(),
contactAddress,
- formatMessage(chatMessage.getMessage(),
- contentType,
+ formatMessageAsHTML(
+ chatMessage.getMessage(),
+ chatMessage.getContentType(),
keyword),
- contentType,
+ ChatHtmlUtils.HTML_CONTENT_TYPE,
chatMessage.getDate(),
false,
isHistory,
@@ -723,7 +732,7 @@ public void run()
}
}
- finishMessageAdd(newMessage, contentType);
+ finishMessageAdd(newMessage);
}
/**
@@ -776,10 +785,10 @@ public void run()
String newMessage = ChatHtmlUtils.createMessageTag(
chatMessage.getMessageUID(),
contactAddress,
- formatMessage( chatMessage.getMessage(),
+ formatMessageAsHTML(chatMessage.getMessage(),
chatMessage.getContentType(),
""),
- chatMessage.getContentType(),
+ ChatHtmlUtils.HTML_CONTENT_TYPE,
chatMessage.getDate(),
true,
isHistory,
@@ -806,16 +815,21 @@ public void run()
}
}
- finishMessageAdd(newMessage, chatMessage.getContentType());
+ finishMessageAdd(newMessage);
}
/**
* Appends the given string at the end of the contained in this panel
* document.
*
- * @param message the message string to append
+ * Note: Currently, it looks like appendMessageToEnd is only called for
+ * messages that are already converted to HTML. So It is quite possible that
+ * we can remove the content type without any issues.
+ *
+ * @param original the message string to append
+ * @param contentType the message's content type
*/
- public void appendMessageToEnd(final String message,
+ public void appendMessageToEnd(final String original,
final String contentType)
{
if (!SwingUtilities.isEventDispatchThread())
@@ -824,14 +838,26 @@ public void appendMessageToEnd(final String message,
{
public void run()
{
- appendMessageToEnd(message, contentType);
+ appendMessageToEnd(original, contentType);
}
});
return;
}
- if (message == null)
+ if (original == null)
+ {
return;
+ }
+
+ final String message;
+ if (ChatHtmlUtils.HTML_CONTENT_TYPE.equalsIgnoreCase(contentType))
+ {
+ message = original;
+ }
+ else
+ {
+ message = StringEscapeUtils.escapeHtml4(original);
+ }
synchronized (scrollToBottomRunnable)
{
@@ -858,15 +884,14 @@ public void run()
{
logger.error("Insert in the HTMLDocument failed.", e);
}
-
}
String lastElemContent = getElementContent(lastMessageUID, message);
if (lastElemContent != null)
- finishMessageAdd(
- getElementContent(lastMessageUID, message),
- contentType);
+ {
+ finishMessageAdd(lastElemContent);
+ }
}
/**
@@ -876,7 +901,7 @@ public void run()
* @param message the message string
* @param contentType
*/
- private void finishMessageAdd(String message, String contentType)
+ private void finishMessageAdd(final String message)
{
// If we're not in chat history case we need to be sure the document
// has not exceeded the required size (number of messages).
@@ -895,9 +920,8 @@ private void finishMessageAdd(String message, String contentType)
ReplacementProperty.getPropertyName("SMILEY"),
true))
{
- processReplacement( ChatHtmlUtils.MESSAGE_TEXT_ID + lastMessageUID,
- message,
- contentType);
+ processReplacement(ChatHtmlUtils.MESSAGE_TEXT_ID + lastMessageUID,
+ message);
}
}
@@ -908,13 +932,10 @@ private void finishMessageAdd(String message, String contentType)
*
* @param messageID the messageID element.
* @param chatString the message.
- * @param contentType
*/
- void processReplacement(String messageID,
- String chatString,
- String contentType)
+ void processReplacement(final String messageID, final String chatString)
{
- new ReplacementWorker(messageID, chatString, contentType).start();
+ new ReplacementWorker(messageID, chatString).start();
}
/**
@@ -1008,9 +1029,8 @@ private void deleteAllMessagesWithoutHeader()
* @param keyword the searched keyword
* @return the formatted message
*/
- private String processKeyword( String message,
- String contentType,
- String keyword)
+ private String processKeyword(final String message,
+ final String contentType, final String keyword)
{
if(message == null)
return message;
@@ -1023,16 +1043,15 @@ private String processKeyword( String message,
while (m.find())
{
- msgBuffer.append(message.substring(prevEnd, m.start()));
+ msgBuffer.append(StringEscapeUtils.escapeHtml4(message.substring(
+ prevEnd, m.start())));
prevEnd = m.end();
String keywordMatch = m.group().trim();
- msgBuffer.append(ChatHtmlUtils.createEndPlainTextTag(contentType));
msgBuffer.append("
");
- msgBuffer.append(keywordMatch);
+ msgBuffer.append(StringEscapeUtils.escapeHtml4(keywordMatch));
msgBuffer.append("");
- msgBuffer.append(ChatHtmlUtils.createStartPlainTextTag(contentType));
}
/*
@@ -1042,7 +1061,8 @@ private String processKeyword( String message,
if (prevEnd == 0)
return message;
- msgBuffer.append(message.substring(prevEnd));
+ msgBuffer.append(StringEscapeUtils.escapeHtml4(message
+ .substring(prevEnd)));
return msgBuffer.toString();
}
@@ -1055,12 +1075,15 @@ private String processKeyword( String message,
* @param keyword the word to be highlighted
* @return the formatted message
*/
- private String formatMessage(String message,
- String contentType,
- String keyword)
+ private String formatMessageAsHTML(final String original,
+ final String contentType,
+ final String keyword)
{
- if(message == null)
+ if(original == null)
return "";
+
+ String message = original;
+
// If the message content type is HTML we won't process links and
// new lines, but only the smileys.
if (!ChatHtmlUtils.HTML_CONTENT_TYPE.equals(contentType))
@@ -1075,6 +1098,9 @@ private String formatMessage(String message,
if ((keyword != null) && (keyword.length() != 0))
{
+ // TODO Doesn't replacing keywords first cause hyperlinks to be
+ // broken if the keyword is in the hyperlink? Maybe we should
+ // insert anchors first, highlighting keywords.
String messageWithProcessedKeyword
= processKeyword(message, contentType, keyword);
@@ -1095,6 +1121,35 @@ private String formatMessage(String message,
// If the message content is HTML, we process br and img tags.
else
{
+ // For HTML message, also check for hyperlinks.
+ int startPos = 0;
+ final StringBuilder buff = new StringBuilder();
+ final Matcher plainTextInHtmlMatcher =
+ TEXT_TO_REPLACE_PATTERN.matcher(message);
+ while (plainTextInHtmlMatcher.find())
+ {
+ final String plainTextAsHtml = plainTextInHtmlMatcher.group(1);
+ final int startMatchPosition = plainTextInHtmlMatcher.start(1);
+ final int endMatchPosition = plainTextInHtmlMatcher.end(1);
+
+ if (!StringUtils.isNullOrEmpty(plainTextAsHtml))
+ {
+ // always add from the end of previous match, to current one
+ // or from the start to the first match
+ buff.append(
+ message.substring(startPos, startMatchPosition));
+
+ final String plaintext =
+ StringEscapeUtils.unescapeHtml4(plainTextAsHtml);
+ buff.append(processLinksAndHTMLChars(plaintext, true,
+ ChatHtmlUtils.TEXT_CONTENT_TYPE));
+
+ startPos = endMatchPosition;
+ }
+ }
+ buff.append(message.substring(startPos));
+ message = buff.toString();
+
if ((keyword != null) && (keyword.length() != 0))
message = processKeyword(message, contentType, keyword);
message = processImgTags(processBrTags(message));
@@ -1118,9 +1173,9 @@ private String formatMessage(String message,
* @param contentType the message content type (html or plain text)
* @return The message string with properly formatted links.
*/
- private String processLinksAndHTMLChars(String message,
- boolean processHTMLChars,
- String contentType)
+ private String processLinksAndHTMLChars(final String message,
+ final boolean processHTMLChars,
+ final String contentType)
{
Matcher m = URL_PATTERN.matcher(message);
StringBuffer msgBuffer = new StringBuffer();
@@ -1128,33 +1183,41 @@ private String processLinksAndHTMLChars(String message,
while (m.find())
{
- String fromPrevEndToStart = message.substring(prevEnd, m.start());
-
+ final String rawMessage = message.substring(prevEnd, m.start());
+ final String fromPrevEndToStart;
if (processHTMLChars)
{
- fromPrevEndToStart =
- GuiUtils.escapeHTMLChars(fromPrevEndToStart);
+ fromPrevEndToStart = StringEscapeUtils.escapeHtml4(rawMessage);
+ }
+ else
+ {
+ fromPrevEndToStart = rawMessage;
}
msgBuffer.append(fromPrevEndToStart);
prevEnd = m.end();
String url = m.group().trim();
- msgBuffer.append(ChatHtmlUtils.createEndPlainTextTag(contentType));
msgBuffer.append("
");
- msgBuffer.append(url);
+ msgBuffer.append(StringEscapeUtils.escapeHtml4(url));
msgBuffer.append("");
- msgBuffer.append(ChatHtmlUtils.createStartPlainTextTag(contentType));
}
- String fromPrevEndToEnd = message.substring(prevEnd);
-
+ final String rawMessage = message.substring(prevEnd);
+ final String fromPrevEndToEnd;
if (processHTMLChars)
- fromPrevEndToEnd = GuiUtils.escapeHTMLChars(fromPrevEndToEnd);
+ {
+ fromPrevEndToEnd = StringEscapeUtils.escapeHtml4(rawMessage);
+ }
+ else
+ {
+ fromPrevEndToEnd = rawMessage;
+ }
+
msgBuffer.append(fromPrevEndToEnd);
return msgBuffer.toString();
@@ -1190,15 +1253,7 @@ private String processNewLines(String message, String contentType)
message = divMatcher.group(2);
closingTag = divMatcher.group(3);
}
- return
- openingTag +
- message
- .replaceAll(
- "\n",
- ChatHtmlUtils.createEndPlainTextTag(contentType)
- + "
"
- + ChatHtmlUtils.createStartPlainTextTag(contentType))
- + closingTag;
+ return openingTag + message.replaceAll("\n", "
") + closingTag;
}
/**
@@ -1746,11 +1801,10 @@ public String processMeCommand(ChatMessage chatMessage)
Pattern.compile(sourcePattern, Pattern.CASE_INSENSITIVE
| Pattern.DOTALL);
Matcher m = p.matcher(chatString);
- // Surround all smilies with
tags.
- chatString = m.replaceAll(
- ChatHtmlUtils.createStartPlainTextTag(contentType)
- + "$0"
- + ChatHtmlUtils.createEndPlainTextTag(contentType));
+ chatString =
+ m.replaceAll(ChatHtmlUtils.HTML_CONTENT_TYPE
+ .equalsIgnoreCase(contentType) ? "$0" : StringEscapeUtils
+ .escapeHtml4("$0"));
}
return chatString;
}
@@ -2185,7 +2239,7 @@ public void debug()
/**
* Swing worker used by processReplacement.
*/
- private class ReplacementWorker
+ private final class ReplacementWorker
extends SwingWorker
{
/**
@@ -2198,11 +2252,6 @@ private class ReplacementWorker
*/
private final String chatString;
- /**
- * The content type of the message.
- */
- private final String contentType;
-
/**
* Counts links while processing. Used to generate unique href.
*/
@@ -2220,16 +2269,15 @@ private class ReplacementWorker
/**
* Constructs worker.
+ *
* @param messageID the messageID element.
* @param chatString the messages.
- * @param contentType the message content type.
*/
- private ReplacementWorker(
- String messageID, String chatString, String contentType)
+ private ReplacementWorker(final String messageID,
+ final String chatString)
{
this.messageID = messageID;
this.chatString = chatString;
- this.contentType = contentType;
ConfigurationService cfg = GuiActivator.getConfigurationService();
isEnabled = cfg.getBoolean(
@@ -2290,8 +2338,8 @@ public Object construct() throws Exception
}
StringBuilder msgBuff;
- for (Map.Entry entry
- : GuiActivator.getReplacementSources().entrySet())
+ for (Map.Entry entry : GuiActivator
+ .getReplacementSources().entrySet())
{
msgBuff = new StringBuilder();
processReplacementService(entry.getValue(), msgStore, msgBuff);
@@ -2303,59 +2351,44 @@ public Object construct() throws Exception
/**
* Process message for a ReplacementService.
+ *
* @param service the service.
* @param msg the message.
* @param buff current accumulated buffer.
*/
- private void processReplacementService(ReplacementService service,
- String msg,
- StringBuilder buff)
+ private void processReplacementService(final ReplacementService service,
+ final String msg, final StringBuilder buff)
{
String sourcePattern = service.getPattern();
- Pattern pattern
- = Pattern.compile(
- sourcePattern, Pattern.CASE_INSENSITIVE | Pattern.DOTALL);
+ Pattern pattern =
+ Pattern.compile(sourcePattern, Pattern.CASE_INSENSITIVE
+ | Pattern.DOTALL);
int startPos = 0;
- Matcher plainTextMatcher = TEXT_TO_REPLACE_PATTERN.matcher(msg);
- while(plainTextMatcher.find())
+ Matcher plainTextInHtmlMatcher =
+ TEXT_TO_REPLACE_PATTERN.matcher(msg);
+ while (plainTextInHtmlMatcher.find())
{
- // our match pattern detects plaintexts or links
- // the first group is when it detects a plaintext nodes
- // second one is the text inside anchor
-
- String text = plainTextMatcher.group(1);
- int startMatchPosition = plainTextMatcher.start(1);
- int endMatchPosition = plainTextMatcher.end(1);
- // when processing links content we skip processing smileys
- // or we will replace stuff like :p in the links
- boolean skipSmileys = false;
-
- if(text == null)
- {
- text = plainTextMatcher.group(2);
- startMatchPosition = plainTextMatcher.start(2);
- endMatchPosition = plainTextMatcher.end(2);
- skipSmileys = true;
- }
+ String plainTextAsHtml = plainTextInHtmlMatcher.group(1);
+ int startMatchPosition = plainTextInHtmlMatcher.start(1);
+ int endMatchPosition = plainTextInHtmlMatcher.end(1);
+
+ // TODO Current pattern might find URL's too, however links
+ // have already been processed by now, so it will at most modify
+ // the anchor text.
// don't process nothing
// or don't process already processed links content
- if(!StringUtils.isNullOrEmpty(text)
- && !(skipSmileys && text.startsWith("");
- msgBuff.append(
- ChatHtmlUtils.createStartPlainTextTag(
- contentType));
}
else
{
- msgBuff.append(group);
+ msgBuff
+ .append(StringEscapeUtils.escapeHtml4(group));
}
}
else if (isProposalEnabled)
{
- msgBuff.append(group);
- msgBuff.append(
- " "
- + GuiActivator.getResources().
- getI18NString("service.gui.SHOW_PREVIEW"));
+ msgBuff.append(StringEscapeUtils.escapeHtml4(group));
+ msgBuff.append(" "
+ + StringEscapeUtils.escapeHtml4(GuiActivator
+ .getResources().getI18NString(
+ "service.gui.SHOW_PREVIEW")));
showPreview.getMsgIDandPositionToLink()
.put(
@@ -2451,7 +2480,7 @@ else if (isEnabled && isEnabledForSource)
if (isDirectImage)
{
DirectImageReplacementService service
- = (DirectImageReplacementService)rService;
+ = (DirectImageReplacementService) rService;
if (service.isDirectImage(group)
&& service.getImageSize(group) != -1)
{
@@ -2465,7 +2494,8 @@ else if (isEnabled && isEnabledForSource)
}
else
{
- msgBuff.append(group);
+ msgBuff.append(StringEscapeUtils
+ .escapeHtml4(group));
}
}
else
@@ -2481,16 +2511,17 @@ else if (isEnabled && isEnabledForSource)
}
else
{
- msgBuff.append(group);
+ msgBuff.append(StringEscapeUtils.escapeHtml4(group));
}
}
else
{
- msgBuff.append(group);
+ msgBuff.append(StringEscapeUtils.escapeHtml4(group));
}
}
- msgBuff.append(plainText.substring(startPos));
+ msgBuff.append(StringEscapeUtils.escapeHtml4(plainText
+ .substring(startPos)));
}
}
}
diff --git a/src/net/java/sip/communicator/impl/gui/main/chat/ChatHtmlUtils.java b/src/net/java/sip/communicator/impl/gui/main/chat/ChatHtmlUtils.java
index 8a2971dbb..3edc561c3 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatHtmlUtils.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatHtmlUtils.java
@@ -14,6 +14,8 @@
import net.java.sip.communicator.service.history.*;
import net.java.sip.communicator.util.*;
+import org.apache.commons.lang3.*;
+
/**
*
* @author Yana Stamcheva
@@ -46,16 +48,6 @@ public class ChatHtmlUtils
*/
public final static String MESSAGE_TEXT_ID = "message";
- /**
- * The closing tag of the PLAINTEXT HTML element.
- */
- public static final String END_PLAINTEXT_TAG = "";
-
- /**
- * The opening tag of the
PLAINTEXT HTML element.
- */
- public static final String START_PLAINTEXT_TAG = "
";
-
/**
* The html text content type.
*/
@@ -592,44 +584,6 @@ private static String createAdvancedMessageHeaderTag(String nameHeader,
return messageHeader.toString();
}
- /**
- * Creates the start tag, which indicates that the next text would be plain
- * text.
- *
- * @param contentType the current content type
- * @return the start plaintext tag
- */
- public static String createStartPlainTextTag(String contentType)
- {
- if (HTML_CONTENT_TYPE.equals(contentType))
- {
- return "";
- }
- else
- {
- return START_PLAINTEXT_TAG;
- }
- }
-
- /**
- * Creates the end tag, which indicates that the next text would be plain
- * text.
- *
- * @param contentType the current content type
- * @return the end plaintext tag
- */
- public static String createEndPlainTextTag(String contentType)
- {
- if (HTML_CONTENT_TYPE.equals(contentType))
- {
- return "";
- }
- else
- {
- return END_PLAINTEXT_TAG;
- }
- }
-
/**
* Creates a tag that shows the last edit time of a message, in the format
* (Edited at ...).
@@ -695,11 +649,16 @@ private static String createSimpleMessageTag(String messageID,
messageTag.append(IncomingMessageStyle
.createSingleMessageStyle(isHistory, isEdited, true));
messageTag.append(">");
- messageTag.append(createStartPlainTextTag(contentType));
- messageTag.append(message);
+ if (HTML_CONTENT_TYPE.equalsIgnoreCase(contentType))
+ {
+ messageTag.append(message);
+ }
+ else
+ {
+ messageTag.append(StringEscapeUtils.escapeHtml4(message));
+ }
if (isEdited)
messageTag.append(" ");
- messageTag.append(createEndPlainTextTag(contentType));
if (isEdited)
messageTag.append(createEditedAt(date));
messageTag.append(" ");
@@ -740,13 +699,19 @@ private static String createAdvancedMessageTag( String messageID,
messageTag.append(IncomingMessageStyle
.createSingleMessageStyle(isHistory, isEdited, false));
messageTag.append(">");
- messageTag.append(createStartPlainTextTag(contentType));
- messageTag.append(message);
+ if (HTML_CONTENT_TYPE.equalsIgnoreCase(contentType))
+ {
+ messageTag.append(message);
+ }
+ else
+ {
+ messageTag.append(StringEscapeUtils.escapeHtml4(message));
+ }
if (isEdited)
+ {
messageTag.append(" ");
- messageTag.append(createEndPlainTextTag(contentType));
- if (isEdited)
messageTag.append(createEditedAt(date));
+ }
messageTag.append("");
return messageTag.toString();
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 a4f50c5c7..3cd3bb7a3 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
@@ -911,7 +911,7 @@ else if (o instanceof FileRecord)
if (historyString != null)
conversationPanel.appendMessageToEnd(
- historyString, ChatHtmlUtils.TEXT_CONTENT_TYPE);
+ historyString, ChatHtmlUtils.HTML_CONTENT_TYPE);
}
fireChatHistoryChange();
@@ -1091,7 +1091,7 @@ private void displayChatMessage(ChatMessage chatMessage)
*
* @param chatMessage the message to append
*/
- private void appendChatMessage(ChatMessage chatMessage)
+ private void appendChatMessage(final ChatMessage chatMessage)
{
String keyword = null;
@@ -1113,12 +1113,14 @@ private void appendChatMessage(ChatMessage chatMessage)
String meCommandMsg
= this.conversationPanel.processMeCommand(chatMessage);
+ // FIXME I'm pretty sure we are losing the previously prepared
+ // processedMessage content.
if (meCommandMsg.length() > 0)
processedMessage = meCommandMsg;
}
this.conversationPanel.appendMessageToEnd(
- processedMessage, chatMessage.getContentType());
+ processedMessage, ChatHtmlUtils.HTML_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 80bc6e277..7c8b4801f 100644
--- a/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java
+++ b/src/net/java/sip/communicator/impl/gui/main/chat/ChatWritePanel.java
@@ -34,6 +34,7 @@
import net.java.sip.communicator.util.*;
import net.java.sip.communicator.util.skin.*;
+import org.apache.commons.lang3.*;
import org.jitsi.service.configuration.*;
import org.osgi.framework.*;
@@ -1065,12 +1066,12 @@ public void setTransportSelectorBoxVisible(boolean isVisible)
if (!transportSelectorBox.getMenu().isEnabled())
{
// Show a message to the user that IM is not possible.
- chatPanel.getChatConversationPanel()
- .appendMessageToEnd("" +
- GuiActivator.getResources().
- getI18NString("service.gui.MSG_NOT_POSSIBLE") +
- "
",
- ChatHtmlUtils.HTML_CONTENT_TYPE);
+ chatPanel.getChatConversationPanel().appendMessageToEnd(
+ ""
+ + StringEscapeUtils.escapeHtml4(GuiActivator
+ .getResources().getI18NString(
+ "service.gui.MSG_NOT_POSSIBLE")) + "
",
+ ChatHtmlUtils.HTML_CONTENT_TYPE);
}
else
{
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 1cd7d0801..f231ca4c1 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
@@ -355,7 +355,7 @@ else if (o instanceof FileRecord)
chatMessage.getContactName());
chatConvPanel.appendMessageToEnd(processedMessage,
- ChatHtmlUtils.TEXT_CONTENT_TYPE);
+ ChatHtmlUtils.HTML_CONTENT_TYPE);
}
}
}
@@ -890,7 +890,13 @@ private void processMessage(Contact contact,
contact.getProtocolProvider(),
contact.getAddress());
- this.appendMessageToDocument(document, processedMessage);
+ if (processedMessage != null)
+ {
+ // ChatConversationPanel#processMessage may return null
+ // if the message turns out to be a consecutive message.
+ this.appendMessageToDocument(
+ document, processedMessage);
+ }
}
}
else if (lastDate == null
diff --git a/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf b/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf
index 7a0147743..4b983b0c4 100644
--- a/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf
+++ b/src/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf
@@ -82,4 +82,5 @@ Import-Package: com.apple.eawt,
say.swing,
net.java.sip.communicator.service.credentialsstorage,
net.java.sip.communicator.service.muc,
- net.java.sip.communicator.plugin.desktoputil.chat
+ net.java.sip.communicator.plugin.desktoputil.chat,
+ org.apache.commons.lang3