source: ipc.c @ f73b969

Last change on this file since f73b969 was f73b969, checked in by Wilmer van der Gaast <wilmer@…>, at 2006-01-20T15:15:49Z

Renamed commands.c, got rid of return values in all command functions.

  • Property mode set to 100644
File size: 8.9 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;
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                        if( commands[i].flags & IPC_CMD_TO_CHILDREN )
166                                ipc_to_children( cmd );
167                        else
168                                commands[i].execute( data, cmd );
169                       
170                        return;
171                }
172}
173
174static char *ipc_readline( int fd )
175{
176        char *buf, *eol;
177        int size;
178       
179        buf = g_new0( char, 513 );
180       
181        /* Because this is internal communication, it should be pretty safe
182           to just peek at the message, find its length (by searching for the
183           end-of-line) and then just read that message. With internal
184           sockets and limites message length, messages should always be
185           complete. Saves us quite a lot of code and buffering. */
186        size = recv( fd, buf, 512, MSG_PEEK );
187        if( size == 0 || ( size < 0 && !sockerr_again() ) )
188                return NULL;
189        else if( size < 0 ) /* && sockerr_again() */
190                return( g_strdup( "" ) );
191        else
192                buf[size] = 0;
193       
194        eol = strstr( buf, "\r\n" );
195        if( eol == NULL )
196                return NULL;
197        else
198                size = eol - buf + 2;
199       
200        g_free( buf );
201        buf = g_new0( char, size + 1 );
202       
203        if( recv( fd, buf, size, 0 ) != size )
204                return NULL;
205        else
206                buf[size-2] = 0;
207       
208        return buf;
209}
210
211void ipc_master_read( gpointer data, gint source, GaimInputCondition cond )
212{
213        char *buf, **cmd;
214       
215        if( ( buf = ipc_readline( source ) ) )
216        {
217                cmd = irc_parse_line( buf );
218                if( cmd )
219                        ipc_command_exec( data, cmd, ipc_master_commands );
220        }
221        else
222        {
223                GSList *l;
224                struct bitlbee_child *c;
225               
226                for( l = child_list; l; l = l->next )
227                {
228                        c = l->data;
229                        if( c->ipc_fd == source )
230                        {
231                                ipc_master_free_one( c );
232                                child_list = g_slist_remove( child_list, c );
233                                break;
234                        }
235                }
236        }
237}
238
239void ipc_child_read( gpointer data, gint source, GaimInputCondition cond )
240{
241        char *buf, **cmd;
242       
243        if( ( buf = ipc_readline( source ) ) )
244        {
245                cmd = irc_parse_line( buf );
246                if( cmd )
247                        ipc_command_exec( data, cmd, ipc_child_commands );
248        }
249        else
250        {
251                gaim_input_remove( global.listen_watch_source_id );
252                close( global.listen_socket );
253               
254                global.listen_socket = -1;
255        }
256}
257
258void ipc_to_master( char **cmd )
259{
260        if( global.conf->runmode == RUNMODE_FORKDAEMON )
261        {
262                char *s = irc_build_line( cmd );
263                ipc_to_master_str( "%s", s );
264                g_free( s );
265        }
266        else if( global.conf->runmode == RUNMODE_DAEMON )
267        {
268                ipc_command_exec( NULL, cmd, ipc_master_commands );
269        }
270}
271
272void ipc_to_master_str( char *format, ... )
273{
274        char *msg_buf;
275        va_list params;
276
277        va_start( params, format );
278        msg_buf = g_strdup_vprintf( format, params );
279        va_end( params );
280       
281        if( strlen( msg_buf ) > 512 )
282        {
283                /* Don't send it, it's too long... */
284        }
285        else if( global.conf->runmode == RUNMODE_FORKDAEMON )
286        {
287                write( global.listen_socket, msg_buf, strlen( msg_buf ) );
288        }
289        else if( global.conf->runmode == RUNMODE_DAEMON )
290        {
291                char **cmd, *s;
292               
293                if( ( s = strchr( msg_buf, '\r' ) ) )
294                        *s = 0;
295               
296                cmd = irc_parse_line( msg_buf );
297                ipc_command_exec( NULL, cmd, ipc_master_commands );
298                g_free( cmd );
299        }
300       
301        g_free( msg_buf );
302}
303
304void ipc_to_children( char **cmd )
305{
306        if( global.conf->runmode == RUNMODE_FORKDAEMON )
307        {
308                char *msg_buf = irc_build_line( cmd );
309                ipc_to_children_str( "%s", msg_buf );
310                g_free( msg_buf );
311        }
312        else if( global.conf->runmode == RUNMODE_DAEMON )
313        {
314                GSList *l;
315               
316                for( l = irc_connection_list; l; l = l->next )
317                        ipc_command_exec( l->data, cmd, ipc_child_commands );
318        }
319}
320
321void ipc_to_children_str( char *format, ... )
322{
323        char *msg_buf;
324        va_list params;
325
326        va_start( params, format );
327        msg_buf = g_strdup_vprintf( format, params );
328        va_end( params );
329       
330        if( strlen( msg_buf ) > 512 )
331        {
332                /* Don't send it, it's too long... */
333        }
334        else if( global.conf->runmode == RUNMODE_FORKDAEMON )
335        {
336                int msg_len = strlen( msg_buf );
337                GSList *l;
338               
339                for( l = child_list; l; l = l->next )
340                {
341                        struct bitlbee_child *c = l->data;
342                        write( c->ipc_fd, msg_buf, msg_len );
343                }
344        }
345        else if( global.conf->runmode == RUNMODE_DAEMON )
346        {
347                char **cmd, *s;
348               
349                if( ( s = strchr( msg_buf, '\r' ) ) )
350                        *s = 0;
351               
352                cmd = irc_parse_line( msg_buf );
353                ipc_to_children( cmd );
354                g_free( cmd );
355        }
356       
357        g_free( msg_buf );
358}
359
360void ipc_master_free_one( struct bitlbee_child *c )
361{
362        gaim_input_remove( c->ipc_inpa );
363        closesocket( c->ipc_fd );
364       
365        g_free( c->host );
366        g_free( c->nick );
367        g_free( c->realname );
368        g_free( c );
369}
370
371void ipc_master_free_all()
372{
373        GSList *l;
374       
375        for( l = child_list; l; l = l->next )
376                ipc_master_free_one( l->data );
377       
378        g_slist_free( child_list );
379        child_list = NULL;
380}
Note: See TracBrowser for help on using the repository browser.