]> jfr.im git - irc/evilnet/x3.git/blame - patches/helpserv-pgsql.diff
Added an error check to help trace users figure out mistakes with mark vs marked
[irc/evilnet/x3.git] / patches / helpserv-pgsql.diff
CommitLineData
d76ed9a9 1Index: src/Makefile.am
2===================================================================
3RCS file: /cvsroot/srvx/services/src/Makefile.am,v
4retrieving revision 1.59
5diff -u -r1.59 Makefile.am
6--- src/Makefile.am 9 Sep 2003 01:56:55 -0000 1.59
7+++ src/Makefile.am 5 Nov 2003 14:15:46 -0000
8@@ -9,7 +9,7 @@
9 ./expnhelp < $(srcdir)/nickserv.help.m4 > $@
10
7827220c 11 EXTRA_srvx_SOURCES = proto-common.c proto-p10.c mod-snoop.c mod-memoserv.c
d76ed9a9 12-srvx_LDADD = @MODULE_OBJS@
13+srvx_LDADD = @MODULE_OBJS@ -lpq
14 srvx_DEPENDENCIES = @MODULE_OBJS@
15 srvx_SOURCES = \
16 chanserv.c chanserv.h \
17Index: src/helpserv.c
18===================================================================
19RCS file: /cvsroot/srvx/services/src/helpserv.c,v
20retrieving revision 1.84
21diff -u -r1.84 helpserv.c
22--- src/helpserv.c 5 Nov 2003 13:52:23 -0000 1.84
23+++ src/helpserv.c 5 Nov 2003 14:15:48 -0000
24@@ -46,6 +46,8 @@
25 #include "opserv.h"
26 #include "saxdb.h"
27 #include "timeq.h"
28+#include "ioset.h"
29+#include <postgresql/libpq-fe.h>
30
31 #define HELPSERV_CONF_NAME "services/helpserv"
32 #define HELPSERV_HELPFILE_NAME "helpserv.help"
33@@ -94,6 +96,7 @@
34 #define KEY_REQ_ON_JOIN "req_on_join"
35 #define KEY_AUTO_VOICE "auto_voice"
36 #define KEY_AUTO_DEVOICE "auto_devoice"
37+#define KEY_LOG_SQL "log_sql"
38
39 /* General */
40 #define HSMSG_WRITE_SUCCESS "HelpServ db write completed (in "FMT_TIME_T".%03lu seconds)."
41@@ -401,6 +404,7 @@
42 const char *description;
43 unsigned long db_backup_frequency;
44 const char *reqlogfile;
45+ PGconn *sql_log;
46 } helpserv_conf;
47
48 static int helpserv_enabled;
49@@ -443,6 +447,7 @@
50 unsigned int req_on_join : 1;
51 unsigned int auto_voice : 1;
52 unsigned int auto_devoice : 1;
53+ unsigned int log_sql : 1;
54
55 unsigned int helpchan_empty : 1;
56
57@@ -608,36 +613,153 @@
58 return dict_find(hs->users, hi->handle, NULL);
59 }
60
61-static void helpserv_log_request(struct helpserv_request *req, const char *reason) {
62- char key[27+NICKLEN];
63- char userhost[USERLEN+HOSTLEN+2];
64+static struct string_list sql_queue;
65+static struct io_fd *sql_fd;
66
67- if (!reqlog_ctx || !req)
68+static void pgsql_send_next_query() {
69+ int res;
70+
71+ res = PQsendQuery(helpserv_conf.sql_log, sql_queue.list[0]);
72+ if (!res) {
73+ log_module(MAIN_LOG, LOG_ERROR, "Error sending query \"%s\": %s", sql_queue.list[0], PQerrorMessage(helpserv_conf.sql_log));
74 return;
75- if (!reason)
76- reason = "";
77+ }
78+ res = PQflush(helpserv_conf.sql_log);
79+ if (res == EOF)
80+ log_module(MAIN_LOG, LOG_ERROR, "Error flushing PgSql output: %s", PQerrorMessage(helpserv_conf.sql_log));
81+}
82+
83+static void pgsql_readable(UNUSED_ARG(struct io_fd *fd)) {
84+ PGconn *conn;
85+ PGresult *pgres;
86+ unsigned int ii;
87+ int res;
88+ ExecStatusType st;
89+
90+ conn = helpserv_conf.sql_log;
91+ res = PQconsumeInput(conn);
92+ if (!res)
93+ log_module(MAIN_LOG, LOG_ERROR, "Error consuming PgSql input: %s", PQerrorMessage(conn));
94+ if (PQisBusy(conn))
95+ return;
96+ while ((pgres = PQgetResult(conn))) {
97+ st = PQresultStatus(pgres);
98+ if (st != PGRES_COMMAND_OK)
99+ log_module(MAIN_LOG, LOG_ERROR, "PgSql error in \"%s\": %s", sql_queue.list[0], PQresultErrorMessage(pgres));
100+ PQclear(pgres);
101+ }
102+ if (sql_queue.used == 1)
103+ sql_queue.list[1] = NULL;
104+ free(sql_queue.list[0]);
105+ sql_queue.used--;
106+ for (ii = 0; ii < sql_queue.used; ++ii)
107+ sql_queue.list[ii] = sql_queue.list[ii+1];
108+ if (sql_queue.used)
109+ pgsql_send_next_query();
110+}
111
112- sprintf(key, "%s-" FMT_TIME_T "-%lu", req->hs->helpserv->nick, req->opened, req->id);
113- saxdb_start_record(reqlog_ctx, key, 1);
114- if (req->helper) {
115- saxdb_write_string(reqlog_ctx, KEY_REQUEST_HELPER, req->helper->handle->handle);
116- saxdb_write_int(reqlog_ctx, KEY_REQUEST_ASSIGNED, req->assigned);
117+static void
118+string_buffer_append_quoted(struct string_buffer *dest, const char *src) {
119+ if (src) {
120+ size_t len = strlen(src);
121+ string_buffer_append(dest, '\'');
122+ if (dest->size < (dest->used + len * 2)) {
123+ if (dest->size < len * 2)
124+ dest->size = len * 4;
125+ else
126+ dest->size = dest->size * 2;
127+ dest->list = realloc(dest->list, dest->size);
128+ }
129+ dest->used += PQescapeString(dest->list + dest->used, src, len);
130+ string_buffer_append_string(dest, "', ");
131+ } else {
132+ string_buffer_append_string(dest, "NULL, ");
133 }
134- if (req->handle) {
135- saxdb_write_string(reqlog_ctx, KEY_REQUEST_HANDLE, req->handle->handle);
136+}
137+
138+static void
139+string_buffer_append_time(struct string_buffer *dest, time_t when) {
140+ struct tm broken_out;
141+ if (!when) {
142+ string_buffer_append_string(dest, "NULL, ");
143+ return;
144 }
145- if (req->user) {
146- saxdb_write_string(reqlog_ctx, KEY_REQUEST_NICK, req->user->nick);
147- sprintf(userhost, "%s@%s", req->user->ident, req->user->hostname);
148- saxdb_write_string(reqlog_ctx, KEY_REQUEST_USERHOST, userhost);
149+ if (dest->size < dest->used + 20) {
150+ if (dest->size < 20) {
151+ dest->size = 40;
152+ } else {
153+ dest->size = dest->size * 2;
154+ }
155+ dest->list = realloc(dest->list, dest->size);
156 }
157- saxdb_write_int(reqlog_ctx, KEY_REQUEST_OPENED, req->opened);
158- saxdb_write_int(reqlog_ctx, KEY_REQUEST_CLOSED, now);
159- saxdb_write_string(reqlog_ctx, KEY_REQUEST_CLOSEREASON, reason);
160- saxdb_write_string_list(reqlog_ctx, KEY_REQUEST_TEXT, req->text);
161- saxdb_end_record(reqlog_ctx);
162+ dest->used += strftime(dest->list + dest->used, dest->size - dest->used, "'%Y-%m-%d %H:%M:%S', ", localtime_r(&when, &broken_out));
163+}
164
165- fflush(reqlog_f);
166+static void
167+pgsql_insert(char *query) {
168+ string_list_append(&sql_queue, query);
169+ if (sql_queue.used == 1)
170+ pgsql_send_next_query();
171+}
172+
173+static void helpserv_log_request(struct helpserv_request *req, const char *reason) {
174+ char userhost[USERLEN+HOSTLEN+2];
175+
176+ if (req->user)
177+ sprintf(userhost, "%s@%s", req->user->ident, req->user->hostname);
178+ else
179+ userhost[0] = 0;
180+ if (reqlog_ctx) {
181+ char key[27+NICKLEN];
182+ sprintf(key, "%s-" FMT_TIME_T "-%lu", req->hs->helpserv->nick, req->opened, req->id);
183+ saxdb_start_record(reqlog_ctx, key, 1);
184+ if (req->helper) {
185+ saxdb_write_string(reqlog_ctx, KEY_REQUEST_HELPER, req->helper->handle->handle);
186+ saxdb_write_int(reqlog_ctx, KEY_REQUEST_ASSIGNED, req->assigned);
187+ }
188+ if (req->handle)
189+ saxdb_write_string(reqlog_ctx, KEY_REQUEST_HANDLE, req->handle->handle);
190+ if (req->user) {
191+ saxdb_write_string(reqlog_ctx, KEY_REQUEST_NICK, req->user->nick);
192+ saxdb_write_string(reqlog_ctx, KEY_REQUEST_USERHOST, userhost);
193+ }
194+ saxdb_write_int(reqlog_ctx, KEY_REQUEST_OPENED, req->opened);
195+ saxdb_write_int(reqlog_ctx, KEY_REQUEST_CLOSED, now);
196+ saxdb_write_string(reqlog_ctx, KEY_REQUEST_CLOSEREASON, reason);
197+ saxdb_write_string_list(reqlog_ctx, KEY_REQUEST_TEXT, req->text);
198+ saxdb_end_record(reqlog_ctx);
199+ fflush(reqlog_f);
200+ }
201+ if (helpserv_conf.sql_log && req->hs->log_sql) {
202+ struct string_buffer query, sb;
203+ unsigned int ii;
204+
205+ sb.used = query.used = 0;
206+ sb.size = query.size = 512;
207+ query.list = malloc(query.size);
208+ sb.list = malloc(sb.size);
209+ string_buffer_append_string(&query, "INSERT INTO srvx_helpserv_reqs (c_bot, t_opened, t_assigned, t_closed, i_id, c_helper, c_user_account, c_user_nick, c_user_host, c_close_reason, c_text) VALUES (");
210+ string_buffer_append_quoted(&query, req->hs->helpserv->nick);
211+ string_buffer_append_time(&query, req->opened);
212+ string_buffer_append_time(&query, req->assigned);
213+ string_buffer_append_time(&query, now);
214+ string_buffer_append_printf(&query, "%lu, ", req->id);
215+ string_buffer_append_quoted(&query, req->helper ? req->helper->handle->handle : NULL);
216+ string_buffer_append_quoted(&query, req->handle ? req->handle->handle : NULL);
217+ string_buffer_append_quoted(&query, req->user ? req->user->nick : NULL);
218+ string_buffer_append_quoted(&query, req->user ? userhost : NULL);
219+ string_buffer_append_quoted(&query, reason);
220+ for (ii = 0; ii < req->text->used; ++ii) {
221+ string_buffer_append_string(&sb, req->text->list[ii]);
222+ string_buffer_append(&sb, '\n');
223+ }
224+ string_buffer_append(&sb, 0);
225+ string_buffer_append_quoted(&query, sb.list);
226+ query.used -= 2; /* chop off ", " from append_quoted */
227+ string_buffer_append_string(&query, ");");
228+ pgsql_insert(query.list);
229+ free(sb.list);
230+ }
231 }
232
233 /* Searches for a request by number, nick, or account (num|nick|*account).
234@@ -2931,6 +3053,28 @@
235 OPTION_BINARY(hs->auto_devoice, "AutoDeVoice");
236 }
237
238+static HELPSERV_OPTION(opt_log_sql) {
239+ int changed = 0;
240+ if (argc > 0) {
241+ if (!from_opserv) {
242+ helpserv_notice(user, HSMSG_SET_NEED_OPER);
243+ return 0;
244+ }
245+ if (enabled_string(argv[0])) {
246+ hs->log_sql = 1;
247+ changed = 1;
248+ } else if (disabled_string(argv[0])) {
249+ hs->log_sql = 0;
250+ changed = 1;
251+ } else {
252+ helpserv_notice(user, MSG_INVALID_BINARY, argv[0]);
253+ return 0;
254+ }
255+ }
256+ helpserv_notice(user, HSMSG_STRING_VALUE, "LogSql", hs->log_sql ? "Enabled" : "Disabled");
257+ return changed;
258+}
259+
260 static HELPSERV_FUNC(cmd_set) {
261 helpserv_option_func_t *opt;
262
263@@ -2944,7 +3088,7 @@
264 opt_empty_interval, opt_stale_delay, opt_request_persistence,
265 opt_helper_persistence, opt_notification, opt_id_wrap,
266 opt_req_maxlen, opt_privmsg_only, opt_req_on_join, opt_auto_voice,
267- opt_auto_devoice
268+ opt_auto_devoice, opt_log_sql
269 };
270
271 helpserv_notice(user, HSMSG_QUEUE_OPTIONS);
272@@ -3267,6 +3411,7 @@
273 saxdb_write_int(ctx, KEY_REQ_ON_JOIN, hs->req_on_join);
274 saxdb_write_int(ctx, KEY_AUTO_VOICE, hs->auto_voice);
275 saxdb_write_int(ctx, KEY_AUTO_DEVOICE, hs->auto_devoice);
276+ saxdb_write_int(ctx, KEY_LOG_SQL, hs->log_sql);
277
278 /* End bot record */
279 saxdb_end_record(ctx);
280@@ -3376,6 +3521,8 @@
281 hs->auto_voice = str ? enabled_string(str) : 0;
282 str = database_get_data(GET_RECORD_OBJECT(br), KEY_AUTO_DEVOICE, RECDB_QSTRING);
283 hs->auto_devoice = str ? enabled_string(str) : 0;
284+ str = database_get_data(GET_RECORD_OBJECT(br), KEY_LOG_SQL, RECDB_QSTRING);
285+ hs->log_sql = str ? enabled_string(str) : 0;
286
287 dict_foreach(users, user_read_helper, hs);
288
289@@ -3422,6 +3569,31 @@
290 helpserv_conf.reqlogfile = NULL;
291 }
292
293+ if (helpserv_conf.sql_log) {
294+ PQfinish(helpserv_conf.sql_log);
295+ helpserv_conf.sql_log = NULL;
296+ }
297+ str = database_get_data(conf_node, "sql_log", RECDB_QSTRING);
298+ if (str) {
299+ PGconn *conn = PQconnectdb(str);
300+ if (!conn) {
301+ log_module(HS_LOG, LOG_ERROR, "Unable to allocate pgsql connection");
302+ } else if (PQstatus(conn) == CONNECTION_BAD) {
303+ log_module(HS_LOG, LOG_ERROR, "Pgsql connection failed: %s", PQerrorMessage(conn));
304+ PQfinish(conn);
305+ } else if (PQsetnonblocking(conn, 1) == -1) {
306+ log_module(HS_LOG, LOG_ERROR, "Unable to make pgsql non-blocking");
307+ PQfinish(conn);
308+ } else {
309+ helpserv_conf.sql_log = conn;
310+ sql_fd = ioset_add(PQsocket(conn));
311+ sql_fd->connected = 1;
312+ sql_fd->wants_reads = 1;
313+ sql_fd->readable_cb = pgsql_readable;
314+ while (PQflush(conn)) ;
315+ }
316+ }
317+
318 if (reqlog_ctx) {
319 saxdb_close_context(reqlog_ctx);
320 reqlog_ctx = NULL;
321@@ -4159,16 +4331,20 @@
322 return mktime(timeinfo);
323 }
324
325-/* If data != NULL, then don't add to the timeq */
326 static void helpserv_run_stats(time_t when) {
327 struct tm when_s;
328+ struct string_buffer query;
329 struct helpserv_bot *hs;
330 struct helpserv_user *hs_user;
331 int i;
332 dict_iterator_t it, it2;
333+ char timestamp[64];
334
335 last_stats_update = when;
336 localtime_r(&when, &when_s);
337+ strftime(timestamp, sizeof(timestamp), "'%Y-%m-%d %H:%M:%S', ", &when_s);
338+ query.size = 512;
339+
340 for (it=dict_first(helpserv_bots_dict); it; it=iter_next(it)) {
341 hs = iter_data(it);
342
343@@ -4195,6 +4371,18 @@
344 hs_user->reassigned_to[i] = hs_user->reassigned_to[i-1];
345 }
346
347+ /* Log to SQL */
348+ if (helpserv_conf.sql_log && hs->log_sql) {
349+ query.list = malloc(query.size);
350+ query.used = 0;
351+ string_buffer_append_string(&query, "INSERT INTO srvx_helpserv_stats (c_bot, t_weekstart, c_helper, i_time, i_picked_up, i_closed, i_reassigned_from, i_reassigned_to) VALUES(");
352+ string_buffer_append_quoted(&query, hs->helpserv->nick);
353+ string_buffer_append_quoted(&query, timestamp);
354+ string_buffer_append_quoted(&query, hs_user->handle->handle);
355+ string_buffer_append_printf(&query, "%d, %d, %d, %d, %d);", hs_user->time_per_week[0], hs_user->picked_up[0], hs_user->closed[0], hs_user->reassigned_from[0], hs_user->reassigned_to[0]);
356+ pgsql_insert(query.list);
357+ }
358+
359 /* Reset it for this week */
360 hs_user->time_per_week[0] = hs_user->picked_up[0] = hs_user->closed[0] = hs_user->reassigned_from[0] = hs_user->reassigned_to[0] = 0;
361 }
362@@ -4228,6 +4416,10 @@
363 saxdb_close_context(reqlog_ctx);
364 if (reqlog_f)
365 fclose(reqlog_f);
366+ if (helpserv_conf.sql_log) {
367+ PQfinish(helpserv_conf.sql_log);
368+ helpserv_conf.sql_log = NULL;
369+ }
370 }
371
372 void init_helpserv() {
373@@ -4293,6 +4485,7 @@
374 helpserv_define_option("REQONJOIN", opt_req_on_join);
375 helpserv_define_option("AUTOVOICE", opt_auto_voice);
376 helpserv_define_option("AUTODEVOICE", opt_auto_devoice);
377+ helpserv_define_option("LOGSQL", opt_log_sql);
378
379 helpserv_bots_dict = dict_new();
380 dict_set_free_data(helpserv_bots_dict, helpserv_free_bot);