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
RevLine 
[0431ea1]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
[74c119d]33
[f73b969]34static void ipc_master_cmd_client( irc_t *data, char **cmd )
[2face62]35{
36        struct bitlbee_child *child = (void*) data;
37       
[bd9b00f]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        }
[2face62]44       
45        ipc_to_children_str( "OPERMSG :Client connecting (PID=%d): %s@%s (%s)\r\n",
[bd9b00f]46                             child ? child->pid : -1, cmd[2], cmd[1], cmd[3] );
[2face62]47}
48
[f73b969]49static void ipc_master_cmd_die( irc_t *data, char **cmd )
[0431ea1]50{
[74c119d]51        if( global.conf->runmode == RUNMODE_FORKDAEMON )
52                ipc_to_children_str( "DIE\r\n" );
53       
[13caf0a]54        bitlbee_shutdown( NULL );
[0431ea1]55}
56
[f73b969]57void ipc_master_cmd_rehash( irc_t *data, char **cmd )
[0431ea1]58{
[f4a5940]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 );
[0431ea1]74}
75
76static const command_t ipc_master_commands[] = {
[2face62]77        { "client",     3, ipc_master_cmd_client,     0 },
[0431ea1]78        { "die",        0, ipc_master_cmd_die,        0 },
[f4a5940]79        { "wallops",    1, NULL,                      IPC_CMD_TO_CHILDREN },
80        { "lilo",       1, NULL,                      IPC_CMD_TO_CHILDREN },
[2face62]81        { "opermsg",    1, NULL,                      IPC_CMD_TO_CHILDREN },
[f4a5940]82        { "rehash",     0, ipc_master_cmd_rehash,     0 },
[48721c3]83        { "kill",       2, NULL,                      IPC_CMD_TO_CHILDREN },
[0431ea1]84        { NULL }
85};
86
[74c119d]87
[f73b969]88static void ipc_child_cmd_die( irc_t *irc, char **cmd )
[74c119d]89{
[f73b969]90        irc_abort( irc, 1, "Shutdown requested by operator" );
[74c119d]91}
92
[f73b969]93static void ipc_child_cmd_wallops( irc_t *irc, char **cmd )
[0431ea1]94{
[daa9e02]95        if( irc->status < USTATUS_LOGGED_IN )
[f73b969]96                return;
[daa9e02]97       
[0431ea1]98        if( strchr( irc->umode, 'w' ) )
[e0ca412]99                irc_write( irc, ":%s WALLOPS :%s", irc->myhost, cmd[1] );
100}
101
[f73b969]102static void ipc_child_cmd_lilo( irc_t *irc, char **cmd )
[e0ca412]103{
[daa9e02]104        if( irc->status < USTATUS_LOGGED_IN )
[f73b969]105                return;
[daa9e02]106       
[74c119d]107        if( strchr( irc->umode, 's' ) )
108                irc_write( irc, ":%s NOTICE %s :%s", irc->myhost, irc->nick, cmd[1] );
[0431ea1]109}
110
[f73b969]111static void ipc_child_cmd_opermsg( irc_t *irc, char **cmd )
[2face62]112{
113        if( irc->status < USTATUS_LOGGED_IN )
[f73b969]114                return;
[2face62]115       
116        if( strchr( irc->umode, 'o' ) )
117                irc_write( irc, ":%s NOTICE %s :*** OperMsg *** %s", irc->myhost, irc->nick, cmd[1] );
118}
119
[f73b969]120static void ipc_child_cmd_rehash( irc_t *irc, char **cmd )
[f4a5940]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
[f73b969]132static void ipc_child_cmd_kill( irc_t *irc, char **cmd )
[48721c3]133{
134        if( irc->status < USTATUS_LOGGED_IN )
[f73b969]135                return;
[48721c3]136       
137        if( nick_cmp( cmd[1], irc->nick ) != 0 )
[f73b969]138                return;         /* It's not for us. */
[48721c3]139       
140        irc_write( irc, ":%s!%s@%s KILL %s :%s", irc->mynick, irc->mynick, irc->myhost, irc->nick, cmd[2] );
[f73b969]141        irc_abort( irc, 0, "Killed by operator: %s", cmd[2] );
[48721c3]142}
143
[0431ea1]144static const command_t ipc_child_commands[] = {
[74c119d]145        { "die",        0, ipc_child_cmd_die,         0 },
146        { "wallops",    1, ipc_child_cmd_wallops,     0 },
147        { "lilo",       1, ipc_child_cmd_lilo,        0 },
[2face62]148        { "opermsg",    1, ipc_child_cmd_opermsg,     0 },
[48721c3]149        { "rehash",     0, ipc_child_cmd_rehash,      0 },
150        { "kill",       2, ipc_child_cmd_kill,        0 },
[0431ea1]151        { NULL }
152};
153
[74c119d]154
[0431ea1]155static void ipc_command_exec( void *data, char **cmd, const command_t *commands )
156{
[f1d38f2]157        int i, j;
[0431ea1]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                {
[f1d38f2]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                       
[f4a5940]171                        if( commands[i].flags & IPC_CMD_TO_CHILDREN )
172                                ipc_to_children( cmd );
173                        else
174                                commands[i].execute( data, cmd );
175                       
[f1d38f2]176                        break;
[0431ea1]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;
[1ea13be]195        else if( size < 0 ) /* && sockerr_again() */
196                return( g_strdup( "" ) );
[0431ea1]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                        {
[2face62]237                                ipc_master_free_one( c );
238                                child_list = g_slist_remove( child_list, c );
[0431ea1]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        {
[74c119d]268                char *s = irc_build_line( cmd );
[2face62]269                ipc_to_master_str( "%s", s );
[f4a5940]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
[2face62]278void ipc_to_master_str( char *format, ... )
[f4a5940]279{
[2face62]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 )
[f4a5940]292        {
293                write( global.listen_socket, msg_buf, strlen( msg_buf ) );
294        }
295        else if( global.conf->runmode == RUNMODE_DAEMON )
296        {
[bd9b00f]297                char **cmd, *s;
298               
299                if( ( s = strchr( msg_buf, '\r' ) ) )
300                        *s = 0;
[f4a5940]301               
[2face62]302                cmd = irc_parse_line( msg_buf );
[f4a5940]303                ipc_command_exec( NULL, cmd, ipc_master_commands );
304                g_free( cmd );
[74c119d]305        }
[2face62]306       
307        g_free( msg_buf );
[74c119d]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 );
[2face62]315                ipc_to_children_str( "%s", msg_buf );
[74c119d]316                g_free( msg_buf );
317        }
[f4a5940]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        }
[74c119d]325}
326
[2face62]327void ipc_to_children_str( char *format, ... )
[74c119d]328{
[2face62]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 )
[74c119d]341        {
342                int msg_len = strlen( msg_buf );
343                GSList *l;
[0431ea1]344               
[74c119d]345                for( l = child_list; l; l = l->next )
[0431ea1]346                {
[74c119d]347                        struct bitlbee_child *c = l->data;
348                        write( c->ipc_fd, msg_buf, msg_len );
[0431ea1]349                }
350        }
[f4a5940]351        else if( global.conf->runmode == RUNMODE_DAEMON )
352        {
[bd9b00f]353                char **cmd, *s;
354               
355                if( ( s = strchr( msg_buf, '\r' ) ) )
356                        *s = 0;
[f4a5940]357               
[2face62]358                cmd = irc_parse_line( msg_buf );
[f4a5940]359                ipc_to_children( cmd );
360                g_free( cmd );
361        }
[2face62]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;
[0431ea1]386}
Note: See TracBrowser for help on using the repository browser.