aboutsummaryrefslogtreecommitdiffstats
path: root/src/net/java/sip/communicator/impl/protocol/irc/OperationSetBasicInstantMessagingIrcImpl.java
blob: 9f33ca824e1028955bedbd16d90de9be069f2f14 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
/*
 * 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;
    }
}