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