1
0
mirror of https://github.com/moparisthebest/k-9 synced 2025-01-12 06:08:25 -05:00

Merge branch 'imap_parser'

This commit is contained in:
cketti 2011-11-16 04:52:05 +01:00
commit 4f060642ee
4 changed files with 150 additions and 28 deletions

View File

@ -916,8 +916,8 @@ public class AccountSettings extends K9PreferenceActivity {
} }
} }
allFolderValues = new String[folders.size()+1]; allFolderValues = new String[folders.size() + 1];
allFolderLabels = new String[folders.size()+1]; allFolderLabels = new String[folders.size() + 1];
allFolderValues[0] = K9.FOLDER_NONE; allFolderValues[0] = K9.FOLDER_NONE;
allFolderLabels[0] = K9.FOLDER_NONE; allFolderLabels[0] = K9.FOLDER_NONE;

View File

@ -1081,7 +1081,7 @@ public class MimeUtility {
*/ */
if (contentTransferEncoding != null) { if (contentTransferEncoding != null) {
contentTransferEncoding = contentTransferEncoding =
MimeUtility.getHeaderParameter(contentTransferEncoding, null); MimeUtility.getHeaderParameter(contentTransferEncoding, null);
if ("quoted-printable".equalsIgnoreCase(contentTransferEncoding)) { if ("quoted-printable".equalsIgnoreCase(contentTransferEncoding)) {
in = new QuotedPrintableInputStream(in); in = new QuotedPrintableInputStream(in);
} else if ("base64".equalsIgnoreCase(contentTransferEncoding)) { } else if ("base64".equalsIgnoreCase(contentTransferEncoding)) {
@ -1107,7 +1107,7 @@ public class MimeUtility {
* @throws MessagingException * @throws MessagingException
*/ */
public static void collectParts(Part part, ArrayList<Part> viewables, public static void collectParts(Part part, ArrayList<Part> viewables,
ArrayList<Part> attachments) throws MessagingException { ArrayList<Part> attachments) throws MessagingException {
/* /*
* If the part is Multipart but not alternative it's either mixed or * If the part is Multipart but not alternative it's either mixed or
* something we don't know about, which means we treat it as mixed * something we don't know about, which means we treat it as mixed
@ -1334,10 +1334,10 @@ public class MimeUtility {
private static String getJisVariantFromAddress(String address) { private static String getJisVariantFromAddress(String address) {
if (isInDomain(address, "docomo.ne.jp") || isInDomain(address, "dwmail.jp") || if (isInDomain(address, "docomo.ne.jp") || isInDomain(address, "dwmail.jp") ||
isInDomain(address, "pdx.ne.jp") || isInDomain(address, "willcom.com")) isInDomain(address, "pdx.ne.jp") || isInDomain(address, "willcom.com"))
return "docomo"; return "docomo";
else if (isInDomain(address, "softbank.ne.jp") || isInDomain(address, "vodafone.ne.jp") || else if (isInDomain(address, "softbank.ne.jp") || isInDomain(address, "vodafone.ne.jp") ||
isInDomain(address, "disney.ne.jp") || isInDomain(address, "vertuclub.ne.jp")) isInDomain(address, "disney.ne.jp") || isInDomain(address, "vertuclub.ne.jp"))
return "softbank"; return "softbank";
else if (isInDomain(address, "ezweb.ne.jp") || isInDomain(address, "ido.ne.jp")) else if (isInDomain(address, "ezweb.ne.jp") || isInDomain(address, "ido.ne.jp"))
return "kddi"; return "kddi";
@ -1372,14 +1372,14 @@ public class MimeUtility {
// iso-2022-jp variants are supported by no versions as of Dec 2010. // iso-2022-jp variants are supported by no versions as of Dec 2010.
if (charset.length() > 19 && charset.startsWith("x-") && if (charset.length() > 19 && charset.startsWith("x-") &&
charset.endsWith("-iso-2022-jp-2007") && !Charset.isSupported(charset)) { charset.endsWith("-iso-2022-jp-2007") && !Charset.isSupported(charset)) {
in = new Iso2022JpToShiftJisInputStream(in); in = new Iso2022JpToShiftJisInputStream(in);
charset = "x-" + charset.substring(2, charset.length() - 17) + "-shift_jis-2007"; charset = "x-" + charset.substring(2, charset.length() - 17) + "-shift_jis-2007";
} }
// shift_jis variants are supported by Eclair and later. // shift_jis variants are supported by Eclair and later.
if (charset.length() > 17 && charset.startsWith("x-") && if (charset.length() > 17 && charset.startsWith("x-") &&
charset.endsWith("-shift_jis-2007") && !Charset.isSupported(charset)) { charset.endsWith("-shift_jis-2007") && !Charset.isSupported(charset)) {
// If the JIS variant is iPhone, map the Unicode private use area in iPhone to the one in Android after // If the JIS variant is iPhone, map the Unicode private use area in iPhone to the one in Android after
// converting the character set from the standard Shift JIS to Unicode. // converting the character set from the standard Shift JIS to Unicode.
if (charset.substring(2, charset.length() - 15).equals("iphone")) if (charset.substring(2, charset.length() - 15).equals("iphone"))
@ -1400,7 +1400,7 @@ public class MimeUtility {
} }
if (!supported) { if (!supported) {
Log.e(K9.LOG_TAG, "I don't know how to deal with the charset " + charset + Log.e(K9.LOG_TAG, "I don't know how to deal with the charset " + charset +
". Falling back to US-ASCII"); ". Falling back to US-ASCII");
charset = "US-ASCII"; charset = "US-ASCII";
} }
/* /*
@ -2401,12 +2401,12 @@ public class MimeUtility {
public static void setCharset(String charset, Part part) throws MessagingException { public static void setCharset(String charset, Part part) throws MessagingException {
part.setHeader(MimeHeader.HEADER_CONTENT_TYPE, part.setHeader(MimeHeader.HEADER_CONTENT_TYPE,
part.getMimeType() + ";\n charset=" + getExternalCharset(charset)); part.getMimeType() + ";\n charset=" + getExternalCharset(charset));
} }
public static String getExternalCharset(String charset) { public static String getExternalCharset(String charset) {
if (charset.length() > 17 && charset.startsWith("x-") && if (charset.length() > 17 && charset.startsWith("x-") &&
charset.endsWith("-shift_jis-2007")) charset.endsWith("-shift_jis-2007"))
return "shift_jis"; return "shift_jis";
return charset; return charset;

View File

@ -1,5 +1,6 @@
package com.fsck.k9.mail.store; package com.fsck.k9.mail.store;
import android.text.TextUtils;
import com.fsck.k9.mail.MessagingException; import com.fsck.k9.mail.MessagingException;
import com.fsck.k9.mail.filter.FixedLengthInputStream; import com.fsck.k9.mail.filter.FixedLengthInputStream;
import com.fsck.k9.mail.filter.PeekableInputStream; import com.fsck.k9.mail.filter.PeekableInputStream;
@ -44,10 +45,8 @@ public class ImapResponseParser {
parseUntaggedResponse(); parseUntaggedResponse();
readTokens(response); readTokens(response);
} else if (ch == '+') { } else if (ch == '+') {
response.mCommandContinuationRequested = response.mCommandContinuationRequested = parseCommandContinuationRequest();
parseCommandContinuationRequest(); parseResponseText(response);
//TODO: Add special "resp-text" parsing
readTokens(response);
} else { } else {
response.mTag = parseTaggedResponse(); response.mTag = parseTaggedResponse();
readTokens(response); readTokens(response);
@ -67,24 +66,72 @@ public class ImapResponseParser {
private void readTokens(ImapResponse response) throws IOException { private void readTokens(ImapResponse response) throws IOException {
response.clear(); response.clear();
Object token;
while ((token = readToken(response)) != null) {
if (!(token instanceof ImapList)) {
response.add(token);
}
/* String firstToken = (String) readToken(response);
* TODO: Check for responses ("OK", "PREAUTH", "BYE", "NO", "BAD") response.add(firstToken);
* that can contain resp-text tokens. If found, hand over to a special
* method that parses a resp-text token. There's no need to use if (isStatusResponse(firstToken)) {
* readToken()/parseToken() on that data. parseResponseText(response);
* } else {
* See RFC 3501, Section 9 Formal Syntax (resp-text) Object token;
*/ while ((token = readToken(response)) != null) {
if (!(token instanceof ImapList)) {
response.add(token);
}
}
} }
response.mCompleted = true; response.mCompleted = true;
} }
/**
* 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>
* <p>Example:</p>
* <p>
* {@code * OK [UIDVALIDITY 3857529045] UIDs valid}
* </p>
* <p>
* See RFC 3501, Section 9 Formal Syntax (resp-text)
* </p>
*
* @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 = mIn.peek();
if (next == '[') {
parseSequence(parent);
skipIfSpace();
}
String rest = readStringUntil('\r');
expect('\n');
if (!TextUtils.isEmpty(rest)) {
// The rest is free-form text.
parent.add(rest);
}
}
private void skipIfSpace() throws IOException {
if (mIn.peek() == ' ') {
expect(' ');
}
}
/** /**
* Reads the next token of the response. The token can be one of: String - * Reads the next token of the response. The token can be one of: String -
* for NIL, QUOTED, NUMBER, ATOM. Object - for LITERAL. * for NIL, QUOTED, NUMBER, ATOM. Object - for LITERAL.
@ -480,6 +527,14 @@ public class ImapResponseParser {
} }
} }
public boolean isStatusResponse(String symbol) {
return symbol.equalsIgnoreCase("OK") ||
symbol.equalsIgnoreCase("NO") ||
symbol.equalsIgnoreCase("BAD") ||
symbol.equalsIgnoreCase("PREAUTH") ||
symbol.equalsIgnoreCase("BYE");
}
public static boolean equalsIgnoreCase(Object o1, Object o2) { public static boolean equalsIgnoreCase(Object o1, Object o2) {
if (o1 != null && o2 != null && o1 instanceof String && o2 instanceof String) { if (o1 != null && o2 != null && o1 instanceof String && o2 instanceof String) {
String s1 = (String)o1; String s1 = (String)o1;

View File

@ -0,0 +1,67 @@
package com.fsck.k9.mail.store;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import com.fsck.k9.mail.filter.PeekableInputStream;
import com.fsck.k9.mail.store.ImapResponseParser.ImapList;
import com.fsck.k9.mail.store.ImapResponseParser.ImapResponse;
import junit.framework.TestCase;
public class ImapResponseParserTest extends TestCase {
public void testSimpleOkResponse() throws IOException {
ImapResponseParser parser = createParser("* OK\r\n");
ImapResponse response = parser.readResponse();
assertNotNull(response);
assertEquals(1, response.size());
assertEquals("OK", response.get(0));
}
public void testOkResponseWithText() throws IOException {
ImapResponseParser parser = createParser("* OK Some text here\r\n");
ImapResponse response = parser.readResponse();
assertNotNull(response);
assertEquals(2, response.size());
assertEquals("OK", response.get(0));
assertEquals("Some text here", response.get(1));
}
public void testOkResponseWithRespTextCode() throws IOException {
ImapResponseParser parser = createParser("* OK [UIDVALIDITY 3857529045]\r\n");
ImapResponse response = parser.readResponse();
assertNotNull(response);
assertEquals(2, response.size());
assertEquals("OK", response.get(0));
assertTrue(response.get(1) instanceof ImapList);
ImapList respTextCode = (ImapList) response.get(1);
assertEquals(2, respTextCode.size());
assertEquals("UIDVALIDITY", respTextCode.get(0));
assertEquals("3857529045", respTextCode.get(1));
}
public void testOkResponseWithRespTextCodeAndText() throws IOException {
ImapResponseParser parser = createParser("* OK [token1 token2] {x} test [...]\r\n");
ImapResponse response = parser.readResponse();
assertNotNull(response);
assertEquals(3, response.size());
assertEquals("OK", response.get(0));
assertTrue(response.get(1) instanceof ImapList);
assertEquals("{x} test [...]", response.get(2));
ImapList respTextCode = (ImapList) response.get(1);
assertEquals(2, respTextCode.size());
assertEquals("token1", respTextCode.get(0));
assertEquals("token2", respTextCode.get(1));
}
private ImapResponseParser createParser(String response) {
ByteArrayInputStream in = new ByteArrayInputStream(response.getBytes());
PeekableInputStream pin = new PeekableInputStream(in);
return new ImapResponseParser(pin);
}
}