remove superfluous autoreconnectonfail and fix SSL reconnect ...
[rofl0r-ixchat.git] / src / common / server.c
blob3a67baa18595ee3884a21e935e16ded06bdbfad8
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 extern SSL_CTX *ctx; /* xchat.c */
71 /* local variables */
72 static struct session *g_sess = NULL;
73 #endif
75 static GSList *away_list = NULL;
76 GSList *serv_list = NULL;
78 static void auto_reconnect (server *serv, int send_quit, int err);
79 static void server_disconnect (session * sess, int sendquit, int err);
80 static int server_cleanup (server * serv);
81 static void server_connect (server *serv, char *hostname, int port, int no_login);
83 #ifdef USE_LIBPROXY
84 extern pxProxyFactory *libproxy_factory;
85 #endif
87 /* actually send to the socket. This might do a character translation or
88 send via SSL. server/dcc both use this function. */
90 int
91 tcp_send_real (void *ssl, int sok, char *encoding, int using_irc, char *buf, int len)
93 int ret;
94 char *locale;
95 gsize loc_len;
97 if (encoding == NULL) /* system */
99 locale = NULL;
100 if (!prefs.utf8_locale)
102 const gchar *charset;
104 g_get_charset (&charset);
105 locale = g_convert_with_fallback (buf, len, charset, "UTF-8",
106 "?", 0, &loc_len, 0);
108 } else
110 if (using_irc) /* using "IRC" encoding (CP1252/UTF-8 hybrid) */
111 /* if all chars fit inside CP1252, use that. Otherwise this
112 returns NULL and we send UTF-8. */
113 locale = g_convert (buf, len, "CP1252", "UTF-8", 0, &loc_len, 0);
114 else
115 locale = g_convert_with_fallback (buf, len, encoding, "UTF-8",
116 "?", 0, &loc_len, 0);
119 if (locale)
121 len = loc_len;
122 #ifdef USE_OPENSSL
123 if (!ssl)
124 ret = send (sok, locale, len, 0);
125 else
126 ret = _SSL_send (ssl, locale, len);
127 #else
128 ret = send (sok, locale, len, 0);
129 #endif
130 g_free (locale);
131 } else
133 #ifdef USE_OPENSSL
134 if (!ssl)
135 ret = send (sok, buf, len, 0);
136 else
137 ret = _SSL_send (ssl, buf, len);
138 #else
139 ret = send (sok, buf, len, 0);
140 #endif
143 return ret;
146 static int
147 server_send_real (server *serv, char *buf, int len)
149 fe_add_rawlog (serv, buf, len, TRUE);
151 return tcp_send_real (serv->ssl, serv->sok, serv->encoding, serv->using_irc,
152 buf, len);
155 /* new throttling system, uses the same method as the Undernet
156 ircu2.10 server; under test, a 200-line paste didn't flood
157 off the client */
159 static int
160 tcp_send_queue (server *serv)
162 char *buf, *p;
163 int len, i, pri;
164 GSList *list;
165 time_t now = time (0);
167 /* did the server close since the timeout was added? */
168 if (!is_server (serv))
169 return 0;
171 /* try priority 2,1,0 */
172 pri = 2;
173 while (pri >= 0)
175 list = serv->outbound_queue;
176 while (list)
178 buf = (char *) list->data;
179 if (buf[0] == pri)
181 buf++; /* skip the priority byte */
182 len = strlen (buf);
184 if (serv->next_send < now)
185 serv->next_send = now;
186 if (serv->next_send - now >= 10)
188 /* check for clock skew */
189 if (now >= serv->prev_now)
190 return 1; /* don't remove the timeout handler */
191 /* it is skewed, reset to something sane */
192 serv->next_send = now;
195 for (p = buf, i = len; i && *p != ' '; p++, i--);
196 serv->next_send += (2 + i / 120);
197 serv->sendq_len -= len;
198 serv->prev_now = now;
199 fe_set_throttle (serv);
201 server_send_real (serv, buf, len);
203 buf--;
204 serv->outbound_queue = g_slist_remove (serv->outbound_queue, buf);
205 free (buf);
206 list = serv->outbound_queue;
207 } else
209 list = list->next;
212 /* now try pri 0 */
213 pri--;
215 return 0; /* remove the timeout handler */
219 tcp_send_len (server *serv, char *buf, int len)
221 char *dbuf;
222 int noqueue = !serv->outbound_queue;
224 if (!prefs.throttle)
225 return server_send_real (serv, buf, len);
227 dbuf = malloc (len + 2); /* first byte is the priority */
228 dbuf[0] = 2; /* pri 2 for most things */
229 memcpy (dbuf + 1, buf, len);
230 dbuf[len + 1] = 0;
232 /* privmsg and notice get a lower priority */
233 if (strncasecmp (dbuf + 1, "PRIVMSG", 7) == 0 ||
234 strncasecmp (dbuf + 1, "NOTICE", 6) == 0)
236 dbuf[0] = 1;
238 else
240 /* WHO/MODE get the lowest priority */
241 if (strncasecmp (dbuf + 1, "WHO ", 4) == 0 ||
242 /* but only MODE queries, not changes */
243 (strncasecmp (dbuf + 1, "MODE", 4) == 0 &&
244 strchr (dbuf, '-') == NULL &&
245 strchr (dbuf, '+') == NULL))
246 dbuf[0] = 0;
249 serv->outbound_queue = g_slist_append (serv->outbound_queue, dbuf);
250 serv->sendq_len += len; /* tcp_send_queue uses strlen */
252 if (tcp_send_queue (serv) && noqueue)
253 fe_timeout_add (500, tcp_send_queue, serv);
255 return 1;
258 /*int
259 tcp_send (server *serv, char *buf)
261 return tcp_send_len (serv, buf, strlen (buf));
264 void
265 tcp_sendf (server *serv, char *fmt, ...)
267 va_list args;
268 /* keep this buffer in BSS. Converting UTF-8 to ISO-8859-x might make the
269 string shorter, so allow alot more than 512 for now. */
270 static char send_buf[1540]; /* good code hey (no it's not overflowable) */
271 int len;
273 va_start (args, fmt);
274 len = vsnprintf (send_buf, sizeof (send_buf) - 1, fmt, args);
275 va_end (args);
277 send_buf[sizeof (send_buf) - 1] = '\0';
278 if (len < 0 || len > (sizeof (send_buf) - 1))
279 len = strlen (send_buf);
281 tcp_send_len (serv, send_buf, len);
284 static int
285 close_socket_cb (gpointer sok)
287 closesocket (GPOINTER_TO_INT (sok));
288 return 0;
291 static void
292 close_socket (int sok)
294 /* close the socket in 5 seconds so the QUIT message is not lost */
295 fe_timeout_add (5000, close_socket_cb, GINT_TO_POINTER (sok));
298 /* handle 1 line of text received from the server */
300 static void
301 server_inline (server *serv, char *line, int len)
303 char *utf_line_allocated = NULL;
305 /* Checks whether we're set to use UTF-8 charset */
306 if (serv->using_irc || /* 1. using CP1252/UTF-8 Hybrid */
307 (serv->encoding == NULL && prefs.utf8_locale) || /* OR 2. using system default->UTF-8 */
308 (serv->encoding != NULL && /* OR 3. explicitly set to UTF-8 */
309 (strcasecmp (serv->encoding, "UTF8") == 0 ||
310 strcasecmp (serv->encoding, "UTF-8") == 0)))
312 /* The user has the UTF-8 charset set, either via /charset
313 command or from his UTF-8 locale. Thus, we first try the
314 UTF-8 charset, and if we fail to convert, we assume
315 it to be ISO-8859-1 (see text_validate). */
317 utf_line_allocated = text_validate (&line, &len);
319 } else
321 /* Since the user has an explicit charset set, either
322 via /charset command or from his non-UTF8 locale,
323 we don't fallback to ISO-8859-1 and instead try to remove
324 errnoeous octets till the string is convertable in the
325 said charset. */
327 const char *encoding = NULL;
329 if (serv->encoding != NULL)
330 encoding = serv->encoding;
331 else
332 g_get_charset (&encoding);
334 if (encoding != NULL)
336 char *conv_line; /* holds a copy of the original string */
337 int conv_len; /* tells g_convert how much of line to convert */
338 gsize utf_len;
339 gsize read_len;
340 GError *err;
341 gboolean retry;
343 conv_line = g_malloc (len + 1);
344 memcpy (conv_line, line, len);
345 conv_line[len] = 0;
346 conv_len = len;
348 /* if CP1255, convert it with the NUL terminator.
349 Works around SF bug #1122089 */
350 if (serv->using_cp1255)
351 conv_len++;
355 err = NULL;
356 retry = FALSE;
357 utf_line_allocated = g_convert_with_fallback (conv_line, conv_len, "UTF-8", encoding, "?", &read_len, &utf_len, &err);
358 if (err != NULL)
360 if (err->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE && conv_len > (read_len + 1))
362 /* Make our best bet by removing the erroneous char.
363 This will work for casual 8-bit strings with non-standard chars. */
364 memmove (conv_line + read_len, conv_line + read_len + 1, conv_len - read_len -1);
365 conv_len--;
366 retry = TRUE;
368 g_error_free (err);
370 } while (retry);
372 g_free (conv_line);
374 /* If any conversion has occured at all. Conversion might fail
375 due to errors other than invalid sequences, e.g. unknown charset. */
376 if (utf_line_allocated != NULL)
378 line = utf_line_allocated;
379 len = utf_len;
380 if (serv->using_cp1255 && len > 0)
381 len--;
383 else
385 /* If all fails, treat as UTF-8 with fallback to ISO-8859-1. */
386 utf_line_allocated = text_validate (&line, &len);
391 fe_add_rawlog (serv, line, len, FALSE);
393 /* let proto-irc.c handle it */
394 serv->p_inline (serv, line, len);
396 if (utf_line_allocated != NULL) /* only if a special copy was allocated */
397 g_free (utf_line_allocated);
400 /* read data from socket */
402 static gboolean
403 server_read (GIOChannel *source, GIOCondition condition, server *serv)
405 int sok = serv->sok;
406 int error, i, len;
407 char lbuf[2050];
409 while (1)
411 #ifdef USE_OPENSSL
412 if (!serv->ssl)
413 #endif
414 len = recv (sok, lbuf, sizeof (lbuf) - 2, 0);
415 #ifdef USE_OPENSSL
416 else
417 len = _SSL_recv (serv->ssl, lbuf, sizeof (lbuf) - 2);
418 #endif
419 if (len < 1)
421 error = 0;
422 if (len < 0)
424 if (would_block ())
425 return TRUE;
426 error = sock_error ();
428 if (!serv->end_of_motd)
430 server_disconnect (serv->server_session, FALSE, error);
431 if (!servlist_cycle (serv))
433 if (prefs.autoreconnect)
434 auto_reconnect (serv, FALSE, error);
436 } else
438 if (prefs.autoreconnect)
439 auto_reconnect (serv, FALSE, error);
440 else
441 server_disconnect (serv->server_session, FALSE, error);
443 return TRUE;
446 i = 0;
448 lbuf[len] = 0;
450 while (i < len)
452 switch (lbuf[i])
454 case '\r':
455 break;
457 case '\n':
458 serv->linebuf[serv->pos] = 0;
459 server_inline (serv, serv->linebuf, serv->pos);
460 serv->pos = 0;
461 break;
463 default:
464 serv->linebuf[serv->pos] = lbuf[i];
465 if (serv->pos >= (sizeof (serv->linebuf) - 1))
466 fprintf (stderr,
467 "*** XCHAT WARNING: Buffer overflow - shit server!\n");
468 else
469 serv->pos++;
471 i++;
476 static void
477 server_connected (server * serv)
479 prefs.wait_on_exit = TRUE;
480 serv->ping_recv = time (0);
481 serv->connected = TRUE;
482 set_nonblocking (serv->sok);
483 serv->iotag = fe_input_add (serv->sok, FIA_READ|FIA_EX, server_read, serv);
484 if (!serv->no_login)
486 EMIT_SIGNAL (XP_TE_CONNECTED, serv->server_session, NULL, NULL, NULL,
487 NULL, 0);
488 if (serv->network)
490 serv->p_login (serv,
491 (!(((ircnet *)serv->network)->flags & FLAG_USE_GLOBAL) &&
492 (((ircnet *)serv->network)->user)) ?
493 (((ircnet *)serv->network)->user) :
494 prefs.username,
495 (!(((ircnet *)serv->network)->flags & FLAG_USE_GLOBAL) &&
496 (((ircnet *)serv->network)->real)) ?
497 (((ircnet *)serv->network)->real) :
498 prefs.realname);
499 } else
501 serv->p_login (serv, prefs.username, prefs.realname);
503 } else
505 EMIT_SIGNAL (XP_TE_SERVERCONNECTED, serv->server_session, NULL, NULL,
506 NULL, NULL, 0);
509 server_set_name (serv, serv->servername);
510 fe_server_event (serv, FE_SE_CONNECT, 0);
514 static void
515 server_stopconnecting (server * serv)
517 if (serv->iotag)
519 fe_input_remove (serv->iotag);
520 serv->iotag = 0;
523 if (serv->joindelay_tag)
525 fe_timeout_remove (serv->joindelay_tag);
526 serv->joindelay_tag = 0;
529 /* kill the child process trying to connect */
530 kill (serv->childpid, SIGKILL);
531 waitpid (serv->childpid, NULL, 0);
533 close (serv->childwrite);
534 close (serv->childread);
536 #ifdef USE_OPENSSL
537 if (serv->ssl_do_connect_tag)
539 fe_timeout_remove (serv->ssl_do_connect_tag);
540 serv->ssl_do_connect_tag = 0;
542 #endif
544 fe_progressbar_end (serv);
546 serv->connecting = FALSE;
547 fe_server_event (serv, FE_SE_DISCONNECT, 0);
550 #ifdef USE_OPENSSL
551 #define SSLTMOUT 90 /* seconds */
552 static void
553 ssl_cb_info (SSL * s, int where, int ret)
555 /* char buf[128];*/
558 return; /* FIXME: make debug level adjustable in serverlist or settings */
560 /* snprintf (buf, sizeof (buf), "%s (%d)", SSL_state_string_long (s), where);
561 if (g_sess)
562 EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
563 else
564 fprintf (stderr, "%s\n", buf);*/
567 static int
568 ssl_cb_verify (int ok, X509_STORE_CTX * ctx)
570 char subject[256];
571 char issuer[256];
572 char buf[512];
575 X509_NAME_oneline (X509_get_subject_name (ctx->current_cert), subject,
576 sizeof (subject));
577 X509_NAME_oneline (X509_get_issuer_name (ctx->current_cert), issuer,
578 sizeof (issuer));
580 snprintf (buf, sizeof (buf), "* Subject: %s", subject);
581 EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
582 snprintf (buf, sizeof (buf), "* Issuer: %s", issuer);
583 EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
585 return (TRUE); /* always ok */
588 static int
589 ssl_do_connect (server * serv)
591 char buf[128];
593 g_sess = serv->server_session;
594 if (SSL_connect (serv->ssl) <= 0)
596 char err_buf[128];
597 int err;
599 g_sess = NULL;
600 if ((err = ERR_get_error ()) > 0)
602 ERR_error_string (err, err_buf);
603 snprintf (buf, sizeof (buf), "(%d) %s", err, err_buf);
604 EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, buf, NULL,
605 NULL, NULL, 0);
607 if (ERR_GET_REASON (err) == SSL_R_WRONG_VERSION_NUMBER)
608 PrintText (serv->server_session, _("Are you sure this is a SSL capable server and port?\n"));
610 server_cleanup (serv);
612 if (prefs.autoreconnect) {
613 auto_reconnect (serv, FALSE, -1);
614 return 1;
617 return (0); /* remove it (0) */
620 g_sess = NULL;
622 if (SSL_is_init_finished (serv->ssl))
624 struct cert_info cert_info;
625 struct chiper_info *chiper_info;
626 int verify_error;
627 int i;
629 if (!_SSL_get_cert_info (&cert_info, serv->ssl))
631 snprintf (buf, sizeof (buf), "* Certification info:");
632 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
633 NULL, 0);
634 snprintf (buf, sizeof (buf), " Subject:");
635 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
636 NULL, 0);
637 for (i = 0; cert_info.subject_word[i]; i++)
639 snprintf (buf, sizeof (buf), " %s", cert_info.subject_word[i]);
640 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
641 NULL, 0);
643 snprintf (buf, sizeof (buf), " Issuer:");
644 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
645 NULL, 0);
646 for (i = 0; cert_info.issuer_word[i]; i++)
648 snprintf (buf, sizeof (buf), " %s", cert_info.issuer_word[i]);
649 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
650 NULL, 0);
652 snprintf (buf, sizeof (buf), " Public key algorithm: %s (%d bits)",
653 cert_info.algorithm, cert_info.algorithm_bits);
654 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
655 NULL, 0);
656 /*if (cert_info.rsa_tmp_bits)
658 snprintf (buf, sizeof (buf),
659 " Public key algorithm uses ephemeral key with %d bits",
660 cert_info.rsa_tmp_bits);
661 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
662 NULL, 0);
664 snprintf (buf, sizeof (buf), " Sign algorithm %s",
665 cert_info.sign_algorithm/*, cert_info.sign_algorithm_bits*/);
666 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
667 NULL, 0);
668 snprintf (buf, sizeof (buf), " Valid since %s to %s",
669 cert_info.notbefore, cert_info.notafter);
670 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
671 NULL, 0);
672 } else
674 snprintf (buf, sizeof (buf), " * No Certificate");
675 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
676 NULL, 0);
679 chiper_info = _SSL_get_cipher_info (serv->ssl); /* static buffer */
680 snprintf (buf, sizeof (buf), "* Cipher info:");
681 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL,
683 snprintf (buf, sizeof (buf), " Version: %s, cipher %s (%u bits)",
684 chiper_info->version, chiper_info->chiper,
685 chiper_info->chiper_bits);
686 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL,
689 verify_error = SSL_get_verify_result (serv->ssl);
690 switch (verify_error)
692 case X509_V_OK:
693 /* snprintf (buf, sizeof (buf), "* Verify OK (?)"); */
694 /* EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL, 0); */
695 break;
696 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
697 case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
698 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
699 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
700 case X509_V_ERR_CERT_HAS_EXPIRED:
701 case X509_V_ERR_CERT_UNTRUSTED:
702 if (serv->accept_invalid_cert)
704 snprintf (buf, sizeof (buf), "* Verify E: %s.? (%d) -- Ignored",
705 X509_verify_cert_error_string (verify_error),
706 verify_error);
707 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
708 NULL, 0);
709 break;
711 default:
712 snprintf (buf, sizeof (buf), "%s.? (%d)",
713 X509_verify_cert_error_string (verify_error),
714 verify_error);
715 EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, buf, NULL, NULL,
716 NULL, 0);
718 server_cleanup (serv);
720 return (0);
723 server_stopconnecting (serv);
725 /* activate gtk poll */
726 server_connected (serv);
728 return (0); /* remove it (0) */
729 } else
731 if (serv->ssl->session && serv->ssl->session->time + SSLTMOUT < time (NULL))
733 snprintf (buf, sizeof (buf), "SSL handshake timed out");
734 EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, buf, NULL,
735 NULL, NULL, 0);
736 server_cleanup (serv); /* ->connecting = FALSE */
738 if (prefs.autoreconnect) {
739 auto_reconnect (serv, FALSE, -1);
740 return 1;
743 return (0); /* remove it (0) */
746 return (1); /* call it more (1) */
749 #endif
751 static int
752 timeout_auto_reconnect (server *serv)
754 if (is_server (serv)) /* make sure it hasnt been closed during the delay */
756 serv->recondelay_tag = 0;
757 if (!serv->connected && !serv->connecting && serv->server_session)
759 server_connect (serv, serv->hostname, serv->port, FALSE);
762 return 0; /* returning 0 should remove the timeout handler */
765 static void
766 auto_reconnect (server *serv, int send_quit, int err)
768 session *s;
769 GSList *list;
770 int del;
772 if (serv->server_session == NULL)
773 return;
775 list = sess_list;
776 while (list) /* make sure auto rejoin can work */
778 s = list->data;
779 if (s->type == SESS_CHANNEL && s->channel[0])
781 strcpy (s->waitchannel, s->channel);
782 strcpy (s->willjoinchannel, s->channel);
784 list = list->next;
787 if (serv->connected)
788 server_disconnect (serv->server_session, send_quit, err);
790 del = prefs.recon_delay * 1000;
791 if (del < 1000)
792 del = 500; /* so it doesn't block the gui */
794 if (err == -1 || err == 0 || err == ECONNRESET || err == ETIMEDOUT)
795 serv->reconnect_away = serv->is_away;
797 /* is this server in a reconnect delay? remove it! */
798 if (serv->recondelay_tag)
800 fe_timeout_remove (serv->recondelay_tag);
801 serv->recondelay_tag = 0;
804 serv->recondelay_tag = fe_timeout_add (del, timeout_auto_reconnect, serv);
805 fe_server_event (serv, FE_SE_RECONDELAY, del);
808 static void
809 server_flush_queue (server *serv)
811 list_free (&serv->outbound_queue);
812 serv->sendq_len = 0;
813 fe_set_throttle (serv);
816 #define waitline2(source,buf,size) waitline(serv->childread,buf,size,0)
818 /* connect() successed */
820 static void
821 server_connect_success (server *serv)
823 #ifdef USE_OPENSSL
824 #define SSLDOCONNTMOUT 300
825 if (serv->use_ssl)
827 char *err;
829 /* it'll be a memory leak, if connection isn't terminated by
830 server_cleanup() */
831 serv->ssl = _SSL_socket (ctx, serv->sok);
832 if ((err = _SSL_set_verify (ctx, ssl_cb_verify, NULL)) && !serv->accept_invalid_cert)
834 EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, err, NULL,
835 NULL, NULL, 0);
836 server_cleanup (serv); /* ->connecting = FALSE */
837 return;
839 /* FIXME: it'll be needed by new servers */
840 /* send(serv->sok, "STLS\r\n", 6, 0); sleep(1); */
841 set_nonblocking (serv->sok);
842 serv->ssl_do_connect_tag = fe_timeout_add (SSLDOCONNTMOUT,
843 ssl_do_connect, serv);
844 return;
847 serv->ssl = NULL;
848 #endif
849 server_stopconnecting (serv); /* ->connecting = FALSE */
850 /* activate glib poll */
851 server_connected (serv);
854 /* receive info from the child-process about connection progress */
856 static gboolean
857 server_read_child (GIOChannel *source, GIOCondition condition, server *serv)
859 session *sess = serv->server_session;
860 char tbuf[128];
861 char outbuf[512];
862 char host[100];
863 char ip[100];
864 char *p;
866 waitline2 (source, tbuf, sizeof tbuf);
868 switch (tbuf[0])
870 case '0': /* print some text */
871 waitline2 (source, tbuf, sizeof tbuf);
872 PrintText (serv->server_session, tbuf);
873 break;
874 case '1': /* unknown host */
875 server_stopconnecting (serv);
876 closesocket (serv->sok4);
877 if (serv->proxy_sok4 != -1)
878 closesocket (serv->proxy_sok4);
879 #ifdef USE_IPV6
880 if (serv->sok6 != -1)
881 closesocket (serv->sok6);
882 if (serv->proxy_sok6 != -1)
883 closesocket (serv->proxy_sok6);
884 #endif
885 EMIT_SIGNAL (XP_TE_UKNHOST, sess, NULL, NULL, NULL, NULL, 0);
886 if (!servlist_cycle (serv))
887 if (prefs.autoreconnect)
888 auto_reconnect (serv, FALSE, -1);
889 break;
890 case '2': /* connection failed */
891 waitline2 (source, tbuf, sizeof tbuf);
892 server_stopconnecting (serv);
893 closesocket (serv->sok4);
894 if (serv->proxy_sok4 != -1)
895 closesocket (serv->proxy_sok4);
896 #ifdef USE_IPV6
897 if (serv->sok6 != -1)
898 closesocket (serv->sok6);
899 if (serv->proxy_sok6 != -1)
900 closesocket (serv->proxy_sok6);
901 #endif
902 EMIT_SIGNAL (XP_TE_CONNFAIL, sess, errorstring (atoi (tbuf)), NULL,
903 NULL, NULL, 0);
904 if (!servlist_cycle (serv))
905 if (prefs.autoreconnect)
906 auto_reconnect (serv, FALSE, -1);
907 break;
908 case '3': /* gethostbyname finished */
909 waitline2 (source, host, sizeof host);
910 waitline2 (source, ip, sizeof ip);
911 waitline2 (source, outbuf, sizeof outbuf);
912 EMIT_SIGNAL (XP_TE_CONNECT, sess, host, ip, outbuf, NULL, 0);
913 snprintf (outbuf, sizeof (outbuf), "%s/auth/xchat_auth",
914 g_get_home_dir ());
915 if (access (outbuf, X_OK) == 0)
917 snprintf (outbuf, sizeof (outbuf), "exec -d %s/auth/xchat_auth %s",
918 g_get_home_dir (), prefs.username);
919 handle_command (serv->server_session, outbuf, FALSE);
921 break;
922 case '4': /* success */
923 waitline2 (source, tbuf, sizeof (tbuf));
924 #ifdef USE_MSPROXY
925 serv->sok = strtol (tbuf, &p, 10);
926 if (*p++ == ' ')
928 serv->proxy_sok = strtol (p, &p, 10);
929 serv->msp_state.clientid = strtol (++p, &p, 10);
930 serv->msp_state.serverid = strtol (++p, &p, 10);
931 serv->msp_state.seq_sent = atoi (++p);
932 } else
933 serv->proxy_sok = -1;
934 #ifdef DEBUG_MSPROXY
935 printf ("Parent got main socket: %d, proxy socket: %d\n", serv->sok, serv->proxy_sok);
936 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);
937 #endif
938 #else
939 serv->sok = atoi (tbuf);
940 #endif
941 #ifdef USE_IPV6
942 /* close the one we didn't end up using */
943 if (serv->sok == serv->sok4)
944 closesocket (serv->sok6);
945 else
946 closesocket (serv->sok4);
947 if (serv->proxy_sok != -1)
949 if (serv->proxy_sok == serv->proxy_sok4)
950 closesocket (serv->proxy_sok6);
951 else
952 closesocket (serv->proxy_sok4);
954 #endif
955 server_connect_success (serv);
956 break;
957 case '5': /* prefs ip discovered */
958 waitline2 (source, tbuf, sizeof tbuf);
959 prefs.local_ip = inet_addr (tbuf);
960 break;
961 case '7': /* gethostbyname (prefs.hostname) failed */
962 sprintf (outbuf,
963 _("Cannot resolve hostname %s\nCheck your IP Settings!\n"),
964 prefs.hostname);
965 PrintText (sess, outbuf);
966 break;
967 case '8':
968 PrintText (sess, _("Proxy traversal failed.\n"));
969 server_disconnect (sess, FALSE, -1);
970 break;
971 case '9':
972 waitline2 (source, tbuf, sizeof tbuf);
973 EMIT_SIGNAL (XP_TE_SERVERLOOKUP, sess, tbuf, NULL, NULL, NULL, 0);
974 break;
977 return TRUE;
980 /* kill all sockets & iotags of a server. Stop a connection attempt, or
981 disconnect if already connected. */
983 static int
984 server_cleanup (server * serv)
986 fe_set_lag (serv, 0.0);
988 if (serv->iotag)
990 fe_input_remove (serv->iotag);
991 serv->iotag = 0;
994 if (serv->joindelay_tag)
996 fe_timeout_remove (serv->joindelay_tag);
997 serv->joindelay_tag = 0;
1000 #ifdef USE_OPENSSL
1001 if (serv->ssl)
1003 _SSL_close (serv->ssl);
1004 serv->ssl = NULL;
1006 #endif
1008 if (serv->connecting)
1010 server_stopconnecting (serv);
1011 closesocket (serv->sok4);
1012 if (serv->proxy_sok4 != -1)
1013 closesocket (serv->proxy_sok4);
1014 if (serv->sok6 != -1)
1015 closesocket (serv->sok6);
1016 if (serv->proxy_sok6 != -1)
1017 closesocket (serv->proxy_sok6);
1018 return 1;
1021 if (serv->connected)
1023 close_socket (serv->sok);
1024 if (serv->proxy_sok)
1025 close_socket (serv->proxy_sok);
1026 serv->connected = FALSE;
1027 serv->end_of_motd = FALSE;
1028 return 2;
1031 /* is this server in a reconnect delay? remove it! */
1032 if (serv->recondelay_tag)
1034 fe_timeout_remove (serv->recondelay_tag);
1035 serv->recondelay_tag = 0;
1036 return 3;
1039 return 0;
1042 static void
1043 server_disconnect (session * sess, int sendquit, int err)
1045 server *serv = sess->server;
1046 GSList *list;
1047 char tbuf[64];
1048 gboolean shutup = FALSE;
1050 /* send our QUIT reason */
1051 if (sendquit && serv->connected)
1053 server_sendquit (sess);
1056 fe_server_event (serv, FE_SE_DISCONNECT, 0);
1058 /* close all sockets & io tags */
1059 switch (server_cleanup (serv))
1061 case 0: /* it wasn't even connected! */
1062 notc_msg (sess);
1063 return;
1064 case 1: /* it was in the process of connecting */
1065 sprintf (tbuf, "%d", sess->server->childpid);
1066 EMIT_SIGNAL (XP_TE_STOPCONNECT, sess, tbuf, NULL, NULL, NULL, 0);
1067 return;
1068 case 3:
1069 shutup = TRUE; /* won't print "disconnected" in channels */
1072 server_flush_queue (serv);
1074 list = sess_list;
1075 while (list)
1077 sess = (struct session *) list->data;
1078 if (sess->server == serv)
1080 if (!shutup || sess->type == SESS_SERVER)
1081 /* print "Disconnected" to each window using this server */
1082 EMIT_SIGNAL (XP_TE_DISCON, sess, errorstring (err), NULL, NULL, NULL, 0);
1084 if (!sess->channel[0] || sess->type == SESS_CHANNEL)
1085 clear_channel (sess);
1087 list = list->next;
1090 serv->pos = 0;
1091 serv->motd_skipped = FALSE;
1092 serv->no_login = FALSE;
1093 serv->servername[0] = 0;
1094 serv->lag_sent = 0;
1096 notify_cleanup ();
1099 /* send a "print text" command to the parent process - MUST END IN \n! */
1101 static void
1102 proxy_error (int fd, char *msg)
1104 write (fd, "0\n", 2);
1105 write (fd, msg, strlen (msg));
1108 struct sock_connect
1110 char version;
1111 char type;
1112 guint16 port;
1113 guint32 address;
1114 char username[10];
1117 /* traverse_socks() returns:
1118 * 0 success *
1119 * 1 socks traversal failed */
1121 static int
1122 traverse_socks (int print_fd, int sok, char *serverAddr, int port)
1124 struct sock_connect sc;
1125 unsigned char buf[256];
1127 sc.version = 4;
1128 sc.type = 1;
1129 sc.port = htons (port);
1130 sc.address = inet_addr (serverAddr);
1131 strncpy (sc.username, prefs.username, 9);
1133 send (sok, (char *) &sc, 8 + strlen (sc.username) + 1, 0);
1134 buf[1] = 0;
1135 recv (sok, buf, 10, 0);
1136 if (buf[1] == 90)
1137 return 0;
1139 snprintf (buf, sizeof (buf), "SOCKS\tServer reported error %d,%d.\n", buf[0], buf[1]);
1140 proxy_error (print_fd, buf);
1141 return 1;
1144 struct sock5_connect1
1146 char version;
1147 char nmethods;
1148 char method;
1151 static int
1152 traverse_socks5 (int print_fd, int sok, char *serverAddr, int port)
1154 struct sock5_connect1 sc1;
1155 unsigned char *sc2;
1156 unsigned int packetlen, addrlen;
1157 unsigned char buf[260];
1158 int auth = prefs.proxy_auth && prefs.proxy_user[0] && prefs.proxy_pass[0];
1160 sc1.version = 5;
1161 sc1.nmethods = 1;
1162 if (auth)
1163 sc1.method = 2; /* Username/Password Authentication (UPA) */
1164 else
1165 sc1.method = 0; /* NO Authentication */
1166 send (sok, (char *) &sc1, 3, 0);
1167 if (recv (sok, buf, 2, 0) != 2)
1168 goto read_error;
1170 if (buf[0] != 5)
1172 proxy_error (print_fd, "SOCKS\tServer is not socks version 5.\n");
1173 return 1;
1176 /* did the server say no auth required? */
1177 if (buf[1] == 0)
1178 auth = 0;
1180 if (auth)
1182 int len_u=0, len_p=0;
1184 /* authentication sub-negotiation (RFC1929) */
1185 if (buf[1] != 2) /* UPA not supported by server */
1187 proxy_error (print_fd, "SOCKS\tServer doesn't support UPA authentication.\n");
1188 return 1;
1191 memset (buf, 0, sizeof(buf));
1193 /* form the UPA request */
1194 len_u = strlen (prefs.proxy_user);
1195 len_p = strlen (prefs.proxy_pass);
1196 buf[0] = 1;
1197 buf[1] = len_u;
1198 memcpy (buf + 2, prefs.proxy_user, len_u);
1199 buf[2 + len_u] = len_p;
1200 memcpy (buf + 3 + len_u, prefs.proxy_pass, len_p);
1202 send (sok, buf, 3 + len_u + len_p, 0);
1203 if ( recv (sok, buf, 2, 0) != 2 )
1204 goto read_error;
1205 if ( buf[1] != 0 )
1207 proxy_error (print_fd, "SOCKS\tAuthentication failed. "
1208 "Is username and password correct?\n");
1209 return 1; /* UPA failed! */
1212 else
1214 if (buf[1] != 0)
1216 proxy_error (print_fd, "SOCKS\tAuthentication required but disabled in settings.\n");
1217 return 1;
1221 addrlen = strlen (serverAddr);
1222 packetlen = 4 + 1 + addrlen + 2;
1223 sc2 = malloc (packetlen);
1224 sc2[0] = 5; /* version */
1225 sc2[1] = 1; /* command */
1226 sc2[2] = 0; /* reserved */
1227 sc2[3] = 3; /* address type */
1228 sc2[4] = (unsigned char) addrlen; /* hostname length */
1229 memcpy (sc2 + 5, serverAddr, addrlen);
1230 *((unsigned short *) (sc2 + 5 + addrlen)) = htons (port);
1231 send (sok, sc2, packetlen, 0);
1232 free (sc2);
1234 /* consume all of the reply */
1235 if (recv (sok, buf, 4, 0) != 4)
1236 goto read_error;
1237 if (buf[0] != 5 || buf[1] != 0)
1239 if (buf[1] == 2)
1240 snprintf (buf, sizeof (buf), "SOCKS\tProxy refused to connect to host (not allowed).\n");
1241 else
1242 snprintf (buf, sizeof (buf), "SOCKS\tProxy failed to connect to host (error %d).\n", buf[1]);
1243 proxy_error (print_fd, buf);
1244 return 1;
1246 if (buf[3] == 1) /* IPV4 32bit address */
1248 if (recv (sok, buf, 6, 0) != 6)
1249 goto read_error;
1250 } else if (buf[3] == 4) /* IPV6 128bit address */
1252 if (recv (sok, buf, 18, 0) != 18)
1253 goto read_error;
1254 } else if (buf[3] == 3) /* string, 1st byte is size */
1256 if (recv (sok, buf, 1, 0) != 1) /* read the string size */
1257 goto read_error;
1258 packetlen = buf[0] + 2; /* can't exceed 260 */
1259 if (recv (sok, buf, packetlen, 0) != packetlen)
1260 goto read_error;
1263 return 0; /* success */
1265 read_error:
1266 proxy_error (print_fd, "SOCKS\tRead error from server.\n");
1267 return 1;
1270 static int
1271 traverse_wingate (int print_fd, int sok, char *serverAddr, int port)
1273 char buf[128];
1275 snprintf (buf, sizeof (buf), "%s %d\r\n", serverAddr, port);
1276 send (sok, buf, strlen (buf), 0);
1278 return 0;
1281 /* stuff for HTTP auth is here */
1283 static void
1284 three_to_four (char *from, char *to)
1286 static const char tab64[64]=
1288 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
1289 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
1290 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
1291 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
1294 to[0] = tab64 [ (from[0] >> 2) & 63 ];
1295 to[1] = tab64 [ ((from[0] << 4) | (from[1] >> 4)) & 63 ];
1296 to[2] = tab64 [ ((from[1] << 2) | (from[2] >> 6)) & 63 ];
1297 to[3] = tab64 [ from[2] & 63 ];
1300 void
1301 base64_encode (char *to, char *from, unsigned int len)
1303 while (len >= 3)
1305 three_to_four (from, to);
1306 len -= 3;
1307 from += 3;
1308 to += 4;
1310 if (len)
1312 char three[3]={0,0,0};
1313 int i=0;
1314 for (i=0;i<len;i++)
1315 three[i] = *from++;
1316 three_to_four (three, to);
1317 if (len == 1)
1318 to[2] = to[3] = '=';
1319 else if (len == 2)
1320 to[3] = '=';
1321 to += 4;
1323 to[0] = 0;
1326 static int
1327 http_read_line (int print_fd, int sok, char *buf, int len)
1329 len = waitline (sok, buf, len, TRUE);
1330 if (len >= 1)
1332 /* print the message out (send it to the parent process) */
1333 write (print_fd, "0\n", 2);
1335 if (buf[len-1] == '\r')
1337 buf[len-1] = '\n';
1338 write (print_fd, buf, len);
1339 } else
1341 write (print_fd, buf, len);
1342 write (print_fd, "\n", 1);
1346 return len;
1349 static int
1350 traverse_http (int print_fd, int sok, char *serverAddr, int port)
1352 char buf[512];
1353 char auth_data[256];
1354 char auth_data2[252];
1355 int n, n2;
1357 n = snprintf (buf, sizeof (buf), "CONNECT %s:%d HTTP/1.0\r\n",
1358 serverAddr, port);
1359 if (prefs.proxy_auth)
1361 n2 = snprintf (auth_data2, sizeof (auth_data2), "%s:%s",
1362 prefs.proxy_user, prefs.proxy_pass);
1363 base64_encode (auth_data, auth_data2, n2);
1364 n += snprintf (buf+n, sizeof (buf)-n, "Proxy-Authorization: Basic %s\r\n", auth_data);
1366 n += snprintf (buf+n, sizeof (buf)-n, "\r\n");
1367 send (sok, buf, n, 0);
1369 n = http_read_line (print_fd, sok, buf, sizeof (buf));
1370 /* "HTTP/1.0 200 OK" */
1371 if (n < 12)
1372 return 1;
1373 if (memcmp (buf, "HTTP/", 5) || memcmp (buf + 9, "200", 3))
1374 return 1;
1375 while (1)
1377 /* read until blank line */
1378 n = http_read_line (print_fd, sok, buf, sizeof (buf));
1379 if (n < 1 || (n == 1 && buf[0] == '\n'))
1380 break;
1382 return 0;
1385 static int
1386 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)
1388 switch (proxy_type)
1390 case 1:
1391 return traverse_wingate (print_fd, sok, ip, port);
1392 case 2:
1393 return traverse_socks (print_fd, sok, ip, port);
1394 case 3:
1395 return traverse_socks5 (print_fd, sok, ip, port);
1396 case 4:
1397 return traverse_http (print_fd, sok, ip, port);
1398 #ifdef USE_MSPROXY
1399 case 5:
1400 return traverse_msproxy (sok, ip, port, state, ns_proxy, csok4, csok6, csok, bound);
1401 #endif
1404 return 1;
1407 /* this is the child process making the connection attempt */
1409 static int
1410 server_child (server * serv)
1412 netstore *ns_server;
1413 netstore *ns_proxy = NULL;
1414 netstore *ns_local;
1415 int port = serv->port;
1416 int error;
1417 int sok, psok;
1418 char *hostname = serv->hostname;
1419 char *real_hostname = NULL;
1420 char *ip;
1421 char *proxy_ip = NULL;
1422 char *local_ip;
1423 int connect_port;
1424 char buf[512];
1425 char bound = 0;
1426 int proxy_type = 0;
1427 char *proxy_host = NULL;
1428 int proxy_port;
1430 ns_server = net_store_new ();
1432 /* is a hostname set? - bind to it */
1433 if (prefs.hostname[0])
1435 ns_local = net_store_new ();
1436 local_ip = net_resolve (ns_local, prefs.hostname, 0, &real_hostname);
1437 if (local_ip != NULL)
1439 snprintf (buf, sizeof (buf), "5\n%s\n", local_ip);
1440 write (serv->childwrite, buf, strlen (buf));
1441 net_bind (ns_local, serv->sok4, serv->sok6);
1442 bound = 1;
1443 } else
1445 write (serv->childwrite, "7\n", 2);
1447 net_store_destroy (ns_local);
1450 if (!serv->dont_use_proxy) /* blocked in serverlist? */
1452 if (FALSE)
1454 #ifdef USE_LIBPROXY
1455 else if (prefs.proxy_type == 5)
1457 char **proxy_list;
1458 char *url, *proxy;
1460 url = g_strdup_printf ("irc://%s:%d", hostname, port);
1461 proxy_list = px_proxy_factory_get_proxies (libproxy_factory, url);
1463 if (proxy_list) {
1464 /* can use only one */
1465 proxy = proxy_list[0];
1466 if (!strncmp (proxy, "direct", 6))
1467 proxy_type = 0;
1468 else if (!strncmp (proxy, "http", 4))
1469 proxy_type = 4;
1470 else if (!strncmp (proxy, "socks5", 6))
1471 proxy_type = 3;
1472 else if (!strncmp (proxy, "socks", 5))
1473 proxy_type = 2;
1476 if (proxy_type) {
1477 char *c;
1478 c = strchr (proxy, ':') + 3;
1479 proxy_host = strdup (c);
1480 c = strchr (proxy_host, ':');
1481 *c = '\0';
1482 proxy_port = atoi (c + 1);
1485 g_strfreev (proxy_list);
1486 g_free (url);
1488 #endif
1489 else if (prefs.proxy_host[0] &&
1490 prefs.proxy_type > 0 &&
1491 prefs.proxy_use != 2) /* proxy is NOT dcc-only */
1493 proxy_type = prefs.proxy_type;
1494 proxy_host = strdup (prefs.proxy_host);
1495 proxy_port = prefs.proxy_port;
1499 serv->proxy_type = proxy_type;
1501 /* first resolve where we want to connect to */
1502 if (proxy_type > 0)
1504 snprintf (buf, sizeof (buf), "9\n%s\n", proxy_host);
1505 write (serv->childwrite, buf, strlen (buf));
1506 ip = net_resolve (ns_server, proxy_host, proxy_port, &real_hostname);
1507 free (proxy_host);
1508 if (!ip)
1510 write (serv->childwrite, "1\n", 2);
1511 goto xit;
1513 connect_port = proxy_port;
1515 /* if using socks4 or MS Proxy, attempt to resolve ip for irc server */
1516 if ((proxy_type == 2) || (proxy_type == 5))
1518 ns_proxy = net_store_new ();
1519 proxy_ip = net_resolve (ns_proxy, hostname, port, &real_hostname);
1520 if (!proxy_ip)
1522 write (serv->childwrite, "1\n", 2);
1523 goto xit;
1525 } else /* otherwise we can just use the hostname */
1526 proxy_ip = strdup (hostname);
1527 } else
1529 ip = net_resolve (ns_server, hostname, port, &real_hostname);
1530 if (!ip)
1532 write (serv->childwrite, "1\n", 2);
1533 goto xit;
1535 connect_port = port;
1538 snprintf (buf, sizeof (buf), "3\n%s\n%s\n%d\n",
1539 real_hostname, ip, connect_port);
1540 write (serv->childwrite, buf, strlen (buf));
1542 if (!serv->dont_use_proxy && (proxy_type == 5))
1543 error = net_connect (ns_server, serv->proxy_sok4, serv->proxy_sok6, &psok);
1544 else
1546 error = net_connect (ns_server, serv->sok4, serv->sok6, &sok);
1547 psok = sok;
1550 if (error != 0)
1552 snprintf (buf, sizeof (buf), "2\n%d\n", sock_error ());
1553 write (serv->childwrite, buf, strlen (buf));
1554 } else
1556 /* connect succeeded */
1557 if (proxy_ip)
1559 switch (traverse_proxy (proxy_type, serv->childwrite, psok, proxy_ip, port, &serv->msp_state, ns_proxy, serv->sok4, serv->sok6, &sok, bound))
1561 case 0: /* success */
1562 #ifdef USE_MSPROXY
1563 if (!serv->dont_use_proxy && (proxy_type == 5))
1564 snprintf (buf, sizeof (buf), "4\n%d %d %d %d %d\n", sok, psok, serv->msp_state.clientid, serv->msp_state.serverid,
1565 serv->msp_state.seq_sent);
1566 else
1567 #endif
1568 snprintf (buf, sizeof (buf), "4\n%d\n", sok); /* success */
1569 write (serv->childwrite, buf, strlen (buf));
1570 break;
1571 case 1: /* socks traversal failed */
1572 write (serv->childwrite, "8\n", 2);
1573 break;
1575 } else
1577 snprintf (buf, sizeof (buf), "4\n%d\n", sok); /* success */
1578 write (serv->childwrite, buf, strlen (buf));
1582 xit:
1584 #if defined (USE_IPV6)
1585 /* this is probably not needed */
1586 net_store_destroy (ns_server);
1587 if (ns_proxy)
1588 net_store_destroy (ns_proxy);
1589 #endif
1591 /* no need to free ip/real_hostname, this process is exiting */
1593 return 0;
1596 static void
1597 server_connect (server *serv, char *hostname, int port, int no_login)
1599 int pid, read_des[2];
1600 session *sess = serv->server_session;
1602 #ifdef USE_OPENSSL
1603 if (!ctx && serv->use_ssl)
1605 if (!(ctx = _SSL_context_init (ssl_cb_info, FALSE)))
1607 fprintf (stderr, "_SSL_context_init failed\n");
1608 exit (1);
1611 #endif
1613 if (!hostname[0])
1614 return;
1616 if (port < 0)
1618 /* use default port for this server type */
1619 port = 6667;
1620 #ifdef USE_OPENSSL
1621 if (serv->use_ssl)
1622 port = 9999;
1623 #endif
1625 port &= 0xffff; /* wrap around */
1627 if (serv->connected || serv->connecting || serv->recondelay_tag)
1628 server_disconnect (sess, TRUE, -1);
1630 fe_progressbar_start (sess);
1632 EMIT_SIGNAL (XP_TE_SERVERLOOKUP, sess, hostname, NULL, NULL, NULL, 0);
1634 safe_strcpy (serv->servername, hostname, sizeof (serv->servername));
1635 /* overlap illegal in strncpy */
1636 if (hostname != serv->hostname)
1637 safe_strcpy (serv->hostname, hostname, sizeof (serv->hostname));
1639 #ifdef USE_OPENSSL
1640 if (serv->use_ssl)
1642 char cert_file[256];
1644 /* first try network specific cert/key */
1645 snprintf (cert_file, sizeof (cert_file), "%s/%s.pem",
1646 get_xdir_fs (), server_get_network (serv, TRUE));
1647 if (SSL_CTX_use_certificate_file (ctx, cert_file, SSL_FILETYPE_PEM) == 1)
1648 SSL_CTX_use_PrivateKey_file (ctx, cert_file, SSL_FILETYPE_PEM);
1649 else
1651 /* if that doesn't exist, try ~/.xchat2/client.pem */
1652 snprintf (cert_file, sizeof (cert_file), "%s/%s.pem",
1653 get_xdir_fs (), "client");
1654 if (SSL_CTX_use_certificate_file (ctx, cert_file, SSL_FILETYPE_PEM) == 1)
1655 SSL_CTX_use_PrivateKey_file (ctx, cert_file, SSL_FILETYPE_PEM);
1658 #endif
1660 server_set_defaults (serv);
1661 serv->connecting = TRUE;
1662 serv->port = port;
1663 serv->no_login = no_login;
1665 fe_server_event (serv, FE_SE_CONNECTING, 0);
1666 fe_set_away (serv);
1667 server_flush_queue (serv);
1669 if (pipe (read_des) < 0)
1670 return;
1671 serv->childread = read_des[0];
1672 serv->childwrite = read_des[1];
1674 /* create both sockets now, drop one later */
1675 net_sockets (&serv->sok4, &serv->sok6);
1676 #ifdef USE_MSPROXY
1677 /* In case of MS Proxy we have a separate UDP control connection */
1678 if (!serv->dont_use_proxy && (serv->proxy_type == 5))
1679 udp_sockets (&serv->proxy_sok4, &serv->proxy_sok6);
1680 else
1681 #endif
1683 serv->proxy_sok4 = -1;
1684 serv->proxy_sok6 = -1;
1687 #ifdef LOOKUPD
1688 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. */
1689 #endif
1690 switch (pid = fork ())
1692 case -1:
1693 return;
1695 case 0:
1696 /* this is the child */
1697 setuid (getuid ());
1698 server_child (serv);
1699 _exit (0);
1701 serv->childpid = pid;
1702 serv->iotag = fe_input_add (serv->childread, FIA_READ, server_read_child,
1703 serv);
1706 void
1707 server_fill_her_up (server *serv)
1709 serv->connect = server_connect;
1710 serv->disconnect = server_disconnect;
1711 serv->cleanup = server_cleanup;
1712 serv->flush_queue = server_flush_queue;
1713 serv->auto_reconnect = auto_reconnect;
1715 proto_fill_her_up (serv);
1718 void
1719 server_set_encoding (server *serv, char *new_encoding)
1721 char *space;
1723 if (serv->encoding)
1725 free (serv->encoding);
1726 /* can be left as NULL to indicate system encoding */
1727 serv->encoding = NULL;
1728 serv->using_cp1255 = FALSE;
1729 serv->using_irc = FALSE;
1732 if (new_encoding)
1734 serv->encoding = strdup (new_encoding);
1735 /* the serverlist GUI might have added a space
1736 and short description - remove it. */
1737 space = strchr (serv->encoding, ' ');
1738 if (space)
1739 space[0] = 0;
1741 /* server_inline() uses these flags */
1742 if (!strcasecmp (serv->encoding, "CP1255") ||
1743 !strcasecmp (serv->encoding, "WINDOWS-1255"))
1744 serv->using_cp1255 = TRUE;
1745 else if (!strcasecmp (serv->encoding, "IRC"))
1746 serv->using_irc = TRUE;
1750 server *
1751 server_new (void)
1753 static int id = 0;
1754 server *serv;
1756 serv = malloc (sizeof (struct server));
1757 memset (serv, 0, sizeof (struct server));
1759 /* use server.c and proto-irc.c functions */
1760 server_fill_her_up (serv);
1762 serv->id = id++;
1763 serv->sok = -1;
1764 strcpy (serv->nick, prefs.nick1);
1765 server_set_defaults (serv);
1767 serv_list = g_slist_prepend (serv_list, serv);
1769 fe_new_server (serv);
1771 return serv;
1775 is_server (server *serv)
1777 return g_slist_find (serv_list, serv) ? 1 : 0;
1780 void
1781 server_set_defaults (server *serv)
1783 if (serv->chantypes)
1784 free (serv->chantypes);
1785 if (serv->chanmodes)
1786 free (serv->chanmodes);
1787 if (serv->nick_prefixes)
1788 free (serv->nick_prefixes);
1789 if (serv->nick_modes)
1790 free (serv->nick_modes);
1792 serv->chantypes = strdup ("#&!+");
1793 serv->chanmodes = strdup ("beI,k,l");
1794 serv->nick_prefixes = strdup ("@%+");
1795 serv->nick_modes = strdup ("ohv");
1797 serv->nickcount = 1;
1798 serv->nickservtype = 1;
1799 serv->end_of_motd = FALSE;
1800 serv->is_away = FALSE;
1801 serv->supports_watch = FALSE;
1802 serv->bad_prefix = FALSE;
1803 serv->use_who = TRUE;
1804 serv->have_namesx = FALSE;
1805 serv->have_uhnames = FALSE;
1806 serv->have_whox = FALSE;
1807 serv->have_capab = FALSE;
1808 serv->have_idmsg = FALSE;
1809 serv->have_except = FALSE;
1812 char *
1813 server_get_network (server *serv, gboolean fallback)
1815 if (serv->network)
1816 return ((ircnet *)serv->network)->name;
1818 if (fallback)
1819 return serv->servername;
1821 return NULL;
1824 void
1825 server_set_name (server *serv, char *name)
1827 GSList *list = sess_list;
1828 session *sess;
1830 if (name[0] == 0)
1831 name = serv->hostname;
1833 /* strncpy parameters must NOT overlap */
1834 if (name != serv->servername)
1836 safe_strcpy (serv->servername, name, sizeof (serv->servername));
1839 while (list)
1841 sess = (session *) list->data;
1842 if (sess->server == serv)
1843 fe_set_title (sess);
1844 list = list->next;
1847 if (serv->server_session->type == SESS_SERVER)
1849 if (serv->network)
1851 safe_strcpy (serv->server_session->channel, ((ircnet *)serv->network)->name, CHANLEN);
1852 } else
1854 safe_strcpy (serv->server_session->channel, name, CHANLEN);
1856 fe_set_channel (serv->server_session);
1860 struct away_msg *
1861 server_away_find_message (server *serv, char *nick)
1863 struct away_msg *away;
1864 GSList *list = away_list;
1865 while (list)
1867 away = (struct away_msg *) list->data;
1868 if (away->server == serv && !serv->p_cmp (nick, away->nick))
1869 return away;
1870 list = list->next;
1872 return NULL;
1875 static void
1876 server_away_free_messages (server *serv)
1878 GSList *list, *next;
1879 struct away_msg *away;
1881 list = away_list;
1882 while (list)
1884 away = list->data;
1885 next = list->next;
1886 if (away->server == serv)
1888 away_list = g_slist_remove (away_list, away);
1889 if (away->message)
1890 free (away->message);
1891 free (away);
1892 next = away_list;
1894 list = next;
1898 void
1899 server_away_save_message (server *serv, char *nick, char *msg)
1901 struct away_msg *away = server_away_find_message (serv, nick);
1903 if (away) /* Change message for known user */
1905 if (away->message)
1906 free (away->message);
1907 away->message = strdup (msg);
1908 } else
1909 /* Create brand new entry */
1911 away = malloc (sizeof (struct away_msg));
1912 if (away)
1914 away->server = serv;
1915 safe_strcpy (away->nick, nick, sizeof (away->nick));
1916 away->message = strdup (msg);
1917 away_list = g_slist_prepend (away_list, away);
1922 void
1923 server_free (server *serv)
1925 serv->cleanup (serv);
1927 serv_list = g_slist_remove (serv_list, serv);
1929 dcc_notify_kill (serv);
1930 serv->flush_queue (serv);
1931 server_away_free_messages (serv);
1933 free (serv->nick_modes);
1934 free (serv->nick_prefixes);
1935 free (serv->chanmodes);
1936 free (serv->chantypes);
1937 if (serv->bad_nick_prefixes)
1938 free (serv->bad_nick_prefixes);
1939 if (serv->last_away_reason)
1940 free (serv->last_away_reason);
1941 if (serv->encoding)
1942 free (serv->encoding);
1943 if (serv->autojoin)
1944 free (serv->autojoin);
1946 fe_server_callback (serv);
1948 free (serv);
1950 notify_cleanup ();