Implements XEP-0280 (message carbons).

cusax-fix 5061
hristoterezov 12 years ago
parent 5c5fb51f2a
commit a522c7f51a

@ -1087,6 +1087,7 @@ plugin.jabberaccregwizz.EXISTING_ACCOUNT=Existing XMPP account
plugin.jabberaccregwizz.DOMAIN_BYPASS_CAPS=Domain that will use GTalk call
plugin.jabberaccregwizz.TELEPHONY_DOMAIN=Telephony domain
plugin.jabberaccregwizz.ALLOW_NON_SECURE=Allow non-secure connections
plugin.jabberaccregwizz.DISABLE_CARBON=Disable message carbons
plugin.jabberaccregwizz.DTMF_AUTO=Auto: Choose automatically between RTP and Inband
plugin.jabberaccregwizz.SERVER_OPTIONS=Server options
plugin.jabberaccregwizz.CHANGE_PASSWORD=Change account password

@ -8,6 +8,7 @@
import java.util.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.carbon.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.mailnotification.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.messagecorrection.*;
import net.java.sip.communicator.service.protocol.*;
@ -125,6 +126,11 @@ private class TargetAddress
*/
private List<PacketFilter> packetFilters = new ArrayList<PacketFilter>();
/**
* Whether carbon is enabled or not.
*/
private boolean isCarbonEnabled = false;
/**
* Creates an instance of this operation set.
* @param provider a reference to the <tt>ProtocolProviderServiceImpl</tt>
@ -501,6 +507,11 @@ private MessageDeliveredEvent sendMessage( Contact to,
//msg.addExtension(new Version());
if(msgDeliveryPendingEvt.isMessageEncrypted())
{
msg.addExtension(new CarbonPacketExtension.PrivateExtension());
}
MessageEventManager.
addNotificationsRequests(msg, true, false, false, true);
@ -664,6 +675,20 @@ else if (evt.getNewState() == RegistrationState.REGISTERED)
if (enableGmailNotifications)
subscribeForGmailNotifications();
boolean enableCarbon
= isCarbonSupported() && !jabberProvider.getAccountID()
.getAccountPropertyBoolean(
ProtocolProviderFactory.IS_CARBON_DISABLED,
false);
if(enableCarbon)
{
enableDisableCarbon(true);
}
else
{
isCarbonEnabled = false;
}
}
else if(evt.getNewState() == RegistrationState.UNREGISTERED
|| evt.getNewState() == RegistrationState.CONNECTION_FAILED
@ -679,6 +704,91 @@ else if(evt.getNewState() == RegistrationState.UNREGISTERED
smackMessageListener = null;
}
}
}
/**
* Sends enable or disable carbon packet to the server.
* @param enable if <tt>true</tt> sends enable packet otherwise sends
* disable packet.
*/
private void enableDisableCarbon(final boolean enable)
{
IQ iq = new IQ(){
@Override
public String getChildElementXML()
{
return "<" + (enable? "enable" : "disable") + " xmlns='urn:xmpp:carbons:2' />";
}
};
Packet response = null;
try
{
PacketCollector packetCollector
= jabberProvider.getConnection().createPacketCollector(
new PacketIDFilter(iq.getPacketID()));
iq.setFrom(jabberProvider.getOurJID());
iq.setType(IQ.Type.SET);
jabberProvider.getConnection().sendPacket(iq);
response
= packetCollector.nextResult(
SmackConfiguration.getPacketReplyTimeout());
packetCollector.cancel();
}
catch(Exception e)
{
logger.error("Failed to enable carbon.", e);
}
isCarbonEnabled = false;
if (response == null)
{
logger.error(
"Failed to enable carbon. No response is received.");
}
else if (response.getError() != null)
{
logger.error(
"Failed to enable carbon: "
+ response.getError());
}
else if (!(response instanceof IQ)
|| !((IQ) response).getType().equals(IQ.Type.RESULT))
{
logger.error(
"Failed to enable carbon. The response is not correct.");
}
else
{
isCarbonEnabled = true;
}
}
/**
* Checks whether the carbon is supported by the server or not.
* @return <tt>true</tt> if carbon is supported by the server and
* <tt>false</tt> if not.
*/
private boolean isCarbonSupported()
{
try
{
return jabberProvider.getDiscoveryManager().discoverInfo(
jabberProvider.getAccountID().getService())
.containsFeature(CarbonPacketExtension.NAMESPACE);
}
catch (XMPPException e)
{
logger.error("Failed to retrieve carbon support.",e);
}
return false;
}
/**
@ -701,8 +811,30 @@ public void processPacket(Packet packet)
org.jivesoftware.smack.packet.Message msg =
(org.jivesoftware.smack.packet.Message)packet;
boolean isForwardedSentMessage = false;
if(msg.getBody() == null)
return;
{
CarbonPacketExtension carbonExt
= (CarbonPacketExtension) msg.getExtension(
CarbonPacketExtension.NAMESPACE);
if(carbonExt == null)
return;
isForwardedSentMessage
= (carbonExt.getElementName()
== CarbonPacketExtension.SENT_ELEMENT_NAME);
List<ForwardedPacketExtension> extensions
= carbonExt.getChildExtensionsOfType(
ForwardedPacketExtension.class);
if(extensions.isEmpty())
return;
ForwardedPacketExtension forwardedExt = extensions.get(0);
msg = forwardedExt.getMessage();
if(msg == null || msg.getBody() == null)
return;
}
Object multiChatExtension =
msg.getExtension("x", "http://jabber.org/protocol/muc#user");
@ -710,12 +842,16 @@ public void processPacket(Packet packet)
// its not for us
if(multiChatExtension != null)
return;
String fromUserID = StringUtils.parseBareAddress(msg.getFrom());
String userFullId
= isForwardedSentMessage? msg.getTo() : msg.getFrom();
String userBareID = StringUtils.parseBareAddress(userFullId);
boolean isPrivateMessaging = false;
ChatRoom privateContactRoom = ((OperationSetMultiUserChatJabberImpl)
jabberProvider.getOperationSet(OperationSetMultiUserChat.class))
.getChatRoom(fromUserID);
.getChatRoom(userBareID);
if(privateContactRoom != null)
{
isPrivateMessaging = true;
@ -725,7 +861,7 @@ public void processPacket(Packet packet)
{
if (logger.isDebugEnabled())
logger.debug("Received from "
+ fromUserID
+ userBareID
+ " the message "
+ msg.toXML());
}
@ -785,12 +921,12 @@ public void processPacket(Packet packet)
Contact sourceContact
= opSetPersPresence.findContactByID(
(isPrivateMessaging? msg.getFrom() : fromUserID));
(isPrivateMessaging? userFullId : userBareID));
if(msg.getType()
== org.jivesoftware.smack.packet.Message.Type.error)
{
if (logger.isInfoEnabled())
logger.info("Message error received from " + fromUserID);
logger.info("Message error received from " + userBareID);
int errorCode = packet.getError().getCode();
int errorResultCode = MessageDeliveryFailedEvent.UNKNOWN_ERROR;
@ -823,20 +959,20 @@ public void processPacket(Packet packet)
//cache the jid (resource included) of the contact that's sending us
//a message so that all following messages would go to the resource
//that they contacted us from.
String address = fromUserID;
String address = userBareID;
if(isPrivateMessaging)
{
address = JabberActivator.getResources().getI18NString(
"service.gui.FROM",
new String[]{
StringUtils.parseResource(msg.getFrom()),
fromUserID} );
userBareID} );
}
putJidForAddress(address, msg.getFrom());
putJidForAddress(address, userFullId);
if (logger.isTraceEnabled())
logger.trace("just mapped: " + fromUserID
logger.trace("just mapped: " + userBareID
+ " to " + msg.getFrom());
// In the second condition we filter all group chat messages,
@ -845,10 +981,12 @@ public void processPacket(Packet packet)
{
if (logger.isDebugEnabled())
logger.debug("received a message from an unknown contact: "
+ fromUserID);
+ userBareID);
//create the volatile contact
sourceContact = opSetPersPresence
.createVolatileContact(msg.getFrom(), isPrivateMessaging);
.createVolatileContact(
userFullId,
isPrivateMessaging);
}
Date timestamp = new Date();
@ -866,20 +1004,23 @@ public void processPacket(Packet packet)
}
ContactResource resource = ((ContactJabberImpl) sourceContact)
.getResourceFromJid(msg.getFrom());
MessageReceivedEvent msgReceivedEvt
= new MessageReceivedEvent( newMessage,
sourceContact,
resource,
timestamp,
correctedMessageUID,
isPrivateMessaging,
privateContactRoom);
.getResourceFromJid(userFullId);
EventObject msgEvt = null;
if(!isForwardedSentMessage)
msgEvt
= new MessageReceivedEvent( newMessage,
sourceContact,
resource,
timestamp,
correctedMessageUID,
isPrivateMessaging,
privateContactRoom);
else
msgEvt = new MessageDeliveredEvent(newMessage, sourceContact, timestamp);
// msgReceivedEvt = messageReceivedTransform(msgReceivedEvt);
if (msgReceivedEvt != null)
fireMessageEvent(msgReceivedEvt);
if (msgEvt != null)
fireMessageEvent(msgEvt);
}
}

@ -18,6 +18,7 @@
import net.java.sip.communicator.impl.protocol.jabber.debugger.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.caps.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.carbon.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.colibri.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.coin.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.inputevt.*;
@ -1708,6 +1709,18 @@ protected void initialize(String screenname,
ConferenceDescriptionPacketExtension.NAMESPACE,
new ConferenceDescriptionPacketExtension.Provider());
providerManager.addExtensionProvider(
CarbonPacketExtension.RECEIVED_ELEMENT_NAME,
CarbonPacketExtension.NAMESPACE,
new CarbonPacketExtension.Provider(
CarbonPacketExtension.RECEIVED_ELEMENT_NAME));
providerManager.addExtensionProvider(
CarbonPacketExtension.SENT_ELEMENT_NAME,
CarbonPacketExtension.NAMESPACE,
new CarbonPacketExtension.Provider(
CarbonPacketExtension.SENT_ELEMENT_NAME));
//initialize the telephony operation set
boolean isCallingDisabled
= JabberActivator.getConfigurationService()

@ -42,6 +42,11 @@ public abstract class AbstractPacketExtension
*/
protected final Map<String, String> attributes
= new LinkedHashMap<String, String>();
/**
* A list of all packets that are wrapped by this extension.
*/
private final List<Packet> packets = new LinkedList<Packet>();
/**
* The text content of this packet extension, if any.
@ -125,8 +130,9 @@ public String toXML()
//add child elements if any
List<? extends PacketExtension> childElements = getChildExtensions();
String text = getText();
List<Packet> packets = getPackets();
if (childElements == null)
if (childElements == null && packets == null)
{
if ((text == null) || (text.length() == 0))
{
@ -140,7 +146,7 @@ public String toXML()
{
synchronized(childElements)
{
if (childElements.isEmpty()
if (childElements.isEmpty() && packets.isEmpty()
&& ((text == null) || (text.length() == 0)))
{
bldr.append("/>");
@ -151,6 +157,8 @@ public String toXML()
bldr.append(">");
for(PacketExtension packExt : childElements)
bldr.append(packExt.toXML());
for(Packet packet : packets)
bldr.append(packet.toXML());
}
}
}
@ -159,6 +167,7 @@ public String toXML()
if((text != null) && (text.trim().length() > 0))
bldr.append(text);
bldr.append("</").append(getElementName()).append(">");
return bldr.toString();
@ -192,7 +201,27 @@ public void addChildExtension(PacketExtension childExtension)
{
childExtensions.add(childExtension);
}
/**
* Returns the list of packets.
*
* @return the list of packets.
*/
public List<Packet> getPackets()
{
return packets;
}
/**
* Adds packet to the list of packets.
*
* @param packet the packet to add.
*/
public void addPacket(Packet packet)
{
packets.add(packet);
}
/**
* Sets the value of the attribute named <tt>name</tt> to <tt>value</tt>.
*

@ -0,0 +1,137 @@
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.carbon;
import org.jivesoftware.smack.packet.*;
import org.xmlpull.v1.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
/**
* This class implements message carbons extensions added to message stanzas.
*
* @author Hristo Terezov
*/
public class CarbonPacketExtension
extends AbstractPacketExtension
{
/**
* The namespace for the XML element.
*/
public static final String NAMESPACE = "urn:xmpp:carbons:2";
/**
* The name of the "received" XML element.
*/
public static final String RECEIVED_ELEMENT_NAME = "received";
/**
* The name of the "sent" XML element.
*/
public static final String SENT_ELEMENT_NAME = "sent";
/**
* The name of the "private" XML element.
*/
public static final String PRIVATE_ELEMENT_NAME = "private";
/**
* Constructs new <tt>CarbonPacketExtension</tt> instance.
* @param elementName the name of the XML element.
*/
public CarbonPacketExtension( String elementName)
{
super(NAMESPACE, elementName);
}
/**
* Parses sent and received XML elements.
*/
public static class Provider
extends ForwardedPacketExtension.Provider
{
/**
* The name of the elements to be parsed.
*/
private String elementName;
/**
* Constructs new <tt>Provider</tt> instance.
* @param elementName the name of the elements to be parsed
*/
public Provider(String elementName)
{
this.elementName = elementName;
}
/**
* Creates a <tt>CarbonPacketExtension</tt> by parsing
* an XML document.
* @param parser the parser to use.
* @return the created <tt>CarbonPacketExtension</tt>.
* @throws Exception
*/
@Override
public PacketExtension parseExtension(XmlPullParser parser)
throws Exception
{
CarbonPacketExtension packetExtension
= new CarbonPacketExtension(elementName);
//now parse the sub elements
boolean done = false;
String elementName;
ForwardedPacketExtension extension = null;
while (!done)
{
switch (parser.next())
{
case XmlPullParser.START_TAG:
{
elementName = parser.getName();
if (ForwardedPacketExtension.ELEMENT_NAME.equals(
elementName))
{
extension = (ForwardedPacketExtension) super
.parseExtension(parser);
if (extension != null)
{
packetExtension.addChildExtension(extension);
}
}
break;
}
case XmlPullParser.END_TAG:
{
elementName = parser.getName();
if (this.elementName.equals(elementName))
{
done = true;
}
break;
}
}
}
return packetExtension;
}
}
/**
* This class implements the private carbon extension.
*/
public static class PrivateExtension extends AbstractPacketExtension
{
public PrivateExtension()
{
super(NAMESPACE, PRIVATE_ELEMENT_NAME);
}
}
}

@ -0,0 +1,123 @@
/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.jabber.extensions.carbon;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.provider.*;
import org.jivesoftware.smack.util.*;
import org.xmlpull.v1.*;
import net.java.sip.communicator.impl.protocol.jabber.extensions.*;
/**
* This class implements the forward extension. It is used by carbon extensions.
* @author Hristo Terezov
*/
public class ForwardedPacketExtension
extends AbstractPacketExtension
{
/**
* The namespace for the XML element.
*/
public static final String NAMESPACE = "urn:xmpp:forward:0";
/**
* The name of the "forwarded" XML element.
*/
public static final String ELEMENT_NAME = "forwarded";
/**
* The message instance included in the forwarded extension.
*/
private Message message = null;
/**
* Constructs new <tt>ForwardedPacketExtension</tt> instance.
*/
public ForwardedPacketExtension()
{
super(NAMESPACE, ELEMENT_NAME);
}
/**
* Sets the <tt>Message</tt> instance to the forwarded extension.
* @param message the messages
*/
public void setMessage(Message message)
{
this.message = message;
addPacket(message);
}
/**
* Returns the <tt>Message</tt> instance.
* @return the <tt>Message</tt> instance.
*/
public Message getMessage()
{
return message;
}
/**
* Parses the forwarded XML element.
*/
public static class Provider
implements PacketExtensionProvider
{
/**
* Creates a <tt>ForwardedPacketExtension</tt> by parsing
* an XML document.
* @param parser the parser to use.
* @return the created <tt>ForwardedPacketExtension</tt>.
* @throws Exception
*/
@Override
public PacketExtension parseExtension(XmlPullParser parser)
throws Exception
{
ForwardedPacketExtension packetExtension
= new ForwardedPacketExtension();
//now parse the sub elements
boolean done = false;
String elementName;
Message message = null;
while (!done)
{
switch (parser.next())
{
case XmlPullParser.START_TAG:
{
elementName = parser.getName();
if ("message".equals(elementName))
{
message
= (Message)PacketParserUtils.parseMessage(parser);
if (message != null)
{
packetExtension.setMessage(message);
}
}
break;
}
case XmlPullParser.END_TAG:
{
elementName = parser.getName();
if (ELEMENT_NAME.equals(elementName))
{
done = true;
}
break;
}
}
}
return packetExtension;
}
}
}

@ -102,6 +102,11 @@ public class ConnectionPanel
JabberAccountID.getDefaultBool(
ProtocolProviderFactory.IS_ALLOW_NON_SECURE));
JCheckBox disableCarbon = new SIPCommCheckBox(
Resources.getString("plugin.jabberaccregwizz.DISABLE_CARBON"),
JabberAccountID.getDefaultBool(
ProtocolProviderFactory.IS_CARBON_DISABLED));
private JComboBox dtmfMethodBox = new JComboBox(new Object []
{
Resources.getString(
@ -207,6 +212,7 @@ public void actionPerformed(ActionEvent e)
checkBoxesPanel.add(gmailNotificationsBox);
checkBoxesPanel.add(googleContactsBox);
checkBoxesPanel.add(allowNonSecureBox);
checkBoxesPanel.add(disableCarbon);
final JPanel resourcePanel
= new TransparentPanel(new BorderLayout(10, 10));
@ -524,6 +530,25 @@ boolean isAllowNonSecure()
return allowNonSecureBox.isSelected();
}
/**
* Set disable carbon value.
* @param value the new value.
*/
void setDisableCarbon(boolean value)
{
this.disableCarbon.setSelected(value);
}
/**
* Checks if message carbons are disabled
* @return <tt>true</tt> if message carbons are disabled and <tt>false</tt>
* otherwise.
*/
boolean isCarbonDisabled()
{
return disableCarbon.isSelected();
}
/**
* Returns the DTMF method.
* @return the DTMF method

@ -354,6 +354,7 @@ public boolean commitPage(JabberAccountRegistration registration)
registration.setUseUPNP(iceConfigPanel.isUseUPNP());
registration.setAllowNonSecure(connectionPanel.isAllowNonSecure());
registration.setDisableCarbon(connectionPanel.isCarbonDisabled());
registration.setDisableJingle(
telephonyConfigPanel.isJingleDisabled());
@ -447,6 +448,7 @@ public void loadAccount(JabberAccountRegistration accountReg)
iceConfigPanel.setUseUPNP(accountReg.isUseUPNP());
connectionPanel.setAllowNonSecure(accountReg.isAllowNonSecure());
connectionPanel.setDisableCarbon(accountReg.isCarbonDisabled());
connectionPanel.setServerOverridden(accountReg.isServerOverridden());

@ -7,6 +7,7 @@
package net.java.sip.communicator.plugin.otr;
import net.java.otr4j.*;
import net.java.otr4j.io.*;
import net.java.sip.communicator.plugin.otr.OtrContactManager.OtrContact;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
@ -110,6 +111,11 @@ public MessageDeliveredEvent messageDeliveryPending(
new MessageDeliveredEvent(processedMessage, contact, evt
.getTimestamp());
if(processedMessage.getContent().contains(SerializationConstants.HEAD))
{
processedEvent.setMessageEncrypted(true);
}
return processedEvent;
}

@ -557,6 +557,12 @@ public abstract class ProtocolProviderFactory
*/
public static final String SDES_CIPHER_SUITES = "SDES_CIPHER_SUITES";
/**
* The name of the property that defines the enabled/disabled state of
* message carbons.
*/
public static final String IS_CARBON_DISABLED = "CARBON_DISABLED";
/**
* Creates a new <tt>ProtocolProviderFactory</tt>.
*

@ -49,6 +49,11 @@ public class MessageDeliveredEvent
* Whether the delivered message is a sms message.
*/
private boolean smsMessage = false;
/**
* Whether the delivered message is encrypted or not.
*/
private boolean isMessageEncrypted = false;
/**
* Constructor.
@ -211,4 +216,24 @@ public ContactResource getContactResource()
{
return toResource;
}
/**
* Returns <tt>true</tt> if the message is encrypted and <tt>false</tt> if
* not.
* @return <tt>true</tt> if the message is encrypted and <tt>false</tt> if
* not.
*/
public boolean isMessageEncrypted()
{
return isMessageEncrypted;
}
/**
* Sets the message encrypted flag of the event.
* @param isMessageEncrypted the value to be set.
*/
public void setMessageEncrypted(boolean isMessageEncrypted)
{
this.isMessageEncrypted = isMessageEncrypted;
}
}

@ -466,6 +466,28 @@ public void setAllowNonSecure(boolean isAllowNonSecure)
ProtocolProviderFactory.IS_ALLOW_NON_SECURE, isAllowNonSecure);
}
/**
* Indicates if message carbons are allowed for this account
* @return <tt>true</tt> if message carbons are allowed for this account,
* otherwise returns <tt>false</tt>
*/
public boolean isCarbonDisabled()
{
return getAccountPropertyBoolean(
ProtocolProviderFactory.IS_CARBON_DISABLED, false);
}
/**
* Sets the <tt>IS_CARBON_DISABLED</tt> property.
* @param isCarbonEnabled <tt>true</tt> to indicate that message carbons are
* allowed for this account, <tt>false</tt> - otherwise.
*/
public void setDisableCarbon(boolean isCarbonEnabled)
{
putAccountProperty(
ProtocolProviderFactory.IS_CARBON_DISABLED, isCarbonEnabled);
}
/**
* Is resource auto generate enabled.
*

Loading…
Cancel
Save