#define CLEANUP_INACTIVE_DAYS 30 /* disable channels where nothing happened for this many days */
#define CLEANUP_DELETE_DAYS 5 /* delete data for channels that have been disabled for this many days */
+#define A4STATS_DB_TOLOWER(x) "translate(lower(" x "), E'[]\\\\~', '{}|^')"
+#define A4STATS_DB_EQ_NOCASE(x, y) A4STATS_DB_TOLOWER(x) " = " A4STATS_DB_TOLOWER(y)
+
MODULE_VERSION("");
DBAPIConn *a4statsdb;
free(dci);
}
-static void a4stats_fetch_user_cb(const struct DBAPIResult *result, void *uarg) {
- db_callback_info *dci = uarg;
- time_t seen = 0, quotereset = 0;
-
- if (result) {
- if (result->success) {
- while (result->next(result)) {
- seen = (result->get(result, 0)) ? (time_t)strtoul(result->get(result, 0), NULL, 10) : 0;
- quotereset = (result->get(result, 1)) ? (time_t)strtoul(result->get(result, 1), NULL, 10) : 0;
- }
- }
-
- result->clear(result);
- }
-
- if (dci->interp) {
- lua_vpcall(dci->interp, dci->callback, "llR", (long)seen, (long)quotereset, dci->uarg_index);
- luaL_unref(dci->interp, LUA_REGISTRYINDEX, dci->uarg_index);
- }
-
- a4stats_delete_dci(dci);
-}
-
-static int a4stats_lua_fetch_user(lua_State *ps) {
- const char *account, *callback;
- unsigned long channelid, accountid;
- db_callback_info *dci;
-
- if (!lua_islong(ps, 1) || !lua_isstring(ps, 2) || !lua_isnumber(ps, 3) || !lua_isstring(ps, 4))
- LUA_RETURN(ps, LUA_FAIL);
-
- channelid = lua_tonumber(ps, 1);
- account = lua_tostring(ps, 2);
- accountid = lua_tonumber(ps, 3);
- callback = lua_tostring(ps, 4);
-
- dci = malloc(sizeof(*dci));
- dci->interp = ps;
-
- strncpy(dci->callback, callback, sizeof(dci->callback));
- dci->callback[sizeof(dci->callback) - 1] = '\0';
-
- lua_pushvalue(ps, 5);
- dci->uarg_index = luaL_ref(ps, LUA_REGISTRYINDEX);
-
- a4statsdb->query(a4statsdb, a4stats_fetch_user_cb, dci, "SELECT seen, quotereset FROM ? WHERE channelid = ? AND (accountid != 0 AND accountid = ? OR accountid = 0 AND account = ?)", "TUUs", "users", channelid, accountid, account);
-
- LUA_RETURN(ps, LUA_OK);
-}
-
typedef struct user_update_info {
int stage;
char *update;
free(uui->update);
free(uui->account);
free(uui);
- return;
+ goto a4_uuc_return;
}
a4statsdb->query(a4statsdb, a4stats_update_user_cb, uui, "INSERT INTO ? (channelid, account, accountid, firstseen) VALUES (?, ?, ?, ?)", "TUsUt", "users", uui->channelid, uui->account, uui->accountid, time(NULL));
}
+
+a4_uuc_return:
+ if (result)
+ result->clear(result);
}
static int a4stats_lua_update_user(lua_State *ps) {
a4statsdb->query(a4statsdb, a4stats_update_relation_cb, rui, "UPDATE ? SET score = score + 1, seen = ? "
"WHERE channelid = ? AND first = ? AND firstid = ? AND second = ? AND secondid = ?",
"TtUsUsU", "relations", time(NULL), rui->channelid, rui->first, rui->firstid, rui->second, rui->secondid);
- return;
+ goto a4_urc_return;
} else if (rui->stage == 2 && result && result->affected == 0) {
a4statsdb->query(a4statsdb, a4stats_update_relation_cb, rui, "INSERT INTO ? (channelid, first, firstid, second, secondid, seen) VALUES (?, ?, ?, ?, ?, ?)",
"TUsUsUt", "relations", rui->channelid, rui->first, rui->firstid, rui->second, rui->secondid, time(NULL));
- return;
+ goto a4_urc_return;
}
if (!result || result->affected == 0)
free(rui->first);
free(rui->second);
free(rui);
+
+a4_urc_return:
+ if (result)
+ result->clear(result);
}
static int a4stats_lua_update_relation(lua_State *ps) {
channel = lua_tostring(ps, 1);
hour = lua_tonumber(ps, 2);
- snprintf(query, sizeof(query), "UPDATE ? SET h%d = h%d + 1 WHERE name = ?", hour, hour);
+ snprintf(query, sizeof(query), "UPDATE ? SET h%d = h%d + 1 WHERE " A4STATS_DB_EQ_NOCASE("name", "?"), hour, hour);
a4statsdb->squery(a4statsdb, query, "Ts", "channels", channel);
LUA_RETURN(ps, LUA_FAIL);
a4statsdb->squery(a4statsdb, "INSERT INTO ? (name, timestamp) VALUES (?, ?)", "Tst", "channels", lua_tostring(ps, 1), time(NULL));
- a4statsdb->squery(a4statsdb, "UPDATE ? SET active = 1, deleted = 0 WHERE name = ?", "Ts", "channels", lua_tostring(ps, 1));
+ a4statsdb->squery(a4statsdb, "UPDATE ? SET active = 1, deleted = 0 WHERE " A4STATS_DB_EQ_NOCASE("name", "?"), "Ts", "channels", lua_tostring(ps, 1));
LUA_RETURN(ps, LUA_OK);
}
if (!lua_isstring(ps, 1))
LUA_RETURN(ps, LUA_FAIL);
- a4statsdb->squery(a4statsdb, "UPDATE ? SET active = 0, deleted = ? WHERE name = ?", "Tts", "channels", time(NULL), lua_tostring(ps, 1));
+ a4statsdb->squery(a4statsdb, "UPDATE ? SET active = 0, deleted = ? WHERE " A4STATS_DB_EQ_NOCASE("name", "?"), "Tts", "channels", time(NULL), lua_tostring(ps, 1));
+
+ LUA_RETURN(ps, LUA_OK);
+}
+
+static int a4stats_lua_set_privacy(lua_State *ps) {
+ const char *channel;
+ unsigned long privacy;
+
+ if (!lua_isstring(ps, 1) || !lua_isnumber(ps, 2))
+ LUA_RETURN(ps, LUA_FAIL);
+
+ channel = lua_tostring(ps, 1);
+ privacy = lua_tonumber(ps, 2);
+ a4statsdb->squery(a4statsdb, "UPDATE ? SET privacy = ? WHERE " A4STATS_DB_EQ_NOCASE("name", "?"), "TUs", "channels", privacy, channel);
LUA_RETURN(ps, LUA_OK);
}
LUA_RETURN(ps, LUA_OK);
}
+static int a4stats_lua_db_begin(lua_State *ps) {
+ a4statsdb->query(a4statsdb, NULL, NULL, "BEGIN TRANSACTION", "");
+ LUA_RETURN(ps, LUA_OK);
+}
+
+static int a4stats_lua_db_commit(lua_State *ps) {
+ a4statsdb->query(a4statsdb, NULL, NULL, "COMMIT TRANSACTION", "");
+ LUA_RETURN(ps, LUA_OK);
+}
+
static void a4stats_hook_loadscript(int hooknum, void *arg) {
void **args = arg;
lua_State *l = args[1];
lua_register(l, "a4_enable_channel", a4stats_lua_enable_channel);
lua_register(l, "a4_disable_channel", a4stats_lua_disable_channel);
+ lua_register(l, "a4_set_privacy", a4stats_lua_set_privacy);
lua_register(l, "a4_fetch_channels", a4stats_lua_fetch_channels);
lua_register(l, "a4_add_kick", a4stats_lua_add_kick);
lua_register(l, "a4_add_topic", a4stats_lua_add_topic);
lua_register(l, "a4_add_line", a4stats_lua_add_line);
- lua_register(l, "a4_fetch_user", a4stats_lua_fetch_user);
lua_register(l, "a4_update_user", a4stats_lua_update_user);
lua_register(l, "a4_update_relation", a4stats_lua_update_relation);
lua_register(l, "a4_escape_string", a4stats_lua_escape_string);
+ lua_register(l, "a4_db_begin", a4stats_lua_db_begin);
+ lua_register(l, "a4_db_commit", a4stats_lua_db_commit);
}
#define lua_unregister(L, n) (lua_pushnil(L), lua_setglobal(L, n))
lua_unregister(l->l, "a4_enable_channel");
lua_unregister(l->l, "a4_disable_channel");
+ lua_unregister(l->l, "a4_set_privacy");
lua_unregister(l->l, "a4_fetch_channels");
lua_unregister(l->l, "a4_add_kick");
lua_unregister(l->l, "a4_add_topic");
lua_unregister(l->l, "a4_update_user");
lua_unregister(l->l, "a4_update_relation");
lua_unregister(l->l, "a4_escape_string");
+ lua_unregister(l->l, "a4_db_begin");
+ lua_unregister(l->l, "a4_db_commit");
}
deregisterhook(HOOK_LUA_LOADSCRIPT, a4stats_hook_loadscript);