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