]> jfr.im git - irc/quakenet/newserv.git/blob - numerictracker/numerictracker.c
NUMERICTRACKER: initial import.
[irc/quakenet/newserv.git] / numerictracker / numerictracker.c
1 #include <stdio.h>
2 #include <time.h>
3 #include "../lib/version.h"
4 #include "../dbapi2/dbapi2.h"
5 #include "../core/error.h"
6 #include "../core/hooks.h"
7 #include "../core/schedule.h"
8 #include "../server/server.h"
9 #include "../control/control.h"
10
11 MODULE_VERSION("")
12
13 static DBAPIConn *db;
14
15 static void hook_server(int hook, void *arg);
16 static void create_entry(unsigned long servernum, int start_transaction);
17 static int list_numerics(void *source, int cargc, char **cargv);
18 static void rescan_network(void);
19 static void rescan_network_s(void *arg);
20
21 void _init(void) {
22 db = dbapi2open(NULL, "numerictracker");
23 if(!db) {
24 Error("numerictracker", ERR_WARNING, "Unable to connect to db -- not loaded.");
25 return;
26 }
27
28 db->createtable(db, NULL, NULL, "CREATE TABLE ? (numeric VARCHAR(2) NOT NULL, server_name VARCHAR(?), last_seen INT, PRIMARY KEY (numeric, server_name));", "Td", "numerics", HOSTLEN);
29
30 registerhook(HOOK_SERVER_NEWSERVER, &hook_server);
31 registerhook(HOOK_SERVER_LOSTSERVER, &hook_server);
32 rescan_network();
33 schedulerecurring(time(NULL)+60*5, 0, 60*5, rescan_network_s, NULL);
34
35 registercontrolhelpcmd("listnumerics", NO_OPER, 0, list_numerics, "Usage: listnumerics\nLists all numeric-servername pairs ever seen by the service.");
36 }
37
38 void _fini(void) {
39 if(!db)
40 return;
41
42 deregisterhook(HOOK_SERVER_NEWSERVER, &hook_server);
43 deregisterhook(HOOK_SERVER_LOSTSERVER, &hook_server);
44 deregistercontrolcmd("listnumerics", list_numerics);
45 deleteallschedules(rescan_network_s);
46 }
47
48 static void rescan_network() {
49 int i;
50
51 db->squery(db, "BEGIN TRANSACTION;", "");
52
53 for(i=0;i<MAXSERVERS;i++)
54 if(serverlist[i].linkstate != LS_INVALID)
55 create_entry(i, 0);
56
57 db->squery(db, "COMMIT;", "");
58 }
59
60 static void rescan_network_s(void *arg) {
61 rescan_network();
62 }
63
64 static void hook_server(int hook, void *arg) {
65 unsigned long servernum = (unsigned long)arg;
66
67 create_entry(servernum, 1);
68 }
69
70 static void create_entry(unsigned long servernum, int start_transaction) {
71 char *server_name = serverlist[servernum].name->content;
72 char *numeric = longtonumeric(servernum, 2);
73
74 if(start_transaction)
75 db->squery(db, "BEGIN TRANSACTION;", "");
76
77 db->squery(db, "DELETE FROM ? WHERE numeric = ? AND server_name = ?;", "Tss", "numerics", numeric, server_name);
78 db->squery(db, "INSERT INTO ? (numeric, server_name, last_seen) VALUES (?, ?, ?);", "Tsst", "numerics", numeric, server_name, time(NULL));
79
80 if(start_transaction)
81 db->squery(db, "COMMIT;", "");
82 }
83
84 static void list_numerics_callback(const DBAPIResult *result, void *tag) {
85 nick *sender = getnickbynumeric((unsigned long)tag);
86
87 if(!result) {
88 if(sender)
89 controlreply(sender, "DB query error 1.");
90 return;
91 }
92
93 if(!sender || !result->success || (result->fields != 3)) {
94 if(sender)
95 controlreply(sender, "DB query error 2.");
96
97 result->clear(result);
98 return;
99 }
100
101 controlreply(sender, "%s %-50s %s", "NN", "Server name", "Last seen");
102 while(result->next(result)) {
103 char *numeric;
104 char *server_name;
105 time_t last_seen;
106 char timebuf[50];
107
108 numeric = result->get(result, 0);
109 server_name = result->get(result, 1);
110 last_seen = strtoul(result->get(result, 2), NULL, 10);
111
112 strftime(timebuf, sizeof(timebuf), "%d/%m/%y %H:%M GMT", gmtime(&last_seen));
113 controlreply(sender, " %s %-50s %s", numeric, server_name, timebuf);
114 }
115 result->clear(result);
116
117 controlreply(sender, "End of listing.");
118 }
119
120 static int list_numerics(void *source, int cargc, char **cargv) {
121 nick *sender = (nick *)source;
122
123 rescan_network();
124 db->query(db, list_numerics_callback, (void *)sender->numeric, "SELECT numeric, server_name, last_seen FROM ? ORDER BY last_seen ASC, numeric, server_name", "T", "numerics");
125
126 return CMD_OK;
127 }