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