Initial support for updated otr4j with support for outgoing message fragmentation.

Modifications include the following:
- Updated otr4j which includes support for fragmentation of outgoing
  messages. The modifications to otr4j to enable outgoing message
  fragmentation includes breaking the API such that we are able to
  return more than 1 message after it has been transformed.
  (Corresponding modifications have been made to
  AbstractOperationSetBasicInstantMessaging to facilitate the new API.)
- Fixed IRC implementation for OperationSetInstantMessageTransform.
- Modified AbstractOperationSetBasicInstantMessaging to handle multiple
  Events returning from a call to messageTransform.
- Modified OperationSetBasicInstantMessaging implementations to
  correspond to changes in AbstractOSBIM.
- OTR plugin has been modified to implement the newly added
  getFragmenterInstructions method which is used to query instructions
  on desired fragmentation behaviour.
- As a temporary solution, a hard dependency has been added to IRC
  library such that I'm able to test fragmentation behaviour in a real
  use case until an OperationSet is defined that can be used to query
  for Instant Messaging transport parameters necessary to determine
  appropriate fragmentation instructions.
cefexperiments
Danny van Heumen 12 years ago
parent 9c302d8c96
commit f970c50c8e

Binary file not shown.

@ -172,29 +172,35 @@ public void sendInstantMessage(Contact to, Message message)
MessageDeliveredEvent msgDeliveryPendingEvt
= new MessageDeliveredEvent(message, to);
msgDeliveryPendingEvt = this.messageDeliveryPendingTransform(msgDeliveryPendingEvt);
if (msgDeliveryPendingEvt == null)
MessageDeliveredEvent[] msgDeliveryPendingEvts = this.messageDeliveryPendingTransform(msgDeliveryPendingEvt);
if (msgDeliveryPendingEvts == null || msgDeliveryPendingEvts.length == 0)
return;
String transformedContent = msgDeliveryPendingEvt.getSourceMessage().getContent();
if (to.getPresenceStatus().isOnline())
for (MessageDeliveredEvent pendingEvt : msgDeliveryPendingEvts)
{
//do not add the conversation listener in here. we'll add it
//inside the icbm listener
imConversation.sendMessage(new SimpleMessage(transformedContent));
}
else
imConversation.sendMessage(new SimpleMessage(transformedContent), true);
String transformedContent =
pendingEvt.getSourceMessage().getContent();
MessageDeliveredEvent msgDeliveredEvt
= new MessageDeliveredEvent(message, to);
if (to.getPresenceStatus().isOnline())
{
// do not add the conversation listener in here. we'll add it
// inside the icbm listener
imConversation
.sendMessage(new SimpleMessage(transformedContent));
}
else
imConversation.sendMessage(
new SimpleMessage(transformedContent), true);
// msgDeliveredEvt = this.messageDeliveredTransform(msgDeliveredEvt);
MessageDeliveredEvent msgDeliveredEvt =
new MessageDeliveredEvent(message, to);
if (msgDeliveredEvt != null)
fireMessageEvent(msgDeliveredEvt);
// msgDeliveredEvt =
// this.messageDeliveredTransform(msgDeliveredEvt);
if (msgDeliveredEvt != null)
fireMessageEvent(msgDeliveredEvt);
}
}
/**

@ -151,6 +151,12 @@ public class IrcStack
*/
private PresenceManager presence = null;
/**
* The local user's identity as it will be used in server-client
* communication for sent messages.
*/
private Identity identity;
/**
* The cached channel list.
*
@ -253,6 +259,8 @@ public void connect(final String host, final int port,
connectSynchronized();
queryIdentity();
// TODO Read IRC network capabilities based on RPL_ISUPPORT (005)
// replies if available. This information should be available in
// irc-api if possible.
@ -362,6 +370,27 @@ public void onFailure(final Exception e)
}
}
/**
* Issue WHOIS query to discover identity as seen by the server.
*/
private void queryIdentity()
{
this.session.get().rawMessage(
"WHOIS " + this.connectionState.getNickname());
}
/**
* Get the current identity string, based on nick, user and host of local
* user.
*
* @return returns identity string
*/
public String getIdentityString()
{
final String currentNick = this.connectionState.getNickname();
return this.identity.getIdentityString(currentNick);
}
/**
* Create a custom SSL context for this particular server.
*
@ -1022,16 +1051,12 @@ public void message(final Contact contact, final Message message)
{
final IRCApi irc = this.session.get();
irc.message(target, message.getContent());
IrcStack.this.provider.getBasicInstantMessaging()
.fireMessageDelivered(message, contact);
LOGGER.trace("Message delivered to server successfully.");
}
catch (RuntimeException e)
{
IrcStack.this.provider.getBasicInstantMessaging()
.fireMessageDeliveryFailed(message, contact,
MessageDeliveryFailedEvent.NETWORK_FAILURE);
LOGGER.trace("Failed to deliver message: " + e.getMessage(), e);
throw e;
}
}
@ -1185,6 +1210,11 @@ private final class ServerListener
*/
private static final int RPL_LISTEND =
IRCServerNumerics.CHANNEL_NICKS_END_OF_LIST;
/**
* Reply for WHOIS query.
*/
private static final int IRC_RPL_WHOISUSER = 311;
/**
* IRCApi instance.
@ -1359,6 +1389,29 @@ public void onServerNumericMessage(final ServerNumericMessage msg)
.fireMessageReceived(awayMessage, awayUser);
break;
case IRC_RPL_WHOISUSER:
final String whoismsg = msg.getText();
final int endNickIndex = whoismsg.indexOf(' ');
final String nick = whoismsg.substring(0, endNickIndex);
if (!IrcStack.this.connectionState.getNickname().equals(nick))
{
// We need WHOIS info on ourselves to discover our identity
// on the IRC server. So skip other WHOIS replies.
return;
}
final int endUserIndex =
whoismsg.indexOf(' ', endNickIndex + 1);
final int endHostIndex =
whoismsg.indexOf(' ', endUserIndex + 1);
final String user =
whoismsg.substring(endNickIndex + 1, endUserIndex);
final String host =
whoismsg.substring(endUserIndex + 1, endHostIndex);
LOGGER.debug(String.format("Current identity: %s!%s@%s",
IrcStack.this.connectionState.getNickname(), user, host));
IrcStack.this.identity = new IrcStack.Identity(user, host);
break;
default:
if (LOGGER.isTraceEnabled())
{
@ -2592,4 +2645,49 @@ public void run()
LOGGER.debug("Old channel list cache has been cleared.");
}
}
/**
* Storage container for identity components.
*
* IRC identity components user and host are stored. The nick name component
* isn't stored, because it changes too frequently. When getting the
* identity string, the nick name component is provided at calling time.
*
* @author Danny van Heumen
*/
private static final class Identity
{
/**
* User name.
*/
private final String user;
/**
* Host name.
*/
private final String host;
/**
* Constructor.
*
* @param user user
* @param host host
*/
private Identity(final String user, final String host)
{
this.user = user;
this.host = host;
}
/**
* Get identity string.
*
* @param currentNick the current nick
* @return returns identity string
*/
public String getIdentityString(final String currentNick)
{
return String.format("%s!%s@%s", currentNick, this.user, this.host);
}
}
}

@ -6,6 +6,8 @@
package net.java.sip.communicator.impl.protocol.irc;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
/**
* Implementation of Basic Instant Messaging as utilized for IRC private
@ -16,6 +18,11 @@
public class OperationSetBasicInstantMessagingIrcImpl
extends AbstractOperationSetBasicInstantMessaging
{
/**
* Logger.
*/
private static final Logger LOGGER = Logger.getLogger(OperationSetBasicInstantMessagingIrcImpl.class);
/**
* IRC protocol provider service.
*/
@ -59,28 +66,74 @@ public MessageIrcImpl createMessage(final String content,
* Send instant message.
*
* @param to contact to send message to
* @param message message to send
* @param original message to send
* @throws IllegalStateException in case of bad internal state
* @throws IllegalArgumentException in case invalid arguments have been
* passed
*/
@Override
public void sendInstantMessage(final Contact to, final Message message)
public void sendInstantMessage(final Contact to, final Message original)
throws IllegalStateException,
IllegalArgumentException
{
if (!(original instanceof MessageIrcImpl))
{
LOGGER.error("Invalid class of Message implementation received. "
+ "Not sending message.");
return;
}
// OTR seems to be compatible with the command syntax (starts with '/')
// and there were no other obvious problems so we decided to implement
// IRC command support for IM infrastructure too.
if (message instanceof MessageIrcImpl
&& ((MessageIrcImpl) message).isCommand())
final MessageDeliveredEvent[] msgDeliveryPendingEvts =
messageDeliveryPendingTransform(new MessageDeliveredEvent(original,
to));
try
{
this.provider.getIrcStack().command(to, (MessageIrcImpl) message);
for (MessageDeliveredEvent event : msgDeliveryPendingEvts)
{
if (event == null)
{
return;
}
String transformedContent =
event.getSourceMessage().getContent();
// FIXME how to handle HTML content?
// Note: can't set subject since it leaks information while
// message content actually gets encoded.
MessageIrcImpl message = this.createMessage(transformedContent,
original.getContentType(), original.getEncoding(), "");
try
{
if (message.isCommand())
{
this.provider.getIrcStack().command(to, message);
}
else
{
this.provider.getIrcStack().message(to, message);
}
}
catch (RuntimeException e)
{
LOGGER.debug("Failed to deliver (raw) message: " + message);
throw e;
}
}
fireMessageDelivered(original, to);
}
else
catch (RuntimeException e)
{
this.provider.getIrcStack().message(to, message);
LOGGER.warn("Failed to deliver message: " + original, e);
fireMessageDeliveryFailed(original, to,
MessageDeliveryFailedEvent.NETWORK_FAILURE);
}
}

@ -3,7 +3,8 @@ Bundle-Name: Irc Protocol Provider
Bundle-Description: A bundle providing support for the Irc protocol.
Bundle-Vendor: jitsi.org
Bundle-Version: 0.0.1
Bundle-SymbolicName: net.java.sip.communicator.protocol.irc
Bundle-SymbolicName: net.java.sip.communicator.impl.protocol.irc
Export-Package: net.java.sip.communicator.impl.protocol.irc
Import-Package: org.osgi.framework,
org.jitsi.service.configuration,
org.jitsi.service.resources,

@ -442,62 +442,60 @@ private MessageDeliveredEvent sendMessage( Contact to,
MessageDeliveredEvent msgDeliveryPendingEvt
= new MessageDeliveredEvent(message, to, toResource);
msgDeliveryPendingEvt
= messageDeliveryPendingTransform(msgDeliveryPendingEvt);
MessageDeliveredEvent[] transformedEvents = messageDeliveryPendingTransform(msgDeliveryPendingEvt);
if (msgDeliveryPendingEvt == null)
if (transformedEvents == null || transformedEvents.length == 0)
return null;
String content = msgDeliveryPendingEvt
.getSourceMessage().getContent();
if(message.getContentType().equals(HTML_MIME_TYPE))
for (MessageDeliveredEvent event : transformedEvents)
{
msg.setBody(Html2Text.extractText(content));
String content = event.getSourceMessage().getContent();
// Check if the other user supports XHTML messages
// make sure we use our discovery manager as it caches calls
if(jabberProvider.isFeatureListSupported(
toJID,
HTML_NAMESPACE))
if (message.getContentType().equals(HTML_MIME_TYPE))
{
// Add the XHTML text to the message
XHTMLManager.addBody(msg,
OPEN_BODY_TAG + content + CLOSE_BODY_TAG);
}
}
else
{
// this is plain text so keep it as it is.
msg.setBody(content);
}
msg.setBody(Html2Text.extractText(content));
//msg.addExtension(new Version());
// Check if the other user supports XHTML messages
// make sure we use our discovery manager as it caches calls
if (jabberProvider
.isFeatureListSupported(toJID, HTML_NAMESPACE))
{
// Add the XHTML text to the message
XHTMLManager.addBody(msg, OPEN_BODY_TAG + content
+ CLOSE_BODY_TAG);
}
}
else
{
// this is plain text so keep it as it is.
msg.setBody(content);
}
if(msgDeliveryPendingEvt.isMessageEncrypted())
{
msg.addExtension(new CarbonPacketExtension.PrivateExtension());
}
// msg.addExtension(new Version());
MessageEventManager.
addNotificationsRequests(msg, true, false, false, true);
if (event.isMessageEncrypted())
{
msg.addExtension(new CarbonPacketExtension.PrivateExtension());
}
String threadID = getThreadIDForAddress(toJID);
if(threadID == null)
threadID = nextThreadID();
MessageEventManager.addNotificationsRequests(msg, true, false,
false, true);
msg.setThread(threadID);
msg.setType(org.jivesoftware.smack.packet.Message.Type.chat);
msg.setFrom(jabberProvider.getConnection().getUser());
String threadID = getThreadIDForAddress(toJID);
if (threadID == null)
threadID = nextThreadID();
jabberProvider.getConnection().sendPacket(msg);
msg.setThread(threadID);
msg.setType(org.jivesoftware.smack.packet.Message.Type.chat);
msg.setFrom(jabberProvider.getConnection().getUser());
putJidForAddress(toJID, threadID);
jabberProvider.getConnection().sendPacket(msg);
MessageDeliveredEvent msgDeliveredEvt
= new MessageDeliveredEvent(message, to, toResource);
putJidForAddress(toJID, threadID);
}
// msgDeliveredEvt = messageDeliveredTransform(msgDeliveredEvt);
MessageDeliveredEvent msgDeliveredEvt =
new MessageDeliveredEvent(message, to, toResource);
return msgDeliveredEvt;
}
@ -1119,6 +1117,7 @@ private String createMailboxDescription(MailboxIQ mailboxIQ)
? "service.gui.NEW_GMAIL_MANY_FOOTER"
: "service.gui.NEW_GMAIL_FOOTER";
// FIXME Escape HTML!
String newMailHeader = JabberActivator.getResources().getI18NString(
resourceHeaderKey,
new String[]

@ -113,7 +113,7 @@ public Message createMessage(String content, String contentType,
* @throws java.lang.IllegalArgumentException if <tt>to</tt> is not an
* instance of ContactImpl.
*/
public void sendInstantMessage(final Contact to, Message message)
public void sendInstantMessage(final Contact to, final Message message)
throws IllegalStateException, IllegalArgumentException
{
assertConnected();
@ -123,29 +123,30 @@ public void sendInstantMessage(final Contact to, Message message)
"The specified contact is not an MSN contact."
+ to);
final MessageDeliveredEvent msgDeliveryPendingEvt
= messageDeliveryPendingTransform(
new MessageDeliveredEvent(message, to));
MessageDeliveredEvent[] transformedEvents = messageDeliveryPendingTransform(
new MessageDeliveredEvent(message, to));
if (msgDeliveryPendingEvt == null)
if (transformedEvents == null || transformedEvents.length == 0)
return;
MessageDeliveredEvent msgDeliveredEvt
= new MessageDeliveredEvent(message, to);
MessageDeliveredEvent msgDeliveredEvt =
new MessageDeliveredEvent(message, to);
fireMessageEvent(msgDeliveredEvt);
// send message in separate thread so we won't block ui if
// it takes time.
if(senderThread == null)
// send message in separate thread so we won't block ui if it takes
// time.
if (senderThread == null)
{
senderThread = new SenderThread();
senderThread.start();
}
senderThread.sendMessage(
(ContactMsnImpl)to,
msgDeliveryPendingEvt.getSourceMessage().getContent());
for (MessageDeliveredEvent event : transformedEvents)
{
senderThread.sendMessage((ContactMsnImpl) to, event
.getSourceMessage().getContent());
}
}
/**
@ -323,6 +324,7 @@ public void newEmailNotificationReceived(MsnSwitchboard switchboard,
logger.warn("Failed to decode the subject of a new e-mail", ex);
}
// FIXME Escape HTML!
String messageFrom = message.getFrom();
Message newMailMessage = new MessageMsnImpl(
MessageFormat.format(

@ -214,53 +214,44 @@ public void sendInstantMessage(Contact to, Message message)
}
// create the message
Request mes;
try
{
Message transformedMessage = transformSIPMessage(to, message);
mes = createMessageRequest(to, transformedMessage);
}
catch (OperationFailedException ex)
Message[] transformedMessages = transformSIPMessage(to, message);
for (Message msg : transformedMessages)
{
logger.error(
"Failed to create the message."
, ex);
Request mes;
try
{
mes = createMessageRequest(to, msg);
}
catch (OperationFailedException ex)
{
logger.error("Failed to create the message.", ex);
fireMessageDeliveryFailed(
message,
to,
MessageDeliveryFailedEvent.INTERNAL_ERROR);
return;
}
fireMessageDeliveryFailed(message, to,
MessageDeliveryFailedEvent.INTERNAL_ERROR);
continue;
}
try
{
sendMessageRequest(mes, to, message);
}
catch(TransactionUnavailableException ex)
{
logger.error(
"Failed to create messageTransaction.\n"
+ "This is most probably a network connection error."
, ex);
try
{
sendMessageRequest(mes, to, message);
}
catch (TransactionUnavailableException ex)
{
logger.error("Failed to create messageTransaction.\n"
+ "This is most probably a network connection error.", ex);
fireMessageDeliveryFailed(
message,
to,
MessageDeliveryFailedEvent.NETWORK_FAILURE);
return;
}
catch(SipException ex)
{
logger.error(
"Failed to send the message."
, ex);
fireMessageDeliveryFailed(message, to,
MessageDeliveryFailedEvent.NETWORK_FAILURE);
continue;
}
catch (SipException ex)
{
logger.error("Failed to send the message.", ex);
fireMessageDeliveryFailed(
message,
to,
MessageDeliveryFailedEvent.INTERNAL_ERROR);
return;
fireMessageDeliveryFailed(message, to,
MessageDeliveryFailedEvent.INTERNAL_ERROR);
continue;
}
}
}
@ -482,28 +473,36 @@ Request createMessageRequest(Contact to, Message message)
*
* @return The new transformed <tt>Message</tt>
*/
private Message transformSIPMessage(Contact to, Message message)
private Message[] transformSIPMessage(final Contact to,
final Message message)
{
MessageDeliveredEvent msgDeliveryPendingEvt
= new MessageDeliveredEvent(message, to);
msgDeliveryPendingEvt
= messageDeliveryPendingTransform(msgDeliveryPendingEvt);
MessageDeliveredEvent[] msgDeliveryPendingEvts =
messageDeliveryPendingTransform(msgDeliveryPendingEvt);
if (msgDeliveryPendingEvt == null)
return null;
String content = msgDeliveryPendingEvt.getSourceMessage().getContent();
if (msgDeliveryPendingEvts == null
|| msgDeliveryPendingEvts.length == 0)
{
return new Message[0];
}
OperationSetBasicInstantMessaging opSetBasicIM =
(OperationSetBasicInstantMessaging) sipProvider
.getSupportedOperationSets().get(
OperationSetBasicInstantMessaging.class.getName());
Message transformedMesssage =
opSetBasicIM.createMessage(content, message.getContentType(),
message.getEncoding(), message.getSubject());
return transformedMesssage;
Message[] transformedMessages =
new Message[msgDeliveryPendingEvts.length];
for (int i = 0; i < msgDeliveryPendingEvts.length; i++)
{
MessageDeliveredEvent event = msgDeliveryPendingEvts[i];
String content = event.getSourceMessage().getContent();
transformedMessages[i] =
opSetBasicIM.createMessage(content, message.getContentType(),
message.getEncoding(), message.getSubject());
}
return transformedMessages;
}
/**

@ -150,56 +150,55 @@ public void sendInstantMessage(Contact to, Message message)
{
String toUserID = ((ContactYahooImpl) to).getID();
MessageDeliveredEvent msgDeliveryPendingEvt
= new MessageDeliveredEvent(
message, to, new Date());
MessageDeliveredEvent msgDeliveryPendingEvt =
new MessageDeliveredEvent(message, to, new Date());
msgDeliveryPendingEvt = messageDeliveryPendingTransform(msgDeliveryPendingEvt);
MessageDeliveredEvent[] msgDeliveryPendingEvts = messageDeliveryPendingTransform(msgDeliveryPendingEvt);
if (msgDeliveryPendingEvt == null)
if (msgDeliveryPendingEvts == null || msgDeliveryPendingEvts.length == 0)
return;
byte[] msgBytesToBeSent = msgDeliveryPendingEvt.getSourceMessage().
getContent().trim().getBytes("UTF-8");
// split the message in parts with max allowed length
// and send them all
do
for (MessageDeliveredEvent event : msgDeliveryPendingEvts)
{
if(msgBytesToBeSent.length > MAX_MESSAGE_LENGTH)
{
byte[] tmp1 = new byte[MAX_MESSAGE_LENGTH];
System.arraycopy(msgBytesToBeSent,
0, tmp1, 0, MAX_MESSAGE_LENGTH);
byte[] tmp2 =
new byte[msgBytesToBeSent.length - MAX_MESSAGE_LENGTH];
System.arraycopy(msgBytesToBeSent,
MAX_MESSAGE_LENGTH, tmp2, 0, tmp2.length);
byte[] msgBytesToBeSent =
event.getSourceMessage().getContent().trim()
.getBytes("UTF-8");
msgBytesToBeSent = tmp2;
yahooProvider.getYahooSession().sendMessage(
toUserID,
new String(tmp1, "UTF-8"));
}
else
// split the message in parts with max allowed length
// and send them all
do
{
yahooProvider.getYahooSession().sendMessage(
toUserID,
new String(msgBytesToBeSent, "UTF-8"));
if (msgBytesToBeSent.length > MAX_MESSAGE_LENGTH)
{
byte[] tmp1 = new byte[MAX_MESSAGE_LENGTH];
System.arraycopy(msgBytesToBeSent, 0, tmp1, 0,
MAX_MESSAGE_LENGTH);
byte[] tmp2 =
new byte[msgBytesToBeSent.length
- MAX_MESSAGE_LENGTH];
System.arraycopy(msgBytesToBeSent, MAX_MESSAGE_LENGTH,
tmp2, 0, tmp2.length);
msgBytesToBeSent = tmp2;
yahooProvider.getYahooSession().sendMessage(toUserID,
new String(tmp1, "UTF-8"));
}
else
{
yahooProvider.getYahooSession().sendMessage(toUserID,
new String(msgBytesToBeSent, "UTF-8"));
}
MessageDeliveredEvent msgDeliveredEvt =
new MessageDeliveredEvent(message, to, new Date());
if (msgDeliveredEvt != null)
fireMessageEvent(msgDeliveredEvt);
}
MessageDeliveredEvent msgDeliveredEvt
= new MessageDeliveredEvent(
message, to, new Date());
// msgDeliveredEvt = messageDeliveredTransform(msgDeliveredEvt);
if (msgDeliveredEvt != null)
fireMessageEvent(msgDeliveredEvt);
while (msgBytesToBeSent.length > MAX_MESSAGE_LENGTH);
}
while(msgBytesToBeSent.length > MAX_MESSAGE_LENGTH);
}
catch (IOException ex)
{
@ -210,8 +209,6 @@ public void sendInstantMessage(Contact to, Message message)
to,
MessageDeliveryFailedEvent.NETWORK_FAILURE);
// evt = messageDeliveryFailedTransform(evt);
if (evt != null)
fireMessageEvent(evt);
}
@ -374,6 +371,7 @@ public void newMailReceived(SessionNewMailEvent ev)
+ yahooMailLogon + "\">"
+ yahooMailLogon + "</a>";
// FIXME Escape HTML!
String newMail = YahooActivator.getResources().getI18NString(
"service.gui.NEW_MAIL",
new String[]{ev.getFrom(),

@ -61,7 +61,7 @@ public MessageDeliveryFailedEvent messageDeliveryFailed(
/*
* Implements TransformLayer#messageDeliveryPending(MessageDeliveredEvent).
*/
public MessageDeliveredEvent messageDeliveryPending(
public MessageDeliveredEvent[] messageDeliveryPending(
MessageDeliveredEvent evt)
{
Contact contact = evt.getDestinationContact();
@ -76,47 +76,57 @@ public MessageDeliveredEvent messageDeliveryPending(
if (!policy.getEnableManual()
&& sessionStatus != ScSessionStatus.ENCRYPTED
&& sessionStatus != ScSessionStatus.FINISHED)
return evt;
return new MessageDeliveredEvent[] {evt};
// If this is a message otr4j injected earlier, return the event as is.
if (OtrActivator.scOtrEngine.isMessageUIDInjected(evt
.getSourceMessage().getMessageUID()))
return evt;
return new MessageDeliveredEvent[] {evt};
// Process the outgoing message.
String msgContent = evt.getSourceMessage().getContent();
String processedMessageContent =
String[] processedMessageContent =
OtrActivator.scOtrEngine.transformSending(otrContact, msgContent);
if (processedMessageContent == null
|| processedMessageContent.length() < 1)
return null;
if (processedMessageContent.equals(msgContent))
return evt;
// Forge a new message based on the new contents.
OperationSetBasicInstantMessaging imOpSet =
contact.getProtocolProvider().getOperationSet(
OperationSetBasicInstantMessaging.class);
Message processedMessage =
imOpSet.createMessage(
processedMessageContent,
evt.getSourceMessage().getContentType(),
evt.getSourceMessage().getEncoding(),
evt.getSourceMessage().getSubject());
|| processedMessageContent.length <= 0
|| processedMessageContent[0].length() < 1)
return new MessageDeliveredEvent[0];
// Create a new event and return.
MessageDeliveredEvent processedEvent =
new MessageDeliveredEvent(processedMessage, contact, evt
.getTimestamp());
if (processedMessageContent.length == 1
&& processedMessageContent[0].equals(msgContent))
return new MessageDeliveredEvent[] {evt};
if(processedMessage.getContent().contains(SerializationConstants.HEAD))
final MessageDeliveredEvent[] processedEvents =
new MessageDeliveredEvent[processedMessageContent.length];
for (int i = 0; i < processedMessageContent.length; i++)
{
processedEvent.setMessageEncrypted(true);
final String fragmentContent = processedMessageContent[i];
// Forge a new message based on the new contents.
OperationSetBasicInstantMessaging imOpSet =
contact.getProtocolProvider().getOperationSet(
OperationSetBasicInstantMessaging.class);
Message processedMessage =
imOpSet.createMessage(fragmentContent, evt
.getSourceMessage().getContentType(), evt
.getSourceMessage().getEncoding(), evt.getSourceMessage()
.getSubject());
// Create a new event and return.
final MessageDeliveredEvent processedEvent =
new MessageDeliveredEvent(processedMessage, contact,
evt.getTimestamp());
if (processedMessage.getContent().contains(
SerializationConstants.HEAD))
{
processedEvent.setMessageEncrypted(true);
}
processedEvents[i] = processedEvent;
}
return processedEvent;
return processedEvents;
}
/*

@ -70,7 +70,7 @@ public abstract void respondSmp(OtrContact contact,
* @param content the original message content.
* @return the transformed message content.
*/
public abstract String transformSending(OtrContact contact, String content);
public abstract String[] transformSending(OtrContact contact, String content);
/**
* Transforms an incoming message.

@ -14,6 +14,7 @@
import net.java.otr4j.*;
import net.java.otr4j.crypto.*;
import net.java.otr4j.session.*;
import net.java.sip.communicator.impl.protocol.irc.*;
import net.java.sip.communicator.plugin.otr.OtrContactManager.OtrContact;
import net.java.sip.communicator.plugin.otr.authdialog.*;
import net.java.sip.communicator.service.browserlauncher.*;
@ -420,6 +421,44 @@ public void messageFromAnotherInstanceReceived(SessionID sessionID)
message,
OperationSetBasicInstantMessaging.HTML_MIME_TYPE);
}
/**
* Provide fragmenter instructions according to the Instant Messaging
* transport channel of the contact's protocol.
*/
@Override
public FragmenterInstructions getFragmenterInstructions(
final SessionID sessionID)
{
final OtrContact otrContact = getOtrContact(sessionID);
// FIXME Change this into querying an Operation Set that provides
// Instant Message medium/transport information that we can use to
// determine fragmentation parameters.
if (ProtocolNames.IRC.equals(otrContact.contact
.getProtocolProvider().getProtocolName()))
{
// :<nick>!<user>@<host> PRIVMSG <targetnick> :<message>
//
// Example:
// :ircotrtest!~ircotrtes@77-175-185-165.FTTH.ispfabriek.nl
// PRIVMSG test12345abc :
final String identity =
((ProtocolProviderServiceIrcImpl) otrContact.contact
.getProtocolProvider()).getIrcStack()
.getIdentityString();
final int size =
510 - (":" + identity + " PRIVMSG "
+ otrContact.contact.getAddress() + " :").length();
return new FragmenterInstructions(
FragmenterInstructions.UNLIMITED, size);
}
else
{
return new FragmenterInstructions(
FragmenterInstructions.UNLIMITED,
FragmenterInstructions.UNLIMITED);
}
}
}
/**
@ -510,11 +549,11 @@ public static SessionID getSessionID(OtrContact otrContact)
private final OtrEngineHost otrEngineHost = new ScOtrEngineHost();
private final OtrEngine otrEngine;
private final OtrSessionManager otrEngine;
public ScOtrEngineImpl()
{
otrEngine = new OtrEngineImpl(otrEngineHost);
otrEngine = new OtrSessionManagerImpl(otrEngineHost);
// Clears the map after previous instance
// This is required because of OSGi restarts in the same VM on Android
@ -539,13 +578,13 @@ public void sessionStatusChanged(SessionID sessionID)
ScSessionStatus scSessionStatus = getSessionStatus(otrContact);
String message = "";
switch (otrEngine.getSessionStatus(sessionID))
final Session session = otrEngine.getSession(sessionID);
switch (session.getSessionStatus())
{
case ENCRYPTED:
scSessionStatus = ScSessionStatus.ENCRYPTED;
scSessionStatusMap.put(sessionID, scSessionStatus);
PublicKey remotePubKey =
otrEngine.getRemotePublicKey(sessionID);
PublicKey remotePubKey = session.getRemotePublicKey();
String remoteFingerprint = null;
try
@ -790,7 +829,7 @@ public void endSession(OtrContact otrContact)
{
setSessionStatus(otrContact, ScSessionStatus.PLAINTEXT);
otrEngine.endSession(sessionID);
otrEngine.getSession(sessionID).endSession();
}
catch (OtrException e)
{
@ -926,7 +965,7 @@ private void setSessionStatus(OtrContact contact, ScSessionStatus status)
public ScSessionStatus getSessionStatus(OtrContact contact)
{
SessionID sessionID = getSessionID(contact);
SessionStatus sessionStatus = otrEngine.getSessionStatus(sessionID);
SessionStatus sessionStatus = otrEngine.getSession(sessionID).getSessionStatus();
ScSessionStatus scSessionStatus = null;
if (!scSessionStatusMap.containsKey(sessionID))
{
@ -976,7 +1015,7 @@ public void refreshSession(OtrContact otrContact)
SessionID sessionID = getSessionID(otrContact);
try
{
otrEngine.refreshSession(sessionID);
otrEngine.getSession(sessionID).refreshSession();
}
catch (OtrException e)
{
@ -1112,7 +1151,7 @@ public void startSession(OtrContact otrContact)
try
{
otrEngine.startSession(sessionID);
otrEngine.getSession(sessionID).startSession();
}
catch (OtrException e)
{
@ -1127,7 +1166,7 @@ public String transformReceiving(OtrContact otrContact, String msgText)
SessionID sessionID = getSessionID(otrContact);
try
{
return otrEngine.transformReceiving(sessionID, msgText);
return otrEngine.getSession(sessionID).transformReceiving(msgText);
}
catch (OtrException e)
{
@ -1138,12 +1177,12 @@ public String transformReceiving(OtrContact otrContact, String msgText)
}
@Override
public String transformSending(OtrContact otrContact, String msgText)
public String[] transformSending(OtrContact otrContact, String msgText)
{
SessionID sessionID = getSessionID(otrContact);
try
{
return otrEngine.transformSending(sessionID, msgText);
return otrEngine.getSession(sessionID).transformSending(msgText);
}
catch (OtrException e)
{
@ -1280,6 +1319,6 @@ public Session getOutgoingSession(OtrContact contact)
SessionID sessionID = getSessionID(contact);
return otrEngine.getOutgoingSession(sessionID);
return otrEngine.getSession(sessionID).getOutgoingInstance();
}
}

@ -33,4 +33,5 @@ Import-Package: org.osgi.framework,
org.bouncycastle.crypto.modes,
org.bouncycastle.util,
org.bouncycastle.util.encoders,
net.java.sip.communicator.service.msghistory
net.java.sip.communicator.service.msghistory,
net.java.sip.communicator.impl.protocol.irc

@ -205,38 +205,41 @@ else if (evt instanceof MessageDeliveryFailedEvent)
}
// Transform the event.
try
EventObject[] events = messageTransform(evt, eventType);
for (EventObject event : events)
{
evt = messageTransform(evt, eventType);
if (evt == null)
return;
for (MessageListener listener : listeners)
try
{
switch (eventType)
if (event == null)
return;
for (MessageListener listener : listeners)
{
case MessageDelivered:
listener.messageDelivered((MessageDeliveredEvent) evt);
break;
case MessageDeliveryFailed:
listener.messageDeliveryFailed(
(MessageDeliveryFailedEvent)evt);
break;
case MessageReceived:
listener.messageReceived((MessageReceivedEvent) evt);
break;
default:
/*
* We either have nothing to do or we do not know what to
* do. Anyway, we'll silence the compiler.
*/
break;
switch (eventType)
{
case MessageDelivered:
listener.messageDelivered((MessageDeliveredEvent) event);
break;
case MessageDeliveryFailed:
listener
.messageDeliveryFailed((MessageDeliveryFailedEvent) event);
break;
case MessageReceived:
listener.messageReceived((MessageReceivedEvent) event);
break;
default:
/*
* We either have nothing to do or we do not know what
* to do. Anyway, we'll silence the compiler.
*/
break;
}
}
}
}
catch (Throwable e)
{
logger.error("Error delivering message", e);
catch (Throwable e)
{
logger.error("Error delivering message", e);
}
}
}
@ -268,18 +271,44 @@ public void removeMessageListener(MessageListener listener)
}
}
public MessageDeliveredEvent messageDeliveryPendingTransform(
MessageDeliveredEvent evt)
/**
* Messages pending delivery to be transformed.
*
* @param evt the message delivery event
* @return returns message delivery events
*/
public MessageDeliveredEvent[] messageDeliveryPendingTransform(
final MessageDeliveredEvent evt)
{
return (MessageDeliveredEvent) messageTransform(
EventObject[] transformed = messageTransform(
evt, MessageEventType.MessageDeliveryPending);
}
private EventObject messageTransform( EventObject evt,
MessageEventType eventType){
final int size = transformed.length;
MessageDeliveredEvent[] events =
new MessageDeliveredEvent[size];
System.arraycopy(transformed, 0, events, 0, size);
return events;
}
/**
* Transform provided source event by processing transform layers in
* sequence.
*
* @param evt the source event to transform
* @param eventType the event type of the source event
* @return returns the resulting (transformed) events, if any. (I.e. an
* array of 0 or more size containing events.)
*/
private EventObject[] messageTransform(final EventObject evt,
final MessageEventType eventType)
{
if (evt == null)
{
return new EventObject[0];
}
ProtocolProviderService protocolProvider;
switch (eventType){
switch (eventType)
{
case MessageDelivered:
protocolProvider
= ((MessageDeliveredEvent) evt)
@ -301,7 +330,7 @@ private EventObject messageTransform( EventObject evt,
.getSourceContact().getProtocolProvider();
break;
default:
return evt;
return new EventObject[] {evt};
}
OperationSetInstantMessageTransformImpl opSetMessageTransform
@ -309,49 +338,81 @@ private EventObject messageTransform( EventObject evt,
.getOperationSet(OperationSetInstantMessageTransform.class);
if (opSetMessageTransform == null)
return evt;
return new EventObject[] {evt};
// 'current' contains the events that need to be transformed. It should
// not contain null values.
final LinkedList<EventObject> current = new LinkedList<EventObject>();
// Add source event as start of transformation.
current.add(evt);
// 'next' contains the resulting events after transformation in the
// current iteration. It should not contain null values.
final LinkedList<EventObject> next = new LinkedList<EventObject>();
for (Map.Entry<Integer, Vector<TransformLayer>> entry
: opSetMessageTransform.transformLayers.entrySet())
{
for (TransformLayer transformLayer : entry.getValue())
{
if (evt != null){
switch (eventType){
next.clear();
while (!current.isEmpty())
{
final EventObject event = current.remove();
switch (eventType)
{
case MessageDelivered:
evt
= transformLayer
.messageDelivered((MessageDeliveredEvent)evt);
MessageDeliveredEvent transformedDelivered =
transformLayer.messageDelivered(
(MessageDeliveredEvent) event);
if (transformedDelivered != null)
{
next.add(transformedDelivered);
}
break;
case MessageDeliveryPending:
evt
= transformLayer
.messageDeliveryPending(
(MessageDeliveredEvent)evt);
MessageDeliveredEvent[] evts = transformLayer
.messageDeliveryPending(
(MessageDeliveredEvent) event);
for (MessageDeliveredEvent mde : evts)
{
if (mde != null)
{
next.add(mde);
}
}
break;
case MessageDeliveryFailed:
evt
= transformLayer
.messageDeliveryFailed(
(MessageDeliveryFailedEvent)evt);
MessageDeliveryFailedEvent transformedDeliveryFailed =
transformLayer.messageDeliveryFailed(
(MessageDeliveryFailedEvent) event);
if (transformedDeliveryFailed != null)
{
next.add(transformedDeliveryFailed);
}
break;
case MessageReceived:
evt
= transformLayer
.messageReceived((MessageReceivedEvent)evt);
MessageReceivedEvent transformedReceived =
transformLayer
.messageReceived((MessageReceivedEvent) event);
if (transformedReceived != null)
{
next.add(transformedReceived);
}
break;
default:
next.add(event);
/*
* We either have nothing to do or we do not know what
* to do. Anyway, we'll silence the compiler.
* We either have nothing to do or we do not know
* what to do. Anyway, we'll silence the compiler.
*/
break;
}
}
// Set events for next round of transformations.
current.addAll(next);
}
}
return evt;
return current.toArray(new EventObject[current.size()]);
}
/**

@ -61,12 +61,13 @@ public interface TransformLayer
* @param evt the MessageDeliveredEvent containing the id of the message
* that has caused the event.
*
* @return an instance of a (possibly new) <tt>MessageDeliveredEvent</tt>
* instance containing the transformed message or <tt>null</tt> if the
* <tt>TransportLayer</tt> has determined that this message event should not
* be delivered to the upper layers.
* @return a number of instances of (possibly new)
* <tt>MessageDeliveredEvent</tt> instances containing the transformed
* message(s) or an empty array if the <tt>TransportLayer</tt> has
* determined that there are no message event that should be delivered to
* the upper layers.
*/
public MessageDeliveredEvent messageDeliveryPending(MessageDeliveredEvent evt);
public MessageDeliveredEvent[] messageDeliveryPending(MessageDeliveredEvent evt);
/**
* Called when the underlying implementation has received an indication

@ -40,7 +40,7 @@ public MessageDeliveryFailedEvent messageDeliveryFailed(
.getDestinationContact(), evt.getErrorCode());
}
public MessageDeliveredEvent messageDeliveryPending(
public MessageDeliveredEvent[] messageDeliveryPending(
MessageDeliveredEvent evt)
{
logger
@ -51,8 +51,9 @@ public MessageDeliveredEvent messageDeliveryPending(
"DELIVERY_PENDING");
logger.debug("OUT: " + transformedMessage.getContent());
return new MessageDeliveredEvent(transformedMessage, evt
.getDestinationContact(), evt.getTimestamp());
return new MessageDeliveredEvent[]
{ new MessageDeliveredEvent(transformedMessage,
evt.getDestinationContact(), evt.getTimestamp()) };
}
public MessageReceivedEvent messageReceived(MessageReceivedEvent evt)

Loading…
Cancel
Save