/* * 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.irc; import java.util.*; import net.java.sip.communicator.impl.protocol.irc.exception.*; 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 * user-to-user messaging. * * @author Danny van Heumen */ public class OperationSetBasicInstantMessagingIrcImpl extends AbstractOperationSetBasicInstantMessaging implements OperationSetBasicInstantMessagingTransport { /** * Logger. */ private static final Logger LOGGER = Logger .getLogger(OperationSetBasicInstantMessagingIrcImpl.class); /** * IRC protocol provider service. */ private final ProtocolProviderServiceIrcImpl provider; /** * Constructor. * * @param provider IRC provider service. */ public OperationSetBasicInstantMessagingIrcImpl( final ProtocolProviderServiceIrcImpl provider) { if (provider == null) { throw new IllegalArgumentException("provider cannot be null"); } this.provider = provider; } /** * Create a new message. * * {@inheritDoc} * * @param content Message content * @param contentType Message content type * @param contentEncoding message encoding * @param subject Message subject */ @Override public MessageIrcImpl createMessage(final String content, final String contentType, final String contentEncoding, final String subject) { return new MessageIrcImpl(content, contentType, contentEncoding, subject); } /** * Send instant message. * * @param to contact to send message to * @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 original) throws IllegalStateException, IllegalArgumentException { if (!(original instanceof MessageIrcImpl)) { LOGGER.error("Invalid class of Message implementation received. " + "Not sending message."); return; } final IrcConnection connection = this.provider.getIrcStack().getConnection(); if (connection == null) { throw new IllegalStateException("Connection is not available."); } // 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. final MessageDeliveredEvent[] msgDeliveryPendingEvts = messageDeliveryPendingTransform(new MessageDeliveredEvent(original, to)); if (msgDeliveryPendingEvts.length == 0) { LOGGER.warn("Message transformation result does not contain a " + "single message. Nothing to send."); return; } try { for (MessageDeliveredEvent event : msgDeliveryPendingEvts) { if (event == null) { continue; } final Message transformed = event.getSourceMessage(); // Note: can't set subject since it leaks information while // message content actually did get encrypted. MessageIrcImpl message = this.createMessage(transformed.getContent(), transformed.getContentType(), transformed.getEncoding(), ""); try { if (!event.isMessageEncrypted() && message.isCommand()) { try { connection.getMessageManager().command(to, message); } catch (final UnsupportedCommandException e) { fireMessageDeliveryFailed(message, to, MessageDeliveryFailedEvent .UNSUPPORTED_OPERATION); } catch (BadCommandException e) { LOGGER.error("Error during command execution. " + "This is most likely due to a bug in the " + "implementation of the command.", e); fireMessageDeliveryFailed(message, to, MessageDeliveryFailedEvent.INTERNAL_ERROR); } catch (BadCommandInvocationException e) { StringBuilder helpText = new StringBuilder(); if (e.getCause() != null) { helpText.append(e.getCause().getMessage()); helpText.append('\n'); } helpText.append(e.getHelp()); MessageIrcImpl helpMessage = new MessageIrcImpl( helpText.toString(), OperationSetBasicInstantMessaging .DEFAULT_MIME_TYPE, OperationSetBasicInstantMessaging .DEFAULT_MIME_ENCODING, "Command usage:"); MessageReceivedEvent helpEvent = new MessageReceivedEvent( helpMessage, to, new Date(), MessageReceivedEvent .SYSTEM_MESSAGE_RECEIVED); fireMessageEvent(helpEvent); } } else { connection.getMessageManager().message(to, message); } } catch (RuntimeException e) { LOGGER.debug("Failed to deliver (raw) message: " + message); throw e; } } fireMessageDelivered(original, to); } catch (RuntimeException e) { LOGGER.warn("Failed to deliver message: " + original, e); fireMessageDeliveryFailed(original, to, MessageDeliveryFailedEvent.NETWORK_FAILURE); } } /** * Check if offline messaging is supported. * * @return returns true if offline messaging is supported or false * otherwise. */ @Override public boolean isOfflineMessagingSupported() { return false; } /** * Test content type support. * * {@inheritDoc} * * @param contentType contentType to test * @return returns true if content type is supported */ @Override public boolean isContentTypeSupported(final String contentType) { return OperationSetBasicInstantMessaging.HTML_MIME_TYPE .equalsIgnoreCase(contentType); } /** * {@inheritDoc} * * @param message the received message * @param from the sender */ @Override protected void fireMessageReceived(final Message message, final Contact from) { super.fireMessageReceived(message, from); } /** * {@inheritDoc} * * @param message Message that has been delivered successfully. * @param to Contact to deliver message to. */ @Override protected void fireMessageDelivered(final Message message, final Contact to) { super.fireMessageDelivered(message, to); } /** * {@inheritDoc} * * @param message Message that was failed to deliver. * @param to Contact to deliver message to. * @param errorCode Error code of failed delivery. */ @Override protected void fireMessageDeliveryFailed(final Message message, final Contact to, final int errorCode) { super.fireMessageDeliveryFailed(message, to, errorCode); } /** * Calculate the maximum message size for IRC messages. * * @param contact the contact receiving the message * @return returns the size the message can be at maximum to receive a * complete message. */ @Override public int getMaxMessageSize(final Contact contact) { IrcConnection connection = this.provider.getIrcStack().getConnection(); if (connection == null) { throw new IllegalStateException("Connection is not available."); } return connection.getMessageManager().calculateMaximumMessageSize( contact); } /** * Calculate number of messages allowed to send over IRC. * * @param contact contact receiving the messages * @return returns number of messages that can be received at maximum */ @Override public int getMaxNumberOfMessages(final Contact contact) { return OperationSetBasicInstantMessagingTransport.UNLIMITED; } }