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