content: /*
   * Copyright (C) 2010 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.net.sip;
  
  import android.os.Parcel;
  import android.os.Parcelable;
  import android.text.TextUtils;
  
  import java.io.ObjectStreamException;
  import java.io.Serializable;
  import java.text.ParseException;
  import javax.sip.InvalidArgumentException;
  import javax.sip.ListeningPoint;
  import javax.sip.PeerUnavailableException;
  import javax.sip.SipFactory;
  import javax.sip.address.Address;
  import javax.sip.address.AddressFactory;
  import javax.sip.address.SipURI;
  import javax.sip.address.URI;
  
  /**
   * Defines a SIP profile, including a SIP account, domain and server information.
   * <p>You can create a {@link SipProfile} using {@link
   * SipProfile.Builder}. You can also retrieve one from a {@link SipSession}, using {@link
   * SipSession#getLocalProfile} and {@link SipSession#getPeerProfile}.</p>
   *
   * <div class="special reference">
   * <h3>Developer Guides</h3>
   * <p>For more information about using SIP, read the
   * <a href="{@docRoot}guide/topics/network/sip.html">Session Initiation Protocol</a>
   * developer guide.</p>
   * </div>
   */
  public class SipProfile implements Parcelable, Serializable, Cloneable {
      private static final long serialVersionUID = 1L;
      private static final int DEFAULT_PORT = 5060;
      private static final String TCP = "TCP";
      private static final String UDP = "UDP";
      private Address mAddress;
      private String mProxyAddress;
      private String mPassword;
      private String mDomain;
      private String mProtocol = UDP;
      private String mProfileName;
      private String mAuthUserName;
      private int mPort = DEFAULT_PORT;
      private boolean mSendKeepAlive = false;
      private boolean mAutoRegistration = true;
      private transient int mCallingUid = 0;
  
      public static final Parcelable.Creator<SipProfile> CREATOR =
              new Parcelable.Creator<SipProfile>() {
                  public SipProfile createFromParcel(Parcel in) {
                      return new SipProfile(in);
                  }
  
                  public SipProfile[] newArray(int size) {
                      return new SipProfile[size];
                  }
              };
  
      /**
       * Helper class for creating a {@link SipProfile}.
       */
      public static class Builder {
          private AddressFactory mAddressFactory;
          private SipProfile mProfile = new SipProfile();
          private SipURI mUri;
          private String mDisplayName;
          private String mProxyAddress;
  
          {
              try {
                  mAddressFactory =
                          SipFactory.getInstance().createAddressFactory();
              } catch (PeerUnavailableException e) {
                  throw new RuntimeException(e);
              }
          }
  
          /**
           * Creates a builder based on the given profile.
           */
          public Builder(SipProfile profile) {
              if (profile == null) throw new NullPointerException();
              try {
                  mProfile = (SipProfile) profile.clone();
              } catch (CloneNotSupportedException e) {
                  throw new RuntimeException("should not occur", e);
              }
              mProfile.mAddress = null;
              mUri = profile.getUri();
              mUri.setUserPassword(profile.getPassword());
              mDisplayName = profile.getDisplayName();
              mProxyAddress = profile.getProxyAddress();
              mProfile.mPort = profile.getPort();
          }
  
          /**
           * Constructor.
           *
           * @param uriString the URI string as "sip:<user_name>@<domain>"
           * @throws ParseException if the string is not a valid URI
           */
          public Builder(String uriString) throws ParseException {
              if (uriString == null) {
                  throw new NullPointerException("uriString cannot be null");
              }
              URI uri = mAddressFactory.createURI(fix(uriString));
              if (uri instanceof SipURI) {
                  mUri = (SipURI) uri;
              } else {
                  throw new ParseException(uriString + " is not a SIP URI", 0);
              }
              mProfile.mDomain = mUri.getHost();
          }
  
          /**
           * Constructor.
           *
           * @param username username of the SIP account
           * @param serverDomain the SIP server domain; if the network address
           *      is different from the domain, use {@link #setOutboundProxy} to
           *      set server address
           * @throws ParseException if the parameters are not valid
           */
          public Builder(String username, String serverDomain)
                  throws ParseException {
              if ((username == null) || (serverDomain == null)) {
                  throw new NullPointerException(
                          "username and serverDomain cannot be null");
              }
              mUri = mAddressFactory.createSipURI(username, serverDomain);
              mProfile.mDomain = serverDomain;
          }
  
          private String fix(String uriString) {
              return (uriString.trim().toLowerCase().startsWith("sip:")
                      ? uriString
                      : "sip:" + uriString);
          }
  
          /**
           * Sets the username used for authentication.
           *
           * @param name authentication username of the profile
           * @return this builder object
           */
          public Builder setAuthUserName(String name) {
              mProfile.mAuthUserName = name;
              return this;
          }
  
          /**
           * Sets the name of the profile. This name is given by user.
           *
           * @param name name of the profile
           * @return this builder object
           */
          public Builder setProfileName(String name) {
              mProfile.mProfileName = name;
              return this;
          }
  
          /**
           * Sets the password of the SIP account
           *
           * @param password password of the SIP account
           * @return this builder object
           */
          public Builder setPassword(String password) {
              mUri.setUserPassword(password);
              return this;
          }
  
          /**
           * Sets the port number of the server. By default, it is 5060.
           *
           * @param port port number of the server
           * @return this builder object
           * @throws IllegalArgumentException if the port number is out of range
           */
          public Builder setPort(int port) throws IllegalArgumentException {
              if ((port > 65535) || (port < 1000)) {
                  throw new IllegalArgumentException("incorrect port arugment: " + port);
              }
              mProfile.mPort = port;
              return this;
          }
  
          /**
           * Sets the protocol used to connect to the SIP server. Currently,
           * only "UDP" and "TCP" are supported.
           *
           * @param protocol the protocol string
           * @return this builder object
           * @throws IllegalArgumentException if the protocol is not recognized
           */
          public Builder setProtocol(String protocol)
                  throws IllegalArgumentException {
              if (protocol == null) {
                  throw new NullPointerException("protocol cannot be null");
              }
              protocol = protocol.toUpperCase();
              if (!protocol.equals(UDP) && !protocol.equals(TCP)) {
                  throw new IllegalArgumentException(
                          "unsupported protocol: " + protocol);
              }
              mProfile.mProtocol = protocol;
              return this;
          }
  
          /**
           * Sets the outbound proxy of the SIP server.
           *
           * @param outboundProxy the network address of the outbound proxy
           * @return this builder object
           */
          public Builder setOutboundProxy(String outboundProxy) {
              mProxyAddress = outboundProxy;
              return this;
          }
  
          /**
           * Sets the display name of the user.
           *
           * @param displayName display name of the user
           * @return this builder object
           */
          public Builder setDisplayName(String displayName) {
              mDisplayName = displayName;
              return this;
          }
  
          /**
           * Sets the send keep-alive flag.
           *
           * @param flag true if sending keep-alive message is required,
           *      false otherwise
           * @return this builder object
           */
          public Builder setSendKeepAlive(boolean flag) {
              mProfile.mSendKeepAlive = flag;
              return this;
          }
  
  
          /**
           * Sets the auto. registration flag.
           *
           * @param flag true if the profile will be registered automatically,
           *      false otherwise
           * @return this builder object
           */
          public Builder setAutoRegistration(boolean flag) {
              mProfile.mAutoRegistration = flag;
              return this;
          }
  
          /**
           * Builds and returns the SIP profile object.
           *
           * @return the profile object created
           */
          public SipProfile build() {
              // remove password from URI
              mProfile.mPassword = mUri.getUserPassword();
              mUri.setUserPassword(null);
              try {
                  if (!TextUtils.isEmpty(mProxyAddress)) {
                      SipURI uri = (SipURI)
                              mAddressFactory.createURI(fix(mProxyAddress));
                      mProfile.mProxyAddress = uri.getHost();
                  } else {
                      if (!mProfile.mProtocol.equals(UDP)) {
                          mUri.setTransportParam(mProfile.mProtocol);
                      }
                      if (mProfile.mPort != DEFAULT_PORT) {
                          mUri.setPort(mProfile.mPort);
                      }
                  }
                  mProfile.mAddress = mAddressFactory.createAddress(
                          mDisplayName, mUri);
              } catch (InvalidArgumentException e) {
                  throw new RuntimeException(e);
              } catch (ParseException e) {
                  // must not occur
                  throw new RuntimeException(e);
              }
              return mProfile;
          }
      }
  
      private SipProfile() {
      }
  
      private SipProfile(Parcel in) {
          mAddress = (Address) in.readSerializable();
          mProxyAddress = in.readString();
          mPassword = in.readString();
          mDomain = in.readString();
          mProtocol = in.readString();
          mProfileName = in.readString();
          mSendKeepAlive = (in.readInt() == 0) ? false : true;
          mAutoRegistration = (in.readInt() == 0) ? false : true;
          mCallingUid = in.readInt();
          mPort = in.readInt();
          mAuthUserName = in.readString();
      }
  
      @Override
      public void writeToParcel(Parcel out, int flags) {
          out.writeSerializable(mAddress);
          out.writeString(mProxyAddress);
          out.writeString(mPassword);
          out.writeString(mDomain);
          out.writeString(mProtocol);
          out.writeString(mProfileName);
          out.writeInt(mSendKeepAlive ? 1 : 0);
          out.writeInt(mAutoRegistration ? 1 : 0);
          out.writeInt(mCallingUid);
          out.writeInt(mPort);
          out.writeString(mAuthUserName);
      }
  
      @Override
      public int describeContents() {
          return 0;
      }
  
      /**
       * Gets the SIP URI of this profile.
       *
       * @return the SIP URI of this profile
       * @hide
       */
      public SipURI getUri() {
          return (SipURI) mAddress.getURI();
      }
  
      /**
       * Gets the SIP URI string of this profile.
       *
       * @return the SIP URI string of this profile
       */
      public String getUriString() {
          // We need to return the sip uri domain instead of
          // the SIP URI with transport, port information if
          // the outbound proxy address exists.
          if (!TextUtils.isEmpty(mProxyAddress)) {
              return "sip:" + getUserName() + "@" + mDomain;
          }
          return getUri().toString();
      }
  
      /**
       * Gets the SIP address of this profile.
       *
       * @return the SIP address of this profile
       * @hide
       */
      public Address getSipAddress() {
          return mAddress;
      }
  
      /**
       * Gets the display name of the user.
       *
       * @return the display name of the user
       */
      public String getDisplayName() {
          return mAddress.getDisplayName();
      }
  
      /**
       * Gets the username.
       *
       * @return the username
       */
      public String getUserName() {
          return getUri().getUser();
      }
  
      /**
       * Gets the username for authentication. If it is null, then the username
       * is used in authentication instead.
       *
       * @return the authentication username
       * @see #getUserName
       */
      public String getAuthUserName() {
          return mAuthUserName;
      }
  
      /**
       * Gets the password.
       *
       * @return the password
       */
      public String getPassword() {
          return mPassword;
      }
  
      /**
       * Gets the SIP domain.
       *
       * @return the SIP domain
       */
      public String getSipDomain() {
          return mDomain;
      }
  
      /**
       * Gets the port number of the SIP server.
       *
       * @return the port number of the SIP server
       */
      public int getPort() {
          return mPort;
      }
  
      /**
       * Gets the protocol used to connect to the server.
       *
       * @return the protocol
       */
      public String getProtocol() {
          return mProtocol;
      }
  
      /**
       * Gets the network address of the server outbound proxy.
       *
       * @return the network address of the server outbound proxy
       */
      public String getProxyAddress() {
          return mProxyAddress;
      }
  
      /**
       * Gets the (user-defined) name of the profile.
       *
       * @return name of the profile
       */
      public String getProfileName() {
          return mProfileName;
      }
  
      /**
       * Gets the flag of 'Sending keep-alive'.
       *
       * @return the flag of sending SIP keep-alive messages.
       */
      public boolean getSendKeepAlive() {
          return mSendKeepAlive;
      }
  
      /**
       * Gets the flag of 'Auto Registration'.
       *
       * @return the flag of registering the profile automatically.
       */
      public boolean getAutoRegistration() {
          return mAutoRegistration;
      }
  
      /**
       * Sets the calling process's Uid in the sip service.
       * @hide
       */
      public void setCallingUid(int uid) {
          mCallingUid = uid;
      }
  
      /**
       * Gets the calling process's Uid in the sip settings.
       * @hide
       */
      public int getCallingUid() {
          return mCallingUid;
      }
  
      private Object readResolve() throws ObjectStreamException {
          // For compatibility.
          if (mPort == 0) mPort = DEFAULT_PORT;
          return this;
      }
  }
  