anchor.diff:      logger:log(error, "Resolver: ENUM lookup on non-E.164 number (~p)", [Foo]),
       none.
   
  +%%--------------------------------------------------------------------
  +%% Function: enumlookup/2
  +%% Description: Do ENUM (RFC2916 and 2916bis) lookup on a E.164 number
  +%%              in a set of domains. Returns the result of ENUM regexp
  +%%              rewrite as a string.
  +%% Returns:
  +%%--------------------------------------------------------------------
   enumlookup("+" ++ Number, DomainList) ->
  +    %% XXX remove dashes and spaces etc. from Number
       logger:log(debug, "Resolver: ENUM query for ~p in ~p", ["+" ++ Number, DomainList]),
       L1 = enumalldomains(Number, DomainList),
       %% SIP+E2U is RFC2916 and E2U+SIP is 2916bis
       L2 = lists:append([chooseenum(L1, "SIP+E2U"), chooseenum(L1, "E2U+SIP")]),
       L3 = lists:sort(fun sortenum/2, L2),
  -    L4 = enumregexp(L3),
  +    L4 = naptr_regexp(L3),
       applyregexp("+" ++ Number, L4).
   
  -isnaptr(Entry) ->
  +
  +%%--------------------------------------------------------------------
  +%% Function: isnaptr/1
  +%% Description: Evaluate if a dns_rr is of type NAPTR or not. To be
  +%%              used with lists:filter.
  +%% Returns: true  |
  +%%          false
  +%%--------------------------------------------------------------------
  +isnaptr(Entry) when record(Entry, dns_rr) ->
       if
   	Entry#dns_rr.type == ?T_NAPTR ->
   	    true;
   	true ->
   	    false
  -    end.
  -
  +    end;
  +isnaptr(_) ->
  +    false.
  +
  +
  +%%--------------------------------------------------------------------
  +%% Function: naptrlookup/1
  +%% Description: Look up and return all NAPTR records for a given DNS
  +%%              domain name.
  +%% Returns: NAPTRList
  +%%--------------------------------------------------------------------
   naptrlookup(Name) ->
       case inet_res:nslookup(Name, in, ?T_NAPTR) of
   	{ok, Rec} ->
  
positive.code: 				 parsenaptr(Entry#dns_rr.data)
  			 end,
  	    NAPTRs = lists:map(ParseNAPTR, lists:filter(fun isnaptr/1,
  					       Rec#dns_rec.anlist)),
  	    logger:log(debug, "Resolver: naptrlookup: ~p -> found", [Name]),
  	    NAPTRs;
  	{error, E} ->
  	    logger:log(debug, "Resolver: naptrlookup: ~p -> error ~p", [Name, E]),
  	    []
      end.
  
  parsenaptr(Record) ->
      Binary = list_to_binary(Record),
      <<Order:16,
      Preference:16,
      Flagslength:8,
      Rest/binary>> = Binary,
      <<Flags:Flagslength/binary-unit:8,
      Serviceslength:8,
      Rest2/binary>> = Rest,
      <<Services:Serviceslength/binary-unit:8,
      Regexplength:8,
      Rest3/binary>> = Rest2,
      <<Regexp:Regexplength/binary-unit:8,
      Replacementlength:8,
      Rest4/binary>> = Rest3,
      <<Replacement:Replacementlength/binary-unit:8>> = Rest4,
      {Order,
       Preference,
       binary_to_list(Flags),
       httpd_util:to_upper(binary_to_list(Services)),
       binary_to_list(Regexp),
       binary_to_list(Replacement)}.
  
negative.code: -export([siplookup/1, enumlookup/1, enumlookup/2, get_ip_port/2]).
  
  -include("inet_dns.hrl").
  -include_lib("kernel/include/inet.hrl").
  
  %% For debugging
  -compile(export_all).
  
  %% These records is entirely internal to this module
  -record(srventry, {proto, dnsrrdata}).
  -record(naptrrecord, {order, preference, flags, services, regexp, replacement}).
  
  %%--------------------------------------------------------------------
  %% Function: srvlookup/2
  %% Description: Resolve a SRV record (indicated by Name) and return a
  %%              list of srventry records. The DNS RR data in them is
  %%              of the format {Order, Pref, Port, Host}.
  %% Returns: SRVList         |
  %%          {error, Reason}
  %%--------------------------------------------------------------------
  srvlookup(Proto, Name) when list(Name) ->
      case inet_res:nslookup(Name, in, srv) of
  	{ok, Rec} ->
  	    ParseSRV = fun(Entry) ->
  			       #srventry{proto=Proto, dnsrrdata=Entry#dns_rr.data}
  		       end,
  	    lists:map(ParseSRV, Rec#dns_rec.anlist);
  	{error, What} ->
  	    logger:log(debug, "dns resolver: Error ~p when resolving ~p IN SRV", [What, Name]),
  	    {error, What}
      end.
  
  
  %%--------------------------------------------------------------------
  %% Function: siplookup/1
  %% Description: Look up where to send SIP requests for a domain name.
  %%              Ultimately return a list of {Proto, Host, Port} and/or
  %%              {error, E} entrys. Proto is tcp, udp or tls. Never
  %%              tcp6, udp6 or tls6 since we do not resolve Host into
  %%              an address.
  %% Returns: ProtoHostPortList
  %%--------------------------------------------------------------------
  siplookup([]) ->
      none;
  siplookup(Domain) ->
      case siplookup_naptr(Domain) of
  	nomatch ->
  	    %% No domain NAPTR records found. Perform RFC2543 backwards compatible
  	    %% SRV lookup of the domain.
  	    logger:log(debug, "Resolver: Domain ~p has no NAPTR records, perform RFC2543 backwards " ++
  		       "compatible lookup for SIP SRV records under that domain name", [Domain]),
  	    TCP = srvlookup(tcp, "_sip._tcp." ++ Domain),
  	    UDP = srvlookup(udp, "_sip._udp." ++ Domain),
  	    combine_srvresults(lists:sort(fun sortsrv/2, lists:flatten([TCP, UDP])));
  	Res ->
  	    %% siplookup_naptr does it's own sorting
  	    combine_srvresults(Res)
      end.
  
  %%--------------------------------------------------------------------
  %% Function: siplookup_naptr/1
  %% Description: Look for NAPTR records for a domain telling us where
  %%              to look for SRV records for the very same domain.
  %% Returns: SRVList |
  %%          nomatch
  %%--------------------------------------------------------------------
  siplookup_naptr(Domain) when list(Domain) ->
      case naptrlookup(Domain) of
  	[] ->
  	    nomatch;
  	L1 ->
  	    L2 = lists:append([filter_naptr(L1, "s", "SIP+D2U"), filter_naptr(L1, "s", "SIP+D2T"),
  			      filter_naptr(L1, "s","SIPS+D2T")]),
  	    L3 = lists:sort(fun sortenum/2, L2),
  	    %% Ok, we now have a preference sorted list of NAPTR results. Look for
  	    %% SRV records matching each of them. Sort SRV records only per NAPTR -
  	    %% the NAPTR order of preference supersedes the SRV ordering.
  	    naptr_to_srvlist(Domain, L3)
      end.
  
  
  %%--------------------------------------------------------------------
  %% Function: siplookup_naptr/1
  %% Description: Take a list of sorted NAPTR records and try to turn
  %%              them into SRV records.
  %% Returns: SRVList |
  %%          nomatch
  %%--------------------------------------------------------------------
  naptr_to_srvlist(Domain, In) ->
      naptr_to_srvlist2(Domain, In, []).
  
  naptr_to_srvlist2(Domain, [], Res) ->
      logger:log(debug, "dns resolver: Domain ~s NAPTR lookup result : ~p", [Domain, Res]),
      Res;
  naptr_to_srvlist2(Domain, [H | Rest], Res) when record(H, naptrrecord) ->
      Proto = case H#naptrrecord.services of
  		"SIP+D2U"  ++ _ -> udp;
  		"SIP+D2T"  ++ _ -> tcp;
  		"SIPS+D2T" ++ _ -> tls
  	    end,
      %% Regexp should be empty for domain NAPTR - RFC3263 #4.1. The
      %% interesting thing is the replacement.
      This = srvlookup(Proto, H#naptrrecord.replacement),
      Sorted = lists:sort(fun sortsrv/2, This),
      naptr_to_srvlist2(Domain, Rest, lists:flatten([Res, Sorted])).
  
  
  %%--------------------------------------------------------------------
  %% Function: combine_srvresults/1
  %% Description: Walk through a list of srventry records or {error, R}
  %%              tuples and turn the srventry records into
  %%              {Proto, Host, Port} tuples.
  %% Returns: ProtoHostPortList
  %%--------------------------------------------------------------------
  combine_srvresults(List) ->
      combine_srvresults(List, [], []).
  
  