content: /*
  * Conditions Of Use
  *
  * This software was developed by employees of the National Institute of
  * Standards and Technology (NIST), an agency of the Federal Government.
  * Pursuant to title 15 Untied States Code Section 105, works of NIST
  * employees are not subject to copyright protection in the United States
  * and are considered to be in the public domain.  As a result, a formal
  * license is not needed to use the software.
  *
  * This software is provided by NIST as a service and is expressly
  * provided "AS IS."  NIST MAKES NO WARRANTY OF ANY KIND, EXPRESS, IMPLIED
  * OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTY OF
  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT
  * AND DATA ACCURACY.  NIST does not warrant or make any representations
  * regarding the use of the software or the results thereof, including but
  * not limited to the correctness, accuracy, reliability or usefulness of
  * the software.
  *
  * Permission to use this software is contingent upon your acceptance
  * of the terms of this agreement
  *
  * .
  *
  */
  package gov2.nist.javax2.sip.parser;
  
  import gov2.nist.core.*;
  import gov2.nist.javax2.sip.header.*;
  
  import java.text.ParseException;
  
  /**
   * Parser for via headers.
   *
   * @version 1.2 $Revision: 1.12 $ $Date: 2009/07/17 18:58:07 $
   * @since 1.1
   *
   * @author Olivier Deruelle
   * @author M. Ranganathan
   */
  public class ViaParser extends HeaderParser {
  
      public ViaParser(String via) {
          super(via);
      }
  
      public ViaParser(Lexer lexer) {
          super(lexer);
      }
  
      /**
       * a parser for the essential part of the via header.
       */
      private void parseVia(Via v) throws ParseException {
          // The protocol
          lexer.match(TokenTypes.ID);
          Token protocolName = lexer.getNextToken();
  
          this.lexer.SPorHT();
          // consume the "/"
          lexer.match('/');
          this.lexer.SPorHT();
          lexer.match(TokenTypes.ID);
          this.lexer.SPorHT();
          Token protocolVersion = lexer.getNextToken();
  
          this.lexer.SPorHT();
  
          // We consume the "/"
          lexer.match('/');
          this.lexer.SPorHT();
          lexer.match(TokenTypes.ID);
          this.lexer.SPorHT();
  
          Token transport = lexer.getNextToken();
          this.lexer.SPorHT();
  
          Protocol protocol = new Protocol();
          protocol.setProtocolName(protocolName.getTokenValue());
          protocol.setProtocolVersion(protocolVersion.getTokenValue());
          protocol.setTransport(transport.getTokenValue());
          v.setSentProtocol(protocol);
  
          // sent-By
          HostNameParser hnp = new HostNameParser(this.getLexer());
          HostPort hostPort = hnp.hostPort( true );
          v.setSentBy(hostPort);
  
          // Ignore blanks
          this.lexer.SPorHT();
  
          // parameters
          while (lexer.lookAhead(0) == ';') {
              this.lexer.consume(1);
              this.lexer.SPorHT();
              NameValue nameValue = this.nameValue();
              String name = nameValue.getName();
              if (name.equals(Via.BRANCH)) {
                  String branchId = (String) nameValue.getValueAsObject();
                  if (branchId == null)
                      throw new ParseException("null branch Id", lexer.getPtr());
  
              }
              v.setParameter(nameValue);
              this.lexer.SPorHT();
          }
  
          //
          // JvB Note: RFC3261 does not allow a comment in Via headers anymore
          //
          if (lexer.lookAhead(0) == '(') {
              this.lexer.selectLexer("charLexer");
              lexer.consume(1);
              StringBuffer comment = new StringBuffer();
              while (true) {
                  char ch = lexer.lookAhead(0);
                  if (ch == ')') {
                      lexer.consume(1);
                      break;
                  } else if (ch == '\\') {
                      // Escaped character
                      Token tok = lexer.getNextToken();
                      comment.append(tok.getTokenValue());
                      lexer.consume(1);
                      tok = lexer.getNextToken();
                      comment.append(tok.getTokenValue());
                      lexer.consume(1);
                  } else if (ch == '\n') {
                      break;
                  } else {
                      comment.append(ch);
                      lexer.consume(1);
                  }
              }
              v.setComment(comment.toString());
          }
  
      }
  
      /**
       * Overrides the superclass nameValue parser because we have to tolerate
       * IPV6 addresses in the received parameter.
       */
      protected NameValue nameValue() throws ParseException {
          if (debug)
              dbg_enter("nameValue");
          try {
  
              lexer.match(LexerCore.ID);
              Token name = lexer.getNextToken();
              // eat white space.
              lexer.SPorHT();
              try {
  
                  boolean quoted = false;
  
                  char la = lexer.lookAhead(0);
  
                  if (la == '=') {
                      lexer.consume(1);
                      lexer.SPorHT();
                      String str = null;
                      if (name.getTokenValue().compareToIgnoreCase(Via.RECEIVED) == 0) {
                          // Allow for IPV6 Addresses.
                          // these could have : in them!
                          str = lexer.byteStringNoSemicolon();
                      } else {
                          if (lexer.lookAhead(0) == '\"') {
                              str = lexer.quotedString();
                              quoted = true;
                          } else {
                              lexer.match(LexerCore.ID);
                              Token value = lexer.getNextToken();
                              str = value.getTokenValue();
                          }
                      }
                      NameValue nv = new NameValue(name.getTokenValue()
                              .toLowerCase(), str);
                      if (quoted)
                          nv.setQuotedValue();
                      return nv;
                  } else {
                      return new NameValue(name.getTokenValue().toLowerCase(),
                              null);
                  }
              } catch (ParseException ex) {
                  return new NameValue(name.getTokenValue(), null);
              }
  
          } finally {
              if (debug)
                  dbg_leave("nameValue");
          }
  
      }
  
      public SIPHeader parse() throws ParseException {
          if (debug)
              dbg_enter("parse");
          try {
              ViaList viaList = new ViaList();
              // The first via header.
              this.lexer.match(TokenTypes.VIA);
              this.lexer.SPorHT(); // ignore blanks
              this.lexer.match(':'); // expect a colon.
              this.lexer.SPorHT(); // ingore blanks.
  
              while (true) {
                  Via v = new Via();
                  parseVia(v);
                  viaList.add(v);
                  this.lexer.SPorHT(); // eat whitespace.
                  if (this.lexer.lookAhead(0) == ',') {
                      this.lexer.consume(1); // Consume the comma
                      this.lexer.SPorHT(); // Ignore space after.
                  }
                  if (this.lexer.lookAhead(0) == '\n')
                      break;
              }
              this.lexer.match('\n');
              return viaList;
          } finally {
              if (debug)
                  dbg_leave("parse");
          }
  
      }
  
      /**
       *
       * public static void main(String args[]) throws ParseException { String
       * via[] = { "Via: SIP/2.0/UDP 135.180.130.133;branch=-12345\n", "Via:
       * SIP/2.0/UDP 166.34.120.100;branch=0000045d-00000001"+ ",SIP/2.0/UDP
       * 166.35.224.216:5000\n", "Via: SIP/2.0/UDP sip33.example.com,"+ "
       * SIP/2.0/UDP sip32.example.com (oli),"+ "SIP/2.0/UDP sip31.example.com\n",
       * "Via: SIP/2.0/UDP host.example.com;received=::133;"+ "
       * branch=C1C3344E2710000000E299E568E7potato10potato0potato0\n", "Via:
       * SIP/2.0/UDP host.example.com;received=135.180.130.133;"+ "
       * branch=C1C3344E2710000000E299E568E7potato10potato0potato0\n", "Via:
       * SIP/2.0/UDP company.com:5604 ( Hello )"+ ", SIP / 2.0 / UDP
       * 135.180.130.133\n", "Via: SIP/2.0/UDP
       * 129.6.55.9:7060;received=stinkbug.antd.nist.gov\n",
       *
       * "Via: SIP/2.0/UDP ss2.wcom.com:5060;branch=721e418c4.1"+ ", SIP/2.0/UDP
       * ss1.wcom.com:5060;branch=2d4790.1"+ " , SIP/2.0/UDP here.com:5060( Hello
       * the big world) \n" ,"Via: SIP/2.0/UDP
       * ss1.wcom.com:5060;branch=2d4790.1\n", "Via: SIP/2.0/UDP
       * first.example.com:4000;ttl=16"+ ";maddr=224.2.0.1 ;branch=a7c6a8dlze.1
       * (Acme server)\n" };
       *
       * for (int i = 0; i < via.length; i++ ) { ViaParser vp = new
       * ViaParser(via[i]); System.out.println("toParse = " + via[i]); ViaList vl =
       * (ViaList) vp.parse(); System.out.println("encoded = " + vl.encode()); }
       *  }
       *
       */
  
  }
  