1/* 2 * Copyright (C) 2007-2008 Esmertec AG. 3 * Copyright (C) 2007-2008 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package com.android.im.imps; 19 20import android.os.Parcel; 21 22import com.android.im.engine.Address; 23import com.android.im.engine.ImEntity; 24 25/** 26 * The abstract representation of an IMPS address. 27 */ 28public abstract class ImpsAddress extends Address { 29 private static final char[] SPECIALS = {'/', '@', '+'}; 30 31 protected String mUser; 32 protected String mResource; 33 protected String mDomain; 34 35 private String mFullAddress; 36 37 protected ImpsAddress() { 38 } 39 40 protected ImpsAddress(String user, String resource, String domain) { 41 // build the full address and unify the fields to lower case since imps 42 // address is case insensitive. 43 StringBuilder buf = new StringBuilder(ImpsConstants.ADDRESS_PREFIX); 44 if(user != null) { 45 buf.append(user.toLowerCase()); 46 } 47 if(resource != null) { 48 buf.append('/').append(resource.toLowerCase()); 49 } 50 if(domain != null) { 51 buf.append('@').append(domain.toLowerCase()); 52 } 53 mFullAddress = buf.toString(); 54 mUser = user; 55 mResource = resource; 56 mDomain = domain; 57 verifyAddress(); 58 } 59 60 protected ImpsAddress(String full){ 61 this(full, true); 62 } 63 64 protected ImpsAddress(String full, boolean verify) { 65 if (full == null || full.length() == 0) { 66 throw new IllegalArgumentException(); 67 } 68 69 //TODO: escape reserved characters. 70 if(!full.startsWith(ImpsConstants.ADDRESS_PREFIX)) { 71 full = ImpsConstants.ADDRESS_PREFIX + full; 72 } 73 74 parse(full); 75 mFullAddress = full; 76 77 if (verify) { 78 verifyAddress(); 79 } 80 } 81 82 private void parse(String full) { 83 mUser = parseUser(full); 84 mResource = parseResource(full); 85 mDomain = parseDomain(full); 86 } 87 88 private void verifyAddress() throws IllegalArgumentException { 89 ImpsLog.log("verifyAddress:" + mUser + ", " + mResource + ", " + mDomain); 90 if(mUser == null && mResource == null) { 91 throw new IllegalArgumentException(); 92 } 93 94 if(mUser != null) { 95 if(mUser.length() == 0) { 96 throw new IllegalArgumentException("Invalid user"); 97 } 98 if(mUser.charAt(0) == '+') {//mobile number 99 for(int i = 1; i < mUser.length(); i++) { 100 if(!Character.isDigit(mUser.charAt(i))) { 101 throw new IllegalArgumentException("Invalid user"); 102 } 103 } 104 } else if(!isAlphaSequence(mUser)) { 105 throw new IllegalArgumentException("Invalid user"); 106 } 107 } 108 109 if(mResource != null && !isAlphaSequence(mResource)) { 110 throw new IllegalArgumentException("Invalid resource"); 111 } 112 if(mDomain != null && !isAlphaSequence(mDomain)) { 113 throw new IllegalArgumentException("Invalid domain"); 114 } 115 } 116 117 /** 118 * Gets the User-part of the address which refers to the identification of 119 * the IMPS user. 120 * 121 * @return the User-part of the address. 122 */ 123 public String getUser() { 124 return mUser; 125 } 126 127 /** 128 * Gets the Resource-part of the address which identifies the referred 129 * public or private resource. 130 * 131 * @return the Resource-part of the address. 132 */ 133 public String getResource() { 134 return mResource; 135 } 136 137 /** 138 * Gets the Domain-part of the address which identifies the IMPS server 139 * domain. 140 * 141 * @return the Domain-part of the address. 142 */ 143 public String getDomain() { 144 return mDomain; 145 } 146 147 /** 148 * Gets the full string representation of the address. 149 */ 150 @Override 151 public String getFullName() { 152 return mFullAddress; 153 } 154 155 @Override 156 public void writeToParcel(Parcel dest) { 157 dest.writeString(mFullAddress); 158 } 159 160 @Override 161 public void readFromParcel(Parcel source) { 162 mFullAddress = source.readString(); 163 parse(mFullAddress); 164 } 165 166 @Override 167 public boolean equals(Object other) { 168 return other instanceof ImpsAddress 169 && mFullAddress.equalsIgnoreCase(((ImpsAddress)other).mFullAddress); 170 } 171 172 @Override 173 public int hashCode() { 174 return mFullAddress.toLowerCase().hashCode(); 175 } 176 177 /** 178 * Formats the address to a PrimitiveElement which can be used as the 179 * content of Sender or Recipient. 180 * 181 * @return a PrimitiveElement. 182 */ 183 public abstract PrimitiveElement toPrimitiveElement(); 184 185 /** 186 * Gets the entity this address object refers to. 187 * 188 * @param connection 189 * @return the entity this address refers to or <code>null</code> if the 190 * entity not found. 191 */ 192 abstract ImEntity getEntity(ImpsConnection connection); 193 194 /** 195 * Constructs an ImpsAddress from the Sender or Recipient element in a 196 * primitive. 197 * 198 * @param elem the Sender of Recipient element. 199 * @return the ImpsAddress object or <code>null</code> if it's not a valid 200 * element. 201 */ 202 public static ImpsAddress fromPrimitiveElement(PrimitiveElement elem) { 203 String type = elem.getTagName(); 204 if(ImpsTags.User.equals(type)) { 205 return new ImpsUserAddress(elem.getChildContents(ImpsTags.UserID), false); 206 } else if(ImpsTags.Group.equals(type)) { 207 PrimitiveElement child = elem.getFirstChild(); 208 if(child == null) { 209 throw new IllegalArgumentException(); 210 } 211 if(ImpsTags.GroupID.equals(child.getTagName())){ 212 return new ImpsGroupAddress(child.getContents()); 213 } else { 214 String screeName = child.getChildContents(ImpsTags.SName); 215 String groupId = child.getChildContents(ImpsTags.GroupID); 216 return new ImpsGroupAddress(groupId, screeName); 217 } 218 } else if(ImpsTags.ContactList.equals(type)) { 219 return new ImpsContactListAddress(elem.getContents(), false); 220 } else { 221 throw new IllegalArgumentException(); 222 } 223 } 224 225 private String parseUser(String full) { 226 int index = full.indexOf('/'); 227 if(index == 3) { 228 return null; 229 } 230 if (index == -1) { 231 index = full.lastIndexOf('@'); 232 } 233 if (index == -1) { 234 index = full.length(); 235 } 236 return full.substring(3, index); 237 } 238 239 private String parseResource(String full) { 240 int beginIndex = full.indexOf('/'); 241 if (beginIndex == -1) { 242 return null; 243 } 244 int endIndex = full.lastIndexOf('@'); 245 if (endIndex == -1 || endIndex < beginIndex) { 246 endIndex = full.length(); 247 } 248 return full.substring(beginIndex + 1, endIndex); 249 } 250 251 private String parseDomain(String full) { 252 int beginIndex = full.lastIndexOf('@'); 253 return beginIndex == -1 ? null : full.substring(beginIndex + 1); 254 } 255 256 private boolean isAlphaSequence(String str) { 257 for(int i = 0; i < str.length(); i++) { 258 char ch = str.charAt(i); 259 if(ch < 32 || ch > 126 || isSpecial(ch)) { 260 return false; 261 } 262 } 263 return true; 264 } 265 266 private boolean isSpecial(char ch) { 267 for (char element : SPECIALS) { 268 if(ch == element) { 269 return true; 270 } 271 } 272 return false; 273 } 274} 275