1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.exchange.eas;
18
19import com.android.exchange.Eas;
20import com.android.exchange.EasResponse;
21import com.android.mail.utils.LogUtils;
22import com.google.common.collect.Sets;
23
24import org.apache.http.Header;
25import org.apache.http.HttpEntity;
26import org.apache.http.client.methods.HttpUriRequest;
27
28import java.io.IOException;
29import java.util.HashSet;
30
31/**
32 * Performs an HTTP Options request to the Exchange server, in order to get the protocol
33 * version.
34 */
35public class EasOptions extends EasOperation {
36    private static final String LOG_TAG = Eas.LOG_TAG;
37
38    /** Result code indicating we successfully got a protocol version. */
39    public static final int RESULT_OK = 1;
40
41    /** Set of Exchange protocol versions we understand. */
42    private static final HashSet<String> SUPPORTED_PROTOCOL_VERSIONS = Sets.newHashSet(
43            Eas.SUPPORTED_PROTOCOL_EX2003,
44            Eas.SUPPORTED_PROTOCOL_EX2007, Eas.SUPPORTED_PROTOCOL_EX2007_SP1,
45            Eas.SUPPORTED_PROTOCOL_EX2010, Eas.SUPPORTED_PROTOCOL_EX2010_SP1);
46
47    private String mProtocolVersion = null;
48
49    public EasOptions(final EasOperation parentOperation) {
50        super(parentOperation);
51    }
52
53    /**
54     * Perform the server request. If successful, callers should use
55     * {@link #getProtocolVersionString} to get the actual protocol version value.
56     * @return A result code; {@link #RESULT_OK} is the only value that indicates success.
57     */
58    public int getProtocolVersionFromServer() {
59        return performOperation();
60    }
61
62    /**
63     * @return The protocol version to use, or null if we did not successfully get one.
64     */
65    public String getProtocolVersionString() {
66        return mProtocolVersion;
67    }
68
69    /**
70     * Note that this operation does not actually use this name when forming the request.
71     * @return A useful name for logging this operation.
72     */
73    @Override
74    protected String getCommand() {
75        return "OPTIONS";
76    }
77
78    @Override
79    protected HttpEntity getRequestEntity() {
80        return null;
81    }
82
83    @Override
84    protected int handleResponse(final EasResponse response) {
85        final Header commands = response.getHeader("MS-ASProtocolCommands");
86        final Header versions = response.getHeader("ms-asprotocolversions");
87        final boolean hasProtocolVersion;
88        if (commands == null || versions == null) {
89            LogUtils.e(LOG_TAG, "OPTIONS response without commands or versions");
90            hasProtocolVersion = false;
91        } else {
92            mProtocolVersion = getProtocolVersionFromHeader(versions);
93            hasProtocolVersion = (mProtocolVersion != null);
94        }
95        if (!hasProtocolVersion) {
96            return RESULT_PROTOCOL_VERSION_UNSUPPORTED;
97        }
98
99        return RESULT_OK;
100    }
101
102    @Override
103    protected String getRequestUri() {
104        return null;
105    }
106
107    protected HttpUriRequest makeRequest() throws IOException, MessageInvalidException {
108        return mConnection.makeOptions();
109    }
110    /**
111     * Find the best protocol version to use from the header.
112     * @param versionHeader The {@link Header} for the server's supported versions.
113     * @return The best protocol version we mutually support, or null if none found.
114     */
115    private String getProtocolVersionFromHeader(final Header versionHeader) {
116        // The string is a comma separated list of EAS versions in ascending order
117        // e.g. 1.0,2.0,2.5,12.0,12.1,14.0,14.1
118        final String supportedVersions = versionHeader.getValue();
119        LogUtils.d(LOG_TAG, "Server supports versions: %s", supportedVersions);
120        final String[] supportedVersionsArray = supportedVersions.split(",");
121        // Find the most recent version we support
122        String newProtocolVersion = null;
123        for (final String version: supportedVersionsArray) {
124            if (SUPPORTED_PROTOCOL_VERSIONS.contains(version)) {
125                newProtocolVersion = version;
126            }
127        }
128        return newProtocolVersion;
129    }
130}
131