Different approach to (plain text) chat message processing.

This modification fixes issues w.r.t. message caused by loss of styling
due to opening/closing <plaintext> tags. Additionally it simplifies
html / plain text message handling and text replacement.

Implemented a different approach to ChatMessage processing. This new
implementation strictly watches for the moment when a chat message
(possibly HTML already, but might also be plain text) is definitely
converted into HTML. This happens when certain processing steps are
taken.

As soon as these processing steps are taken, the approach changes into
HTML by default and every piece of text that still is plain text will be
HTML-escaped. Just before appending the new text message to the (HTML)
chat document, we always have HTML "text" and as soon as a processing
step is used of which we know that it definitely converts to HTML, we
start using the HTML content type. This also means that on a number of
occasions we have removed the contentType parameter, since we already
know or have this information.

Since we now know for sure that from a certain moment on, we are
strictly dealing with HTML "text" and we also know that everything plain
text will be HTML-escaped, we can adopt a different plain text search
pattern (TEXT_TO_REPLACE_PATTERN). This search approach searches for all
text in between lesser than (<) and greater than (>) signs, since we can
be sure that that is normal (escaped) text. We unescape these pieces of
text before running through the replacement services such that they can
behave as they always have. This shouldn't break (much of) the
Replacement Services implementations.

Also check and tag hyperlinks for HTML messages.

Added dependency to Apache Commons Lang to swing-ui.

Removed option skipSmiley. It is not needed anymore, now that hyperlink
hrefs aren't found anymore.
fix-message-formatting
Danny van Heumen 12 years ago
parent e0887ceb8e
commit 7e2c9bdf72

@ -1734,7 +1734,7 @@ javax.swing.event, javax.swing.border"/>
</target>
<!-- BUNDLE-SWING-UI -->
<target name="bundle-swing-ui">
<target name="bundle-swing-ui" depends="bundle-commons-lang">
<!-- Bundle Jitsi's UI.-->
<jar compress="false" destfile="${bundles.dest}/swing-ui.jar"
manifest="${src}/net/java/sip/communicator/impl/gui/swing.ui.manifest.mf">

@ -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("(<div[^>]*>)(.*)(</div>)", 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. <i>This expression assumes that the plain text part is
* correctly escaped, such that there is no occurrence of the symbols &lt;
* and &gt;.</i>
*
* <p>The first group matches any piece of text outside of HTML tags.</p>
*/
private static final Pattern TEXT_TO_REPLACE_PATTERN =
Pattern.compile(
ChatHtmlUtils.START_PLAINTEXT_TAG
+ "(.*?)" +
ChatHtmlUtils.END_PLAINTEXT_TAG
+ "|<a[^>]+>(.+?)</a>",
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 = "<h4 id=\"statusMessage\" date=\""
+ date + "\">";
chatString = "<h4 id=\"statusMessage\" date=\"" + date + "\">";
endHeaderTag = "</h4>";
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 = "</p>";
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
= "<DIV id=\"systemMessage\" style=\"color:#627EB7;\">";
String startSystemDivTag =
"<DIV id=\"systemMessage\" style=\"color:#627EB7;\">";
String endDivTag = "</DIV>";
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
+ "<h5>" + message + "</h5>";
{
chatString +=
errorIcon
+ processLinksAndHTMLChars(messageTitle, true,
ChatHtmlUtils.TEXT_CONTENT_TYPE) + endHeaderTag
+ "<h5>"
+ formatMessageAsHTML(message, contentType, keyword)
+ "</h5>";
}
else
chatString += endHeaderTag
+ "<h5>" + errorIcon + " " + message + "</h5>";
{
chatString +=
endHeaderTag + "<h5>" + errorIcon + " "
+ formatMessageAsHTML(message, contentType, keyword)
+ "</h5>";
}
}
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 <tt>true</tt> if the append succeeded, <tt>false</tt> - 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("<b>");
msgBuffer.append(keywordMatch);
msgBuffer.append(StringEscapeUtils.escapeHtml4(keywordMatch));
msgBuffer.append("</b>");
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("<A href=\"");
if (url.startsWith("www"))
msgBuffer.append("http://");
msgBuffer.append(url);
msgBuffer.append("\">");
msgBuffer.append(url);
msgBuffer.append(StringEscapeUtils.escapeHtml4(url));
msgBuffer.append("</A>");
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)
+ "<BR/>&#10;"
+ ChatHtmlUtils.createStartPlainTextTag(contentType))
+ closingTag;
return openingTag + message.replaceAll("\n", "<BR/>&#10;") + 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 <plaintext> 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<String, ReplacementService> entry
: GuiActivator.getReplacementSources().entrySet())
for (Map.Entry<String, ReplacementService> 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("<I")))
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(
msg.substring(startPos, startMatchPosition));
buff.append(msg.substring(startPos, startMatchPosition));
processText(
text,
buff,
pattern,
service,
skipSmileys);
final String plaintext =
StringEscapeUtils.unescapeHtml4(plainTextAsHtml);
processText(plaintext, buff, pattern, service);
startPos = endMatchPosition;
}
@ -2374,11 +2407,10 @@ private void processReplacementService(ReplacementService service,
* @param rService the replacement service.
* @param skipSmileys whether to skip processing smileys
*/
private void processText(String plainText,
StringBuilder msgBuff,
Pattern pattern,
ReplacementService rService,
boolean skipSmileys)
private void processText(final String plainText,
final StringBuilder msgBuff,
final Pattern pattern,
final ReplacementService rService)
{
Matcher m = pattern.matcher(plainText);
@ -2395,49 +2427,46 @@ private void processText(String plainText,
int startPos = 0;
while (m.find())
{
msgBuff.append(plainText.substring(startPos, m.start()));
msgBuff.append(StringEscapeUtils.escapeHtml4(plainText
.substring(startPos, m.start())));
startPos = m.end();
String group = m.group();
String temp = rService.getReplacement(group);
String group0 = m.group(0);
if(!temp.equals(group0) || isDirectImage)
if (!temp.equals(group0) || isDirectImage)
{
if (isSmiley)
{
if (cfg.getBoolean(ReplacementProperty.
getPropertyName("SMILEY"),
true)
&& !skipSmileys)
true))
{
msgBuff.append(
ChatHtmlUtils.createEndPlainTextTag(
contentType));
msgBuff.append("<IMG SRC=\"");
msgBuff.append(temp);
msgBuff.append("\" BORDER=\"0\" ALT=\"");
msgBuff.append(group0);
msgBuff.append("\"></IMG>");
msgBuff.append(
ChatHtmlUtils.createStartPlainTextTag(
contentType));
}
else
{
msgBuff.append(group);
msgBuff
.append(StringEscapeUtils.escapeHtml4(group));
}
}
else if (isProposalEnabled)
{
msgBuff.append(group);
msgBuff.append(
"</A> <A href=\"jitsi://"
+ showPreview.getClass().getName()
+ "/SHOWPREVIEW?" + messageID + "#"
+ linkCounter + "\">"
+ GuiActivator.getResources().
getI18NString("service.gui.SHOW_PREVIEW"));
msgBuff.append(StringEscapeUtils.escapeHtml4(group));
msgBuff.append("</A> <A href=\"jitsi://"
+ showPreview.getClass().getName()
+ "/SHOWPREVIEW?" + messageID
+ "#"
+ linkCounter
+ "\">"
+ 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)));
}
}
}

@ -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 <code>PLAINTEXT</code> HTML element.
*/
public static final String END_PLAINTEXT_TAG = "</PLAINTEXT>";
/**
* The opening tag of the <code>PLAINTEXT</code> HTML element.
*/
public static final String START_PLAINTEXT_TAG = "<PLAINTEXT>";
/**
* 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("</div>");
@ -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("</div>");
return messageTag.toString();

@ -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);
}
/**

@ -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("<h5>" +
GuiActivator.getResources().
getI18NString("service.gui.MSG_NOT_POSSIBLE") +
"</h5>",
ChatHtmlUtils.HTML_CONTENT_TYPE);
chatPanel.getChatConversationPanel().appendMessageToEnd(
"<h5>"
+ StringEscapeUtils.escapeHtml4(GuiActivator
.getResources().getI18NString(
"service.gui.MSG_NOT_POSSIBLE")) + "</h5>",
ChatHtmlUtils.HTML_CONTENT_TYPE);
}
else
{

@ -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

@ -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

Loading…
Cancel
Save