private String executeSimpleCommand(String command, boolean sensitive) throws MessagingException { try { open(Folder.OPEN_MODE_RW); if (command != null) { if (K9MailLib.isDebug() && DEBUG_PROTOCOL_POP3) { if (sensitive && !K9MailLib.isDebugSensitive()) { Log.d(LOG_TAG, ">>> " + "[Command Hidden, Enable Sensitive Debug Logging To Show]"); } else { Log.d(LOG_TAG, ">>> " + command); } } writeLine(command); } String response = readLine(); if (response.length() == 0 || response.charAt(0) != '+') { throw new Pop3ErrorResponse(response); } return response; } catch (MessagingException me) { throw me; } catch (Exception e) { closeIO(); throw new MessagingException("Unable to execute POP3 command", e); } }
private void indexMessage(int msgNum, Pop3Message message) { if (K9MailLib.isDebug() && DEBUG_PROTOCOL_POP3) { Log.d(LOG_TAG, "Adding index for UID " + message.getUid() + " to msgNum " + msgNum); } mMsgNumToMsgMap.put(msgNum, message); mUidToMsgMap.put(message.getUid(), message); mUidToMsgNumMap.put(message.getUid(), msgNum); }
private void indexUids(List<String> uids) throws MessagingException, IOException { Set<String> unindexedUids = new HashSet<String>(); for (String uid : uids) { if (mUidToMsgMap.get(uid) == null) { if (K9MailLib.isDebug() && DEBUG_PROTOCOL_POP3) { Log.d(LOG_TAG, "Need to index UID " + uid); } unindexedUids.add(uid); } } if (unindexedUids.isEmpty()) { return; } /* * If we are missing uids in the cache the only sure way to * get them is to do a full UIDL list. A possible optimization * would be trying UIDL for the latest X messages and praying. */ String response = executeSimpleCommand(UIDL_COMMAND); while ((response = readLine()) != null) { if (response.equals(".")) { break; } String[] uidParts = response.split(" +"); // Ignore messages without a unique-id if (uidParts.length >= 2) { Integer msgNum = Integer.valueOf(uidParts[0]); String msgUid = uidParts[1]; if (unindexedUids.contains(msgUid)) { if (K9MailLib.isDebug() && DEBUG_PROTOCOL_POP3) { Log.d(LOG_TAG, "Got msgNum " + msgNum + " for UID " + msgUid); } Pop3Message message = mUidToMsgMap.get(msgUid); if (message == null) { message = new Pop3Message(msgUid, this); } indexMessage(msgNum, message); } } } }
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 String readLine() throws IOException { StringBuilder sb = new StringBuilder(); int d = mIn.read(); if (d == -1) { throw new IOException("End of stream reached while trying to read line."); } do { if (((char) d) == '\r') { continue; } else if (((char) d) == '\n') { break; } else { sb.append((char) d); } } while ((d = mIn.read()) != -1); String ret = sb.toString(); if (K9MailLib.isDebug() && DEBUG_PROTOCOL_POP3) { Log.d(LOG_TAG, "<<< " + ret); } return ret; }
private int getMessageCount(boolean read) throws MessagingException { String isRead; int messageCount = 0; Map<String, String> headers = new HashMap<String, String>(); String messageBody; if (read) { isRead = "True"; } else { isRead = "False"; } messageBody = store.getMessageCountXml(isRead); headers.put("Brief", "t"); DataSet dataset = store.processRequest(this.mFolderUrl, "SEARCH", messageBody, headers); if (dataset != null) { messageCount = dataset.getMessageCount(); } if (K9MailLib.isDebug() && DEBUG_PROTOCOL_WEBDAV) { Log.v(LOG_TAG, "Counted messages and webdav returned: " + messageCount); } return messageCount; }
void autoconfigureFolders(final ImapConnection connection) throws IOException, MessagingException { if (!connection.hasCapability(Capabilities.SPECIAL_USE)) { if (K9MailLib.isDebug()) { Log.d(LOG_TAG, "No detected folder auto-configuration methods."); } return; } if (K9MailLib.isDebug()) { Log.d(LOG_TAG, "Folder auto-configuration: Using RFC6154/SPECIAL-USE."); } String command = String.format( "LIST (SPECIAL-USE) \"\" %s", ImapUtility.encodeString(getCombinedPrefix() + "*")); List<ImapResponse> responses = connection.executeSimpleCommand(command); List<ListResponse> listResponses = ListResponse.parseList(responses); for (ListResponse listResponse : listResponses) { String decodedFolderName; try { decodedFolderName = folderNameCodec.decode(listResponse.getName()); } catch (CharacterCodingException e) { Log.w( LOG_TAG, "Folder name not correctly encoded with the UTF-7 variant " + "as defined by RFC 3501: " + listResponse.getName(), e); // We currently just skip folders with malformed names. continue; } if (pathDelimiter == null) { pathDelimiter = listResponse.getHierarchyDelimiter(); combinedPrefix = null; } if (listResponse.hasAttribute("\\Archive") || listResponse.hasAttribute("\\All")) { mStoreConfig.setArchiveFolderName(decodedFolderName); if (K9MailLib.isDebug()) { Log.d(LOG_TAG, "Folder auto-configuration detected Archive folder: " + decodedFolderName); } } else if (listResponse.hasAttribute("\\Drafts")) { mStoreConfig.setDraftsFolderName(decodedFolderName); if (K9MailLib.isDebug()) { Log.d(LOG_TAG, "Folder auto-configuration detected Drafts folder: " + decodedFolderName); } } else if (listResponse.hasAttribute("\\Sent")) { mStoreConfig.setSentFolderName(decodedFolderName); if (K9MailLib.isDebug()) { Log.d(LOG_TAG, "Folder auto-configuration detected Sent folder: " + decodedFolderName); } } else if (listResponse.hasAttribute("\\Junk")) { mStoreConfig.setSpamFolderName(decodedFolderName); if (K9MailLib.isDebug()) { Log.d(LOG_TAG, "Folder auto-configuration detected Spam folder: " + decodedFolderName); } } else if (listResponse.hasAttribute("\\Trash")) { mStoreConfig.setTrashFolderName(decodedFolderName); if (K9MailLib.isDebug()) { Log.d(LOG_TAG, "Folder auto-configuration detected Trash folder: " + decodedFolderName); } } } }
/** * Fetches the body of the given message, limiting the downloaded data to the specified number * of lines if possible. * * <p>If lines is -1 the entire message is fetched. This is implemented with RETR for lines = -1 * or TOP for any other value. If the server does not support TOP, RETR is used instead. */ private void fetchBody(Pop3Message message, int lines) throws IOException, MessagingException { String response = null; // Try hard to use the TOP command if we're not asked to download the whole message. if (lines != -1 && (!mTopNotSupported || mCapabilities.top)) { try { if (K9MailLib.isDebug() && DEBUG_PROTOCOL_POP3 && !mCapabilities.top) { Log.d( LOG_TAG, "This server doesn't support the CAPA command. " + "Checking to see if the TOP command is supported nevertheless."); } response = executeSimpleCommand( String.format( Locale.US, TOP_COMMAND + " %d %d", mUidToMsgNumMap.get(message.getUid()), lines)); // TOP command is supported. Remember this for the next time. mCapabilities.top = true; } catch (Pop3ErrorResponse e) { if (mCapabilities.top) { // The TOP command should be supported but something went wrong. throw e; } else { if (K9MailLib.isDebug() && DEBUG_PROTOCOL_POP3) { Log.d( LOG_TAG, "The server really doesn't support the TOP " + "command. Using RETR instead."); } // Don't try to use the TOP command again. mTopNotSupported = true; } } } if (response == null) { executeSimpleCommand( String.format(Locale.US, RETR_COMMAND + " %d", mUidToMsgNumMap.get(message.getUid()))); } try { message.parse(new Pop3ResponseInputStream(mIn)); // TODO: if we've received fewer lines than requested we also have the complete message. if (lines == -1 || !mCapabilities.top) { message.setFlag(Flag.X_DOWNLOADED_FULL, true); } } catch (MessagingException me) { /* * If we're only downloading headers it's possible * we'll get a broken MIME message which we're not * real worried about. If we've downloaded the body * and can't parse it we need to let the user know. */ if (lines == -1) { throw me; } } }