1ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hupackage com.android.exchange.service;
2ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
3ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.content.Context;
4ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.net.Uri;
5ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.os.Bundle;
6ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport android.util.Xml;
7ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
8ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport com.android.emailcommon.mail.MessagingException;
9ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport com.android.emailcommon.provider.Account;
10ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport com.android.emailcommon.provider.HostAuth;
11ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport com.android.emailcommon.service.EmailServiceProxy;
12ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport com.android.exchange.Eas;
13ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport com.android.exchange.EasResponse;
14ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport com.android.mail.utils.LogUtils;
15ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
16ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport org.apache.http.HttpStatus;
17ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport org.apache.http.client.methods.HttpPost;
18ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport org.apache.http.entity.StringEntity;
19ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport org.xmlpull.v1.XmlPullParser;
20ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport org.xmlpull.v1.XmlPullParserException;
21ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport org.xmlpull.v1.XmlPullParserFactory;
22ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport org.xmlpull.v1.XmlSerializer;
23ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
24ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport java.io.ByteArrayOutputStream;
25ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport java.io.IOException;
26ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Huimport java.net.URI;
27ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
28ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu/**
29ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * Performs Autodiscover for Exchange servers. This feature tries to find all the configuration
30ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu * options needed based on just a username and password.
31ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu */
32ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hupublic class EasAutoDiscover extends EasServerConnection {
33110837ebff288a75f9bda067c38e2c46797d99b5Alon Albert    private static final String TAG = Eas.LOG_TAG;
34ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
35ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private static final String AUTO_DISCOVER_SCHEMA_PREFIX =
36ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        "http://schemas.microsoft.com/exchange/autodiscover/mobilesync/";
37ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private static final String AUTO_DISCOVER_PAGE = "/autodiscover/autodiscover.xml";
38ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
39ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    // Set of string constants for parsing the autodiscover response.
40ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    // TODO: Merge this into Tags.java? It's not quite the same but conceptually belongs there.
41ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private static final String ELEMENT_NAME_SERVER = "Server";
42ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private static final String ELEMENT_NAME_TYPE = "Type";
43ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private static final String ELEMENT_NAME_MOBILE_SYNC = "MobileSync";
44ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private static final String ELEMENT_NAME_URL = "Url";
45ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private static final String ELEMENT_NAME_SETTINGS = "Settings";
46ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private static final String ELEMENT_NAME_ACTION = "Action";
47ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private static final String ELEMENT_NAME_ERROR = "Error";
48ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private static final String ELEMENT_NAME_REDIRECT = "Redirect";
49ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private static final String ELEMENT_NAME_USER = "User";
50ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private static final String ELEMENT_NAME_EMAIL_ADDRESS = "EMailAddress";
51ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private static final String ELEMENT_NAME_DISPLAY_NAME = "DisplayName";
52ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private static final String ELEMENT_NAME_RESPONSE = "Response";
53ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private static final String ELEMENT_NAME_AUTODISCOVER = "Autodiscover";
54ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
55ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    public EasAutoDiscover(final Context context, final String username, final String password) {
56ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        super(context, new Account(), new HostAuth());
57ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        mHostAuth.mLogin = username;
58ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        mHostAuth.mPassword = password;
59ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        mHostAuth.mFlags = HostAuth.FLAG_AUTHENTICATE | HostAuth.FLAG_SSL;
60ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        mHostAuth.mPort = 443;
61ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    }
62ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
63ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    /**
64ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * Do all the work of autodiscovery.
65ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @return A {@link Bundle} with the host information if autodiscovery succeeded. If we failed
66ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     *     due to an authentication failure, we return a {@link Bundle} with no host info but with
67ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     *     an appropriate error code. Otherwise, we return null.
68ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     */
69ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    public Bundle doAutodiscover() {
70ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        final String domain = getDomain();
71ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        if (domain == null) {
72ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            return null;
73ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        }
74ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
75ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        final StringEntity entity = buildRequestEntity();
76ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        if (entity == null) {
77ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            return null;
78ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        }
79ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        try {
80432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu            final HttpPost post = makePost("https://" + domain + AUTO_DISCOVER_PAGE, entity,
81432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                    "text/xml", false);
82432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu            final EasResponse resp = getResponse(post, domain);
83432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu            if (resp == null) {
84432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                return null;
85432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu            }
86432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu
87432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu            try {
88432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                // resp is either an authentication error, or a good response.
89432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                final int code = resp.getStatus();
90432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                if (code == HttpStatus.SC_UNAUTHORIZED) {
9154ab11d4050d543927e4e5809484927cdfafd433Paul Sliwowski                    final Bundle bundle = new Bundle(1);
9254ab11d4050d543927e4e5809484927cdfafd433Paul Sliwowski                    bundle.putInt(EmailServiceProxy.AUTO_DISCOVER_BUNDLE_ERROR_CODE,
9354ab11d4050d543927e4e5809484927cdfafd433Paul Sliwowski                            MessagingException.AUTODISCOVER_AUTHENTICATION_FAILED);
9454ab11d4050d543927e4e5809484927cdfafd433Paul Sliwowski                    return bundle;
95432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                } else {
96432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                    final HostAuth hostAuth = parseAutodiscover(resp);
97432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                    if (hostAuth != null) {
98432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                        // Fill in the rest of the HostAuth
99432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                        // We use the user name and password that were successful during
100432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                        // the autodiscover process
101432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                        hostAuth.mLogin = mHostAuth.mLogin;
102432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                        hostAuth.mPassword = mHostAuth.mPassword;
103432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                        // Note: there is no way we can auto-discover the proper client
104432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                        // SSL certificate to use, if one is needed.
105432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                        hostAuth.mPort = 443;
106432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                        hostAuth.mProtocol = Eas.PROTOCOL;
107432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                        hostAuth.mFlags = HostAuth.FLAG_SSL | HostAuth.FLAG_AUTHENTICATE;
108432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                        final Bundle bundle = new Bundle(2);
109432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                        bundle.putParcelable(EmailServiceProxy.AUTO_DISCOVER_BUNDLE_HOST_AUTH,
110432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                                hostAuth);
111432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                        bundle.putInt(EmailServiceProxy.AUTO_DISCOVER_BUNDLE_ERROR_CODE,
112432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                                MessagingException.NO_ERROR);
113432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                        return bundle;
114432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                    }
115ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                }
116432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu            } finally {
117432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu                resp.close();
118ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            }
119432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu        } catch (final IllegalArgumentException e) {
120432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu            // This happens when the domain is malformatted.
121432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu            // TODO: Fix sanitizing of the domain -- we try to in UI but apparently not correctly.
122432f1de519032c9381650ba5a40d0ff06d19c51bYu Ping Hu            LogUtils.e(TAG, "ISE with domain: %s", domain);
123ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        }
124ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        return null;
125ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    }
126ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
127ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    /**
128ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * Get the domain of our account.
129ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @return The domain of the email address.
130ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     */
131ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private String getDomain() {
132ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        final int amp = mHostAuth.mLogin.indexOf('@');
133ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        if (amp < 0) {
134ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            return null;
135ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        }
136ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        return mHostAuth.mLogin.substring(amp + 1);
137ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    }
138ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
139ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    /**
140ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * Create the payload of the request.
141ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @return A {@link StringEntity} for the request XML.
142ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     */
143ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private StringEntity buildRequestEntity() {
144ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        try {
145ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            final XmlSerializer s = Xml.newSerializer();
146ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            final ByteArrayOutputStream os = new ByteArrayOutputStream(1024);
147ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            s.setOutput(os, "UTF-8");
148ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            s.startDocument("UTF-8", false);
149ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            s.startTag(null, "Autodiscover");
150ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            s.attribute(null, "xmlns", AUTO_DISCOVER_SCHEMA_PREFIX + "requestschema/2006");
151ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            s.startTag(null, "Request");
152ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            s.startTag(null, "EMailAddress").text(mHostAuth.mLogin).endTag(null, "EMailAddress");
153ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            s.startTag(null, "AcceptableResponseSchema");
154ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            s.text(AUTO_DISCOVER_SCHEMA_PREFIX + "responseschema/2006");
155ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            s.endTag(null, "AcceptableResponseSchema");
156ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            s.endTag(null, "Request");
157ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            s.endTag(null, "Autodiscover");
158ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            s.endDocument();
159ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            return new StringEntity(os.toString());
160ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        } catch (final IOException e) {
161ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            // For all exception types, we can simply punt on autodiscover.
162ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        } catch (final IllegalArgumentException e) {
163ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        } catch (final IllegalStateException e) {
164ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        }
165ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
166ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        return null;
167ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    }
168ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
169ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    /**
170ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * Perform all requests necessary and get the server response. If the post fails or is
171ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * redirected, we alter the post and retry.
172ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @param post The initial {@link HttpPost} for this request.
173ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @param domain The domain for our account.
174ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @return If this request succeeded or has an unrecoverable authentication error, an
175ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     *     {@link EasResponse} with the details. For other errors, we return null.
176ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     */
177ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private EasResponse getResponse(final HttpPost post, final String domain) {
178ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        EasResponse resp = doPost(post, true);
179ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        if (resp == null) {
180ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            LogUtils.d(TAG, "Error in autodiscover, trying aternate address");
181ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            post.setURI(URI.create("https://autodiscover." + domain + AUTO_DISCOVER_PAGE));
182ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            resp = doPost(post, true);
183ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        }
184ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        return resp;
185ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    }
186ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
187ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    /**
188ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * Perform one attempt to get autodiscover information. Redirection and some authentication
189ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * errors are handled by recursively calls with modified host information.
190ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @param post The {@link HttpPost} for this request.
191ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @param canRetry Whether we can retry after an authentication failure.
192ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @return If this request succeeded or has an unrecoverable authentication error, an
193ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     *     {@link EasResponse} with the details. For other errors, we return null.
194ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     */
195ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    private EasResponse doPost(final HttpPost post, final boolean canRetry) {
196ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        final EasResponse resp;
197ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        try {
198ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            resp = executePost(post);
199ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        } catch (final IOException e) {
200ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            return null;
201ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        }
202ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
203ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        final int code = resp.getStatus();
204ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
205ff7e02603bc8196f411c0c491d74a42e747b7dc5Yu Ping Hu        if (resp.isRedirectError()) {
206ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            final String loc = resp.getRedirectAddress();
207ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            if (loc != null && loc.startsWith("http")) {
208ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                LogUtils.d(TAG, "Posting autodiscover to redirect: " + loc);
209ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                redirectHostAuth(loc);
210ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                post.setURI(URI.create(loc));
211ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                return doPost(post, canRetry);
212ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            }
213ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            return null;
214ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        }
215ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
216ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        if (code == HttpStatus.SC_UNAUTHORIZED) {
217ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            if (canRetry && mHostAuth.mLogin.contains("@")) {
218ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                // Try again using the bare user name
219ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                final int atSignIndex = mHostAuth.mLogin.indexOf('@');
220ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                mHostAuth.mLogin = mHostAuth.mLogin.substring(0, atSignIndex);
221ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                LogUtils.d(TAG, "401 received; trying username: %s", mHostAuth.mLogin);
222ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                resetAuthorization(post);
223ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                return doPost(post, false);
224ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            }
225ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        } else if (code != HttpStatus.SC_OK) {
226ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            // We'll try the next address if this doesn't work
227ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            LogUtils.d(TAG, "Bad response code when posting autodiscover: %d", code);
228ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            return null;
229ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        }
230ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
231ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        return resp;
232ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    }
233ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
234ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    /**
235ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * Parse the Server element of the server response.
236ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @param parser The {@link XmlPullParser}.
237ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @param hostAuth The {@link HostAuth} to populate with the results of parsing.
238ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @throws XmlPullParserException
239ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @throws IOException
240ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     */
24156d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy    private static void parseServer(final XmlPullParser parser, final HostAuth hostAuth)
242ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            throws XmlPullParserException, IOException {
243ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        boolean mobileSync = false;
244ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        while (true) {
245ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            final int type = parser.next();
246ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            if (type == XmlPullParser.END_TAG && parser.getName().equals(ELEMENT_NAME_SERVER)) {
247ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                break;
248ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            } else if (type == XmlPullParser.START_TAG) {
249ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                final String name = parser.getName();
250ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                if (name.equals(ELEMENT_NAME_TYPE)) {
251ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    if (parser.nextText().equals(ELEMENT_NAME_MOBILE_SYNC)) {
252ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                        mobileSync = true;
253ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    }
254ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                } else if (mobileSync && name.equals(ELEMENT_NAME_URL)) {
255ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    final String url = parser.nextText();
256ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    if (url != null) {
257ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                        LogUtils.d(TAG, "Autodiscover URL: %s", url);
258ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                        hostAuth.mAddress = Uri.parse(url).getHost();
259ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    }
260ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                }
261ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            }
262ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        }
263ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    }
264ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
265ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    /**
266ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * Parse the Settings element of the server response.
267ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @param parser The {@link XmlPullParser}.
268ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @param hostAuth The {@link HostAuth} to populate with the results of parsing.
269ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @throws XmlPullParserException
270ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @throws IOException
271ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     */
27256d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy    private static void parseSettings(final XmlPullParser parser, final HostAuth hostAuth)
273ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            throws XmlPullParserException, IOException {
274ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        while (true) {
275ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            final int type = parser.next();
276ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            if (type == XmlPullParser.END_TAG && parser.getName().equals(ELEMENT_NAME_SETTINGS)) {
277ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                break;
278ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            } else if (type == XmlPullParser.START_TAG) {
279ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                final String name = parser.getName();
280ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                if (name.equals(ELEMENT_NAME_SERVER)) {
281ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    parseServer(parser, hostAuth);
282ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                }
283ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            }
284ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        }
285ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    }
286ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
287ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    /**
288ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * Parse the Action element of the server response.
289ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @param parser The {@link XmlPullParser}.
290ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @param hostAuth The {@link HostAuth} to populate with the results of parsing.
291ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @throws XmlPullParserException
292ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @throws IOException
293ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     */
29456d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy    private static void parseAction(final XmlPullParser parser, final HostAuth hostAuth)
295ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            throws XmlPullParserException, IOException {
296ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        while (true) {
297ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            final int type = parser.next();
298ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            if (type == XmlPullParser.END_TAG && parser.getName().equals(ELEMENT_NAME_ACTION)) {
299ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                break;
300ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            } else if (type == XmlPullParser.START_TAG) {
301ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                final String name = parser.getName();
302ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                if (name.equals(ELEMENT_NAME_ERROR)) {
303ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    // Should parse the error
304ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                } else if (name.equals(ELEMENT_NAME_REDIRECT)) {
305ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    LogUtils.d(TAG, "Redirect: " + parser.nextText());
306ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                } else if (name.equals(ELEMENT_NAME_SETTINGS)) {
307ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    parseSettings(parser, hostAuth);
308ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                }
309ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            }
310ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        }
311ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    }
312ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
313ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    /**
314ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * Parse the User element of the server response.
315ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @param parser The {@link XmlPullParser}.
316ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @param hostAuth The {@link HostAuth} to populate with the results of parsing.
317ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @throws XmlPullParserException
318ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @throws IOException
319ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     */
32056d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy    private static void parseUser(final XmlPullParser parser, final HostAuth hostAuth)
321ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            throws XmlPullParserException, IOException {
322ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        while (true) {
323ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            int type = parser.next();
324ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            if (type == XmlPullParser.END_TAG && parser.getName().equals(ELEMENT_NAME_USER)) {
325ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                break;
326ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            } else if (type == XmlPullParser.START_TAG) {
327ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                String name = parser.getName();
328ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                if (name.equals(ELEMENT_NAME_EMAIL_ADDRESS)) {
329ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    final String addr = parser.nextText();
330ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    LogUtils.d(TAG, "Autodiscover, email: %s", addr);
331ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                } else if (name.equals(ELEMENT_NAME_DISPLAY_NAME)) {
332ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    final String dn = parser.nextText();
333ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    LogUtils.d(TAG, "Autodiscover, user: %s", dn);
334ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                }
335ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            }
336ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        }
337ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    }
338ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
339ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    /**
340ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * Parse the Response element of the server response.
341ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @param parser The {@link XmlPullParser}.
342ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @param hostAuth The {@link HostAuth} to populate with the results of parsing.
343ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @throws XmlPullParserException
344ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @throws IOException
345ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     */
34656d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy    private static void parseResponse(final XmlPullParser parser, final HostAuth hostAuth)
347ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            throws XmlPullParserException, IOException {
348ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        while (true) {
349ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            final int type = parser.next();
350ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            if (type == XmlPullParser.END_TAG && parser.getName().equals(ELEMENT_NAME_RESPONSE)) {
351ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                break;
352ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            } else if (type == XmlPullParser.START_TAG) {
353ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                final String name = parser.getName();
354ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                if (name.equals(ELEMENT_NAME_USER)) {
355ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    parseUser(parser, hostAuth);
356ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                } else if (name.equals(ELEMENT_NAME_ACTION)) {
357ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    parseAction(parser, hostAuth);
358ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                }
359ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            }
360ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        }
361ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    }
362ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
363ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    /**
364ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * Parse the server response for the final {@link HostAuth}.
365ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @param resp The {@link EasResponse} from the server.
366ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     * @return The final {@link HostAuth} for this server.
367ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu     */
36856d35257ef1493e849522c3c2828d904e4c5531fScott Kennedy    private static HostAuth parseAutodiscover(final EasResponse resp) {
369ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        // The response to Autodiscover is regular XML (not WBXML)
370ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        try {
371ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            final XmlPullParser parser = XmlPullParserFactory.newInstance().newPullParser();
372ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            parser.setInput(resp.getInputStream(), "UTF-8");
373ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            if (parser.getEventType() != XmlPullParser.START_DOCUMENT) {
374ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                return null;
375ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            }
376ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            if (parser.next() != XmlPullParser.START_TAG) {
377ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                return null;
378ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            }
379ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            if (!parser.getName().equals(ELEMENT_NAME_AUTODISCOVER)) {
380ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                return null;
381ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            }
382ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu
383ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            final HostAuth hostAuth = new HostAuth();
384ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            while (true) {
385ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                final int type = parser.nextTag();
386ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                if (type == XmlPullParser.END_TAG && parser.getName()
387ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                        .equals(ELEMENT_NAME_AUTODISCOVER)) {
388ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    break;
389ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                } else if (type == XmlPullParser.START_TAG && parser.getName()
390ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                        .equals(ELEMENT_NAME_RESPONSE)) {
391ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    parseResponse(parser, hostAuth);
392ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    // Valid responses will set the address.
393ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    if (hostAuth.mAddress != null) {
394ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                        return hostAuth;
395ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                    }
396ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu                }
397ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            }
398ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        } catch (final XmlPullParserException e) {
399ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            // Parse error.
400ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        } catch (final IOException e) {
401ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu            // Error reading parser.
402ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        }
403ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu        return null;
404ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu    }
405ddbe7744f17d9dd0e26bc2d5a1e89aec9b031bddYu Ping Hu}
406