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