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}