anchor.diff:  empty_displayname(Name) ->
       Name.
   
  -auth_print(Auth) ->
  -    auth_print(Auth, false).
  -
  -auth_print(Auth, Stale) ->
  -    {Realm, Nonce, Opaque} = Auth,
  -    ["Digest realm=\"" ++ Realm ++ "\", nonce=\"" ++ Nonce ++ "\", opaque=\"" ++ Opaque ++ "\"" ++
  -     case Stale of
  -	 true ->
  -	     ", stale=true";
  -	 _ ->
  -	     ""
  -     end
  -    ].
  -
  -auth([In]) ->
  -    % lowercase first word
  -    case string:chr(In, $\ ) of
  -	0 ->
  -	    In;	% uhm, is really broken
  -	Index when integer(Index) ->
  -	    H = string:substr(In, 1, Index - 1),
  -	    LH = httpd_util:to_lower(H),
  -	    T = string:substr(In, Index + 1),
  -	    Out = [lists:flatten(LH ++ " " ++ T)],
  -	    auth2(Out)
  -    end.
  -
  -auth2(["gssapi " ++ String]) ->
  -    Headers = comma(String),
  -    L = lists:map(fun(A) ->
  -			  H = string:strip(A,left),
  -			  Index = string:chr(H, $=),
  -			  Name = string:substr(H, 1, Index - 1),
  -			  Value = string:substr(H, Index + 1),
  -			  
  -			  {Name, unquote(Value)}
  -		  end, Headers),
  -    dict:from_list(L);
  -
  -auth2(["digest " ++ String]) ->
  -    Headers = comma(String),
  -    L = lists:map(fun(A) ->
  -			  H = string:strip(A,left),
  -			  Index = string:chr(H, $=),
  -			  Name = string:substr(H, 1, Index - 1),
  -			  Value = string:substr(H, Index + 1),
  -			  
  -			  {Name, unquote(Value)}
  -		  end, Headers),
  -    dict:from_list(L);
  -
  -auth2(In) ->
  -    logger:log(error, "sipheader:auth() called with unrecognized authentication data"),
  -    throw({siperror, 500, "Server Internal Error"}).
  -
  -unescape([]) ->
  -    [];
  -unescape([$%, C1, C2 | Rest]) ->
  -    [hex:from([C1, C2]) | unescape(Rest)];
  -unescape([C | Rest]) ->
  -    [C | unescape(Rest)].
  -
  -param_to_dict(Param) ->
  -    L = lists:map(fun(A) ->
  -			  H = string:strip(A,left),
  -			  Index = string:chr(H, $=),
  -			  case Index of
  -			      0 ->
  -			          {httpd_util:to_lower(H), ""};
  -			      _ ->
  -				  Name = httpd_util:to_lower(string:substr(H, 1, Index - 1)),
  -				  Value = string:substr(H, Index + 1),
  -				  {Name, unescape(Value)}
  -			  end
  -		  end, Param),
  -    dict:from_list(L).    
  -
  -dict_to_param(Dict) ->
  -    list_to_parameters(lists:keysort(1, dict:to_list(Dict))).
  -    
  -list_to_parameters([]) ->
  -    [];
  -list_to_parameters([{Key, Value}]) ->
  -    [Key ++ "=" ++ Value];
  -list_to_parameters([{Key, Value} | Rest]) ->
  -    [Key ++ "=" ++ Value | list_to_parameters(Rest)].
  -    
  -
  -httparg(String) ->
  -    Headers = string:tokens(String, "&"),
  -    param_to_dict(Headers).
  -
  -cseq([String]) ->
  -    case string:tokens(String, " ") of
  -	[Seq, Method] ->
  -	    {Seq, Method};
  -	_ ->
  -	    {unparseable, String}
  -    end.
  -
  -cseq_print({Seq, Method}) ->
  -    Seq ++ " " ++ Method.
  -
  -print_one_header(_, _, []) ->
  -    [];
  -print_one_header(Name, LCName, [Value | Rest]) ->
  -    case util:casegrep(Name, ["Allow", "Supported", "Require",
  -			      "Proxy-Require"]) of
  -	true ->
  -	    [Name ++ ": " ++ util:join(lists:append([Value], Rest), ", ")];
  -	_ ->
  -	    lists:append([Name ++ ": " ++ Value], print_one_header(Name, LCName, Rest))
  -    end.
  -
  -build_header(Header) ->
  -    case catch build_header_unsafe(Header) of
  -	{'EXIT', E} ->
  -	    logger:log(error, "=ERROR REPORT==== failed to build header ~p,~nfrom build_header_unsafe :~n~p", [Header, E]),
  -	    throw({siperror, 500, "Server Internal Error"});
  -	Res ->
  -	    Res
  -    end.
  -
  -build_header_unsafe(Header) ->
  -    Lines = keylist:map(fun print_one_header/3, Header),
  -    lists:map(fun(H) ->
  -			util:concat(H, "\r\n")
  -		end, Lines).
  -
  -get_tag([String]) ->
  -    Index = string:chr(String, $>),
  -    ParamStr = string:substr(String, Index + 1),
  -    ParamList = string:tokens(ParamStr, ";"),
  -    ParamDict = param_to_dict(ParamList),
  -    case dict:find("tag", ParamDict) of
  -	error ->
  -	    none;
  -	{ok, Tag} ->
  -	    Tag
  -    end.
  -
  -dialogueid(Header) ->
  -    get_dialogid(Header).
  -
  -via_sentby(Via) when record(Via, via) ->
  -    {Via#via.proto, Via#via.host, Via#via.port}.
  -
  -get_server_transaction_id(Request) ->
  -    case catch guarded_get_server_transaction_id(Request) of
  -	{'EXIT', E} ->
  -	    logger:log(error, "=ERROR REPORT==== from get_server_transaction_id(~p) :~n~p", [Request, E]),
  -	    error;
  -	Id ->
  -	    Id
  -    end.
  -
  -get_client_transaction_id(Response) ->
  -    case catch guarded_get_client_transaction_id(Response) of
  -	{'EXIT', E} ->
  -	    logger:log(error, "=ERROR REPORT==== from get_client_transaction_id(~p) :~n~p", [Response, E]),
  -	    error;
  -	Id ->
  -	    Id
  -    end.
  -
  -get_server_transaction_ack_id_2543(Request) ->
  -    % When using this function, you have to make sure the To-tag
  -    % of this ACK matches the To-tag of the response you think this
  -    % might be the ACK for! RFC3261 17.2.3
  -    case catch guarded_get_server_transaction_ack_id_2543(Request) of
  -	{'EXIT', E} ->
  -	    logger:log(error, "=ERROR REPORT==== from get_server_transaction_ack_id_2543(~p) :~n~p", [Request, E]),
  -	    error;
  -	Id ->
  -	    Id
  -    end.
  -
  -
  -guarded_get_server_transaction_id(Request) when record(Request, request) ->
  -    R = case Request#request.method of
  -	"ACK" ->
  -	    % RFC3261 17.2.3, when looking for server transaction for ACK, the method of the transaction is INVITE
  -	    Request#request{method="INVITE"};
  -	_ ->
  -	    Request
  -    end,	    
  -    TopVia = sipheader:topvia(R#request.header),
  -    Branch = get_via_branch(TopVia),
  -    case Branch of
  -	"z9hG4bK" ++ RestOfBranch ->
  -	    guarded_get_server_transaction_id_3261(R#request.method, TopVia);
  -	_ ->
  -	    guarded_get_server_transaction_id_2543(R, TopVia)
  -    end.
  -
  -guarded_get_server_transaction_ack_id_2543(Request) when record(Request, request) ->
  -    {URI, Header} = {Request#request.uri, Request#request.header},
  -    TopVia = remove_branch(sipheader:topvia(Header)),
  -    [CallID] = keylist:fetch("Call-ID", Header),
  -    {CSeqNum, _} = sipheader:cseq(keylist:fetch("CSeq", Header)),
  -    FromTag = sipheader:get_tag(keylist:fetch("From", Header)),
  -    ToTag = sipheader:get_tag(keylist:fetch("To", Header)),
  -    {URI, FromTag, CallID, CSeqNum, TopVia}.
  -
  -remove_branch(Via) when record(Via, via) ->
  -    ParamDict = sipheader:param_to_dict(Via#via.param),
  -    NewDict = dict:erase("branch", ParamDict),
  -    Via#via{param=sipheader:dict_to_param(NewDict)}.
  -
  -guarded_get_client_transaction_id(Response) when record(Response, response) ->
  -    Header = Response#response.header,
  -    TopVia = sipheader:topvia(Header),
  -    Branch = get_via_branch(TopVia),
  -    {_, CSeqMethod} = sipheader:cseq(keylist:fetch("CSeq", Header)),
  -    {Branch, CSeqMethod}.
  -
  -get_server_transaction_id_using_3261_response_header(Header) ->
  -    TopVia = topvia(Header),
  -    {_, CSeqMethod} = sipheader:cseq(keylist:fetch("CSeq", Header)),
  -    guarded_get_server_transaction_id_3261(CSeqMethod, TopVia).
  -
  +%%--------------------------------------------------------------------
  +%% Function:
  +%% Descrip.:
  +%% Returns :
  +%%--------------------------------------------------------------------
   guarded_get_server_transaction_id_3261(Method, TopVia) ->
       Branch = get_via_branch_full(TopVia),
       SentBy = via_sentby(TopVia),
  
positive.code: 			   end, Headers),
  		 via(Rest)).
  
  topvia(Header) ->
      case via(keylist:fetch("Via", Header)) of
  	[] -> none;
  	[TopVia | _] when record(TopVia, via) -> TopVia;
  	_ -> error
      end.
  
  print_parameters([]) ->
      "";
  print_parameters([A | B]) ->
      ";" ++ A ++ print_parameters(B).
  
  via_print(Via) when record(Via, via) ->
      via_print([Via]);
  via_print(Via) ->
      lists:map(fun(H) ->
  		      {Protocol, Host, Port, Parameters} = {H#via.proto, H#via.host, H#via.port, H#via.param},
  		      Protocol ++ " " ++ sipurl:print_hostport(Host, Port) ++ print_parameters(Parameters)
  	      end, Via).
  
  via_params(Via) when record(Via, via) ->
      param_to_dict(Via#via.param).
  
  contact_print(Contact) ->
      lists:map(fun(H) ->
  		      name_print(H)
  	      end, Contact).
  
  to_print(To) ->
      name_print(To).
  
  name_print({_, wildcard, Parameters}) ->
      sipurl:print({wildcard, Parameters});
      
  name_print({none, URI}) ->
      "<" ++ sipurl:print(URI) ++ ">";
  
  name_print({Name, URI}) ->
      "\"" ++ Name ++ "\" <" ++ sipurl:print(URI) ++ ">".
  
  unquote([$" | QString]) ->
      Index = string:chr(QString, $"),
      string:substr(QString, 1, Index - 1);
  
negative.code: unquote(QString) ->
      QString.
  
  
  %%--------------------------------------------------------------------
  %% Function: param_to_dict(Param)
  %%           Param = list() of string(), each string is a "para=value"
  %%           pair, that may have preceding or trailing spaces as well
  %%           as hex encoded values (e.g. chars of the format %hh,
  %%           h = hex number)
  %% Descrip.: convert sip paramter strings into dictionary
  %% Returns : dict()
  %%--------------------------------------------------------------------
  param_to_dict(Param) ->
      L = lists:map(fun(A) ->
  			  H = string:strip(A,left),
  			  Index = string:chr(H, $=),
  			  case Index of
  			      0 ->
  			          {httpd_util:to_lower(H), ""};
  			      _ ->
  				  Name = httpd_util:to_lower(string:substr(H, 1, Index - 1)),
  				  Value = string:substr(H, Index + 1),
  				  {Name, unescape(Value)}
  			  end
  		  end, Param),
      dict:from_list(L).
  
  %% convert (2) hex codes to singel 8 bit char
  unescape([]) ->
      [];
  unescape([$%, C1, C2 | Rest]) ->
      [hex:from([C1, C2]) | unescape(Rest)];
  unescape([C | Rest]) ->
      [C | unescape(Rest)].
  
  %%--------------------------------------------------------------------
  %% Function: dict_to_param(Dict)
  %%           Dict = dict(), a dictionary containing parameter entries
  %% Descrip.: convert a dictionary containing parameters back into a
  %%           "name=value" format - the inverse of param_to_dict/1
  %% Returns : list() of string()
  %% XXX should certain chars in the "value" part be hex encoded ?
  %%--------------------------------------------------------------------
  dict_to_param(Dict) ->
      list_to_parameters(lists:keysort(1, dict:to_list(Dict))).
  
  list_to_parameters([]) ->
      [];
  list_to_parameters([{Key, Value}]) ->
      [Key ++ "=" ++ Value];
  list_to_parameters([{Key, Value} | Rest]) ->
      [Key ++ "=" ++ Value | list_to_parameters(Rest)].
  
  
  %%--------------------------------------------------------------------
  %% Function:
  %% Descrip.:
  %% Returns :
  %%--------------------------------------------------------------------
  httparg(String) ->
      Headers = string:tokens(String, "&"),
      param_to_dict(Headers).
  
  
  %%--------------------------------------------------------------------
  %% Function: cseq([String])
  %%           cseq(Header)
  %%           String = string(), the contens of a CSEQ header (usually 
  %%           the result of keylist:fetch(cseq, Header))
  %%           Header = keylist record()
  %% Descrip.: parse header data
  %% Returns : {Seq, Method} | {unparseable, String}
  %%--------------------------------------------------------------------
  cseq(Header) when is_record(Header, keylist) -> 
      cseq(keylist:fetch("CSeq", Header));
  
  cseq([String]) ->
      case string:tokens(String, " ") of
  	[Seq, Method] ->
  	    {Seq, Method};
  	_ ->
  	    {unparseable, String}
      end.
  
  %%--------------------------------------------------------------------
  %% Function:
  %% Descrip.: print data parsed with cseq/1
  %% Returns :
  %%--------------------------------------------------------------------
  cseq_print({Seq, Method}) ->
      Seq ++ " " ++ Method.
  
  %%--------------------------------------------------------------------
  %% Function: callid(Header)
  %%           Header = keylist record()
  %% Descrip.: get call from header
  %% Returns : string()
  %%--------------------------------------------------------------------
  callid(Header) when is_record(Header, keylist) -> 
      [CallId] = keylist:fetch("Call-Id", Header),
      CallId.
  
  %%--------------------------------------------------------------------
  %% Function: build_header_binary(Header)
  %%           Header = keylist record()
  %% Descrip.: build a sip header
  %% Returns : binary() | throw()
  %%--------------------------------------------------------------------
  build_header_binary(Header) when is_record(Header, keylist) ->
      case catch build_header_unsafe_binary(Header) of
  	{'EXIT', E} ->
  	    logger:log(error, "=ERROR REPORT==== failed to build header ~p,~nfrom build_header_unsafe_binary :~n~p",
  		       [Header, E]),
  	    throw({siperror, 500, "Server Internal Error"});
  	Res ->
  	    Res
      end.
  
  build_header_unsafe_binary(Header) ->
      %% process each line in Header
      Lines = keylist:map(fun print_one_header_binary/3, Header),
      Lines.
  
  
  print_one_header_binary(_, _, []) ->
      [];
  print_one_header_binary(Name, CaseKey, ValueList) ->
      %% certain headers that have multple values are written on a single line separated by "," -
      %% this is not because any RFC says so but because these are common headers that look
      %% considerably much better when appearing on one line
      OneLine =
  	if
  	    CaseKey == "accept" ->		true;
  	    CaseKey == "allow" ->		true;
  	    CaseKey == "allow-events" ->	true;
  	    CaseKey == "supported" ->		true;
  	    CaseKey == "require" ->		true;
  	    CaseKey == "proxy-require" ->	true;
  	    CaseKey == "rtp-rxstat" ->		true;	%% Cisco 79xx
  	    CaseKey == "rtp-txstat" ->		true;	%% Cisco 79xx
  	    true -> false
  	end,
      MakeBin = fun(V) ->                      list_to_binary(V)
                end,
      BinValueList = lists:map(MakeBin, ValueList),
      BinName = list_to_binary(Name),
      print_one_header_binary2(OneLine, BinName, BinValueList).
  
  print_one_header_binary2(true, BinName, BinValueList) ->
      %% return as one line
      OneLine = fun(Value, Acc) ->
  		      case Acc of
  			  [] ->
  			      %% No prior elements - return only Value
  			      [Value];
  			  _ ->
  			      %% Accumulated comma space Value
  			      concat_binary([Acc, $\,, 32, Value])
  		      end
  	      end,
      BinValues = lists:foldl(OneLine, [], BinValueList),
      concat_binary([BinName, $:, 32, BinValues, 13, 10]);
  print_one_header_binary2(false, BinName, [First | Rest]) ->
      %% Return one "Key: Value" for every element in BinValueList
      This = concat_binary([BinName, $:, 32, First, 13, 10]),	%% Name: First\r\n
      [This | print_one_header_binary2(false, BinName, Rest)];
  print_one_header_binary2(false, _BinName, []) ->
      [].
  
  %%--------------------------------------------------------------------
  %% Function:
  %% Descrip.:
  %% Returns :
  %%--------------------------------------------------------------------
  get_tag([String]) ->
      Index = string:chr(String, $>),
      ParamStr = string:substr(String, Index + 1),
      ParamList = string:tokens(ParamStr, ";"),
      ParamDict = param_to_dict(ParamList),
      case dict:find("tag", ParamDict) of
  	error ->
  	    none;
  	{ok, Tag} ->
  	    Tag
      end.
  
  %%--------------------------------------------------------------------
  %% Function: dialogueid(Header)
  %%           Header = keylist record()
  %% Descrip.: get the contens of several sip headers in Header
  %% Returns : {CallID, FromTag, ToTag}
  %%           the contens of "Call-ID", "From" and "To"
  %%--------------------------------------------------------------------
  dialogueid(Header) when is_record(Header, keylist) ->
      get_dialogid(Header).
  
  get_dialogid(Header) ->
      [CallID] = keylist:fetch("Call-Id", Header),
      FromTag = sipheader:get_tag(keylist:fetch("From", Header)),
      ToTag = sipheader:get_tag(keylist:fetch("To", Header)),
      {CallID, FromTag, ToTag}.
  
  %%--------------------------------------------------------------------
  %% Function:
  %% Descrip.:
  %% Returns : {Proto, Host, Port}
  %%--------------------------------------------------------------------
  via_sentby(Via) when is_record(Via, via) ->
      {Via#via.proto, Via#via.host, Via#via.port}.
  
  %%--------------------------------------------------------------------
  %% Function:
  %% Descrip.:
  %% Returns :
  %%--------------------------------------------------------------------
  get_server_transaction_id(Request) ->
      case catch guarded_get_server_transaction_id(Request) of
  	{'EXIT', E} ->
  	    logger:log(error, "=ERROR REPORT==== from get_server_transaction_id(~p) :~n~p", [Request, E]),
  	    error;
  	Id ->
  	    Id
      end.
  
  guarded_get_server_transaction_id(Request) when is_record(Request, request) ->
      R = case Request#request.method of
  	"ACK" ->
  	    % RFC3261 17.2.3, when looking for server transaction for ACK, the method of the transaction is INVITE
  	    Request#request{method="INVITE"};
  	_ ->
  	    Request
      end,
      TopVia = sipheader:topvia(R#request.header),
      Branch = get_via_branch(TopVia),
      case Branch of
  	"z9hG4bK" ++ _RestOfBranch ->
  	    guarded_get_server_transaction_id_3261(R#request.method, TopVia);
  	_ ->
  	    guarded_get_server_transaction_id_2543(R, TopVia)
      end.
  
  %%--------------------------------------------------------------------
  %% Function:
  %% Descrip.:
  %% Returns :
  %%--------------------------------------------------------------------
  get_client_transaction_id(Response) ->
      case catch guarded_get_client_transaction_id(Response) of
  	{'EXIT', E} ->
  	    logger:log(error, "=ERROR REPORT==== from get_client_transaction_id(~p) :~n~p", [Response, E]),
  	    error;
  	Id ->
  	    Id
      end.
  
  guarded_get_client_transaction_id(Response) when is_record(Response, response) ->
      Header = Response#response.header,
      TopVia = sipheader:topvia(Header),
      Branch = get_via_branch(TopVia),
      {_, CSeqMethod} = sipheader:cseq(keylist:fetch("CSeq", Header)),
      {Branch, CSeqMethod}.
  
  %%--------------------------------------------------------------------
  %% Function:
  %% Descrip.:
  %% Returns :
  %%--------------------------------------------------------------------
  get_server_transaction_ack_id_2543(Request) ->
      % When using this function, you have to make sure the To-tag
      % of this ACK matches the To-tag of the response you think this
      % might be the ACK for! RFC3261 17.2.3
      case catch guarded_get_server_transaction_ack_id_2543(Request) of
  	{'EXIT', E} ->
  	    logger:log(error, "=ERROR REPORT==== from get_server_transaction_ack_id_2543(~p) :~n~p", [Request, E]),
  	    error;
  	Id ->
  	    Id
      end.
  
  guarded_get_server_transaction_ack_id_2543(Request) when is_record(Request, request) ->
      {URI, Header} = {Request#request.uri, Request#request.header},
      TopVia = remove_branch(sipheader:topvia(Header)),
      [CallID] = keylist:fetch("Call-Id", Header),
      {CSeqNum, _} = sipheader:cseq(keylist:fetch("CSeq", Header)),
      FromTag = sipheader:get_tag(keylist:fetch("From", Header)),
      %% XXX ToTag is unused, are we supposed to use it or not?
      ToTag = sipheader:get_tag(keylist:fetch("To", Header)),
      {URI, FromTag, CallID, CSeqNum, TopVia}.
  
  remove_branch(Via) when is_record(Via, via) ->
      ParamDict = sipheader:param_to_dict(Via#via.param),
      NewDict = dict:erase("branch", ParamDict),
      Via#via{param=sipheader:dict_to_param(NewDict)}.
  
  %%--------------------------------------------------------------------
  %% Function:
  %% Descrip.:
  %% Returns :
  %%--------------------------------------------------------------------
  get_server_transaction_id_using_3261_response_header(Header) ->
      TopVia = topvia(Header),
      {_, CSeqMethod} = sipheader:cseq(keylist:fetch("CSeq", Header)),
      guarded_get_server_transaction_id_3261(CSeqMethod, TopVia).
  
  %%--------------------------------------------------------------------
  %% Function:
  %% Descrip.:
  %% Returns :
  %%--------------------------------------------------------------------
  get_via_branch(TopVia) when is_record(TopVia, via) ->
      case get_via_branch_full(TopVia) of
  	"z9hG4bK-yxa-" ++ RestOfBranch ->
  	    remove_loop_cookie("z9hG4bK-yxa-" ++ RestOfBranch);
  	Res ->
  	    Res
      end.
  
  %%--------------------------------------------------------------------
  %% Function:
  %% Descrip.:
  %% Returns :
  %%--------------------------------------------------------------------
  remove_loop_cookie(Branch) ->
      case Branch of
  	"z9hG4bK-yxa-" ++ RestOfBranch ->
  	    case sipserver:get_env(detect_loops, true) of
  		true ->
  		    case string:rstr(RestOfBranch, "-o") of
  			0 ->
  			    Branch;
  			Index when is_integer(Index) ->
  			    %% Return branch without Yxa loop cookie
  			    "z9hG4bK-yxa-" ++ string:substr(RestOfBranch, 1, Index - 1)
  		    end;
  		_ ->
  		    Branch
  	    end;
          _ ->
  	    Branch
      end.
  
  %%--------------------------------------------------------------------
  %% Function:
  %% Descrip.:
  %% Returns :
  %%--------------------------------------------------------------------
  get_via_branch_full(Via) when is_record(Via, via) ->
      case dict:find("branch", sipheader:param_to_dict(Via#via.param)) of
  	error ->
  	    none;
  	{ok, Branch} ->
  	    Branch
      end;
  get_via_branch_full(_) ->
      none.
  
  %%--------------------------------------------------------------------
  %% Function: via_is_equal/2
  %% Descrip.: Compare two Via records according to the rules in
  %%           RFC3261 20.42 (Via)
  %% Returns : true  |
  %%           false
  %%--------------------------------------------------------------------
  via_is_equal(A, B) when is_record(A, via), is_record(B, via) ->
      via_is_equal(A, B, [proto, host, port, param]).
  
  
  %%--------------------------------------------------------------------
  %% Function: via_is_equal/3
  %% Descrip.: Compare one or more parts of two Via records according
  %%           to RFC3261 20.42.
  %% Returns : true  |
  %%           false
  %%--------------------------------------------------------------------
  
  %%
  %% Protocol (e.g. "SIP/2.0/TCP"), string compare case sensitive
  %%
  via_is_equal(A, B, [proto | T]) when is_record(A, via), is_record(B, via), A#via.proto == B#via.proto ->
      via_is_equal(A, B, T);
  via_is_equal(A, B, [proto | _T]) when is_record(A, via), is_record(B, via) ->
      false;
  
  %%
  %% Host, string compare case insensitive
  %%
  via_is_equal(A, B, [host | T]) when is_record(A, via), is_record(B, via) ->
      case util:casecompare(A#via.host, B#via.host) of
  	true ->
  	    via_is_equal(A, B, T);
  	_ ->
  	    false
      end;
  
  %%
  %% Port, specified port does not equal un-specified port
  %%
  via_is_equal(A, B, [port | T]) when is_record(A, via), is_record(B, via), A#via.port == B#via.port ->
      via_is_equal(A, B, T);
  via_is_equal(A, B, [port | _T]) when is_record(A, via), is_record(B, via) ->
      false;
  
  %%
  %% Parameters. All parameters must be present and their values must be equal
  %% for the vias to be considerered equal.
  %%
  via_is_equal(A, B, [parameters | T]) ->
      Alist = lists:keysort(1, dict:to_list(A#via.param)),
      Blist = lists:keysort(1, dict:to_list(B#via.param)),
      case Alist of
  	Blist ->
  	    via_is_equal(A, B, T);
  	_ ->
  	    false
      end;
  
  %%
  %% Nothing to compare left, consider them equal
  %%
  via_is_equal(A, B, []) when is_record(A, via), is_record(B, via) ->
      true.
  
  %%--------------------------------------------------------------------
  %% Function: 
  %% Descrip.: autotest callback
  %% Returns : 
  %%--------------------------------------------------------------------
  test() ->
  
      %% comma
      %%--------------------------------------------------------------------
      %% test empty string
      io:format("test: comma/1 - 1~n"),
      [""] = comma(""),
  
      %% test string without comma
      io:format("test: comma/1 - 2~n"),
      ["foobar"] = comma("foobar"),
  
      %% test with single comma
      io:format("test: comma/1 - 3~n"),
      ["foo","bar"] = comma("foo,bar"),
  
      %% test with several comma
      io:format("test: comma/1 - 4~n"),
      ["fo","ob","ar"] = comma("fo,ob,ar"),
      
      %% test with quotes inside string
      io:format("test: comma/1 - 5~n"),
      ["foobar: \"this is a string\""] = comma("foobar: \"this is a string\""),
  
      %% test with commas inside quoted string part
      io:format("test: comma/1 - 6~n"),
      ["foobar: \"this, is, a, string,\""] = comma("foobar: \"this, is, a, string,\""),
  
      %% test with commas outside quoutes
      io:format("test: comma/1 - 7~n"),
      ["foobar:", "\",this is a string\""] = comma("foobar:, \",this is a string\""),
      
      %% test with commas outside and inside quoutes
      io:format("test: comma/1 - 8~n"),
      ["foobar:", "\",this is a ,string\"", "foo"] = comma("foobar:, \",this is a ,string\",foo"),
  
      %% preceding comma
      io:format("test: comma/1 - 9~n"),
      ["fo","ob","ar",""] = comma("fo,ob,ar,"),
  
      %% trailing comma
      io:format("test: comma/1 - 10~n"),
      ["","fo","ob","ar"] = comma(",fo,ob,ar"),
  
  
      ok.
  
  %%====================================================================
  %% Behaviour functions
  %%====================================================================
  
  %%====================================================================
  %% Internal functions
  %%====================================================================
  
  %%--------------------------------------------------------------------
  %% Function: name_header(String)
  %%           String = string(), a sip URI string or sip URI inside "<" 
  %%           and ">" quotes, preceded by a displayname
  %% Descrip.: used to parse the contens in a to, from or contact header
  %% Returns : {Displayname, URI}
  %%           Displayname = none | string()
  %%           URI = sipurl record()
  %%--------------------------------------------------------------------
  name_header(String) ->
      %logger:log(debug, "n: ~p", [String]),
      Index1 = string:rchr(String, $<),
  