private void readContinuationRequest(ImapResponseCallback callback) throws IOException {
    parseCommandContinuationRequest();
    response = ImapResponse.newContinuationRequest(callback);

    skipIfSpace();
    String rest = readStringUntilEndOfLine();
    response.add(rest);
  }
 private void parseListResponse(ImapResponse response) throws IOException {
   expect(' ');
   parseList(response, '(', ')');
   expect(' ');
   // TODO: Add support for NIL
   String delimiter = parseQuoted();
   response.add(delimiter);
   expect(' ');
   String name = parseString();
   response.add(name);
   expect('\r');
   expect('\n');
 }
  /**
   * A "{" has been read. Read the rest of the size string, the space and then notify the callback
   * with an {@code InputStream}.
   */
  private Object parseLiteral() throws IOException {
    expect('{');
    int size = Integer.parseInt(readStringUntil('}'));
    expect('\r');
    expect('\n');

    if (size == 0) {
      return "";
    }

    if (response.getCallback() != null) {
      FixedLengthInputStream fixed = new FixedLengthInputStream(inputStream, size);

      Object result = null;
      try {
        result = response.getCallback().foundLiteral(response, fixed);
      } catch (IOException e) {
        // Pass IOExceptions through
        throw e;
      } catch (Exception e) {
        // Catch everything else and save it for later.
        exception = e;
      }

      // Check if only some of the literal data was read
      int available = fixed.available();
      if (available > 0 && available != size) {
        // If so, skip the rest
        while (fixed.available() > 0) {
          fixed.skip(fixed.available());
        }
      }

      if (result != null) {
        return result;
      }
    }

    byte[] data = new byte[size];
    int read = 0;
    while (read != size) {
      int count = inputStream.read(data, read, size - read);
      if (count == -1) {
        throw new IOException("parseLiteral(): end of stream reached");
      }
      read += count;
    }

    return new String(data, "US-ASCII");
  }
  /** @see CommandTemplate#doProcess */
  protected void doProcess(
      ImapRequestLineReader request, ImapResponse response, ImapSession session)
      throws ProtocolException, FolderException, AuthorizationException {
    String mailboxName = parser.mailbox(request);
    parser.endLine(request);

    session.getHost().createMailbox(session.getUser(), mailboxName);
    session.unsolicitedResponses(response);
    response.commandComplete(this);
  }
  /**
   * Reads the next response available on the stream and returns an {@link ImapResponse} object that
   * represents it.
   *
   * <p>When this method successfully returns an {@link ImapResponse}, the {@link ImapResponse} is
   * stored in the internal storage. When the {@link ImapResponse} is no longer used {@link
   * #destroyResponses} should be called to destroy all the responses in the array.
   *
   * @return the parsed {@link ImapResponse} object.
   * @exception ByeException when detects BYE.
   */
  public ImapResponse readResponse() throws IOException, MessagingException {
    ImapResponse response = null;
    try {
      response = parseResponse();
      if (Email.DEBUG) {
        Log.d(Logging.LOG_TAG, "<<< " + response.toString());
      }

    } catch (RuntimeException e) {
      // Parser crash -- log network activities.
      onParseError(e);
      throw e;
    } catch (IOException e) {
      // Network error, or received an unexpected char.
      onParseError(e);
      throw e;
    } finally {
      synchronized (MailService.sSynchronizeLock) {
        if (MailService.sWakeLock != null) {
          if (!MailService.sWakeLock.isHeld()) {
            MailService.sWakeLock.acquire();
            Log.d("Email-MailService", "ImapResponse readResponse MailService.sWakeLock.acquire");
          }
        }
      }
    }

    // Handle this outside of try-catch.  We don't have to dump protocol log when getting BYE.
    if (response.is(0, ImapConstants.BYE)) {
      Log.w(Logging.LOG_TAG, ByeException.MESSAGE);
      response.destroy();
      throw new ByeException();
    }
    mResponsesToDestroy.add(response);
    return response;
  }
  private void readTokens(ImapResponse response) throws IOException {
    response.clear();

    Object firstToken = readToken(response);

    checkTokenIsString(firstToken);
    String symbol = (String) firstToken;

    response.add(symbol);

    if (isStatusResponse(symbol)) {
      parseResponseText(response);
    } else if (equalsIgnoreCase(symbol, Responses.LIST)
        || equalsIgnoreCase(symbol, Responses.LSUB)) {
      parseListResponse(response);
    } else {
      Object token;
      while ((token = readToken(response)) != null) {
        if (!(token instanceof ImapList)) {
          response.add(token);
        }
      }
    }
  }
  /**
   * Parse {@code resp-text} tokens
   *
   * <p>Responses "OK", "PREAUTH", "BYE", "NO", "BAD", and continuation request responses can
   * contain {@code resp-text} tokens. We parse the {@code resp-text-code} part as tokens and read
   * the rest as sequence of characters to avoid the parser interpreting things like "{123}" as
   * start of a literal.
   *
   * <p>Example:
   *
   * <p>{@code * OK [UIDVALIDITY 3857529045] UIDs valid}
   *
   * <p>See RFC 3501, Section 9 Formal Syntax (resp-text)
   *
   * @param parent The {@link ImapResponse} instance that holds the parsed tokens of the response.
   * @throws IOException If there's a network error.
   * @see #isStatusResponse(String)
   */
  private void parseResponseText(ImapResponse parent) throws IOException {
    skipIfSpace();

    int next = inputStream.peek();
    if (next == '[') {
      parseList(parent, '[', ']');
      skipIfSpace();
    }

    String rest = readStringUntilEndOfLine();

    if (rest != null && !rest.isEmpty()) {
      // The rest is free-form text.
      parent.add(rest);
    }
  }
Exemple #8
0
  /** @see CommandTemplate#doProcess */
  protected void doProcess(
      ImapRequestLineReader request, ImapResponse response, ImapSession session)
      throws ProtocolException, FolderException, AuthorizationException {

    String mailboxName = parser.mailbox(request);
    parser.endLine(request);

    MailFolder folder = getMailbox(mailboxName, session, true);
    if (session.getSelected() != null
        && folder.getFullName().equals(session.getSelected().getFullName())) {
      session.deselect();
    }
    session.getHost().deleteMailbox(session.getUser(), mailboxName);

    session.unsolicitedResponses(response);
    response.commandComplete(this);
  }
  /** Parse and return the response line. */
  private ImapResponse parseResponse() throws IOException, MessagingException {
    // We need to destroy the response if we get an exception.
    // So, we first store the response that's being built in responseToDestroy, until it's
    // completely built, at which point we copy it into responseToReturn and null out
    // responseToDestroyt.
    // If responseToDestroy is not null in finally, we destroy it because that means
    // we got an exception somewhere.
    ImapResponse responseToDestroy = null;
    final ImapResponse responseToReturn;

    try {
      final int ch = peek();
      if (ch == '+') { // Continuation request
        readByte(); // skip +
        expect(' ');
        responseToDestroy = new ImapResponse(null, true);

        // If it's continuation request, we don't really care what's in it.
        responseToDestroy.add(new ImapSimpleString(readUntilEol()));

        // Response has successfully been built.  Let's return it.
        responseToReturn = responseToDestroy;
        responseToDestroy = null;
      } else {
        // Status response or response data
        final String tag;
        if (ch == '*') {
          tag = null;
          readByte(); // skip *
          expect(' ');
        } else {
          tag = readUntil(' ');
        }
        responseToDestroy = new ImapResponse(tag, false);

        final ImapString firstString = parseBareString();
        responseToDestroy.add(firstString);

        // parseBareString won't eat a space after the string, so we need to skip it,
        // if exists.
        // If the next char is not ' ', it should be EOL.
        if (peek() == ' ') {
          readByte(); // skip ' '

          if (responseToDestroy.isStatusResponse()) { // It's a status response

            // Is there a response code?
            final int next = peek();
            if (next == '[') {
              responseToDestroy.add(parseList('[', ']'));
              if (peek() == ' ') { // Skip following space
                readByte();
              }
            }

            String rest = readUntilEol();
            if (!TextUtils.isEmpty(rest)) {
              // The rest is free-form text.
              responseToDestroy.add(new ImapSimpleString(rest));
            }
          } else { // It's a response data.
            parseElements(responseToDestroy, '\0');
          }
        } else {
          expect('\r');
          expect('\n');
        }

        // Response has successfully been built.  Let's return it.
        responseToReturn = responseToDestroy;
        responseToDestroy = null;
      }
    } finally {
      if (responseToDestroy != null) {
        // We get an exception.
        responseToDestroy.destroy();
      }
    }

    return responseToReturn;
  }
 /**
  * Destroy all the {@link ImapResponse}s stored in the internal storage and clear it.
  *
  * @see #readResponse()
  */
 public void destroyResponses() {
   for (ImapResponse r : mResponsesToDestroy) {
     r.destroy();
   }
   mResponsesToDestroy.clear();
 }
  List<ImapResponse> readStatusResponse(
      String tag, String commandToLog, String logId, UntaggedHandler untaggedHandler)
      throws IOException, NegativeImapResponseException {

    List<ImapResponse> responses = new ArrayList<ImapResponse>();

    ImapResponse response;
    do {
      response = readResponse();

      if (K9MailLib.isDebug() && DEBUG_PROTOCOL_IMAP) {
        Log.v(LOG_TAG, logId + "<<<" + response);
      }

      if (response.getTag() != null && !response.getTag().equalsIgnoreCase(tag)) {
        Log.w(
            LOG_TAG,
            "After sending tag "
                + tag
                + ", got tag response from previous command "
                + response
                + " for "
                + logId);

        Iterator<ImapResponse> responseIterator = responses.iterator();

        while (responseIterator.hasNext()) {
          ImapResponse delResponse = responseIterator.next();
          if (delResponse.getTag() != null
              || delResponse.size() < 2
              || (!equalsIgnoreCase(delResponse.get(1), Responses.EXISTS)
                  && !equalsIgnoreCase(delResponse.get(1), Responses.EXPUNGE))) {
            responseIterator.remove();
          }
        }
        response = null;
        continue;
      }

      if (untaggedHandler != null) {
        untaggedHandler.handleAsyncUntaggedResponse(response);
      }

      responses.add(response);
    } while (response == null || response.getTag() == null);

    if (response.size() < 1 || !equalsIgnoreCase(response.get(0), Responses.OK)) {
      throw new NegativeImapResponseException(
          "Command: " + commandToLog + "; response: " + response.toString(),
          response.getAlertText());
    }

    return responses;
  }
  private void readTaggedResponse(ImapResponseCallback callback) throws IOException {
    String tag = parseTaggedResponse();
    response = ImapResponse.newTaggedResponse(callback, tag);

    readTokens(response);
  }
  private void readUntaggedResponse(ImapResponseCallback callback) throws IOException {
    parseUntaggedResponse();
    response = ImapResponse.newUntaggedResponse(callback);

    readTokens(response);
  }