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