ImapUtility.java revision 284d8d7db5743d24b9aa246afe3d24139bdb0813
1/*
2 * Copyright (C) 2011 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.email.mail.store.imap;
18
19import com.android.emailcommon.Logging;
20
21import android.util.Log;
22
23import java.util.ArrayList;
24
25/**
26 * Utility methods for use with IMAP.
27 */
28public class ImapUtility {
29    /**
30     * Apply quoting rules per IMAP RFC,
31     * quoted          = DQUOTE *QUOTED-CHAR DQUOTE
32     * QUOTED-CHAR     = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials
33     * quoted-specials = DQUOTE / "\"
34     *
35     * This is used primarily for IMAP login, but might be useful elsewhere.
36     *
37     * NOTE:  Not very efficient - you may wish to preflight this, or perhaps it should check
38     * for trouble chars before calling the replace functions.
39     *
40     * @param s The string to be quoted.
41     * @return A copy of the string, having undergone quoting as described above
42     */
43    public static String imapQuoted(String s) {
44
45        // First, quote any backslashes by replacing \ with \\
46        // regex Pattern:  \\    (Java string const = \\\\)
47        // Substitute:     \\\\  (Java string const = \\\\\\\\)
48        String result = s.replaceAll("\\\\", "\\\\\\\\");
49
50        // Then, quote any double-quotes by replacing " with \"
51        // regex Pattern:  "    (Java string const = \")
52        // Substitute:     \\"  (Java string const = \\\\\")
53        result = result.replaceAll("\"", "\\\\\"");
54
55        // return string with quotes around it
56        return "\"" + result + "\"";
57    }
58
59    /**
60     * Gets all of the values in a sequence set per RFC 3501. Any ranges are expanded into a
61     * list of individual numbers. If the set is invalid, an empty array is returned.
62     * <pre>
63     * sequence-number = nz-number / "*"
64     * sequence-range  = sequence-number ":" sequence-number
65     * sequence-set    = (sequence-number / sequence-range) *("," sequence-set)
66     * </pre>
67     */
68    public static String[] getImapSequenceValues(String set) {
69        ArrayList<String> list = new ArrayList<String>();
70        if (set != null) {
71            String[] setItems = set.split(",");
72            for (String item : setItems) {
73                if (item.indexOf(':') == -1) {
74                    // simple item
75                    try {
76                        Integer.parseInt(item); // Don't need the value; just ensure it's valid
77                        list.add(item);
78                    } catch (NumberFormatException e) {
79                        Log.d(Logging.LOG_TAG, "Invalid UID value", e);
80                    }
81                } else {
82                    // range
83                    for (String rangeItem : getImapRangeValues(item)) {
84                        list.add(rangeItem);
85                    }
86                }
87            }
88        }
89        String[] stringList = new String[list.size()];
90        return list.toArray(stringList);
91    }
92
93    /**
94     * Expand the given number range into a list of individual numbers. If the range is not valid,
95     * an empty array is returned.
96     * <pre>
97     * sequence-number = nz-number / "*"
98     * sequence-range  = sequence-number ":" sequence-number
99     * sequence-set    = (sequence-number / sequence-range) *("," sequence-set)
100     * </pre>
101     */
102    public static String[] getImapRangeValues(String range) {
103        ArrayList<String> list = new ArrayList<String>();
104        try {
105            if (range != null) {
106                int colonPos = range.indexOf(':');
107                if (colonPos > 0) {
108                    int first  = Integer.parseInt(range.substring(0, colonPos));
109                    int second = Integer.parseInt(range.substring(colonPos + 1));
110                    if (first < second) {
111                        for (int i = first; i <= second; i++) {
112                            list.add(Integer.toString(i));
113                        }
114                    } else {
115                        for (int i = first; i >= second; i--) {
116                            list.add(Integer.toString(i));
117                        }
118                    }
119                }
120            }
121        } catch (NumberFormatException e) {
122            Log.d(Logging.LOG_TAG, "Invalid range value", e);
123        }
124        String[] stringList = new String[list.size()];
125        return list.toArray(stringList);
126    }
127}
128