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