/**
   * Selects an appropriate stream negotiator after examining the incoming file transfer request.
   *
   * @param request The related file transfer request.
   * @return The file transfer object that handles the transfer
   * @throws XMPPException If there are either no stream methods contained in the packet, or there
   *     is not an appropriate stream method.
   */
  public StreamNegotiator selectStreamNegotiator(FileTransferRequest request) throws XMPPException {
    final StreamInitiation si = request.getStreamInitiation();
    final FormField streamMethodField = getStreamMethodField(si.getFeatureNegotiationForm());

    if (streamMethodField == null) {
      final String errorMessage = "No stream methods contained in packet.";
      final XMPPError error = new XMPPError(XMPPError.Condition.bad_request, errorMessage);
      final IQ iqPacket = createIQ(si.getPacketID(), si.getFrom(), si.getTo(), IQ.Type.ERROR);
      iqPacket.setError(error);
      connection.sendPacket(iqPacket);
      throw new XMPPException(errorMessage, error);
    }

    // select the appropriate protocol

    StreamNegotiator selectedStreamNegotiator;
    try {
      selectedStreamNegotiator = getNegotiator(streamMethodField);
    } catch (final XMPPException e) {
      final IQ iqPacket = createIQ(si.getPacketID(), si.getFrom(), si.getTo(), IQ.Type.ERROR);
      iqPacket.setError(e.getXMPPError());
      connection.sendPacket(iqPacket);
      throw e;
    }

    // return the appropriate negotiator

    return selectedStreamNegotiator;
  }
Example #2
0
  /**
   * Returns the discovered items of a given XMPP entity addressed by its JID and note attribute.
   * Use this message only when trying to query information which is not directly addressable.
   *
   * @param entityID the address of the XMPP entity.
   * @param node the attribute that supplements the 'jid' attribute.
   * @return the discovered items.
   * @throws XMPPException if the operation failed for some reason.
   */
  public DiscoverItems discoverItems(String entityID, String node) throws XMPPException {
    // Discover the entity's items
    DiscoverItems disco = new DiscoverItems();
    disco.setType(IQ.Type.GET);
    disco.setTo(entityID);
    disco.setNode(node);

    // Create a packet collector to listen for a response.
    PacketCollector collector =
        connection.createPacketCollector(new PacketIDFilter(disco.getPacketID()));

    connection.sendPacket(disco);

    // Wait up to 5 seconds for a result.
    IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
    // Stop queuing results
    collector.cancel();
    if (result == null) {
      throw new XMPPException("No response from the server.");
    }
    if (result.getType() == IQ.Type.ERROR) {
      throw new XMPPException(result.getError());
    }
    return (DiscoverItems) result;
  }
  /**
   * Sends a reply to a previously received packet that was sent to multiple recipients. Before
   * attempting to send the reply message some checkings are performed. If any of those checkings
   * fail then an XMPPException is going to be thrown with the specific error detail.
   *
   * @param connection the connection to use to send the reply.
   * @param original the previously received packet that was sent to multiple recipients.
   * @param reply the new message to send as a reply.
   * @throws XMPPException if the original message was not sent to multiple recipients, or the
   *     original message cannot be replied or reply should be sent to a room.
   */
  public static void reply(Connection connection, Message original, Message reply)
      throws XMPPException {
    MultipleRecipientInfo info = getMultipleRecipientInfo(original);
    if (info == null) {
      throw new XMPPException("Original message does not contain multiple recipient info");
    }
    if (info.shouldNotReply()) {
      throw new XMPPException("Original message should not be replied");
    }
    if (info.getReplyRoom() != null) {
      throw new XMPPException("Reply should be sent through a room");
    }
    // Any <thread/> element from the initial message MUST be copied into the reply.
    if (original.getThread() != null) {
      reply.setThread(original.getThread());
    }
    MultipleAddresses.Address replyAddress = info.getReplyAddress();
    if (replyAddress != null && replyAddress.getJid() != null) {
      // Send reply to the reply_to address
      reply.setTo(replyAddress.getJid());
      connection.sendPacket(reply);
    } else {
      // Send reply to multiple recipients
      List<String> to = new ArrayList<String>();
      List<String> cc = new ArrayList<String>();
      for (Iterator<MultipleAddresses.Address> it = info.getTOAddresses().iterator();
          it.hasNext(); ) {
        String jid = it.next().getJid();
        to.add(jid);
      }
      for (Iterator<MultipleAddresses.Address> it = info.getCCAddresses().iterator();
          it.hasNext(); ) {
        String jid = it.next().getJid();
        cc.add(jid);
      }
      // Add original sender as a 'to' address (if not already present)
      if (!to.contains(original.getFrom()) && !cc.contains(original.getFrom())) {
        to.add(original.getFrom());
      }
      // Remove the sender from the TO/CC list (try with bare JID too)
      String from = connection.getUser();
      if (!to.remove(from) && !cc.remove(from)) {
        String bareJID = StringUtils.parseBareAddress(from);
        to.remove(bareJID);
        cc.remove(bareJID);
      }

      String serviceAddress = getMultipleRecipienServiceAddress(connection);
      if (serviceAddress != null) {
        // Send packet to target users using multiple recipient service provided by the server
        sendThroughService(connection, reply, to, cc, null, null, null, false, serviceAddress);
      } else {
        // Server does not support JEP-33 so try to send the packet to each recipient
        sendToIndividualRecipients(connection, reply, to, cc, null);
      }
    }
  }
  protected void rejectIncomingFileTransfer(FileTransferRequest request) {
    StreamInitiation initiation = request.getStreamInitiation();

    IQ rejection =
        FileTransferNegotiator.createIQ(
            initiation.getPacketID(), initiation.getFrom(), initiation.getTo(), IQ.Type.ERROR);
    rejection.setError(new XMPPError(XMPPError.Condition.no_acceptable));
    connection.sendPacket(rejection);
  }
Example #5
0
  public InputStream createIncomingStream(StreamInitiation initiation) throws XMPPException {
    PacketCollector collector =
        connection.createPacketCollector(
            getInitiationPacketFilter(initiation.getFrom(), initiation.getSessionID()));

    connection.sendPacket(super.createInitiationAccept(initiation, getNamespaces()));

    ExecutorService threadPoolExecutor = Executors.newFixedThreadPool(2);
    CompletionService<InputStream> service =
        new ExecutorCompletionService<InputStream>(threadPoolExecutor);
    List<Future<InputStream>> futures = new ArrayList<Future<InputStream>>();
    InputStream stream = null;
    XMPPException exception = null;
    try {
      futures.add(service.submit(new NegotiatorService(collector)));
      futures.add(service.submit(new NegotiatorService(collector)));

      int i = 0;
      while (stream == null && i < futures.size()) {
        Future<InputStream> future;
        try {
          i++;
          future = service.poll(10, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
          continue;
        }

        if (future == null) {
          continue;
        }

        try {
          stream = future.get();
        } catch (InterruptedException e) {
          /* Do Nothing */
        } catch (ExecutionException e) {
          exception = new XMPPException(e.getCause());
        }
      }
    } finally {
      for (Future<InputStream> future : futures) {
        future.cancel(true);
      }
      collector.cancel();
      threadPoolExecutor.shutdownNow();
    }
    if (stream == null) {
      if (exception != null) {
        throw exception;
      } else {
        throw new XMPPException("File transfer negotiation failed.");
      }
    }

    return stream;
  }
  /**
   * Sends a roster to userID. All the entries of the roster will be sent to the target user.
   *
   * @param roster the roster to send
   * @param targetUserID the user that will receive the roster entries
   */
  public void send(Roster roster, String targetUserID) {
    // Create a new message to send the roster
    Message msg = new Message(targetUserID);
    // Create a RosterExchange Package and add it to the message
    RosterExchange rosterExchange = new RosterExchange(roster);
    msg.addExtension(rosterExchange);

    // Send the message that contains the roster
    con.sendPacket(msg);
  }
Example #7
0
 /**
  * Sets the name associated with this entry.
  *
  * @param name the name.
  */
 public void setName(String name) {
   // Do nothing if the name hasn't changed.
   if (name != null && name.equals(this.name)) {
     return;
   }
   this.name = name;
   RosterPacket packet = new RosterPacket();
   packet.setType(IQ.Type.SET);
   packet.addRosterItem(toRosterItem(this));
   connection.sendPacket(packet);
 }
Example #8
0
  /**
   * Returns true if the workgroup is available for receiving new requests. The workgroup will be
   * available only when agents are available for this workgroup.
   *
   * @return true if the workgroup is available for receiving new requests.
   * @throws XMPPException
   */
  public boolean isAvailable() throws XMPPException {
    Presence directedPresence = new Presence(Presence.Type.available);
    directedPresence.setTo(workgroupJID);
    PacketFilter typeFilter = new PacketTypeFilter(Presence.class);
    PacketFilter fromFilter = FromMatchesFilter.create(workgroupJID);
    PacketCollector collector =
        connection.createPacketCollector(new AndFilter(fromFilter, typeFilter));

    connection.sendPacket(directedPresence);

    Presence response = (Presence) collector.nextResultOrThrow();
    return Presence.Type.available == response.getType();
  }
  /**
   * Sends a roster group to userID. All the entries of the group will be sent to the target user.
   *
   * @param rosterGroup the roster group to send
   * @param targetUserID the user that will receive the roster entries
   */
  public void send(RosterGroup rosterGroup, String targetUserID) {
    // Create a new message to send the roster
    Message msg = new Message(targetUserID);
    // Create a RosterExchange Package and add it to the message
    RosterExchange rosterExchange = new RosterExchange();
    for (RosterEntry entry : rosterGroup.getEntries()) {
      rosterExchange.addRosterEntry(entry);
    }
    msg.addExtension(rosterExchange);

    // Send the message that contains the roster
    con.sendPacket(msg);
  }
 private static void sendToIndividualRecipients(
     Connection connection, Packet packet, List<String> to, List<String> cc, List<String> bcc) {
   if (to != null) {
     for (Iterator<String> it = to.iterator(); it.hasNext(); ) {
       String jid = it.next();
       packet.setTo(jid);
       connection.sendPacket(new PacketCopy(packet.toXML()));
     }
   }
   if (cc != null) {
     for (Iterator<String> it = cc.iterator(); it.hasNext(); ) {
       String jid = it.next();
       packet.setTo(jid);
       connection.sendPacket(new PacketCopy(packet.toXML()));
     }
   }
   if (bcc != null) {
     for (Iterator<String> it = bcc.iterator(); it.hasNext(); ) {
       String jid = it.next();
       packet.setTo(jid);
       connection.sendPacket(new PacketCopy(packet.toXML()));
     }
   }
 }
 private static void sendThroughService(
     Connection connection,
     Packet packet,
     List<String> to,
     List<String> cc,
     List<String> bcc,
     String replyTo,
     String replyRoom,
     boolean noReply,
     String serviceAddress) {
   // Create multiple recipient extension
   MultipleAddresses multipleAddresses = new MultipleAddresses();
   if (to != null) {
     for (Iterator<String> it = to.iterator(); it.hasNext(); ) {
       String jid = it.next();
       multipleAddresses.addAddress(MultipleAddresses.TO, jid, null, null, false, null);
     }
   }
   if (cc != null) {
     for (Iterator<String> it = cc.iterator(); it.hasNext(); ) {
       String jid = it.next();
       multipleAddresses.addAddress(MultipleAddresses.CC, jid, null, null, false, null);
     }
   }
   if (bcc != null) {
     for (Iterator<String> it = bcc.iterator(); it.hasNext(); ) {
       String jid = it.next();
       multipleAddresses.addAddress(MultipleAddresses.BCC, jid, null, null, false, null);
     }
   }
   if (noReply) {
     multipleAddresses.setNoReply();
   } else {
     if (replyTo != null && replyTo.trim().length() > 0) {
       multipleAddresses.addAddress(MultipleAddresses.REPLY_TO, replyTo, null, null, false, null);
     }
     if (replyRoom != null && replyRoom.trim().length() > 0) {
       multipleAddresses.addAddress(
           MultipleAddresses.REPLY_ROOM, replyRoom, null, null, false, null);
     }
   }
   // Set the multiple recipient service address as the target address
   packet.setTo(serviceAddress);
   // Add extension to packet
   packet.addExtension(multipleAddresses);
   // Send the packet
   connection.sendPacket(packet);
 }
Example #12
0
  /**
   * Notify server to change the carbons state. This method returns immediately and changes the
   * variable when the reply arrives.
   *
   * <p>You should first check for support using isSupportedByServer().
   *
   * @param new_state whether carbons should be enabled or disabled
   */
  public void sendCarbonsEnabled(final boolean new_state) {
    final Connection connection = weakRefConnection.get();
    IQ setIQ = carbonsEnabledIQ(new_state);

    connection.addPacketListener(
        new PacketListener() {
          public void processPacket(Packet packet) {
            IQ result = (IQ) packet;
            if (result.getType() == IQ.Type.RESULT) {
              enabled_state = new_state;
            }
            connection.removePacketListener(this);
          }
        },
        new IQReplyFilter(setIQ, connection));

    connection.sendPacket(setIQ);
  }
Example #13
0
 /**
  * Gets the account registration info from the server.
  *
  * @throws XMPPException if an error occurs.
  */
 private synchronized void getRegistrationInfo() throws XMPPException {
   Registration reg = new Registration();
   reg.setTo(connection.getServiceName());
   PacketFilter filter =
       new AndFilter(new PacketIDFilter(reg.getPacketID()), new PacketTypeFilter(IQ.class));
   PacketCollector collector = connection.createPacketCollector(filter);
   connection.sendPacket(reg);
   IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
   // Stop queuing results
   collector.cancel();
   if (result == null) {
     throw new XMPPException("No response from server.");
   } else if (result.getType() == IQ.Type.ERROR) {
     throw new XMPPException(result.getError());
   } else {
     info = (Registration) result;
   }
 }
  /**
   * Send a request to another user to send them a file. The other user has the option of,
   * accepting, rejecting, or not responding to a received file transfer request.
   *
   * <p>If they accept, the packet will contain the other user's chosen stream type to send the file
   * across. The two choices this implementation provides to the other user for file transfer are <a
   * href="http://www.jabber.org/jeps/jep-0065.html">SOCKS5 Bytestreams</a>, which is the preferred
   * method of transfer, and <a href="http://www.jabber.org/jeps/jep-0047.html">In-Band
   * Bytestreams</a>, which is the fallback mechanism.
   *
   * <p>The other user may choose to decline the file request if they do not desire the file, their
   * client does not support JEP-0096, or if there are no acceptable means to transfer the file.
   *
   * <p>Finally, if the other user does not respond this method will return null after the specified
   * timeout.
   *
   * @param userID The userID of the user to whom the file will be sent.
   * @param streamID The unique identifier for this file transfer.
   * @param fileName The name of this file. Preferably it should include an extension as it is used
   *     to determine what type of file it is.
   * @param size The size, in bytes, of the file.
   * @param desc A description of the file.
   * @param responseTimeout The amount of time, in milliseconds, to wait for the remote user to
   *     respond. If they do not respond in time, this
   * @return Returns the stream negotiator selected by the peer.
   * @throws XMPPException Thrown if there is an error negotiating the file transfer.
   */
  public StreamNegotiator negotiateOutgoingTransfer(
      final String userID,
      final String streamID,
      final String fileName,
      final long size,
      final String desc,
      int responseTimeout)
      throws XMPPException {
    final StreamInitiation si = new StreamInitiation();
    si.setSesssionID(streamID);
    si.setMimeType(URLConnection.guessContentTypeFromName(fileName));

    final StreamInitiation.File siFile = new StreamInitiation.File(fileName, size);
    siFile.setDesc(desc);
    si.setFile(siFile);

    si.setFeatureNegotiationForm(createDefaultInitiationForm());

    si.setFrom(connection.getUser());
    si.setTo(userID);
    si.setType(IQ.Type.SET);

    final PacketCollector collector =
        connection.createPacketCollector(new PacketIDFilter(si.getPacketID()));
    connection.sendPacket(si);
    final Packet siResponse = collector.nextResult(responseTimeout);
    collector.cancel();

    if (siResponse instanceof IQ) {
      final IQ iqResponse = (IQ) siResponse;
      if (iqResponse.getType().equals(IQ.Type.RESULT)) {
        final StreamInitiation response = (StreamInitiation) siResponse;
        return getOutgoingNegotiator(getStreamMethodField(response.getFeatureNegotiationForm()));

      } else if (iqResponse.getType().equals(IQ.Type.ERROR)) {
        throw new XMPPException(iqResponse.getError());
      } else {
        throw new XMPPException("File transfer response unreadable");
      }
    } else {
      return null;
    }
  }
Example #15
0
 /**
  * Changes the password of the currently logged-in account. This operation can only be performed
  * after a successful login operation has been completed. Not all servers support changing
  * passwords; an XMPPException will be thrown when that is the case.
  *
  * @throws IllegalStateException if not currently logged-in to the server.
  * @throws XMPPException if an error occurs when changing the password.
  */
 public void changePassword(String newPassword) throws XMPPException {
   Registration reg = new Registration();
   reg.setType(IQ.Type.SET);
   reg.setTo(connection.getServiceName());
   Map<String, String> map = new HashMap<String, String>();
   map.put("username", StringUtils.parseName(connection.getUser()));
   map.put("password", newPassword);
   reg.setAttributes(map);
   PacketFilter filter =
       new AndFilter(new PacketIDFilter(reg.getPacketID()), new PacketTypeFilter(IQ.class));
   PacketCollector collector = connection.createPacketCollector(filter);
   connection.sendPacket(reg);
   IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
   // Stop queuing results
   collector.cancel();
   if (result == null) {
     throw new XMPPException("No response from server.");
   } else if (result.getType() == IQ.Type.ERROR) {
     throw new XMPPException(result.getError());
   }
 }
Example #16
0
  /**
   * Returns the transcripts of a given user. The answer will contain the complete history of
   * conversations that a user had.
   *
   * @param userID the id of the user to get his conversations.
   * @param workgroupJID the JID of the workgroup that will process the request.
   * @return the transcripts of a given user.
   * @throws XMPPException if an error occurs while getting the information.
   */
  public Transcripts getTranscripts(String workgroupJID, String userID) throws XMPPException {
    Transcripts request = new Transcripts(userID);
    request.setTo(workgroupJID);
    PacketCollector collector =
        connection.createPacketCollector(new PacketIDFilter(request.getPacketID()));
    // Send the request
    connection.sendPacket(request);

    Transcripts response =
        (Transcripts) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());

    // Cancel the collector.
    collector.cancel();
    if (response == null) {
      throw new XMPPException("No response from server on status set.");
    }
    if (response.getError() != null) {
      throw new XMPPException(response.getError());
    }
    return response;
  }
Example #17
0
 /**
  * Creates a new account using the specified username, password and account attributes. The
  * attributes Map must contain only String name/value pairs and must also have values for all
  * required attributes.
  *
  * @param username the username.
  * @param password the password.
  * @param attributes the account attributes.
  * @throws XMPPException if an error occurs creating the account.
  * @see #getAccountAttributes()
  */
 public void createAccount(String username, String password, Map<String, String> attributes)
     throws XMPPException {
   if (!supportsAccountCreation()) {
     throw new XMPPException("Server does not support account creation.");
   }
   Registration reg = new Registration();
   reg.setType(IQ.Type.SET);
   reg.setTo(connection.getServiceName());
   attributes.put("username", username);
   attributes.put("password", password);
   reg.setAttributes(attributes);
   PacketFilter filter =
       new AndFilter(new PacketIDFilter(reg.getPacketID()), new PacketTypeFilter(IQ.class));
   PacketCollector collector = connection.createPacketCollector(filter);
   connection.sendPacket(reg);
   IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
   // Stop queuing results
   collector.cancel();
   if (result == null) {
     throw new XMPPException("No response from server.");
   } else if (result.getType() == IQ.Type.ERROR) {
     throw new XMPPException(result.getError());
   }
 }
Example #18
0
 /**
  * Deletes the currently logged-in account from the server. This operation can only be performed
  * after a successful login operation has been completed. Not all servers support deleting
  * accounts; an XMPPException will be thrown when that is the case.
  *
  * @throws IllegalStateException if not currently logged-in to the server.
  * @throws XMPPException if an error occurs when deleting the account.
  */
 public void deleteAccount() throws XMPPException {
   if (!connection.isAuthenticated()) {
     throw new IllegalStateException("Must be logged in to delete a account.");
   }
   Registration reg = new Registration();
   reg.setType(IQ.Type.SET);
   reg.setTo(connection.getServiceName());
   Map<String, String> attributes = new HashMap<String, String>();
   // To delete an account, we add a single attribute, "remove", that is blank.
   attributes.put("remove", "");
   reg.setAttributes(attributes);
   PacketFilter filter =
       new AndFilter(new PacketIDFilter(reg.getPacketID()), new PacketTypeFilter(IQ.class));
   PacketCollector collector = connection.createPacketCollector(filter);
   connection.sendPacket(reg);
   IQ result = (IQ) collector.nextResult(SmackConfiguration.getPacketReplyTimeout());
   // Stop queuing results
   collector.cancel();
   if (result == null) {
     throw new XMPPException("No response from server.");
   } else if (result.getType() == IQ.Type.ERROR) {
     throw new XMPPException(result.getError());
   }
 }
Example #19
0
  public void send(String destination, String text) {
    Message response = new Message(destination, Message.Type.chat);
    response.setBody("*" + text);

    connection.sendPacket(response);
  }
Example #20
0
  /**
   * Process the AdHoc-Command packet that request the execution of some action of a command. If
   * this is the first request, this method checks, before executing the command, if:
   *
   * <ul>
   *   <li>The requested command exists
   *   <li>The requester has permissions to execute it
   *   <li>The command has more than one stage, if so, it saves the command and session ID for
   *       further use
   * </ul>
   *
   * <br>
   * <br>
   * If this is not the first request, this method checks, before executing the command, if:
   *
   * <ul>
   *   <li>The session ID of the request was stored
   *   <li>The session life do not exceed the time out
   *   <li>The action to execute is one of the available actions
   * </ul>
   *
   * @param requestData the packet to process.
   */
  private void processAdHocCommand(AdHocCommandData requestData) {
    // Only process requests of type SET
    if (requestData.getType() != IQ.Type.SET) {
      return;
    }

    // Creates the response with the corresponding data
    AdHocCommandData response = new AdHocCommandData();
    response.setTo(requestData.getFrom());
    response.setPacketID(requestData.getPacketID());
    response.setNode(requestData.getNode());
    response.setId(requestData.getTo());

    String sessionId = requestData.getSessionID();
    String commandNode = requestData.getNode();

    if (sessionId == null) {
      // A new execution request has been received. Check that the
      // command exists
      if (!commands.containsKey(commandNode)) {
        // Requested command does not exist so return
        // item_not_found error.
        respondError(response, XMPPError.Condition.item_not_found);
        return;
      }

      // Create new session ID
      sessionId = StringUtils.randomString(15);

      try {
        // Create a new instance of the command with the
        // corresponding sessioid
        LocalCommand command = newInstanceOfCmd(commandNode, sessionId);

        response.setType(IQ.Type.RESULT);
        command.setData(response);

        // Check that the requester has enough permission.
        // Answer forbidden error if requester permissions are not
        // enough to execute the requested command
        if (!command.hasPermission(requestData.getFrom())) {
          respondError(response, XMPPError.Condition.forbidden);
          return;
        }

        Action action = requestData.getAction();

        // If the action is unknown then respond an error.
        if (action != null && action.equals(Action.unknown)) {
          respondError(
              response,
              XMPPError.Condition.bad_request,
              AdHocCommand.SpecificErrorCondition.malformedAction);
          return;
        }

        // If the action is not execute, then it is an invalid action.
        if (action != null && !action.equals(Action.execute)) {
          respondError(
              response,
              XMPPError.Condition.bad_request,
              AdHocCommand.SpecificErrorCondition.badAction);
          return;
        }

        // Increase the state number, so the command knows in witch
        // stage it is
        command.incrementStage();
        // Executes the command
        command.execute();

        if (command.isLastStage()) {
          // If there is only one stage then the command is completed
          response.setStatus(Status.completed);
        } else {
          // Else it is still executing, and is registered to be
          // available for the next call
          response.setStatus(Status.executing);
          executingCommands.put(sessionId, command);
          // See if the session reaping thread is started. If not, start it.
          if (!sessionsSweeper.isAlive()) {
            sessionsSweeper.start();
          }
        }

        // Sends the response packet
        connection.sendPacket(response);

      } catch (XMPPException e) {
        // If there is an exception caused by the next, complete,
        // prev or cancel method, then that error is returned to the
        // requester.
        XMPPError error = e.getXMPPError();

        // If the error type is cancel, then the execution is
        // canceled therefore the status must show that, and the
        // command be removed from the executing list.
        if (XMPPError.Type.CANCEL.equals(error.getType())) {
          response.setStatus(Status.canceled);
          executingCommands.remove(sessionId);
        }
        respondError(response, error);
        e.printStackTrace();
      }
    } else {
      LocalCommand command = executingCommands.get(sessionId);

      // Check that a command exists for the specified sessionID
      // This also handles if the command was removed in the meanwhile
      // of getting the key and the value of the map.
      if (command == null) {
        respondError(
            response,
            XMPPError.Condition.bad_request,
            AdHocCommand.SpecificErrorCondition.badSessionid);
        return;
      }

      // Check if the Session data has expired (default is 10 minutes)
      long creationStamp = command.getCreationDate();
      if (System.currentTimeMillis() - creationStamp > SESSION_TIMEOUT * 1000) {
        // Remove the expired session
        executingCommands.remove(sessionId);

        // Answer a not_allowed error (session-expired)
        respondError(
            response,
            XMPPError.Condition.not_allowed,
            AdHocCommand.SpecificErrorCondition.sessionExpired);
        return;
      }

      /*
       * Since the requester could send two requests for the same
       * executing command i.e. the same session id, all the execution of
       * the action must be synchronized to avoid inconsistencies.
       */
      synchronized (command) {
        Action action = requestData.getAction();

        // If the action is unknown the respond an error
        if (action != null && action.equals(Action.unknown)) {
          respondError(
              response,
              XMPPError.Condition.bad_request,
              AdHocCommand.SpecificErrorCondition.malformedAction);
          return;
        }

        // If the user didn't specify an action or specify the execute
        // action then follow the actual default execute action
        if (action == null || Action.execute.equals(action)) {
          action = command.getExecuteAction();
        }

        // Check that the specified action was previously
        // offered
        if (!command.isValidAction(action)) {
          respondError(
              response,
              XMPPError.Condition.bad_request,
              AdHocCommand.SpecificErrorCondition.badAction);
          return;
        }

        try {
          // TODO: Check that all the requierd fields of the form are
          // TODO: filled, if not throw an exception. This will simplify the
          // TODO: construction of new commands

          // Since all errors were passed, the response is now a
          // result
          response.setType(IQ.Type.RESULT);

          // Set the new data to the command.
          command.setData(response);

          if (Action.next.equals(action)) {
            command.incrementStage();
            command.next(new Form(requestData.getForm()));
            if (command.isLastStage()) {
              // If it is the last stage then the command is
              // completed
              response.setStatus(Status.completed);
            } else {
              // Otherwise it is still executing
              response.setStatus(Status.executing);
            }
          } else if (Action.complete.equals(action)) {
            command.incrementStage();
            command.complete(new Form(requestData.getForm()));
            response.setStatus(Status.completed);
            // Remove the completed session
            executingCommands.remove(sessionId);
          } else if (Action.prev.equals(action)) {
            command.decrementStage();
            command.prev();
          } else if (Action.cancel.equals(action)) {
            command.cancel();
            response.setStatus(Status.canceled);
            // Remove the canceled session
            executingCommands.remove(sessionId);
          }

          connection.sendPacket(response);
        } catch (XMPPException e) {
          // If there is an exception caused by the next, complete,
          // prev or cancel method, then that error is returned to the
          // requester.
          XMPPError error = e.getXMPPError();

          // If the error type is cancel, then the execution is
          // canceled therefore the status must show that, and the
          // command be removed from the executing list.
          if (XMPPError.Type.CANCEL.equals(error.getType())) {
            response.setStatus(Status.canceled);
            executingCommands.remove(sessionId);
          }
          respondError(response, error);

          e.printStackTrace();
        }
      }
    }
  }
 /**
  * Reject a stream initiation request from a remote user.
  *
  * @param si The Stream Initiation request to reject.
  */
 public void rejectStream(final StreamInitiation si) {
   final XMPPError error = new XMPPError(XMPPError.Condition.forbidden, "Offer Declined");
   final IQ iqPacket = createIQ(si.getPacketID(), si.getFrom(), si.getTo(), IQ.Type.ERROR);
   iqPacket.setError(error);
   connection.sendPacket(iqPacket);
 }
Example #22
0
 /**
  * Responds an error with an specific error.
  *
  * @param response the response to send.
  * @param error the error to send.
  */
 private void respondError(AdHocCommandData response, XMPPError error) {
   response.setType(IQ.Type.ERROR);
   response.setError(error);
   connection.sendPacket(response);
 }
  /**
   * Parses an IQ packet.
   *
   * @param parser the XML parser, positioned at the start of an IQ packet.
   * @return an IQ object.
   * @throws Exception if an exception occurs while parsing the packet.
   */
  public static IQ parseIQ(XmlPullParser parser, Connection connection) throws Exception {
    IQ iqPacket = null;

    String id = parser.getAttributeValue("", "id");
    String to = parser.getAttributeValue("", "to");
    String from = parser.getAttributeValue("", "from");
    IQ.Type type = IQ.Type.fromString(parser.getAttributeValue("", "type"));
    XMPPError error = null;

    boolean done = false;
    while (!done) {
      int eventType = parser.next();

      if (eventType == XmlPullParser.START_TAG) {
        String elementName = parser.getName();
        String namespace = parser.getNamespace();
        if (elementName.equals("error")) {
          error = PacketParserUtils.parseError(parser);
        } else if (elementName.equals("query") && namespace.equals("jabber:iq:auth")) {
          iqPacket = parseAuthentication(parser);
        } else if (elementName.equals("query") && namespace.equals("jabber:iq:roster")) {
          iqPacket = parseRoster(parser);
        } else if (elementName.equals("query") && namespace.equals("jabber:iq:register")) {
          iqPacket = parseRegistration(parser);
        } else if (elementName.equals("bind")
            && namespace.equals("urn:ietf:params:xml:ns:xmpp-bind")) {
          iqPacket = parseResourceBinding(parser);
        }
        // Otherwise, see if there is a registered provider for
        // this element name and namespace.
        else {
          Object provider = ProviderManager.getInstance().getIQProvider(elementName, namespace);
          if (provider != null) {
            if (provider instanceof IQProvider) {
              iqPacket = ((IQProvider) provider).parseIQ(parser);
            } else if (provider instanceof Class) {
              iqPacket =
                  (IQ)
                      PacketParserUtils.parseWithIntrospection(
                          elementName, (Class<?>) provider, parser);
            }
          }
          // Only handle unknown IQs of type result. Types of 'get' and 'set' which are not
          // understood
          // have to be answered with an IQ error response. See the code a few lines below
          else if (IQ.Type.RESULT == type) {
            // No Provider found for the IQ stanza, parse it to an UnparsedIQ instance
            // so that the content of the IQ can be examined later on
            iqPacket = new UnparsedResultIQ(parseContent(parser));
          }
        }
      } else if (eventType == XmlPullParser.END_TAG) {
        if (parser.getName().equals("iq")) {
          done = true;
        }
      }
    }
    // Decide what to do when an IQ packet was not understood
    if (iqPacket == null) {
      if (IQ.Type.GET == type || IQ.Type.SET == type) {
        // If the IQ stanza is of type "get" or "set" containing a child element
        // qualified by a namespace it does not understand, then answer an IQ of
        // type "error" with code 501 ("feature-not-implemented")
        iqPacket =
            new IQ() {
              @Override
              public String getChildElementXML() {
                return null;
              }
            };
        iqPacket.setPacketID(id);
        iqPacket.setTo(from);
        iqPacket.setFrom(to);
        iqPacket.setType(IQ.Type.ERROR);
        iqPacket.setError(new XMPPError(XMPPError.Condition.feature_not_implemented));
        connection.sendPacket(iqPacket);
        return null;
      } else {
        // If an IQ packet wasn't created above, create an empty IQ packet.
        iqPacket =
            new IQ() {
              @Override
              public String getChildElementXML() {
                return null;
              }
            };
      }
    }

    // Set basic values on the iq packet.
    iqPacket.setPacketID(id);
    iqPacket.setTo(to);
    iqPacket.setFrom(from);
    iqPacket.setType(type);
    iqPacket.setError(error);

    return iqPacket;
  }
 /**
  * Responses to the given IQ packet's sender with an XMPP error that an In-Band Bytestream open
  * request is rejected because its block size is greater than the maximum allowed block size.
  *
  * @param request IQ packet that should be answered with a resource-constraint error
  */
 protected void replyResourceConstraintPacket(IQ request) {
   final XMPPError xmppError = new XMPPError(XMPPError.Condition.resource_constraint);
   final IQ error = IQ.createErrorResponse(request, xmppError);
   connection.sendPacket(error);
 }
 /**
  * Responses to the given IQ packet's sender with an XMPP error that an In-Band Bytestream is not
  * accepted.
  *
  * @param request IQ packet that should be answered with a not-acceptable error
  */
 protected void replyRejectPacket(IQ request) {
   final XMPPError xmppError = new XMPPError(XMPPError.Condition.no_acceptable);
   final IQ error = IQ.createErrorResponse(request, xmppError);
   connection.sendPacket(error);
 }
 /**
  * Responses to the given IQ packet's sender with an XMPP error that an In-Band Bytestream session
  * could not be found.
  *
  * @param request IQ packet that should be answered with a item-not-found error
  */
 protected void replyItemNotFoundPacket(IQ request) {
   final XMPPError xmppError = new XMPPError(XMPPError.Condition.item_not_found);
   final IQ error = IQ.createErrorResponse(request, xmppError);
   connection.sendPacket(error);
 }