2 ===================================================================
3 RCS file: /cvsroot/srvx/services/src/Makefile.am,v
4 retrieving revision 1.59
5 diff -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
9 ./expnhelp < $(srcdir)/nickserv.help.m4 > $@
11 EXTRA_srvx_SOURCES = proto-bahamut.c proto-common.c proto-p10.c mod-snoop.c mod-memoserv.c
12 -srvx_LDADD = @MODULE_OBJS@
13 +srvx_LDADD = @MODULE_OBJS@ -lpq
14 srvx_DEPENDENCIES = @MODULE_OBJS@
16 chanserv.c chanserv.h \
18 ===================================================================
19 RCS file: /cvsroot/srvx/services/src/helpserv.c,v
20 retrieving revision 1.84
21 diff -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
29 +#include <postgresql/libpq-fe.h>
31 #define HELPSERV_CONF_NAME "services/helpserv"
32 #define HELPSERV_HELPFILE_NAME "helpserv.help"
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"
40 #define HSMSG_WRITE_SUCCESS "HelpServ db write completed (in "FMT_TIME_T".%03lu seconds)."
42 const char *description;
43 unsigned long db_backup_frequency;
44 const char *reqlogfile;
48 static int helpserv_enabled;
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;
55 unsigned int helpchan_empty : 1;
57 @@ -608,36 +613,153 @@
58 return dict_find(hs->users, hi->handle, NULL);
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;
67 - if (!reqlog_ctx || !req)
68 +static void pgsql_send_next_query() {
71 + res = PQsendQuery(helpserv_conf.sql_log, sql_queue.list[0]);
73 + log_module(MAIN_LOG, LOG_ERROR, "Error sending query \"%s\": %s", sql_queue.list[0], PQerrorMessage(helpserv_conf.sql_log));
78 + res = PQflush(helpserv_conf.sql_log);
80 + log_module(MAIN_LOG, LOG_ERROR, "Error flushing PgSql output: %s", PQerrorMessage(helpserv_conf.sql_log));
83 +static void pgsql_readable(UNUSED_ARG(struct io_fd *fd)) {
90 + conn = helpserv_conf.sql_log;
91 + res = PQconsumeInput(conn);
93 + log_module(MAIN_LOG, LOG_ERROR, "Error consuming PgSql input: %s", PQerrorMessage(conn));
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));
102 + if (sql_queue.used == 1)
103 + sql_queue.list[1] = NULL;
104 + free(sql_queue.list[0]);
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();
112 - sprintf(key, "%s-" FMT_TIME_T "-%lu", req->hs->helpserv->nick, req->opened, req->id);
113 - saxdb_start_record(reqlog_ctx, key, 1);
115 - saxdb_write_string(reqlog_ctx, KEY_REQUEST_HELPER, req->helper->handle->handle);
116 - saxdb_write_int(reqlog_ctx, KEY_REQUEST_ASSIGNED, req->assigned);
118 +string_buffer_append_quoted(struct string_buffer *dest, const char *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;
126 + dest->size = dest->size * 2;
127 + dest->list = realloc(dest->list, dest->size);
129 + dest->used += PQescapeString(dest->list + dest->used, src, len);
130 + string_buffer_append_string(dest, "', ");
132 + string_buffer_append_string(dest, "NULL, ");
135 - saxdb_write_string(reqlog_ctx, KEY_REQUEST_HANDLE, req->handle->handle);
139 +string_buffer_append_time(struct string_buffer *dest, time_t when) {
140 + struct tm broken_out;
142 + string_buffer_append_string(dest, "NULL, ");
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) {
153 + dest->size = dest->size * 2;
155 + dest->list = realloc(dest->list, dest->size);
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));
167 +pgsql_insert(char *query) {
168 + string_list_append(&sql_queue, query);
169 + if (sql_queue.used == 1)
170 + pgsql_send_next_query();
173 +static void helpserv_log_request(struct helpserv_request *req, const char *reason) {
174 + char userhost[USERLEN+HOSTLEN+2];
177 + sprintf(userhost, "%s@%s", req->user->ident, req->user->hostname);
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);
185 + saxdb_write_string(reqlog_ctx, KEY_REQUEST_HELPER, req->helper->handle->handle);
186 + saxdb_write_int(reqlog_ctx, KEY_REQUEST_ASSIGNED, req->assigned);
189 + saxdb_write_string(reqlog_ctx, KEY_REQUEST_HANDLE, req->handle->handle);
191 + saxdb_write_string(reqlog_ctx, KEY_REQUEST_NICK, req->user->nick);
192 + saxdb_write_string(reqlog_ctx, KEY_REQUEST_USERHOST, userhost);
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);
201 + if (helpserv_conf.sql_log && req->hs->log_sql) {
202 + struct string_buffer query, sb;
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');
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);
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");
238 +static HELPSERV_OPTION(opt_log_sql) {
241 + if (!from_opserv) {
242 + helpserv_notice(user, HSMSG_SET_NEED_OPER);
245 + if (enabled_string(argv[0])) {
248 + } else if (disabled_string(argv[0])) {
252 + helpserv_notice(user, MSG_INVALID_BINARY, argv[0]);
256 + helpserv_notice(user, HSMSG_STRING_VALUE, "LogSql", hs->log_sql ? "Enabled" : "Disabled");
260 static HELPSERV_FUNC(cmd_set) {
261 helpserv_option_func_t *opt;
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,
268 + opt_auto_devoice, opt_log_sql
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);
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;
287 dict_foreach(users, user_read_helper, hs);
289 @@ -3422,6 +3569,31 @@
290 helpserv_conf.reqlogfile = NULL;
293 + if (helpserv_conf.sql_log) {
294 + PQfinish(helpserv_conf.sql_log);
295 + helpserv_conf.sql_log = NULL;
297 + str = database_get_data(conf_node, "sql_log", RECDB_QSTRING);
299 + PGconn *conn = PQconnectdb(str);
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));
305 + } else if (PQsetnonblocking(conn, 1) == -1) {
306 + log_module(HS_LOG, LOG_ERROR, "Unable to make pgsql non-blocking");
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)) ;
319 saxdb_close_context(reqlog_ctx);
321 @@ -4159,16 +4331,20 @@
322 return mktime(timeinfo);
325 -/* If data != NULL, then don't add to the timeq */
326 static void helpserv_run_stats(time_t when) {
328 + struct string_buffer query;
329 struct helpserv_bot *hs;
330 struct helpserv_user *hs_user;
332 dict_iterator_t it, it2;
333 + char timestamp[64];
335 last_stats_update = when;
336 localtime_r(&when, &when_s);
337 + strftime(timestamp, sizeof(timestamp), "'%Y-%m-%d %H:%M:%S', ", &when_s);
340 for (it=dict_first(helpserv_bots_dict); it; it=iter_next(it)) {
343 @@ -4195,6 +4371,18 @@
344 hs_user->reassigned_to[i] = hs_user->reassigned_to[i-1];
348 + if (helpserv_conf.sql_log && hs->log_sql) {
349 + query.list = malloc(query.size);
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);
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;
362 @@ -4228,6 +4416,10 @@
363 saxdb_close_context(reqlog_ctx);
366 + if (helpserv_conf.sql_log) {
367 + PQfinish(helpserv_conf.sql_log);
368 + helpserv_conf.sql_log = NULL;
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);
379 helpserv_bots_dict = dict_new();
380 dict_set_free_data(helpserv_bots_dict, helpserv_free_bot);