configure: add stuff for spell checking
[rofl0r-ixchat.git] / src / common / server.c
blobf1a40a25e04a9c75421c46a6eacbc43ae6a5fe2b
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 #ifndef WIN32
38 #include <signal.h>
39 #include <sys/wait.h>
40 #else
41 #include <winbase.h>
42 #endif
44 #include "xchat.h"
45 #include "fe.h"
46 #include "cfgfiles.h"
47 #include "network.h"
48 #include "notify.h"
49 #include "xchatc.h"
50 #include "inbound.h"
51 #include "outbound.h"
52 #include "text.h"
53 #include "util.h"
54 #include "url.h"
55 #include "proto-irc.h"
56 #include "servlist.h"
57 #include "server.h"
59 #ifdef USE_OPENSSL
60 #include <openssl/ssl.h> /* SSL_() */
61 #include <openssl/err.h> /* ERR_() */
62 #include "ssl.h"
63 #endif
65 #ifdef USE_MSPROXY
66 #include "msproxy.h"
67 #endif
69 #ifdef WIN32
70 #include "identd.c"
71 #endif
73 #ifdef USE_LIBPROXY
74 #include <proxy.h>
75 #endif
77 #ifdef USE_OPENSSL
78 extern SSL_CTX *ctx; /* xchat.c */
79 /* local variables */
80 static struct session *g_sess = NULL;
81 #endif
83 static GSList *away_list = NULL;
84 GSList *serv_list = NULL;
86 static void auto_reconnect (server *serv, int send_quit, int err);
87 static void server_disconnect (session * sess, int sendquit, int err);
88 static int server_cleanup (server * serv);
89 static void server_connect (server *serv, char *hostname, int port, int no_login);
91 #ifdef USE_LIBPROXY
92 extern pxProxyFactory *libproxy_factory;
93 #endif
95 /* actually send to the socket. This might do a character translation or
96 send via SSL. server/dcc both use this function. */
98 int
99 tcp_send_real (void *ssl, int sok, char *encoding, int using_irc, char *buf, int len)
101 int ret;
102 char *locale;
103 gsize loc_len;
105 if (encoding == NULL) /* system */
107 locale = NULL;
108 if (!prefs.utf8_locale)
110 const gchar *charset;
112 g_get_charset (&charset);
113 locale = g_convert_with_fallback (buf, len, charset, "UTF-8",
114 "?", 0, &loc_len, 0);
116 } else
118 if (using_irc) /* using "IRC" encoding (CP1252/UTF-8 hybrid) */
119 /* if all chars fit inside CP1252, use that. Otherwise this
120 returns NULL and we send UTF-8. */
121 locale = g_convert (buf, len, "CP1252", "UTF-8", 0, &loc_len, 0);
122 else
123 locale = g_convert_with_fallback (buf, len, encoding, "UTF-8",
124 "?", 0, &loc_len, 0);
127 if (locale)
129 len = loc_len;
130 #ifdef USE_OPENSSL
131 if (!ssl)
132 ret = send (sok, locale, len, 0);
133 else
134 ret = _SSL_send (ssl, locale, len);
135 #else
136 ret = send (sok, locale, len, 0);
137 #endif
138 g_free (locale);
139 } else
141 #ifdef USE_OPENSSL
142 if (!ssl)
143 ret = send (sok, buf, len, 0);
144 else
145 ret = _SSL_send (ssl, buf, len);
146 #else
147 ret = send (sok, buf, len, 0);
148 #endif
151 return ret;
154 static int
155 server_send_real (server *serv, char *buf, int len)
157 fe_add_rawlog (serv, buf, len, TRUE);
159 return tcp_send_real (serv->ssl, serv->sok, serv->encoding, serv->using_irc,
160 buf, len);
163 /* new throttling system, uses the same method as the Undernet
164 ircu2.10 server; under test, a 200-line paste didn't flood
165 off the client */
167 static int
168 tcp_send_queue (server *serv)
170 char *buf, *p;
171 int len, i, pri;
172 GSList *list;
173 time_t now = time (0);
175 /* did the server close since the timeout was added? */
176 if (!is_server (serv))
177 return 0;
179 /* try priority 2,1,0 */
180 pri = 2;
181 while (pri >= 0)
183 list = serv->outbound_queue;
184 while (list)
186 buf = (char *) list->data;
187 if (buf[0] == pri)
189 buf++; /* skip the priority byte */
190 len = strlen (buf);
192 if (serv->next_send < now)
193 serv->next_send = now;
194 if (serv->next_send - now >= 10)
196 /* check for clock skew */
197 if (now >= serv->prev_now)
198 return 1; /* don't remove the timeout handler */
199 /* it is skewed, reset to something sane */
200 serv->next_send = now;
203 for (p = buf, i = len; i && *p != ' '; p++, i--);
204 serv->next_send += (2 + i / 120);
205 serv->sendq_len -= len;
206 serv->prev_now = now;
207 fe_set_throttle (serv);
209 server_send_real (serv, buf, len);
211 buf--;
212 serv->outbound_queue = g_slist_remove (serv->outbound_queue, buf);
213 free (buf);
214 list = serv->outbound_queue;
215 } else
217 list = list->next;
220 /* now try pri 0 */
221 pri--;
223 return 0; /* remove the timeout handler */
227 tcp_send_len (server *serv, char *buf, int len)
229 char *dbuf;
230 int noqueue = !serv->outbound_queue;
232 if (!prefs.throttle)
233 return server_send_real (serv, buf, len);
235 dbuf = malloc (len + 2); /* first byte is the priority */
236 dbuf[0] = 2; /* pri 2 for most things */
237 memcpy (dbuf + 1, buf, len);
238 dbuf[len + 1] = 0;
240 /* privmsg and notice get a lower priority */
241 if (strncasecmp (dbuf + 1, "PRIVMSG", 7) == 0 ||
242 strncasecmp (dbuf + 1, "NOTICE", 6) == 0)
244 dbuf[0] = 1;
246 else
248 /* WHO/MODE get the lowest priority */
249 if (strncasecmp (dbuf + 1, "WHO ", 4) == 0 ||
250 /* but only MODE queries, not changes */
251 (strncasecmp (dbuf + 1, "MODE", 4) == 0 &&
252 strchr (dbuf, '-') == NULL &&
253 strchr (dbuf, '+') == NULL))
254 dbuf[0] = 0;
257 serv->outbound_queue = g_slist_append (serv->outbound_queue, dbuf);
258 serv->sendq_len += len; /* tcp_send_queue uses strlen */
260 if (tcp_send_queue (serv) && noqueue)
261 fe_timeout_add (500, tcp_send_queue, serv);
263 return 1;
266 /*int
267 tcp_send (server *serv, char *buf)
269 return tcp_send_len (serv, buf, strlen (buf));
272 void
273 tcp_sendf (server *serv, char *fmt, ...)
275 va_list args;
276 /* keep this buffer in BSS. Converting UTF-8 to ISO-8859-x might make the
277 string shorter, so allow alot more than 512 for now. */
278 static char send_buf[1540]; /* good code hey (no it's not overflowable) */
279 int len;
281 va_start (args, fmt);
282 len = vsnprintf (send_buf, sizeof (send_buf) - 1, fmt, args);
283 va_end (args);
285 send_buf[sizeof (send_buf) - 1] = '\0';
286 if (len < 0 || len > (sizeof (send_buf) - 1))
287 len = strlen (send_buf);
289 tcp_send_len (serv, send_buf, len);
292 static int
293 close_socket_cb (gpointer sok)
295 closesocket (GPOINTER_TO_INT (sok));
296 return 0;
299 static void
300 close_socket (int sok)
302 /* close the socket in 5 seconds so the QUIT message is not lost */
303 fe_timeout_add (5000, close_socket_cb, GINT_TO_POINTER (sok));
306 /* handle 1 line of text received from the server */
308 static void
309 server_inline (server *serv, char *line, int len)
311 char *utf_line_allocated = NULL;
313 /* Checks whether we're set to use UTF-8 charset */
314 if (serv->using_irc || /* 1. using CP1252/UTF-8 Hybrid */
315 (serv->encoding == NULL && prefs.utf8_locale) || /* OR 2. using system default->UTF-8 */
316 (serv->encoding != NULL && /* OR 3. explicitly set to UTF-8 */
317 (strcasecmp (serv->encoding, "UTF8") == 0 ||
318 strcasecmp (serv->encoding, "UTF-8") == 0)))
320 /* The user has the UTF-8 charset set, either via /charset
321 command or from his UTF-8 locale. Thus, we first try the
322 UTF-8 charset, and if we fail to convert, we assume
323 it to be ISO-8859-1 (see text_validate). */
325 utf_line_allocated = text_validate (&line, &len);
327 } else
329 /* Since the user has an explicit charset set, either
330 via /charset command or from his non-UTF8 locale,
331 we don't fallback to ISO-8859-1 and instead try to remove
332 errnoeous octets till the string is convertable in the
333 said charset. */
335 const char *encoding = NULL;
337 if (serv->encoding != NULL)
338 encoding = serv->encoding;
339 else
340 g_get_charset (&encoding);
342 if (encoding != NULL)
344 char *conv_line; /* holds a copy of the original string */
345 int conv_len; /* tells g_convert how much of line to convert */
346 gsize utf_len;
347 gsize read_len;
348 GError *err;
349 gboolean retry;
351 conv_line = g_malloc (len + 1);
352 memcpy (conv_line, line, len);
353 conv_line[len] = 0;
354 conv_len = len;
356 /* if CP1255, convert it with the NUL terminator.
357 Works around SF bug #1122089 */
358 if (serv->using_cp1255)
359 conv_len++;
363 err = NULL;
364 retry = FALSE;
365 utf_line_allocated = g_convert_with_fallback (conv_line, conv_len, "UTF-8", encoding, "?", &read_len, &utf_len, &err);
366 if (err != NULL)
368 if (err->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE && conv_len > (read_len + 1))
370 /* Make our best bet by removing the erroneous char.
371 This will work for casual 8-bit strings with non-standard chars. */
372 memmove (conv_line + read_len, conv_line + read_len + 1, conv_len - read_len -1);
373 conv_len--;
374 retry = TRUE;
376 g_error_free (err);
378 } while (retry);
380 g_free (conv_line);
382 /* If any conversion has occured at all. Conversion might fail
383 due to errors other than invalid sequences, e.g. unknown charset. */
384 if (utf_line_allocated != NULL)
386 line = utf_line_allocated;
387 len = utf_len;
388 if (serv->using_cp1255 && len > 0)
389 len--;
391 else
393 /* If all fails, treat as UTF-8 with fallback to ISO-8859-1. */
394 utf_line_allocated = text_validate (&line, &len);
399 fe_add_rawlog (serv, line, len, FALSE);
401 /* let proto-irc.c handle it */
402 serv->p_inline (serv, line, len);
404 if (utf_line_allocated != NULL) /* only if a special copy was allocated */
405 g_free (utf_line_allocated);
408 /* read data from socket */
410 static gboolean
411 server_read (GIOChannel *source, GIOCondition condition, server *serv)
413 int sok = serv->sok;
414 int error, i, len;
415 char lbuf[2050];
417 while (1)
419 #ifdef USE_OPENSSL
420 if (!serv->ssl)
421 #endif
422 len = recv (sok, lbuf, sizeof (lbuf) - 2, 0);
423 #ifdef USE_OPENSSL
424 else
425 len = _SSL_recv (serv->ssl, lbuf, sizeof (lbuf) - 2);
426 #endif
427 if (len < 1)
429 error = 0;
430 if (len < 0)
432 if (would_block ())
433 return TRUE;
434 error = sock_error ();
436 if (!serv->end_of_motd)
438 server_disconnect (serv->server_session, FALSE, error);
439 if (!servlist_cycle (serv))
441 if (prefs.autoreconnect)
442 auto_reconnect (serv, FALSE, error);
444 } else
446 if (prefs.autoreconnect)
447 auto_reconnect (serv, FALSE, error);
448 else
449 server_disconnect (serv->server_session, FALSE, error);
451 return TRUE;
454 i = 0;
456 lbuf[len] = 0;
458 while (i < len)
460 switch (lbuf[i])
462 case '\r':
463 break;
465 case '\n':
466 serv->linebuf[serv->pos] = 0;
467 server_inline (serv, serv->linebuf, serv->pos);
468 serv->pos = 0;
469 break;
471 default:
472 serv->linebuf[serv->pos] = lbuf[i];
473 if (serv->pos >= (sizeof (serv->linebuf) - 1))
474 fprintf (stderr,
475 "*** XCHAT WARNING: Buffer overflow - shit server!\n");
476 else
477 serv->pos++;
479 i++;
484 static void
485 server_connected (server * serv)
487 prefs.wait_on_exit = TRUE;
488 serv->ping_recv = time (0);
489 serv->connected = TRUE;
490 set_nonblocking (serv->sok);
491 serv->iotag = fe_input_add (serv->sok, FIA_READ|FIA_EX, server_read, serv);
492 if (!serv->no_login)
494 EMIT_SIGNAL (XP_TE_CONNECTED, serv->server_session, NULL, NULL, NULL,
495 NULL, 0);
496 if (serv->network)
498 serv->p_login (serv,
499 (!(((ircnet *)serv->network)->flags & FLAG_USE_GLOBAL) &&
500 (((ircnet *)serv->network)->user)) ?
501 (((ircnet *)serv->network)->user) :
502 prefs.username,
503 (!(((ircnet *)serv->network)->flags & FLAG_USE_GLOBAL) &&
504 (((ircnet *)serv->network)->real)) ?
505 (((ircnet *)serv->network)->real) :
506 prefs.realname);
507 } else
509 serv->p_login (serv, prefs.username, prefs.realname);
511 } else
513 EMIT_SIGNAL (XP_TE_SERVERCONNECTED, serv->server_session, NULL, NULL,
514 NULL, NULL, 0);
517 server_set_name (serv, serv->servername);
518 fe_server_event (serv, FE_SE_CONNECT, 0);
521 #ifdef WIN32
523 static gboolean
524 server_close_pipe (int *pipefd) /* see comments below */
526 close (pipefd[0]); /* close WRITE end first to cause an EOF on READ */
527 close (pipefd[1]); /* in giowin32, and end that thread. */
528 free (pipefd);
529 return FALSE;
532 #endif
534 static void
535 server_stopconnecting (server * serv)
537 if (serv->iotag)
539 fe_input_remove (serv->iotag);
540 serv->iotag = 0;
543 if (serv->joindelay_tag)
545 fe_timeout_remove (serv->joindelay_tag);
546 serv->joindelay_tag = 0;
549 #ifndef WIN32
550 /* kill the child process trying to connect */
551 kill (serv->childpid, SIGKILL);
552 waitpid (serv->childpid, NULL, 0);
554 close (serv->childwrite);
555 close (serv->childread);
556 #else
557 PostThreadMessage (serv->childpid, WM_QUIT, 0, 0);
560 /* if we close the pipe now, giowin32 will crash. */
561 int *pipefd = malloc (sizeof (int) * 2);
562 pipefd[0] = serv->childwrite;
563 pipefd[1] = serv->childread;
564 g_idle_add ((GSourceFunc)server_close_pipe, pipefd);
566 #endif
568 #ifdef USE_OPENSSL
569 if (serv->ssl_do_connect_tag)
571 fe_timeout_remove (serv->ssl_do_connect_tag);
572 serv->ssl_do_connect_tag = 0;
574 #endif
576 fe_progressbar_end (serv);
578 serv->connecting = FALSE;
579 fe_server_event (serv, FE_SE_DISCONNECT, 0);
582 #ifdef USE_OPENSSL
583 #define SSLTMOUT 90 /* seconds */
584 static void
585 ssl_cb_info (SSL * s, int where, int ret)
587 /* char buf[128];*/
590 return; /* FIXME: make debug level adjustable in serverlist or settings */
592 /* snprintf (buf, sizeof (buf), "%s (%d)", SSL_state_string_long (s), where);
593 if (g_sess)
594 EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
595 else
596 fprintf (stderr, "%s\n", buf);*/
599 static int
600 ssl_cb_verify (int ok, X509_STORE_CTX * ctx)
602 char subject[256];
603 char issuer[256];
604 char buf[512];
607 X509_NAME_oneline (X509_get_subject_name (ctx->current_cert), subject,
608 sizeof (subject));
609 X509_NAME_oneline (X509_get_issuer_name (ctx->current_cert), issuer,
610 sizeof (issuer));
612 snprintf (buf, sizeof (buf), "* Subject: %s", subject);
613 EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
614 snprintf (buf, sizeof (buf), "* Issuer: %s", issuer);
615 EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
617 return (TRUE); /* always ok */
620 static int
621 ssl_do_connect (server * serv)
623 char buf[128];
625 g_sess = serv->server_session;
626 if (SSL_connect (serv->ssl) <= 0)
628 char err_buf[128];
629 int err;
631 g_sess = NULL;
632 if ((err = ERR_get_error ()) > 0)
634 ERR_error_string (err, err_buf);
635 snprintf (buf, sizeof (buf), "(%d) %s", err, err_buf);
636 EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, buf, NULL,
637 NULL, NULL, 0);
639 if (ERR_GET_REASON (err) == SSL_R_WRONG_VERSION_NUMBER)
640 PrintText (serv->server_session, _("Are you sure this is a SSL capable server and port?\n"));
642 server_cleanup (serv);
644 if (prefs.autoreconnectonfail)
645 auto_reconnect (serv, FALSE, -1);
647 return (0); /* remove it (0) */
650 g_sess = NULL;
652 if (SSL_is_init_finished (serv->ssl))
654 struct cert_info cert_info;
655 struct chiper_info *chiper_info;
656 int verify_error;
657 int i;
659 if (!_SSL_get_cert_info (&cert_info, serv->ssl))
661 snprintf (buf, sizeof (buf), "* Certification info:");
662 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
663 NULL, 0);
664 snprintf (buf, sizeof (buf), " Subject:");
665 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
666 NULL, 0);
667 for (i = 0; cert_info.subject_word[i]; i++)
669 snprintf (buf, sizeof (buf), " %s", cert_info.subject_word[i]);
670 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
671 NULL, 0);
673 snprintf (buf, sizeof (buf), " Issuer:");
674 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
675 NULL, 0);
676 for (i = 0; cert_info.issuer_word[i]; i++)
678 snprintf (buf, sizeof (buf), " %s", cert_info.issuer_word[i]);
679 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
680 NULL, 0);
682 snprintf (buf, sizeof (buf), " Public key algorithm: %s (%d bits)",
683 cert_info.algorithm, cert_info.algorithm_bits);
684 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
685 NULL, 0);
686 /*if (cert_info.rsa_tmp_bits)
688 snprintf (buf, sizeof (buf),
689 " Public key algorithm uses ephemeral key with %d bits",
690 cert_info.rsa_tmp_bits);
691 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
692 NULL, 0);
694 snprintf (buf, sizeof (buf), " Sign algorithm %s",
695 cert_info.sign_algorithm/*, cert_info.sign_algorithm_bits*/);
696 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
697 NULL, 0);
698 snprintf (buf, sizeof (buf), " Valid since %s to %s",
699 cert_info.notbefore, cert_info.notafter);
700 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
701 NULL, 0);
702 } else
704 snprintf (buf, sizeof (buf), " * No Certificate");
705 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
706 NULL, 0);
709 chiper_info = _SSL_get_cipher_info (serv->ssl); /* static buffer */
710 snprintf (buf, sizeof (buf), "* Cipher info:");
711 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL,
713 snprintf (buf, sizeof (buf), " Version: %s, cipher %s (%u bits)",
714 chiper_info->version, chiper_info->chiper,
715 chiper_info->chiper_bits);
716 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL,
719 verify_error = SSL_get_verify_result (serv->ssl);
720 switch (verify_error)
722 case X509_V_OK:
723 /* snprintf (buf, sizeof (buf), "* Verify OK (?)"); */
724 /* EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL, 0); */
725 break;
726 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
727 case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
728 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
729 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
730 case X509_V_ERR_CERT_HAS_EXPIRED:
731 case X509_V_ERR_CERT_UNTRUSTED:
732 if (serv->accept_invalid_cert)
734 snprintf (buf, sizeof (buf), "* Verify E: %s.? (%d) -- Ignored",
735 X509_verify_cert_error_string (verify_error),
736 verify_error);
737 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
738 NULL, 0);
739 break;
741 default:
742 snprintf (buf, sizeof (buf), "%s.? (%d)",
743 X509_verify_cert_error_string (verify_error),
744 verify_error);
745 EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, buf, NULL, NULL,
746 NULL, 0);
748 server_cleanup (serv);
750 return (0);
753 server_stopconnecting (serv);
755 /* activate gtk poll */
756 server_connected (serv);
758 return (0); /* remove it (0) */
759 } else
761 if (serv->ssl->session && serv->ssl->session->time + SSLTMOUT < time (NULL))
763 snprintf (buf, sizeof (buf), "SSL handshake timed out");
764 EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, buf, NULL,
765 NULL, NULL, 0);
766 server_cleanup (serv); /* ->connecting = FALSE */
768 if (prefs.autoreconnectonfail)
769 auto_reconnect (serv, FALSE, -1);
771 return (0); /* remove it (0) */
774 return (1); /* call it more (1) */
777 #endif
779 static int
780 timeout_auto_reconnect (server *serv)
782 if (is_server (serv)) /* make sure it hasnt been closed during the delay */
784 serv->recondelay_tag = 0;
785 if (!serv->connected && !serv->connecting && serv->server_session)
787 server_connect (serv, serv->hostname, serv->port, FALSE);
790 return 0; /* returning 0 should remove the timeout handler */
793 static void
794 auto_reconnect (server *serv, int send_quit, int err)
796 session *s;
797 GSList *list;
798 int del;
800 if (serv->server_session == NULL)
801 return;
803 list = sess_list;
804 while (list) /* make sure auto rejoin can work */
806 s = list->data;
807 if (s->type == SESS_CHANNEL && s->channel[0])
809 strcpy (s->waitchannel, s->channel);
810 strcpy (s->willjoinchannel, s->channel);
812 list = list->next;
815 if (serv->connected)
816 server_disconnect (serv->server_session, send_quit, err);
818 del = prefs.recon_delay * 1000;
819 if (del < 1000)
820 del = 500; /* so it doesn't block the gui */
822 #ifndef WIN32
823 if (err == -1 || err == 0 || err == ECONNRESET || err == ETIMEDOUT)
824 #else
825 if (err == -1 || err == 0 || err == WSAECONNRESET || err == WSAETIMEDOUT)
826 #endif
827 serv->reconnect_away = serv->is_away;
829 /* is this server in a reconnect delay? remove it! */
830 if (serv->recondelay_tag)
832 fe_timeout_remove (serv->recondelay_tag);
833 serv->recondelay_tag = 0;
836 serv->recondelay_tag = fe_timeout_add (del, timeout_auto_reconnect, serv);
837 fe_server_event (serv, FE_SE_RECONDELAY, del);
840 static void
841 server_flush_queue (server *serv)
843 list_free (&serv->outbound_queue);
844 serv->sendq_len = 0;
845 fe_set_throttle (serv);
848 #define waitline2(source,buf,size) waitline(serv->childread,buf,size,0)
850 /* connect() successed */
852 static void
853 server_connect_success (server *serv)
855 #ifdef USE_OPENSSL
856 #define SSLDOCONNTMOUT 300
857 if (serv->use_ssl)
859 char *err;
861 /* it'll be a memory leak, if connection isn't terminated by
862 server_cleanup() */
863 serv->ssl = _SSL_socket (ctx, serv->sok);
864 if ((err = _SSL_set_verify (ctx, ssl_cb_verify, NULL)) && !serv->accept_invalid_cert)
866 EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, err, NULL,
867 NULL, NULL, 0);
868 server_cleanup (serv); /* ->connecting = FALSE */
869 return;
871 /* FIXME: it'll be needed by new servers */
872 /* send(serv->sok, "STLS\r\n", 6, 0); sleep(1); */
873 set_nonblocking (serv->sok);
874 serv->ssl_do_connect_tag = fe_timeout_add (SSLDOCONNTMOUT,
875 ssl_do_connect, serv);
876 return;
879 serv->ssl = NULL;
880 #endif
881 server_stopconnecting (serv); /* ->connecting = FALSE */
882 /* activate glib poll */
883 server_connected (serv);
886 /* receive info from the child-process about connection progress */
888 static gboolean
889 server_read_child (GIOChannel *source, GIOCondition condition, server *serv)
891 session *sess = serv->server_session;
892 char tbuf[128];
893 char outbuf[512];
894 char host[100];
895 char ip[100];
896 char *p;
898 waitline2 (source, tbuf, sizeof tbuf);
900 switch (tbuf[0])
902 case '0': /* print some text */
903 waitline2 (source, tbuf, sizeof tbuf);
904 PrintText (serv->server_session, tbuf);
905 break;
906 case '1': /* unknown host */
907 server_stopconnecting (serv);
908 closesocket (serv->sok4);
909 if (serv->proxy_sok4 != -1)
910 closesocket (serv->proxy_sok4);
911 #ifdef USE_IPV6
912 if (serv->sok6 != -1)
913 closesocket (serv->sok6);
914 if (serv->proxy_sok6 != -1)
915 closesocket (serv->proxy_sok6);
916 #endif
917 EMIT_SIGNAL (XP_TE_UKNHOST, sess, NULL, NULL, NULL, NULL, 0);
918 if (!servlist_cycle (serv))
919 if (prefs.autoreconnectonfail)
920 auto_reconnect (serv, FALSE, -1);
921 break;
922 case '2': /* connection failed */
923 waitline2 (source, tbuf, sizeof tbuf);
924 server_stopconnecting (serv);
925 closesocket (serv->sok4);
926 if (serv->proxy_sok4 != -1)
927 closesocket (serv->proxy_sok4);
928 #ifdef USE_IPV6
929 if (serv->sok6 != -1)
930 closesocket (serv->sok6);
931 if (serv->proxy_sok6 != -1)
932 closesocket (serv->proxy_sok6);
933 #endif
934 EMIT_SIGNAL (XP_TE_CONNFAIL, sess, errorstring (atoi (tbuf)), NULL,
935 NULL, NULL, 0);
936 if (!servlist_cycle (serv))
937 if (prefs.autoreconnectonfail)
938 auto_reconnect (serv, FALSE, -1);
939 break;
940 case '3': /* gethostbyname finished */
941 waitline2 (source, host, sizeof host);
942 waitline2 (source, ip, sizeof ip);
943 waitline2 (source, outbuf, sizeof outbuf);
944 EMIT_SIGNAL (XP_TE_CONNECT, sess, host, ip, outbuf, NULL, 0);
945 #ifdef WIN32
946 if (prefs.identd)
948 if (serv->network)
949 identd_start ((((ircnet *)serv->network)->user) ?
950 (((ircnet *)serv->network)->user) :
951 prefs.username);
952 else
953 identd_start (prefs.username);
955 #else
956 snprintf (outbuf, sizeof (outbuf), "%s/auth/xchat_auth",
957 g_get_home_dir ());
958 if (access (outbuf, X_OK) == 0)
960 snprintf (outbuf, sizeof (outbuf), "exec -d %s/auth/xchat_auth %s",
961 g_get_home_dir (), prefs.username);
962 handle_command (serv->server_session, outbuf, FALSE);
964 #endif
965 break;
966 case '4': /* success */
967 waitline2 (source, tbuf, sizeof (tbuf));
968 #ifdef USE_MSPROXY
969 serv->sok = strtol (tbuf, &p, 10);
970 if (*p++ == ' ')
972 serv->proxy_sok = strtol (p, &p, 10);
973 serv->msp_state.clientid = strtol (++p, &p, 10);
974 serv->msp_state.serverid = strtol (++p, &p, 10);
975 serv->msp_state.seq_sent = atoi (++p);
976 } else
977 serv->proxy_sok = -1;
978 #ifdef DEBUG_MSPROXY
979 printf ("Parent got main socket: %d, proxy socket: %d\n", serv->sok, serv->proxy_sok);
980 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);
981 #endif
982 #else
983 serv->sok = atoi (tbuf);
984 #endif
985 #ifdef USE_IPV6
986 /* close the one we didn't end up using */
987 if (serv->sok == serv->sok4)
988 closesocket (serv->sok6);
989 else
990 closesocket (serv->sok4);
991 if (serv->proxy_sok != -1)
993 if (serv->proxy_sok == serv->proxy_sok4)
994 closesocket (serv->proxy_sok6);
995 else
996 closesocket (serv->proxy_sok4);
998 #endif
999 server_connect_success (serv);
1000 break;
1001 case '5': /* prefs ip discovered */
1002 waitline2 (source, tbuf, sizeof tbuf);
1003 prefs.local_ip = inet_addr (tbuf);
1004 break;
1005 case '7': /* gethostbyname (prefs.hostname) failed */
1006 sprintf (outbuf,
1007 _("Cannot resolve hostname %s\nCheck your IP Settings!\n"),
1008 prefs.hostname);
1009 PrintText (sess, outbuf);
1010 break;
1011 case '8':
1012 PrintText (sess, _("Proxy traversal failed.\n"));
1013 server_disconnect (sess, FALSE, -1);
1014 break;
1015 case '9':
1016 waitline2 (source, tbuf, sizeof tbuf);
1017 EMIT_SIGNAL (XP_TE_SERVERLOOKUP, sess, tbuf, NULL, NULL, NULL, 0);
1018 break;
1021 return TRUE;
1024 /* kill all sockets & iotags of a server. Stop a connection attempt, or
1025 disconnect if already connected. */
1027 static int
1028 server_cleanup (server * serv)
1030 fe_set_lag (serv, 0.0);
1032 if (serv->iotag)
1034 fe_input_remove (serv->iotag);
1035 serv->iotag = 0;
1038 if (serv->joindelay_tag)
1040 fe_timeout_remove (serv->joindelay_tag);
1041 serv->joindelay_tag = 0;
1044 #ifdef USE_OPENSSL
1045 if (serv->ssl)
1047 _SSL_close (serv->ssl);
1048 serv->ssl = NULL;
1050 #endif
1052 if (serv->connecting)
1054 server_stopconnecting (serv);
1055 closesocket (serv->sok4);
1056 if (serv->proxy_sok4 != -1)
1057 closesocket (serv->proxy_sok4);
1058 if (serv->sok6 != -1)
1059 closesocket (serv->sok6);
1060 if (serv->proxy_sok6 != -1)
1061 closesocket (serv->proxy_sok6);
1062 return 1;
1065 if (serv->connected)
1067 close_socket (serv->sok);
1068 if (serv->proxy_sok)
1069 close_socket (serv->proxy_sok);
1070 serv->connected = FALSE;
1071 serv->end_of_motd = FALSE;
1072 return 2;
1075 /* is this server in a reconnect delay? remove it! */
1076 if (serv->recondelay_tag)
1078 fe_timeout_remove (serv->recondelay_tag);
1079 serv->recondelay_tag = 0;
1080 return 3;
1083 return 0;
1086 static void
1087 server_disconnect (session * sess, int sendquit, int err)
1089 server *serv = sess->server;
1090 GSList *list;
1091 char tbuf[64];
1092 gboolean shutup = FALSE;
1094 /* send our QUIT reason */
1095 if (sendquit && serv->connected)
1097 server_sendquit (sess);
1100 fe_server_event (serv, FE_SE_DISCONNECT, 0);
1102 /* close all sockets & io tags */
1103 switch (server_cleanup (serv))
1105 case 0: /* it wasn't even connected! */
1106 notc_msg (sess);
1107 return;
1108 case 1: /* it was in the process of connecting */
1109 sprintf (tbuf, "%d", sess->server->childpid);
1110 EMIT_SIGNAL (XP_TE_STOPCONNECT, sess, tbuf, NULL, NULL, NULL, 0);
1111 return;
1112 case 3:
1113 shutup = TRUE; /* won't print "disconnected" in channels */
1116 server_flush_queue (serv);
1118 list = sess_list;
1119 while (list)
1121 sess = (struct session *) list->data;
1122 if (sess->server == serv)
1124 if (!shutup || sess->type == SESS_SERVER)
1125 /* print "Disconnected" to each window using this server */
1126 EMIT_SIGNAL (XP_TE_DISCON, sess, errorstring (err), NULL, NULL, NULL, 0);
1128 if (!sess->channel[0] || sess->type == SESS_CHANNEL)
1129 clear_channel (sess);
1131 list = list->next;
1134 serv->pos = 0;
1135 serv->motd_skipped = FALSE;
1136 serv->no_login = FALSE;
1137 serv->servername[0] = 0;
1138 serv->lag_sent = 0;
1140 notify_cleanup ();
1143 /* send a "print text" command to the parent process - MUST END IN \n! */
1145 static void
1146 proxy_error (int fd, char *msg)
1148 write (fd, "0\n", 2);
1149 write (fd, msg, strlen (msg));
1152 struct sock_connect
1154 char version;
1155 char type;
1156 guint16 port;
1157 guint32 address;
1158 char username[10];
1161 /* traverse_socks() returns:
1162 * 0 success *
1163 * 1 socks traversal failed */
1165 static int
1166 traverse_socks (int print_fd, int sok, char *serverAddr, int port)
1168 struct sock_connect sc;
1169 unsigned char buf[256];
1171 sc.version = 4;
1172 sc.type = 1;
1173 sc.port = htons (port);
1174 sc.address = inet_addr (serverAddr);
1175 strncpy (sc.username, prefs.username, 9);
1177 send (sok, (char *) &sc, 8 + strlen (sc.username) + 1, 0);
1178 buf[1] = 0;
1179 recv (sok, buf, 10, 0);
1180 if (buf[1] == 90)
1181 return 0;
1183 snprintf (buf, sizeof (buf), "SOCKS\tServer reported error %d,%d.\n", buf[0], buf[1]);
1184 proxy_error (print_fd, buf);
1185 return 1;
1188 struct sock5_connect1
1190 char version;
1191 char nmethods;
1192 char method;
1195 static int
1196 traverse_socks5 (int print_fd, int sok, char *serverAddr, int port)
1198 struct sock5_connect1 sc1;
1199 unsigned char *sc2;
1200 unsigned int packetlen, addrlen;
1201 unsigned char buf[260];
1202 int auth = prefs.proxy_auth && prefs.proxy_user[0] && prefs.proxy_pass[0];
1204 sc1.version = 5;
1205 sc1.nmethods = 1;
1206 if (auth)
1207 sc1.method = 2; /* Username/Password Authentication (UPA) */
1208 else
1209 sc1.method = 0; /* NO Authentication */
1210 send (sok, (char *) &sc1, 3, 0);
1211 if (recv (sok, buf, 2, 0) != 2)
1212 goto read_error;
1214 if (buf[0] != 5)
1216 proxy_error (print_fd, "SOCKS\tServer is not socks version 5.\n");
1217 return 1;
1220 /* did the server say no auth required? */
1221 if (buf[1] == 0)
1222 auth = 0;
1224 if (auth)
1226 int len_u=0, len_p=0;
1228 /* authentication sub-negotiation (RFC1929) */
1229 if (buf[1] != 2) /* UPA not supported by server */
1231 proxy_error (print_fd, "SOCKS\tServer doesn't support UPA authentication.\n");
1232 return 1;
1235 memset (buf, 0, sizeof(buf));
1237 /* form the UPA request */
1238 len_u = strlen (prefs.proxy_user);
1239 len_p = strlen (prefs.proxy_pass);
1240 buf[0] = 1;
1241 buf[1] = len_u;
1242 memcpy (buf + 2, prefs.proxy_user, len_u);
1243 buf[2 + len_u] = len_p;
1244 memcpy (buf + 3 + len_u, prefs.proxy_pass, len_p);
1246 send (sok, buf, 3 + len_u + len_p, 0);
1247 if ( recv (sok, buf, 2, 0) != 2 )
1248 goto read_error;
1249 if ( buf[1] != 0 )
1251 proxy_error (print_fd, "SOCKS\tAuthentication failed. "
1252 "Is username and password correct?\n");
1253 return 1; /* UPA failed! */
1256 else
1258 if (buf[1] != 0)
1260 proxy_error (print_fd, "SOCKS\tAuthentication required but disabled in settings.\n");
1261 return 1;
1265 addrlen = strlen (serverAddr);
1266 packetlen = 4 + 1 + addrlen + 2;
1267 sc2 = malloc (packetlen);
1268 sc2[0] = 5; /* version */
1269 sc2[1] = 1; /* command */
1270 sc2[2] = 0; /* reserved */
1271 sc2[3] = 3; /* address type */
1272 sc2[4] = (unsigned char) addrlen; /* hostname length */
1273 memcpy (sc2 + 5, serverAddr, addrlen);
1274 *((unsigned short *) (sc2 + 5 + addrlen)) = htons (port);
1275 send (sok, sc2, packetlen, 0);
1276 free (sc2);
1278 /* consume all of the reply */
1279 if (recv (sok, buf, 4, 0) != 4)
1280 goto read_error;
1281 if (buf[0] != 5 || buf[1] != 0)
1283 if (buf[1] == 2)
1284 snprintf (buf, sizeof (buf), "SOCKS\tProxy refused to connect to host (not allowed).\n");
1285 else
1286 snprintf (buf, sizeof (buf), "SOCKS\tProxy failed to connect to host (error %d).\n", buf[1]);
1287 proxy_error (print_fd, buf);
1288 return 1;
1290 if (buf[3] == 1) /* IPV4 32bit address */
1292 if (recv (sok, buf, 6, 0) != 6)
1293 goto read_error;
1294 } else if (buf[3] == 4) /* IPV6 128bit address */
1296 if (recv (sok, buf, 18, 0) != 18)
1297 goto read_error;
1298 } else if (buf[3] == 3) /* string, 1st byte is size */
1300 if (recv (sok, buf, 1, 0) != 1) /* read the string size */
1301 goto read_error;
1302 packetlen = buf[0] + 2; /* can't exceed 260 */
1303 if (recv (sok, buf, packetlen, 0) != packetlen)
1304 goto read_error;
1307 return 0; /* success */
1309 read_error:
1310 proxy_error (print_fd, "SOCKS\tRead error from server.\n");
1311 return 1;
1314 static int
1315 traverse_wingate (int print_fd, int sok, char *serverAddr, int port)
1317 char buf[128];
1319 snprintf (buf, sizeof (buf), "%s %d\r\n", serverAddr, port);
1320 send (sok, buf, strlen (buf), 0);
1322 return 0;
1325 /* stuff for HTTP auth is here */
1327 static void
1328 three_to_four (char *from, char *to)
1330 static const char tab64[64]=
1332 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
1333 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
1334 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
1335 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
1338 to[0] = tab64 [ (from[0] >> 2) & 63 ];
1339 to[1] = tab64 [ ((from[0] << 4) | (from[1] >> 4)) & 63 ];
1340 to[2] = tab64 [ ((from[1] << 2) | (from[2] >> 6)) & 63 ];
1341 to[3] = tab64 [ from[2] & 63 ];
1344 void
1345 base64_encode (char *to, char *from, unsigned int len)
1347 while (len >= 3)
1349 three_to_four (from, to);
1350 len -= 3;
1351 from += 3;
1352 to += 4;
1354 if (len)
1356 char three[3]={0,0,0};
1357 int i=0;
1358 for (i=0;i<len;i++)
1359 three[i] = *from++;
1360 three_to_four (three, to);
1361 if (len == 1)
1362 to[2] = to[3] = '=';
1363 else if (len == 2)
1364 to[3] = '=';
1365 to += 4;
1367 to[0] = 0;
1370 static int
1371 http_read_line (int print_fd, int sok, char *buf, int len)
1373 #ifdef WIN32
1374 /* make sure waitline() uses recv() or it'll fail on win32 */
1375 len = waitline (sok, buf, len, FALSE);
1376 #else
1377 len = waitline (sok, buf, len, TRUE);
1378 #endif
1379 if (len >= 1)
1381 /* print the message out (send it to the parent process) */
1382 write (print_fd, "0\n", 2);
1384 if (buf[len-1] == '\r')
1386 buf[len-1] = '\n';
1387 write (print_fd, buf, len);
1388 } else
1390 write (print_fd, buf, len);
1391 write (print_fd, "\n", 1);
1395 return len;
1398 static int
1399 traverse_http (int print_fd, int sok, char *serverAddr, int port)
1401 char buf[512];
1402 char auth_data[256];
1403 char auth_data2[252];
1404 int n, n2;
1406 n = snprintf (buf, sizeof (buf), "CONNECT %s:%d HTTP/1.0\r\n",
1407 serverAddr, port);
1408 if (prefs.proxy_auth)
1410 n2 = snprintf (auth_data2, sizeof (auth_data2), "%s:%s",
1411 prefs.proxy_user, prefs.proxy_pass);
1412 base64_encode (auth_data, auth_data2, n2);
1413 n += snprintf (buf+n, sizeof (buf)-n, "Proxy-Authorization: Basic %s\r\n", auth_data);
1415 n += snprintf (buf+n, sizeof (buf)-n, "\r\n");
1416 send (sok, buf, n, 0);
1418 n = http_read_line (print_fd, sok, buf, sizeof (buf));
1419 /* "HTTP/1.0 200 OK" */
1420 if (n < 12)
1421 return 1;
1422 if (memcmp (buf, "HTTP/", 5) || memcmp (buf + 9, "200", 3))
1423 return 1;
1424 while (1)
1426 /* read until blank line */
1427 n = http_read_line (print_fd, sok, buf, sizeof (buf));
1428 if (n < 1 || (n == 1 && buf[0] == '\n'))
1429 break;
1431 return 0;
1434 static int
1435 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)
1437 switch (proxy_type)
1439 case 1:
1440 return traverse_wingate (print_fd, sok, ip, port);
1441 case 2:
1442 return traverse_socks (print_fd, sok, ip, port);
1443 case 3:
1444 return traverse_socks5 (print_fd, sok, ip, port);
1445 case 4:
1446 return traverse_http (print_fd, sok, ip, port);
1447 #ifdef USE_MSPROXY
1448 case 5:
1449 return traverse_msproxy (sok, ip, port, state, ns_proxy, csok4, csok6, csok, bound);
1450 #endif
1453 return 1;
1456 /* this is the child process making the connection attempt */
1458 static int
1459 server_child (server * serv)
1461 netstore *ns_server;
1462 netstore *ns_proxy = NULL;
1463 netstore *ns_local;
1464 int port = serv->port;
1465 int error;
1466 int sok, psok;
1467 char *hostname = serv->hostname;
1468 char *real_hostname = NULL;
1469 char *ip;
1470 char *proxy_ip = NULL;
1471 char *local_ip;
1472 int connect_port;
1473 char buf[512];
1474 char bound = 0;
1475 int proxy_type = 0;
1476 char *proxy_host = NULL;
1477 int proxy_port;
1479 ns_server = net_store_new ();
1481 /* is a hostname set? - bind to it */
1482 if (prefs.hostname[0])
1484 ns_local = net_store_new ();
1485 local_ip = net_resolve (ns_local, prefs.hostname, 0, &real_hostname);
1486 if (local_ip != NULL)
1488 snprintf (buf, sizeof (buf), "5\n%s\n", local_ip);
1489 write (serv->childwrite, buf, strlen (buf));
1490 net_bind (ns_local, serv->sok4, serv->sok6);
1491 bound = 1;
1492 } else
1494 write (serv->childwrite, "7\n", 2);
1496 net_store_destroy (ns_local);
1499 if (!serv->dont_use_proxy) /* blocked in serverlist? */
1501 if (FALSE)
1503 #ifdef USE_LIBPROXY
1504 else if (prefs.proxy_type == 5)
1506 char **proxy_list;
1507 char *url, *proxy;
1509 url = g_strdup_printf ("irc://%s:%d", hostname, port);
1510 proxy_list = px_proxy_factory_get_proxies (libproxy_factory, url);
1512 if (proxy_list) {
1513 /* can use only one */
1514 proxy = proxy_list[0];
1515 if (!strncmp (proxy, "direct", 6))
1516 proxy_type = 0;
1517 else if (!strncmp (proxy, "http", 4))
1518 proxy_type = 4;
1519 else if (!strncmp (proxy, "socks5", 6))
1520 proxy_type = 3;
1521 else if (!strncmp (proxy, "socks", 5))
1522 proxy_type = 2;
1525 if (proxy_type) {
1526 char *c;
1527 c = strchr (proxy, ':') + 3;
1528 proxy_host = strdup (c);
1529 c = strchr (proxy_host, ':');
1530 *c = '\0';
1531 proxy_port = atoi (c + 1);
1534 g_strfreev (proxy_list);
1535 g_free (url);
1537 #endif
1538 else if (prefs.proxy_host[0] &&
1539 prefs.proxy_type > 0 &&
1540 prefs.proxy_use != 2) /* proxy is NOT dcc-only */
1542 proxy_type = prefs.proxy_type;
1543 proxy_host = strdup (prefs.proxy_host);
1544 proxy_port = prefs.proxy_port;
1548 serv->proxy_type = proxy_type;
1550 /* first resolve where we want to connect to */
1551 if (proxy_type > 0)
1553 snprintf (buf, sizeof (buf), "9\n%s\n", proxy_host);
1554 write (serv->childwrite, buf, strlen (buf));
1555 ip = net_resolve (ns_server, proxy_host, proxy_port, &real_hostname);
1556 free (proxy_host);
1557 if (!ip)
1559 write (serv->childwrite, "1\n", 2);
1560 goto xit;
1562 connect_port = proxy_port;
1564 /* if using socks4 or MS Proxy, attempt to resolve ip for irc server */
1565 if ((proxy_type == 2) || (proxy_type == 5))
1567 ns_proxy = net_store_new ();
1568 proxy_ip = net_resolve (ns_proxy, hostname, port, &real_hostname);
1569 if (!proxy_ip)
1571 write (serv->childwrite, "1\n", 2);
1572 goto xit;
1574 } else /* otherwise we can just use the hostname */
1575 proxy_ip = strdup (hostname);
1576 } else
1578 ip = net_resolve (ns_server, hostname, port, &real_hostname);
1579 if (!ip)
1581 write (serv->childwrite, "1\n", 2);
1582 goto xit;
1584 connect_port = port;
1587 snprintf (buf, sizeof (buf), "3\n%s\n%s\n%d\n",
1588 real_hostname, ip, connect_port);
1589 write (serv->childwrite, buf, strlen (buf));
1591 if (!serv->dont_use_proxy && (proxy_type == 5))
1592 error = net_connect (ns_server, serv->proxy_sok4, serv->proxy_sok6, &psok);
1593 else
1595 error = net_connect (ns_server, serv->sok4, serv->sok6, &sok);
1596 psok = sok;
1599 if (error != 0)
1601 snprintf (buf, sizeof (buf), "2\n%d\n", sock_error ());
1602 write (serv->childwrite, buf, strlen (buf));
1603 } else
1605 /* connect succeeded */
1606 if (proxy_ip)
1608 switch (traverse_proxy (proxy_type, serv->childwrite, psok, proxy_ip, port, &serv->msp_state, ns_proxy, serv->sok4, serv->sok6, &sok, bound))
1610 case 0: /* success */
1611 #ifdef USE_MSPROXY
1612 if (!serv->dont_use_proxy && (proxy_type == 5))
1613 snprintf (buf, sizeof (buf), "4\n%d %d %d %d %d\n", sok, psok, serv->msp_state.clientid, serv->msp_state.serverid,
1614 serv->msp_state.seq_sent);
1615 else
1616 #endif
1617 snprintf (buf, sizeof (buf), "4\n%d\n", sok); /* success */
1618 write (serv->childwrite, buf, strlen (buf));
1619 break;
1620 case 1: /* socks traversal failed */
1621 write (serv->childwrite, "8\n", 2);
1622 break;
1624 } else
1626 snprintf (buf, sizeof (buf), "4\n%d\n", sok); /* success */
1627 write (serv->childwrite, buf, strlen (buf));
1631 xit:
1633 #if defined (USE_IPV6) || defined (WIN32)
1634 /* this is probably not needed */
1635 net_store_destroy (ns_server);
1636 if (ns_proxy)
1637 net_store_destroy (ns_proxy);
1638 #endif
1640 /* no need to free ip/real_hostname, this process is exiting */
1641 #ifdef WIN32
1642 /* under win32 we use a thread -> shared memory, must free! */
1643 if (proxy_ip)
1644 free (proxy_ip);
1645 if (ip)
1646 free (ip);
1647 if (real_hostname)
1648 free (real_hostname);
1649 #endif
1651 return 0;
1654 static void
1655 server_connect (server *serv, char *hostname, int port, int no_login)
1657 int pid, read_des[2];
1658 session *sess = serv->server_session;
1660 #ifdef USE_OPENSSL
1661 if (!ctx && serv->use_ssl)
1663 if (!(ctx = _SSL_context_init (ssl_cb_info, FALSE)))
1665 fprintf (stderr, "_SSL_context_init failed\n");
1666 exit (1);
1669 #endif
1671 if (!hostname[0])
1672 return;
1674 if (port < 0)
1676 /* use default port for this server type */
1677 port = 6667;
1678 #ifdef USE_OPENSSL
1679 if (serv->use_ssl)
1680 port = 9999;
1681 #endif
1683 port &= 0xffff; /* wrap around */
1685 if (serv->connected || serv->connecting || serv->recondelay_tag)
1686 server_disconnect (sess, TRUE, -1);
1688 fe_progressbar_start (sess);
1690 EMIT_SIGNAL (XP_TE_SERVERLOOKUP, sess, hostname, NULL, NULL, NULL, 0);
1692 safe_strcpy (serv->servername, hostname, sizeof (serv->servername));
1693 /* overlap illegal in strncpy */
1694 if (hostname != serv->hostname)
1695 safe_strcpy (serv->hostname, hostname, sizeof (serv->hostname));
1697 #ifdef USE_OPENSSL
1698 if (serv->use_ssl)
1700 char cert_file[256];
1702 /* first try network specific cert/key */
1703 snprintf (cert_file, sizeof (cert_file), "%s/%s.pem",
1704 get_xdir_fs (), server_get_network (serv, TRUE));
1705 if (SSL_CTX_use_certificate_file (ctx, cert_file, SSL_FILETYPE_PEM) == 1)
1706 SSL_CTX_use_PrivateKey_file (ctx, cert_file, SSL_FILETYPE_PEM);
1707 else
1709 /* if that doesn't exist, try ~/.xchat2/client.pem */
1710 snprintf (cert_file, sizeof (cert_file), "%s/%s.pem",
1711 get_xdir_fs (), "client");
1712 if (SSL_CTX_use_certificate_file (ctx, cert_file, SSL_FILETYPE_PEM) == 1)
1713 SSL_CTX_use_PrivateKey_file (ctx, cert_file, SSL_FILETYPE_PEM);
1716 #endif
1718 server_set_defaults (serv);
1719 serv->connecting = TRUE;
1720 serv->port = port;
1721 serv->no_login = no_login;
1723 fe_server_event (serv, FE_SE_CONNECTING, 0);
1724 fe_set_away (serv);
1725 server_flush_queue (serv);
1727 #ifdef WIN32
1728 if (_pipe (read_des, 4096, _O_BINARY) < 0)
1729 #else
1730 if (pipe (read_des) < 0)
1731 #endif
1732 return;
1733 #ifdef __EMX__ /* os/2 */
1734 setmode (read_des[0], O_BINARY);
1735 setmode (read_des[1], O_BINARY);
1736 #endif
1737 serv->childread = read_des[0];
1738 serv->childwrite = read_des[1];
1740 /* create both sockets now, drop one later */
1741 net_sockets (&serv->sok4, &serv->sok6);
1742 #ifdef USE_MSPROXY
1743 /* In case of MS Proxy we have a separate UDP control connection */
1744 if (!serv->dont_use_proxy && (serv->proxy_type == 5))
1745 udp_sockets (&serv->proxy_sok4, &serv->proxy_sok6);
1746 else
1747 #endif
1749 serv->proxy_sok4 = -1;
1750 serv->proxy_sok6 = -1;
1753 #ifdef WIN32
1754 CloseHandle (CreateThread (NULL, 0,
1755 (LPTHREAD_START_ROUTINE)server_child,
1756 serv, 0, (DWORD *)&pid));
1757 #else
1758 #ifdef LOOKUPD
1759 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. */
1760 #endif
1761 switch (pid = fork ())
1763 case -1:
1764 return;
1766 case 0:
1767 /* this is the child */
1768 setuid (getuid ());
1769 server_child (serv);
1770 _exit (0);
1772 #endif
1773 serv->childpid = pid;
1774 serv->iotag = fe_input_add (serv->childread, FIA_READ, server_read_child,
1775 serv);
1778 void
1779 server_fill_her_up (server *serv)
1781 serv->connect = server_connect;
1782 serv->disconnect = server_disconnect;
1783 serv->cleanup = server_cleanup;
1784 serv->flush_queue = server_flush_queue;
1785 serv->auto_reconnect = auto_reconnect;
1787 proto_fill_her_up (serv);
1790 void
1791 server_set_encoding (server *serv, char *new_encoding)
1793 char *space;
1795 if (serv->encoding)
1797 free (serv->encoding);
1798 /* can be left as NULL to indicate system encoding */
1799 serv->encoding = NULL;
1800 serv->using_cp1255 = FALSE;
1801 serv->using_irc = FALSE;
1804 if (new_encoding)
1806 serv->encoding = strdup (new_encoding);
1807 /* the serverlist GUI might have added a space
1808 and short description - remove it. */
1809 space = strchr (serv->encoding, ' ');
1810 if (space)
1811 space[0] = 0;
1813 /* server_inline() uses these flags */
1814 if (!strcasecmp (serv->encoding, "CP1255") ||
1815 !strcasecmp (serv->encoding, "WINDOWS-1255"))
1816 serv->using_cp1255 = TRUE;
1817 else if (!strcasecmp (serv->encoding, "IRC"))
1818 serv->using_irc = TRUE;
1822 server *
1823 server_new (void)
1825 static int id = 0;
1826 server *serv;
1828 serv = malloc (sizeof (struct server));
1829 memset (serv, 0, sizeof (struct server));
1831 /* use server.c and proto-irc.c functions */
1832 server_fill_her_up (serv);
1834 serv->id = id++;
1835 serv->sok = -1;
1836 strcpy (serv->nick, prefs.nick1);
1837 server_set_defaults (serv);
1839 serv_list = g_slist_prepend (serv_list, serv);
1841 fe_new_server (serv);
1843 return serv;
1847 is_server (server *serv)
1849 return g_slist_find (serv_list, serv) ? 1 : 0;
1852 void
1853 server_set_defaults (server *serv)
1855 if (serv->chantypes)
1856 free (serv->chantypes);
1857 if (serv->chanmodes)
1858 free (serv->chanmodes);
1859 if (serv->nick_prefixes)
1860 free (serv->nick_prefixes);
1861 if (serv->nick_modes)
1862 free (serv->nick_modes);
1864 serv->chantypes = strdup ("#&!+");
1865 serv->chanmodes = strdup ("beI,k,l");
1866 serv->nick_prefixes = strdup ("@%+");
1867 serv->nick_modes = strdup ("ohv");
1869 serv->nickcount = 1;
1870 serv->nickservtype = 1;
1871 serv->end_of_motd = FALSE;
1872 serv->is_away = FALSE;
1873 serv->supports_watch = FALSE;
1874 serv->bad_prefix = FALSE;
1875 serv->use_who = TRUE;
1876 serv->have_namesx = FALSE;
1877 serv->have_uhnames = FALSE;
1878 serv->have_whox = FALSE;
1879 serv->have_capab = FALSE;
1880 serv->have_idmsg = FALSE;
1881 serv->have_except = FALSE;
1884 char *
1885 server_get_network (server *serv, gboolean fallback)
1887 if (serv->network)
1888 return ((ircnet *)serv->network)->name;
1890 if (fallback)
1891 return serv->servername;
1893 return NULL;
1896 void
1897 server_set_name (server *serv, char *name)
1899 GSList *list = sess_list;
1900 session *sess;
1902 if (name[0] == 0)
1903 name = serv->hostname;
1905 /* strncpy parameters must NOT overlap */
1906 if (name != serv->servername)
1908 safe_strcpy (serv->servername, name, sizeof (serv->servername));
1911 while (list)
1913 sess = (session *) list->data;
1914 if (sess->server == serv)
1915 fe_set_title (sess);
1916 list = list->next;
1919 if (serv->server_session->type == SESS_SERVER)
1921 if (serv->network)
1923 safe_strcpy (serv->server_session->channel, ((ircnet *)serv->network)->name, CHANLEN);
1924 } else
1926 safe_strcpy (serv->server_session->channel, name, CHANLEN);
1928 fe_set_channel (serv->server_session);
1932 struct away_msg *
1933 server_away_find_message (server *serv, char *nick)
1935 struct away_msg *away;
1936 GSList *list = away_list;
1937 while (list)
1939 away = (struct away_msg *) list->data;
1940 if (away->server == serv && !serv->p_cmp (nick, away->nick))
1941 return away;
1942 list = list->next;
1944 return NULL;
1947 static void
1948 server_away_free_messages (server *serv)
1950 GSList *list, *next;
1951 struct away_msg *away;
1953 list = away_list;
1954 while (list)
1956 away = list->data;
1957 next = list->next;
1958 if (away->server == serv)
1960 away_list = g_slist_remove (away_list, away);
1961 if (away->message)
1962 free (away->message);
1963 free (away);
1964 next = away_list;
1966 list = next;
1970 void
1971 server_away_save_message (server *serv, char *nick, char *msg)
1973 struct away_msg *away = server_away_find_message (serv, nick);
1975 if (away) /* Change message for known user */
1977 if (away->message)
1978 free (away->message);
1979 away->message = strdup (msg);
1980 } else
1981 /* Create brand new entry */
1983 away = malloc (sizeof (struct away_msg));
1984 if (away)
1986 away->server = serv;
1987 safe_strcpy (away->nick, nick, sizeof (away->nick));
1988 away->message = strdup (msg);
1989 away_list = g_slist_prepend (away_list, away);
1994 void
1995 server_free (server *serv)
1997 serv->cleanup (serv);
1999 serv_list = g_slist_remove (serv_list, serv);
2001 dcc_notify_kill (serv);
2002 serv->flush_queue (serv);
2003 server_away_free_messages (serv);
2005 free (serv->nick_modes);
2006 free (serv->nick_prefixes);
2007 free (serv->chanmodes);
2008 free (serv->chantypes);
2009 if (serv->bad_nick_prefixes)
2010 free (serv->bad_nick_prefixes);
2011 if (serv->last_away_reason)
2012 free (serv->last_away_reason);
2013 if (serv->encoding)
2014 free (serv->encoding);
2015 if (serv->autojoin)
2016 free (serv->autojoin);
2018 fe_server_callback (serv);
2020 free (serv);
2022 notify_cleanup ();