1/* 2 * Copyright (C) 2010 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 android.net.sip; 18 19import android.os.Parcel; 20import android.os.Parcelable; 21import android.text.TextUtils; 22 23import java.io.ObjectStreamException; 24import java.io.Serializable; 25import java.text.ParseException; 26import javax.sip.InvalidArgumentException; 27import javax.sip.ListeningPoint; 28import javax.sip.PeerUnavailableException; 29import javax.sip.SipFactory; 30import javax.sip.address.Address; 31import javax.sip.address.AddressFactory; 32import javax.sip.address.SipURI; 33import javax.sip.address.URI; 34 35/** 36 * Defines a SIP profile, including a SIP account, domain and server information. 37 * <p>You can create a {@link SipProfile} using {@link 38 * SipProfile.Builder}. You can also retrieve one from a {@link SipSession}, using {@link 39 * SipSession#getLocalProfile} and {@link SipSession#getPeerProfile}.</p> 40 */ 41public class SipProfile implements Parcelable, Serializable, Cloneable { 42 private static final long serialVersionUID = 1L; 43 private static final int DEFAULT_PORT = 5060; 44 private static final String TCP = "TCP"; 45 private static final String UDP = "UDP"; 46 private Address mAddress; 47 private String mProxyAddress; 48 private String mPassword; 49 private String mDomain; 50 private String mProtocol = UDP; 51 private String mProfileName; 52 private String mAuthUserName; 53 private int mPort = DEFAULT_PORT; 54 private boolean mSendKeepAlive = false; 55 private boolean mAutoRegistration = true; 56 private transient int mCallingUid = 0; 57 58 public static final Parcelable.Creator<SipProfile> CREATOR = 59 new Parcelable.Creator<SipProfile>() { 60 public SipProfile createFromParcel(Parcel in) { 61 return new SipProfile(in); 62 } 63 64 public SipProfile[] newArray(int size) { 65 return new SipProfile[size]; 66 } 67 }; 68 69 /** 70 * Helper class for creating a {@link SipProfile}. 71 */ 72 public static class Builder { 73 private AddressFactory mAddressFactory; 74 private SipProfile mProfile = new SipProfile(); 75 private SipURI mUri; 76 private String mDisplayName; 77 private String mProxyAddress; 78 79 { 80 try { 81 mAddressFactory = 82 SipFactory.getInstance().createAddressFactory(); 83 } catch (PeerUnavailableException e) { 84 throw new RuntimeException(e); 85 } 86 } 87 88 /** 89 * Creates a builder based on the given profile. 90 */ 91 public Builder(SipProfile profile) { 92 if (profile == null) throw new NullPointerException(); 93 try { 94 mProfile = (SipProfile) profile.clone(); 95 } catch (CloneNotSupportedException e) { 96 throw new RuntimeException("should not occur", e); 97 } 98 mProfile.mAddress = null; 99 mUri = profile.getUri(); 100 mUri.setUserPassword(profile.getPassword()); 101 mDisplayName = profile.getDisplayName(); 102 mProxyAddress = profile.getProxyAddress(); 103 mProfile.mPort = profile.getPort(); 104 } 105 106 /** 107 * Constructor. 108 * 109 * @param uriString the URI string as "sip:<user_name>@<domain>" 110 * @throws ParseException if the string is not a valid URI 111 */ 112 public Builder(String uriString) throws ParseException { 113 if (uriString == null) { 114 throw new NullPointerException("uriString cannot be null"); 115 } 116 URI uri = mAddressFactory.createURI(fix(uriString)); 117 if (uri instanceof SipURI) { 118 mUri = (SipURI) uri; 119 } else { 120 throw new ParseException(uriString + " is not a SIP URI", 0); 121 } 122 mProfile.mDomain = mUri.getHost(); 123 } 124 125 /** 126 * Constructor. 127 * 128 * @param username username of the SIP account 129 * @param serverDomain the SIP server domain; if the network address 130 * is different from the domain, use {@link #setOutboundProxy} to 131 * set server address 132 * @throws ParseException if the parameters are not valid 133 */ 134 public Builder(String username, String serverDomain) 135 throws ParseException { 136 if ((username == null) || (serverDomain == null)) { 137 throw new NullPointerException( 138 "username and serverDomain cannot be null"); 139 } 140 mUri = mAddressFactory.createSipURI(username, serverDomain); 141 mProfile.mDomain = serverDomain; 142 } 143 144 private String fix(String uriString) { 145 return (uriString.trim().toLowerCase().startsWith("sip:") 146 ? uriString 147 : "sip:" + uriString); 148 } 149 150 /** 151 * Sets the username used for authentication. 152 * 153 * @param name auth. name of the profile 154 * @return this builder object 155 * @hide // TODO: remove when we make it public 156 */ 157 public Builder setAuthUserName(String name) { 158 mProfile.mAuthUserName = name; 159 return this; 160 } 161 162 /** 163 * Sets the name of the profile. This name is given by user. 164 * 165 * @param name name of the profile 166 * @return this builder object 167 */ 168 public Builder setProfileName(String name) { 169 mProfile.mProfileName = name; 170 return this; 171 } 172 173 /** 174 * Sets the password of the SIP account 175 * 176 * @param password password of the SIP account 177 * @return this builder object 178 */ 179 public Builder setPassword(String password) { 180 mUri.setUserPassword(password); 181 return this; 182 } 183 184 /** 185 * Sets the port number of the server. By default, it is 5060. 186 * 187 * @param port port number of the server 188 * @return this builder object 189 * @throws IllegalArgumentException if the port number is out of range 190 */ 191 public Builder setPort(int port) throws IllegalArgumentException { 192 if ((port > 65535) || (port < 1000)) { 193 throw new IllegalArgumentException("incorrect port arugment: " + port); 194 } 195 mProfile.mPort = port; 196 return this; 197 } 198 199 /** 200 * Sets the protocol used to connect to the SIP server. Currently, 201 * only "UDP" and "TCP" are supported. 202 * 203 * @param protocol the protocol string 204 * @return this builder object 205 * @throws IllegalArgumentException if the protocol is not recognized 206 */ 207 public Builder setProtocol(String protocol) 208 throws IllegalArgumentException { 209 if (protocol == null) { 210 throw new NullPointerException("protocol cannot be null"); 211 } 212 protocol = protocol.toUpperCase(); 213 if (!protocol.equals(UDP) && !protocol.equals(TCP)) { 214 throw new IllegalArgumentException( 215 "unsupported protocol: " + protocol); 216 } 217 mProfile.mProtocol = protocol; 218 return this; 219 } 220 221 /** 222 * Sets the outbound proxy of the SIP server. 223 * 224 * @param outboundProxy the network address of the outbound proxy 225 * @return this builder object 226 */ 227 public Builder setOutboundProxy(String outboundProxy) { 228 mProxyAddress = outboundProxy; 229 return this; 230 } 231 232 /** 233 * Sets the display name of the user. 234 * 235 * @param displayName display name of the user 236 * @return this builder object 237 */ 238 public Builder setDisplayName(String displayName) { 239 mDisplayName = displayName; 240 return this; 241 } 242 243 /** 244 * Sets the send keep-alive flag. 245 * 246 * @param flag true if sending keep-alive message is required, 247 * false otherwise 248 * @return this builder object 249 */ 250 public Builder setSendKeepAlive(boolean flag) { 251 mProfile.mSendKeepAlive = flag; 252 return this; 253 } 254 255 256 /** 257 * Sets the auto. registration flag. 258 * 259 * @param flag true if the profile will be registered automatically, 260 * false otherwise 261 * @return this builder object 262 */ 263 public Builder setAutoRegistration(boolean flag) { 264 mProfile.mAutoRegistration = flag; 265 return this; 266 } 267 268 /** 269 * Builds and returns the SIP profile object. 270 * 271 * @return the profile object created 272 */ 273 public SipProfile build() { 274 // remove password from URI 275 mProfile.mPassword = mUri.getUserPassword(); 276 mUri.setUserPassword(null); 277 try { 278 if (!TextUtils.isEmpty(mProxyAddress)) { 279 SipURI uri = (SipURI) 280 mAddressFactory.createURI(fix(mProxyAddress)); 281 mProfile.mProxyAddress = uri.getHost(); 282 } else { 283 if (!mProfile.mProtocol.equals(UDP)) { 284 mUri.setTransportParam(mProfile.mProtocol); 285 } 286 if (mProfile.mPort != DEFAULT_PORT) { 287 mUri.setPort(mProfile.mPort); 288 } 289 } 290 mProfile.mAddress = mAddressFactory.createAddress( 291 mDisplayName, mUri); 292 } catch (InvalidArgumentException e) { 293 throw new RuntimeException(e); 294 } catch (ParseException e) { 295 // must not occur 296 throw new RuntimeException(e); 297 } 298 return mProfile; 299 } 300 } 301 302 private SipProfile() { 303 } 304 305 private SipProfile(Parcel in) { 306 mAddress = (Address) in.readSerializable(); 307 mProxyAddress = in.readString(); 308 mPassword = in.readString(); 309 mDomain = in.readString(); 310 mProtocol = in.readString(); 311 mProfileName = in.readString(); 312 mSendKeepAlive = (in.readInt() == 0) ? false : true; 313 mAutoRegistration = (in.readInt() == 0) ? false : true; 314 mCallingUid = in.readInt(); 315 mPort = in.readInt(); 316 mAuthUserName = in.readString(); 317 } 318 319 @Override 320 public void writeToParcel(Parcel out, int flags) { 321 out.writeSerializable(mAddress); 322 out.writeString(mProxyAddress); 323 out.writeString(mPassword); 324 out.writeString(mDomain); 325 out.writeString(mProtocol); 326 out.writeString(mProfileName); 327 out.writeInt(mSendKeepAlive ? 1 : 0); 328 out.writeInt(mAutoRegistration ? 1 : 0); 329 out.writeInt(mCallingUid); 330 out.writeInt(mPort); 331 out.writeString(mAuthUserName); 332 } 333 334 @Override 335 public int describeContents() { 336 return 0; 337 } 338 339 /** 340 * Gets the SIP URI of this profile. 341 * 342 * @return the SIP URI of this profile 343 * @hide 344 */ 345 public SipURI getUri() { 346 return (SipURI) mAddress.getURI(); 347 } 348 349 /** 350 * Gets the SIP URI string of this profile. 351 * 352 * @return the SIP URI string of this profile 353 */ 354 public String getUriString() { 355 // We need to return the sip uri domain instead of 356 // the SIP URI with transport, port information if 357 // the outbound proxy address exists. 358 if (!TextUtils.isEmpty(mProxyAddress)) { 359 return "sip:" + getUserName() + "@" + mDomain; 360 } 361 return getUri().toString(); 362 } 363 364 /** 365 * Gets the SIP address of this profile. 366 * 367 * @return the SIP address of this profile 368 * @hide 369 */ 370 public Address getSipAddress() { 371 return mAddress; 372 } 373 374 /** 375 * Gets the display name of the user. 376 * 377 * @return the display name of the user 378 */ 379 public String getDisplayName() { 380 return mAddress.getDisplayName(); 381 } 382 383 /** 384 * Gets the username. 385 * 386 * @return the username 387 */ 388 public String getUserName() { 389 return getUri().getUser(); 390 } 391 392 /** 393 * Gets the username for authentication. If it is null, then the username 394 * should be used in authentication instead. 395 * 396 * @return the auth. username 397 * @hide // TODO: remove when we make it public 398 */ 399 public String getAuthUserName() { 400 return mAuthUserName; 401 } 402 403 /** 404 * Gets the password. 405 * 406 * @return the password 407 */ 408 public String getPassword() { 409 return mPassword; 410 } 411 412 /** 413 * Gets the SIP domain. 414 * 415 * @return the SIP domain 416 */ 417 public String getSipDomain() { 418 return mDomain; 419 } 420 421 /** 422 * Gets the port number of the SIP server. 423 * 424 * @return the port number of the SIP server 425 */ 426 public int getPort() { 427 return mPort; 428 } 429 430 /** 431 * Gets the protocol used to connect to the server. 432 * 433 * @return the protocol 434 */ 435 public String getProtocol() { 436 return mProtocol; 437 } 438 439 /** 440 * Gets the network address of the server outbound proxy. 441 * 442 * @return the network address of the server outbound proxy 443 */ 444 public String getProxyAddress() { 445 return mProxyAddress; 446 } 447 448 /** 449 * Gets the (user-defined) name of the profile. 450 * 451 * @return name of the profile 452 */ 453 public String getProfileName() { 454 return mProfileName; 455 } 456 457 /** 458 * Gets the flag of 'Sending keep-alive'. 459 * 460 * @return the flag of sending SIP keep-alive messages. 461 */ 462 public boolean getSendKeepAlive() { 463 return mSendKeepAlive; 464 } 465 466 /** 467 * Gets the flag of 'Auto Registration'. 468 * 469 * @return the flag of registering the profile automatically. 470 */ 471 public boolean getAutoRegistration() { 472 return mAutoRegistration; 473 } 474 475 /** 476 * Sets the calling process's Uid in the sip service. 477 * @hide 478 */ 479 public void setCallingUid(int uid) { 480 mCallingUid = uid; 481 } 482 483 /** 484 * Gets the calling process's Uid in the sip settings. 485 * @hide 486 */ 487 public int getCallingUid() { 488 return mCallingUid; 489 } 490 491 private Object readResolve() throws ObjectStreamException { 492 // For compatibility. 493 if (mPort == 0) mPort = DEFAULT_PORT; 494 return this; 495 } 496} 497