001/**
002 *
003 * Copyright 2017 Paul Schaub
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smackx.jingle;
018
019import org.jivesoftware.smack.SmackException;
020import org.jivesoftware.smack.SmackException.NoResponseException;
021import org.jivesoftware.smack.XMPPConnection;
022import org.jivesoftware.smack.XMPPException;
023import org.jivesoftware.smack.XMPPException.XMPPErrorException;
024import org.jivesoftware.smack.packet.IQ;
025import org.jivesoftware.smack.packet.StanzaError;
026
027import org.jivesoftware.smackx.jingle.element.Jingle;
028import org.jivesoftware.smackx.jingle.element.JingleAction;
029import org.jivesoftware.smackx.jingle.element.JingleContent;
030import org.jivesoftware.smackx.jingle.element.JingleContentDescription;
031import org.jivesoftware.smackx.jingle.element.JingleContentTransport;
032import org.jivesoftware.smackx.jingle.element.JingleError;
033import org.jivesoftware.smackx.jingle.element.JingleReason;
034
035import org.jxmpp.jid.FullJid;
036
037/**
038 * Util to quickly create and send jingle stanzas.
039 */
040public class JingleUtil {
041
042    private final XMPPConnection connection;
043
044    public JingleUtil(XMPPConnection connection) {
045        this.connection = connection;
046    }
047
048    public Jingle createSessionInitiate(FullJid recipient,
049                                        String sessionId,
050                                        JingleContent.Creator contentCreator,
051                                        String contentName,
052                                        JingleContent.Senders contentSenders,
053                                        JingleContentDescription description,
054                                        JingleContentTransport transport) {
055
056        Jingle.Builder jb = Jingle.builder(connection);
057        jb.setAction(JingleAction.session_initiate)
058                .setSessionId(sessionId)
059                .setInitiator(connection.getUser());
060
061        JingleContent.Builder cb = JingleContent.getBuilder();
062        cb.setCreator(contentCreator)
063                .setName(contentName)
064                .setSenders(contentSenders)
065                .setDescription(description)
066                .setTransport(transport);
067
068        Jingle jingle = jb.addJingleContent(cb.build()).build();
069        jingle.setFrom(connection.getUser());
070        jingle.setTo(recipient);
071
072        return jingle;
073    }
074
075    public Jingle createSessionInitiateFileOffer(FullJid recipient,
076                                                 String sessionId,
077                                                 JingleContent.Creator contentCreator,
078                                                 String contentName,
079                                                 JingleContentDescription description,
080                                                 JingleContentTransport transport) {
081        return createSessionInitiate(recipient, sessionId, contentCreator, contentName,
082                JingleContent.Senders.initiator, description, transport);
083    }
084
085    public IQ sendSessionInitiateFileOffer(FullJid recipient,
086                                           String sessionId,
087                                           JingleContent.Creator contentCreator,
088                                           String contentName,
089                                           JingleContentDescription description,
090                                           JingleContentTransport transport)
091            throws SmackException.NotConnectedException, InterruptedException,
092            XMPPException.XMPPErrorException, SmackException.NoResponseException {
093
094        Jingle jingle = createSessionInitiateFileOffer(recipient, sessionId, contentCreator, contentName, description, transport);
095        return connection.sendIqRequestAndWaitForResponse(jingle);
096    }
097
098    public IQ sendSessionInitiate(FullJid recipient,
099                                  String sessionId,
100                                  JingleContent.Creator contentCreator,
101                                  String contentName,
102                                  JingleContent.Senders contentSenders,
103                                  JingleContentDescription description,
104                                  JingleContentTransport transport)
105            throws SmackException.NotConnectedException, InterruptedException, NoResponseException, XMPPErrorException {
106
107        Jingle jingle = createSessionInitiate(recipient, sessionId, contentCreator, contentName, contentSenders,
108                description, transport);
109
110        return connection.sendIqRequestAndWaitForResponse(jingle);
111    }
112
113    public Jingle createSessionAccept(FullJid recipient,
114                                      String sessionId,
115                                      JingleContent.Creator contentCreator,
116                                      String contentName,
117                                      JingleContent.Senders contentSenders,
118                                      JingleContentDescription description,
119                                      JingleContentTransport transport) {
120
121        Jingle.Builder jb = Jingle.builder(connection);
122        jb.setResponder(connection.getUser())
123                .setAction(JingleAction.session_accept)
124                .setSessionId(sessionId);
125
126        JingleContent.Builder cb = JingleContent.getBuilder();
127        cb.setCreator(contentCreator)
128                .setName(contentName)
129                .setSenders(contentSenders)
130                .setDescription(description)
131                .setTransport(transport);
132
133        Jingle jingle = jb.addJingleContent(cb.build()).build();
134        jingle.setTo(recipient);
135        jingle.setFrom(connection.getUser());
136
137        return jingle;
138    }
139
140    public IQ sendSessionAccept(FullJid recipient,
141                                String sessionId,
142                                JingleContent.Creator contentCreator,
143                                String contentName,
144                                JingleContent.Senders contentSenders,
145                                JingleContentDescription description,
146                                JingleContentTransport transport)
147            throws SmackException.NotConnectedException, InterruptedException, NoResponseException, XMPPErrorException {
148
149        Jingle jingle = createSessionAccept(recipient, sessionId, contentCreator, contentName, contentSenders,
150                description, transport);
151
152        return connection.sendIqRequestAndWaitForResponse(jingle);
153    }
154
155    public Jingle createSessionTerminate(FullJid recipient, String sessionId, JingleReason reason) {
156        Jingle.Builder jb = Jingle.builder(connection);
157        jb.setAction(JingleAction.session_terminate)
158                .setSessionId(sessionId)
159                .setReason(reason);
160
161        Jingle jingle = jb.build();
162        jingle.setFrom(connection.getUser());
163        jingle.setTo(recipient);
164
165        return jingle;
166    }
167
168    public Jingle createSessionTerminate(FullJid recipient, String sessionId, JingleReason.Reason reason) {
169        return createSessionTerminate(recipient, sessionId, new JingleReason(reason));
170    }
171
172    public Jingle createSessionTerminateDecline(FullJid recipient, String sessionId) {
173        return createSessionTerminate(recipient, sessionId, JingleReason.Reason.decline);
174    }
175
176    public IQ sendSessionTerminateDecline(FullJid recipient, String sessionId)
177            throws SmackException.NotConnectedException, InterruptedException,
178            XMPPException.XMPPErrorException, SmackException.NoResponseException {
179
180        Jingle jingle = createSessionTerminateDecline(recipient, sessionId);
181        return connection.sendIqRequestAndWaitForResponse(jingle);
182    }
183
184    public Jingle createSessionTerminateSuccess(FullJid recipient, String sessionId) {
185        return createSessionTerminate(recipient, sessionId, JingleReason.Reason.success);
186    }
187
188    public IQ sendSessionTerminateSuccess(FullJid recipient, String sessionId)
189            throws InterruptedException, XMPPException.XMPPErrorException,
190            SmackException.NotConnectedException, SmackException.NoResponseException {
191
192        Jingle jingle = createSessionTerminateSuccess(recipient, sessionId);
193        return connection.sendIqRequestAndWaitForResponse(jingle);
194    }
195
196    public Jingle createSessionTerminateBusy(FullJid recipient, String sessionId) {
197        return createSessionTerminate(recipient, sessionId, JingleReason.Reason.busy);
198    }
199
200    public IQ sendSessionTerminateBusy(FullJid recipient, String sessionId)
201            throws InterruptedException, XMPPException.XMPPErrorException,
202            SmackException.NotConnectedException, SmackException.NoResponseException {
203
204        Jingle jingle = createSessionTerminateBusy(recipient, sessionId);
205        return connection.sendIqRequestAndWaitForResponse(jingle);
206    }
207
208    public Jingle createSessionTerminateAlternativeSession(FullJid recipient, String sessionId, String altSessionId) {
209        return createSessionTerminate(recipient, sessionId, JingleReason.AlternativeSession(altSessionId));
210    }
211
212    public IQ sendSessionTerminateAlternativeSession(FullJid recipient, String sessionId, String altSessionId)
213            throws InterruptedException, XMPPException.XMPPErrorException,
214            SmackException.NotConnectedException, SmackException.NoResponseException {
215
216        Jingle jingle = createSessionTerminateAlternativeSession(recipient, sessionId, altSessionId);
217        return connection.sendIqRequestAndWaitForResponse(jingle);
218    }
219
220    public Jingle createSessionTerminateCancel(FullJid recipient, String sessionId) {
221        return createSessionTerminate(recipient, sessionId, JingleReason.Reason.cancel);
222    }
223
224    public IQ sendSessionTerminateCancel(FullJid recipient,
225                                  String sessionId)
226            throws InterruptedException, XMPPException.XMPPErrorException,
227            SmackException.NotConnectedException, SmackException.NoResponseException {
228
229        Jingle jingle = createSessionTerminateCancel(recipient, sessionId);
230        return connection.sendIqRequestAndWaitForResponse(jingle);
231    }
232
233    public Jingle createSessionTerminateContentCancel(FullJid recipient, String sessionId,
234                                                      JingleContent.Creator contentCreator, String contentName) {
235        Jingle.Builder jb = Jingle.builder(connection);
236        jb.setAction(JingleAction.session_terminate)
237                .setSessionId(sessionId);
238
239        JingleContent.Builder cb = JingleContent.getBuilder();
240        cb.setCreator(contentCreator).setName(contentName);
241
242        Jingle jingle = jb.addJingleContent(cb.build()).build();
243        jingle.setFrom(connection.getUser());
244        jingle.setTo(recipient);
245
246        return jingle;
247    }
248
249    public IQ sendSessionTerminateContentCancel(FullJid recipient, String sessionId,
250                                  JingleContent.Creator contentCreator, String contentName)
251            throws SmackException.NotConnectedException, InterruptedException,
252            XMPPException.XMPPErrorException, SmackException.NoResponseException {
253        Jingle jingle = createSessionTerminateContentCancel(recipient, sessionId, contentCreator, contentName);
254        return connection.sendIqRequestAndWaitForResponse(jingle);
255    }
256
257    public Jingle createSessionTerminateUnsupportedTransports(FullJid recipient, String sessionId) {
258        return createSessionTerminate(recipient, sessionId, JingleReason.Reason.unsupported_transports);
259    }
260
261    public IQ sendSessionTerminateUnsupportedTransports(FullJid recipient, String sessionId)
262            throws InterruptedException, XMPPException.XMPPErrorException,
263            SmackException.NotConnectedException, SmackException.NoResponseException {
264        Jingle jingle = createSessionTerminateUnsupportedTransports(recipient, sessionId);
265        return connection.sendIqRequestAndWaitForResponse(jingle);
266    }
267
268    public Jingle createSessionTerminateFailedTransport(FullJid recipient, String sessionId) {
269        return createSessionTerminate(recipient, sessionId, JingleReason.Reason.failed_transport);
270    }
271
272    public IQ sendSessionTerminateFailedTransport(FullJid recipient, String sessionId)
273            throws InterruptedException, XMPPException.XMPPErrorException,
274            SmackException.NotConnectedException, SmackException.NoResponseException {
275        Jingle jingle = createSessionTerminateFailedTransport(recipient, sessionId);
276        return connection.sendIqRequestAndWaitForResponse(jingle);
277    }
278
279    public Jingle createSessionTerminateUnsupportedApplications(FullJid recipient, String sessionId) {
280        return createSessionTerminate(recipient, sessionId, JingleReason.Reason.unsupported_applications);
281    }
282
283    public IQ sendSessionTerminateUnsupportedApplications(FullJid recipient, String sessionId)
284            throws InterruptedException, XMPPException.XMPPErrorException,
285            SmackException.NotConnectedException, SmackException.NoResponseException {
286        Jingle jingle = createSessionTerminateUnsupportedApplications(recipient, sessionId);
287        return connection.sendIqRequestAndWaitForResponse(jingle);
288    }
289
290    public Jingle createSessionTerminateFailedApplication(FullJid recipient, String sessionId) {
291        return createSessionTerminate(recipient, sessionId, JingleReason.Reason.failed_application);
292    }
293
294    public IQ sendSessionTerminateFailedApplication(FullJid recipient, String sessionId)
295            throws InterruptedException, XMPPException.XMPPErrorException,
296            SmackException.NotConnectedException, SmackException.NoResponseException {
297        Jingle jingle = createSessionTerminateFailedApplication(recipient, sessionId);
298        return connection.sendIqRequestAndWaitForResponse(jingle);
299    }
300
301    public Jingle createSessionTerminateIncompatibleParameters(FullJid recipient, String sessionId) {
302        return createSessionTerminate(recipient, sessionId, JingleReason.Reason.incompatible_parameters);
303    }
304
305    public IQ sendSessionTerminateIncompatibleParameters(FullJid recipient, String sessionId)
306            throws InterruptedException, XMPPException.XMPPErrorException,
307            SmackException.NotConnectedException, SmackException.NoResponseException {
308        Jingle jingle = createSessionTerminateIncompatibleParameters(recipient, sessionId);
309        return connection.sendIqRequestAndWaitForResponse(jingle);
310    }
311
312    public IQ sendContentRejectFileNotAvailable(FullJid recipient, String sessionId, JingleContentDescription description) {
313        return null; //TODO Later
314    }
315
316    public Jingle createSessionPing(FullJid recipient, String sessionId) {
317        Jingle.Builder jb = Jingle.builder(connection);
318        jb.setSessionId(sessionId)
319                .setAction(JingleAction.session_info);
320
321        Jingle jingle = jb.build();
322        jingle.setFrom(connection.getUser());
323        jingle.setTo(recipient);
324
325        return jingle;
326    }
327
328    public IQ sendSessionPing(FullJid recipient, String sessionId)
329            throws SmackException.NotConnectedException, InterruptedException,
330            XMPPException.XMPPErrorException, SmackException.NoResponseException {
331        Jingle jingle = createSessionPing(recipient, sessionId);
332        return connection.sendIqRequestAndWaitForResponse(jingle);
333    }
334
335    public IQ createAck(Jingle jingle) {
336        return IQ.createResultIQ(jingle);
337    }
338
339    public void sendAck(Jingle jingle) throws SmackException.NotConnectedException, InterruptedException {
340        connection.sendStanza(createAck(jingle));
341    }
342
343    public Jingle createTransportReplace(FullJid recipient, FullJid initiator, String sessionId,
344                                         JingleContent.Creator contentCreator, String contentName,
345                                         JingleContentTransport transport) {
346        Jingle.Builder jb = Jingle.builder(connection);
347        jb.setInitiator(initiator)
348                .setSessionId(sessionId)
349                .setAction(JingleAction.transport_replace);
350
351        JingleContent.Builder cb = JingleContent.getBuilder();
352        cb.setName(contentName).setCreator(contentCreator).setTransport(transport);
353        Jingle jingle = jb.addJingleContent(cb.build()).build();
354
355        jingle.setTo(recipient);
356        jingle.setFrom(connection.getUser());
357
358        return jingle;
359    }
360
361    public IQ sendTransportReplace(FullJid recipient, FullJid initiator, String sessionId,
362                                   JingleContent.Creator contentCreator, String contentName,
363                                   JingleContentTransport transport)
364            throws SmackException.NotConnectedException, InterruptedException,
365            XMPPException.XMPPErrorException, SmackException.NoResponseException {
366        Jingle jingle = createTransportReplace(recipient, initiator, sessionId, contentCreator, contentName, transport);
367        return connection.sendIqRequestAndWaitForResponse(jingle);
368    }
369
370    public Jingle createTransportAccept(FullJid recipient, FullJid initiator, String sessionId,
371                                        JingleContent.Creator contentCreator, String contentName,
372                                        JingleContentTransport transport) {
373        Jingle.Builder jb = Jingle.builder(connection);
374        jb.setAction(JingleAction.transport_accept)
375                .setInitiator(initiator)
376                .setSessionId(sessionId);
377
378        JingleContent.Builder cb = JingleContent.getBuilder();
379        cb.setCreator(contentCreator).setName(contentName).setTransport(transport);
380
381        Jingle jingle = jb.addJingleContent(cb.build()).build();
382        jingle.setTo(recipient);
383        jingle.setFrom(connection.getUser());
384
385        return jingle;
386    }
387
388    public IQ sendTransportAccept(FullJid recipient, FullJid initiator, String sessionId,
389                                  JingleContent.Creator contentCreator, String contentName,
390                                  JingleContentTransport transport)
391            throws SmackException.NotConnectedException, InterruptedException,
392            XMPPException.XMPPErrorException, SmackException.NoResponseException {
393        Jingle jingle = createTransportAccept(recipient, initiator, sessionId, contentCreator, contentName, transport);
394        return connection.sendIqRequestAndWaitForResponse(jingle);
395    }
396
397    public Jingle createTransportReject(FullJid recipient, FullJid initiator, String sessionId,
398                                        JingleContent.Creator contentCreator, String contentName,
399                                        JingleContentTransport transport) {
400        Jingle.Builder jb = Jingle.builder(connection);
401        jb.setAction(JingleAction.transport_reject)
402                .setInitiator(initiator)
403                .setSessionId(sessionId);
404
405        JingleContent.Builder cb = JingleContent.getBuilder();
406        cb.setCreator(contentCreator).setName(contentName).setTransport(transport);
407
408        Jingle jingle = jb.addJingleContent(cb.build()).build();
409        jingle.setTo(recipient);
410        jingle.setFrom(connection.getUser());
411
412        return jingle;
413    }
414
415    public IQ sendTransportReject(FullJid recipient, FullJid initiator, String sessionId,
416                                  JingleContent.Creator contentCreator, String contentName,
417                                  JingleContentTransport transport)
418            throws SmackException.NotConnectedException, InterruptedException,
419            XMPPException.XMPPErrorException, SmackException.NoResponseException {
420        Jingle jingle = createTransportReject(recipient, initiator, sessionId, contentCreator, contentName, transport);
421        return connection.sendIqRequestAndWaitForResponse(jingle);
422    }
423
424    /*
425     * ####################################################################################################
426     */
427
428    public IQ createErrorUnknownSession(Jingle request) {
429        StanzaError error = StanzaError.getBuilder()
430                        .setCondition(StanzaError.Condition.item_not_found)
431                        .addExtension(JingleError.UNKNOWN_SESSION)
432                        .build();
433        return IQ.createErrorResponse(request, error);
434    }
435
436    public void sendErrorUnknownSession(Jingle request)
437            throws SmackException.NotConnectedException, InterruptedException {
438        connection.sendStanza(createErrorUnknownSession(request));
439    }
440
441    public IQ createErrorUnknownInitiator(Jingle request) {
442        return IQ.createErrorResponse(request, StanzaError.Condition.service_unavailable);
443    }
444
445    public void sendErrorUnknownInitiator(Jingle request)
446            throws SmackException.NotConnectedException, InterruptedException {
447        connection.sendStanza(createErrorUnknownInitiator(request));
448    }
449
450    public IQ createErrorUnsupportedInfo(Jingle request) {
451        StanzaError error = StanzaError.getBuilder()
452                        .setCondition(StanzaError.Condition.feature_not_implemented)
453                        .addExtension(JingleError.UNSUPPORTED_INFO)
454                        .build();
455        return IQ.createErrorResponse(request, error);
456    }
457
458    public void sendErrorUnsupportedInfo(Jingle request)
459            throws SmackException.NotConnectedException, InterruptedException {
460        connection.sendStanza(createErrorUnsupportedInfo(request));
461    }
462
463    public IQ createErrorTieBreak(Jingle request) {
464        StanzaError error = StanzaError.getBuilder()
465                        .setCondition(StanzaError.Condition.conflict)
466                        .addExtension(JingleError.TIE_BREAK)
467                        .build();
468        return IQ.createErrorResponse(request, error);
469    }
470
471    public void sendErrorTieBreak(Jingle request)
472            throws SmackException.NotConnectedException, InterruptedException {
473        connection.sendStanza(createErrorTieBreak(request));
474    }
475
476    public IQ createErrorOutOfOrder(Jingle request) {
477        StanzaError error = StanzaError.getBuilder()
478                        .setCondition(StanzaError.Condition.unexpected_request)
479                        .addExtension(JingleError.OUT_OF_ORDER)
480                        .build();
481        return IQ.createErrorResponse(request, error);
482    }
483
484    public void sendErrorOutOfOrder(Jingle request)
485            throws SmackException.NotConnectedException, InterruptedException {
486        connection.sendStanza(createErrorOutOfOrder(request));
487    }
488
489    public IQ createErrorMalformedRequest(Jingle request) {
490        return IQ.createErrorResponse(request, StanzaError.Condition.bad_request);
491    }
492
493    public void sendErrorMalformedRequest(Jingle request)
494            throws SmackException.NotConnectedException, InterruptedException {
495        connection.sendStanza(createErrorMalformedRequest(request));
496    }
497}