anchor.diff:  %%--------------------------------------------------------------------
   %% Function: get_forwards_for_users(In)
   %%           In = list() of string(), list of usernames
  -%% Descrip.: Return a list of all forwards for a list of users.
  +%% Descrip.: Return a list of forward addresses for a list of users.
   %%           Uses the next function, get_forward_for_user/1.
   %% Returns : Forwards, list() of string()
   %%--------------------------------------------------------------------
  
positive.code: %%           Spec = OTP supervisor child specification
  %%--------------------------------------------------------------------
  yxa_init() ->
      [{sipuserdb_file, {sipuserdb_file, start_link, []},
        permanent, 2000, worker, [sipuserdb_file]}
      ].
  
  %%--------------------------------------------------------------------
  %% Function: start_link()
  %% Descrip.: Starts the persistent sipuserdb_file gen_server.
  %%--------------------------------------------------------------------
  start_link() ->
      gen_server:start_link({local, sipuserdb_file}, ?MODULE, [], []).
  
  %%====================================================================
  %% Server functions
  %%====================================================================
  
  %%--------------------------------------------------------------------
  %% Function: init([])
  %% Descrip.: Initiates the server
  %% Returns : {ok, State}          |
  %%           {ok, State, Timeout} |
  %%           ignore               |
  %%           {stop, Reason}
  %%--------------------------------------------------------------------
  init([]) ->
      case sipserver:get_env(sipuserdb_file_filename, none) of
  	none ->
  	    E = "sipuserdb_file module activated, but sipuserdb_file_filename not set - module disabled",
  	    logger:log(error, E),
  	    ignore;
  	Fn when is_list(Fn) ->
  	    case sipserver:get_env(sipuserdb_file_refresh_interval, 15) of
  		X when X == 0; X == none ->
  		    ok;
  		Interval when is_integer(Interval) ->
  		    {ok, _T} = timer:send_interval(Interval * 1000, sipuserdb_file, {check_file})
  	    end,
  	    case get_mtime(Fn) of
  		{ok, MTime} ->
  		    case read_userdb(#state{fn=Fn}, MTime, init) of
  			NewState when is_record(NewState, state) ->
  			    {ok, NewState};
  			{error, Reason} ->
  			    logger:log(error, Reason, []),
  			    {stop, Reason}
  		    end;
  		Unknown ->
  		    logger:log(error, "sipuserdb_file: could not get mtime for file ~p : ~p", [Fn, Unknown]),
  		    {ok, #state{fn=Fn}}
  	    end
      end.
  
  
  %%--------------------------------------------------------------------
  %% Function: handle_call(Msg, From, State)
  %% Descrip.: Handling call messages
  %% Returns : {reply, Reply, State}          |
  %%           {reply, Reply, State, Timeout} |
  %%           {noreply, State}               |
  %%           {noreply, State, Timeout}      |
  %%           {stop, Reason, Reply, State}   | (terminate/2 is called)
  %%           {stop, Reason, State}            (terminate/2 is called)
  %%--------------------------------------------------------------------
  
  %%--------------------------------------------------------------------
  %% Function: handle_call({fetch_users}, From, State)
  %% Descrip.: Fetch our user database.
  %% Returns : {reply, {ok, Users}, State}
  %%           Users = list() of user record()
  %%--------------------------------------------------------------------
  handle_call({fetch_users}, _From, State) ->
      {reply, {ok, State#state.userlist}, State};
  
  %%--------------------------------------------------------------------
  %% Function: handle_call({fetch_addresses}, From, State)
  %% Descrip.: Fetch our address database.
  %% Returns : {reply, {ok, Addresses}, State}
  %%           Addresses = list() of address record()
  %%--------------------------------------------------------------------
  handle_call({fetch_addresses}, _From, State) ->
      {reply, {ok, State#state.addresslist}, State};
  
  handle_call(Unknown, _From, State) ->
      logger:log(error, "sipuserdb_file: Received unknown gen_server call : ~p", [Unknown]),
      {reply, {error, "unknown gen_server call in sipuserdb_file"}, State}.
  
  
  %%--------------------------------------------------------------------
  %% Function: handle_cast/2
  %% Description: Handling cast messages
  %% Returns: {noreply, State}          |
  %%          {noreply, State, Timeout} |
  %%          {stop, Reason, State}            (terminate/2 is called)
  %%--------------------------------------------------------------------
  
  %%--------------------------------------------------------------------
  %% Function: handle_cast({reload_userdb}, State)
  %% Descrip.: Signal to reload our user database, even if mtime has
  %%           not changed.
  %% Returns : {noreply, State}
  %%--------------------------------------------------------------------
  handle_cast({reload_userdb}, State) ->
      logger:log(debug, "sipuserdb_file: Forcing reload of userdb upon request"),
      case get_mtime(State#state.fn) of
  	{ok, MTime} ->
  	    case read_userdb(State, MTime, cast) of
  		NewState when is_record(NewState, state) ->
  		    {noreply, NewState};
  		{error, _} ->
  		    {noreply, State}
  	    end;
  	Unknown ->
  	    logger:log(error, "sipuserdb_file: Could not get mtime of file ~p : ~p",
  		       [State#state.fn, Unknown]),
  	    {noreply, State}
      end;
  
  handle_cast(Unknown, State) ->
      logger:log(error, "sipuserdb_file: Received unknown gen_server cast : ~p", [Unknown]),
      {noreply, State}.
  
  
  %%--------------------------------------------------------------------
  %% Function: handle_info(Msg, State)
  %% Descrip.: Handling all non call/cast messages
  %% Returns : {noreply, State}          |
  %%           {noreply, State, Timeout} |
  %%           {stop, Reason, State}            (terminate/2 is called)
  %%--------------------------------------------------------------------
  
  %%--------------------------------------------------------------------
  %% Function: handle_info({check_file}, State)
  %% Descrip.: Periodically check if our files mtime has changed, and if
  %%           so reload it.
  %% Returns: {noreply, State}
  %%--------------------------------------------------------------------
  handle_info({check_file}, State) ->
      case get_mtime(State#state.fn) of
  	{ok, MTime} when MTime /= State#state.file_mtime ->
  	    case read_userdb(State, MTime, info) of
  		NewState when is_record(NewState, state) ->
  		    {noreply, NewState};
  		{error, _} ->
  		    {noreply, State}
  	    end;
  	_ ->
  	    %% Either error returned from read_file_info, or file mtime has not changed.
  	    %% We don't check (care) which one...
  	    {noreply, State}
      end;
  
  handle_info(Info, State) ->
      logger:log(error, "sipuserdb_file: Received unknown signal : ~p", [Info]),
      {noreply, State}.
  
  %%--------------------------------------------------------------------
  %% Function: terminate/2
  %% Description: Shutdown the server
  %% Returns: any (ignored by gen_server)
  %%--------------------------------------------------------------------
  terminate(_Reason, _State) ->
      ok.
  
  %%--------------------------------------------------------------------
  %% Func: code_change/3
  %% Purpose: Convert process state when code is changed
  %% Returns: {ok, NewState}
  %%--------------------------------------------------------------------
  code_change(_OldVsn, State, _Extra) ->
      {ok, State}.
  
  
  %%--------------------------------------------------------------------
  %%% Interface functions
  %%--------------------------------------------------------------------
  
  
  %%--------------------------------------------------------------------
  %% Function: get_user_with_address(Address)
  
negative.code: %% Function: get_addresses_for_user(Username)
  %%           Username = string()
  %% Descrip.: Get all possible addresses of a user. Both configured
  %%           ones, and implicit ones. Used for example to check if a
  %%           request from a user has an acceptable From: header.
  %% Returns : Addresses |
  %%           error
  %%           Addresses = list() of string()
  %%--------------------------------------------------------------------
  get_addresses_for_user(Username) ->
      case get_user(Username) of
  