++handle_call({log_message, Msg}, _From, #state{dbref=DBRef, vhost=VHost, schema=Schema}=State) ->
++ Date = convert_timestamp_brief(Msg#msg.timestamp),
++ TableName = messages_table(VHost, Schema, Date),
++ ViewName = view_table(VHost, Schema, Date),
++
++ Query = [ "SELECT ", logmessage_name(VHost, Schema)," "
++ "('", TableName, "',",
++ "'", ViewName, "',",
++ "'", Date, "',",
++ "'", Msg#msg.owner_name, "',",
++ "'", Msg#msg.peer_name, "',",
++ "'", Msg#msg.peer_server, "',",
++ "'", ejabberd_odbc:escape(Msg#msg.peer_resource), "',",
++ "'", atom_to_list(Msg#msg.direction), "',",
++ "'", Msg#msg.type, "',",
++ "'", ejabberd_odbc:escape(Msg#msg.subject), "',",
++ "'", ejabberd_odbc:escape(Msg#msg.body), "',",
++ "'", Msg#msg.timestamp, "');"],
++
++ case sql_query_internal_silent(DBRef, Query) of
++ % TODO: change this
++ {data, [{"0"}]} ->
++ ?MYDEBUG("Logged ok for ~p, peer: ~p", [Msg#msg.owner_name++"@"++VHost,
++ Msg#msg.peer_name++"@"++Msg#msg.peer_server]),
++ ok;
++ {error, _Reason} ->
++ error
++ end,
++ {reply, ok, State};
++handle_call({rebuild_stats_at, Date}, _From, #state{dbref=DBRef, vhost=VHost, schema=Schema}=State) ->
++ Reply = rebuild_stats_at_int(DBRef, VHost, Schema, Date),
++ {reply, Reply, State};
++handle_call({delete_messages_by_user_at, [], _Date}, _From, State) ->
++ {reply, error, State};
++handle_call({delete_messages_by_user_at, Msgs, Date}, _From, #state{dbref=DBRef, vhost=VHost, schema=Schema}=State) ->
++ Temp = lists:flatmap(fun(#msg{timestamp=Timestamp} = _Msg) ->
++ ["'",Timestamp,"'",","]
++ end, Msgs),
++
++ Temp1 = lists:append([lists:sublist(Temp, length(Temp)-1), ");"]),
++
++ Query = ["DELETE FROM ",messages_table(VHost, Schema, Date)," ",
++ "WHERE timestamp IN (", Temp1],
++
++ Reply =
++ case sql_query_internal(DBRef, Query) of
++ {updated, _} ->
++ rebuild_stats_at_int(DBRef, VHost, Schema, Date);
++ {error, _} ->
++ error
++ end,
++ {reply, Reply, State};
++handle_call({delete_all_messages_by_user_at, User, Date}, _From, #state{dbref=DBRef, vhost=VHost, schema=Schema}=State) ->
++ ok = delete_all_messages_by_user_at_int(DBRef, Schema, User, VHost, Date),
++ ok = delete_stats_by_user_at_int(DBRef, Schema, User, VHost, Date),
++ {reply, ok, State};
++handle_call({delete_messages_at, Date}, _From, #state{dbref=DBRef, vhost=VHost, schema=Schema}=State) ->
++ {updated, _} = sql_query_internal(DBRef, ["DROP VIEW ",view_table(VHost, Schema, Date),";"]),
++ Reply =
++ case sql_query_internal(DBRef, ["DROP TABLE ",messages_table(VHost, Schema, Date)," CASCADE;"]) of
++ {updated, _} ->
++ Query = ["DELETE FROM ",stats_table(VHost, Schema)," "
++ "WHERE at='",Date,"';"],
++ case sql_query_internal(DBRef, Query) of
++ {updated, _} ->
++ ok;
++ {error, _} ->
++ error
++ end;
++ {error, _} ->
++ error
++ end,
++ {reply, Reply, State};
++handle_call({get_vhost_stats}, _From, #state{dbref=DBRef, vhost=VHost, schema=Schema}=State) ->
++ SName = stats_table(VHost, Schema),
++ Query = ["SELECT at, sum(count) ",
++ "FROM ",SName," ",
++ "GROUP BY at ",
++ "ORDER BY DATE(at) DESC;"
++ ],
++ Reply =
++ case sql_query_internal(DBRef, Query) of
++ {data, Recs} ->
++ {ok, [ {Date, list_to_integer(Count)} || {Date, Count} <- Recs]};
++ {error, Reason} ->
++ % TODO: Duplicate error message ?
++ {error, Reason}
++ end,
++ {reply, Reply, State};
++handle_call({get_vhost_stats_at, Date}, _From, #state{dbref=DBRef, vhost=VHost, schema=Schema}=State) ->
++ SName = stats_table(VHost, Schema),
++ Query = ["SELECT username, sum(count) AS allcount ",
++ "FROM ",SName," ",
++ "JOIN ",users_table(VHost, Schema)," ON owner_id=user_id ",
++ "WHERE at='",Date,"' ",
++ "GROUP BY username ",
++ "ORDER BY allcount DESC;"
++ ],
++ Reply =
++ case sql_query_internal(DBRef, Query) of
++ {data, Recs} ->
++ RFun = fun({User, Count}) ->
++ {User, list_to_integer(Count)}
++ end,
++ {ok, lists:reverse(lists:keysort(2, lists:map(RFun, Recs)))};
++ {error, Reason} ->
++ % TODO:
++ {error, Reason}
++ end,
++ {reply, Reply, State};
++handle_call({get_user_stats, User}, _From, #state{dbref=DBRef, vhost=VHost, schema=Schema}=State) ->
++ {reply, get_user_stats_int(DBRef, Schema, User, VHost), State};
++handle_call({get_user_messages_at, User, Date}, _From, #state{dbref=DBRef, vhost=VHost, schema=Schema}=State) ->
++ Query = ["SELECT peer_name,",
++ "peer_server,",
++ "peer_resource,",
++ "direction,"
++ "type,"
++ "subject,"
++ "body,"
++ "timestamp "
++ "FROM ",view_table(VHost, Schema, Date)," "
++ "WHERE owner_name='",User,"';"],
++ Reply =
++ case sql_query_internal(DBRef, Query) of
++ {data, Recs} ->
++ Fun = fun({Peer_name, Peer_server, Peer_resource,
++ Direction,
++ Type,
++ Subject, Body,
++ Timestamp}) ->
++ #msg{peer_name=Peer_name, peer_server=Peer_server, peer_resource=Peer_resource,
++ direction=list_to_atom(Direction),
++ type=Type,
++ subject=Subject, body=Body,
++ timestamp=Timestamp}
++ end,
++ {ok, lists:map(Fun, Recs)};
++ {error, Reason} ->
++ {error, Reason}
++ end,
++ {reply, Reply, State};
++handle_call({get_dates}, _From, #state{dbref=DBRef, vhost=VHost, schema=Schema}=State) ->
++ SName = stats_table(VHost, Schema),
++ Query = ["SELECT at ",
++ "FROM ",SName," ",
++ "GROUP BY at ",
++ "ORDER BY at DESC;"
++ ],
++ Reply =
++ case sql_query_internal(DBRef, Query) of
++ {data, Result} ->
++ [ Date || {Date} <- Result ];
++ {error, Reason} ->
++ {error, Reason}
++ end,
++ {reply, Reply, State};
++handle_call({get_users_settings}, _From, #state{dbref=DBRef, vhost=VHost, schema=Schema}=State) ->
++ Query = ["SELECT username,dolog_default,dolog_list,donotlog_list ",
++ "FROM ",settings_table(VHost, Schema)," ",
++ "JOIN ",users_table(VHost, Schema)," ON user_id=owner_id;"],
++ Reply =
++ case sql_query_internal(DBRef, Query) of
++ {data, Recs} ->
++ {ok, [#user_settings{owner_name=Owner,
++ dolog_default=list_to_bool(DoLogDef),
++ dolog_list=string_to_list(DoLogL),
++ donotlog_list=string_to_list(DoNotLogL)
++ } || {Owner, DoLogDef, DoLogL, DoNotLogL} <- Recs]};
++ {error, Reason} ->
++ {error, Reason}
++ end,
++ {reply, Reply, State};
++handle_call({get_user_settings, User}, _From, #state{dbref=DBRef, vhost=VHost, schema=Schema}=State) ->
++ Query = ["SELECT dolog_default,dolog_list,donotlog_list ",
++ "FROM ",settings_table(VHost, Schema)," ",
++ "WHERE owner_id=(SELECT user_id FROM ",users_table(VHost, Schema)," WHERE username='",User,"');"],
++ Reply =
++ case sql_query_internal_silent(DBRef, Query) of
++ {data, []} ->
++ {ok, []};
++ {data, [{DoLogDef, DoLogL, DoNotLogL}]} ->
++ {ok, #user_settings{owner_name=User,
++ dolog_default=list_to_bool(DoLogDef),
++ dolog_list=string_to_list(DoLogL),
++ donotlog_list=string_to_list(DoNotLogL)}};
++ {error, Reason} ->
++ ?ERROR_MSG("Failed to get_user_settings for ~p@~p: ~p", [User, VHost, Reason]),
++ error
++ end,
++ {reply, Reply, State};
++handle_call({set_user_settings, User, #user_settings{dolog_default=DoLogDef,
++ dolog_list=DoLogL,
++ donotlog_list=DoNotLogL}},
++ _From, #state{dbref=DBRef, vhost=VHost, schema=Schema}=State) ->
++ User_id = get_user_id(DBRef, VHost, Schema, User),
++ Query = ["UPDATE ",settings_table(VHost, Schema)," ",
++ "SET dolog_default=",bool_to_list(DoLogDef),", ",
++ "dolog_list='",list_to_string(DoLogL),"', ",
++ "donotlog_list='",list_to_string(DoNotLogL),"' ",
++ "WHERE owner_id=",User_id,";"],
++
++ Reply =
++ case sql_query_internal(DBRef, Query) of
++ {updated, 0} ->
++ IQuery = ["INSERT INTO ",settings_table(VHost, Schema)," ",
++ "(owner_id, dolog_default, dolog_list, donotlog_list) ",
++ "VALUES ",
++ "(",User_id,", ",bool_to_list(DoLogDef),",'",list_to_string(DoLogL),"','",list_to_string(DoNotLogL),"');"],
++ case sql_query_internal(DBRef, IQuery) of
++ {updated, 1} ->
++ ?MYDEBUG("New settings for ~s@~s", [User, VHost]),
++ ok;
++ {error, _} ->
++ error
++ end;
++ {updated, 1} ->
++ ?MYDEBUG("Updated settings for ~s@~s", [User, VHost]),
++ ok;
++ {error, _} ->
++ error
++ end,
++ {reply, Reply, State};
++handle_call({stop}, _From, State) ->
++ ?MYDEBUG("Stoping pgsql backend for ~p", [State#state.vhost]),
++ {stop, normal, ok, State};
++handle_call(Msg, _From, State) ->
++ ?INFO_MSG("Got call Msg: ~p, State: ~p", [Msg, State]),
++ {noreply, State}.