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          */
Builder(SipProfile profile)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          */
Builder(String uriString)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          */
Builder(String username, String serverDomain)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 
fix(String uriString)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          */
setAuthUserName(String name)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          */
setProfileName(String name)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          */
setPassword(String password)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          */
setPort(int port)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          */
setProtocol(String protocol)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          */
setOutboundProxy(String outboundProxy)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          */
setDisplayName(String displayName)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          */
setSendKeepAlive(boolean flag)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          */
setAutoRegistration(boolean flag)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          */
build()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 
SipProfile()308     private SipProfile() {
309     }
310 
SipProfile(Parcel in)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
writeToParcel(Parcel out, int flags)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
describeContents()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      */
getUri()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      */
getUriString()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      */
getSipAddress()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      */
getDisplayName()385     public String getDisplayName() {
386         return mAddress.getDisplayName();
387     }
388 
389     /**
390      * Gets the username.
391      *
392      * @return the username
393      */
getUserName()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      */
getAuthUserName()405     public String getAuthUserName() {
406         return mAuthUserName;
407     }
408 
409     /**
410      * Gets the password.
411      *
412      * @return the password
413      */
getPassword()414     public String getPassword() {
415         return mPassword;
416     }
417 
418     /**
419      * Gets the SIP domain.
420      *
421      * @return the SIP domain
422      */
getSipDomain()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      */
getPort()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      */
getProtocol()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      */
getProxyAddress()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      */
getProfileName()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      */
getSendKeepAlive()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      */
getAutoRegistration()477     public boolean getAutoRegistration() {
478         return mAutoRegistration;
479     }
480 
481     /**
482      * Sets the calling process's Uid in the sip service.
483      * @hide
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      * @hide
492      */
getCallingUid()493     public int getCallingUid() {
494         return mCallingUid;
495     }
496 
readResolve()497     private Object readResolve() throws ObjectStreamException {
498         // For compatibility.
499         if (mPort == 0) mPort = DEFAULT_PORT;
500         return this;
501     }
502 }
503