/**
   * Returns an Iterator with the offline <tt>Messages</tt> whose stamp matches the specified
   * request. The request will include the list of stamps that uniquely identifies the offline
   * messages to retrieve. The returned offline messages will not be deleted from the server. Use
   * {@link #deleteMessages(java.util.List)} to delete the messages.
   *
   * @param nodes the list of stamps that uniquely identifies offline message.
   * @return an Iterator with the offline <tt>Messages</tt> that were received as part of this
   *     request.
   * @throws XMPPException If the user is not allowed to make this request or the server does not
   *     support offline message retrieval.
   */
  public Iterator getMessages(final List nodes) throws XMPPException {
    List messages = new ArrayList();
    OfflineMessageRequest request = new OfflineMessageRequest();
    for (Iterator it = nodes.iterator(); it.hasNext(); ) {
      OfflineMessageRequest.Item item = new OfflineMessageRequest.Item((String) it.next());
      item.setAction("view");
      request.addItem(item);
    }
    // Filter packets looking for an answer from the server.
    PacketFilter responseFilter = new PacketIDFilter(request.getPacketID());
    PacketCollector response = connection.createPacketCollector(responseFilter);
    // Filter offline messages that were requested by this request
    PacketFilter messageFilter =
        new AndFilter(
            packetFilter,
            new PacketFilter() {
              public boolean accept(Packet packet) {
                OfflineMessageInfo info =
                    (OfflineMessageInfo) packet.getExtension("offline", namespace);
                return nodes.contains(info.getNode());
              }
            });
    PacketCollector messageCollector = connection.createPacketCollector(messageFilter);
    // Send the retrieval request to the server.
    connection.sendPacket(request);
    // Wait up to a certain number of seconds for a reply.
    IQ answer = (IQ) response.nextResult(SmackConfiguration.getPacketReplyTimeout());
    // Stop queuing results
    response.cancel();

    if (answer == null) {
      throw new XMPPException("No response from server.");
    } else if (answer.getError() != null) {
      throw new XMPPException(answer.getError());
    }

    // Collect the received offline messages
    Message message =
        (Message) messageCollector.nextResult(SmackConfiguration.getPacketReplyTimeout());
    while (message != null) {
      messages.add(message);
      message = (Message) messageCollector.nextResult(SmackConfiguration.getPacketReplyTimeout());
    }
    // Stop queuing offline messages
    messageCollector.cancel();
    return messages.iterator();
  }
  /**
   * Deletes the specified list of offline messages. The request will include the list of stamps
   * that uniquely identifies the offline messages to delete.
   *
   * @param nodes the list of stamps that uniquely identifies offline message.
   * @throws XMPPException If the user is not allowed to make this request or the server does not
   *     support offline message retrieval.
   */
  public void deleteMessages(List nodes) throws XMPPException {
    OfflineMessageRequest request = new OfflineMessageRequest();
    for (Iterator it = nodes.iterator(); it.hasNext(); ) {
      OfflineMessageRequest.Item item = new OfflineMessageRequest.Item((String) it.next());
      item.setAction("remove");
      request.addItem(item);
    }
    // Filter packets looking for an answer from the server.
    PacketFilter responseFilter = new PacketIDFilter(request.getPacketID());
    PacketCollector response = connection.createPacketCollector(responseFilter);
    // Send the deletion request to the server.
    connection.sendPacket(request);
    // Wait up to a certain number of seconds for a reply.
    IQ answer = (IQ) response.nextResult(SmackConfiguration.getPacketReplyTimeout());
    // Stop queuing results
    response.cancel();

    if (answer == null) {
      throw new XMPPException("No response from server.");
    } else if (answer.getError() != null) {
      throw new XMPPException(answer.getError());
    }
  }