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