]> jfr.im git - irc/quakenet/newserv.git/blob - a4stats/nterfacer_a4stats.c
A4STATS: remove E style escapes and switch to createtable for indices
[irc/quakenet/newserv.git] / a4stats / nterfacer_a4stats.c
1 #include <stdio.h>
2 #include <stdarg.h>
3 #include "../lib/version.h"
4 #include "../core/error.h"
5 #include "../nterfacer/library.h"
6 #include "../nterfacer/nterfacer.h"
7 #include "a4stats.h"
8
9 MODULE_VERSION("");
10
11 static struct service_node *a4stats_node;
12
13 static void a4stats_nt_query_cb(const struct DBAPIResult *result, void *uarg) {
14 struct rline *ri = uarg;
15 int i;
16
17 if (result) {
18 ri_append(ri, "%s", result->success ? "OK" : "FAILED");
19
20 if (result->success) {
21 ri_append(ri, "%d", result->fields);
22
23 while (result->next(result)) {
24 for (i = 0; i < result->fields; i++) {
25 const char *field = result->get(result, i);
26 ri_append(ri, "%s", field ? field : "");
27 }
28 }
29 }
30
31 result->clear(result);
32 } else
33 ri_append(ri, "FAILED");
34
35 ri_final(ri);
36 }
37
38 static int handle_getchannel(struct rline *ri, int argc, char **argv) {
39 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, "SELECT timestamp, active, privacy, deleted FROM ? WHERE name = ?", "Ts", "channels", argv[0]);
40 return 0;
41 }
42
43 static int handle_getlines(struct rline *ri, int argc, char **argv) {
44 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, "SELECT h0, h1, h2, h3, h4, h5, h6, h7, h8, h9, h10, h11,"
45 "h12, h13, h14, h15, h16, h17, h18, h19, h20, h21, h22, h23 "
46 "FROM ? WHERE name = ?", "Ts", "channels", argv[0]);
47
48 return 0;
49 }
50
51 static int handle_getusers(struct rline *ri, int argc, char **argv) {
52 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, "SELECT users.account, users.accountid, users.seen, users.rating, users.lines, users.chars, users.words, users.h0, users.h1, users.h2, users.h3, users.h4, users.h5, users.h6, users.h7, users.h8, users.h9, users.h10, users.h11, users."
53 "h12, users.h13, users.h14, users.h15, users.h16, users.h17, users.h18, users.h19, users.h20, users.h21, users.h22, users.h23, users."
54 "last, users.quote, users.quotereset, users.mood_happy, users.mood_sad, users.questions, users.yelling, users.caps, users."
55 "slaps, users.slapped, users.highlights, users.kicks, users.kicked, users.ops, users.deops, users.actions, users.skitzo, users.foul, users."
56 "firstseen, users.curnick FROM ? LEFT JOIN ? ON channels.id = users.channelid WHERE channels.name = ? AND users.quote IS NOT NULL ORDER BY lines DESC LIMIT 25", "TTs", "users", "channels", argv[0]);
57
58 return 0;
59 }
60
61 static int handle_getkicks(struct rline *ri, int argc, char **argv) {
62 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, "SELECT kicks.kicker, kicks.kickerid, ukicker.seen, ukicker.curnick, kicks.victim, kicks.victimid, uvictim.seen, uvictim.curnick, kicks.timestamp, kicks.reason "
63 "FROM ? "
64 "LEFT JOIN ? ON channels.id = kicks.channelid "
65 "LEFT JOIN ? AS ukicker ON (ukicker.channelid = channels.id AND kicks.kickerid = ukicker.accountid AND kicks.kicker = ukicker.account) "
66 "LEFT JOIN ? AS uvictim ON (uvictim.channelid = channels.id AND kicks.victimid = uvictim.accountid AND kicks.victim = uvictim.account) "
67 "WHERE channels.name = ? ORDER BY kicks.timestamp DESC LIMIT 10", "TTTTs", "kicks", "channels", "users", "users", argv[0]);
68
69 return 0;
70 }
71
72 static int handle_gettopics(struct rline *ri, int argc, char **argv) {
73 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, "SELECT topics.topic, topics.timestamp, topics.setby, topics.setbyid, users.seen, users.curnick "
74 "FROM ? "
75 "LEFT JOIN ? ON channels.id = topics.channelid "
76 "LEFT JOIN ? ON (users.channelid = channels.id AND topics.setbyid = users.accountid AND topics.setby = users.account) "
77 "WHERE channels.name = ? ORDER BY topics.timestamp DESC LIMIT 10", "TTTs", "topics", "channels", "users", argv[0]);
78
79 return 0;
80 }
81
82 static int handle_getuser(struct rline *ri, int argc, char **argv) {
83 #define USER_QUERY(b) "SELECT users.account, users.accountid, users.seen, users.rating, users.lines, users.chars, users.words, " \
84 "users.h0, users.h1, users.h2, users.h3, users.h4, users.h5, users.h6, users.h7, users.h8, users.h9, " \
85 "users.h10, users.h11, users.h12, users.h13, users.h14, users.h15, users.h16, users.h17, users.h18, " \
86 "users.h19, users.h20, users.h21, users.h22, users.h23, users.last, users.quote, users.quotereset, " \
87 "users.mood_happy, users.mood_sad, users.questions, users.yelling, users.caps, users.slaps, users.slapped, " \
88 "users.highlights, users.kicks, users.kicked, users.ops, users.deops, users.actions, users.skitzo, " \
89 "users.foul, users.firstseen, users.curnick FROM ? LEFT JOIN ? ON channels.id = users.channelid WHERE channels.name = ? AND " b
90
91 /*
92 Possible cases:
93 accountid = 0, account = "username" -> new-style account, look up latest account for user
94 accountid = 0, account = "#username" -> legacy account or user not authed, look up using "username" (remove #)
95 accountid = <some value>, account = <unused> -> new-style account, look up by account id
96 */
97
98 if (argv[1][0] == '#') {
99 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, USER_QUERY("(users.accountid = 0 AND users.account = ?)"),
100 "TTss", "users", "channels", argv[0], &(argv[1][1]));
101 } else if (atoi(argv[2]) == 0) {
102 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, USER_QUERY("(users.accountid != 0 AND users.account = ?) ORDER BY users.accountid DESC LIMIT 1"),
103 "TTss", "users", "channels", argv[0], argv[1]);
104 } else {
105 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, USER_QUERY("(users.accountid = ?)"),
106 "TTss", "users", "channels", argv[0], argv[2]);
107 }
108
109 return 0;
110 }
111
112 static int handle_getrelations(struct rline *ri, int argc, char **argv) {
113 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, "SELECT relations.first, relations.firstid, ufirst.curnick, ufirst.seen, relations.second, relations.secondid, usecond.curnick, usecond.seen, relations.seen, relations.score "
114 "FROM ? "
115 "LEFT JOIN ? ON relations.channelid = channels.id "
116 "LEFT JOIN ? AS ufirst ON (ufirst.channelid = channels.id AND relations.firstid = ufirst.accountid AND relations.first = ufirst.account) "
117 "LEFT JOIN ? AS usecond ON (usecond.channelid = channels.id AND relations.secondid = usecond.accountid AND relations.second = usecond.account) "
118 "WHERE channels.name = ? ORDER BY score DESC LIMIT 50",
119 "TTTTs", "relations", "channels", "users", "users", argv[0]);
120
121 return 0;
122 }
123
124 static int handle_getuserrelations(struct rline *ri, int argc, char **argv) {
125 #define USERREALTIONS_QUERY(b) "SELECT relations.first, relations.firstid, ufirst.curnick, ufirst.seen, relations.second, relations.secondid, usecond.curnick, usecond.seen, relations.seen, relations.score " \
126 "FROM ? " \
127 "LEFT JOIN ? ON relations.channelid = channels.id " \
128 "LEFT JOIN ? AS ufirst ON (ufirst.channelid = channels.id AND relations.firstid = ufirst.accountid AND relations.first = ufirst.account) " \
129 "LEFT JOIN ? AS usecond ON (usecond.channelid = channels.id AND relations.secondid = usecond.accountid AND relations.second = usecond.account) " \
130 "WHERE channels.name = ? AND " b " ORDER BY score DESC LIMIT 25"
131 /*
132 Possible cases:
133 accountid = 0, account = "username" -> new-style account, look up latest account for user
134 accountid = 0, account = "#username" -> legacy account or user not authed, look up using "username" (remove #)
135 accountid = <some value>, account = <unused> -> new-style account, look up by account id
136 */
137
138 if (argv[1][0] == '#') {
139 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, USERREALTIONS_QUERY("(relations.first = ? AND relations.firstid = 0 OR relations.second = ? AND relations.secondid = 0)"),
140 "TTTTsss", "relations", "channels", "users", "users", argv[0], &(argv[1][1]), &(argv[1][1]));
141 } else if (atoi(argv[2]) == 0) {
142 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, USERREALTIONS_QUERY("(ROW(relations.first, relations.firstid) = "
143 "(SELECT account, accountid FROM ? WHERE accountid != 0 AND account = ? ORDER BY accountid DESC LIMIT 1) OR "
144 "ROW(relations.second, relations.secondid) = (SELECT account, accountid FROM ? WHERE accountid != 0 AND account = ? ORDER BY accountid DESC LIMIT 1))"),
145 "TTTTsTsTs", "relations", "channels", "users", "users", argv[0], "users", argv[1], "users", argv[1]);
146 } else {
147 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, USERREALTIONS_QUERY("(relations.firstid = ? OR relations.secondid = ?)"),
148 "TTTTsssss", "relations", "channels", "users", "users", argv[0], argv[1], argv[2], argv[1], argv[2]);
149 }
150
151 return 0;
152 }
153
154 static int handle_setprivacy(struct rline *ri, int argc, char **argv) {
155 a4statsdb->squery(a4statsdb, "UPDATE ? SET privacy = ? WHERE name = ?", "Tss", "channels", argv[1], argv[0]);
156 return ri_final(ri);
157 }
158
159 static int handle_finduser(struct rline *ri, int argc, char **argv) {
160 a4statsdb->query(a4statsdb, a4stats_nt_query_cb, ri, "SELECT users.account, users.accountid, users.seen, users.curnick, channels.privacy "
161 "FROM ? "
162 "LEFT JOIN ? ON channels.id = users.channelid "
163 "WHERE channels.name = ? AND (lines > 5 OR accountid != 0) AND (LOWER(curnick) LIKE ? OR LOWER(account) LIKE ?) ORDER BY seen DESC LIMIT 150",
164 "TTsss", "users", "channels", argv[0], argv[1], argv[1]);
165
166 return 0;
167 }
168
169 void _init(void) {
170 a4stats_node = register_service("a4stats");
171 if (!a4stats_node)
172 return;
173
174 register_handler(a4stats_node, "getchannel", 1, handle_getchannel);
175 register_handler(a4stats_node, "getlines", 1, handle_getlines);
176 register_handler(a4stats_node, "getusers", 1, handle_getusers);
177 register_handler(a4stats_node, "getkicks", 1, handle_getkicks);
178 register_handler(a4stats_node, "gettopics", 1, handle_gettopics);
179 register_handler(a4stats_node, "getuser", 3, handle_getuser);
180 register_handler(a4stats_node, "getrelations", 1, handle_getrelations);
181 register_handler(a4stats_node, "getuserrelations", 3, handle_getuserrelations);
182 register_handler(a4stats_node, "setprivacy", 2, handle_setprivacy);
183 register_handler(a4stats_node, "finduser", 2, handle_finduser);
184 }
185
186 void _fini(void) {
187 if (a4stats_node)
188 deregister_service(a4stats_node);
189 }