import fedora patch for openssl 1.1.0 support
[rofl0r-ixchat.git] / src / common / server.c
blobc48983df4d10bc83643d1a28a1b9e8d8373dbee9
1 /* X-Chat
2 * Copyright (C) 1998 Peter Zelezny.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18 * MS Proxy (ISA server) support is (c) 2006 Pavel Fedin <sonic_amiga@rambler.ru>
19 * based on Dante source code
20 * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
21 * Inferno Nettverk A/S, Norway. All rights reserved.
24 /*#define DEBUG_MSPROXY*/
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <fcntl.h>
33 #define WANTSOCKET
34 #define WANTARPA
35 #include "inet.h"
37 #include <signal.h>
38 #include <sys/wait.h>
40 #include "xchat.h"
41 #include "fe.h"
42 #include "cfgfiles.h"
43 #include "network.h"
44 #include "notify.h"
45 #include "xchatc.h"
46 #include "inbound.h"
47 #include "outbound.h"
48 #include "text.h"
49 #include "util.h"
50 #include "url.h"
51 #include "proto-irc.h"
52 #include "servlist.h"
53 #include "server.h"
55 #ifdef USE_OPENSSL
56 #include <openssl/ssl.h> /* SSL_() */
57 #include <openssl/err.h> /* ERR_() */
58 #include "ssl.h"
59 #endif
61 #ifdef USE_MSPROXY
62 #include "msproxy.h"
63 #endif
65 #ifdef USE_LIBPROXY
66 #include <proxy.h>
67 #endif
69 #ifdef USE_OPENSSL
70 /* local variables */
71 static struct session *g_sess = NULL;
72 #endif
74 static GSList *away_list = NULL;
75 GSList *serv_list = NULL;
77 static void auto_reconnect (server *serv, int send_quit, int err);
78 static void server_disconnect (session * sess, int sendquit, int err);
79 static int server_cleanup (server * serv);
80 static void server_connect (server *serv, char *hostname, int port, int no_login);
82 #ifdef USE_LIBPROXY
83 extern pxProxyFactory *libproxy_factory;
84 #endif
86 /* actually send to the socket. This might do a character translation or
87 send via SSL. server/dcc both use this function. */
89 int
90 tcp_send_real (void *ssl, int sok, char *encoding, int using_irc, char *buf, int len)
92 int ret;
93 char *locale;
94 gsize loc_len;
96 if (encoding == NULL) /* system */
98 locale = NULL;
99 if (!prefs.utf8_locale)
101 const gchar *charset;
103 g_get_charset (&charset);
104 locale = g_convert_with_fallback (buf, len, charset, "UTF-8",
105 "?", 0, &loc_len, 0);
107 } else
109 if (using_irc) /* using "IRC" encoding (CP1252/UTF-8 hybrid) */
110 /* if all chars fit inside CP1252, use that. Otherwise this
111 returns NULL and we send UTF-8. */
112 locale = g_convert (buf, len, "CP1252", "UTF-8", 0, &loc_len, 0);
113 else
114 locale = g_convert_with_fallback (buf, len, encoding, "UTF-8",
115 "?", 0, &loc_len, 0);
118 if (locale)
120 len = loc_len;
121 #ifdef USE_OPENSSL
122 if (!ssl)
123 ret = send (sok, locale, len, 0);
124 else
125 ret = _SSL_send (ssl, locale, len);
126 #else
127 ret = send (sok, locale, len, 0);
128 #endif
129 g_free (locale);
130 } else
132 #ifdef USE_OPENSSL
133 if (!ssl)
134 ret = send (sok, buf, len, 0);
135 else
136 ret = _SSL_send (ssl, buf, len);
137 #else
138 ret = send (sok, buf, len, 0);
139 #endif
142 return ret;
145 static int
146 server_send_real (server *serv, char *buf, int len)
148 fe_add_rawlog (serv, buf, len, TRUE);
150 return tcp_send_real (serv->ssl, serv->sok, serv->encoding, serv->using_irc,
151 buf, len);
154 /* new throttling system, uses the same method as the Undernet
155 ircu2.10 server; under test, a 200-line paste didn't flood
156 off the client */
158 static int
159 tcp_send_queue (server *serv)
161 char *buf, *p;
162 int len, i, pri;
163 GSList *list;
164 time_t now = time (0);
166 /* did the server close since the timeout was added? */
167 if (!is_server (serv))
168 return 0;
170 /* try priority 2,1,0 */
171 pri = 2;
172 while (pri >= 0)
174 list = serv->outbound_queue;
175 while (list)
177 buf = (char *) list->data;
178 if (buf[0] == pri)
180 buf++; /* skip the priority byte */
181 len = strlen (buf);
183 if (serv->next_send < now)
184 serv->next_send = now;
185 if (serv->next_send - now >= 10)
187 /* check for clock skew */
188 if (now >= serv->prev_now)
189 return 1; /* don't remove the timeout handler */
190 /* it is skewed, reset to something sane */
191 serv->next_send = now;
194 for (p = buf, i = len; i && *p != ' '; p++, i--);
195 serv->next_send += (2 + i / 120);
196 serv->sendq_len -= len;
197 serv->prev_now = now;
198 fe_set_throttle (serv);
200 server_send_real (serv, buf, len);
202 buf--;
203 serv->outbound_queue = g_slist_remove (serv->outbound_queue, buf);
204 free (buf);
205 list = serv->outbound_queue;
206 } else
208 list = list->next;
211 /* now try pri 0 */
212 pri--;
214 return 0; /* remove the timeout handler */
218 tcp_send_len (server *serv, char *buf, int len)
220 char *dbuf;
221 int noqueue = !serv->outbound_queue;
223 if (!prefs.throttle)
224 return server_send_real (serv, buf, len);
226 dbuf = malloc (len + 2); /* first byte is the priority */
227 dbuf[0] = 2; /* pri 2 for most things */
228 memcpy (dbuf + 1, buf, len);
229 dbuf[len + 1] = 0;
231 /* privmsg and notice get a lower priority */
232 if (strncasecmp (dbuf + 1, "PRIVMSG", 7) == 0 ||
233 strncasecmp (dbuf + 1, "NOTICE", 6) == 0)
235 dbuf[0] = 1;
237 else
239 /* WHO/MODE get the lowest priority */
240 if (strncasecmp (dbuf + 1, "WHO ", 4) == 0 ||
241 /* but only MODE queries, not changes */
242 (strncasecmp (dbuf + 1, "MODE", 4) == 0 &&
243 strchr (dbuf, '-') == NULL &&
244 strchr (dbuf, '+') == NULL))
245 dbuf[0] = 0;
248 serv->outbound_queue = g_slist_append (serv->outbound_queue, dbuf);
249 serv->sendq_len += len; /* tcp_send_queue uses strlen */
251 if (tcp_send_queue (serv) && noqueue)
252 fe_timeout_add (500, tcp_send_queue, serv);
254 return 1;
257 /*int
258 tcp_send (server *serv, char *buf)
260 return tcp_send_len (serv, buf, strlen (buf));
263 void
264 tcp_sendf (server *serv, char *fmt, ...)
266 va_list args;
267 /* keep this buffer in BSS. Converting UTF-8 to ISO-8859-x might make the
268 string shorter, so allow alot more than 512 for now. */
269 static char send_buf[1540]; /* good code hey (no it's not overflowable) */
270 int len;
272 va_start (args, fmt);
273 len = vsnprintf (send_buf, sizeof (send_buf) - 1, fmt, args);
274 va_end (args);
276 send_buf[sizeof (send_buf) - 1] = '\0';
277 if (len < 0 || len > (sizeof (send_buf) - 1))
278 len = strlen (send_buf);
280 tcp_send_len (serv, send_buf, len);
283 static int
284 close_socket_cb (gpointer sok)
286 closesocket (GPOINTER_TO_INT (sok));
287 return 0;
290 static void
291 close_socket (int sok)
293 /* close the socket in 5 seconds so the QUIT message is not lost */
294 fe_timeout_add (5000, close_socket_cb, GINT_TO_POINTER (sok));
297 /* handle 1 line of text received from the server */
299 static void
300 server_inline (server *serv, char *line, int len)
302 char *utf_line_allocated = NULL;
304 /* Checks whether we're set to use UTF-8 charset */
305 if (serv->using_irc || /* 1. using CP1252/UTF-8 Hybrid */
306 (serv->encoding == NULL && prefs.utf8_locale) || /* OR 2. using system default->UTF-8 */
307 (serv->encoding != NULL && /* OR 3. explicitly set to UTF-8 */
308 (strcasecmp (serv->encoding, "UTF8") == 0 ||
309 strcasecmp (serv->encoding, "UTF-8") == 0)))
311 /* The user has the UTF-8 charset set, either via /charset
312 command or from his UTF-8 locale. Thus, we first try the
313 UTF-8 charset, and if we fail to convert, we assume
314 it to be ISO-8859-1 (see text_validate). */
316 utf_line_allocated = text_validate (&line, &len);
318 } else
320 /* Since the user has an explicit charset set, either
321 via /charset command or from his non-UTF8 locale,
322 we don't fallback to ISO-8859-1 and instead try to remove
323 errnoeous octets till the string is convertable in the
324 said charset. */
326 const char *encoding = NULL;
328 if (serv->encoding != NULL)
329 encoding = serv->encoding;
330 else
331 g_get_charset (&encoding);
333 if (encoding != NULL)
335 char *conv_line; /* holds a copy of the original string */
336 int conv_len; /* tells g_convert how much of line to convert */
337 gsize utf_len;
338 gsize read_len;
339 GError *err;
340 gboolean retry;
342 conv_line = g_malloc (len + 1);
343 memcpy (conv_line, line, len);
344 conv_line[len] = 0;
345 conv_len = len;
347 /* if CP1255, convert it with the NUL terminator.
348 Works around SF bug #1122089 */
349 if (serv->using_cp1255)
350 conv_len++;
354 err = NULL;
355 retry = FALSE;
356 utf_line_allocated = g_convert_with_fallback (conv_line, conv_len, "UTF-8", encoding, "?", &read_len, &utf_len, &err);
357 if (err != NULL)
359 if (err->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE && conv_len > (read_len + 1))
361 /* Make our best bet by removing the erroneous char.
362 This will work for casual 8-bit strings with non-standard chars. */
363 memmove (conv_line + read_len, conv_line + read_len + 1, conv_len - read_len -1);
364 conv_len--;
365 retry = TRUE;
367 g_error_free (err);
369 } while (retry);
371 g_free (conv_line);
373 /* If any conversion has occured at all. Conversion might fail
374 due to errors other than invalid sequences, e.g. unknown charset. */
375 if (utf_line_allocated != NULL)
377 line = utf_line_allocated;
378 len = utf_len;
379 if (serv->using_cp1255 && len > 0)
380 len--;
382 else
384 /* If all fails, treat as UTF-8 with fallback to ISO-8859-1. */
385 utf_line_allocated = text_validate (&line, &len);
390 fe_add_rawlog (serv, line, len, FALSE);
392 /* let proto-irc.c handle it */
393 serv->p_inline (serv, line, len);
395 if (utf_line_allocated != NULL) /* only if a special copy was allocated */
396 g_free (utf_line_allocated);
399 /* read data from socket */
401 static gboolean
402 server_read (GIOChannel *source, GIOCondition condition, server *serv)
404 int sok = serv->sok;
405 int error, i, len;
406 char lbuf[2050];
408 while (1)
410 #ifdef USE_OPENSSL
411 if (!serv->ssl)
412 #endif
413 len = recv (sok, lbuf, sizeof (lbuf) - 2, 0);
414 #ifdef USE_OPENSSL
415 else
416 len = _SSL_recv (serv->ssl, lbuf, sizeof (lbuf) - 2);
417 #endif
418 if (len < 1)
420 error = 0;
421 if (len < 0)
423 if (would_block ())
424 return TRUE;
425 error = sock_error ();
427 if (!serv->end_of_motd)
429 server_disconnect (serv->server_session, FALSE, error);
430 if (!servlist_cycle (serv))
432 if (prefs.autoreconnect)
433 auto_reconnect (serv, FALSE, error);
435 } else
437 if (prefs.autoreconnect)
438 auto_reconnect (serv, FALSE, error);
439 else
440 server_disconnect (serv->server_session, FALSE, error);
442 return TRUE;
445 i = 0;
447 lbuf[len] = 0;
449 while (i < len)
451 switch (lbuf[i])
453 case '\r':
454 break;
456 case '\n':
457 serv->linebuf[serv->pos] = 0;
458 server_inline (serv, serv->linebuf, serv->pos);
459 serv->pos = 0;
460 break;
462 default:
463 serv->linebuf[serv->pos] = lbuf[i];
464 if (serv->pos >= (sizeof (serv->linebuf) - 1))
465 fprintf (stderr,
466 "*** XCHAT WARNING: Buffer overflow - shit server!\n");
467 else
468 serv->pos++;
470 i++;
475 static void
476 server_connected (server * serv)
478 prefs.wait_on_exit = TRUE;
479 serv->ping_recv = time (0);
480 serv->connected = TRUE;
481 set_nonblocking (serv->sok);
482 serv->iotag = fe_input_add (serv->sok, FIA_READ|FIA_EX, server_read, serv);
483 if (!serv->no_login)
485 EMIT_SIGNAL (XP_TE_CONNECTED, serv->server_session, NULL, NULL, NULL,
486 NULL, 0);
487 if (serv->network)
489 serv->p_login (serv,
490 (!(((ircnet *)serv->network)->flags & FLAG_USE_GLOBAL) &&
491 (((ircnet *)serv->network)->user)) ?
492 (((ircnet *)serv->network)->user) :
493 prefs.username,
494 (!(((ircnet *)serv->network)->flags & FLAG_USE_GLOBAL) &&
495 (((ircnet *)serv->network)->real)) ?
496 (((ircnet *)serv->network)->real) :
497 prefs.realname);
498 } else
500 serv->p_login (serv, prefs.username, prefs.realname);
502 } else
504 EMIT_SIGNAL (XP_TE_SERVERCONNECTED, serv->server_session, NULL, NULL,
505 NULL, NULL, 0);
508 server_set_name (serv, serv->servername);
509 fe_server_event (serv, FE_SE_CONNECT, 0);
513 static void
514 server_stopconnecting (server * serv)
516 if (serv->iotag)
518 fe_input_remove (serv->iotag);
519 serv->iotag = 0;
522 if (serv->joindelay_tag)
524 fe_timeout_remove (serv->joindelay_tag);
525 serv->joindelay_tag = 0;
528 /* kill the child process trying to connect */
529 kill (serv->childpid, SIGKILL);
530 waitpid (serv->childpid, NULL, 0);
532 close (serv->childwrite);
533 close (serv->childread);
535 #ifdef USE_OPENSSL
536 if (serv->ssl_do_connect_tag)
538 fe_timeout_remove (serv->ssl_do_connect_tag);
539 serv->ssl_do_connect_tag = 0;
541 #endif
543 fe_progressbar_end (serv);
545 serv->connecting = FALSE;
546 fe_server_event (serv, FE_SE_DISCONNECT, 0);
549 #ifdef USE_OPENSSL
550 #define SSLTMOUT 90 /* seconds */
551 static void
552 ssl_cb_info (SSL * s, int where, int ret)
554 /* char buf[128];*/
557 return; /* FIXME: make debug level adjustable in serverlist or settings */
559 /* snprintf (buf, sizeof (buf), "%s (%d)", SSL_state_string_long (s), where);
560 if (g_sess)
561 EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
562 else
563 fprintf (stderr, "%s\n", buf);*/
566 static int
567 ssl_cb_verify (int ok, X509_STORE_CTX * ctx)
569 X509 *current_cert;
570 char subject[256];
571 char issuer[256];
572 char buf[512];
575 current_cert = X509_STORE_CTX_get_current_cert (ctx);
576 X509_NAME_oneline (X509_get_subject_name (current_cert), subject,
577 sizeof (subject));
578 X509_NAME_oneline (X509_get_issuer_name (current_cert), issuer,
579 sizeof (issuer));
581 snprintf (buf, sizeof (buf), "* Subject: %s", subject);
582 EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
583 snprintf (buf, sizeof (buf), "* Issuer: %s", issuer);
584 EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
586 return (TRUE); /* always ok */
589 static int
590 ssl_do_connect (server * serv)
592 char buf[128];
594 g_sess = serv->server_session;
595 if (SSL_connect (serv->ssl) <= 0)
597 char err_buf[128];
598 int err;
600 g_sess = NULL;
601 if ((err = ERR_get_error ()) > 0)
603 ERR_error_string (err, err_buf);
604 snprintf (buf, sizeof (buf), "(%d) %s", err, err_buf);
605 EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, buf, NULL,
606 NULL, NULL, 0);
608 if (ERR_GET_REASON (err) == SSL_R_WRONG_VERSION_NUMBER)
609 PrintText (serv->server_session, _("Are you sure this is a SSL capable server and port?\n"));
611 server_cleanup (serv);
613 if (prefs.autoreconnect) {
614 auto_reconnect (serv, FALSE, -1);
615 return 1;
618 return (0); /* remove it (0) */
621 g_sess = NULL;
623 if (SSL_is_init_finished (serv->ssl))
625 struct cert_info cert_info;
626 struct chiper_info *chiper_info;
627 int verify_error;
628 int i;
630 if (!_SSL_get_cert_info (&cert_info, serv->ssl))
632 snprintf (buf, sizeof (buf), "* Certification info:");
633 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
634 NULL, 0);
635 snprintf (buf, sizeof (buf), " Subject:");
636 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
637 NULL, 0);
638 for (i = 0; cert_info.subject_word[i]; i++)
640 snprintf (buf, sizeof (buf), " %s", cert_info.subject_word[i]);
641 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
642 NULL, 0);
644 snprintf (buf, sizeof (buf), " Issuer:");
645 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
646 NULL, 0);
647 for (i = 0; cert_info.issuer_word[i]; i++)
649 snprintf (buf, sizeof (buf), " %s", cert_info.issuer_word[i]);
650 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
651 NULL, 0);
653 snprintf (buf, sizeof (buf), " Public key algorithm: %s (%d bits)",
654 cert_info.algorithm, cert_info.algorithm_bits);
655 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
656 NULL, 0);
657 /*if (cert_info.rsa_tmp_bits)
659 snprintf (buf, sizeof (buf),
660 " Public key algorithm uses ephemeral key with %d bits",
661 cert_info.rsa_tmp_bits);
662 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
663 NULL, 0);
665 snprintf (buf, sizeof (buf), " Sign algorithm %s",
666 cert_info.sign_algorithm/*, cert_info.sign_algorithm_bits*/);
667 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
668 NULL, 0);
669 snprintf (buf, sizeof (buf), " Valid since %s to %s",
670 cert_info.notbefore, cert_info.notafter);
671 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
672 NULL, 0);
673 } else
675 snprintf (buf, sizeof (buf), " * No Certificate");
676 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
677 NULL, 0);
680 chiper_info = _SSL_get_cipher_info (serv->ssl); /* static buffer */
681 snprintf (buf, sizeof (buf), "* Cipher info:");
682 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL,
684 snprintf (buf, sizeof (buf), " Version: %s, cipher %s (%u bits)",
685 chiper_info->version, chiper_info->chiper,
686 chiper_info->chiper_bits);
687 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL,
690 verify_error = SSL_get_verify_result (serv->ssl);
691 switch (verify_error)
693 case X509_V_OK:
694 /* snprintf (buf, sizeof (buf), "* Verify OK (?)"); */
695 /* EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL, 0); */
696 break;
697 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
698 case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
699 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
700 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
701 case X509_V_ERR_CERT_HAS_EXPIRED:
702 case X509_V_ERR_CERT_UNTRUSTED:
703 if (serv->accept_invalid_cert)
705 snprintf (buf, sizeof (buf), "* Verify E: %s.? (%d) -- Ignored",
706 X509_verify_cert_error_string (verify_error),
707 verify_error);
708 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
709 NULL, 0);
710 break;
712 default:
713 snprintf (buf, sizeof (buf), "%s.? (%d)",
714 X509_verify_cert_error_string (verify_error),
715 verify_error);
716 EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, buf, NULL, NULL,
717 NULL, 0);
719 server_cleanup (serv);
721 return (0);
724 server_stopconnecting (serv);
726 /* activate gtk poll */
727 server_connected (serv);
729 return (0); /* remove it (0) */
730 } else
732 SSL_SESSION *session;
733 long session_time;
735 session = SSL_get_session (serv->ssl);
736 session_time = SSL_SESSION_get_time (session);
737 if (session && session_time + SSLTMOUT < time (NULL))
739 snprintf (buf, sizeof (buf), "SSL handshake timed out");
740 EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, buf, NULL,
741 NULL, NULL, 0);
742 server_cleanup (serv); /* ->connecting = FALSE */
744 if (prefs.autoreconnect) {
745 auto_reconnect (serv, FALSE, -1);
746 return 1;
749 return (0); /* remove it (0) */
752 return (1); /* call it more (1) */
755 #endif
757 static int
758 timeout_auto_reconnect (server *serv)
760 if (is_server (serv)) /* make sure it hasnt been closed during the delay */
762 serv->recondelay_tag = 0;
763 if (!serv->connected && !serv->connecting && serv->server_session)
765 server_connect (serv, serv->hostname, serv->port, FALSE);
768 return 0; /* returning 0 should remove the timeout handler */
771 static void
772 auto_reconnect (server *serv, int send_quit, int err)
774 session *s;
775 GSList *list;
776 int del;
778 if (serv->server_session == NULL)
779 return;
781 list = sess_list;
782 while (list) /* make sure auto rejoin can work */
784 s = list->data;
785 if (s->type == SESS_CHANNEL && s->channel[0])
787 strcpy (s->waitchannel, s->channel);
788 strcpy (s->willjoinchannel, s->channel);
790 list = list->next;
793 if (serv->connected)
794 server_disconnect (serv->server_session, send_quit, err);
796 del = prefs.recon_delay * 1000;
797 if (del < 1000)
798 del = 500; /* so it doesn't block the gui */
800 if (err == -1 || err == 0 || err == ECONNRESET || err == ETIMEDOUT)
801 serv->reconnect_away = serv->is_away;
803 /* is this server in a reconnect delay? remove it! */
804 if (serv->recondelay_tag)
806 fe_timeout_remove (serv->recondelay_tag);
807 serv->recondelay_tag = 0;
810 serv->recondelay_tag = fe_timeout_add (del, timeout_auto_reconnect, serv);
811 fe_server_event (serv, FE_SE_RECONDELAY, del);
814 static void
815 server_flush_queue (server *serv)
817 list_free (&serv->outbound_queue);
818 serv->sendq_len = 0;
819 fe_set_throttle (serv);
822 #define waitline2(source,buf,size) waitline(serv->childread,buf,size,0)
824 /* connect() successed */
826 static void
827 server_connect_success (server *serv)
829 #ifdef USE_OPENSSL
830 #define SSLDOCONNTMOUT 300
831 if (serv->use_ssl)
833 char *err;
835 /* it'll be a memory leak, if connection isn't terminated by
836 server_cleanup() */
837 serv->ssl = _SSL_socket (serv->ctx, serv->sok);
838 if ((err = _SSL_set_verify (serv->ctx, ssl_cb_verify, NULL)))
840 EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, err, NULL,
841 NULL, NULL, 0);
842 server_cleanup (serv); /* ->connecting = FALSE */
843 return;
845 /* FIXME: it'll be needed by new servers */
846 /* send(serv->sok, "STLS\r\n", 6, 0); sleep(1); */
847 set_nonblocking (serv->sok);
848 serv->ssl_do_connect_tag = fe_timeout_add (SSLDOCONNTMOUT,
849 ssl_do_connect, serv);
850 return;
853 serv->ssl = NULL;
854 #endif
855 server_stopconnecting (serv); /* ->connecting = FALSE */
856 /* activate glib poll */
857 server_connected (serv);
860 /* receive info from the child-process about connection progress */
862 static gboolean
863 server_read_child (GIOChannel *source, GIOCondition condition, server *serv)
865 session *sess = serv->server_session;
866 char tbuf[128];
867 char outbuf[512];
868 char host[100];
869 char ip[100];
870 char *p;
872 waitline2 (source, tbuf, sizeof tbuf);
874 switch (tbuf[0])
876 case '0': /* print some text */
877 waitline2 (source, tbuf, sizeof tbuf);
878 PrintText (serv->server_session, tbuf);
879 break;
880 case '1': /* unknown host */
881 server_stopconnecting (serv);
882 closesocket (serv->sok4);
883 if (serv->proxy_sok4 != -1)
884 closesocket (serv->proxy_sok4);
885 #ifdef USE_IPV6
886 if (serv->sok6 != -1)
887 closesocket (serv->sok6);
888 if (serv->proxy_sok6 != -1)
889 closesocket (serv->proxy_sok6);
890 #endif
891 EMIT_SIGNAL (XP_TE_UKNHOST, sess, NULL, NULL, NULL, NULL, 0);
892 if (!servlist_cycle (serv))
893 if (prefs.autoreconnect)
894 auto_reconnect (serv, FALSE, -1);
895 break;
896 case '2': /* connection failed */
897 waitline2 (source, tbuf, sizeof tbuf);
898 server_stopconnecting (serv);
899 closesocket (serv->sok4);
900 if (serv->proxy_sok4 != -1)
901 closesocket (serv->proxy_sok4);
902 #ifdef USE_IPV6
903 if (serv->sok6 != -1)
904 closesocket (serv->sok6);
905 if (serv->proxy_sok6 != -1)
906 closesocket (serv->proxy_sok6);
907 #endif
908 EMIT_SIGNAL (XP_TE_CONNFAIL, sess, errorstring (atoi (tbuf)), NULL,
909 NULL, NULL, 0);
910 if (!servlist_cycle (serv))
911 if (prefs.autoreconnect)
912 auto_reconnect (serv, FALSE, -1);
913 break;
914 case '3': /* gethostbyname finished */
915 waitline2 (source, host, sizeof host);
916 waitline2 (source, ip, sizeof ip);
917 waitline2 (source, outbuf, sizeof outbuf);
918 EMIT_SIGNAL (XP_TE_CONNECT, sess, host, ip, outbuf, NULL, 0);
919 snprintf (outbuf, sizeof (outbuf), "%s/auth/xchat_auth",
920 g_get_home_dir ());
921 if (access (outbuf, X_OK) == 0)
923 snprintf (outbuf, sizeof (outbuf), "exec -d %s/auth/xchat_auth %s",
924 g_get_home_dir (), prefs.username);
925 handle_command (serv->server_session, outbuf, FALSE);
927 break;
928 case '4': /* success */
929 waitline2 (source, tbuf, sizeof (tbuf));
930 #ifdef USE_MSPROXY
931 serv->sok = strtol (tbuf, &p, 10);
932 if (*p++ == ' ')
934 serv->proxy_sok = strtol (p, &p, 10);
935 serv->msp_state.clientid = strtol (++p, &p, 10);
936 serv->msp_state.serverid = strtol (++p, &p, 10);
937 serv->msp_state.seq_sent = atoi (++p);
938 } else
939 serv->proxy_sok = -1;
940 #ifdef DEBUG_MSPROXY
941 printf ("Parent got main socket: %d, proxy socket: %d\n", serv->sok, serv->proxy_sok);
942 printf ("Client ID 0x%08x server ID 0x%08x seq_sent %d\n", serv->msp_state.clientid, serv->msp_state.serverid, serv->msp_state.seq_sent);
943 #endif
944 #else
945 serv->sok = atoi (tbuf);
946 #endif
947 #ifdef USE_IPV6
948 /* close the one we didn't end up using */
949 if (serv->sok == serv->sok4)
950 closesocket (serv->sok6);
951 else
952 closesocket (serv->sok4);
953 if (serv->proxy_sok != -1)
955 if (serv->proxy_sok == serv->proxy_sok4)
956 closesocket (serv->proxy_sok6);
957 else
958 closesocket (serv->proxy_sok4);
960 #endif
961 server_connect_success (serv);
962 break;
963 case '5': /* prefs ip discovered */
964 waitline2 (source, tbuf, sizeof tbuf);
965 prefs.local_ip = inet_addr (tbuf);
966 break;
967 case '7': /* gethostbyname (prefs.hostname) failed */
968 sprintf (outbuf,
969 _("Cannot resolve hostname %s\nCheck your IP Settings!\n"),
970 prefs.hostname);
971 PrintText (sess, outbuf);
972 break;
973 case '8':
974 PrintText (sess, _("Proxy traversal failed.\n"));
975 server_disconnect (sess, FALSE, -1);
976 if (prefs.autoreconnect)
977 auto_reconnect (serv, FALSE, -1);
978 break;
979 case '9':
980 waitline2 (source, tbuf, sizeof tbuf);
981 EMIT_SIGNAL (XP_TE_SERVERLOOKUP, sess, tbuf, NULL, NULL, NULL, 0);
982 break;
985 return TRUE;
988 /* kill all sockets & iotags of a server. Stop a connection attempt, or
989 disconnect if already connected. */
991 static int
992 server_cleanup (server * serv)
994 fe_set_lag (serv, 0.0);
996 if (serv->iotag)
998 fe_input_remove (serv->iotag);
999 serv->iotag = 0;
1002 if (serv->joindelay_tag)
1004 fe_timeout_remove (serv->joindelay_tag);
1005 serv->joindelay_tag = 0;
1008 #ifdef USE_OPENSSL
1009 if (serv->ssl)
1011 SSL_shutdown (serv->ssl);
1012 SSL_free (serv->ssl);
1013 serv->ssl = NULL;
1015 #endif
1017 if (serv->connecting)
1019 server_stopconnecting (serv);
1020 closesocket (serv->sok4);
1021 if (serv->proxy_sok4 != -1)
1022 closesocket (serv->proxy_sok4);
1023 if (serv->sok6 != -1)
1024 closesocket (serv->sok6);
1025 if (serv->proxy_sok6 != -1)
1026 closesocket (serv->proxy_sok6);
1027 return 1;
1030 if (serv->connected)
1032 close_socket (serv->sok);
1033 if (serv->proxy_sok)
1034 close_socket (serv->proxy_sok);
1035 serv->connected = FALSE;
1036 serv->end_of_motd = FALSE;
1037 return 2;
1040 /* is this server in a reconnect delay? remove it! */
1041 if (serv->recondelay_tag)
1043 fe_timeout_remove (serv->recondelay_tag);
1044 serv->recondelay_tag = 0;
1045 return 3;
1048 return 0;
1051 static void
1052 server_disconnect (session * sess, int sendquit, int err)
1054 server *serv = sess->server;
1055 GSList *list;
1056 char tbuf[64];
1057 gboolean shutup = FALSE;
1059 /* send our QUIT reason */
1060 if (sendquit && serv->connected)
1062 server_sendquit (sess);
1065 fe_server_event (serv, FE_SE_DISCONNECT, 0);
1067 /* close all sockets & io tags */
1068 switch (server_cleanup (serv))
1070 case 0: /* it wasn't even connected! */
1071 notc_msg (sess);
1072 return;
1073 case 1: /* it was in the process of connecting */
1074 sprintf (tbuf, "%d", sess->server->childpid);
1075 EMIT_SIGNAL (XP_TE_STOPCONNECT, sess, tbuf, NULL, NULL, NULL, 0);
1076 return;
1077 case 3:
1078 shutup = TRUE; /* won't print "disconnected" in channels */
1081 server_flush_queue (serv);
1083 list = sess_list;
1084 while (list)
1086 sess = (struct session *) list->data;
1087 if (sess->server == serv)
1089 if (!shutup || sess->type == SESS_SERVER)
1090 /* print "Disconnected" to each window using this server */
1091 EMIT_SIGNAL (XP_TE_DISCON, sess, errorstring (err), NULL, NULL, NULL, 0);
1093 if (!sess->channel[0] || sess->type == SESS_CHANNEL)
1094 clear_channel (sess);
1096 list = list->next;
1099 serv->pos = 0;
1100 serv->motd_skipped = FALSE;
1101 serv->no_login = FALSE;
1102 serv->servername[0] = 0;
1103 serv->lag_sent = 0;
1105 notify_cleanup ();
1108 /* send a "print text" command to the parent process - MUST END IN \n! */
1110 static void
1111 proxy_error (int fd, char *msg)
1113 write (fd, "0\n", 2);
1114 write (fd, msg, strlen (msg));
1117 struct sock_connect
1119 char version;
1120 char type;
1121 guint16 port;
1122 guint32 address;
1123 char username[10];
1126 /* traverse_socks() returns:
1127 * 0 success *
1128 * 1 socks traversal failed */
1130 static int
1131 traverse_socks (int print_fd, int sok, char *serverAddr, int port)
1133 struct sock_connect sc;
1134 unsigned char buf[256];
1136 sc.version = 4;
1137 sc.type = 1;
1138 sc.port = htons (port);
1139 sc.address = inet_addr (serverAddr);
1140 strncpy (sc.username, prefs.username, 9);
1142 send (sok, (char *) &sc, 8 + strlen (sc.username) + 1, 0);
1143 buf[1] = 0;
1144 recv (sok, buf, 10, 0);
1145 if (buf[1] == 90)
1146 return 0;
1148 snprintf (buf, sizeof (buf), "SOCKS\tServer reported error %d,%d.\n", buf[0], buf[1]);
1149 proxy_error (print_fd, buf);
1150 return 1;
1153 struct sock5_connect1
1155 char version;
1156 char nmethods;
1157 char method;
1160 static int
1161 traverse_socks5 (int print_fd, int sok, char *serverAddr, int port)
1163 struct sock5_connect1 sc1;
1164 unsigned char *sc2;
1165 unsigned int packetlen, addrlen;
1166 unsigned char buf[260];
1167 int auth = prefs.proxy_auth && prefs.proxy_user[0] && prefs.proxy_pass[0];
1169 sc1.version = 5;
1170 sc1.nmethods = 1;
1171 if (auth)
1172 sc1.method = 2; /* Username/Password Authentication (UPA) */
1173 else
1174 sc1.method = 0; /* NO Authentication */
1175 send (sok, (char *) &sc1, 3, 0);
1176 if (recv (sok, buf, 2, 0) != 2)
1177 goto read_error;
1179 if (buf[0] != 5)
1181 proxy_error (print_fd, "SOCKS\tServer is not socks version 5.\n");
1182 return 1;
1185 /* did the server say no auth required? */
1186 if (buf[1] == 0)
1187 auth = 0;
1189 if (auth)
1191 int len_u=0, len_p=0;
1193 /* authentication sub-negotiation (RFC1929) */
1194 if (buf[1] != 2) /* UPA not supported by server */
1196 proxy_error (print_fd, "SOCKS\tServer doesn't support UPA authentication.\n");
1197 return 1;
1200 memset (buf, 0, sizeof(buf));
1202 /* form the UPA request */
1203 len_u = strlen (prefs.proxy_user);
1204 len_p = strlen (prefs.proxy_pass);
1205 buf[0] = 1;
1206 buf[1] = len_u;
1207 memcpy (buf + 2, prefs.proxy_user, len_u);
1208 buf[2 + len_u] = len_p;
1209 memcpy (buf + 3 + len_u, prefs.proxy_pass, len_p);
1211 send (sok, buf, 3 + len_u + len_p, 0);
1212 if ( recv (sok, buf, 2, 0) != 2 )
1213 goto read_error;
1214 if ( buf[1] != 0 )
1216 proxy_error (print_fd, "SOCKS\tAuthentication failed. "
1217 "Is username and password correct?\n");
1218 return 1; /* UPA failed! */
1221 else
1223 if (buf[1] != 0)
1225 proxy_error (print_fd, "SOCKS\tAuthentication required but disabled in settings.\n");
1226 return 1;
1230 addrlen = strlen (serverAddr);
1231 packetlen = 4 + 1 + addrlen + 2;
1232 sc2 = malloc (packetlen);
1233 sc2[0] = 5; /* version */
1234 sc2[1] = 1; /* command */
1235 sc2[2] = 0; /* reserved */
1236 sc2[3] = 3; /* address type */
1237 sc2[4] = (unsigned char) addrlen; /* hostname length */
1238 memcpy (sc2 + 5, serverAddr, addrlen);
1239 *((unsigned short *) (sc2 + 5 + addrlen)) = htons (port);
1240 send (sok, sc2, packetlen, 0);
1241 free (sc2);
1243 /* consume all of the reply */
1244 if (recv (sok, buf, 4, 0) != 4)
1245 goto read_error;
1246 if (buf[0] != 5 || buf[1] != 0)
1248 if (buf[1] == 2)
1249 snprintf (buf, sizeof (buf), "SOCKS\tProxy refused to connect to host (not allowed).\n");
1250 else
1251 snprintf (buf, sizeof (buf), "SOCKS\tProxy failed to connect to host (error %d).\n", buf[1]);
1252 proxy_error (print_fd, buf);
1253 return 1;
1255 if (buf[3] == 1) /* IPV4 32bit address */
1257 if (recv (sok, buf, 6, 0) != 6)
1258 goto read_error;
1259 } else if (buf[3] == 4) /* IPV6 128bit address */
1261 if (recv (sok, buf, 18, 0) != 18)
1262 goto read_error;
1263 } else if (buf[3] == 3) /* string, 1st byte is size */
1265 if (recv (sok, buf, 1, 0) != 1) /* read the string size */
1266 goto read_error;
1267 packetlen = buf[0] + 2; /* can't exceed 260 */
1268 if (recv (sok, buf, packetlen, 0) != packetlen)
1269 goto read_error;
1272 return 0; /* success */
1274 read_error:
1275 proxy_error (print_fd, "SOCKS\tRead error from server.\n");
1276 return 1;
1279 static int
1280 traverse_wingate (int print_fd, int sok, char *serverAddr, int port)
1282 char buf[128];
1284 snprintf (buf, sizeof (buf), "%s %d\r\n", serverAddr, port);
1285 send (sok, buf, strlen (buf), 0);
1287 return 0;
1290 /* stuff for HTTP auth is here */
1292 static void
1293 three_to_four (char *from, char *to)
1295 static const char tab64[64]=
1297 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
1298 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
1299 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
1300 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
1303 to[0] = tab64 [ (from[0] >> 2) & 63 ];
1304 to[1] = tab64 [ ((from[0] << 4) | (from[1] >> 4)) & 63 ];
1305 to[2] = tab64 [ ((from[1] << 2) | (from[2] >> 6)) & 63 ];
1306 to[3] = tab64 [ from[2] & 63 ];
1309 void
1310 base64_encode (char *to, char *from, unsigned int len)
1312 while (len >= 3)
1314 three_to_four (from, to);
1315 len -= 3;
1316 from += 3;
1317 to += 4;
1319 if (len)
1321 char three[3]={0,0,0};
1322 int i=0;
1323 for (i=0;i<len;i++)
1324 three[i] = *from++;
1325 three_to_four (three, to);
1326 if (len == 1)
1327 to[2] = to[3] = '=';
1328 else if (len == 2)
1329 to[3] = '=';
1330 to += 4;
1332 to[0] = 0;
1335 static int
1336 http_read_line (int print_fd, int sok, char *buf, int len)
1338 len = waitline (sok, buf, len, TRUE);
1339 if (len >= 1)
1341 /* print the message out (send it to the parent process) */
1342 write (print_fd, "0\n", 2);
1344 if (buf[len-1] == '\r')
1346 buf[len-1] = '\n';
1347 write (print_fd, buf, len);
1348 } else
1350 write (print_fd, buf, len);
1351 write (print_fd, "\n", 1);
1355 return len;
1358 static int
1359 traverse_http (int print_fd, int sok, char *serverAddr, int port)
1361 char buf[512];
1362 char auth_data[256];
1363 char auth_data2[252];
1364 int n, n2;
1366 n = snprintf (buf, sizeof (buf), "CONNECT %s:%d HTTP/1.0\r\n",
1367 serverAddr, port);
1368 if (prefs.proxy_auth)
1370 n2 = snprintf (auth_data2, sizeof (auth_data2), "%s:%s",
1371 prefs.proxy_user, prefs.proxy_pass);
1372 base64_encode (auth_data, auth_data2, n2);
1373 n += snprintf (buf+n, sizeof (buf)-n, "Proxy-Authorization: Basic %s\r\n", auth_data);
1375 n += snprintf (buf+n, sizeof (buf)-n, "\r\n");
1376 send (sok, buf, n, 0);
1378 n = http_read_line (print_fd, sok, buf, sizeof (buf));
1379 /* "HTTP/1.0 200 OK" */
1380 if (n < 12)
1381 return 1;
1382 if (memcmp (buf, "HTTP/", 5) || memcmp (buf + 9, "200", 3))
1383 return 1;
1384 while (1)
1386 /* read until blank line */
1387 n = http_read_line (print_fd, sok, buf, sizeof (buf));
1388 if (n < 1 || (n == 1 && buf[0] == '\n'))
1389 break;
1391 return 0;
1394 static int
1395 traverse_proxy (int proxy_type, int print_fd, int sok, char *ip, int port, struct msproxy_state_t *state, netstore *ns_proxy, int csok4, int csok6, int *csok, char bound)
1397 switch (proxy_type)
1399 case 1:
1400 return traverse_wingate (print_fd, sok, ip, port);
1401 case 2:
1402 return traverse_socks (print_fd, sok, ip, port);
1403 case 3:
1404 return traverse_socks5 (print_fd, sok, ip, port);
1405 case 4:
1406 return traverse_http (print_fd, sok, ip, port);
1407 #ifdef USE_MSPROXY
1408 case 5:
1409 return traverse_msproxy (sok, ip, port, state, ns_proxy, csok4, csok6, csok, bound);
1410 #endif
1413 return 1;
1416 /* this is the child process making the connection attempt */
1418 static int
1419 server_child (server * serv)
1421 netstore *ns_server;
1422 netstore *ns_proxy = NULL;
1423 netstore *ns_local;
1424 int port = serv->port;
1425 int error;
1426 int sok, psok;
1427 char *hostname = serv->hostname;
1428 char *real_hostname = NULL;
1429 char *ip;
1430 char *proxy_ip = NULL;
1431 char *local_ip;
1432 int connect_port;
1433 char buf[512];
1434 char bound = 0;
1435 int proxy_type = 0;
1436 char *proxy_host = NULL;
1437 int proxy_port;
1439 ns_server = net_store_new ();
1441 /* is a hostname set? - bind to it */
1442 if (prefs.hostname[0])
1444 ns_local = net_store_new ();
1445 local_ip = net_resolve (ns_local, prefs.hostname, 0, &real_hostname);
1446 if (local_ip != NULL)
1448 snprintf (buf, sizeof (buf), "5\n%s\n", local_ip);
1449 write (serv->childwrite, buf, strlen (buf));
1450 net_bind (ns_local, serv->sok4, serv->sok6);
1451 bound = 1;
1452 } else
1454 write (serv->childwrite, "7\n", 2);
1456 net_store_destroy (ns_local);
1459 if (!serv->dont_use_proxy) /* blocked in serverlist? */
1461 if (FALSE)
1463 #ifdef USE_LIBPROXY
1464 else if (prefs.proxy_type == 5)
1466 char **proxy_list;
1467 char *url, *proxy;
1469 url = g_strdup_printf ("irc://%s:%d", hostname, port);
1470 proxy_list = px_proxy_factory_get_proxies (libproxy_factory, url);
1472 if (proxy_list) {
1473 /* can use only one */
1474 proxy = proxy_list[0];
1475 if (!strncmp (proxy, "direct", 6))
1476 proxy_type = 0;
1477 else if (!strncmp (proxy, "http", 4))
1478 proxy_type = 4;
1479 else if (!strncmp (proxy, "socks5", 6))
1480 proxy_type = 3;
1481 else if (!strncmp (proxy, "socks", 5))
1482 proxy_type = 2;
1485 if (proxy_type) {
1486 char *c;
1487 c = strchr (proxy, ':') + 3;
1488 proxy_host = strdup (c);
1489 c = strchr (proxy_host, ':');
1490 *c = '\0';
1491 proxy_port = atoi (c + 1);
1494 g_strfreev (proxy_list);
1495 g_free (url);
1497 #endif
1498 else if (prefs.proxy_host[0] &&
1499 prefs.proxy_type > 0 &&
1500 prefs.proxy_use != 2) /* proxy is NOT dcc-only */
1502 proxy_type = prefs.proxy_type;
1503 proxy_host = strdup (prefs.proxy_host);
1504 proxy_port = prefs.proxy_port;
1508 serv->proxy_type = proxy_type;
1510 /* first resolve where we want to connect to */
1511 if (proxy_type > 0)
1513 snprintf (buf, sizeof (buf), "9\n%s\n", proxy_host);
1514 write (serv->childwrite, buf, strlen (buf));
1515 ip = net_resolve (ns_server, proxy_host, proxy_port, &real_hostname);
1516 free (proxy_host);
1517 if (!ip)
1519 write (serv->childwrite, "1\n", 2);
1520 goto xit;
1522 connect_port = proxy_port;
1524 /* if using socks4 or MS Proxy, attempt to resolve ip for irc server */
1525 if ((proxy_type == 2) || (proxy_type == 5))
1527 ns_proxy = net_store_new ();
1528 proxy_ip = net_resolve (ns_proxy, hostname, port, &real_hostname);
1529 if (!proxy_ip)
1531 write (serv->childwrite, "1\n", 2);
1532 goto xit;
1534 } else /* otherwise we can just use the hostname */
1535 proxy_ip = strdup (hostname);
1536 } else
1538 ip = net_resolve (ns_server, hostname, port, &real_hostname);
1539 if (!ip)
1541 write (serv->childwrite, "1\n", 2);
1542 goto xit;
1544 connect_port = port;
1547 snprintf (buf, sizeof (buf), "3\n%s\n%s\n%d\n",
1548 real_hostname, ip, connect_port);
1549 write (serv->childwrite, buf, strlen (buf));
1551 if (!serv->dont_use_proxy && (proxy_type == 5))
1552 error = net_connect (ns_server, serv->proxy_sok4, serv->proxy_sok6, &psok);
1553 else
1555 error = net_connect (ns_server, serv->sok4, serv->sok6, &sok);
1556 psok = sok;
1559 if (error != 0)
1561 snprintf (buf, sizeof (buf), "2\n%d\n", sock_error ());
1562 write (serv->childwrite, buf, strlen (buf));
1563 } else
1565 /* connect succeeded */
1566 if (proxy_ip)
1568 switch (traverse_proxy (proxy_type, serv->childwrite, psok, proxy_ip, port, &serv->msp_state, ns_proxy, serv->sok4, serv->sok6, &sok, bound))
1570 case 0: /* success */
1571 #ifdef USE_MSPROXY
1572 if (!serv->dont_use_proxy && (proxy_type == 5))
1573 snprintf (buf, sizeof (buf), "4\n%d %d %d %d %d\n", sok, psok, serv->msp_state.clientid, serv->msp_state.serverid,
1574 serv->msp_state.seq_sent);
1575 else
1576 #endif
1577 snprintf (buf, sizeof (buf), "4\n%d\n", sok); /* success */
1578 write (serv->childwrite, buf, strlen (buf));
1579 break;
1580 case 1: /* socks traversal failed */
1581 write (serv->childwrite, "8\n", 2);
1582 break;
1584 } else
1586 snprintf (buf, sizeof (buf), "4\n%d\n", sok); /* success */
1587 write (serv->childwrite, buf, strlen (buf));
1591 xit:
1593 #if defined (USE_IPV6)
1594 /* this is probably not needed */
1595 net_store_destroy (ns_server);
1596 if (ns_proxy)
1597 net_store_destroy (ns_proxy);
1598 #endif
1600 /* no need to free ip/real_hostname, this process is exiting */
1602 return 0;
1605 static void
1606 server_connect (server *serv, char *hostname, int port, int no_login)
1608 int pid, read_des[2];
1609 session *sess = serv->server_session;
1611 #ifdef USE_OPENSSL
1612 if (!serv->ctx && serv->use_ssl)
1614 if (!(serv->ctx = _SSL_context_init (ssl_cb_info)))
1616 fprintf (stderr, "_SSL_context_init failed\n");
1617 exit (1);
1620 #endif
1622 if (!hostname[0])
1623 return;
1625 if (port < 0)
1627 /* use default port for this server type */
1628 port = 6667;
1629 #ifdef USE_OPENSSL
1630 if (serv->use_ssl)
1631 port = 9999;
1632 #endif
1634 port &= 0xffff; /* wrap around */
1636 if (serv->connected || serv->connecting || serv->recondelay_tag)
1637 server_disconnect (sess, TRUE, -1);
1639 fe_progressbar_start (sess);
1641 EMIT_SIGNAL (XP_TE_SERVERLOOKUP, sess, hostname, NULL, NULL, NULL, 0);
1643 safe_strcpy (serv->servername, hostname, sizeof (serv->servername));
1644 /* overlap illegal in strncpy */
1645 if (hostname != serv->hostname)
1646 safe_strcpy (serv->hostname, hostname, sizeof (serv->hostname));
1648 #ifdef USE_OPENSSL
1649 if (serv->use_ssl)
1651 char cert_file[256];
1652 serv->have_cert = FALSE;
1654 /* first try network specific cert/key */
1655 snprintf (cert_file, sizeof (cert_file), "%s/%s.pem",
1656 get_xdir_fs (), server_get_network (serv, TRUE));
1657 if (SSL_CTX_use_certificate_file (serv->ctx, cert_file, SSL_FILETYPE_PEM) == 1)
1659 if (SSL_CTX_use_PrivateKey_file (serv->ctx, cert_file, SSL_FILETYPE_PEM) == 1)
1660 serv->have_cert = TRUE;
1662 else
1664 /* if that doesn't exist, try ~/.xchat2/client.pem */
1665 snprintf (cert_file, sizeof (cert_file), "%s/%s.pem",
1666 get_xdir_fs (), "client");
1667 if (SSL_CTX_use_certificate_file (serv->ctx, cert_file, SSL_FILETYPE_PEM) == 1)
1669 if (SSL_CTX_use_PrivateKey_file (serv->ctx, cert_file, SSL_FILETYPE_PEM) == 1)
1670 serv->have_cert = TRUE;
1674 #endif
1676 server_set_defaults (serv);
1677 serv->connecting = TRUE;
1678 serv->port = port;
1679 serv->no_login = no_login;
1681 fe_server_event (serv, FE_SE_CONNECTING, 0);
1682 fe_set_away (serv);
1683 server_flush_queue (serv);
1685 if (pipe (read_des) < 0)
1686 return;
1687 serv->childread = read_des[0];
1688 serv->childwrite = read_des[1];
1690 /* create both sockets now, drop one later */
1691 net_sockets (&serv->sok4, &serv->sok6);
1692 #ifdef USE_MSPROXY
1693 /* In case of MS Proxy we have a separate UDP control connection */
1694 if (!serv->dont_use_proxy && (serv->proxy_type == 5))
1695 udp_sockets (&serv->proxy_sok4, &serv->proxy_sok6);
1696 else
1697 #endif
1699 serv->proxy_sok4 = -1;
1700 serv->proxy_sok6 = -1;
1703 #ifdef LOOKUPD
1704 rand(); /* CL: net_resolve calls rand() when LOOKUPD is set, so prepare a different seed for each child. This method giver a bigger variation in seed values than calling srand(time(0)) in the child itself. */
1705 #endif
1706 switch (pid = fork ())
1708 case -1:
1709 return;
1711 case 0:
1712 /* this is the child */
1713 setuid (getuid ());
1714 server_child (serv);
1715 _exit (0);
1717 serv->childpid = pid;
1718 serv->iotag = fe_input_add (serv->childread, FIA_READ, server_read_child,
1719 serv);
1722 void
1723 server_fill_her_up (server *serv)
1725 serv->connect = server_connect;
1726 serv->disconnect = server_disconnect;
1727 serv->cleanup = server_cleanup;
1728 serv->flush_queue = server_flush_queue;
1729 serv->auto_reconnect = auto_reconnect;
1731 proto_fill_her_up (serv);
1734 void
1735 server_set_encoding (server *serv, char *new_encoding)
1737 char *space;
1739 if (serv->encoding)
1741 free (serv->encoding);
1742 /* can be left as NULL to indicate system encoding */
1743 serv->encoding = NULL;
1744 serv->using_cp1255 = FALSE;
1745 serv->using_irc = FALSE;
1748 if (new_encoding)
1750 serv->encoding = strdup (new_encoding);
1751 /* the serverlist GUI might have added a space
1752 and short description - remove it. */
1753 space = strchr (serv->encoding, ' ');
1754 if (space)
1755 space[0] = 0;
1757 /* server_inline() uses these flags */
1758 if (!strcasecmp (serv->encoding, "CP1255") ||
1759 !strcasecmp (serv->encoding, "WINDOWS-1255"))
1760 serv->using_cp1255 = TRUE;
1761 else if (!strcasecmp (serv->encoding, "IRC"))
1762 serv->using_irc = TRUE;
1766 server *
1767 server_new (void)
1769 static int id = 0;
1770 server *serv;
1772 serv = malloc (sizeof (struct server));
1773 memset (serv, 0, sizeof (struct server));
1775 /* use server.c and proto-irc.c functions */
1776 server_fill_her_up (serv);
1778 serv->id = id++;
1779 serv->sok = -1;
1780 strcpy (serv->nick, prefs.nick1);
1781 server_set_defaults (serv);
1783 serv_list = g_slist_prepend (serv_list, serv);
1785 fe_new_server (serv);
1787 return serv;
1791 is_server (server *serv)
1793 return g_slist_find (serv_list, serv) ? 1 : 0;
1796 void
1797 server_set_defaults (server *serv)
1799 if (serv->chantypes)
1800 free (serv->chantypes);
1801 if (serv->chanmodes)
1802 free (serv->chanmodes);
1803 if (serv->nick_prefixes)
1804 free (serv->nick_prefixes);
1805 if (serv->nick_modes)
1806 free (serv->nick_modes);
1808 serv->chantypes = strdup ("#&!+");
1809 serv->chanmodes = strdup ("beI,k,l");
1810 serv->nick_prefixes = strdup ("@%+");
1811 serv->nick_modes = strdup ("ohv");
1813 serv->nickcount = 1;
1814 serv->end_of_motd = FALSE;
1815 serv->is_away = FALSE;
1816 serv->supports_watch = FALSE;
1817 serv->supports_monitor = FALSE;
1818 serv->bad_prefix = FALSE;
1819 serv->use_who = TRUE;
1820 serv->have_namesx = FALSE;
1821 serv->have_awaynotify = FALSE;
1822 serv->have_uhnames = FALSE;
1823 serv->have_whox = FALSE;
1824 serv->have_idmsg = FALSE;
1825 serv->have_accnotify = FALSE;
1826 serv->have_extjoin = FALSE;
1827 serv->have_sasl = FALSE;
1828 serv->have_except = FALSE;
1831 char *
1832 server_get_network (server *serv, gboolean fallback)
1834 if (serv->network)
1835 return ((ircnet *)serv->network)->name;
1837 if (fallback)
1838 return serv->servername;
1840 return NULL;
1843 void
1844 server_set_name (server *serv, char *name)
1846 GSList *list = sess_list;
1847 session *sess;
1849 if (name[0] == 0)
1850 name = serv->hostname;
1852 /* strncpy parameters must NOT overlap */
1853 if (name != serv->servername)
1855 safe_strcpy (serv->servername, name, sizeof (serv->servername));
1858 while (list)
1860 sess = (session *) list->data;
1861 if (sess->server == serv)
1862 fe_set_title (sess);
1863 list = list->next;
1866 if (serv->server_session->type == SESS_SERVER)
1868 if (serv->network)
1870 safe_strcpy (serv->server_session->channel, ((ircnet *)serv->network)->name, CHANLEN);
1871 } else
1873 safe_strcpy (serv->server_session->channel, name, CHANLEN);
1875 fe_set_channel (serv->server_session);
1879 struct away_msg *
1880 server_away_find_message (server *serv, char *nick)
1882 struct away_msg *away;
1883 GSList *list = away_list;
1884 while (list)
1886 away = (struct away_msg *) list->data;
1887 if (away->server == serv && !serv->p_cmp (nick, away->nick))
1888 return away;
1889 list = list->next;
1891 return NULL;
1894 static void
1895 server_away_free_messages (server *serv)
1897 GSList *list, *next;
1898 struct away_msg *away;
1900 list = away_list;
1901 while (list)
1903 away = list->data;
1904 next = list->next;
1905 if (away->server == serv)
1907 away_list = g_slist_remove (away_list, away);
1908 if (away->message)
1909 free (away->message);
1910 free (away);
1911 next = away_list;
1913 list = next;
1917 void
1918 server_away_save_message (server *serv, char *nick, char *msg)
1920 struct away_msg *away = server_away_find_message (serv, nick);
1922 if (away) /* Change message for known user */
1924 if (away->message)
1925 free (away->message);
1926 away->message = strdup (msg);
1927 } else
1928 /* Create brand new entry */
1930 away = malloc (sizeof (struct away_msg));
1931 if (away)
1933 away->server = serv;
1934 safe_strcpy (away->nick, nick, sizeof (away->nick));
1935 away->message = strdup (msg);
1936 away_list = g_slist_prepend (away_list, away);
1941 void
1942 server_free (server *serv)
1944 serv->cleanup (serv);
1946 serv_list = g_slist_remove (serv_list, serv);
1948 dcc_notify_kill (serv);
1949 serv->flush_queue (serv);
1950 server_away_free_messages (serv);
1952 free (serv->nick_modes);
1953 free (serv->nick_prefixes);
1954 free (serv->chanmodes);
1955 free (serv->chantypes);
1956 if (serv->bad_nick_prefixes)
1957 free (serv->bad_nick_prefixes);
1958 if (serv->last_away_reason)
1959 free (serv->last_away_reason);
1960 if (serv->encoding)
1961 free (serv->encoding);
1962 if (serv->autojoin)
1963 free (serv->autojoin);
1964 #ifdef USE_OPENSSL
1965 if (serv->ctx)
1966 _SSL_context_free (serv->ctx);
1967 #endif
1969 fe_server_callback (serv);
1971 free (serv);
1973 notify_cleanup ();