1f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki/*
2f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki * Copyright (C) 2010 The Android Open Source Project
3f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki *
4f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki * Licensed under the Apache License, Version 2.0 (the "License");
5f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki * you may not use this file except in compliance with the License.
6f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki * You may obtain a copy of the License at
7f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki *
8f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki *      http://www.apache.org/licenses/LICENSE-2.0
9f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki *
10f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki * Unless required by applicable law or agreed to in writing, software
11f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki * distributed under the License is distributed on an "AS IS" BASIS,
12f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki * See the License for the specific language governing permissions and
14f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki * limitations under the License.
15f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki */
16f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki
17c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blankpackage com.android.emailcommon;
18ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler
19f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onukiimport android.content.Context;
20f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onukiimport android.content.pm.ApplicationInfo;
21f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onukiimport android.content.pm.PackageManager.NameNotFoundException;
22f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onukiimport android.os.Bundle;
23560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy
24560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedyimport com.android.mail.utils.LogUtils;
25f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki
26c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blankimport java.io.Serializable;
27f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onukiimport java.lang.reflect.Method;
28f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki
29f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki/**
30f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki * A bridge class to the email vendor policy apk.
31f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki *
32f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki * <p>Email vendor policy is a system apk named "com.android.email.helper".  When exists, it must
33f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki * contain a class called "com.android.email.policy.EmailPolicy" with a static public method
34f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki * <code>Bundle getPolicy(String, Bundle)</code>, which serves vendor specific configurations.
35f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki *
36f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki * <p>A vendor policy apk is optional.  The email application will operate properly when none is
37f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki * found.
38f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki */
39f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onukipublic class VendorPolicyLoader {
40f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    private static final String POLICY_PACKAGE = "com.android.email.policy";
41f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    private static final String POLICY_CLASS = POLICY_PACKAGE + ".EmailPolicy";
42f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    private static final String GET_POLICY_METHOD = "getPolicy";
43f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    private static final Class<?>[] ARGS = new Class<?>[] {String.class, Bundle.class};
44f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki
45ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler    // call keys and i/o bundle keys
46ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler    // when there is only one parameter or return value, use call key
47f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    private static final String USE_ALTERNATE_EXCHANGE_STRINGS = "useAlternateExchangeStrings";
48ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler    private static final String GET_IMAP_ID = "getImapId";
49ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler    private static final String GET_IMAP_ID_USER = "getImapId.user";
50ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler    private static final String GET_IMAP_ID_HOST = "getImapId.host";
51ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler    private static final String GET_IMAP_ID_CAPA = "getImapId.capabilities";
52ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler    private static final String FIND_PROVIDER = "findProvider";
53ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler    private static final String FIND_PROVIDER_IN_URI = "findProvider.inUri";
54ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler    private static final String FIND_PROVIDER_IN_USER = "findProvider.inUser";
55ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler    private static final String FIND_PROVIDER_OUT_URI = "findProvider.outUri";
56ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler    private static final String FIND_PROVIDER_OUT_USER = "findProvider.outUser";
57ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler    private static final String FIND_PROVIDER_NOTE = "findProvider.note";
58f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki
59f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    /** Singleton instance */
60f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    private static VendorPolicyLoader sInstance;
61f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki
62f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    private final Method mPolicyMethod;
63f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki
64f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    public static VendorPolicyLoader getInstance(Context context) {
65f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        if (sInstance == null) {
66f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki            // It's okay to instantiate VendorPolicyLoader multiple times.  No need to synchronize.
67f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki            sInstance = new VendorPolicyLoader(context);
68f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        }
69f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        return sInstance;
70f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    }
71f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki
7236d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki    /**
7336d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki     * For testing only.
7436d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki     *
7536d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki     * Replaces the instance with a new instance that loads a specified class.
7636d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki     */
7736d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki    public static void injectPolicyForTest(Context context, String apkPackageName, Class<?> clazz) {
7836d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki        String name = clazz.getName();
79560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy        LogUtils.d(Logging.LOG_TAG, String.format("Using policy: package=%s name=%s",
8036d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki                apkPackageName, name));
8136d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki        sInstance = new VendorPolicyLoader(context, apkPackageName, name, true);
8236d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki    }
8336d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki
8436d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki    /**
8536d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki     * For testing only.
8636d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki     *
8736d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki     * Clear the instance so that the next {@link #getInstance} call will return a regular,
8836d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki     * non-injected instance.
8936d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki     */
9036d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki    public static void clearInstanceForTest() {
9136d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki        sInstance = null;
9236d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki    }
9336d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki
94f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    private VendorPolicyLoader(Context context) {
95f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        this(context, POLICY_PACKAGE, POLICY_CLASS, false);
96f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    }
97f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki
98f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    /**
99f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki     * Constructor for testing, where we need to use an alternate package/class name, and skip
100f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki     * the system apk check.
101f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki     */
10217d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie    public VendorPolicyLoader(Context context, String apkPackageName, String className,
103f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki            boolean allowNonSystemApk) {
10436d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki        if (!allowNonSystemApk && !isSystemPackage(context, apkPackageName)) {
105f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki            mPolicyMethod = null;
106f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki            return;
107f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        }
108f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki
109f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        Class<?> clazz = null;
110f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        Method method = null;
111f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        try {
11236d3dfaeac1a80561ef41a78ecc9bf3583d0ca7bMakoto Onuki            final Context policyContext = context.createPackageContext(apkPackageName,
113f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki                    Context.CONTEXT_IGNORE_SECURITY | Context.CONTEXT_INCLUDE_CODE);
114f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki            final ClassLoader classLoader = policyContext.getClassLoader();
115f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki            clazz = classLoader.loadClass(className);
116f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki            method = clazz.getMethod(GET_POLICY_METHOD, ARGS);
117f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        } catch (NameNotFoundException ignore) {
118a6e6dd096cf41e556ed8aa23cd18d0227e10ddd1Andrew Stadler            // Package not found -- it's okay - there's no policy .apk found, which is OK
119a6e6dd096cf41e556ed8aa23cd18d0227e10ddd1Andrew Stadler        } catch (ClassNotFoundException e) {
120a6e6dd096cf41e556ed8aa23cd18d0227e10ddd1Andrew Stadler            // Class not found -- probably not OK, but let's not crash here
121560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy            LogUtils.w(Logging.LOG_TAG, "VendorPolicyLoader: " + e);
122a6e6dd096cf41e556ed8aa23cd18d0227e10ddd1Andrew Stadler        } catch (NoSuchMethodException e) {
123a6e6dd096cf41e556ed8aa23cd18d0227e10ddd1Andrew Stadler            // Method not found -- probably not OK, but let's not crash here
124560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy            LogUtils.w(Logging.LOG_TAG, "VendorPolicyLoader: " + e);
125f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        }
126f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        mPolicyMethod = method;
127f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    }
128f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki
129f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    // Not private for testing
13017d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie    public static boolean isSystemPackage(Context context, String packageName) {
131f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        try {
132f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki            ApplicationInfo ai = context.getPackageManager().getApplicationInfo(packageName, 0);
133f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki            return (ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
134f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        } catch (NameNotFoundException e) {
135f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki            return false; // Package not found.
136f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        }
137f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    }
138f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki
139f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    /**
140f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki     * Calls the getPolicy method in the policy apk, if one exists.  This method never returns null;
141f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki     * It returns an empty {@link Bundle} when there is no policy apk (or even if the inner
142f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki     * getPolicy returns null).
143f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki     */
144f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    // Not private for testing
14517d3a29c9d8f7a27c463239f190bdcc4e0804527Jerry Xie    public Bundle getPolicy(String policy, Bundle args) {
146f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        Bundle ret = null;
147f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        if (mPolicyMethod != null) {
148f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki            try {
149f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki                ret = (Bundle) mPolicyMethod.invoke(null, policy, args);
150f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki            } catch (Exception e) {
151560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy                LogUtils.w(Logging.LOG_TAG, "VendorPolicyLoader", e);
152f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki            }
153f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        }
154f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        return (ret != null) ? ret : Bundle.EMPTY;
155f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    }
156f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki
157f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    /**
158f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki     * Returns true if alternate exchange descriptive text is required.
159ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *
160ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     * Vendor function:
161ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *  Select: USE_ALTERNATE_EXCHANGE_STRINGS
162ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *  Params: none
163ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *  Result: USE_ALTERNATE_EXCHANGE_STRINGS (boolean)
164f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki     */
165f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    public boolean useAlternateExchangeStrings() {
166f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki        return getPolicy(USE_ALTERNATE_EXCHANGE_STRINGS, null)
167f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki                .getBoolean(USE_ALTERNATE_EXCHANGE_STRINGS, false);
168f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki    }
169ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler
170ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler    /**
171ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     * Returns additional key/value pairs for the IMAP ID string.
172ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *
173ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     * Vendor function:
174ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *  Select: GET_IMAP_ID
175ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *  Params: GET_IMAP_ID_USER (String)
176ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *          GET_IMAP_ID_HOST (String)
177ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *          GET_IMAP_ID_CAPABILITIES (String)
178ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *  Result: GET_IMAP_ID (String)
179ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *
180ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     * @param userName the server that is being contacted (e.g. "imap.server.com")
181ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     * @param host the server that is being contacted (e.g. "imap.server.com")
182a6e6dd096cf41e556ed8aa23cd18d0227e10ddd1Andrew Stadler     * @param capabilities reported capabilities, if known.  null is OK
183ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     * @return zero or more key/value pairs, quoted and delimited by spaces.  If there is
184ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     * nothing to add, return null.
185ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     */
186ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler    public String getImapIdValues(String userName, String host, String capabilities) {
187ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler        Bundle params = new Bundle();
188ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler        params.putString(GET_IMAP_ID_USER, userName);
189ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler        params.putString(GET_IMAP_ID_HOST, host);
190ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler        params.putString(GET_IMAP_ID_CAPA, capabilities);
191ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler        String result = getPolicy(GET_IMAP_ID, params).getString(GET_IMAP_ID);
192ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler        return result;
193ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler    }
194ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler
195e62688f0d67edd7119e82a5cbfe6b8815721df2fMartin Hibdon    public static class OAuthProvider implements Serializable {
196e62688f0d67edd7119e82a5cbfe6b8815721df2fMartin Hibdon        private static final long serialVersionUID = 8511656164616538990L;
197e62688f0d67edd7119e82a5cbfe6b8815721df2fMartin Hibdon
198e62688f0d67edd7119e82a5cbfe6b8815721df2fMartin Hibdon        public String id;
199e62688f0d67edd7119e82a5cbfe6b8815721df2fMartin Hibdon        public String label;
200e62688f0d67edd7119e82a5cbfe6b8815721df2fMartin Hibdon        public String authEndpoint;
201e62688f0d67edd7119e82a5cbfe6b8815721df2fMartin Hibdon        public String tokenEndpoint;
202e62688f0d67edd7119e82a5cbfe6b8815721df2fMartin Hibdon        public String refreshEndpoint;
203e62688f0d67edd7119e82a5cbfe6b8815721df2fMartin Hibdon        public String responseType;
204e62688f0d67edd7119e82a5cbfe6b8815721df2fMartin Hibdon        public String redirectUri;
205e62688f0d67edd7119e82a5cbfe6b8815721df2fMartin Hibdon        public String scope;
206e62688f0d67edd7119e82a5cbfe6b8815721df2fMartin Hibdon        public String clientId;
207e62688f0d67edd7119e82a5cbfe6b8815721df2fMartin Hibdon        public String clientSecret;
208e62688f0d67edd7119e82a5cbfe6b8815721df2fMartin Hibdon        public String state;
209e62688f0d67edd7119e82a5cbfe6b8815721df2fMartin Hibdon    }
210e62688f0d67edd7119e82a5cbfe6b8815721df2fMartin Hibdon
211c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank    public static class Provider implements Serializable {
212c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        private static final long serialVersionUID = 8511656164616538989L;
213c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank
214c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        public String id;
215c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        public String label;
216c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        public String domain;
217c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        public String incomingUriTemplate;
218c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        public String incomingUsernameTemplate;
219c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        public String outgoingUriTemplate;
220c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        public String outgoingUsernameTemplate;
221d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler        public String altIncomingUriTemplate;
222d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler        public String altIncomingUsernameTemplate;
223d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler        public String altOutgoingUriTemplate;
224d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler        public String altOutgoingUsernameTemplate;
225c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        public String incomingUri;
226c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        public String incomingUsername;
227c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        public String outgoingUri;
228c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        public String outgoingUsername;
229c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        public String note;
230e62688f0d67edd7119e82a5cbfe6b8815721df2fMartin Hibdon        public String oauth;
231c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank
232c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        /**
233c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank         * Expands templates in all of the  provider fields that support them. Currently,
234c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank         * templates are used in 4 fields -- incoming and outgoing URI and user name.
235c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank         * @param email user-specified data used to replace template values
236c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank         */
237c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        public void expandTemplates(String email) {
238d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler            final String[] emailParts = email.split("@");
239d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler            final String user = emailParts[0];
240c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank
241c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank            incomingUri = expandTemplate(incomingUriTemplate, email, user);
242c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank            incomingUsername = expandTemplate(incomingUsernameTemplate, email, user);
243c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank            outgoingUri = expandTemplate(outgoingUriTemplate, email, user);
244c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank            outgoingUsername = expandTemplate(outgoingUsernameTemplate, email, user);
245c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        }
246c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank
247c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        /**
248d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler         * Like the above, but expands the alternate templates instead
249d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler         * @param email user-specified data used to replace template values
250d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler         */
251d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler        public void expandAlternateTemplates(String email) {
252d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler            final String[] emailParts = email.split("@");
253d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler            final String user = emailParts[0];
254d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler
255d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler            incomingUri = expandTemplate(altIncomingUriTemplate, email, user);
256d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler            incomingUsername = expandTemplate(altIncomingUsernameTemplate, email, user);
257d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler            outgoingUri = expandTemplate(altOutgoingUriTemplate, email, user);
258d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler            outgoingUsername = expandTemplate(altOutgoingUsernameTemplate, email, user);
259d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler        }
260d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler
261d039322f7402ef402eb66c92b899510dd6649e2dTony Mantler        /**
262c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank         * Replaces all parameterized values in the given template. The values replaced are
263c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank         * $domain, $user and $email.
264c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank         */
265c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        private String expandTemplate(String template, String email, String user) {
266c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank            String returnString = template;
267c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank            returnString = returnString.replaceAll("\\$email", email);
268c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank            returnString = returnString.replaceAll("\\$user", user);
269c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank            returnString = returnString.replaceAll("\\$domain", domain);
270c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank            return returnString;
271c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank        }
272c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank    }
273c6089bc01f2ae49fb11904a4b4f222811358254fMarc Blank
274ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler    /**
275ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     * Returns provider setup information for a given email address
276ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *
277ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     * Vendor function:
278ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *  Select: FIND_PROVIDER
279ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *  Param:  FIND_PROVIDER (String)
280ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *  Result: FIND_PROVIDER_IN_URI
281ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *          FIND_PROVIDER_IN_USER
282ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *          FIND_PROVIDER_OUT_URI
283ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *          FIND_PROVIDER_OUT_USER
284a6e6dd096cf41e556ed8aa23cd18d0227e10ddd1Andrew Stadler     *          FIND_PROVIDER_NOTE (optional - null is OK)
285a6e6dd096cf41e556ed8aa23cd18d0227e10ddd1Andrew Stadler     *
286a6e6dd096cf41e556ed8aa23cd18d0227e10ddd1Andrew Stadler     * Note, if we get this far, we expect "correct" results from the policy method.  But throwing
287a6e6dd096cf41e556ed8aa23cd18d0227e10ddd1Andrew Stadler     * checked exceptions requires a bunch of upstream changes, so we're going to catch them here
288a6e6dd096cf41e556ed8aa23cd18d0227e10ddd1Andrew Stadler     * and add logging.  Other exceptions may escape here (such as null pointers) to fail fast.
289ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     *
290ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     * @param domain The domain portion of the user's email address
291ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     * @return suitable Provider definition, or null if no match found
292ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler     */
293ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler    public Provider findProviderForDomain(String domain) {
294ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler        Bundle params = new Bundle();
295ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler        params.putString(FIND_PROVIDER, domain);
296ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler        Bundle out = getPolicy(FIND_PROVIDER, params);
2970434fef1f6706a0a6fc53b499f3e982f70d7142dAndrew Stadler        if (out != null && !out.isEmpty()) {
298040ddf60cfef4aaecf4bfe1f897fce3248d777a4Todd Kennedy            Provider p = new Provider();
299040ddf60cfef4aaecf4bfe1f897fce3248d777a4Todd Kennedy            p.id = null;
300040ddf60cfef4aaecf4bfe1f897fce3248d777a4Todd Kennedy            p.label = null;
301040ddf60cfef4aaecf4bfe1f897fce3248d777a4Todd Kennedy            p.domain = domain;
302040ddf60cfef4aaecf4bfe1f897fce3248d777a4Todd Kennedy            p.incomingUriTemplate = out.getString(FIND_PROVIDER_IN_URI);
303040ddf60cfef4aaecf4bfe1f897fce3248d777a4Todd Kennedy            p.incomingUsernameTemplate = out.getString(FIND_PROVIDER_IN_USER);
304040ddf60cfef4aaecf4bfe1f897fce3248d777a4Todd Kennedy            p.outgoingUriTemplate = out.getString(FIND_PROVIDER_OUT_URI);
305040ddf60cfef4aaecf4bfe1f897fce3248d777a4Todd Kennedy            p.outgoingUsernameTemplate = out.getString(FIND_PROVIDER_OUT_USER);
306040ddf60cfef4aaecf4bfe1f897fce3248d777a4Todd Kennedy            p.note = out.getString(FIND_PROVIDER_NOTE);
307040ddf60cfef4aaecf4bfe1f897fce3248d777a4Todd Kennedy            return p;
308ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler        }
309ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler        return null;
310ecb1af804144689d4ead96a247b565f9b4eb8160Andrew Stadler    }
311f613489663cdc5df71b029dfcec5fd3c5173a549Makoto Onuki}
312