Try to show the user_split info for a protocol in "help purple $PROTOCOL".
[bitlbee.git] / bitlbee.c
blob0e1415e845157ab132bde04b2e8342e424d8c32a
1 /********************************************************************\
2 * BitlBee -- An IRC to other IM-networks gateway *
3 * *
4 * Copyright 2002-2004 Wilmer van der Gaast and others *
5 \********************************************************************/
7 /* Main file */
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.
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.
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
26 #define BITLBEE_CORE
27 #include "bitlbee.h"
28 #include "commands.h"
29 #include "protocols/nogaim.h"
30 #include "help.h"
31 #include "ipc.h"
32 #include <signal.h>
33 #include <stdio.h>
34 #include <errno.h>
36 static gboolean bitlbee_io_new_client( gpointer data, gint fd, b_input_condition condition );
38 static gboolean try_listen( struct addrinfo *res )
40 int i;
42 global.listen_socket = socket( res->ai_family, res->ai_socktype, res->ai_protocol );
43 if( global.listen_socket < 0 )
45 log_error( "socket" );
46 return FALSE;
49 #ifdef IPV6_V6ONLY
50 if( res->ai_family == AF_INET6 )
52 i = 0;
53 setsockopt( global.listen_socket, IPPROTO_IPV6, IPV6_V6ONLY,
54 (char *) &i, sizeof( i ) );
56 #endif
58 /* TIME_WAIT (?) sucks.. */
59 i = 1;
60 setsockopt( global.listen_socket, SOL_SOCKET, SO_REUSEADDR, &i, sizeof( i ) );
62 i = bind( global.listen_socket, res->ai_addr, res->ai_addrlen );
63 if( i == -1 )
65 closesocket( global.listen_socket );
66 global.listen_socket = -1;
68 log_error( "bind" );
69 return FALSE;
72 return TRUE;
75 int bitlbee_daemon_init()
77 struct addrinfo *res, hints, *addrinfo_bind;
78 int i;
79 FILE *fp;
81 log_link( LOGLVL_ERROR, LOGOUTPUT_CONSOLE );
82 log_link( LOGLVL_WARNING, LOGOUTPUT_CONSOLE );
84 memset( &hints, 0, sizeof( hints ) );
85 hints.ai_family = PF_UNSPEC;
86 hints.ai_socktype = SOCK_STREAM;
87 hints.ai_flags = AI_PASSIVE
88 #ifdef AI_ADDRCONFIG
89 /* Disabled as it may be doing more harm than good: this flag
90 ignores IPv6 addresses on lo (which seems reasonable), but
91 the result is that some clients (including irssi) try to
92 connect to ::1 and fail.
93 | AI_ADDRCONFIG */
94 #endif
97 i = getaddrinfo( global.conf->iface_in, global.conf->port, &hints, &addrinfo_bind );
98 if( i )
100 log_message( LOGLVL_ERROR, "Couldn't parse address `%s': %s",
101 global.conf->iface_in, gai_strerror(i) );
102 return -1;
105 global.listen_socket = -1;
107 /* Try IPv6 first (which will become an IPv6+IPv4 socket). */
108 for( res = addrinfo_bind; res; res = res->ai_next )
109 if( res->ai_family == AF_INET6 && try_listen( res ) )
110 break;
112 /* The rest (so IPv4, I guess). */
113 if( res == NULL )
114 for( res = addrinfo_bind; res; res = res->ai_next )
115 if( res->ai_family != AF_INET6 && try_listen( res ) )
116 break;
118 freeaddrinfo( addrinfo_bind );
120 i = listen( global.listen_socket, 10 );
121 if( i == -1 )
123 log_error( "listen" );
124 return( -1 );
127 global.listen_watch_source_id = b_input_add( global.listen_socket, B_EV_IO_READ, bitlbee_io_new_client, NULL );
129 #ifndef _WIN32
130 if( !global.conf->nofork )
132 i = fork();
133 if( i == -1 )
135 log_error( "fork" );
136 return( -1 );
138 else if( i != 0 )
139 exit( 0 );
141 setsid();
142 i = chdir( "/" );
143 /* Don't use i, just make gcc happy. :-/ */
145 if( getenv( "_BITLBEE_RESTART_STATE" ) == NULL )
146 for( i = 0; i < 3; i ++ )
147 if( close( i ) == 0 )
149 /* Keep something bogus on those fd's just in case. */
150 open( "/dev/null", O_WRONLY );
153 #endif
155 if( global.conf->runmode == RUNMODE_FORKDAEMON )
156 ipc_master_load_state( getenv( "_BITLBEE_RESTART_STATE" ) );
158 if( global.conf->runmode == RUNMODE_DAEMON || global.conf->runmode == RUNMODE_FORKDAEMON )
159 ipc_master_listen_socket();
161 #ifndef _WIN32
162 if( ( fp = fopen( global.conf->pidfile, "w" ) ) )
164 fprintf( fp, "%d\n", (int) getpid() );
165 fclose( fp );
167 else
169 log_message( LOGLVL_WARNING, "Warning: Couldn't write PID to `%s'", global.conf->pidfile );
171 #endif
173 if( !global.conf->nofork )
175 log_link( LOGLVL_ERROR, LOGOUTPUT_SYSLOG );
176 log_link( LOGLVL_WARNING, LOGOUTPUT_SYSLOG );
179 return( 0 );
182 int bitlbee_inetd_init()
184 if( !irc_new( 0 ) )
185 return( 1 );
187 return( 0 );
190 gboolean bitlbee_io_current_client_read( gpointer data, gint fd, b_input_condition cond )
192 irc_t *irc = data;
193 char line[513];
194 int st;
196 st = read( irc->fd, line, sizeof( line ) - 1 );
197 if( st == 0 )
199 irc_abort( irc, 1, "Connection reset by peer" );
200 return FALSE;
202 else if( st < 0 )
204 if( sockerr_again() )
206 return TRUE;
208 else
210 irc_abort( irc, 1, "Read error: %s", strerror( errno ) );
211 return FALSE;
215 line[st] = '\0';
216 if( irc->readbuffer == NULL )
218 irc->readbuffer = g_strdup( line );
220 else
222 irc->readbuffer = g_renew( char, irc->readbuffer, strlen( irc->readbuffer ) + strlen ( line ) + 1 );
223 strcpy( ( irc->readbuffer + strlen( irc->readbuffer ) ), line );
226 irc_process( irc );
228 /* Normally, irc_process() shouldn't call irc_free() but irc_abort(). Just in case: */
229 if( !g_slist_find( irc_connection_list, irc ) )
231 log_message( LOGLVL_WARNING, "Abnormal termination of connection with fd %d.", fd );
232 return FALSE;
235 /* Very naughty, go read the RFCs! >:) */
236 if( irc->readbuffer && ( strlen( irc->readbuffer ) > 1024 ) )
238 irc_abort( irc, 0, "Maximum line length exceeded" );
239 return FALSE;
242 return TRUE;
245 gboolean bitlbee_io_current_client_write( gpointer data, gint fd, b_input_condition cond )
247 irc_t *irc = data;
248 int st, size;
249 char *temp;
251 if( irc->sendbuffer == NULL )
252 return FALSE;
254 size = strlen( irc->sendbuffer );
255 st = write( irc->fd, irc->sendbuffer, size );
257 if( st == 0 || ( st < 0 && !sockerr_again() ) )
259 irc_abort( irc, 1, "Write error: %s", strerror( errno ) );
260 return FALSE;
262 else if( st < 0 ) /* && sockerr_again() */
264 return TRUE;
267 if( st == size )
269 if( irc->status & USTATUS_SHUTDOWN )
271 irc_free( irc );
273 else
275 g_free( irc->sendbuffer );
276 irc->sendbuffer = NULL;
277 irc->w_watch_source_id = 0;
280 return FALSE;
282 else
284 temp = g_strdup( irc->sendbuffer + st );
285 g_free( irc->sendbuffer );
286 irc->sendbuffer = temp;
288 return TRUE;
292 static gboolean bitlbee_io_new_client( gpointer data, gint fd, b_input_condition condition )
294 socklen_t size = sizeof( struct sockaddr_in );
295 struct sockaddr_in conn_info;
296 int new_socket = accept( global.listen_socket, (struct sockaddr *) &conn_info, &size );
298 if( new_socket == -1 )
300 log_message( LOGLVL_WARNING, "Could not accept new connection: %s", strerror( errno ) );
301 return TRUE;
304 #ifndef _WIN32
305 if( global.conf->runmode == RUNMODE_FORKDAEMON )
307 pid_t client_pid = 0;
308 int fds[2];
310 if( socketpair( AF_UNIX, SOCK_STREAM, 0, fds ) == -1 )
312 log_message( LOGLVL_WARNING, "Could not create IPC socket for client: %s", strerror( errno ) );
313 fds[0] = fds[1] = -1;
316 sock_make_nonblocking( fds[0] );
317 sock_make_nonblocking( fds[1] );
319 client_pid = fork();
321 if( client_pid > 0 && fds[0] != -1 )
323 struct bitlbee_child *child;
325 /* TODO: Stuff like this belongs in ipc.c. */
326 child = g_new0( struct bitlbee_child, 1 );
327 child->pid = client_pid;
328 child->ipc_fd = fds[0];
329 child->ipc_inpa = b_input_add( child->ipc_fd, B_EV_IO_READ, ipc_master_read, child );
330 child->to_fd = -1;
331 child_list = g_slist_append( child_list, child );
333 log_message( LOGLVL_INFO, "Creating new subprocess with pid %d.", (int) client_pid );
335 /* Close some things we don't need in the parent process. */
336 close( new_socket );
337 close( fds[1] );
339 else if( client_pid == 0 )
341 irc_t *irc;
343 /* Since we're fork()ing here, let's make sure we won't
344 get the same random numbers as the parent/siblings. */
345 srand( time( NULL ) ^ getpid() );
347 b_main_init();
349 /* Close the listening socket, we're a client. */
350 close( global.listen_socket );
351 b_event_remove( global.listen_watch_source_id );
353 /* Make the connection. */
354 irc = irc_new( new_socket );
356 /* We can store the IPC fd there now. */
357 global.listen_socket = fds[1];
358 global.listen_watch_source_id = b_input_add( fds[1], B_EV_IO_READ, ipc_child_read, irc );
360 close( fds[0] );
362 ipc_master_free_all();
365 else
366 #endif
368 log_message( LOGLVL_INFO, "Creating new connection with fd %d.", new_socket );
369 irc_new( new_socket );
372 return TRUE;
375 gboolean bitlbee_shutdown( gpointer data, gint fd, b_input_condition cond )
377 /* Try to save data for all active connections (if desired). */
378 while( irc_connection_list != NULL )
379 irc_abort( irc_connection_list->data, TRUE,
380 "BitlBee server shutting down" );
382 /* We'll only reach this point when not running in inetd mode: */
383 b_main_quit();
385 return FALSE;