~ctrlproxy/ctrlproxy/trunk

« back to all changes in this revision

Viewing changes to mods/admin.c

  • Committer: jelmer
  • Date: 2003-10-18 22:02:02 UTC
  • Revision ID: jelmer@samba.org-20031018220202-6801a76318fb4d13
Update

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
        ctrlproxy: A modular IRC proxy
 
3
        admin: module for remote administration. Available commands:
 
4
         * ADDNETWORK <network>
 
5
         * ADDLISTEN <network> <type> [<key>=<value>] [...]
 
6
         * ADDSERVER <network> <type> [<key>=<value>] [...]
 
7
         * CONNECT <network>
 
8
         * DIE
 
9
         * DISCONNECT [<network>]
 
10
         * LISTNETWORKS
 
11
         * LOADMODULE <location>
 
12
         * RELOADMODULE <location>
 
13
         * UNLOADMODULE <location>
 
14
         * LISTMODULES
 
15
         * DUMPCONFIG 
 
16
         * SAVECONFIG
 
17
         * HELP
 
18
        
 
19
        (c) 2003 Jelmer Vernooij <jelmer@nl.linux.org>
 
20
 
 
21
        This program is free software; you can redistribute it and/or modify
 
22
        it under the terms of the GNU General Public License as published by
 
23
        the Free Software Foundation; either version 2 of the License, or
 
24
        (at your option) any later version.
 
25
 
 
26
        This program is distributed in the hope that it will be useful,
 
27
        but WITHOUT ANY WARRANTY; without even the implied warranty of
 
28
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
29
        GNU General Public License for more details.
 
30
 
 
31
        You should have received a copy of the GNU General Public License
 
32
        along with this program; if not, write to the Free Software
 
33
        Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
34
*/
 
35
 
 
36
#define _GNU_SOURCE
 
37
#include "ctrlproxy.h"
 
38
#include <string.h>
 
39
 
 
40
static gboolean with_privmsg = FALSE;
 
41
static GList *commands = NULL;
 
42
 
 
43
struct admin_command {
 
44
        char *name;
 
45
        void (*handler) (char **args, struct line *l);
 
46
};
 
47
 
 
48
void admin_out(struct line *l, char *fmt, ...)
 
49
{
 
50
        va_list ap;
 
51
        char *msg, *tot, *server_name;
 
52
        char *nick;
 
53
        va_start(ap, fmt);
 
54
        vasprintf(&msg, fmt, ap);
 
55
        va_end(ap);
 
56
 
 
57
        nick = xmlGetProp(l->network->xmlConf, "nick");
 
58
        server_name = xmlGetProp(l->network->xmlConf, "name");
 
59
 
 
60
        asprintf(&tot, ":ctrlproxy!ctrlproxy@%s PRIVMSG %s :%s\r\n", server_name, nick, msg);
 
61
        free(msg);
 
62
 
 
63
        transport_write(l->client->incoming, tot);
 
64
        free(tot);
 
65
        xmlFree(nick);
 
66
        xmlFree(server_name);
 
67
}
 
68
 
 
69
xmlNodePtr find_network_xml(char *name)
 
70
{
 
71
        char *nname;
 
72
        xmlNodePtr cur = xmlNode_networks->xmlChildrenNode;
 
73
        while(cur)
 
74
        {
 
75
                nname = xmlGetProp(cur, "name");
 
76
                if(nname && !strcmp(nname, name)){xmlFree(nname); return cur; }
 
77
                xmlFree(nname);
 
78
                cur = cur->next;
 
79
        }
 
80
        return NULL;
 
81
}
 
82
 
 
83
struct network *find_network_struct(char *name)
 
84
{
 
85
        char *nname;
 
86
        GList *g = networks;
 
87
        while(g) {
 
88
                struct network *n = (struct network *)g->data;
 
89
                nname = xmlGetProp(n->xmlConf, "name");
 
90
                if(!strcmp(nname, name)){ xmlFree(nname); return n; }
 
91
                xmlFree(nname);
 
92
                g = g->next;
 
93
        }
 
94
        return NULL;
 
95
}
 
96
 
 
97
static void add_network (char **args, struct line *l)
 
98
{       
 
99
        xmlNodePtr cur;
 
100
        if(!args[1]) {
 
101
                admin_out(l, "No name specified");
 
102
                return;
 
103
        }
 
104
        
 
105
        if(find_network_xml(args[1])) {
 
106
                admin_out(l, "Such a network already exists");
 
107
                return;
 
108
        }
 
109
 
 
110
        /* Add node to networks node with specified name */
 
111
        cur = xmlNewNode(NULL, "network");
 
112
        xmlSetProp(cur, "name", args[1]);
 
113
        xmlAddChild(xmlNode_networks, cur);
 
114
 
 
115
        /* Add a 'servers' element */
 
116
        xmlAddChild(cur, xmlNewNode(NULL, "servers"));
 
117
}
 
118
 
 
119
static void add_listen (char **args, struct line *l)
 
120
{
 
121
        xmlNodePtr net, serv, listen;
 
122
        struct network *n;
 
123
        int i;
 
124
        
 
125
        if(!args[1] || !args[2]) {
 
126
                admin_out(l, "Not enough parameters");
 
127
                return;
 
128
        }
 
129
 
 
130
        net = find_network_xml(args[1]);
 
131
 
 
132
        /* Add network if it didn't exist yet */
 
133
        if(!net) {
 
134
                /* Add node to networks node with specified name */
 
135
                net = xmlNewNode(NULL, "network");
 
136
                xmlSetProp(net, "name", args[1]);
 
137
                xmlAddChild(xmlNode_networks, net);
 
138
 
 
139
                /* Add a 'listen' element */
 
140
                xmlAddChild(net, xmlNewNode(NULL, "listen"));
 
141
        }
 
142
 
 
143
        listen = xmlFindChildByElementName(net, "listen");
 
144
 
 
145
        /* Add listen node if it didn't exist yet */
 
146
        if(!listen) {
 
147
                listen = xmlNewNode(NULL, "listen"); 
 
148
                xmlAddChild(net, listen); 
 
149
        }
 
150
 
 
151
        serv = xmlNewNode(NULL, args[2]);
 
152
        xmlAddChild(listen, serv);
 
153
 
 
154
        for(i = 3; args[i]; i++) {
 
155
                char *val = strchr(args[i], '=');
 
156
                if(!val) {
 
157
                        admin_out(l, "Properties should be in the format 'key=value'");
 
158
                        continue;
 
159
                }
 
160
                *val = '\0'; val++;
 
161
                xmlSetProp(serv, args[i], val);
 
162
        }
 
163
        
 
164
        /* In case the network is active */
 
165
        n = find_network_struct(args[1]);
 
166
        if(n) {
 
167
                if(!n->listen)n->listen = listen;
 
168
                network_add_listen(n, serv);
 
169
        }
 
170
}
 
171
 
 
172
static void add_server (char **args, struct line *l)
 
173
{
 
174
        xmlNodePtr net, serv, servers;
 
175
        int i;
 
176
        
 
177
        if(!args[1] || !args[2]) {
 
178
                admin_out(l, "Not enough parameters");
 
179
                return;
 
180
        }
 
181
 
 
182
        net = find_network_xml(args[1]);
 
183
 
 
184
        /* Add network if it didn't exist yet */
 
185
        if(!net) {
 
186
                /* Add node to networks node with specified name */
 
187
                net = xmlNewNode(NULL, "network");
 
188
                xmlSetProp(net, "name", args[1]);
 
189
                xmlAddChild(xmlNode_networks, net);
 
190
 
 
191
                /* Add a 'servers' element */
 
192
                xmlAddChild(net, xmlNewNode(NULL, "servers"));
 
193
        }
 
194
 
 
195
        servers = xmlFindChildByElementName(net, "servers");
 
196
 
 
197
        /* Add servers node if it didn't exist yet */
 
198
        if(!servers) {
 
199
                servers = xmlNewNode(NULL, "servers"); 
 
200
                xmlAddChild(net, servers); 
 
201
        }
 
202
 
 
203
        serv = xmlNewNode(NULL, args[2]);
 
204
        xmlAddChild(servers, serv);
 
205
 
 
206
        for(i = 3; args[i]; i++) {
 
207
                char *val = strchr(args[i], '=');
 
208
                if(!val) {
 
209
                        admin_out(l, "Properties should be in the format 'key=value'");
 
210
                        continue;
 
211
                }
 
212
                *val = '\0'; val++;
 
213
                xmlSetProp(serv, args[i], val);
 
214
        }
 
215
}
 
216
 
 
217
static void connect_network (char **args, struct line *l)
 
218
 
219
        xmlNodePtr n;
 
220
        if(!args[1]) {
 
221
                 admin_out(l, "No network specified");
 
222
                 return;
 
223
        }
 
224
 
 
225
        n = find_network_xml(args[1]);
 
226
        if(!n) {
 
227
                admin_out(l, "Can't find network named %s", args[1]);
 
228
                return;
 
229
        }
 
230
 
 
231
        g_message("Connecting to %s", args[1]);
 
232
        
 
233
        connect_to_server(n);
 
234
}
 
235
 
 
236
static void disconnect_network (char **args, struct line *l)
 
237
 
238
        struct network *n;
 
239
        if(!args[1])n = l->network;
 
240
        else {
 
241
                n = find_network_struct(args[1]);
 
242
                if(!n) {
 
243
                        admin_out(l, "Can't find network with that name");
 
244
                        return;
 
245
                }
 
246
        }
 
247
        
 
248
        close_server(n);
 
249
}
 
250
 
 
251
static void list_modules (char **args, struct line *l)
 
252
{
 
253
        GList *g = plugins;
 
254
        while(g) {
 
255
                struct plugin *p = (struct plugin *)g->data;
 
256
                admin_out(l, "%s", p->name);
 
257
                g = g->next;
 
258
        }
 
259
}
 
260
 
 
261
static void unload_module (char **args, struct line *l)
 
262
{
 
263
        GList *g = plugins;
 
264
 
 
265
        if(!args[1]) {
 
266
                admin_out(l, "Not enough arguments");
 
267
                return;
 
268
        }
 
269
 
 
270
        if(!strcmp(args[1], "admin")) {
 
271
                admin_out(l, "Can't unload /this/ module");
 
272
                return;
 
273
        }
 
274
        
 
275
        /* Find specified plugins' GModule and xmlNodePtr */
 
276
        while(g) {
 
277
                struct plugin *p = (struct plugin *)g->data;
 
278
                if(!strcmp(p->name, args[1])) { 
 
279
                        if(unload_plugin(p)) plugins = g_list_remove(plugins, p);
 
280
                        return; 
 
281
                }
 
282
                g = g->next;
 
283
        }
 
284
 
 
285
        admin_out(l, "No such plugin loaded");
 
286
}
 
287
 
 
288
static void load_module (char **args, struct line *l)
 
289
 
290
        xmlNodePtr cur;
 
291
        if(!args[1]) { 
 
292
                admin_out(l, "No file specified");
 
293
                return;
 
294
        }
 
295
 
 
296
    if(!strcmp(args[1], "admin")) {
 
297
                admin_out(l, "Can't load this module /again/");
 
298
                return;
 
299
        }
 
300
 
 
301
        cur = xmlNewNode(NULL, "plugin");
 
302
        xmlSetProp(cur, "file", args[1]);
 
303
        xmlAddChild(xmlNode_plugins, cur);
 
304
 
 
305
        load_plugin(cur);
 
306
}
 
307
 
 
308
 
 
309
static void reload_module (char **args, struct line *l)
 
310
{
 
311
        unload_module(args, l);
 
312
        load_module(args, l);
 
313
}
 
314
 
 
315
static void dump_config (char **args, struct line *l)
 
316
 
317
        xmlChar *buffer;
 
318
        int lastend = 0;
 
319
        int size;
 
320
        int i;
 
321
        char *tmp;
 
322
        xmlDocDumpMemory(configuration, &buffer, &size);
 
323
        for(i = 0; i < size; i++)
 
324
        {
 
325
                /* If we encounter a newline or a null-character, we 
 
326
                 * print the last line */
 
327
                if(buffer[i] != '\n' && buffer[i] != '\0') continue;
 
328
 
 
329
                tmp = strndup(buffer + lastend, i - lastend);
 
330
                admin_out(l, tmp);
 
331
                free(tmp);
 
332
                lastend = i+1;
 
333
        }
 
334
}
 
335
 
 
336
static void save_config (char **args, struct line *l)
 
337
{ save_configuration(); }
 
338
 
 
339
static void help (char **args, struct line *l)
 
340
{
 
341
        int i;
 
342
        GList *gl = commands;
 
343
        while(gl) {
 
344
                struct admin_command *cmd = (struct admin_command *)gl->data;
 
345
                admin_out(l, cmd->name);
 
346
                gl = gl->next;
 
347
        }
 
348
}
 
349
 
 
350
static void list_networks(char **args, struct line *l)
 
351
{
 
352
        char *nname;
 
353
        GList *g = networks;
 
354
        while(g) {
 
355
                struct network *n = (struct network *)g->data;
 
356
                nname = xmlGetProp(n->xmlConf, "name");
 
357
                admin_out(l, nname);
 
358
                xmlFree(nname);
 
359
                g = g->next;
 
360
        }
 
361
}
 
362
 
 
363
static void handle_die(char **args, struct line *l) 
 
364
{
 
365
        clean_exit();
 
366
        exit(0);
 
367
}
 
368
 
 
369
 
 
370
void register_admin_command(char *name, void (*handler) (char **args, struct line *l))
 
371
{
 
372
        struct admin_command *cmd = malloc(sizeof(struct admin_command));
 
373
        cmd->name = strdup(name);
 
374
        cmd->handler = handler;
 
375
        commands = g_list_append(commands, cmd);
 
376
}
 
377
 
 
378
void unregister_admin_command(char *name)
 
379
{
 
380
        GList *gl = commands;
 
381
        while(gl) {
 
382
                struct admin_command *cmd = (struct admin_command *)gl->data;
 
383
                if(!strcasecmp(cmd->name, name)) {
 
384
                        free(cmd->name);
 
385
                        commands = g_list_remove(gl, cmd);
 
386
                        free(cmd);
 
387
                        return;
 
388
                }
 
389
                gl = gl->next;
 
390
        }
 
391
}
 
392
 
 
393
struct admin_command builtin_commands[] = {
 
394
        { "ADDNETWORK", add_network },
 
395
        { "ADDSERVER", add_server },
 
396
        { "ADDLISTEN", add_listen },
 
397
        { "CONNECT", connect_network },
 
398
        { "DIE", handle_die },
 
399
        { "DISCONNECT", disconnect_network },
 
400
        { "LISTNETWORKS", list_networks },
 
401
        { "LOADMODULE", load_module },
 
402
        { "UNLOADMODULE", unload_module },
 
403
        { "RELOADMODULE", reload_module },
 
404
        { "LISTMODULES", list_modules },
 
405
        { "DUMPCONFIG", dump_config },
 
406
        { "SAVECONFIG", save_config },
 
407
        { "HELP", help },
 
408
        { NULL }
 
409
};
 
410
 
 
411
static gboolean handle_data(struct line *l) {
 
412
        char *tmp, **args = NULL, *p, *n;
 
413
        int cmdoffset = 0;
 
414
        int curarg = 0;
 
415
        int i;
 
416
        GList *gl;
 
417
        if(l->direction != TO_SERVER) return TRUE;
 
418
        if(strcasecmp(l->args[0], "CTRLPROXY") == 0)cmdoffset = 1;
 
419
        if(with_privmsg && strcasecmp(l->args[0], "PRIVMSG") == 0 && 
 
420
           strcasecmp(l->args[1], "CTRLPROXY") == 0) cmdoffset = 2;
 
421
 
 
422
        if(cmdoffset == 0) return TRUE;
 
423
 
 
424
        args = malloc(sizeof(char *) * 2);
 
425
        l->options |= LINE_DONT_SEND | LINE_IS_PRIVATE;
 
426
        tmp = strdup(l->args[cmdoffset]);
 
427
        args[0] = tmp;
 
428
        p = tmp;
 
429
 
 
430
        while((n = strchr(p, ' '))) {
 
431
                args = realloc(args, (curarg + 2) * sizeof(char *));
 
432
                args[++curarg] = n+1;
 
433
                *n = '\0'; p = n+1;
 
434
        }
 
435
        
 
436
        args[++curarg] = NULL;
 
437
        
 
438
        /* Ok, arguments are processed now. Execute the corresponding command */
 
439
        gl = commands;
 
440
        while(gl) {
 
441
                struct admin_command *cmd = (struct admin_command *)gl->data;
 
442
                if(!strcasecmp(cmd->name, args[0])) {
 
443
                        cmd->handler(args, l);
 
444
                        free(args);
 
445
                        free(tmp);
 
446
                        return TRUE;
 
447
                }
 
448
        }
 
449
 
 
450
        admin_out(l, "Can't find command '%s'", args[0]);
 
451
 
 
452
        free(args);
 
453
        free(tmp);
 
454
        
 
455
        return TRUE;
 
456
}
 
457
 
 
458
gboolean fini_plugin(struct plugin *p) {
 
459
        del_filter(handle_data);
 
460
        return TRUE;
 
461
}
 
462
 
 
463
gboolean init_plugin(struct plugin *p) {
 
464
        xmlNodePtr cur;
 
465
        int i;
 
466
 
 
467
        add_filter("admin", handle_data);
 
468
        cur = xmlFindChildByElementName(p->xmlConf, "with_privmsg");
 
469
        if(cur) with_privmsg = TRUE;
 
470
 
 
471
        for(i = 0; builtin_commands[i].name; i++) {
 
472
                register_admin_command(builtin_commands[i].name, builtin_commands[i].handler);
 
473
        }
 
474
        
 
475
        return TRUE;
 
476
}