Now inbound_cap_ls() can enable extensions when a bouncer uses a namespace for the...
[rofl0r-ixchat.git] / src / common / server.c
blob4fd11dc4d8bbdf3834fb0bba161de2da4b61549f
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 if (prefs.autoreconnect)
971 auto_reconnect (serv, FALSE, -1);
972 break;
973 case '9':
974 waitline2 (source, tbuf, sizeof tbuf);
975 EMIT_SIGNAL (XP_TE_SERVERLOOKUP, sess, tbuf, NULL, NULL, NULL, 0);
976 break;
979 return TRUE;
982 /* kill all sockets & iotags of a server. Stop a connection attempt, or
983 disconnect if already connected. */
985 static int
986 server_cleanup (server * serv)
988 fe_set_lag (serv, 0.0);
990 if (serv->iotag)
992 fe_input_remove (serv->iotag);
993 serv->iotag = 0;
996 if (serv->joindelay_tag)
998 fe_timeout_remove (serv->joindelay_tag);
999 serv->joindelay_tag = 0;
1002 #ifdef USE_OPENSSL
1003 if (serv->ssl)
1005 _SSL_close (serv->ssl);
1006 serv->ssl = NULL;
1008 #endif
1010 if (serv->connecting)
1012 server_stopconnecting (serv);
1013 closesocket (serv->sok4);
1014 if (serv->proxy_sok4 != -1)
1015 closesocket (serv->proxy_sok4);
1016 if (serv->sok6 != -1)
1017 closesocket (serv->sok6);
1018 if (serv->proxy_sok6 != -1)
1019 closesocket (serv->proxy_sok6);
1020 return 1;
1023 if (serv->connected)
1025 close_socket (serv->sok);
1026 if (serv->proxy_sok)
1027 close_socket (serv->proxy_sok);
1028 serv->connected = FALSE;
1029 serv->end_of_motd = FALSE;
1030 return 2;
1033 /* is this server in a reconnect delay? remove it! */
1034 if (serv->recondelay_tag)
1036 fe_timeout_remove (serv->recondelay_tag);
1037 serv->recondelay_tag = 0;
1038 return 3;
1041 return 0;
1044 static void
1045 server_disconnect (session * sess, int sendquit, int err)
1047 server *serv = sess->server;
1048 GSList *list;
1049 char tbuf[64];
1050 gboolean shutup = FALSE;
1052 /* send our QUIT reason */
1053 if (sendquit && serv->connected)
1055 server_sendquit (sess);
1058 fe_server_event (serv, FE_SE_DISCONNECT, 0);
1060 /* close all sockets & io tags */
1061 switch (server_cleanup (serv))
1063 case 0: /* it wasn't even connected! */
1064 notc_msg (sess);
1065 return;
1066 case 1: /* it was in the process of connecting */
1067 sprintf (tbuf, "%d", sess->server->childpid);
1068 EMIT_SIGNAL (XP_TE_STOPCONNECT, sess, tbuf, NULL, NULL, NULL, 0);
1069 return;
1070 case 3:
1071 shutup = TRUE; /* won't print "disconnected" in channels */
1074 server_flush_queue (serv);
1076 list = sess_list;
1077 while (list)
1079 sess = (struct session *) list->data;
1080 if (sess->server == serv)
1082 if (!shutup || sess->type == SESS_SERVER)
1083 /* print "Disconnected" to each window using this server */
1084 EMIT_SIGNAL (XP_TE_DISCON, sess, errorstring (err), NULL, NULL, NULL, 0);
1086 if (!sess->channel[0] || sess->type == SESS_CHANNEL)
1087 clear_channel (sess);
1089 list = list->next;
1092 serv->pos = 0;
1093 serv->motd_skipped = FALSE;
1094 serv->no_login = FALSE;
1095 serv->servername[0] = 0;
1096 serv->lag_sent = 0;
1098 notify_cleanup ();
1101 /* send a "print text" command to the parent process - MUST END IN \n! */
1103 static void
1104 proxy_error (int fd, char *msg)
1106 write (fd, "0\n", 2);
1107 write (fd, msg, strlen (msg));
1110 struct sock_connect
1112 char version;
1113 char type;
1114 guint16 port;
1115 guint32 address;
1116 char username[10];
1119 /* traverse_socks() returns:
1120 * 0 success *
1121 * 1 socks traversal failed */
1123 static int
1124 traverse_socks (int print_fd, int sok, char *serverAddr, int port)
1126 struct sock_connect sc;
1127 unsigned char buf[256];
1129 sc.version = 4;
1130 sc.type = 1;
1131 sc.port = htons (port);
1132 sc.address = inet_addr (serverAddr);
1133 strncpy (sc.username, prefs.username, 9);
1135 send (sok, (char *) &sc, 8 + strlen (sc.username) + 1, 0);
1136 buf[1] = 0;
1137 recv (sok, buf, 10, 0);
1138 if (buf[1] == 90)
1139 return 0;
1141 snprintf (buf, sizeof (buf), "SOCKS\tServer reported error %d,%d.\n", buf[0], buf[1]);
1142 proxy_error (print_fd, buf);
1143 return 1;
1146 struct sock5_connect1
1148 char version;
1149 char nmethods;
1150 char method;
1153 static int
1154 traverse_socks5 (int print_fd, int sok, char *serverAddr, int port)
1156 struct sock5_connect1 sc1;
1157 unsigned char *sc2;
1158 unsigned int packetlen, addrlen;
1159 unsigned char buf[260];
1160 int auth = prefs.proxy_auth && prefs.proxy_user[0] && prefs.proxy_pass[0];
1162 sc1.version = 5;
1163 sc1.nmethods = 1;
1164 if (auth)
1165 sc1.method = 2; /* Username/Password Authentication (UPA) */
1166 else
1167 sc1.method = 0; /* NO Authentication */
1168 send (sok, (char *) &sc1, 3, 0);
1169 if (recv (sok, buf, 2, 0) != 2)
1170 goto read_error;
1172 if (buf[0] != 5)
1174 proxy_error (print_fd, "SOCKS\tServer is not socks version 5.\n");
1175 return 1;
1178 /* did the server say no auth required? */
1179 if (buf[1] == 0)
1180 auth = 0;
1182 if (auth)
1184 int len_u=0, len_p=0;
1186 /* authentication sub-negotiation (RFC1929) */
1187 if (buf[1] != 2) /* UPA not supported by server */
1189 proxy_error (print_fd, "SOCKS\tServer doesn't support UPA authentication.\n");
1190 return 1;
1193 memset (buf, 0, sizeof(buf));
1195 /* form the UPA request */
1196 len_u = strlen (prefs.proxy_user);
1197 len_p = strlen (prefs.proxy_pass);
1198 buf[0] = 1;
1199 buf[1] = len_u;
1200 memcpy (buf + 2, prefs.proxy_user, len_u);
1201 buf[2 + len_u] = len_p;
1202 memcpy (buf + 3 + len_u, prefs.proxy_pass, len_p);
1204 send (sok, buf, 3 + len_u + len_p, 0);
1205 if ( recv (sok, buf, 2, 0) != 2 )
1206 goto read_error;
1207 if ( buf[1] != 0 )
1209 proxy_error (print_fd, "SOCKS\tAuthentication failed. "
1210 "Is username and password correct?\n");
1211 return 1; /* UPA failed! */
1214 else
1216 if (buf[1] != 0)
1218 proxy_error (print_fd, "SOCKS\tAuthentication required but disabled in settings.\n");
1219 return 1;
1223 addrlen = strlen (serverAddr);
1224 packetlen = 4 + 1 + addrlen + 2;
1225 sc2 = malloc (packetlen);
1226 sc2[0] = 5; /* version */
1227 sc2[1] = 1; /* command */
1228 sc2[2] = 0; /* reserved */
1229 sc2[3] = 3; /* address type */
1230 sc2[4] = (unsigned char) addrlen; /* hostname length */
1231 memcpy (sc2 + 5, serverAddr, addrlen);
1232 *((unsigned short *) (sc2 + 5 + addrlen)) = htons (port);
1233 send (sok, sc2, packetlen, 0);
1234 free (sc2);
1236 /* consume all of the reply */
1237 if (recv (sok, buf, 4, 0) != 4)
1238 goto read_error;
1239 if (buf[0] != 5 || buf[1] != 0)
1241 if (buf[1] == 2)
1242 snprintf (buf, sizeof (buf), "SOCKS\tProxy refused to connect to host (not allowed).\n");
1243 else
1244 snprintf (buf, sizeof (buf), "SOCKS\tProxy failed to connect to host (error %d).\n", buf[1]);
1245 proxy_error (print_fd, buf);
1246 return 1;
1248 if (buf[3] == 1) /* IPV4 32bit address */
1250 if (recv (sok, buf, 6, 0) != 6)
1251 goto read_error;
1252 } else if (buf[3] == 4) /* IPV6 128bit address */
1254 if (recv (sok, buf, 18, 0) != 18)
1255 goto read_error;
1256 } else if (buf[3] == 3) /* string, 1st byte is size */
1258 if (recv (sok, buf, 1, 0) != 1) /* read the string size */
1259 goto read_error;
1260 packetlen = buf[0] + 2; /* can't exceed 260 */
1261 if (recv (sok, buf, packetlen, 0) != packetlen)
1262 goto read_error;
1265 return 0; /* success */
1267 read_error:
1268 proxy_error (print_fd, "SOCKS\tRead error from server.\n");
1269 return 1;
1272 static int
1273 traverse_wingate (int print_fd, int sok, char *serverAddr, int port)
1275 char buf[128];
1277 snprintf (buf, sizeof (buf), "%s %d\r\n", serverAddr, port);
1278 send (sok, buf, strlen (buf), 0);
1280 return 0;
1283 /* stuff for HTTP auth is here */
1285 static void
1286 three_to_four (char *from, char *to)
1288 static const char tab64[64]=
1290 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P',
1291 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f',
1292 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v',
1293 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/'
1296 to[0] = tab64 [ (from[0] >> 2) & 63 ];
1297 to[1] = tab64 [ ((from[0] << 4) | (from[1] >> 4)) & 63 ];
1298 to[2] = tab64 [ ((from[1] << 2) | (from[2] >> 6)) & 63 ];
1299 to[3] = tab64 [ from[2] & 63 ];
1302 void
1303 base64_encode (char *to, char *from, unsigned int len)
1305 while (len >= 3)
1307 three_to_four (from, to);
1308 len -= 3;
1309 from += 3;
1310 to += 4;
1312 if (len)
1314 char three[3]={0,0,0};
1315 int i=0;
1316 for (i=0;i<len;i++)
1317 three[i] = *from++;
1318 three_to_four (three, to);
1319 if (len == 1)
1320 to[2] = to[3] = '=';
1321 else if (len == 2)
1322 to[3] = '=';
1323 to += 4;
1325 to[0] = 0;
1328 static int
1329 http_read_line (int print_fd, int sok, char *buf, int len)
1331 len = waitline (sok, buf, len, TRUE);
1332 if (len >= 1)
1334 /* print the message out (send it to the parent process) */
1335 write (print_fd, "0\n", 2);
1337 if (buf[len-1] == '\r')
1339 buf[len-1] = '\n';
1340 write (print_fd, buf, len);
1341 } else
1343 write (print_fd, buf, len);
1344 write (print_fd, "\n", 1);
1348 return len;
1351 static int
1352 traverse_http (int print_fd, int sok, char *serverAddr, int port)
1354 char buf[512];
1355 char auth_data[256];
1356 char auth_data2[252];
1357 int n, n2;
1359 n = snprintf (buf, sizeof (buf), "CONNECT %s:%d HTTP/1.0\r\n",
1360 serverAddr, port);
1361 if (prefs.proxy_auth)
1363 n2 = snprintf (auth_data2, sizeof (auth_data2), "%s:%s",
1364 prefs.proxy_user, prefs.proxy_pass);
1365 base64_encode (auth_data, auth_data2, n2);
1366 n += snprintf (buf+n, sizeof (buf)-n, "Proxy-Authorization: Basic %s\r\n", auth_data);
1368 n += snprintf (buf+n, sizeof (buf)-n, "\r\n");
1369 send (sok, buf, n, 0);
1371 n = http_read_line (print_fd, sok, buf, sizeof (buf));
1372 /* "HTTP/1.0 200 OK" */
1373 if (n < 12)
1374 return 1;
1375 if (memcmp (buf, "HTTP/", 5) || memcmp (buf + 9, "200", 3))
1376 return 1;
1377 while (1)
1379 /* read until blank line */
1380 n = http_read_line (print_fd, sok, buf, sizeof (buf));
1381 if (n < 1 || (n == 1 && buf[0] == '\n'))
1382 break;
1384 return 0;
1387 static int
1388 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)
1390 switch (proxy_type)
1392 case 1:
1393 return traverse_wingate (print_fd, sok, ip, port);
1394 case 2:
1395 return traverse_socks (print_fd, sok, ip, port);
1396 case 3:
1397 return traverse_socks5 (print_fd, sok, ip, port);
1398 case 4:
1399 return traverse_http (print_fd, sok, ip, port);
1400 #ifdef USE_MSPROXY
1401 case 5:
1402 return traverse_msproxy (sok, ip, port, state, ns_proxy, csok4, csok6, csok, bound);
1403 #endif
1406 return 1;
1409 /* this is the child process making the connection attempt */
1411 static int
1412 server_child (server * serv)
1414 netstore *ns_server;
1415 netstore *ns_proxy = NULL;
1416 netstore *ns_local;
1417 int port = serv->port;
1418 int error;
1419 int sok, psok;
1420 char *hostname = serv->hostname;
1421 char *real_hostname = NULL;
1422 char *ip;
1423 char *proxy_ip = NULL;
1424 char *local_ip;
1425 int connect_port;
1426 char buf[512];
1427 char bound = 0;
1428 int proxy_type = 0;
1429 char *proxy_host = NULL;
1430 int proxy_port;
1432 ns_server = net_store_new ();
1434 /* is a hostname set? - bind to it */
1435 if (prefs.hostname[0])
1437 ns_local = net_store_new ();
1438 local_ip = net_resolve (ns_local, prefs.hostname, 0, &real_hostname);
1439 if (local_ip != NULL)
1441 snprintf (buf, sizeof (buf), "5\n%s\n", local_ip);
1442 write (serv->childwrite, buf, strlen (buf));
1443 net_bind (ns_local, serv->sok4, serv->sok6);
1444 bound = 1;
1445 } else
1447 write (serv->childwrite, "7\n", 2);
1449 net_store_destroy (ns_local);
1452 if (!serv->dont_use_proxy) /* blocked in serverlist? */
1454 if (FALSE)
1456 #ifdef USE_LIBPROXY
1457 else if (prefs.proxy_type == 5)
1459 char **proxy_list;
1460 char *url, *proxy;
1462 url = g_strdup_printf ("irc://%s:%d", hostname, port);
1463 proxy_list = px_proxy_factory_get_proxies (libproxy_factory, url);
1465 if (proxy_list) {
1466 /* can use only one */
1467 proxy = proxy_list[0];
1468 if (!strncmp (proxy, "direct", 6))
1469 proxy_type = 0;
1470 else if (!strncmp (proxy, "http", 4))
1471 proxy_type = 4;
1472 else if (!strncmp (proxy, "socks5", 6))
1473 proxy_type = 3;
1474 else if (!strncmp (proxy, "socks", 5))
1475 proxy_type = 2;
1478 if (proxy_type) {
1479 char *c;
1480 c = strchr (proxy, ':') + 3;
1481 proxy_host = strdup (c);
1482 c = strchr (proxy_host, ':');
1483 *c = '\0';
1484 proxy_port = atoi (c + 1);
1487 g_strfreev (proxy_list);
1488 g_free (url);
1490 #endif
1491 else if (prefs.proxy_host[0] &&
1492 prefs.proxy_type > 0 &&
1493 prefs.proxy_use != 2) /* proxy is NOT dcc-only */
1495 proxy_type = prefs.proxy_type;
1496 proxy_host = strdup (prefs.proxy_host);
1497 proxy_port = prefs.proxy_port;
1501 serv->proxy_type = proxy_type;
1503 /* first resolve where we want to connect to */
1504 if (proxy_type > 0)
1506 snprintf (buf, sizeof (buf), "9\n%s\n", proxy_host);
1507 write (serv->childwrite, buf, strlen (buf));
1508 ip = net_resolve (ns_server, proxy_host, proxy_port, &real_hostname);
1509 free (proxy_host);
1510 if (!ip)
1512 write (serv->childwrite, "1\n", 2);
1513 goto xit;
1515 connect_port = proxy_port;
1517 /* if using socks4 or MS Proxy, attempt to resolve ip for irc server */
1518 if ((proxy_type == 2) || (proxy_type == 5))
1520 ns_proxy = net_store_new ();
1521 proxy_ip = net_resolve (ns_proxy, hostname, port, &real_hostname);
1522 if (!proxy_ip)
1524 write (serv->childwrite, "1\n", 2);
1525 goto xit;
1527 } else /* otherwise we can just use the hostname */
1528 proxy_ip = strdup (hostname);
1529 } else
1531 ip = net_resolve (ns_server, hostname, port, &real_hostname);
1532 if (!ip)
1534 write (serv->childwrite, "1\n", 2);
1535 goto xit;
1537 connect_port = port;
1540 snprintf (buf, sizeof (buf), "3\n%s\n%s\n%d\n",
1541 real_hostname, ip, connect_port);
1542 write (serv->childwrite, buf, strlen (buf));
1544 if (!serv->dont_use_proxy && (proxy_type == 5))
1545 error = net_connect (ns_server, serv->proxy_sok4, serv->proxy_sok6, &psok);
1546 else
1548 error = net_connect (ns_server, serv->sok4, serv->sok6, &sok);
1549 psok = sok;
1552 if (error != 0)
1554 snprintf (buf, sizeof (buf), "2\n%d\n", sock_error ());
1555 write (serv->childwrite, buf, strlen (buf));
1556 } else
1558 /* connect succeeded */
1559 if (proxy_ip)
1561 switch (traverse_proxy (proxy_type, serv->childwrite, psok, proxy_ip, port, &serv->msp_state, ns_proxy, serv->sok4, serv->sok6, &sok, bound))
1563 case 0: /* success */
1564 #ifdef USE_MSPROXY
1565 if (!serv->dont_use_proxy && (proxy_type == 5))
1566 snprintf (buf, sizeof (buf), "4\n%d %d %d %d %d\n", sok, psok, serv->msp_state.clientid, serv->msp_state.serverid,
1567 serv->msp_state.seq_sent);
1568 else
1569 #endif
1570 snprintf (buf, sizeof (buf), "4\n%d\n", sok); /* success */
1571 write (serv->childwrite, buf, strlen (buf));
1572 break;
1573 case 1: /* socks traversal failed */
1574 write (serv->childwrite, "8\n", 2);
1575 break;
1577 } else
1579 snprintf (buf, sizeof (buf), "4\n%d\n", sok); /* success */
1580 write (serv->childwrite, buf, strlen (buf));
1584 xit:
1586 #if defined (USE_IPV6)
1587 /* this is probably not needed */
1588 net_store_destroy (ns_server);
1589 if (ns_proxy)
1590 net_store_destroy (ns_proxy);
1591 #endif
1593 /* no need to free ip/real_hostname, this process is exiting */
1595 return 0;
1598 static void
1599 server_connect (server *serv, char *hostname, int port, int no_login)
1601 int pid, read_des[2];
1602 session *sess = serv->server_session;
1604 #ifdef USE_OPENSSL
1605 if (!ctx && serv->use_ssl)
1607 if (!(ctx = _SSL_context_init (ssl_cb_info, FALSE)))
1609 fprintf (stderr, "_SSL_context_init failed\n");
1610 exit (1);
1613 #endif
1615 if (!hostname[0])
1616 return;
1618 if (port < 0)
1620 /* use default port for this server type */
1621 port = 6667;
1622 #ifdef USE_OPENSSL
1623 if (serv->use_ssl)
1624 port = 9999;
1625 #endif
1627 port &= 0xffff; /* wrap around */
1629 if (serv->connected || serv->connecting || serv->recondelay_tag)
1630 server_disconnect (sess, TRUE, -1);
1632 fe_progressbar_start (sess);
1634 EMIT_SIGNAL (XP_TE_SERVERLOOKUP, sess, hostname, NULL, NULL, NULL, 0);
1636 safe_strcpy (serv->servername, hostname, sizeof (serv->servername));
1637 /* overlap illegal in strncpy */
1638 if (hostname != serv->hostname)
1639 safe_strcpy (serv->hostname, hostname, sizeof (serv->hostname));
1641 #ifdef USE_OPENSSL
1642 if (serv->use_ssl)
1644 char cert_file[256];
1646 /* first try network specific cert/key */
1647 snprintf (cert_file, sizeof (cert_file), "%s/%s.pem",
1648 get_xdir_fs (), server_get_network (serv, TRUE));
1649 if (SSL_CTX_use_certificate_file (ctx, cert_file, SSL_FILETYPE_PEM) == 1)
1650 SSL_CTX_use_PrivateKey_file (ctx, cert_file, SSL_FILETYPE_PEM);
1651 else
1653 /* if that doesn't exist, try ~/.xchat2/client.pem */
1654 snprintf (cert_file, sizeof (cert_file), "%s/%s.pem",
1655 get_xdir_fs (), "client");
1656 if (SSL_CTX_use_certificate_file (ctx, cert_file, SSL_FILETYPE_PEM) == 1)
1657 SSL_CTX_use_PrivateKey_file (ctx, cert_file, SSL_FILETYPE_PEM);
1660 #endif
1662 server_set_defaults (serv);
1663 serv->connecting = TRUE;
1664 serv->port = port;
1665 serv->no_login = no_login;
1667 fe_server_event (serv, FE_SE_CONNECTING, 0);
1668 fe_set_away (serv);
1669 server_flush_queue (serv);
1671 if (pipe (read_des) < 0)
1672 return;
1673 serv->childread = read_des[0];
1674 serv->childwrite = read_des[1];
1676 /* create both sockets now, drop one later */
1677 net_sockets (&serv->sok4, &serv->sok6);
1678 #ifdef USE_MSPROXY
1679 /* In case of MS Proxy we have a separate UDP control connection */
1680 if (!serv->dont_use_proxy && (serv->proxy_type == 5))
1681 udp_sockets (&serv->proxy_sok4, &serv->proxy_sok6);
1682 else
1683 #endif
1685 serv->proxy_sok4 = -1;
1686 serv->proxy_sok6 = -1;
1689 #ifdef LOOKUPD
1690 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. */
1691 #endif
1692 switch (pid = fork ())
1694 case -1:
1695 return;
1697 case 0:
1698 /* this is the child */
1699 setuid (getuid ());
1700 server_child (serv);
1701 _exit (0);
1703 serv->childpid = pid;
1704 serv->iotag = fe_input_add (serv->childread, FIA_READ, server_read_child,
1705 serv);
1708 void
1709 server_fill_her_up (server *serv)
1711 serv->connect = server_connect;
1712 serv->disconnect = server_disconnect;
1713 serv->cleanup = server_cleanup;
1714 serv->flush_queue = server_flush_queue;
1715 serv->auto_reconnect = auto_reconnect;
1717 proto_fill_her_up (serv);
1720 void
1721 server_set_encoding (server *serv, char *new_encoding)
1723 char *space;
1725 if (serv->encoding)
1727 free (serv->encoding);
1728 /* can be left as NULL to indicate system encoding */
1729 serv->encoding = NULL;
1730 serv->using_cp1255 = FALSE;
1731 serv->using_irc = FALSE;
1734 if (new_encoding)
1736 serv->encoding = strdup (new_encoding);
1737 /* the serverlist GUI might have added a space
1738 and short description - remove it. */
1739 space = strchr (serv->encoding, ' ');
1740 if (space)
1741 space[0] = 0;
1743 /* server_inline() uses these flags */
1744 if (!strcasecmp (serv->encoding, "CP1255") ||
1745 !strcasecmp (serv->encoding, "WINDOWS-1255"))
1746 serv->using_cp1255 = TRUE;
1747 else if (!strcasecmp (serv->encoding, "IRC"))
1748 serv->using_irc = TRUE;
1752 server *
1753 server_new (void)
1755 static int id = 0;
1756 server *serv;
1758 serv = malloc (sizeof (struct server));
1759 memset (serv, 0, sizeof (struct server));
1761 /* use server.c and proto-irc.c functions */
1762 server_fill_her_up (serv);
1764 serv->id = id++;
1765 serv->sok = -1;
1766 strcpy (serv->nick, prefs.nick1);
1767 server_set_defaults (serv);
1769 serv_list = g_slist_prepend (serv_list, serv);
1771 fe_new_server (serv);
1773 return serv;
1777 is_server (server *serv)
1779 return g_slist_find (serv_list, serv) ? 1 : 0;
1782 void
1783 server_set_defaults (server *serv)
1785 if (serv->chantypes)
1786 free (serv->chantypes);
1787 if (serv->chanmodes)
1788 free (serv->chanmodes);
1789 if (serv->nick_prefixes)
1790 free (serv->nick_prefixes);
1791 if (serv->nick_modes)
1792 free (serv->nick_modes);
1794 serv->chantypes = strdup ("#&!+");
1795 serv->chanmodes = strdup ("beI,k,l");
1796 serv->nick_prefixes = strdup ("@%+");
1797 serv->nick_modes = strdup ("ohv");
1799 serv->nickcount = 1;
1800 serv->end_of_motd = FALSE;
1801 serv->is_away = FALSE;
1802 serv->supports_watch = FALSE;
1803 serv->supports_monitor = FALSE;
1804 serv->bad_prefix = FALSE;
1805 serv->use_who = TRUE;
1806 serv->have_namesx = FALSE;
1807 serv->have_awaynotify = FALSE;
1808 serv->have_uhnames = FALSE;
1809 serv->have_whox = FALSE;
1810 serv->have_idmsg = FALSE;
1811 serv->have_accnotify = FALSE;
1812 serv->have_extjoin = FALSE;
1813 serv->have_sasl = FALSE;
1814 serv->have_except = FALSE;
1817 char *
1818 server_get_network (server *serv, gboolean fallback)
1820 if (serv->network)
1821 return ((ircnet *)serv->network)->name;
1823 if (fallback)
1824 return serv->servername;
1826 return NULL;
1829 void
1830 server_set_name (server *serv, char *name)
1832 GSList *list = sess_list;
1833 session *sess;
1835 if (name[0] == 0)
1836 name = serv->hostname;
1838 /* strncpy parameters must NOT overlap */
1839 if (name != serv->servername)
1841 safe_strcpy (serv->servername, name, sizeof (serv->servername));
1844 while (list)
1846 sess = (session *) list->data;
1847 if (sess->server == serv)
1848 fe_set_title (sess);
1849 list = list->next;
1852 if (serv->server_session->type == SESS_SERVER)
1854 if (serv->network)
1856 safe_strcpy (serv->server_session->channel, ((ircnet *)serv->network)->name, CHANLEN);
1857 } else
1859 safe_strcpy (serv->server_session->channel, name, CHANLEN);
1861 fe_set_channel (serv->server_session);
1865 struct away_msg *
1866 server_away_find_message (server *serv, char *nick)
1868 struct away_msg *away;
1869 GSList *list = away_list;
1870 while (list)
1872 away = (struct away_msg *) list->data;
1873 if (away->server == serv && !serv->p_cmp (nick, away->nick))
1874 return away;
1875 list = list->next;
1877 return NULL;
1880 static void
1881 server_away_free_messages (server *serv)
1883 GSList *list, *next;
1884 struct away_msg *away;
1886 list = away_list;
1887 while (list)
1889 away = list->data;
1890 next = list->next;
1891 if (away->server == serv)
1893 away_list = g_slist_remove (away_list, away);
1894 if (away->message)
1895 free (away->message);
1896 free (away);
1897 next = away_list;
1899 list = next;
1903 void
1904 server_away_save_message (server *serv, char *nick, char *msg)
1906 struct away_msg *away = server_away_find_message (serv, nick);
1908 if (away) /* Change message for known user */
1910 if (away->message)
1911 free (away->message);
1912 away->message = strdup (msg);
1913 } else
1914 /* Create brand new entry */
1916 away = malloc (sizeof (struct away_msg));
1917 if (away)
1919 away->server = serv;
1920 safe_strcpy (away->nick, nick, sizeof (away->nick));
1921 away->message = strdup (msg);
1922 away_list = g_slist_prepend (away_list, away);
1927 void
1928 server_free (server *serv)
1930 serv->cleanup (serv);
1932 serv_list = g_slist_remove (serv_list, serv);
1934 dcc_notify_kill (serv);
1935 serv->flush_queue (serv);
1936 server_away_free_messages (serv);
1938 free (serv->nick_modes);
1939 free (serv->nick_prefixes);
1940 free (serv->chanmodes);
1941 free (serv->chantypes);
1942 if (serv->bad_nick_prefixes)
1943 free (serv->bad_nick_prefixes);
1944 if (serv->last_away_reason)
1945 free (serv->last_away_reason);
1946 if (serv->encoding)
1947 free (serv->encoding);
1948 if (serv->autojoin)
1949 free (serv->autojoin);
1951 fe_server_callback (serv);
1953 free (serv);
1955 notify_cleanup ();