configure: fix execution with dash
[rofl0r-ixchat.git] / src / common / server.c
blobeffa931d920d617f399790569b0e72029d325193
1 /* X-Chat
2 * Copyright (C) 1998 Peter Zelezny.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18 * MS Proxy (ISA server) support is (c) 2006 Pavel Fedin <sonic_amiga@rambler.ru>
19 * based on Dante source code
20 * Copyright (c) 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
21 * Inferno Nettverk A/S, Norway. All rights reserved.
24 /*#define DEBUG_MSPROXY*/
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <errno.h>
31 #include <fcntl.h>
33 #define WANTSOCKET
34 #define WANTARPA
35 #include "inet.h"
37 #include <signal.h>
38 #include <sys/wait.h>
40 #include "xchat.h"
41 #include "fe.h"
42 #include "cfgfiles.h"
43 #include "network.h"
44 #include "notify.h"
45 #include "xchatc.h"
46 #include "inbound.h"
47 #include "outbound.h"
48 #include "text.h"
49 #include "util.h"
50 #include "url.h"
51 #include "proto-irc.h"
52 #include "servlist.h"
53 #include "server.h"
55 #ifdef USE_OPENSSL
56 #include <openssl/ssl.h> /* SSL_() */
57 #include <openssl/err.h> /* ERR_() */
58 #include "ssl.h"
59 #endif
61 #ifdef USE_MSPROXY
62 #include "msproxy.h"
63 #endif
65 #ifdef USE_LIBPROXY
66 #include <proxy.h>
67 #endif
69 #ifdef USE_OPENSSL
70 /* local variables */
71 static struct session *g_sess = NULL;
72 #endif
74 static GSList *away_list = NULL;
75 GSList *serv_list = NULL;
77 static void auto_reconnect (server *serv, int send_quit, int err);
78 static void server_disconnect (session * sess, int sendquit, int err);
79 static int server_cleanup (server * serv);
80 static void server_connect (server *serv, char *hostname, int port, int no_login);
82 #ifdef USE_LIBPROXY
83 extern pxProxyFactory *libproxy_factory;
84 #endif
86 /* actually send to the socket. This might do a character translation or
87 send via SSL. server/dcc both use this function. */
89 int
90 tcp_send_real (void *ssl, int sok, char *encoding, int using_irc, char *buf, int len)
92 int ret;
93 char *locale;
94 gsize loc_len;
96 if (encoding == NULL) /* system */
98 locale = NULL;
99 if (!prefs.utf8_locale)
101 const gchar *charset;
103 g_get_charset (&charset);
104 locale = g_convert_with_fallback (buf, len, charset, "UTF-8",
105 "?", 0, &loc_len, 0);
107 } else
109 if (using_irc) /* using "IRC" encoding (CP1252/UTF-8 hybrid) */
110 /* if all chars fit inside CP1252, use that. Otherwise this
111 returns NULL and we send UTF-8. */
112 locale = g_convert (buf, len, "CP1252", "UTF-8", 0, &loc_len, 0);
113 else
114 locale = g_convert_with_fallback (buf, len, encoding, "UTF-8",
115 "?", 0, &loc_len, 0);
118 if (locale)
120 len = loc_len;
121 #ifdef USE_OPENSSL
122 if (!ssl)
123 ret = send (sok, locale, len, 0);
124 else
125 ret = _SSL_send (ssl, locale, len);
126 #else
127 ret = send (sok, locale, len, 0);
128 #endif
129 g_free (locale);
130 } else
132 #ifdef USE_OPENSSL
133 if (!ssl)
134 ret = send (sok, buf, len, 0);
135 else
136 ret = _SSL_send (ssl, buf, len);
137 #else
138 ret = send (sok, buf, len, 0);
139 #endif
142 return ret;
145 static int
146 server_send_real (server *serv, char *buf, int len)
148 fe_add_rawlog (serv, buf, len, TRUE);
150 return tcp_send_real (serv->ssl, serv->sok, serv->encoding, serv->using_irc,
151 buf, len);
154 /* new throttling system, uses the same method as the Undernet
155 ircu2.10 server; under test, a 200-line paste didn't flood
156 off the client */
158 static int
159 tcp_send_queue (server *serv)
161 char *buf, *p;
162 int len, i, pri;
163 GSList *list;
164 time_t now = time (0);
166 /* did the server close since the timeout was added? */
167 if (!is_server (serv))
168 return 0;
170 /* try priority 2,1,0 */
171 pri = 2;
172 while (pri >= 0)
174 list = serv->outbound_queue;
175 while (list)
177 buf = (char *) list->data;
178 if (buf[0] == pri)
180 buf++; /* skip the priority byte */
181 len = strlen (buf);
183 if (serv->next_send < now)
184 serv->next_send = now;
185 if (serv->next_send - now >= 10)
187 /* check for clock skew */
188 if (now >= serv->prev_now)
189 return 1; /* don't remove the timeout handler */
190 /* it is skewed, reset to something sane */
191 serv->next_send = now;
194 for (p = buf, i = len; i && *p != ' '; p++, i--);
195 serv->next_send += (2 + i / 120);
196 serv->sendq_len -= len;
197 serv->prev_now = now;
198 fe_set_throttle (serv);
200 server_send_real (serv, buf, len);
202 buf--;
203 serv->outbound_queue = g_slist_remove (serv->outbound_queue, buf);
204 free (buf);
205 list = serv->outbound_queue;
206 } else
208 list = list->next;
211 /* now try pri 0 */
212 pri--;
214 return 0; /* remove the timeout handler */
218 tcp_send_len (server *serv, char *buf, int len)
220 char *dbuf;
221 int noqueue = !serv->outbound_queue;
223 if (!prefs.throttle)
224 return server_send_real (serv, buf, len);
226 dbuf = malloc (len + 2); /* first byte is the priority */
227 dbuf[0] = 2; /* pri 2 for most things */
228 memcpy (dbuf + 1, buf, len);
229 dbuf[len + 1] = 0;
231 /* privmsg and notice get a lower priority */
232 if (strncasecmp (dbuf + 1, "PRIVMSG", 7) == 0 ||
233 strncasecmp (dbuf + 1, "NOTICE", 6) == 0)
235 dbuf[0] = 1;
237 else
239 /* WHO/MODE get the lowest priority */
240 if (strncasecmp (dbuf + 1, "WHO ", 4) == 0 ||
241 /* but only MODE queries, not changes */
242 (strncasecmp (dbuf + 1, "MODE", 4) == 0 &&
243 strchr (dbuf, '-') == NULL &&
244 strchr (dbuf, '+') == NULL))
245 dbuf[0] = 0;
248 serv->outbound_queue = g_slist_append (serv->outbound_queue, dbuf);
249 serv->sendq_len += len; /* tcp_send_queue uses strlen */
251 if (tcp_send_queue (serv) && noqueue)
252 fe_timeout_add (500, tcp_send_queue, serv);
254 return 1;
257 /*int
258 tcp_send (server *serv, char *buf)
260 return tcp_send_len (serv, buf, strlen (buf));
263 void
264 tcp_sendf (server *serv, char *fmt, ...)
266 va_list args;
267 /* keep this buffer in BSS. Converting UTF-8 to ISO-8859-x might make the
268 string shorter, so allow alot more than 512 for now. */
269 static char send_buf[1540]; /* good code hey (no it's not overflowable) */
270 int len;
272 va_start (args, fmt);
273 len = vsnprintf (send_buf, sizeof (send_buf) - 1, fmt, args);
274 va_end (args);
276 send_buf[sizeof (send_buf) - 1] = '\0';
277 if (len < 0 || len > (sizeof (send_buf) - 1))
278 len = strlen (send_buf);
280 tcp_send_len (serv, send_buf, len);
283 static int
284 close_socket_cb (gpointer sok)
286 closesocket (GPOINTER_TO_INT (sok));
287 return 0;
290 static void
291 close_socket (int sok)
293 /* close the socket in 5 seconds so the QUIT message is not lost */
294 fe_timeout_add (5000, close_socket_cb, GINT_TO_POINTER (sok));
297 /* handle 1 line of text received from the server */
299 static void
300 server_inline (server *serv, char *line, int len)
302 char *utf_line_allocated = NULL;
304 /* Checks whether we're set to use UTF-8 charset */
305 if (serv->using_irc || /* 1. using CP1252/UTF-8 Hybrid */
306 (serv->encoding == NULL && prefs.utf8_locale) || /* OR 2. using system default->UTF-8 */
307 (serv->encoding != NULL && /* OR 3. explicitly set to UTF-8 */
308 (strcasecmp (serv->encoding, "UTF8") == 0 ||
309 strcasecmp (serv->encoding, "UTF-8") == 0)))
311 /* The user has the UTF-8 charset set, either via /charset
312 command or from his UTF-8 locale. Thus, we first try the
313 UTF-8 charset, and if we fail to convert, we assume
314 it to be ISO-8859-1 (see text_validate). */
316 utf_line_allocated = text_validate (&line, &len);
318 } else
320 /* Since the user has an explicit charset set, either
321 via /charset command or from his non-UTF8 locale,
322 we don't fallback to ISO-8859-1 and instead try to remove
323 errnoeous octets till the string is convertable in the
324 said charset. */
326 const char *encoding = NULL;
328 if (serv->encoding != NULL)
329 encoding = serv->encoding;
330 else
331 g_get_charset (&encoding);
333 if (encoding != NULL)
335 char *conv_line; /* holds a copy of the original string */
336 int conv_len; /* tells g_convert how much of line to convert */
337 gsize utf_len;
338 gsize read_len;
339 GError *err;
340 gboolean retry;
342 conv_line = g_malloc (len + 1);
343 memcpy (conv_line, line, len);
344 conv_line[len] = 0;
345 conv_len = len;
347 /* if CP1255, convert it with the NUL terminator.
348 Works around SF bug #1122089 */
349 if (serv->using_cp1255)
350 conv_len++;
354 err = NULL;
355 retry = FALSE;
356 utf_line_allocated = g_convert_with_fallback (conv_line, conv_len, "UTF-8", encoding, "?", &read_len, &utf_len, &err);
357 if (err != NULL)
359 if (err->code == G_CONVERT_ERROR_ILLEGAL_SEQUENCE && conv_len > (read_len + 1))
361 /* Make our best bet by removing the erroneous char.
362 This will work for casual 8-bit strings with non-standard chars. */
363 memmove (conv_line + read_len, conv_line + read_len + 1, conv_len - read_len -1);
364 conv_len--;
365 retry = TRUE;
367 g_error_free (err);
369 } while (retry);
371 g_free (conv_line);
373 /* If any conversion has occured at all. Conversion might fail
374 due to errors other than invalid sequences, e.g. unknown charset. */
375 if (utf_line_allocated != NULL)
377 line = utf_line_allocated;
378 len = utf_len;
379 if (serv->using_cp1255 && len > 0)
380 len--;
382 else
384 /* If all fails, treat as UTF-8 with fallback to ISO-8859-1. */
385 utf_line_allocated = text_validate (&line, &len);
390 fe_add_rawlog (serv, line, len, FALSE);
392 /* let proto-irc.c handle it */
393 serv->p_inline (serv, line, len);
395 if (utf_line_allocated != NULL) /* only if a special copy was allocated */
396 g_free (utf_line_allocated);
399 /* read data from socket */
401 static gboolean
402 server_read (GIOChannel *source, GIOCondition condition, server *serv)
404 int sok = serv->sok;
405 int error, i, len;
406 char lbuf[2050];
408 while (1)
410 #ifdef USE_OPENSSL
411 if (!serv->ssl)
412 #endif
413 len = recv (sok, lbuf, sizeof (lbuf) - 2, 0);
414 #ifdef USE_OPENSSL
415 else
416 len = _SSL_recv (serv->ssl, lbuf, sizeof (lbuf) - 2);
417 #endif
418 if (len < 1)
420 error = 0;
421 if (len < 0)
423 if (would_block ())
424 return TRUE;
425 error = sock_error ();
427 if (!serv->end_of_motd)
429 server_disconnect (serv->server_session, FALSE, error);
430 if (!servlist_cycle (serv))
432 if (prefs.autoreconnect)
433 auto_reconnect (serv, FALSE, error);
435 } else
437 if (prefs.autoreconnect)
438 auto_reconnect (serv, FALSE, error);
439 else
440 server_disconnect (serv->server_session, FALSE, error);
442 return TRUE;
445 i = 0;
447 lbuf[len] = 0;
449 while (i < len)
451 switch (lbuf[i])
453 case '\r':
454 break;
456 case '\n':
457 serv->linebuf[serv->pos] = 0;
458 server_inline (serv, serv->linebuf, serv->pos);
459 serv->pos = 0;
460 break;
462 default:
463 serv->linebuf[serv->pos] = lbuf[i];
464 if (serv->pos >= (sizeof (serv->linebuf) - 1))
465 fprintf (stderr,
466 "*** XCHAT WARNING: Buffer overflow - shit server!\n");
467 else
468 serv->pos++;
470 i++;
475 static void
476 server_connected (server * serv)
478 prefs.wait_on_exit = TRUE;
479 serv->ping_recv = time (0);
480 serv->connected = TRUE;
481 set_nonblocking (serv->sok);
482 serv->iotag = fe_input_add (serv->sok, FIA_READ|FIA_EX, server_read, serv);
483 if (!serv->no_login)
485 EMIT_SIGNAL (XP_TE_CONNECTED, serv->server_session, NULL, NULL, NULL,
486 NULL, 0);
487 if (serv->network)
489 serv->p_login (serv,
490 (!(((ircnet *)serv->network)->flags & FLAG_USE_GLOBAL) &&
491 (((ircnet *)serv->network)->user)) ?
492 (((ircnet *)serv->network)->user) :
493 prefs.username,
494 (!(((ircnet *)serv->network)->flags & FLAG_USE_GLOBAL) &&
495 (((ircnet *)serv->network)->real)) ?
496 (((ircnet *)serv->network)->real) :
497 prefs.realname);
498 } else
500 serv->p_login (serv, prefs.username, prefs.realname);
502 } else
504 EMIT_SIGNAL (XP_TE_SERVERCONNECTED, serv->server_session, NULL, NULL,
505 NULL, NULL, 0);
508 server_set_name (serv, serv->servername);
509 fe_server_event (serv, FE_SE_CONNECT, 0);
513 static void
514 server_stopconnecting (server * serv)
516 if (serv->iotag)
518 fe_input_remove (serv->iotag);
519 serv->iotag = 0;
522 if (serv->joindelay_tag)
524 fe_timeout_remove (serv->joindelay_tag);
525 serv->joindelay_tag = 0;
528 /* kill the child process trying to connect */
529 kill (serv->childpid, SIGKILL);
530 waitpid (serv->childpid, NULL, 0);
532 close (serv->childwrite);
533 close (serv->childread);
535 #ifdef USE_OPENSSL
536 if (serv->ssl_do_connect_tag)
538 fe_timeout_remove (serv->ssl_do_connect_tag);
539 serv->ssl_do_connect_tag = 0;
541 #endif
543 fe_progressbar_end (serv);
545 serv->connecting = FALSE;
546 fe_server_event (serv, FE_SE_DISCONNECT, 0);
549 #ifdef USE_OPENSSL
550 #define SSLTMOUT 90 /* seconds */
551 static void
552 ssl_cb_info (SSL * s, int where, int ret)
554 /* char buf[128];*/
557 return; /* FIXME: make debug level adjustable in serverlist or settings */
559 /* snprintf (buf, sizeof (buf), "%s (%d)", SSL_state_string_long (s), where);
560 if (g_sess)
561 EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
562 else
563 fprintf (stderr, "%s\n", buf);*/
566 static int
567 ssl_cb_verify (int ok, X509_STORE_CTX * ctx)
569 char subject[256];
570 char issuer[256];
571 char buf[512];
574 X509_NAME_oneline (X509_get_subject_name (ctx->current_cert), subject,
575 sizeof (subject));
576 X509_NAME_oneline (X509_get_issuer_name (ctx->current_cert), issuer,
577 sizeof (issuer));
579 snprintf (buf, sizeof (buf), "* Subject: %s", subject);
580 EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
581 snprintf (buf, sizeof (buf), "* Issuer: %s", issuer);
582 EMIT_SIGNAL (XP_TE_SSLMESSAGE, g_sess, buf, NULL, NULL, NULL, 0);
584 return (TRUE); /* always ok */
587 static int
588 ssl_do_connect (server * serv)
590 char buf[128];
592 g_sess = serv->server_session;
593 if (SSL_connect (serv->ssl) <= 0)
595 char err_buf[128];
596 int err;
598 g_sess = NULL;
599 if ((err = ERR_get_error ()) > 0)
601 ERR_error_string (err, err_buf);
602 snprintf (buf, sizeof (buf), "(%d) %s", err, err_buf);
603 EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, buf, NULL,
604 NULL, NULL, 0);
606 if (ERR_GET_REASON (err) == SSL_R_WRONG_VERSION_NUMBER)
607 PrintText (serv->server_session, _("Are you sure this is a SSL capable server and port?\n"));
609 server_cleanup (serv);
611 if (prefs.autoreconnect) {
612 auto_reconnect (serv, FALSE, -1);
613 return 1;
616 return (0); /* remove it (0) */
619 g_sess = NULL;
621 if (SSL_is_init_finished (serv->ssl))
623 struct cert_info cert_info;
624 struct chiper_info *chiper_info;
625 int verify_error;
626 int i;
628 if (!_SSL_get_cert_info (&cert_info, serv->ssl))
630 snprintf (buf, sizeof (buf), "* Certification info:");
631 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
632 NULL, 0);
633 snprintf (buf, sizeof (buf), " Subject:");
634 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
635 NULL, 0);
636 for (i = 0; cert_info.subject_word[i]; i++)
638 snprintf (buf, sizeof (buf), " %s", cert_info.subject_word[i]);
639 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
640 NULL, 0);
642 snprintf (buf, sizeof (buf), " Issuer:");
643 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
644 NULL, 0);
645 for (i = 0; cert_info.issuer_word[i]; i++)
647 snprintf (buf, sizeof (buf), " %s", cert_info.issuer_word[i]);
648 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
649 NULL, 0);
651 snprintf (buf, sizeof (buf), " Public key algorithm: %s (%d bits)",
652 cert_info.algorithm, cert_info.algorithm_bits);
653 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
654 NULL, 0);
655 /*if (cert_info.rsa_tmp_bits)
657 snprintf (buf, sizeof (buf),
658 " Public key algorithm uses ephemeral key with %d bits",
659 cert_info.rsa_tmp_bits);
660 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
661 NULL, 0);
663 snprintf (buf, sizeof (buf), " Sign algorithm %s",
664 cert_info.sign_algorithm/*, cert_info.sign_algorithm_bits*/);
665 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
666 NULL, 0);
667 snprintf (buf, sizeof (buf), " Valid since %s to %s",
668 cert_info.notbefore, cert_info.notafter);
669 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
670 NULL, 0);
671 } else
673 snprintf (buf, sizeof (buf), " * No Certificate");
674 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
675 NULL, 0);
678 chiper_info = _SSL_get_cipher_info (serv->ssl); /* static buffer */
679 snprintf (buf, sizeof (buf), "* Cipher info:");
680 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL,
682 snprintf (buf, sizeof (buf), " Version: %s, cipher %s (%u bits)",
683 chiper_info->version, chiper_info->chiper,
684 chiper_info->chiper_bits);
685 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL,
688 verify_error = SSL_get_verify_result (serv->ssl);
689 switch (verify_error)
691 case X509_V_OK:
692 /* snprintf (buf, sizeof (buf), "* Verify OK (?)"); */
693 /* EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL, NULL, 0); */
694 break;
695 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
696 case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
697 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
698 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
699 case X509_V_ERR_CERT_HAS_EXPIRED:
700 case X509_V_ERR_CERT_UNTRUSTED:
701 if (serv->accept_invalid_cert)
703 snprintf (buf, sizeof (buf), "* Verify E: %s.? (%d) -- Ignored",
704 X509_verify_cert_error_string (verify_error),
705 verify_error);
706 EMIT_SIGNAL (XP_TE_SSLMESSAGE, serv->server_session, buf, NULL, NULL,
707 NULL, 0);
708 break;
710 default:
711 snprintf (buf, sizeof (buf), "%s.? (%d)",
712 X509_verify_cert_error_string (verify_error),
713 verify_error);
714 EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, buf, NULL, NULL,
715 NULL, 0);
717 server_cleanup (serv);
719 return (0);
722 server_stopconnecting (serv);
724 /* activate gtk poll */
725 server_connected (serv);
727 return (0); /* remove it (0) */
728 } else
730 if (serv->ssl->session && serv->ssl->session->time + SSLTMOUT < time (NULL))
732 snprintf (buf, sizeof (buf), "SSL handshake timed out");
733 EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, buf, NULL,
734 NULL, NULL, 0);
735 server_cleanup (serv); /* ->connecting = FALSE */
737 if (prefs.autoreconnect) {
738 auto_reconnect (serv, FALSE, -1);
739 return 1;
742 return (0); /* remove it (0) */
745 return (1); /* call it more (1) */
748 #endif
750 static int
751 timeout_auto_reconnect (server *serv)
753 if (is_server (serv)) /* make sure it hasnt been closed during the delay */
755 serv->recondelay_tag = 0;
756 if (!serv->connected && !serv->connecting && serv->server_session)
758 server_connect (serv, serv->hostname, serv->port, FALSE);
761 return 0; /* returning 0 should remove the timeout handler */
764 static void
765 auto_reconnect (server *serv, int send_quit, int err)
767 session *s;
768 GSList *list;
769 int del;
771 if (serv->server_session == NULL)
772 return;
774 list = sess_list;
775 while (list) /* make sure auto rejoin can work */
777 s = list->data;
778 if (s->type == SESS_CHANNEL && s->channel[0])
780 strcpy (s->waitchannel, s->channel);
781 strcpy (s->willjoinchannel, s->channel);
783 list = list->next;
786 if (serv->connected)
787 server_disconnect (serv->server_session, send_quit, err);
789 del = prefs.recon_delay * 1000;
790 if (del < 1000)
791 del = 500; /* so it doesn't block the gui */
793 if (err == -1 || err == 0 || err == ECONNRESET || err == ETIMEDOUT)
794 serv->reconnect_away = serv->is_away;
796 /* is this server in a reconnect delay? remove it! */
797 if (serv->recondelay_tag)
799 fe_timeout_remove (serv->recondelay_tag);
800 serv->recondelay_tag = 0;
803 serv->recondelay_tag = fe_timeout_add (del, timeout_auto_reconnect, serv);
804 fe_server_event (serv, FE_SE_RECONDELAY, del);
807 static void
808 server_flush_queue (server *serv)
810 list_free (&serv->outbound_queue);
811 serv->sendq_len = 0;
812 fe_set_throttle (serv);
815 #define waitline2(source,buf,size) waitline(serv->childread,buf,size,0)
817 /* connect() successed */
819 static void
820 server_connect_success (server *serv)
822 #ifdef USE_OPENSSL
823 #define SSLDOCONNTMOUT 300
824 if (serv->use_ssl)
826 char *err;
828 /* it'll be a memory leak, if connection isn't terminated by
829 server_cleanup() */
830 serv->ssl = _SSL_socket (serv->ctx, serv->sok);
831 if ((err = _SSL_set_verify (serv->ctx, ssl_cb_verify, NULL)))
833 EMIT_SIGNAL (XP_TE_CONNFAIL, serv->server_session, err, NULL,
834 NULL, NULL, 0);
835 server_cleanup (serv); /* ->connecting = FALSE */
836 return;
838 /* FIXME: it'll be needed by new servers */
839 /* send(serv->sok, "STLS\r\n", 6, 0); sleep(1); */
840 set_nonblocking (serv->sok);
841 serv->ssl_do_connect_tag = fe_timeout_add (SSLDOCONNTMOUT,
842 ssl_do_connect, serv);
843 return;
846 serv->ssl = NULL;
847 #endif
848 server_stopconnecting (serv); /* ->connecting = FALSE */
849 /* activate glib poll */
850 server_connected (serv);
853 /* receive info from the child-process about connection progress */
855 static gboolean
856 server_read_child (GIOChannel *source, GIOCondition condition, server *serv)
858 session *sess = serv->server_session;
859 char tbuf[128];
860 char outbuf[512];
861 char host[100];
862 char ip[100];
863 char *p;
865 waitline2 (source, tbuf, sizeof tbuf);
867 switch (tbuf[0])
869 case '0': /* print some text */
870 waitline2 (source, tbuf, sizeof tbuf);
871 PrintText (serv->server_session, tbuf);
872 break;
873 case '1': /* unknown host */
874 server_stopconnecting (serv);
875 closesocket (serv->sok4);
876 if (serv->proxy_sok4 != -1)
877 closesocket (serv->proxy_sok4);
878 #ifdef USE_IPV6
879 if (serv->sok6 != -1)
880 closesocket (serv->sok6);
881 if (serv->proxy_sok6 != -1)
882 closesocket (serv->proxy_sok6);
883 #endif
884 EMIT_SIGNAL (XP_TE_UKNHOST, sess, NULL, NULL, NULL, NULL, 0);
885 if (!servlist_cycle (serv))
886 if (prefs.autoreconnect)
887 auto_reconnect (serv, FALSE, -1);
888 break;
889 case '2': /* connection failed */
890 waitline2 (source, tbuf, sizeof tbuf);
891 server_stopconnecting (serv);
892 closesocket (serv->sok4);
893 if (serv->proxy_sok4 != -1)
894 closesocket (serv->proxy_sok4);
895 #ifdef USE_IPV6
896 if (serv->sok6 != -1)
897 closesocket (serv->sok6);
898 if (serv->proxy_sok6 != -1)
899 closesocket (serv->proxy_sok6);
900 #endif
901 EMIT_SIGNAL (XP_TE_CONNFAIL, sess, errorstring (atoi (tbuf)), NULL,
902 NULL, NULL, 0);
903 if (!servlist_cycle (serv))
904 if (prefs.autoreconnect)
905 auto_reconnect (serv, FALSE, -1);
906 break;
907 case '3': /* gethostbyname finished */
908 waitline2 (source, host, sizeof host);
909 waitline2 (source, ip, sizeof ip);
910 waitline2 (source, outbuf, sizeof outbuf);
911 EMIT_SIGNAL (XP_TE_CONNECT, sess, host, ip, outbuf, NULL, 0);
912 snprintf (outbuf, sizeof (outbuf), "%s/auth/xchat_auth",
913 g_get_home_dir ());
914 if (access (outbuf, X_OK) == 0)
916 snprintf (outbuf, sizeof (outbuf), "exec -d %s/auth/xchat_auth %s",
917 g_get_home_dir (), prefs.username);
918 handle_command (serv->server_session, outbuf, FALSE);
920 break;
921 case '4': /* success */
922 waitline2 (source, tbuf, sizeof (tbuf));
923 #ifdef USE_MSPROXY
924 serv->sok = strtol (tbuf, &p, 10);
925 if (*p++ == ' ')
927 serv->proxy_sok = strtol (p, &p, 10);
928 serv->msp_state.clientid = strtol (++p, &p, 10);
929 serv->msp_state.serverid = strtol (++p, &p, 10);
930 serv->msp_state.seq_sent = atoi (++p);
931 } else
932 serv->proxy_sok = -1;
933 #ifdef DEBUG_MSPROXY
934 printf ("Parent got main socket: %d, proxy socket: %d\n", serv->sok, serv->proxy_sok);
935 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);
936 #endif
937 #else
938 serv->sok = atoi (tbuf);
939 #endif
940 #ifdef USE_IPV6
941 /* close the one we didn't end up using */
942 if (serv->sok == serv->sok4)
943 closesocket (serv->sok6);
944 else
945 closesocket (serv->sok4);
946 if (serv->proxy_sok != -1)
948 if (serv->proxy_sok == serv->proxy_sok4)
949 closesocket (serv->proxy_sok6);
950 else
951 closesocket (serv->proxy_sok4);
953 #endif
954 server_connect_success (serv);
955 break;
956 case '5': /* prefs ip discovered */
957 waitline2 (source, tbuf, sizeof tbuf);
958 prefs.local_ip = inet_addr (tbuf);
959 break;
960 case '7': /* gethostbyname (prefs.hostname) failed */
961 sprintf (outbuf,
962 _("Cannot resolve hostname %s\nCheck your IP Settings!\n"),
963 prefs.hostname);
964 PrintText (sess, outbuf);
965 break;
966 case '8':
967 PrintText (sess, _("Proxy traversal failed.\n"));
968 server_disconnect (sess, FALSE, -1);
969 if (prefs.autoreconnect)
970 auto_reconnect (serv, FALSE, -1);
971 break;
972 case '9':
973 waitline2 (source, tbuf, sizeof tbuf);
974 EMIT_SIGNAL (XP_TE_SERVERLOOKUP, sess, tbuf, NULL, NULL, NULL, 0);
975 break;
978 return TRUE;
981 /* kill all sockets & iotags of a server. Stop a connection attempt, or
982 disconnect if already connected. */
984 static int
985 server_cleanup (server * serv)
987 fe_set_lag (serv, 0.0);
989 if (serv->iotag)
991 fe_input_remove (serv->iotag);
992 serv->iotag = 0;
995 if (serv->joindelay_tag)
997 fe_timeout_remove (serv->joindelay_tag);
998 serv->joindelay_tag = 0;
1001 #ifdef USE_OPENSSL
1002 if (serv->ssl)
1004 SSL_shutdown (serv->ssl);
1005 SSL_free (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 (!serv->ctx && serv->use_ssl)
1607 if (!(serv->ctx = _SSL_context_init (ssl_cb_info)))
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];
1645 serv->have_cert = FALSE;
1647 /* first try network specific cert/key */
1648 snprintf (cert_file, sizeof (cert_file), "%s/%s.pem",
1649 get_xdir_fs (), server_get_network (serv, TRUE));
1650 if (SSL_CTX_use_certificate_file (serv->ctx, cert_file, SSL_FILETYPE_PEM) == 1)
1652 if (SSL_CTX_use_PrivateKey_file (serv->ctx, cert_file, SSL_FILETYPE_PEM) == 1)
1653 serv->have_cert = TRUE;
1655 else
1657 /* if that doesn't exist, try ~/.xchat2/client.pem */
1658 snprintf (cert_file, sizeof (cert_file), "%s/%s.pem",
1659 get_xdir_fs (), "client");
1660 if (SSL_CTX_use_certificate_file (serv->ctx, cert_file, SSL_FILETYPE_PEM) == 1)
1662 if (SSL_CTX_use_PrivateKey_file (serv->ctx, cert_file, SSL_FILETYPE_PEM) == 1)
1663 serv->have_cert = TRUE;
1667 #endif
1669 server_set_defaults (serv);
1670 serv->connecting = TRUE;
1671 serv->port = port;
1672 serv->no_login = no_login;
1674 fe_server_event (serv, FE_SE_CONNECTING, 0);
1675 fe_set_away (serv);
1676 server_flush_queue (serv);
1678 if (pipe (read_des) < 0)
1679 return;
1680 serv->childread = read_des[0];
1681 serv->childwrite = read_des[1];
1683 /* create both sockets now, drop one later */
1684 net_sockets (&serv->sok4, &serv->sok6);
1685 #ifdef USE_MSPROXY
1686 /* In case of MS Proxy we have a separate UDP control connection */
1687 if (!serv->dont_use_proxy && (serv->proxy_type == 5))
1688 udp_sockets (&serv->proxy_sok4, &serv->proxy_sok6);
1689 else
1690 #endif
1692 serv->proxy_sok4 = -1;
1693 serv->proxy_sok6 = -1;
1696 #ifdef LOOKUPD
1697 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. */
1698 #endif
1699 switch (pid = fork ())
1701 case -1:
1702 return;
1704 case 0:
1705 /* this is the child */
1706 setuid (getuid ());
1707 server_child (serv);
1708 _exit (0);
1710 serv->childpid = pid;
1711 serv->iotag = fe_input_add (serv->childread, FIA_READ, server_read_child,
1712 serv);
1715 void
1716 server_fill_her_up (server *serv)
1718 serv->connect = server_connect;
1719 serv->disconnect = server_disconnect;
1720 serv->cleanup = server_cleanup;
1721 serv->flush_queue = server_flush_queue;
1722 serv->auto_reconnect = auto_reconnect;
1724 proto_fill_her_up (serv);
1727 void
1728 server_set_encoding (server *serv, char *new_encoding)
1730 char *space;
1732 if (serv->encoding)
1734 free (serv->encoding);
1735 /* can be left as NULL to indicate system encoding */
1736 serv->encoding = NULL;
1737 serv->using_cp1255 = FALSE;
1738 serv->using_irc = FALSE;
1741 if (new_encoding)
1743 serv->encoding = strdup (new_encoding);
1744 /* the serverlist GUI might have added a space
1745 and short description - remove it. */
1746 space = strchr (serv->encoding, ' ');
1747 if (space)
1748 space[0] = 0;
1750 /* server_inline() uses these flags */
1751 if (!strcasecmp (serv->encoding, "CP1255") ||
1752 !strcasecmp (serv->encoding, "WINDOWS-1255"))
1753 serv->using_cp1255 = TRUE;
1754 else if (!strcasecmp (serv->encoding, "IRC"))
1755 serv->using_irc = TRUE;
1759 server *
1760 server_new (void)
1762 static int id = 0;
1763 server *serv;
1765 serv = malloc (sizeof (struct server));
1766 memset (serv, 0, sizeof (struct server));
1768 /* use server.c and proto-irc.c functions */
1769 server_fill_her_up (serv);
1771 serv->id = id++;
1772 serv->sok = -1;
1773 strcpy (serv->nick, prefs.nick1);
1774 server_set_defaults (serv);
1776 serv_list = g_slist_prepend (serv_list, serv);
1778 fe_new_server (serv);
1780 return serv;
1784 is_server (server *serv)
1786 return g_slist_find (serv_list, serv) ? 1 : 0;
1789 void
1790 server_set_defaults (server *serv)
1792 if (serv->chantypes)
1793 free (serv->chantypes);
1794 if (serv->chanmodes)
1795 free (serv->chanmodes);
1796 if (serv->nick_prefixes)
1797 free (serv->nick_prefixes);
1798 if (serv->nick_modes)
1799 free (serv->nick_modes);
1801 serv->chantypes = strdup ("#&!+");
1802 serv->chanmodes = strdup ("beI,k,l");
1803 serv->nick_prefixes = strdup ("@%+");
1804 serv->nick_modes = strdup ("ohv");
1806 serv->nickcount = 1;
1807 serv->end_of_motd = FALSE;
1808 serv->is_away = FALSE;
1809 serv->supports_watch = FALSE;
1810 serv->supports_monitor = FALSE;
1811 serv->bad_prefix = FALSE;
1812 serv->use_who = TRUE;
1813 serv->have_namesx = FALSE;
1814 serv->have_awaynotify = FALSE;
1815 serv->have_uhnames = FALSE;
1816 serv->have_whox = FALSE;
1817 serv->have_idmsg = FALSE;
1818 serv->have_accnotify = FALSE;
1819 serv->have_extjoin = FALSE;
1820 serv->have_sasl = FALSE;
1821 serv->have_except = FALSE;
1824 char *
1825 server_get_network (server *serv, gboolean fallback)
1827 if (serv->network)
1828 return ((ircnet *)serv->network)->name;
1830 if (fallback)
1831 return serv->servername;
1833 return NULL;
1836 void
1837 server_set_name (server *serv, char *name)
1839 GSList *list = sess_list;
1840 session *sess;
1842 if (name[0] == 0)
1843 name = serv->hostname;
1845 /* strncpy parameters must NOT overlap */
1846 if (name != serv->servername)
1848 safe_strcpy (serv->servername, name, sizeof (serv->servername));
1851 while (list)
1853 sess = (session *) list->data;
1854 if (sess->server == serv)
1855 fe_set_title (sess);
1856 list = list->next;
1859 if (serv->server_session->type == SESS_SERVER)
1861 if (serv->network)
1863 safe_strcpy (serv->server_session->channel, ((ircnet *)serv->network)->name, CHANLEN);
1864 } else
1866 safe_strcpy (serv->server_session->channel, name, CHANLEN);
1868 fe_set_channel (serv->server_session);
1872 struct away_msg *
1873 server_away_find_message (server *serv, char *nick)
1875 struct away_msg *away;
1876 GSList *list = away_list;
1877 while (list)
1879 away = (struct away_msg *) list->data;
1880 if (away->server == serv && !serv->p_cmp (nick, away->nick))
1881 return away;
1882 list = list->next;
1884 return NULL;
1887 static void
1888 server_away_free_messages (server *serv)
1890 GSList *list, *next;
1891 struct away_msg *away;
1893 list = away_list;
1894 while (list)
1896 away = list->data;
1897 next = list->next;
1898 if (away->server == serv)
1900 away_list = g_slist_remove (away_list, away);
1901 if (away->message)
1902 free (away->message);
1903 free (away);
1904 next = away_list;
1906 list = next;
1910 void
1911 server_away_save_message (server *serv, char *nick, char *msg)
1913 struct away_msg *away = server_away_find_message (serv, nick);
1915 if (away) /* Change message for known user */
1917 if (away->message)
1918 free (away->message);
1919 away->message = strdup (msg);
1920 } else
1921 /* Create brand new entry */
1923 away = malloc (sizeof (struct away_msg));
1924 if (away)
1926 away->server = serv;
1927 safe_strcpy (away->nick, nick, sizeof (away->nick));
1928 away->message = strdup (msg);
1929 away_list = g_slist_prepend (away_list, away);
1934 void
1935 server_free (server *serv)
1937 serv->cleanup (serv);
1939 serv_list = g_slist_remove (serv_list, serv);
1941 dcc_notify_kill (serv);
1942 serv->flush_queue (serv);
1943 server_away_free_messages (serv);
1945 free (serv->nick_modes);
1946 free (serv->nick_prefixes);
1947 free (serv->chanmodes);
1948 free (serv->chantypes);
1949 if (serv->bad_nick_prefixes)
1950 free (serv->bad_nick_prefixes);
1951 if (serv->last_away_reason)
1952 free (serv->last_away_reason);
1953 if (serv->encoding)
1954 free (serv->encoding);
1955 if (serv->autojoin)
1956 free (serv->autojoin);
1957 #ifdef USE_OPENSSL
1958 if (serv->ctx)
1959 _SSL_context_free (serv->ctx);
1960 #endif
1962 fe_server_callback (serv);
1964 free (serv);
1966 notify_cleanup ();