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.header;
30
31import gov.nist.core.Host;
32import gov.nist.core.HostPort;
33import gov.nist.core.NameValue;
34import gov.nist.core.NameValueList;
35import gov.nist.javax.sip.stack.HopImpl;
36
37import javax.sip.InvalidArgumentException;
38import javax.sip.address.Hop;
39import javax.sip.header.ViaHeader;
40import java.text.ParseException;
41
42/**
43 * Via SIPHeader (these are strung together in a ViaList).
44 *
45 * @see ViaList
46 *
47 * @version 1.2 $Revision: 1.17 $ $Date: 2009/10/18 13:46:33 $
48 *
49 * @author M. Ranganathan   <br/>
50 *
51 *
52 *
53 */
54public class Via
55    extends ParametersHeader
56    implements javax.sip.header.ViaHeader, ViaHeaderExt {
57
58    /**
59     * Comment for <code>serialVersionUID</code>
60     */
61    private static final long serialVersionUID = 5281728373401351378L;
62
63    /** The branch parameter is included by every forking proxy.
64    */
65    public static final String BRANCH = ParameterNames.BRANCH;
66
67    /** The "received" parameter is added only for receiver-added Via Fields.
68     */
69    public static final String RECEIVED = ParameterNames.RECEIVED;
70
71    /** The "maddr" paramter is designating the multicast address.
72     */
73    public static final String MADDR = ParameterNames.MADDR;
74
75    /** The "TTL" parameter is designating the time-to-live value.
76     */
77    public static final String TTL = ParameterNames.TTL;
78
79    /** The RPORT parameter.
80    */
81    public static final String RPORT = ParameterNames.RPORT;
82
83    /** sentProtocol field.
84     */
85    protected Protocol sentProtocol;
86
87    /** sentBy field.
88     */
89    protected HostPort sentBy;
90
91    /**
92     * comment field
93     *
94     * JvB note: RFC3261 does not allow a comment to appear in Via headers, and this
95     * is not accessible through the API. Suggest removal
96     */
97    protected String comment;
98
99    private boolean rPortFlag = false;
100
101    /** Default constructor
102    */
103    public Via() {
104        super(NAME);
105        sentProtocol = new Protocol();
106    }
107
108    public boolean equals(Object other) {
109
110        if (other==this) return true;
111
112        if (other instanceof ViaHeader) {
113            final ViaHeader o = (ViaHeader) other;
114            return getProtocol().equalsIgnoreCase( o.getProtocol() )
115                && getTransport().equalsIgnoreCase( o.getTransport() )
116                && getHost().equalsIgnoreCase( o.getHost() )
117                && getPort() == o.getPort()
118                && equalParameters( o );
119        }
120        return false;
121    }
122
123
124    /** get the Protocol Version
125     * @return String
126     */
127    public String getProtocolVersion() {
128        if (sentProtocol == null)
129            return null;
130        else
131            return sentProtocol.getProtocolVersion();
132    }
133
134    /**
135     * Accessor for the sentProtocol field.
136     * @return Protocol field
137     */
138    public Protocol getSentProtocol() {
139
140        return sentProtocol;
141    }
142
143    /**
144     * Accessor for the sentBy field
145     *@return SentBy field
146     */
147    public HostPort getSentBy() {
148        return sentBy;
149    }
150
151    /**
152     * Get the host, port and transport as a Hop. This is
153     * useful for the stack to avoid duplication of code.
154     *
155     */
156    public Hop getHop() {
157        HopImpl hop = new HopImpl(sentBy.getHost().getHostname(),
158                sentBy.getPort(),sentProtocol.getTransport());
159        return hop;
160    }
161
162    /**
163     * Accessor for the parameters field
164     * @return parameters field
165     */
166    public NameValueList getViaParms() {
167        return parameters;
168    }
169
170    /**
171     * Accessor for the comment field.
172     * @return comment field.
173     * @deprecated RFC 2543 support feature.
174     */
175    public String getComment() {
176        return comment;
177    }
178
179
180
181    /** port of the Via Header.
182     * @return true if Port exists.
183     */
184    public boolean hasPort() {
185        return (getSentBy()).hasPort();
186    }
187
188    /** comment of the Via Header.
189     *
190     * @return false if comment does not exist and true otherwise.
191     */
192    public boolean hasComment() {
193        return comment != null;
194    }
195
196    /** remove the port.
197     */
198    public void removePort() {
199        sentBy.removePort();
200    }
201
202    /** remove the comment field.
203     */
204    public void removeComment() {
205        comment = null;
206    }
207
208    /** set the Protocol Version
209     * @param protocolVersion String to set
210     */
211    public void setProtocolVersion(String protocolVersion) {
212        if (sentProtocol == null)
213            sentProtocol = new Protocol();
214        sentProtocol.setProtocolVersion(protocolVersion);
215    }
216
217    /** set the Host of the Via Header
218         * @param host String to set
219         */
220    public void setHost(Host host) {
221        if (sentBy == null) {
222            sentBy = new HostPort();
223        }
224        sentBy.setHost(host);
225    }
226
227    /**
228     * Set the sentProtocol member
229     * @param s Protocol to set.
230     */
231    public void setSentProtocol(Protocol s) {
232        sentProtocol = s;
233    }
234
235    /**
236     * Set the sentBy member
237     * @param s HostPort to set.
238     */
239    public void setSentBy(HostPort s) {
240        sentBy = s;
241    }
242
243    /**
244     * Set the comment member
245     * @param c String to set.
246     * @deprecated This is an RFC 2543 feature.
247     */
248    public void setComment(String c) {
249        comment = c;
250    }
251
252    /** Encode the body of this header (the stuff that follows headerName).
253     * A.K.A headerValue.
254     */
255    protected String encodeBody() {
256        return encodeBody(new StringBuffer()).toString();
257    }
258
259    protected StringBuffer encodeBody(StringBuffer buffer) {
260        sentProtocol.encode(buffer);
261        buffer.append(SP);
262        sentBy.encode(buffer);
263        if (!parameters.isEmpty()) {
264            buffer.append(SEMICOLON);
265            parameters.encode(buffer);
266        }
267        if (comment != null) {
268            buffer.append(SP).append(LPAREN).append(comment).append(RPAREN);
269        }
270        if (rPortFlag) buffer.append(";rport");
271        return buffer;
272    }
273
274    /**
275     * Set the host part of this ViaHeader to the newly supplied <code>host</code>
276     * parameter.
277     *
278     * @throws ParseException which signals that an error has been reached
279     * unexpectedly while parsing the host value.
280     */
281    public void setHost(String host) throws ParseException {
282        if (sentBy == null)
283            sentBy = new HostPort();
284        try {
285            Host h = new Host(host);
286            sentBy.setHost(h);
287        } catch (Exception e) {
288            throw new NullPointerException(" host parameter is null");
289        }
290    }
291
292    /**
293    * Returns the host part of this ViaHeader.
294    *
295    * @return  the string value of the host
296    */
297    public String getHost() {
298        if (sentBy == null)
299            return null;
300        else {
301            Host host = sentBy.getHost();
302            if (host == null)
303                return null;
304            else
305                return host.getHostname();
306        }
307    }
308
309    /**
310     * Set the port part of this ViaHeader to the newly supplied <code>port</code>
311     * parameter.
312     *
313     * @param port - the Integer.valueOf value of the port of this ViaHeader
314     */
315    public void setPort(int port) throws InvalidArgumentException {
316
317        if ( port!=-1 && (port<1 || port>65535)) {
318            throw new InvalidArgumentException( "Port value out of range -1, [1..65535]" );
319        }
320
321        if (sentBy == null)
322            sentBy = new HostPort();
323        sentBy.setPort(port);
324    }
325
326    /**
327     * Set the RPort flag parameter
328     */
329    public void setRPort(){
330        rPortFlag = true;
331    }
332
333    /**
334     * Returns the port part of this ViaHeader.
335     *
336     * @return the integer value of the port
337     */
338    public int getPort() {
339        if (sentBy == null)
340            return -1;
341        return sentBy.getPort();
342    }
343
344
345    /**
346    * Return the rport parameter.
347    *
348    *@return the rport parameter or -1.
349    */
350       public int getRPort() {
351         String strRport = getParameter(ParameterNames.RPORT);
352         if (strRport != null && ! strRport.equals(""))
353            return Integer.valueOf(strRport).intValue();
354         else
355            return -1;
356         }
357
358
359    /**
360     * Returns the value of the transport parameter.
361     *
362     * @return the string value of the transport paramter of the ViaHeader
363     */
364    public String getTransport() {
365        if (sentProtocol == null)
366            return null;
367        return sentProtocol.getTransport();
368    }
369
370    /**
371     * Sets the value of the transport. This parameter specifies
372     * which transport protocol to use for sending requests and responses to
373     * this entity. The following values are defined: "udp", "tcp", "sctp",
374     * "tls", but other values may be used also.
375     *
376     * @param transport - new value for the transport parameter
377     * @throws ParseException which signals that an error has been reached
378     * unexpectedly while parsing the transport value.
379     */
380    public void setTransport(String transport) throws ParseException {
381        if (transport == null)
382            throw new NullPointerException(
383                "JAIN-SIP Exception, "
384                    + "Via, setTransport(), the transport parameter is null.");
385        if (sentProtocol == null)
386            sentProtocol = new Protocol();
387        sentProtocol.setTransport(transport);
388    }
389
390    /**
391     * Returns the value of the protocol used.
392     *
393     * @return the string value of the protocol paramter of the ViaHeader
394     */
395    public String getProtocol() {
396        if (sentProtocol == null)
397            return null;
398        return sentProtocol.getProtocol();// JvB: Return name ~and~ version
399    }
400
401    /**
402     * Sets the value of the protocol parameter. This parameter specifies
403     * which protocol is used, for example "SIP/2.0".
404     *
405     * @param protocol - new value for the protocol parameter
406     * @throws ParseException which signals that an error has been reached
407     * unexpectedly while parsing the protocol value.
408     */
409    public void setProtocol(String protocol) throws ParseException {
410        if (protocol == null)
411            throw new NullPointerException(
412                "JAIN-SIP Exception, "
413                    + "Via, setProtocol(), the protocol parameter is null.");
414
415        if (sentProtocol == null)
416            sentProtocol = new Protocol();
417
418        sentProtocol.setProtocol(protocol);
419    }
420
421    /**
422     * Returns the value of the ttl parameter, or -1 if this is not set.
423     *
424     * @return the integer value of the <code>ttl</code> parameter
425     */
426    public int getTTL() {
427        int ttl = getParameterAsInt(ParameterNames.TTL);
428        return ttl;
429    }
430
431    /**
432     * Sets the value of the ttl parameter. The ttl parameter specifies the
433     * time-to-live value when packets are sent using UDP multicast.
434     *
435     * @param ttl - new value of the ttl parameter
436     * @throws InvalidArgumentException if supplied value is less than zero or
437     * greater than 255, excluding -1 the default not set value.
438     */
439    public void setTTL(int ttl) throws InvalidArgumentException {
440        if (ttl < 0 && ttl != -1)
441            throw new InvalidArgumentException(
442                "JAIN-SIP Exception"
443                    + ", Via, setTTL(), the ttl parameter is < 0");
444        setParameter(new NameValue(ParameterNames.TTL, Integer.valueOf(ttl)));
445    }
446
447    /**
448     * Returns the value of the <code>maddr</code> parameter, or null if this
449     * is not set.
450     *
451     * @return the string value of the maddr parameter
452     */
453    public String getMAddr() {
454        return getParameter(ParameterNames.MADDR);
455    }
456
457    /**
458     * Sets the value of the <code>maddr</code> parameter of this ViaHeader. The
459     * maddr parameter indicates the server address to be contacted for this
460     * user, overriding any address derived from the host field.
461     *
462     * @param  mAddr new value of the <code>maddr</code> parameter
463     * @throws ParseException which signals that an error has been reached
464     * unexpectedly while parsing the mAddr value.
465     */
466    public void setMAddr(String mAddr) throws ParseException {
467        if (mAddr == null)
468            throw new NullPointerException(
469                "JAIN-SIP Exception, "
470                    + "Via, setMAddr(), the mAddr parameter is null.");
471
472        Host host = new Host();
473        host.setAddress(mAddr);
474        NameValue nameValue = new NameValue(ParameterNames.MADDR, host);
475        setParameter(nameValue);
476
477    }
478
479    /**
480     * Gets the received paramater of the ViaHeader. Returns null if received
481     * does not exist.
482     *
483     * @return the string received value of ViaHeader
484     */
485    public String getReceived() {
486        return getParameter(ParameterNames.RECEIVED);
487    }
488
489    /**
490     * Sets the received parameter of ViaHeader.
491     *
492     * @param received - the newly supplied received parameter.
493     * @throws ParseException which signals that an error has been reached
494     * unexpectedly while parsing the received value.
495     */
496    public void setReceived(String received) throws ParseException {
497        if (received == null)
498            throw new NullPointerException(
499                "JAIN-SIP Exception, "
500                    + "Via, setReceived(), the received parameter is null.");
501
502        setParameter(ParameterNames.RECEIVED, received);
503
504    }
505
506    /**
507     * Gets the branch paramater of the ViaHeader. Returns null if branch
508     * does not exist.
509     *
510     * @return the string branch value of ViaHeader
511     */
512    public String getBranch() {
513        return getParameter(ParameterNames.BRANCH);
514    }
515
516    /**
517     * Sets the branch parameter of the ViaHeader to the newly supplied
518     * branch value.
519     *
520     * @param branch - the new string branch parmameter of the ViaHeader.
521     * @throws ParseException which signals that an error has been reached
522     * unexpectedly while parsing the branch value.
523     */
524    public void setBranch(String branch) throws ParseException {
525        if (branch == null || branch.length()==0)
526            throw new NullPointerException(
527                "JAIN-SIP Exception, "
528                    + "Via, setBranch(), the branch parameter is null or length 0.");
529
530        setParameter(ParameterNames.BRANCH, branch);
531    }
532
533    public Object clone() {
534        Via retval = (Via) super.clone();
535        if (this.sentProtocol != null)
536            retval.sentProtocol = (Protocol) this.sentProtocol.clone();
537        if (this.sentBy != null)
538            retval.sentBy = (HostPort) this.sentBy.clone();
539        if ( this.getRPort() != -1)
540            retval.setParameter(RPORT,this.getRPort());
541        return retval;
542    }
543
544    /*
545     * (non-Javadoc)
546     * @see gov.nist.javax.sip.header.ViaHeaderExt#getSentByField()
547     */
548    public String getSentByField() {
549        if(sentBy != null)
550            return sentBy.encode();
551        return null;
552    }
553    /*
554     * (non-Javadoc)
555     * @see gov.nist.javax.sip.header.ViaHeaderExt#getSentProtocolField()
556     */
557    public String getSentProtocolField() {
558        if(sentProtocol != null)
559            return sentProtocol.encode();
560        return null;
561    }
562
563}
564