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); } }
/** @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); }