1/*
2* Conditions Of Use
3*
4* This software was developed by employees of the National Institute of
5* Standards and Technology (NIST), an agency of the Federal Government.
6* Pursuant to title 15 Untied States Code Section 105, works of NIST
7* employees are not subject to copyright protection in the United States
8* and are considered to be in the public domain.  As a result, a formal
9* license is not needed to use the software.
10*
11* This software is provided by NIST as a service and is expressly
12* provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
13* OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
14* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
15* AND DATA ACCURACY.  NIST does not warrant or make any representations
16* regarding the use of the software or the results thereof, including but
17* not limited to the correctness, accuracy, reliability or usefulness of
18* the software.
19*
20* Permission to use this software is contingent upon your acceptance
21* of the terms of this agreement
22*
23* .
24*
25*/
26/*******************************************************************************
27* Product of NIST/ITL Advanced Networking Technologies Division (ANTD).        *
28*******************************************************************************/
29package gov.nist.javax.sip.address;
30
31/*
32 *Bug fix contributions
33 *Daniel J. Martinez Manzano <dani@dif.um.es>
34 *Stefan Marx.
35 *pmusgrave@newheights.com (Additions for gruu and outbound drafts)
36 *Jeroen van Bemmel ( additions for SCTP transport )
37 */
38import gov.nist.core.*;
39import java.util.*;
40import java.text.ParseException;
41
42import javax.sip.PeerUnavailableException;
43import javax.sip.SipFactory;
44import javax.sip.address.SipURI;
45import javax.sip.header.Header;
46import javax.sip.header.HeaderFactory;
47
48
49/**
50 * Implementation of the SipURI interface.
51 *
52 *
53 * @author M. Ranganathan   <br/>
54 * @version 1.2 $Revision: 1.22 $ $Date: 2009/11/15 19:50:45 $
55 *
56 *
57 *
58 */
59public class SipUri extends GenericURI implements javax.sip.address.SipURI , SipURIExt{
60
61
62    private static final long serialVersionUID = 7749781076218987044L;
63
64    /** Authority for the uri.
65     */
66
67    protected Authority authority;
68
69    /** uriParms list
70     */
71    protected NameValueList uriParms;
72
73    /** qheaders list
74     */
75    protected NameValueList qheaders;
76
77    /** telephoneSubscriber field
78     */
79    protected TelephoneNumber telephoneSubscriber;
80
81    public SipUri() {
82        this.scheme = SIP;
83        this.uriParms = new NameValueList();
84        this.qheaders = new NameValueList();
85        this.qheaders.setSeparator("&");
86    }
87
88    /** Constructor given the scheme.
89    * The scheme must be either Sip or Sips
90    */
91    public void setScheme(String scheme) {
92        if (scheme.compareToIgnoreCase(SIP) != 0
93            && scheme.compareToIgnoreCase(SIPS) != 0)
94            throw new IllegalArgumentException("bad scheme " + scheme);
95        this.scheme = scheme.toLowerCase();
96    }
97
98    /** Get the scheme.
99     */
100    public String getScheme() {
101        return scheme;
102    }
103
104    /**
105     * clear all URI Parameters.
106     * @since v1.0
107     */
108    public void clearUriParms() {
109        uriParms = new NameValueList();
110    }
111    /**
112    *Clear the password from the user part if it exists.
113    */
114    public void clearPassword() {
115        if (this.authority != null) {
116            UserInfo userInfo = authority.getUserInfo();
117            if (userInfo != null)
118                userInfo.clearPassword();
119        }
120    }
121
122    /** Get the authority.
123    */
124    public Authority getAuthority() {
125        return this.authority;
126    }
127
128    /**
129     * Clear all Qheaders.
130     */
131    public void clearQheaders() {
132        qheaders = new NameValueList();
133    }
134
135    /**
136     * Compare two URIs and return true if they are equal.
137     * @param that the object to compare to.
138     * @return true if the object is equal to this object.
139     *
140     * JvB: Updated to define equality in terms of API methods, according to the rules
141     * in RFC3261 section 19.1.4
142     *
143     * Jean Deruelle: Updated to define equality of API methods, according to the rules
144     * in RFC3261 section 19.1.4 convert potential ie :
145     *    %HEX HEX encoding parts of the URI before comparing them
146     *    transport param added in comparison
147     *    header equality enforced in comparison
148     *
149     */
150    @SuppressWarnings("unchecked")
151    @Override
152    public boolean equals(Object that) {
153
154        // Shortcut for same object
155        if (that==this) return true;
156
157        if (that instanceof SipURI) {
158            final SipURI a = this;
159            final SipURI b = (SipURI) that;
160
161            // A SIP and SIPS URI are never equivalent
162            if ( a.isSecure() ^ b.isSecure() ) return false;
163
164            // For two URIs to be equal, the user, password, host, and port
165            // components must match; comparison of userinfo is case-sensitive
166            if (a.getUser()==null ^ b.getUser()==null) return false;
167            if (a.getUserPassword()==null ^ b.getUserPassword()==null) return false;
168
169            if (a.getUser()!=null && !RFC2396UrlDecoder.decode(a.getUser()).equals(RFC2396UrlDecoder.decode(b.getUser()))) return false;
170            if (a.getUserPassword()!=null && !RFC2396UrlDecoder.decode(a.getUserPassword()).equals(RFC2396UrlDecoder.decode(b.getUserPassword()))) return false;
171            if (a.getHost() == null ^ b.getHost() == null) return false;
172            if (a.getHost() != null && !a.getHost().equalsIgnoreCase(b.getHost())) return false;
173            if (a.getPort() != b.getPort()) return false;
174
175            // URI parameters
176            for (Iterator i = a.getParameterNames(); i.hasNext();) {
177                String pname = (String) i.next();
178
179                String p1 = a.getParameter(pname);
180                String p2 = b.getParameter(pname);
181
182                // those present in both must match (case-insensitive)
183                if (p1!=null && p2!=null && !RFC2396UrlDecoder.decode(p1).equalsIgnoreCase(RFC2396UrlDecoder.decode(p2))) return false;
184            }
185
186            // transport, user, ttl or method must match when present in either
187            if (a.getTransportParam()==null ^ b.getTransportParam()==null) return false;
188            if (a.getUserParam()==null ^ b.getUserParam()==null) return false;
189            if (a.getTTLParam()==-1 ^ b.getTTLParam()==-1) return false;
190            if (a.getMethodParam()==null ^ b.getMethodParam()==null) return false;
191            if (a.getMAddrParam()==null ^ b.getMAddrParam()==null) return false;
192
193            // Headers: must match according to their definition.
194            if(a.getHeaderNames().hasNext() && !b.getHeaderNames().hasNext()) return false;
195            if(!a.getHeaderNames().hasNext() && b.getHeaderNames().hasNext()) return false;
196
197            if(a.getHeaderNames().hasNext() && b.getHeaderNames().hasNext()) {
198                HeaderFactory headerFactory = null;
199                try {
200                    headerFactory = SipFactory.getInstance().createHeaderFactory();
201                } catch (PeerUnavailableException e) {
202                    Debug.logError("Cannot get the header factory to parse the header of the sip uris to compare", e);
203                    return false;
204                }
205                for (Iterator i = a.getHeaderNames(); i.hasNext();) {
206                    String hname = (String) i.next();
207
208                    String h1 = a.getHeader(hname);
209                    String h2 = b.getHeader(hname);
210
211                    if(h1 == null && h2 != null) return false;
212                    if(h2 == null && h1 != null) return false;
213                    // The following check should not be needed but we add it for findbugs.
214                    if(h1 == null && h2 == null) continue;
215                    try {
216                        Header header1 = headerFactory.createHeader(hname, RFC2396UrlDecoder.decode(h1));
217                        Header header2 = headerFactory.createHeader(hname, RFC2396UrlDecoder.decode(h2));
218                        // those present in both must match according to the equals method of the corresponding header
219                        if (!header1.equals(header2)) return false;
220                    } catch (ParseException e) {
221                        Debug.logError("Cannot parse one of the header of the sip uris to compare " + a + " " + b, e);
222                        return false;
223                    }
224                }
225            }
226
227            // Finally, we can conclude that they are indeed equal
228            return true;
229        }
230        return false;
231    }
232
233    /**
234     * Construct a URL from the parsed structure.
235     * @return String
236     */
237    public String encode() {
238        return encode(new StringBuffer()).toString();
239    }
240
241    public StringBuffer encode(StringBuffer buffer) {
242        buffer.append(scheme).append(COLON);
243        if (authority != null)
244            authority.encode(buffer);
245        if (!uriParms.isEmpty()) {
246            buffer.append(SEMICOLON);
247            uriParms.encode(buffer);
248        }
249        if (!qheaders.isEmpty()) {
250            buffer.append(QUESTION);
251            qheaders.encode(buffer);
252        }
253        return buffer;
254    }
255
256    /** Return a string representation.
257    *
258    *@return the String representation of this URI.
259    *
260    */
261    public String toString() {
262        return this.encode();
263    }
264
265    /**
266     * getUser@host
267     * @return user@host portion of the uri (null if none exists).
268     *
269     * Peter Musgrave - handle null user
270     */
271    public String getUserAtHost() {
272        String user = "";
273        if (authority.getUserInfo() != null)
274            user = authority.getUserInfo().getUser();
275
276        String host = authority.getHost().encode();
277        StringBuffer s = null;
278        if (user.equals("")) {
279            s = new StringBuffer();
280        } else {
281            s = new StringBuffer(user).append(AT);
282        }
283        return s.append(host).toString();
284    }
285
286    /**
287     * getUser@host
288     * @return user@host portion of the uri (null if none exists).
289     */
290    public String getUserAtHostPort() {
291        String user = "";
292        if (authority.getUserInfo() != null)
293            user = authority.getUserInfo().getUser();
294
295        String host = authority.getHost().encode();
296        int port = authority.getPort();
297        // If port not set assign the default.
298        StringBuffer s = null;
299        if (user.equals("")) {
300            s = new StringBuffer();
301        } else {
302            s = new StringBuffer(user).append(AT);
303        }
304        if (port != -1) {
305            return s.append(host).append(COLON).append(port).toString();
306        } else
307            return s.append(host).toString();
308
309    }
310
311    /**
312     * get the parameter (do a name lookup) and return null if none exists.
313     * @param parmname Name of the parameter to get.
314     * @return Parameter of the given name (null if none exists).
315     */
316    public Object getParm(String parmname) {
317        Object obj = uriParms.getValue(parmname);
318        return obj;
319    }
320
321    /**
322     * Get the method parameter.
323     * @return Method parameter.
324     */
325    public String getMethod() {
326        return (String) getParm(METHOD);
327    }
328
329    /**
330     * Accessor for URI parameters
331     * @return A name-value list containing the parameters.
332     */
333    public NameValueList getParameters() {
334        return uriParms;
335    }
336
337    /** Remove the URI parameters.
338    *
339    */
340    public void removeParameters() {
341        this.uriParms = new NameValueList();
342    }
343
344    /**
345     * Accessor forSIPObjects
346     * @return Get the query headers (that appear after the ? in
347     * the URL)
348     */
349    public NameValueList getQheaders() {
350        return qheaders;
351    }
352
353    /**
354     * Get the urse parameter.
355     * @return User parameter (user= phone or user=ip).
356     */
357    public String getUserType() {
358        return (String) uriParms.getValue(USER);
359    }
360
361    /**
362     * Get the password of the user.
363     * @return User password when it embedded as part of the uri
364     * ( a very bad idea).
365     */
366    public String getUserPassword() {
367        if (authority == null)
368            return null;
369        return authority.getPassword();
370    }
371
372    /** Set the user password.
373     *@param password - password to set.
374     */
375    public void setUserPassword(String password) {
376        if (this.authority == null)
377            this.authority = new Authority();
378        authority.setPassword(password);
379    }
380
381    /**
382     * Returns the stucture corresponding to the telephone number
383     * provided that the user is a telephone subscriber.
384     * @return TelephoneNumber part of the url (only makes sense
385     * when user = phone is specified)
386     */
387    public TelephoneNumber getTelephoneSubscriber() {
388        if (telephoneSubscriber == null) {
389
390            telephoneSubscriber = new TelephoneNumber();
391        }
392        return telephoneSubscriber;
393    }
394
395    /**
396     * Get the host and port of the server.
397     * @return get the host:port part of the url parsed into a
398     * structure.
399     */
400    public HostPort getHostPort() {
401
402        if (authority == null || authority.getHost() == null )
403            return null;
404        else {
405            return authority.getHostPort();
406        }
407    }
408
409    /** Get the port from the authority field.
410    *
411    *@return the port from the authority field.
412    */
413    public int getPort() {
414        HostPort hp = this.getHostPort();
415        if (hp == null)
416            return -1;
417        return hp.getPort();
418    }
419
420    /** Get the host protion of the URI.
421    * @return the host portion of the url.
422    */
423    public String getHost() {
424        if ( authority == null) return null;
425        else if (authority.getHost() == null ) return null;
426        else return authority.getHost().encode();
427    }
428
429    /**
430     * returns true if the user is a telephone subscriber.
431     *  If the host is an Internet telephony
432     * gateway, a telephone-subscriber field MAY be used instead
433     * of a user field. The telephone-subscriber field uses the
434     * notation of RFC 2806 [19]. Any characters of the un-escaped
435     * "telephone-subscriber" that are not either in the set
436     * "unreserved" or "user-unreserved" MUST be escaped. The set
437     * of characters not reserved in the RFC 2806 description of
438     * telephone-subscriber contains a number of characters in
439     * various syntax elements that need to be escaped when used
440     * in SIP URLs, for example quotation marks (%22), hash (%23),
441     * colon (%3a), at-sign (%40) and the "unwise" characters,
442     * i.e., punctuation of %5b and above.
443     *
444     * The telephone number is a special case of a user name and
445     * cannot be distinguished by a BNF. Thus, a URL parameter,
446     * user, is added to distinguish telephone numbers from user
447     * names.
448     *
449     * The user parameter value "phone" indicates that the user
450     * part contains a telephone number. Even without this
451     * parameter, recipients of SIP URLs MAY interpret the pre-@
452     * part as a telephone number if local restrictions on the
453     * @return true if the user is a telephone subscriber.
454     */
455    public boolean isUserTelephoneSubscriber() {
456        String usrtype = (String) uriParms.getValue(USER);
457        if (usrtype == null)
458            return false;
459        return usrtype.equalsIgnoreCase(PHONE);
460    }
461
462    /**
463     *remove the ttl value from the parameter list if it exists.
464     */
465    public void removeTTL() {
466        if (uriParms != null)
467            uriParms.delete(TTL);
468    }
469
470    /**
471     *Remove the maddr param if it exists.
472     */
473    public void removeMAddr() {
474        if (uriParms != null)
475            uriParms.delete(MADDR);
476    }
477
478    /**
479     *Delete the transport string.
480     */
481    public void removeTransport() {
482        if (uriParms != null)
483            uriParms.delete(TRANSPORT);
484    }
485
486    /** Remove a header given its name (provided it exists).
487     * @param name name of the header to remove.
488     */
489    public void removeHeader(String name) {
490        if (qheaders != null)
491            qheaders.delete(name);
492    }
493
494    /** Remove all headers.
495     */
496    public void removeHeaders() {
497        qheaders = new NameValueList();
498    }
499
500    /**
501     * Set the user type.
502     */
503    public void removeUserType() {
504        if (uriParms != null)
505            uriParms.delete(USER);
506    }
507
508    /**
509     *remove the port setting.
510     */
511    public void removePort() {
512        authority.removePort();
513    }
514
515    /**
516     * remove the Method.
517     */
518    public void removeMethod() {
519        if (uriParms != null)
520            uriParms.delete(METHOD);
521    }
522
523    /** Sets the user of SipURI. The identifier of a particular resource at
524     * the host being addressed. The user and the user password including the
525     * "at" sign make up the user-info.
526     *
527     * @param uname The new String value of the user.
528     * @throws ParseException which signals that an error has been reached
529     * unexpectedly while parsing the user value.
530     */
531    public void setUser(String uname) {
532        if (this.authority == null) {
533            this.authority = new Authority();
534        }
535
536        this.authority.setUser(uname);
537    }
538
539    /** Remove the user.
540     */
541    public void removeUser() {
542        this.authority.removeUserInfo();
543    }
544
545    /** Set the default parameters for this URI.
546     * Do nothing if the parameter is already set to some value.
547     * Otherwise set it to the given value.
548     * @param name Name of the parameter to set.
549     * @param value value of the parameter to set.
550     */
551    public void setDefaultParm(String name, Object value) {
552        if (uriParms.getValue(name) == null) {
553            NameValue nv = new NameValue(name, value);
554            uriParms.set(nv);
555        }
556    }
557
558    /** Set the authority member
559     * @param authority Authority to set.
560     */
561    public void setAuthority(Authority authority) {
562        this.authority = authority;
563    }
564
565    /** Set the host for this URI.
566     * @param h host to set.
567     */
568    public void setHost(Host h) {
569        if (this.authority == null)
570            this.authority = new Authority();
571        this.authority.setHost(h);
572    }
573
574    /** Set the uriParms member
575     * @param parms URI parameters to set.
576     */
577    public void setUriParms(NameValueList parms) {
578        uriParms = parms;
579    }
580
581    /**
582     * Set a given URI parameter. Note - parameter must be properly
583    *  encoded before the function is called.
584     * @param name Name of the parameter to set.
585     * @param value value of the parameter to set.
586     */
587    public void setUriParm(String name, Object value) {
588        NameValue nv = new NameValue(name, value);
589        uriParms.set(nv);
590    }
591
592    /** Set the qheaders member
593     * @param parms query headers to set.
594     */
595    public void setQheaders(NameValueList parms) {
596        qheaders = parms;
597    }
598
599    /**
600     * Set the MADDR parameter .
601     * @param mAddr Host Name to set
602     */
603    public void setMAddr(String mAddr) {
604        NameValue nameValue = uriParms.getNameValue(MADDR);
605        Host host = new Host();
606        host.setAddress(mAddr);
607        if (nameValue != null)
608            nameValue.setValueAsObject(host);
609        else {
610            nameValue = new NameValue(MADDR, host);
611            uriParms.set(nameValue);
612        }
613    }
614
615    /** Sets the value of the user parameter. The user URI parameter exists to
616     * distinguish telephone numbers from user names that happen to look like
617     * telephone numbers.  This is equivalent to setParameter("user", user).
618     *
619     * @param usertype New value String value of the method parameter
620     */
621    public void setUserParam(String usertype) {
622        uriParms.set(USER, usertype);
623    }
624
625    /**
626     * Set the Method
627     * @param method method parameter
628     */
629    public void setMethod(String method) {
630        uriParms.set(METHOD, method);
631    }
632
633    /**
634    * Sets ISDN subaddress of SipURL
635    * @param isdnSubAddress ISDN subaddress
636    */
637    public void setIsdnSubAddress(String isdnSubAddress) {
638        if (telephoneSubscriber == null)
639            telephoneSubscriber = new TelephoneNumber();
640        telephoneSubscriber.setIsdnSubaddress(isdnSubAddress);
641    }
642
643    /**
644     * Set the telephone subscriber field.
645     * @param tel Telephone subscriber field to set.
646     */
647    public void setTelephoneSubscriber(TelephoneNumber tel) {
648        telephoneSubscriber = tel;
649    }
650
651    /** set the port to a given value.
652     * @param p Port to set.
653     */
654    public void setPort(int p) {
655        if (authority == null)
656            authority = new Authority();
657        authority.setPort(p);
658    }
659
660    /**
661     * Boolean to check if a parameter of a given name exists.
662     * @param name Name of the parameter to check on.
663     * @return a boolean indicating whether the parameter exists.
664     */
665    public boolean hasParameter(String name) {
666
667        return uriParms.getValue(name) != null;
668    }
669
670    /**
671     * Set the query header when provided as a name-value pair.
672     * @param nameValue qeuery header provided as a name,value pair.
673     */
674    public void setQHeader(NameValue nameValue) {
675        this.qheaders.set(nameValue);
676    }
677
678    /** Set the parameter as given.
679     *@param nameValue - parameter to set.
680     */
681    public void setUriParameter(NameValue nameValue) {
682        this.uriParms.set(nameValue);
683    }
684
685    /** Return true if the transport parameter is defined.
686     * @return true if transport appears as a parameter and false otherwise.
687     */
688    public boolean hasTransport() {
689        return hasParameter(TRANSPORT);
690    }
691
692    /**
693     * Remove a parameter given its name
694     * @param name -- name of the parameter to remove.
695     */
696    public void removeParameter(String name) {
697        uriParms.delete(name);
698    }
699
700    /** Set the hostPort field of the imbedded authority field.
701     *@param hostPort is the hostPort to set.
702     */
703    public void setHostPort(HostPort hostPort) {
704        if (this.authority == null) {
705            this.authority = new Authority();
706        }
707        authority.setHostPort(hostPort);
708    }
709
710    /** clone this.
711     */
712    public Object clone() {
713        SipUri retval = (SipUri) super.clone();
714        if (this.authority != null)
715            retval.authority = (Authority) this.authority.clone();
716        if (this.uriParms != null)
717            retval.uriParms = (NameValueList) this.uriParms.clone();
718        if (this.qheaders != null)
719            retval.qheaders = (NameValueList) this.qheaders.clone();
720        if (this.telephoneSubscriber != null)
721            retval.telephoneSubscriber = (TelephoneNumber) this.telephoneSubscriber.clone();
722        return retval;
723    }
724
725    /**
726     * Returns the value of the named header, or null if it is not set.
727     * SIP/SIPS URIs may specify headers. As an example, the URI
728     * sip:joe@jcp.org?priority=urgent has a header "priority" whose
729     * value is "urgent".
730     *
731     * @param name name of header to retrieve
732     * @return the value of specified header
733     */
734    public String getHeader(String name) {
735        return this.qheaders.getValue(name) != null
736            ? this.qheaders.getValue(name).toString()
737            : null;
738
739    }
740
741    /**
742     * Returns an Iterator over the names (Strings) of all headers present
743     * in this SipURI.
744     *
745     * @return an Iterator over all the header names
746     */
747    public Iterator<String> getHeaderNames() {
748        return this.qheaders.getNames();
749
750    }
751
752    /** Returns the value of the <code>lr</code> parameter, or null if this
753     * is not set. This is equivalent to getParameter("lr").
754     *
755     * @return the value of the <code>lr</code> parameter
756     */
757    public String getLrParam() {
758        boolean haslr = this.hasParameter(LR);
759        return haslr ? "true" : null;
760    }
761
762    /** Returns the value of the <code>maddr</code> parameter, or null if this
763     * is not set. This is equivalent to getParameter("maddr").
764     *
765     * @return the value of the <code>maddr</code> parameter
766     */
767    public String getMAddrParam() {
768        NameValue maddr = uriParms.getNameValue(MADDR);
769        if (maddr == null)
770            return null;
771        String host = (String) maddr.getValueAsObject();
772        return host;
773    }
774
775    /**
776     * Returns the value of the <code>method</code> parameter, or null if this
777     * is not set. This is equivalent to getParameter("method").
778     *
779     * @return  the value of the <code>method</code> parameter
780     */
781    public String getMethodParam() {
782        return this.getParameter(METHOD);
783    }
784
785    /**
786     * Returns the value of the named parameter, or null if it is not set. A
787     * zero-length String indicates flag parameter.
788     *
789     * @param name name of parameter to retrieve
790     * @return the value of specified parameter
791     */
792    public String getParameter(String name) {
793        Object val = uriParms.getValue(name);
794        if (val == null)
795            return null;
796        if (val instanceof GenericObject)
797            return ((GenericObject) val).encode();
798        else
799            return val.toString();
800    }
801
802    /**
803     * Returns an Iterator over the names (Strings) of all parameters present
804     *
805     * in this ParametersHeader.
806     *
807     *
808     *
809     * @return an Iterator over all the parameter names
810     *
811     */
812    public Iterator<String> getParameterNames() {
813        return this.uriParms.getNames();
814    }
815
816    /** Returns the value of the "ttl" parameter, or -1 if this is not set.
817     * This method is equivalent to getParameter("ttl").
818     *
819     * @return the value of the <code>ttl</code> parameter
820     */
821    public int getTTLParam() {
822        Integer ttl = (Integer) uriParms.getValue("ttl");
823        if (ttl != null)
824            return ttl.intValue();
825        else
826            return -1;
827    }
828
829    /** Returns the value of the "transport" parameter, or null if this is not
830     * set. This is equivalent to getParameter("transport").
831     *
832     * @return the transport paramter of the SipURI
833     */
834    public String getTransportParam() {
835        if (uriParms != null) {
836            return (String) uriParms.getValue(TRANSPORT);
837        } else
838            return null;
839    }
840
841    /** Returns the value of the <code>userParam</code>,
842     *or null if this is not set.
843     * <p>
844     * This is equivalent to getParameter("user").
845     *
846     * @return the value of the <code>userParam</code> of the SipURI
847     */
848    public String getUser() {
849        return authority.getUser();
850    }
851
852    /** Returns true if this SipURI is secure i.e. if this SipURI represents a
853     * sips URI. A sip URI returns false.
854     *
855     * @return  <code>true</code> if this SipURI represents a sips URI, and
856     * <code>false</code> if it represents a sip URI.
857     */
858    public boolean isSecure() {
859        return this.getScheme().equalsIgnoreCase(SIPS);
860    }
861
862    /** This method determines if this is a URI with a scheme of "sip" or "sips".
863     *
864     * @return true if the scheme is "sip" or "sips", false otherwise.
865     */
866    public boolean isSipURI() {
867        return true;
868    }
869
870    /** Sets the value of the specified header fields to be included in a
871     * request constructed from the URI. If the header already had a value it
872     * will be overwritten.
873     *
874     * @param name - a String specifying the header name
875     * @param value - a String specifying the header value
876     */
877    public void setHeader(String name, String value) {
878        NameValue nv = new NameValue(name, value);
879        qheaders.set(nv);
880
881    }
882
883    /**
884     * Set the host portion of the SipURI
885     *
886     * @param host host to set.
887     */
888    public void setHost(String host) throws ParseException {
889        Host h = new Host(host);
890        this.setHost(h);
891    }
892
893    /** Sets the value of the <code>lr</code> parameter of this SipURI. The lr
894     * parameter, when present, indicates that the element responsible for
895     * this resource implements the routing mechanisms specified in RFC 3261.
896     * This parameter will be used in the URIs proxies place in the
897     * Record-Route header field values, and may appear in the URIs in a
898     * pre-existing route set.
899     */
900    public void setLrParam() {
901        this.uriParms.set("lr",null);   // JvB: fixed to not add duplicates
902    }
903
904    /**
905     * Sets the value of the <code>maddr</code> parameter of this SipURI. The
906     * maddr parameter indicates the server address to be contacted for this
907     * user, overriding any address derived from the host field. This is
908     * equivalent to setParameter("maddr", maddr).
909     *
910     * @param  maddr New value of the <code>maddr</code> parameter
911     */
912    public void setMAddrParam(String maddr) throws ParseException {
913        if (maddr == null)
914            throw new NullPointerException("bad maddr");
915        setParameter("maddr", maddr);
916    }
917
918    /** Sets the value of the <code>method</code> parameter. This specifies
919     * which SIP method to use in requests directed at this URI. This is
920     * equivalent to setParameter("method", method).
921     *
922     * @param  method - new value String value of the method parameter
923     */
924    public void setMethodParam(String method) throws ParseException {
925        setParameter("method", method);
926    }
927
928    /**
929     * Sets the value of the specified parameter. If the parameter already had
930     *
931     * a value it will be overwritten. A zero-length String indicates flag
932     *
933     * parameter.
934     *
935     *
936     *
937     * @param name - a String specifying the parameter name
938     *
939     * @param value - a String specifying the parameter value
940     *
941     * @throws ParseException which signals that an error has been reached
942     *
943     * unexpectedly while parsing the parameter name or value.
944     *
945     */
946    public void setParameter(String name, String value) throws ParseException {
947        if (name.equalsIgnoreCase("ttl")) {
948            try {
949                Integer.parseInt(value);
950            } catch (NumberFormatException ex) {
951                throw new ParseException("bad parameter " + value, 0);
952            }
953        }
954        uriParms.set(name,value);
955    }
956
957    /** Sets the scheme of this URI to sip or sips depending on whether the
958     * argument is true or false. The default value is false.
959     *
960     * @param secure - the boolean value indicating if the SipURI is secure.
961     */
962    public void setSecure(boolean secure) {
963        if (secure)
964            this.scheme = SIPS;
965        else
966            this.scheme = SIP;
967    }
968
969    /** Sets the value of the <code>ttl</code> parameter. The ttl parameter
970     * specifies the time-to-live value when packets are sent using UDP
971     * multicast. This is equivalent to setParameter("ttl", ttl).
972     *
973     * @param ttl - new value of the <code>ttl</code> parameter
974     */
975    public void setTTLParam(int ttl) {
976        if (ttl <= 0)
977            throw new IllegalArgumentException("Bad ttl value");
978        if (uriParms != null) {
979            NameValue nv = new NameValue("ttl", Integer.valueOf(ttl));
980            uriParms.set(nv);
981        }
982    }
983
984    /** Sets the value of the "transport" parameter. This parameter specifies
985     * which transport protocol to use for sending requests and responses to
986     * this entity. The following values are defined: "udp", "tcp", "sctp",
987     * "tls", but other values may be used also. This method is equivalent to
988     * setParameter("transport", transport). Transport parameter constants
989     * are defined in the {@link javax.sip.ListeningPoint}.
990     *
991     * @param transport - new value for the "transport" parameter
992     * @see javax.sip.ListeningPoint
993     */
994    public void setTransportParam(String transport) throws ParseException {
995        if (transport == null)
996            throw new NullPointerException("null arg");
997        if (transport.compareToIgnoreCase("UDP") == 0
998            || transport.compareToIgnoreCase("TLS") == 0
999            || transport.compareToIgnoreCase("TCP") == 0
1000            || transport.compareToIgnoreCase("SCTP") == 0) {
1001            NameValue nv = new NameValue(TRANSPORT, transport.toLowerCase());
1002            uriParms.set(nv);
1003        } else
1004            throw new ParseException("bad transport " + transport, 0);
1005    }
1006
1007    /** Returns the user part of this SipURI, or null if it is not set.
1008     *
1009     * @return  the user part of this SipURI
1010     */
1011    public String getUserParam() {
1012        return getParameter("user");
1013
1014    }
1015
1016    /** Returns whether the the <code>lr</code> parameter is set. This is
1017     * equivalent to hasParameter("lr"). This interface has no getLrParam as
1018     * RFC3261 does not specify any values for the "lr" paramater.
1019     *
1020     * @return true if the "lr" parameter is set, false otherwise.
1021     */
1022    public boolean hasLrParam() {
1023        return uriParms.getNameValue("lr") != null;
1024    }
1025
1026
1027    /**
1028     * Returns whether the <code>gr</code> parameter is set.
1029     *
1030     * Not part on the interface since gruu is not part of the base RFC3261.
1031     */
1032    public boolean hasGrParam() {
1033        return uriParms.getNameValue(GRUU) != null;
1034    }
1035
1036    /**
1037     * Sets the <code>gr</code> parameter.
1038     *
1039     * Not part on the interface since gruu is not part of the base RFC3261.
1040     */
1041    public void setGrParam(String value) {
1042            this.uriParms.set(GRUU, value); // JvB: fixed to not add duplicates
1043    }
1044
1045    /**
1046     * Sets the <code>gr</code> parameter.
1047     *
1048     * Not part on the interface since gruu is not part of the base RFC3261.
1049     */
1050    public String getGrParam() {
1051            return (String) this.uriParms.getValue(GRUU);   // JvB: fixed to not add duplicates
1052    }
1053
1054    /**
1055     *remove the +sip-instance value from the parameter list if it exists.
1056     */
1057
1058}
1059