source: ipc.c @ f1d38f2

Last change on this file since f1d38f2 was f1d38f2, checked in by Wilmer van der Gaast <wilmer@…>, at 2006-01-21T22:23:58Z

Fixed counting of arguments in i[rp]c_exec(), made them a bit too simple.

  • Property mode set to 100644
File size: 9.0 KB
Line 
1  /********************************************************************\
2  * BitlBee -- An IRC to other IM-networks gateway                     *
3  *                                                                    *
4  * Copyright 2002-2004 Wilmer van der Gaast and others                *
5  \********************************************************************/
6
7/* IPC - communication between BitlBee processes                        */
8
9/*
10  This program is free software; you can redistribute it and/or modify
11  it under the terms of the GNU General Public License as published by
12  the Free Software Foundation; either version 2 of the License, or
13  (at your option) any later version.
14
15  This program is distributed in the hope that it will be useful,
16  but WITHOUT ANY WARRANTY; without even the implied warranty of
17  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  GNU General Public License for more details.
19
20  You should have received a copy of the GNU General Public License with
21  the Debian GNU/Linux distribution in /usr/share/common-licenses/GPL;
22  if not, write to the Free Software Foundation, Inc., 59 Temple Place,
23  Suite 330, Boston, MA  02111-1307  USA
24*/
25
26#define BITLBEE_CORE
27#include "bitlbee.h"
28#include "ipc.h"
29#include "commands.h"
30
31GSList *child_list = NULL;
32
33
34static void ipc_master_cmd_client( irc_t *data, char **cmd )
35{
36        struct bitlbee_child *child = (void*) data;
37       
38        if( child )
39        {
40                child->host = g_strdup( cmd[1] );
41                child->nick = g_strdup( cmd[2] );
42                child->realname = g_strdup( cmd[3] );
43        }
44       
45        ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n",
46                             child ? child->pid : -1, cmd[2], cmd[1], cmd[3] );
47}
48
49static void ipc_master_cmd_die( irc_t *data, char **cmd )
50{
51        if( global.conf->runmode == RUNMODE_FORKDAEMON )
52                ipc_to_children_str( "DIE\r\n" );
53       
54        bitlbee_shutdown( NULL );
55}
56
57void ipc_master_cmd_rehash( irc_t *data, char **cmd )
58{
59        runmode_t oldmode;
60       
61        oldmode = global.conf->runmode;
62       
63        g_free( global.conf );
64        global.conf = conf_load( 0, NULL );
65       
66        if( global.conf->runmode != oldmode )
67        {
68                log_message( LOGLVL_WARNING, "Can't change RunMode setting at runtime, restoring original setting" );
69                global.conf->runmode = oldmode;
70        }
71       
72        if( global.conf->runmode == RUNMODE_FORKDAEMON )
73                ipc_to_children( cmd );
74}
75
76static const command_t ipc_master_commands[] = {
77        { "client",     3, ipc_master_cmd_client,     0 },
78        { "die",        0, ipc_master_cmd_die,        0 },
79        { "wallops",    1, NULL,                      IPC_CMD_TO_CHILDREN },
80        { "lilo",       1, NULL,                      IPC_CMD_TO_CHILDREN },
81        { "opermsg",    1, NULL,                      IPC_CMD_TO_CHILDREN },
82        { "rehash",     0, ipc_master_cmd_rehash,     0 },
83        { "kill",       2, NULL,                      IPC_CMD_TO_CHILDREN },
84        { NULL }
85};
86
87
88static void ipc_child_cmd_die( irc_t *irc, char **cmd )
89{
90        irc_abort( irc, 1, "Shutdown requested by operator" );
91}
92
93static void ipc_child_cmd_wallops( irc_t *irc, char **cmd )
94{
95        if( irc->status < USTATUS_LOGGED_IN )
96                return;
97       
98        if( strchr( irc->umode, 'w' ) )
99                irc_write( irc, ":%s WALLOPS :%s", irc->myhost, cmd[1] );
100}
101
102static void ipc_child_cmd_lilo( irc_t *irc, char **cmd )
103{
104        if( irc->status < USTATUS_LOGGED_IN )
105                return;
106       
107        if( strchr( irc->umode, 's' ) )
108                irc_write( irc, ":%s NOTICE %s :%s", irc->myhost, irc->nick, cmd[1] );
109}
110
111static void ipc_child_cmd_opermsg( irc_t *irc, char **cmd )
112{
113        if( irc->status < USTATUS_LOGGED_IN )
114                return;
115       
116        if( strchr( irc->umode, 'o' ) )
117                irc_write( irc, ":%s NOTICE %s :*** OperMsg *** %s", irc->myhost, irc->nick, cmd[1] );
118}
119
120static void ipc_child_cmd_rehash( irc_t *irc, char **cmd )
121{
122        runmode_t oldmode;
123       
124        oldmode = global.conf->runmode;
125       
126        g_free( global.conf );
127        global.conf = conf_load( 0, NULL );
128       
129        global.conf->runmode = oldmode;
130}
131
132static void ipc_child_cmd_kill( irc_t *irc, char **cmd )
133{
134        if( irc->status < USTATUS_LOGGED_IN )
135                return;
136       
137        if( nick_cmp( cmd[1], irc->nick ) != 0 )
138                return;         /* It's not for us. */
139       
140        irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->mynick, irc->mynick, irc->myhost, irc->nick, cmd[2] );
141        irc_abort( irc, 0, "Killed by operator: %s", cmd[2] );
142}
143
144static const command_t ipc_child_commands[] = {
145        { "die",        0, ipc_child_cmd_die,         0 },
146        { "wallops",    1, ipc_child_cmd_wallops,     0 },
147        { "lilo",       1, ipc_child_cmd_lilo,        0 },
148        { "opermsg",    1, ipc_child_cmd_opermsg,     0 },
149        { "rehash",     0, ipc_child_cmd_rehash,      0 },
150        { "kill",       2, ipc_child_cmd_kill,        0 },
151        { NULL }
152};
153
154
155static void ipc_command_exec( void *data, char **cmd, const command_t *commands )
156{
157        int i, j;
158       
159        if( !cmd[0] )
160                return;
161       
162        for( i = 0; commands[i].command; i ++ )
163                if( g_strcasecmp( commands[i].command, cmd[0] ) == 0 )
164                {
165                        /* There is no typo in this line: */
166                        for( j = 1; cmd[j]; j ++ ); j --;
167                       
168                        if( j < commands[i].required_parameters )
169                                break;
170                       
171                        if( commands[i].flags & IPC_CMD_TO_CHILDREN )
172                                ipc_to_children( cmd );
173                        else
174                                commands[i].execute( data, cmd );
175                       
176                        break;
177                }
178}
179
180static char *ipc_readline( int fd )
181{
182        char *buf, *eol;
183        int size;
184       
185        buf = g_new0( char, 513 );
186       
187        /* Because this is internal communication, it should be pretty safe
188           to just peek at the message, find its length (by searching for the
189           end-of-line) and then just read that message. With internal
190           sockets and limites message length, messages should always be
191           complete. Saves us quite a lot of code and buffering. */
192        size = recv( fd, buf, 512, MSG_PEEK );
193        if( size == 0 || ( size < 0 && !sockerr_again() ) )
194                return NULL;
195        else if( size < 0 ) /* && sockerr_again() */
196                return( g_strdup( "" ) );
197        else
198                buf[size] = 0;
199       
200        eol = strstr( buf, "\r\n" );
201        if( eol == NULL )
202                return NULL;
203        else
204                size = eol - buf + 2;
205       
206        g_free( buf );
207        buf = g_new0( char, size + 1 );
208       
209        if( recv( fd, buf, size, 0 ) != size )
210                return NULL;
211        else
212                buf[size-2] = 0;
213       
214        return buf;
215}
216
217void ipc_master_read( gpointer data, gint source, GaimInputCondition cond )
218{
219        char *buf, **cmd;
220       
221        if( ( buf = ipc_readline( source ) ) )
222        {
223                cmd = irc_parse_line( buf );
224                if( cmd )
225                        ipc_command_exec( data, cmd, ipc_master_commands );
226        }
227        else
228        {
229                GSList *l;
230                struct bitlbee_child *c;
231               
232                for( l = child_list; l; l = l->next )
233                {
234                        c = l->data;
235                        if( c->ipc_fd == source )
236                        {
237                                ipc_master_free_one( c );
238                                child_list = g_slist_remove( child_list, c );
239                                break;
240                        }
241                }
242        }
243}
244
245void ipc_child_read( gpointer data, gint source, GaimInputCondition cond )
246{
247        char *buf, **cmd;
248       
249        if( ( buf = ipc_readline( source ) ) )
250        {
251                cmd = irc_parse_line( buf );
252                if( cmd )
253                        ipc_command_exec( data, cmd, ipc_child_commands );
254        }
255        else
256        {
257                gaim_input_remove( global.listen_watch_source_id );
258                close( global.listen_socket );
259               
260                global.listen_socket = -1;
261        }
262}
263
264void ipc_to_master( char **cmd )
265{
266        if( global.conf->runmode == RUNMODE_FORKDAEMON )
267        {
268                char *s = irc_build_line( cmd );
269                ipc_to_master_str( "%s", s );
270                g_free( s );
271        }
272        else if( global.conf->runmode == RUNMODE_DAEMON )
273        {
274                ipc_command_exec( NULL, cmd, ipc_master_commands );
275        }
276}
277
278void ipc_to_master_str( char *format, ... )
279{
280        char *msg_buf;
281        va_list params;
282
283        va_start( params, format );
284        msg_buf = g_strdup_vprintf( format, params );
285        va_end( params );
286       
287        if( strlen( msg_buf ) > 512 )
288        {
289                /* Don't send it, it's too long... */
290        }
291        else if( global.conf->runmode == RUNMODE_FORKDAEMON )
292        {
293                write( global.listen_socket, msg_buf, strlen( msg_buf ) );
294        }
295        else if( global.conf->runmode == RUNMODE_DAEMON )
296        {
297                char **cmd, *s;
298               
299                if( ( s = strchr( msg_buf, '\r' ) ) )
300                        *s = 0;
301               
302                cmd = irc_parse_line( msg_buf );
303                ipc_command_exec( NULL, cmd, ipc_master_commands );
304                g_free( cmd );
305        }
306       
307        g_free( msg_buf );
308}
309
310void ipc_to_children( char **cmd )
311{
312        if( global.conf->runmode == RUNMODE_FORKDAEMON )
313        {
314                char *msg_buf = irc_build_line( cmd );
315                ipc_to_children_str( "%s", msg_buf );
316                g_free( msg_buf );
317        }
318        else if( global.conf->runmode == RUNMODE_DAEMON )
319        {
320                GSList *l;
321               
322                for( l = irc_connection_list; l; l = l->next )
323                        ipc_command_exec( l->data, cmd, ipc_child_commands );
324        }
325}
326
327void ipc_to_children_str( char *format, ... )
328{
329        char *msg_buf;
330        va_list params;
331
332        va_start( params, format );
333        msg_buf = g_strdup_vprintf( format, params );
334        va_end( params );
335       
336        if( strlen( msg_buf ) > 512 )
337        {
338                /* Don't send it, it's too long... */
339        }
340        else if( global.conf->runmode == RUNMODE_FORKDAEMON )
341        {
342                int msg_len = strlen( msg_buf );
343                GSList *l;
344               
345                for( l = child_list; l; l = l->next )
346                {
347                        struct bitlbee_child *c = l->data;
348                        write( c->ipc_fd, msg_buf, msg_len );
349                }
350        }
351        else if( global.conf->runmode == RUNMODE_DAEMON )
352        {
353                char **cmd, *s;
354               
355                if( ( s = strchr( msg_buf, '\r' ) ) )
356                        *s = 0;
357               
358                cmd = irc_parse_line( msg_buf );
359                ipc_to_children( cmd );
360                g_free( cmd );
361        }
362       
363        g_free( msg_buf );
364}
365
366void ipc_master_free_one( struct bitlbee_child *c )
367{
368        gaim_input_remove( c->ipc_inpa );
369        closesocket( c->ipc_fd );
370       
371        g_free( c->host );
372        g_free( c->nick );
373        g_free( c->realname );
374        g_free( c );
375}
376
377void ipc_master_free_all()
378{
379        GSList *l;
380       
381        for( l = child_list; l; l = l->next )
382                ipc_master_free_one( l->data );
383       
384        g_slist_free( child_list );
385        child_list = NULL;
386}
Note: See TracBrowser for help on using the repository browser.