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 17 package android.net.sip; 18 19 import android.os.Parcel; 20 import android.os.Parcelable; 21 import android.text.TextUtils; 22 23 import java.io.ObjectStreamException; 24 import java.io.Serializable; 25 import java.text.ParseException; 26 import javax.sip.InvalidArgumentException; 27 import javax.sip.ListeningPoint; 28 import javax.sip.PeerUnavailableException; 29 import javax.sip.SipFactory; 30 import javax.sip.address.Address; 31 import javax.sip.address.AddressFactory; 32 import javax.sip.address.SipURI; 33 import 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 */ 41 public 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 authentication username of the profile 154 * @return this builder object 155 */ 156 public Builder setAuthUserName(String name) { 157 mProfile.mAuthUserName = name; 158 return this; 159 } 160 161 /** 162 * Sets the name of the profile. This name is given by user. 163 * 164 * @param name name of the profile 165 * @return this builder object 166 */ 167 public Builder setProfileName(String name) { 168 mProfile.mProfileName = name; 169 return this; 170 } 171 172 /** 173 * Sets the password of the SIP account 174 * 175 * @param password password of the SIP account 176 * @return this builder object 177 */ 178 public Builder setPassword(String password) { 179 mUri.setUserPassword(password); 180 return this; 181 } 182 183 /** 184 * Sets the port number of the server. By default, it is 5060. 185 * 186 * @param port port number of the server 187 * @return this builder object 188 * @throws IllegalArgumentException if the port number is out of range 189 */ 190 public Builder setPort(int port) throws IllegalArgumentException { 191 if ((port > 65535) || (port < 1000)) { 192 throw new IllegalArgumentException("incorrect port arugment: " + port); 193 } 194 mProfile.mPort = port; 195 return this; 196 } 197 198 /** 199 * Sets the protocol used to connect to the SIP server. Currently, 200 * only "UDP" and "TCP" are supported. 201 * 202 * @param protocol the protocol string 203 * @return this builder object 204 * @throws IllegalArgumentException if the protocol is not recognized 205 */ 206 public Builder setProtocol(String protocol) 207 throws IllegalArgumentException { 208 if (protocol == null) { 209 throw new NullPointerException("protocol cannot be null"); 210 } 211 protocol = protocol.toUpperCase(); 212 if (!protocol.equals(UDP) && !protocol.equals(TCP)) { 213 throw new IllegalArgumentException( 214 "unsupported protocol: " + protocol); 215 } 216 mProfile.mProtocol = protocol; 217 return this; 218 } 219 220 /** 221 * Sets the outbound proxy of the SIP server. 222 * 223 * @param outboundProxy the network address of the outbound proxy 224 * @return this builder object 225 */ 226 public Builder setOutboundProxy(String outboundProxy) { 227 mProxyAddress = outboundProxy; 228 return this; 229 } 230 231 /** 232 * Sets the display name of the user. 233 * 234 * @param displayName display name of the user 235 * @return this builder object 236 */ 237 public Builder setDisplayName(String displayName) { 238 mDisplayName = displayName; 239 return this; 240 } 241 242 /** 243 * Sets the send keep-alive flag. 244 * 245 * @param flag true if sending keep-alive message is required, 246 * false otherwise 247 * @return this builder object 248 */ 249 public Builder setSendKeepAlive(boolean flag) { 250 mProfile.mSendKeepAlive = flag; 251 return this; 252 } 253 254 255 /** 256 * Sets the auto. registration flag. 257 * 258 * @param flag true if the profile will be registered automatically, 259 * false otherwise 260 * @return this builder object 261 */ 262 public Builder setAutoRegistration(boolean flag) { 263 mProfile.mAutoRegistration = flag; 264 return this; 265 } 266 267 /** 268 * Builds and returns the SIP profile object. 269 * 270 * @return the profile object created 271 */ 272 public SipProfile build() { 273 // remove password from URI 274 mProfile.mPassword = mUri.getUserPassword(); 275 mUri.setUserPassword(null); 276 try { 277 if (!TextUtils.isEmpty(mProxyAddress)) { 278 SipURI uri = (SipURI) 279 mAddressFactory.createURI(fix(mProxyAddress)); 280 mProfile.mProxyAddress = uri.getHost(); 281 } else { 282 if (!mProfile.mProtocol.equals(UDP)) { 283 mUri.setTransportParam(mProfile.mProtocol); 284 } 285 if (mProfile.mPort != DEFAULT_PORT) { 286 mUri.setPort(mProfile.mPort); 287 } 288 } 289 mProfile.mAddress = mAddressFactory.createAddress( 290 mDisplayName, mUri); 291 } catch (InvalidArgumentException e) { 292 throw new RuntimeException(e); 293 } catch (ParseException e) { 294 // must not occur 295 throw new RuntimeException(e); 296 } 297 return mProfile; 298 } 299 } 300 301 private SipProfile() { 302 } 303 304 private SipProfile(Parcel in) { 305 mAddress = (Address) in.readSerializable(); 306 mProxyAddress = in.readString(); 307 mPassword = in.readString(); 308 mDomain = in.readString(); 309 mProtocol = in.readString(); 310 mProfileName = in.readString(); 311 mSendKeepAlive = (in.readInt() == 0) ? false : true; 312 mAutoRegistration = (in.readInt() == 0) ? false : true; 313 mCallingUid = in.readInt(); 314 mPort = in.readInt(); 315 mAuthUserName = in.readString(); 316 } 317 318 @Override 319 public void writeToParcel(Parcel out, int flags) { 320 out.writeSerializable(mAddress); 321 out.writeString(mProxyAddress); 322 out.writeString(mPassword); 323 out.writeString(mDomain); 324 out.writeString(mProtocol); 325 out.writeString(mProfileName); 326 out.writeInt(mSendKeepAlive ? 1 : 0); 327 out.writeInt(mAutoRegistration ? 1 : 0); 328 out.writeInt(mCallingUid); 329 out.writeInt(mPort); 330 out.writeString(mAuthUserName); 331 } 332 333 @Override 334 public int describeContents() { 335 return 0; 336 } 337 338 /** 339 * Gets the SIP URI of this profile. 340 * 341 * @return the SIP URI of this profile 342 * @hide 343 */ 344 public SipURI getUri() { 345 return (SipURI) mAddress.getURI(); 346 } 347 348 /** 349 * Gets the SIP URI string of this profile. 350 * 351 * @return the SIP URI string of this profile 352 */ 353 public String getUriString() { 354 // We need to return the sip uri domain instead of 355 // the SIP URI with transport, port information if 356 // the outbound proxy address exists. 357 if (!TextUtils.isEmpty(mProxyAddress)) { 358 return "sip:" + getUserName() + "@" + mDomain; 359 } 360 return getUri().toString(); 361 } 362 363 /** 364 * Gets the SIP address of this profile. 365 * 366 * @return the SIP address of this profile 367 * @hide 368 */ 369 public Address getSipAddress() { 370 return mAddress; 371 } 372 373 /** 374 * Gets the display name of the user. 375 * 376 * @return the display name of the user 377 */ 378 public String getDisplayName() { 379 return mAddress.getDisplayName(); 380 } 381 382 /** 383 * Gets the username. 384 * 385 * @return the username 386 */ 387 public String getUserName() { 388 return getUri().getUser(); 389 } 390 391 /** 392 * Gets the username for authentication. If it is null, then the username 393 * is used in authentication instead. 394 * 395 * @return the authentication username 396 * @see #getUserName 397 */ 398 public String getAuthUserName() { 399 return mAuthUserName; 400 } 401 402 /** 403 * Gets the password. 404 * 405 * @return the password 406 */ 407 public String getPassword() { 408 return mPassword; 409 } 410 411 /** 412 * Gets the SIP domain. 413 * 414 * @return the SIP domain 415 */ 416 public String getSipDomain() { 417 return mDomain; 418 } 419 420 /** 421 * Gets the port number of the SIP server. 422 * 423 * @return the port number of the SIP server 424 */ 425 public int getPort() { 426 return mPort; 427 } 428 429 /** 430 * Gets the protocol used to connect to the server. 431 * 432 * @return the protocol 433 */ 434 public String getProtocol() { 435 return mProtocol; 436 } 437 438 /** 439 * Gets the network address of the server outbound proxy. 440 * 441 * @return the network address of the server outbound proxy 442 */ 443 public String getProxyAddress() { 444 return mProxyAddress; 445 } 446 447 /** 448 * Gets the (user-defined) name of the profile. 449 * 450 * @return name of the profile 451 */ 452 public String getProfileName() { 453 return mProfileName; 454 } 455 456 /** 457 * Gets the flag of 'Sending keep-alive'. 458 * 459 * @return the flag of sending SIP keep-alive messages. 460 */ 461 public boolean getSendKeepAlive() { 462 return mSendKeepAlive; 463 } 464 465 /** 466 * Gets the flag of 'Auto Registration'. 467 * 468 * @return the flag of registering the profile automatically. 469 */ 470 public boolean getAutoRegistration() { 471 return mAutoRegistration; 472 } 473 474 /** 475 * Sets the calling process's Uid in the sip service. 476 * @hide 477 */ 478 public void setCallingUid(int uid) { 479 mCallingUid = uid; 480 } 481 482 /** 483 * Gets the calling process's Uid in the sip settings. 484 * @hide 485 */ 486 public int getCallingUid() { 487 return mCallingUid; 488 } 489 490 private Object readResolve() throws ObjectStreamException { 491 // For compatibility. 492 if (mPort == 0) mPort = DEFAULT_PORT; 493 return this; 494 } 495 } 496