15c523858385176c33a7456bb84035de78552d22dMarc Blank/* 25c523858385176c33a7456bb84035de78552d22dMarc Blank * Copyright (C) 2011 The Android Open Source Project 35c523858385176c33a7456bb84035de78552d22dMarc Blank * 45c523858385176c33a7456bb84035de78552d22dMarc Blank * Licensed under the Apache License, Version 2.0 (the "License"); 55c523858385176c33a7456bb84035de78552d22dMarc Blank * you may not use this file except in compliance with the License. 65c523858385176c33a7456bb84035de78552d22dMarc Blank * You may obtain a copy of the License at 75c523858385176c33a7456bb84035de78552d22dMarc Blank * 85c523858385176c33a7456bb84035de78552d22dMarc Blank * http://www.apache.org/licenses/LICENSE-2.0 95c523858385176c33a7456bb84035de78552d22dMarc Blank * 105c523858385176c33a7456bb84035de78552d22dMarc Blank * Unless required by applicable law or agreed to in writing, software 115c523858385176c33a7456bb84035de78552d22dMarc Blank * distributed under the License is distributed on an "AS IS" BASIS, 125c523858385176c33a7456bb84035de78552d22dMarc Blank * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135c523858385176c33a7456bb84035de78552d22dMarc Blank * See the License for the specific language governing permissions and 145c523858385176c33a7456bb84035de78552d22dMarc Blank * limitations under the License. 155c523858385176c33a7456bb84035de78552d22dMarc Blank */ 165c523858385176c33a7456bb84035de78552d22dMarc Blank 175c523858385176c33a7456bb84035de78552d22dMarc Blankpackage com.android.email.mail.store.imap; 185c523858385176c33a7456bb84035de78552d22dMarc Blank 195c523858385176c33a7456bb84035de78552d22dMarc Blankimport com.android.emailcommon.Logging; 20560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedyimport com.android.mail.utils.LogUtils; 215c523858385176c33a7456bb84035de78552d22dMarc Blank 225c523858385176c33a7456bb84035de78552d22dMarc Blankimport java.util.ArrayList; 235c523858385176c33a7456bb84035de78552d22dMarc Blank 245c523858385176c33a7456bb84035de78552d22dMarc Blank/** 255c523858385176c33a7456bb84035de78552d22dMarc Blank * Utility methods for use with IMAP. 265c523858385176c33a7456bb84035de78552d22dMarc Blank */ 275c523858385176c33a7456bb84035de78552d22dMarc Blankpublic class ImapUtility { 285c523858385176c33a7456bb84035de78552d22dMarc Blank /** 295c523858385176c33a7456bb84035de78552d22dMarc Blank * Apply quoting rules per IMAP RFC, 305c523858385176c33a7456bb84035de78552d22dMarc Blank * quoted = DQUOTE *QUOTED-CHAR DQUOTE 315c523858385176c33a7456bb84035de78552d22dMarc Blank * QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> / "\" quoted-specials 325c523858385176c33a7456bb84035de78552d22dMarc Blank * quoted-specials = DQUOTE / "\" 335c523858385176c33a7456bb84035de78552d22dMarc Blank * 345c523858385176c33a7456bb84035de78552d22dMarc Blank * This is used primarily for IMAP login, but might be useful elsewhere. 355c523858385176c33a7456bb84035de78552d22dMarc Blank * 365c523858385176c33a7456bb84035de78552d22dMarc Blank * NOTE: Not very efficient - you may wish to preflight this, or perhaps it should check 375c523858385176c33a7456bb84035de78552d22dMarc Blank * for trouble chars before calling the replace functions. 385c523858385176c33a7456bb84035de78552d22dMarc Blank * 395c523858385176c33a7456bb84035de78552d22dMarc Blank * @param s The string to be quoted. 405c523858385176c33a7456bb84035de78552d22dMarc Blank * @return A copy of the string, having undergone quoting as described above 415c523858385176c33a7456bb84035de78552d22dMarc Blank */ 425c523858385176c33a7456bb84035de78552d22dMarc Blank public static String imapQuoted(String s) { 435c523858385176c33a7456bb84035de78552d22dMarc Blank 445c523858385176c33a7456bb84035de78552d22dMarc Blank // First, quote any backslashes by replacing \ with \\ 455c523858385176c33a7456bb84035de78552d22dMarc Blank // regex Pattern: \\ (Java string const = \\\\) 465c523858385176c33a7456bb84035de78552d22dMarc Blank // Substitute: \\\\ (Java string const = \\\\\\\\) 475c523858385176c33a7456bb84035de78552d22dMarc Blank String result = s.replaceAll("\\\\", "\\\\\\\\"); 485c523858385176c33a7456bb84035de78552d22dMarc Blank 495c523858385176c33a7456bb84035de78552d22dMarc Blank // Then, quote any double-quotes by replacing " with \" 505c523858385176c33a7456bb84035de78552d22dMarc Blank // regex Pattern: " (Java string const = \") 515c523858385176c33a7456bb84035de78552d22dMarc Blank // Substitute: \\" (Java string const = \\\\\") 525c523858385176c33a7456bb84035de78552d22dMarc Blank result = result.replaceAll("\"", "\\\\\""); 535c523858385176c33a7456bb84035de78552d22dMarc Blank 545c523858385176c33a7456bb84035de78552d22dMarc Blank // return string with quotes around it 555c523858385176c33a7456bb84035de78552d22dMarc Blank return "\"" + result + "\""; 565c523858385176c33a7456bb84035de78552d22dMarc Blank } 575c523858385176c33a7456bb84035de78552d22dMarc Blank 585c523858385176c33a7456bb84035de78552d22dMarc Blank /** 595c523858385176c33a7456bb84035de78552d22dMarc Blank * Gets all of the values in a sequence set per RFC 3501. Any ranges are expanded into a 605c523858385176c33a7456bb84035de78552d22dMarc Blank * list of individual numbers. If the set is invalid, an empty array is returned. 615c523858385176c33a7456bb84035de78552d22dMarc Blank * <pre> 625c523858385176c33a7456bb84035de78552d22dMarc Blank * sequence-number = nz-number / "*" 635c523858385176c33a7456bb84035de78552d22dMarc Blank * sequence-range = sequence-number ":" sequence-number 645c523858385176c33a7456bb84035de78552d22dMarc Blank * sequence-set = (sequence-number / sequence-range) *("," sequence-set) 655c523858385176c33a7456bb84035de78552d22dMarc Blank * </pre> 665c523858385176c33a7456bb84035de78552d22dMarc Blank */ 675c523858385176c33a7456bb84035de78552d22dMarc Blank public static String[] getImapSequenceValues(String set) { 685c523858385176c33a7456bb84035de78552d22dMarc Blank ArrayList<String> list = new ArrayList<String>(); 695c523858385176c33a7456bb84035de78552d22dMarc Blank if (set != null) { 705c523858385176c33a7456bb84035de78552d22dMarc Blank String[] setItems = set.split(","); 715c523858385176c33a7456bb84035de78552d22dMarc Blank for (String item : setItems) { 725c523858385176c33a7456bb84035de78552d22dMarc Blank if (item.indexOf(':') == -1) { 735c523858385176c33a7456bb84035de78552d22dMarc Blank // simple item 745c523858385176c33a7456bb84035de78552d22dMarc Blank try { 755c523858385176c33a7456bb84035de78552d22dMarc Blank Integer.parseInt(item); // Don't need the value; just ensure it's valid 765c523858385176c33a7456bb84035de78552d22dMarc Blank list.add(item); 775c523858385176c33a7456bb84035de78552d22dMarc Blank } catch (NumberFormatException e) { 78560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.d(Logging.LOG_TAG, "Invalid UID value", e); 795c523858385176c33a7456bb84035de78552d22dMarc Blank } 805c523858385176c33a7456bb84035de78552d22dMarc Blank } else { 815c523858385176c33a7456bb84035de78552d22dMarc Blank // range 825c523858385176c33a7456bb84035de78552d22dMarc Blank for (String rangeItem : getImapRangeValues(item)) { 835c523858385176c33a7456bb84035de78552d22dMarc Blank list.add(rangeItem); 845c523858385176c33a7456bb84035de78552d22dMarc Blank } 855c523858385176c33a7456bb84035de78552d22dMarc Blank } 865c523858385176c33a7456bb84035de78552d22dMarc Blank } 875c523858385176c33a7456bb84035de78552d22dMarc Blank } 885c523858385176c33a7456bb84035de78552d22dMarc Blank String[] stringList = new String[list.size()]; 895c523858385176c33a7456bb84035de78552d22dMarc Blank return list.toArray(stringList); 905c523858385176c33a7456bb84035de78552d22dMarc Blank } 915c523858385176c33a7456bb84035de78552d22dMarc Blank 925c523858385176c33a7456bb84035de78552d22dMarc Blank /** 935c523858385176c33a7456bb84035de78552d22dMarc Blank * Expand the given number range into a list of individual numbers. If the range is not valid, 945c523858385176c33a7456bb84035de78552d22dMarc Blank * an empty array is returned. 955c523858385176c33a7456bb84035de78552d22dMarc Blank * <pre> 965c523858385176c33a7456bb84035de78552d22dMarc Blank * sequence-number = nz-number / "*" 975c523858385176c33a7456bb84035de78552d22dMarc Blank * sequence-range = sequence-number ":" sequence-number 985c523858385176c33a7456bb84035de78552d22dMarc Blank * sequence-set = (sequence-number / sequence-range) *("," sequence-set) 995c523858385176c33a7456bb84035de78552d22dMarc Blank * </pre> 1005c523858385176c33a7456bb84035de78552d22dMarc Blank */ 1015c523858385176c33a7456bb84035de78552d22dMarc Blank public static String[] getImapRangeValues(String range) { 1025c523858385176c33a7456bb84035de78552d22dMarc Blank ArrayList<String> list = new ArrayList<String>(); 1035c523858385176c33a7456bb84035de78552d22dMarc Blank try { 1045c523858385176c33a7456bb84035de78552d22dMarc Blank if (range != null) { 1055c523858385176c33a7456bb84035de78552d22dMarc Blank int colonPos = range.indexOf(':'); 1065c523858385176c33a7456bb84035de78552d22dMarc Blank if (colonPos > 0) { 1075c523858385176c33a7456bb84035de78552d22dMarc Blank int first = Integer.parseInt(range.substring(0, colonPos)); 1085c523858385176c33a7456bb84035de78552d22dMarc Blank int second = Integer.parseInt(range.substring(colonPos + 1)); 1095c523858385176c33a7456bb84035de78552d22dMarc Blank if (first < second) { 1105c523858385176c33a7456bb84035de78552d22dMarc Blank for (int i = first; i <= second; i++) { 1115c523858385176c33a7456bb84035de78552d22dMarc Blank list.add(Integer.toString(i)); 1125c523858385176c33a7456bb84035de78552d22dMarc Blank } 1135c523858385176c33a7456bb84035de78552d22dMarc Blank } else { 1145c523858385176c33a7456bb84035de78552d22dMarc Blank for (int i = first; i >= second; i--) { 1155c523858385176c33a7456bb84035de78552d22dMarc Blank list.add(Integer.toString(i)); 1165c523858385176c33a7456bb84035de78552d22dMarc Blank } 1175c523858385176c33a7456bb84035de78552d22dMarc Blank } 1185c523858385176c33a7456bb84035de78552d22dMarc Blank } 1195c523858385176c33a7456bb84035de78552d22dMarc Blank } 1205c523858385176c33a7456bb84035de78552d22dMarc Blank } catch (NumberFormatException e) { 121560bfadc3151f7a06f3b06e9a6c92cfa534c63ecScott Kennedy LogUtils.d(Logging.LOG_TAG, "Invalid range value", e); 1225c523858385176c33a7456bb84035de78552d22dMarc Blank } 1235c523858385176c33a7456bb84035de78552d22dMarc Blank String[] stringList = new String[list.size()]; 1245c523858385176c33a7456bb84035de78552d22dMarc Blank return list.toArray(stringList); 1255c523858385176c33a7456bb84035de78552d22dMarc Blank } 1265c523858385176c33a7456bb84035de78552d22dMarc Blank} 127