diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/common/command.c | 47 | ||||
-rw-r--r-- | src/gui/curses/gui-input.c | 23 | ||||
-rw-r--r-- | src/irc/irc-recv.c | 2 | ||||
-rw-r--r-- | src/irc/irc-server.c | 339 | ||||
-rw-r--r-- | src/irc/irc.h | 11 |
5 files changed, 281 insertions, 141 deletions
diff --git a/src/common/command.c b/src/common/command.c index 48e3f85f0..74d4af84c 100644 --- a/src/common/command.c +++ b/src/common/command.c @@ -58,13 +58,13 @@ t_weechat_command weechat_commands[] = N_("-all: clear all windows"), 0, 1, weechat_cmd_clear, NULL }, { "connect", N_("connect to a server"), - N_("servername"), + N_("[servername]"), N_("servername: server name to connect"), - 1, 1, weechat_cmd_connect, NULL }, + 0, 1, weechat_cmd_connect, NULL }, { "disconnect", N_("disconnect from a server"), - N_("servername"), + N_("[servername]"), N_("servername: server name to disconnect"), - 1, 1, weechat_cmd_disconnect, NULL }, + 0, 1, weechat_cmd_disconnect, NULL }, { "help", N_("display help about commands"), N_("[command]"), N_("command: name of a WeeChat or IRC command"), 0, 1, weechat_cmd_help, NULL }, @@ -506,8 +506,8 @@ exec_weechat_command (t_irc_server *server, char *string) { irc_display_prefix (NULL, PREFIX_ERROR); gui_printf (NULL, - _("%s %s command \"%s\" failed\n"), - WEECHAT_ERROR, PACKAGE_NAME, command + 1); + _("%s command \"%s\" failed\n"), + WEECHAT_ERROR, command + 1); } } if (argv) @@ -576,7 +576,7 @@ exec_weechat_command (t_irc_server *server, char *string) { irc_display_prefix (NULL, PREFIX_ERROR); gui_printf (NULL, - _("%s IRC command \"%s\" failed\n"), + _("%s command \"%s\" failed\n"), WEECHAT_ERROR, command + 1); } } @@ -1060,7 +1060,10 @@ weechat_cmd_connect (int argc, char **argv) /* make gcc happy */ (void) argc; - ptr_server = server_search (argv[0]); + if (argc == 1) + ptr_server = server_search (argv[0]); + else + ptr_server = SERVER(gui_current_window->buffer); if (ptr_server) { if (ptr_server->is_connected) @@ -1071,6 +1074,14 @@ weechat_cmd_connect (int argc, char **argv) WEECHAT_ERROR, argv[0]); return -1; } + if (ptr_server->child_pid > 0) + { + irc_display_prefix (NULL, PREFIX_ERROR); + gui_printf (NULL, + _("%s currently connecting to server \"%s\"!\n"), + WEECHAT_ERROR, argv[0]); + return -1; + } if (!ptr_server->buffer) { if (!gui_buffer_new (gui_current_window, ptr_server, NULL, 0, 1)) @@ -1080,15 +1091,12 @@ weechat_cmd_connect (int argc, char **argv) { ptr_server->reconnect_start = 0; ptr_server->reconnect_join = (ptr_server->channels) ? 1 : 0; - irc_login (ptr_server); } } else { irc_display_prefix (NULL, PREFIX_ERROR); - gui_printf (NULL, - _("%s server \"%s\" not found\n"), - WEECHAT_ERROR, argv[0]); + gui_printf (NULL, _("%s server not found\n"), WEECHAT_ERROR); return -1; } return 0; @@ -1106,10 +1114,14 @@ weechat_cmd_disconnect (int argc, char **argv) /* make gcc happy */ (void) argc; - ptr_server = server_search (argv[0]); + if (argc == 1) + ptr_server = server_search (argv[0]); + else + ptr_server = SERVER(gui_current_window->buffer); if (ptr_server) { - if ((!ptr_server->is_connected) && (ptr_server->reconnect_start == 0)) + if ((!ptr_server->is_connected) && (ptr_server->child_pid == 0) + && (ptr_server->reconnect_start == 0)) { irc_display_prefix (ptr_server->buffer, PREFIX_ERROR); gui_printf (ptr_server->buffer, @@ -1129,9 +1141,7 @@ weechat_cmd_disconnect (int argc, char **argv) else { irc_display_prefix (NULL, PREFIX_ERROR); - gui_printf (NULL, - _("%s server \"%s\" not found\n"), - WEECHAT_ERROR, argv[0]); + gui_printf (NULL, _("%s server not found\n"), WEECHAT_ERROR); return -1; } return 0; @@ -1645,8 +1655,7 @@ weechat_cmd_server (int argc, char **argv) if (new_server->autoconnect) { (void) gui_buffer_new (gui_current_window, new_server, NULL, 0, 1); - if (server_connect (new_server)) - irc_login (new_server); + server_connect (new_server); } server_destroy (&server); diff --git a/src/gui/curses/gui-input.c b/src/gui/curses/gui-input.c index 1ca34b5b6..472103e90 100644 --- a/src/gui/curses/gui-input.c +++ b/src/gui/curses/gui-input.c @@ -768,8 +768,13 @@ gui_main_loop () } } - if (ptr_server->sock4 >= 0) - FD_SET (ptr_server->sock4, &read_fd); + if (!ptr_server->is_connected && (ptr_server->child_pid > 0)) + FD_SET (ptr_server->child_read, &read_fd); + else + { + if (ptr_server->sock4 >= 0) + FD_SET (ptr_server->sock4, &read_fd); + } } } if (select (FD_SETSIZE, &read_fd, NULL, NULL, &timeout) > 0) @@ -783,9 +788,17 @@ gui_main_loop () for (ptr_server = irc_servers; ptr_server; ptr_server = ptr_server->next_server) { - if ((ptr_server->sock4 >= 0) && - (FD_ISSET (ptr_server->sock4, &read_fd))) - server_recv (ptr_server); + if (!ptr_server->is_connected && (ptr_server->child_pid > 0)) + { + if (FD_ISSET (ptr_server->child_read, &read_fd)) + server_child_read (ptr_server); + } + else + { + if ((ptr_server->sock4 >= 0) && + (FD_ISSET (ptr_server->sock4, &read_fd))) + server_recv (ptr_server); + } } } } diff --git a/src/irc/irc-recv.c b/src/irc/irc-recv.c index 8e83dee93..1195d7c71 100644 --- a/src/irc/irc-recv.c +++ b/src/irc/irc-recv.c @@ -1600,7 +1600,7 @@ irc_cmd_recv_004 (t_irc_server *server, char *host, char *arguments) } /* auto-join after disconnection (only rejoins opened channels) */ - if (server->reconnect_join) + if (server->reconnect_join && server->channels) { for (ptr_channel = server->channels; ptr_channel; ptr_channel = ptr_channel->next_channel) diff --git a/src/irc/irc-server.c b/src/irc/irc-server.c index 2edf085d2..3bb93686d 100644 --- a/src/irc/irc-server.c +++ b/src/irc/irc-server.c @@ -27,12 +27,14 @@ #include <stdlib.h> #include <unistd.h> #include <errno.h> +#include <signal.h> #include <stdio.h> #include <stdarg.h> #include <string.h> #include <pwd.h> -#include <sys/types.h> #include <sys/socket.h> +#include <sys/types.h> +#include <sys/wait.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> @@ -57,6 +59,7 @@ int check_away = 0; void server_init (t_irc_server *server) { + /* user choices */ server->name = NULL; server->autoconnect = 0; server->autoreconnect = 1; @@ -73,14 +76,18 @@ server_init (t_irc_server *server) server->command = NULL; server->command_delay = 1; server->autojoin = NULL; + server->autorejoin = 0; + + /* internal vars */ + server->child_pid = 0; + server->child_read = -1; + server->child_write = -1; + server->sock4 = -1; + server->is_connected = 0; server->unterminated_message = NULL; server->nick = NULL; - server->is_connected = 0; server->reconnect_start = 0; server->reconnect_join = 0; - server->sock4 = -1; - server->server_read = -1; - server->server_write = -1; server->is_away = 0; server->away_time = 0; server->lag = 0; @@ -643,18 +650,182 @@ server_recv (t_irc_server *server) } /* - * server_connect: connect to an IRC server + * server_kill_child: kill child process and close pipe + */ + +void +server_kill_child (t_irc_server *server) +{ + /* kill process */ + if (server->child_pid > 0) + { + kill (server->child_pid, SIGKILL); + waitpid (server->child_pid, NULL, 0); + server->child_pid = 0; + } + + /* close pipe used with child */ + if (server->child_read != -1) + { + close (server->child_read); + server->child_read = -1; + } + if (server->child_write != -1) + { + close (server->child_write); + server->child_write = -1; + } +} + +/* + * server_close_connection: close server connection (kill child, close socket/pipes) + */ + +void +server_close_connection (t_irc_server *server) +{ + server_kill_child (server); + + /* close network socket */ + if (server->sock4 != -1) + { + close (server->sock4); + server->sock4 = -1; + } + + /* free any pending message */ + if (server->unterminated_message) + { + free (server->unterminated_message); + server->unterminated_message = NULL; + } + + /* server is now disconnected */ + server->is_connected = 0; +} + +/* + * server_reconnect_schedule: schedule reconnect for a server + */ + +void +server_reconnect_schedule (t_irc_server *server) +{ + if (server->autoreconnect) + { + server->reconnect_start = time (NULL); + irc_display_prefix (server->buffer, PREFIX_INFO); + gui_printf (server->buffer, _("%s: Reconnecting to server in %d seconds\n"), + PACKAGE_NAME, server->autoreconnect_delay); + } + else + server->reconnect_start = 0; +} + +/* + * server_child_read: read connection progress from child process + */ + +void +server_child_read (t_irc_server *server) +{ + char buffer[1]; + int num_read; + + num_read = read (server->child_read, buffer, sizeof (buffer)); + if (num_read != -1) + { + switch (buffer[0]) + { + /* connection OK */ + case '0': + server_kill_child (server); + irc_login (server); + break; + /* adress not found */ + case '1': + irc_display_prefix (server->buffer, PREFIX_ERROR); + gui_printf (server->buffer, + _("%s address \"%s\" not found\n"), + WEECHAT_ERROR, server->address); + server_close_connection (server); + server_reconnect_schedule (server); + break; + /* IP address not found */ + case '2': + irc_display_prefix (server->buffer, PREFIX_ERROR); + gui_printf (server->buffer, + _("%s IP address not found\n"), WEECHAT_ERROR); + server_close_connection (server); + server_reconnect_schedule (server); + break; + /* connection refused */ + case '3': + irc_display_prefix (server->buffer, PREFIX_ERROR); + gui_printf (server->buffer, + _("%s connection refused\n"), WEECHAT_ERROR); + server_close_connection (server); + server_reconnect_schedule (server); + break; + } + } +} + +/* + * server_child: child process trying to connect to server */ int -server_connect (t_irc_server *server) +server_child (t_irc_server *server) { - int set; struct hostent *ip4_hostent; struct sockaddr_in addr; char *ip_address; int error; - int server_pipe[2]; + + /* bind to hostname */ + ip4_hostent = gethostbyname (server->address); + if (!ip4_hostent) + { + write (server->child_write, "1", 1); + return 0; + } + memset (&addr, 0, sizeof (addr)); + memcpy (&addr.sin_addr, ip4_hostent->h_addr, ip4_hostent->h_length); + addr.sin_port = htons (server->port); + addr.sin_family = AF_INET; + + /* find IP address */ + ip_address = inet_ntoa (addr.sin_addr); + if (!ip_address) + { + write (server->child_write, "2", 1); + return 0; + } + + /* connect to server */ + error = connect (server->sock4, (struct sockaddr *) &addr, sizeof (addr)); + if (error != 0) + { + write (server->child_write, "3", 1); + return 0; + } + + /* connection OK */ + write (server->child_write, "0", 1); + + return 0; +} + +/* + * server_connect: connect to an IRC server + */ + +int +server_connect (t_irc_server *server) +{ + int child_pipe[2], set; + pid_t pid; irc_display_prefix (server->buffer, PREFIX_INFO); gui_printf (server->buffer, @@ -662,100 +833,70 @@ server_connect (t_irc_server *server) PACKAGE_NAME, server->address, server->port); wee_log_printf (_("connecting to server %s:%d...\n"), server->address, server->port); - server->is_connected = 0; - - /* create pipe */ - if (pipe (server_pipe) < 0) + + /* close any opened connection and kill child process if running */ + server_close_connection (server); + + /* create pipe for child process */ + if (pipe (child_pipe) < 0) { irc_display_prefix (server->buffer, PREFIX_ERROR); gui_printf (server->buffer, _("%s cannot create pipe\n"), WEECHAT_ERROR); - server_free (server); return 0; } - server->server_read = server_pipe[0]; - server->server_write = server_pipe[1]; - + server->child_read = child_pipe[0]; + server->child_write = child_pipe[1]; + /* create socket and set options */ server->sock4 = socket (AF_INET, SOCK_STREAM, 0); - set = 1; - if (setsockopt - (server->sock4, SOL_SOCKET, SO_REUSEADDR, (char *) &set, - sizeof (set)) == -1) + if (server->sock4 == -1) { irc_display_prefix (server->buffer, PREFIX_ERROR); gui_printf (server->buffer, - _("%s cannot set socket option \"SO_REUSEADDR\"\n"), - WEECHAT_ERROR); + _("%s cannot create socket\n"), WEECHAT_ERROR); + server_close_connection (server); + return 0; } + + /* set SO_REUSEADDR option for socket */ set = 1; - if (setsockopt - (server->sock4, SOL_SOCKET, SO_KEEPALIVE, (char *) &set, - sizeof (set)) == -1) - { - irc_display_prefix (server->buffer, PREFIX_ERROR); - gui_printf (server->buffer, - _("%s cannot set socket option \"SO_KEEPALIVE\"\n"), - WEECHAT_ERROR); - } - - /* bind to hostname */ - ip4_hostent = gethostbyname (server->address); - if (!ip4_hostent) + if (setsockopt (server->sock4, SOL_SOCKET, SO_REUSEADDR, + (void *) &set, sizeof (set)) == -1) { irc_display_prefix (server->buffer, PREFIX_ERROR); gui_printf (server->buffer, - _("%s address \"%s\" not found\n"), - WEECHAT_ERROR, server->address); - close (server->server_read); - close (server->server_write); - close (server->sock4); - server->sock4 = -1; - return 0; + _("%s cannot set socket option \"SO_REUSEADDR\"\n"), + WEECHAT_WARNING); } - memset (&addr, 0, sizeof (addr)); - memcpy (&addr.sin_addr, ip4_hostent->h_addr, ip4_hostent->h_length); - addr.sin_port = htons (server->port); - addr.sin_family = AF_INET; - /*error = bind(server->sock4, (struct sockaddr *)(&addr), sizeof(addr)); - if (error != 0) - { - irc_display_prefix (server->buffer, PREFIX_ERROR); - gui_printf (server->buffer, - _("%s can't bind to hostname\n"), WEECHAT_ERROR); - return 0; - }*/ - ip_address = inet_ntoa (addr.sin_addr); - if (!ip_address) + + /* set SO_KEEPALIVE option for socket */ + set = 1; + if (setsockopt (server->sock4, SOL_SOCKET, SO_KEEPALIVE, + (void *) &set, sizeof (set)) == -1) { irc_display_prefix (server->buffer, PREFIX_ERROR); gui_printf (server->buffer, - _("%s IP address not found\n"), WEECHAT_ERROR); - close (server->server_read); - close (server->server_write); - close (server->sock4); - server->sock4 = -1; - return 0; + _("%s cannot set socket option \"SO_KEEPALIVE\"\n"), + WEECHAT_WARNING); } - - /* connection to server */ - irc_display_prefix (server->buffer, PREFIX_INFO); - gui_printf (server->buffer, - _("%s: server IP is: %s\n"), PACKAGE_NAME, ip_address); - - error = connect (server->sock4, (struct sockaddr *) &addr, sizeof (addr)); - if (error != 0) + + switch (pid = fork ()) { - irc_display_prefix (server->buffer, PREFIX_ERROR); - gui_printf (server->buffer, - _("%s cannot connect to irc server\n"), WEECHAT_ERROR); - close (server->server_read); - close (server->server_write); - close (server->sock4); - server->sock4 = -1; - return 0; + /* fork failed */ + case -1: + server_close_connection (server); + return 0; + /* child process */ + case 0: + setuid (getuid ()); + server_child (server); + _exit (EXIT_SUCCESS); } + /* parent process go on here */ + server->child_pid = pid; + return 1; } @@ -772,17 +913,9 @@ server_reconnect (t_irc_server *server) server->reconnect_start = 0; if (server_connect (server)) - { server->reconnect_join = 1; - irc_login (server); - } else - { - server->reconnect_start = time (NULL); - irc_display_prefix (server->buffer, PREFIX_INFO); - gui_printf (server->buffer, _("%s: Reconnecting to server in %d seconds\n"), - PACKAGE_NAME, server->autoreconnect_delay); - } + server_reconnect_schedule (server); } /* @@ -801,8 +934,8 @@ server_auto_connect (int command_line) || ((!command_line) && (ptr_server->autoconnect)) ) { (void) gui_buffer_new (gui_current_window, ptr_server, NULL, 0, 1); - if (server_connect (ptr_server)) - irc_login (ptr_server); + gui_redraw_buffer (gui_current_window->buffer); + server_connect (ptr_server); } } } @@ -828,24 +961,11 @@ server_disconnect (t_irc_server *server, int reconnect) } } - /* close communication with server */ - if (server->server_read >= 0) - close (server->server_read); - server->server_read = -1; - - if (server->server_write >= 0) - close (server->server_write); - server->server_write = -1; - - if (server->sock4 >= 0) - close (server->sock4); - server->sock4 = -1; + irc_display_prefix (server->buffer, PREFIX_INFO); + gui_printf (server->buffer, _("Disconnected from server!\n")); - if (server->unterminated_message) - free (server->unterminated_message); - server->unterminated_message = NULL; + server_close_connection (server); - server->is_connected = 0; server->is_away = 0; server->away_time = 0; server->lag = 0; @@ -854,12 +974,7 @@ server_disconnect (t_irc_server *server, int reconnect) server->lag_next_check = time (NULL) + cfg_irc_lag_check; if ((reconnect) && (server->autoreconnect)) - { - server->reconnect_start = time (NULL); - irc_display_prefix (server->buffer, PREFIX_INFO); - gui_printf (server->buffer, _("%s: Reconnecting to server in %d seconds\n"), - PACKAGE_NAME, server->autoreconnect_delay); - } + server_reconnect_schedule (server); else server->reconnect_start = 0; diff --git a/src/irc/irc.h b/src/irc/irc.h index e48ff289c..828bca973 100644 --- a/src/irc/irc.h +++ b/src/irc/irc.h @@ -23,6 +23,7 @@ #include <time.h> #include <sys/time.h> +#include <sys/types.h> #include "../gui/gui.h" /* prefixes for chat window */ @@ -138,14 +139,15 @@ struct t_irc_server int autorejoin; /* auto rejoin channels when kicked */ /* internal vars */ + pid_t child_pid; /* pid of child process (connecting) */ + int child_read; /* to read into child pipe */ + int child_write; /* to write into child pipe */ + int sock4; /* socket for server */ + int is_connected; /* 1 if WeeChat is connected to server */ char *unterminated_message; /* beginning of a message in input buf */ char *nick; /* current nickname */ - int is_connected; /* 1 if WeeChat is connected to server */ time_t reconnect_start; /* this time + delay = reconnect time */ int reconnect_join; /* 1 if channels opened to rejoin */ - int sock4; /* socket for server */ - int server_read; /* pipe for reading server data */ - int server_write; /* pipe for sending data to server */ int is_away; /* 1 is user is marker as away */ time_t away_time; /* time() when user marking as away */ int lag; /* lag (in milliseconds) */ @@ -235,6 +237,7 @@ extern t_irc_server *server_new (char *, int, int, int, int, char *, int, char * extern int server_send (t_irc_server *, char *, int); extern void server_sendf (t_irc_server *, char *, ...); extern void server_recv (t_irc_server *); +extern void server_child_read (t_irc_server *); extern int server_connect (t_irc_server *); extern void server_reconnect (t_irc_server *); extern void server_auto_connect (int); |