diff libpurple/protocols/gg/lib/common.c @ 29938:6359fde67f4c

Update our internal libgadu to 1.9.0-rc2. This does not yet build on Windows. Refs #10542. The Windows build errors are the only reason this isn't on `im.pidgin.pidgin` already.
author John Bailey <rekkanoryo@rekkanoryo.org>
date Sun, 21 Feb 2010 16:52:42 +0000
parents 259bbfb423d4
children db6735e579f8
line wrap: on
line diff
--- a/libpurple/protocols/gg/lib/common.c	Sun Feb 21 00:11:56 2010 +0000
+++ b/libpurple/protocols/gg/lib/common.c	Sun Feb 21 16:52:42 2010 +0000
@@ -1,8 +1,8 @@
-/* $Id: common.c 16856 2006-08-19 01:13:25Z evands $ */
+/* $Id: common.c 878 2009-11-16 23:48:19Z wojtekka $ */
 
 /*
  *  (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl>
- *                          Robert J. WoĽny <speedy@ziew.org>
+ *                          Robert J. WoĹşny <speedy@ziew.org>
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU Lesser General Public License Version
@@ -15,13 +15,38 @@
  *
  *  You should have received a copy of the GNU Lesser General Public
  *  License along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301,
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
  *  USA.
  */
 
-#include "libgadu.h"
+/*
+ * Funkcje konwersji między UTF-8 i CP1250 są oparte o kod biblioteki iconv.
+ * Informacje o prawach autorskich oryginalnego kodu zamieszczono poniĹĽej:
+ *
+ * Copyright (C) 1999-2001, 2004 Free Software Foundation, Inc.
+ * This file is part of the GNU LIBICONV Library.
+ *
+ * The GNU LIBICONV Library is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * The GNU LIBICONV Library is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the GNU LIBICONV Library; see the file COPYING.LIB.
+ * If not, write to the Free Software Foundation, Inc., 51 Franklin Street,
+ * Fifth Floor, Boston, MA 02110-1301, USA.
+ */
 
-#ifndef _WIN32
+/**
+ * \file common.c
+ *
+ * \brief Funkcje wykorzystywane przez różne moduły biblioteki
+ */
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
@@ -30,94 +55,133 @@
 #ifdef sun
 #  include <sys/filio.h>
 #endif
-#endif
 
 #include <errno.h>
 #include <fcntl.h>
-#ifndef _WIN32
 #include <netdb.h>
-#endif
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 
+#include "libgadu.h"
+#include "libgadu-internal.h"
+
+/**
+ * Plik, do którego będą przekazywane informacje odpluskwiania.
+ *
+ * Funkcja \c gg_debug() i pochodne mogą być przechwytywane przez aplikację
+ * korzystającą z biblioteki, by wyświetlić je na żądanie użytkownika lub
+ * zapisać do późniejszej analizy. Jeśli nie określono pliku, wybrane
+ * informacje będą wysyłane do standardowego wyjścia błędu (\c stderr).
+ *
+ * \ingroup debug
+ */
 FILE *gg_debug_file = NULL;
 
 #ifndef GG_DEBUG_DISABLE
 
-/*
- * gg_debug() // funkcja wewnętrzna
+/**
+ * \internal Przekazuje informacje odpluskwiania do odpowiedniej funkcji.
+ *
+ * Jeśli aplikacja ustawiła odpowiednią funkcję obsługi w
+ * \c gg_debug_handler_session lub \c gg_debug_handler, jest ona wywoływana.
+ * W przeciwnym wypadku wynik jest wysyłany do standardowego wyjścia błędu.
  *
- * wy¶wietla komunikat o danym poziomie, o ile użytkownik sobie tego życzy.
+ * \param sess Struktura sesji (może być \c NULL)
+ * \param level Poziom informacji
+ * \param format Format wiadomości (zgodny z \c printf)
+ * \param ap Lista argumentĂłw (zgodna z \c printf)
+ */
+void gg_debug_common(struct gg_session *sess, int level, const char *format, va_list ap)
+{
+	if (gg_debug_handler_session)
+		(*gg_debug_handler_session)(sess, level, format, ap);
+	else if (gg_debug_handler)
+		(*gg_debug_handler)(level, format, ap);
+	else if (gg_debug_level & level)
+		vfprintf(gg_debug_file ? gg_debug_file : stderr, format, ap);
+}
+
+
+/**
+ * \internal Przekazuje informacjÄ™ odpluskawiania.
  *
- *  - level - poziom wiadomo¶ci
- *  - format... - tre¶ć wiadomo¶ci (kompatybilna z printf())
+ * \param level Poziom wiadomości
+ * \param format Format wiadomości (zgodny z \c printf)
+ *
+ * \ingroup debug
  */
 void gg_debug(int level, const char *format, ...)
 {
 	va_list ap;
 	int old_errno = errno;
-	
-	if (gg_debug_handler) {
-		va_start(ap, format);
-		(*gg_debug_handler)(level, format, ap);
-		va_end(ap);
+	va_start(ap, format);
+	gg_debug_common(NULL, level, format, ap);
+	va_end(ap);
+	errno = old_errno;
+}
 
-		goto cleanup;
-	}
-	
-	if ((gg_debug_level & level)) {
-		va_start(ap, format);
-		vfprintf((gg_debug_file) ? gg_debug_file : stderr, format, ap);
-		va_end(ap);
-	}
-
-cleanup:
+/**
+ * \internal Przekazuje informacjÄ™ odpluskwiania zwiÄ…zanÄ… z sesjÄ….
+ *
+ * \param sess Struktura sesji
+ * \param level Poziom wiadomości
+ * \param format Format wiadomości (zgodny z \c printf)
+ *
+ * \ingroup debug
+ */
+void gg_debug_session(struct gg_session *sess, int level, const char *format, ...)
+{
+	va_list ap;
+	int old_errno = errno;
+	va_start(ap, format);
+	gg_debug_common(sess, level, format, ap);
+	va_end(ap);
 	errno = old_errno;
 }
 
 #endif
 
-/*
- * gg_vsaprintf() // funkcja pomocnicza
+/**
+ * \internal Odpowiednik funkcji \c vsprintf alokujÄ…cy miejsce na wynik.
+ *
+ * Funkcja korzysta z funkcji \c vsnprintf, sprawdzając czy dostępna funkcja
+ * systemowa jest zgodna ze standardem C99 czy wcześniejszymi.
  *
- * robi dokładnie to samo, co vsprintf(), tyle że alokuje sobie wcze¶niej
- * miejsce na dane. powinno działać na tych maszynach, które maj± funkcję
- * vsnprintf() zgodn± z C99, jak i na wcze¶niejszych.
+ * \param format Format wiadomości (zgodny z \c printf)
+ * \param ap Lista argumentĂłw (zgodna z \c printf)
  *
- *  - format - opis wy¶wietlanego tekstu jak dla printf()
- *  - ap - lista argumentów dla printf()
+ * \return Zaalokowany bufor lub NULL, jeśli zabrakło pamięci.
  *
- * zaalokowany bufor, który należy póĽniej zwolnić, lub NULL
- * je¶li nie udało się wykonać zadania.
+ * \ingroup helper
  */
 char *gg_vsaprintf(const char *format, va_list ap)
 {
 	int size = 0;
 	const char *start;
 	char *buf = NULL;
-	
-#ifdef __GG_LIBGADU_HAVE_VA_COPY
+
+#ifdef GG_CONFIG_HAVE_VA_COPY
 	va_list aq;
 
 	va_copy(aq, ap);
 #else
-#  ifdef __GG_LIBGADU_HAVE___VA_COPY
+#  ifdef GG_CONFIG_HAVE___VA_COPY
 	va_list aq;
 
 	__va_copy(aq, ap);
 #  endif
 #endif
 
-	start = format; 
+	start = format;
 
-#ifndef __GG_LIBGADU_HAVE_C99_VSNPRINTF
+#ifndef GG_CONFIG_HAVE_C99_VSNPRINTF
 	{
 		int res;
 		char *tmp;
-		
+
 		size = 128;
 		do {
 			size *= 2;
@@ -132,9 +196,9 @@
 #else
 	{
 		char tmp[2];
-		
-		/* libce Solarisa przy buforze NULL zawsze zwracaj± -1, więc
-		 * musimy podać co¶ istniej±cego jako cel printf()owania. */
+
+		/* libce Solarisa przy buforze NULL zawsze zwracają -1, więc
+		 * musimy podać coś istniejącego jako cel printf()owania. */
 		size = vsnprintf(tmp, sizeof(tmp), format, ap);
 		if (!(buf = malloc(size + 1)))
 			return NULL;
@@ -142,33 +206,33 @@
 #endif
 
 	format = start;
-	
-#ifdef __GG_LIBGADU_HAVE_VA_COPY
+
+#ifdef GG_CONFIG_HAVE_VA_COPY
 	vsnprintf(buf, size + 1, format, aq);
 	va_end(aq);
 #else
-#  ifdef __GG_LIBGADU_HAVE___VA_COPY
+#  ifdef GG_CONFIG_HAVE___VA_COPY
 	vsnprintf(buf, size + 1, format, aq);
 	va_end(aq);
 #  else
 	vsnprintf(buf, size + 1, format, ap);
 #  endif
 #endif
-	
+
 	return buf;
 }
 
-/*
- * gg_saprintf() // funkcja pomocnicza
+/**
+ * \internal Odpowiednik funkcji \c sprintf alokujÄ…cy miejsce na wynik.
+ *
+ * Funkcja korzysta z funkcji \c vsnprintf, sprawdzając czy dostępna funkcja
+ * systemowa jest zgodna ze standardem C99 czy wcześniejszymi.
  *
- * robi dokładnie to samo, co sprintf(), tyle że alokuje sobie wcze¶niej
- * miejsce na dane. powinno działać na tych maszynach, które maj± funkcję
- * vsnprintf() zgodn± z C99, jak i na wcze¶niejszych.
+ * \param format Format wiadomości (zgodny z \c printf)
  *
- *  - format... - tre¶ć taka sama jak w funkcji printf()
+ * \return Zaalokowany bufor lub NULL, jeśli zabrakło pamięci.
  *
- * zaalokowany bufor, który należy póĽniej zwolnić, lub NULL
- * je¶li nie udało się wykonać zadania.
+ * \ingroup helper
  */
 char *gg_saprintf(const char *format, ...)
 {
@@ -182,18 +246,17 @@
 	return res;
 }
 
-/*
- * gg_get_line() // funkcja pomocnicza
- * 
- * podaje kolejn± linię z bufora tekstowego. niszczy go bezpowrotnie, dziel±c
- * na kolejne stringi. zdarza się, nie ma potrzeby pisania funkcji dubluj±cej
- * bufor żeby tylko mieć nieruszone dane wej¶ciowe, skoro i tak nie będ± nam
- * poĽniej potrzebne. obcina `\r\n'.
- * 
- *  - ptr - wskaĽnik do zmiennej, która przechowuje aktualn± pozycję
- *    w przemiatanym buforze
- * 
- * wskaĽnik do kolejnej linii tekstu lub NULL, je¶li to już koniec bufora.
+/**
+ * \internal Pobiera liniÄ™ tekstu z bufora.
+ *
+ * Funkcja niszczy bufor źródłowy bezpowrotnie, dzieląc go na kolejne ciągi
+ * znaków i obcina znaki końca linii.
+ *
+ * \param ptr Wskaźnik do zmiennej, która przechowuje aktualne położenie
+ *            w analizowanym buforze
+ *
+ * \return Wskaźnik do kolejnej linii tekstu lub NULL, jeśli to już koniec
+ *         bufora.
  */
 char *gg_get_line(char **ptr)
 {
@@ -207,99 +270,30 @@
 	if (!(foo = strchr(*ptr, '\n')))
 		*ptr += strlen(*ptr);
 	else {
+		size_t len;
 		*ptr = foo + 1;
 		*foo = 0;
-		if (strlen(res) > 1 && res[strlen(res) - 1] == '\r')
-			res[strlen(res) - 1] = 0;
+
+		len = strlen(res);
+
+		if (len > 1 && res[len - 1] == '\r')
+			res[len - 1] = 0;
 	}
 
 	return res;
 }
 
-/*
- * gg_connect() // funkcja pomocnicza
+/**
+ * \internal Czyta liniÄ™ tekstu z gniazda.
  *
- * ł±czy się z serwerem. pierwszy argument jest typu (void *), żeby nie
- * musieć niczego inkludować w libgadu.h i nie psuć jaki¶ głupich zależno¶ci
- * na dziwnych systemach.
- *
- *  - addr - adres serwera (struct in_addr *)
- *  - port - port serwera
- *  - async - asynchroniczne poł±czenie
+ * Funkcja czyta tekst znak po znaku, więc nie jest efektywna, ale dzięki
+ * brakowi buforowania, nie koliduje z innymi funkcjami odczytu.
  *
- * deskryptor gniazda lub -1 w przypadku błędu (kod błędu w zmiennej errno).
- */
-int gg_connect(void *addr, int port, int async)
-{
-	int sock, one = 1, errno2;
-	struct sockaddr_in sin;
-	struct in_addr *a = addr;
-	struct sockaddr_in myaddr;
-
-	gg_debug(GG_DEBUG_FUNCTION, "** gg_connect(%s, %d, %d);\n", inet_ntoa(*a), port, async);
-	
-	if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
-		gg_debug(GG_DEBUG_MISC, "// gg_connect() socket() failed (errno=%d, %s)\n", errno, strerror(errno));
-		return -1;
-	}
-
-	memset(&myaddr, 0, sizeof(myaddr));
-	myaddr.sin_family = AF_INET;
-
-	myaddr.sin_addr.s_addr = gg_local_ip;
-
-	if (bind(sock, (struct sockaddr *) &myaddr, sizeof(myaddr)) == -1) {
-		gg_debug(GG_DEBUG_MISC, "// gg_connect() bind() failed (errno=%d, %s)\n", errno, strerror(errno));
-		return -1;
-	}
-
-#ifdef ASSIGN_SOCKETS_TO_THREADS
-	gg_win32_thread_socket(0, sock);
-#endif
-
-	if (async) {
-#ifdef FIONBIO
-		if (ioctl(sock, FIONBIO, &one) == -1) {
-#else
-		if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
-#endif
-			gg_debug(GG_DEBUG_MISC, "// gg_connect() ioctl() failed (errno=%d, %s)\n", errno, strerror(errno));
-			errno2 = errno;
-			close(sock);
-			errno = errno2;
-			return -1;
-		}
-	}
-
-	sin.sin_port = htons(port);
-	sin.sin_family = AF_INET;
-	sin.sin_addr.s_addr = a->s_addr;
-	
-	if (connect(sock, (struct sockaddr*) &sin, sizeof(sin)) == -1) {
-		if (errno && (!async || errno != EINPROGRESS)) {
-			gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() failed (errno=%d, %s)\n", errno, strerror(errno));
-			errno2 = errno;
-			close(sock);
-			errno = errno2;
-			return -1;
-		}
-		gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() in progress\n");
-	}
-	
-	return sock;
-}
-
-/*
- * gg_read_line() // funkcja pomocnicza
+ * \param sock Deskryptor gniazda
+ * \param buf WskaĹşnik do bufora
+ * \param length Długość bufora
  *
- * czyta jedn± linię tekstu z gniazda.
- *
- *  - sock - deskryptor gniazda
- *  - buf - wskaĽnik do bufora
- *  - length - długo¶ć bufora
- *
- * je¶li trafi na bł±d odczytu lub podano nieprawidłowe parametry, zwraca NULL.
- * inaczej zwraca buf.
+ * \return Zwraca \c buf jeśli się powiodło, lub \c NULL w przypadku błędu.
  */
 char *gg_read_line(int sock, char *buf, int length)
 {
@@ -331,38 +325,116 @@
 	return buf;
 }
 
-/*
- * gg_chomp() // funkcja pomocnicza
+/**
+ * \internal Nawiązuje połączenie TCP.
+ *
+ * \param addr WskaĹşnik na strukturÄ™ \c in_addr z adresem serwera
+ * \param port Port serwera
+ * \param async Flaga asynchronicznego połączenia
+ *
+ * \return Deskryptor gniazda lub -1 w przypadku błędu
  *
- * ucina "\r\n" lub "\n" z końca linii.
+ * \ingroup helper
+ */
+int gg_connect(void *addr, int port, int async)
+{
+	int sock, one = 1, errno2;
+	struct sockaddr_in sin;
+	struct in_addr *a = addr;
+	struct sockaddr_in myaddr;
+
+	gg_debug(GG_DEBUG_FUNCTION, "** gg_connect(%s, %d, %d);\n", inet_ntoa(*a), port, async);
+
+	if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
+		gg_debug(GG_DEBUG_MISC, "// gg_connect() socket() failed (errno=%d, %s)\n", errno, strerror(errno));
+		return -1;
+	}
+
+	memset(&myaddr, 0, sizeof(myaddr));
+	myaddr.sin_family = AF_INET;
+
+	myaddr.sin_addr.s_addr = gg_local_ip;
+
+	if (bind(sock, (struct sockaddr *) &myaddr, sizeof(myaddr)) == -1) {
+		gg_debug(GG_DEBUG_MISC, "// gg_connect() bind() failed (errno=%d, %s)\n", errno, strerror(errno));
+		errno2 = errno;
+		close(sock);
+		errno = errno2;
+		return -1;
+	}
+
+#ifdef ASSIGN_SOCKETS_TO_THREADS
+	gg_win32_thread_socket(0, sock);
+#endif
+
+	if (async) {
+#ifdef FIONBIO
+		if (ioctl(sock, FIONBIO, &one) == -1) {
+#else
+		if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
+#endif
+			gg_debug(GG_DEBUG_MISC, "// gg_connect() ioctl() failed (errno=%d, %s)\n", errno, strerror(errno));
+			errno2 = errno;
+			close(sock);
+			errno = errno2;
+			return -1;
+		}
+	}
+
+	sin.sin_port = htons(port);
+	sin.sin_family = AF_INET;
+	sin.sin_addr.s_addr = a->s_addr;
+
+	if (connect(sock, (struct sockaddr*) &sin, sizeof(sin)) == -1) {
+		if (errno && (!async || errno != EINPROGRESS)) {
+			gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() failed (errno=%d, %s)\n", errno, strerror(errno));
+			errno2 = errno;
+			close(sock);
+			errno = errno2;
+			return -1;
+		}
+		gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() in progress\n");
+	}
+
+	return sock;
+}
+
+/**
+ * \internal Usuwa znaki końca linii.
  *
- *  - line - linia do przycięcia
+ * Funkcja działa bezpośrednio na buforze.
+ *
+ * \param line Bufor z tekstem
+ *
+ * \ingroup helper
  */
 void gg_chomp(char *line)
 {
 	int len;
-	
+
 	if (!line)
 		return;
 
 	len = strlen(line);
-	
+
 	if (len > 0 && line[len - 1] == '\n')
 		line[--len] = 0;
 	if (len > 0 && line[len - 1] == '\r')
 		line[--len] = 0;
 }
 
-/*
- * gg_urlencode() // funkcja wewnętrzna
+/**
+ * \internal Koduje ciÄ…g znakĂłw do postacji adresu HTTP.
  *
- * zamienia podany tekst na ci±g znaków do formularza http. przydaje się
- * przy różnych usługach katalogu publicznego.
+ * Zamienia znaki niedrukowalne, spoza ASCII i majÄ…ce specjalne znaczenie
+ * dla protokołu HTTP na encje postaci \c %XX, gdzie \c XX jest szesnastkową
+ * wartością znaku.
+ * 
+ * \param str CiÄ…g znakĂłw do zakodowania
  *
- *  - str - ci±g znaków do zakodowania
+ * \return Zaalokowany bufor lub \c NULL w przypadku błędu.
  *
- * zaalokowany bufor, który należy póĽniej zwolnić albo NULL
- * w przypadku błędu.
+ * \ingroup helper
  */
 char *gg_urlencode(const char *str)
 {
@@ -400,16 +472,19 @@
 	return buf;
 }
 
-/*
- * gg_http_hash() // funkcja wewnętrzna
+/**
+ * \internal Wyznacza skrót dla usług HTTP.
  *
- * funkcja licz±ca hash dla adresu e-mail, hasła i paru innych.
+ * Funkcja jest wykorzystywana do wyznaczania skrótu adresu e-mail, hasła
+ * i innych wartości przekazywanych jako parametry usług HTTP.
  *
- *  - format... - format kolejnych parametrów ('s' je¶li dany parametr jest
- *                ci±giem znaków lub 'u' je¶li numerem GG)
+ * W parametrze \c format należy umieścić znaki określające postać kolejnych
+ * parametrów: \c 's' jeśli parametr jest ciągiem znaków, \c 'u' jeśli jest
+ * liczbÄ….
  *
- * hash wykorzystywany przy rejestracji i wszelkich manipulacjach własnego
- * wpisu w katalogu publicznym.
+ * \param format Format kolejnych parametrĂłw (niezgodny z \c printf)
+ *
+ * \return Wartość skrótu
  */
 int gg_http_hash(const char *format, ...)
 {
@@ -428,7 +503,7 @@
 		} else {
 			if (!(arg = va_arg(ap, char*)))
 				arg = "";
-		}	
+		}
 
 		i = 0;
 		while ((c = (unsigned char) arg[i++]) != 0) {
@@ -442,95 +517,6 @@
 	return (b < 0 ? -b : b);
 }
 
-/*
- * gg_gethostbyname() // funkcja pomocnicza
- *
- * odpowiednik gethostbyname() troszcz±cy się o współbieżno¶ć, gdy mamy do
- * dyspozycji funkcję gethostbyname_r().
- *
- *  - hostname - nazwa serwera
- *
- * zwraca wskaĽnik na strukturę in_addr, któr± należy zwolnić.
- */
-struct in_addr *gg_gethostbyname(const char *hostname)
-{
-	struct in_addr *addr = NULL;
-
-#ifdef HAVE_GETHOSTBYNAME_R
-	char *tmpbuf = NULL, *buf = NULL;
-	struct hostent *hp = NULL, *hp2 = NULL;
-	int h_errnop, ret;
-	size_t buflen = 1024;
-	int new_errno;
-	
-	new_errno = ENOMEM;
-	
-	if (!(addr = malloc(sizeof(struct in_addr))))
-		goto cleanup;
-	
-	if (!(hp = calloc(1, sizeof(*hp))))
-		goto cleanup;
-
-	if (!(buf = malloc(buflen)))
-		goto cleanup;
-
-	tmpbuf = buf;
-	
-	while ((ret = gethostbyname_r(hostname, hp, buf, buflen, &hp2, &h_errnop)) == ERANGE) {
-		buflen *= 2;
-		
-		if (!(tmpbuf = realloc(buf, buflen)))
-			break;
-		
-		buf = tmpbuf;
-	}
-	
-	if (ret)
-		new_errno = h_errnop;
-
-	if (ret || !hp2 || !tmpbuf)
-		goto cleanup;
-	
-	memcpy(addr, hp->h_addr, sizeof(struct in_addr));
-	
-	free(buf);
-	free(hp);
-	
-	return addr;
-	
-cleanup:
-	errno = new_errno;
-	
-	if (addr)
-		free(addr);
-	if (hp)
-		free(hp);
-	if (buf)
-		free(buf);
-	
-	return NULL;
-#else
-	struct hostent *hp;
-
-	if (!(addr = malloc(sizeof(struct in_addr)))) {
-		goto cleanup;
-	}
-
-	if (!(hp = gethostbyname(hostname)))
-		goto cleanup;
-
-	memcpy(addr, hp->h_addr, sizeof(struct in_addr));
-
-	return addr;
-	
-cleanup:
-	if (addr)
-		free(addr);
-
-	return NULL;
-#endif
-}
-
 #ifdef ASSIGN_SOCKETS_TO_THREADS
 
 typedef struct gg_win32_thread {
@@ -541,23 +527,22 @@
 
 struct gg_win32_thread *gg_win32_threads = 0;
 
-/*
- * gg_win32_thread_socket() // funkcja pomocnicza, tylko dla win32
+/**
+ * \internal Zwraca deskryptor gniazda, które było ostatnio tworzone dla wątku.
  *
- * zwraca deskryptor gniazda, które było ostatnio tworzone dla w±tku
- * o podanym identyfikatorze.
+ * Jeśli na win32 przy połączeniach synchronicznych zapamiętamy w jakim
+ * wątku uruchomiliśmy funkcję, która się z czymkolwiek łączy, to z osobnego
+ * wątku możemy anulować połączenie poprzez \c gg_win32_thread_socket(watek,-1)
  *
- * je¶li na win32 przy poł±czeniach synchronicznych zapamiętamy w jakim
- * w±tku uruchomili¶my funkcję, która się z czymkolwiek ł±czy, to z osobnego
- * w±tku możemy anulować poł±czenie poprzez gg_win32_thread_socket(watek, -1);
- * 
- * - thread_id - id w±tku. je¶li jest równe 0, brany jest aktualny w±tek,
- *               je¶li równe -1, usuwa wpis o podanym sockecie.
- * - socket - deskryptor gniazda. je¶li równe 0, zwraca deskryptor gniazda
- *            dla podanego w±tku, je¶li równe -1, usuwa wpis, je¶li co¶
- *            innego, ustawia dla podanego w±tku dany numer deskryptora.
+ * \param thread_id Identyfikator wątku (jeśli jest równe 0, brany jest
+ *                  aktualny wątek, jeśli równe -1, usuwa wpis dotyczący
+ *                  danego gniazda sockecie)
+ * \param socket Deskryptor gniazda (jeśli równe 0, zwraca deskryptor gniazda
+ *               dla podanego wątku, jeśli równe -1, usuwa wpis, jeśli coś
+ *               innego, ustawia dla podanego wÄ…tku dany numer deskryptora)
  *
- * je¶li socket jest równe 0, zwraca deskryptor gniazda dla podanego w±tku.
+ * \return Jeśli socket jest równe 0, zwraca deskryptor gniazda dla podanego
+ *         wÄ…tku.
  */
 int gg_win32_thread_socket(int thread_id, int socket)
 {
@@ -567,7 +552,7 @@
 
 	if (!thread_id)
 		thread_id = GetCurrentThreadId();
-	
+
 	while (wsk) {
 		if ((thread_id == -1 && wsk->socket == socket) || wsk->id == thread_id) {
 			if (close) {
@@ -593,7 +578,7 @@
 		closesocket(socket);
 	if (close || !socket)
 		return 0;
-	
+
 	/* Dodaje nowy element */
 	wsk = malloc(sizeof(gg_win32_thread));
 	wsk->id = thread_id;
@@ -606,28 +591,33 @@
 
 #endif /* ASSIGN_SOCKETS_TO_THREADS */
 
+/**
+ * \internal Zestaw znakĂłw kodowania base64.
+ */
 static char gg_base64_charset[] =
 	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
-/*
- * gg_base64_encode()
+/**
+ * \internal Koduje ciÄ…g znakĂłw do base64.
+ *
+ * Wynik funkcji należy zwolnić za pomocą \c free.
  *
- * zapisuje ci±g znaków w base64.
+ * \param buf Bufor z danami do zakodowania
  *
- *  - buf - ci±g znaków.
+ * \return Zaalokowany bufor z zakodowanymi danymi
  *
- * zaalokowany bufor.
+ * \ingroup helper
  */
 char *gg_base64_encode(const char *buf)
 {
 	char *out, *res;
 	unsigned int i = 0, j = 0, k = 0, len = strlen(buf);
-	
+
 	res = out = malloc((len / 3 + 1) * 4 + 2);
 
 	if (!res)
 		return NULL;
-	
+
 	while (j <= len) {
 		switch (i % 4) {
 			case 0:
@@ -660,20 +650,22 @@
 	if (i % 4)
 		for (j = 0; j < 4 - (i % 4); j++, out++)
 			*out = '=';
-	
+
 	*out = 0;
-	
+
 	return res;
 }
 
-/*
- * gg_base64_decode()
+/**
+ * \internal Dekoduje ciÄ…g znakĂłw zapisany w base64.
+ *
+ * Wynik funkcji należy zwolnić za pomocą \c free.
  *
- * dekoduje ci±g znaków z base64.
+ * \param buf Bufor źródłowy z danymi do zdekodowania
  *
- *  - buf - ci±g znaków.
+ * \return Zaalokowany bufor ze zdekodowanymi danymi
  *
- * zaalokowany bufor.
+ * \ingroup helper
  */
 char *gg_base64_decode(const char *buf)
 {
@@ -683,7 +675,7 @@
 
 	if (!buf)
 		return NULL;
-	
+
 	save = res = calloc(1, (strlen(buf) / 4 + 1) * 3 + 2);
 
 	if (!save)
@@ -720,23 +712,24 @@
 		index %= 4;
 	}
 	*res = 0;
-	
+
 	return save;
 }
 
-/*
- * gg_proxy_auth() // funkcja wewnętrzna
+/**
+ * \internal Tworzy nagłówek autoryzacji serwera pośredniczącego.
  *
- * tworzy nagłówek autoryzacji dla proxy.
- * 
- * zaalokowany tekst lub NULL, je¶li proxy nie jest wł±czone lub nie wymaga
- * autoryzacji.
+ * Dane pobiera ze zmiennych globalnych \c gg_proxy_username i
+ * \c gg_proxy_password.
+ *
+ * \return Zaalokowany bufor z tekstem lub NULL, jeśli serwer pośredniczący
+ *         nie jest uĹĽywany lub nie wymaga autoryzacji.
  */
 char *gg_proxy_auth()
 {
 	char *tmp, *enc, *out;
 	unsigned int tmp_size;
-	
+
 	if (!gg_proxy_enabled || !gg_proxy_username || !gg_proxy_password)
 		return NULL;
 
@@ -749,14 +742,14 @@
 		free(tmp);
 		return NULL;
 	}
-	
+
 	free(tmp);
 
 	if (!(out = malloc(strlen(enc) + 40))) {
 		free(enc);
 		return NULL;
 	}
-	
+
 	snprintf(out, strlen(enc) + 40,  "Proxy-Authorization: Basic %s\r\n", enc);
 
 	free(enc);
@@ -764,13 +757,21 @@
 	return out;
 }
 
+/**
+ * \internal Tablica pomocnicza do wyznaczania sumy kontrolnej.
+ */
 static uint32_t gg_crc32_table[256];
+
+/**
+ * \internal Flaga wypełnienia tablicy pomocniczej do wyznaczania sumy
+ * kontrolnej.
+ */
 static int gg_crc32_initialized = 0;
 
-/*
- * gg_crc32_make_table()  // funkcja wewnętrzna
+/**
+ * \internal Tworzy tablicÄ™ pomocniczÄ… do wyznaczania sumy kontrolnej.
  */
-static void gg_crc32_make_table()
+static void gg_crc32_make_table(void)
 {
 	uint32_t h = 1;
 	unsigned int i, j;
@@ -787,16 +788,15 @@
 	gg_crc32_initialized = 1;
 }
 
-/*
- * gg_crc32()
- *
- * wyznacza sumę kontroln± CRC32 danego bloku danych.
+/**
+ * Wyznacza sumÄ™ kontrolnÄ… CRC32.
  *
- *  - crc - suma kontrola poprzedniego bloku danych lub 0 je¶li pierwszy
- *  - buf - bufor danych
- *  - size - ilo¶ć danych
+ * \param crc Suma kontrola poprzedniego bloku danych lub 0 jeśli liczona
+ *            jest suma kontrolna pierwszego bloku
+ * \param buf Bufor danych
+ * \param len Długość bufora danych
  *
- * suma kontrolna CRC32.
+ * \return Suma kontrolna.
  */
 uint32_t gg_crc32(uint32_t crc, const unsigned char *buf, int len)
 {
@@ -814,6 +814,186 @@
 	return crc ^ 0xffffffffL;
 }
 
+/**
+ * \internal Tablica konwersji między CP1250 a UTF-8.
+ */
+static const uint16_t table_cp1250[] = {
+	0x20ac, '?',    0x201a,    '?', 0x201e, 0x2026, 0x2020, 0x2021, 
+	   '?', 0x2030, 0x0160, 0x2039, 0x015a, 0x0164, 0x017d, 0x0179, 
+	   '?', 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014, 
+	   '?', 0x2122, 0x0161, 0x203a, 0x015b, 0x0165, 0x017e, 0x017a, 
+	0x00a0, 0x02c7, 0x02d8, 0x0141, 0x00a4, 0x0104, 0x00a6, 0x00a7, 
+	0x00a8, 0x00a9, 0x015e, 0x00ab, 0x00ac, 0x00ad, 0x00ae, 0x017b, 
+	0x00b0, 0x00b1, 0x02db, 0x0142, 0x00b4, 0x00b5, 0x00b6, 0x00b7, 
+	0x00b8, 0x0105, 0x015f, 0x00bb, 0x013d, 0x02dd, 0x013e, 0x017c, 
+	0x0154, 0x00c1, 0x00c2, 0x0102, 0x00c4, 0x0139, 0x0106, 0x00c7, 
+	0x010c, 0x00c9, 0x0118, 0x00cb, 0x011a, 0x00cd, 0x00ce, 0x010e, 
+	0x0110, 0x0143, 0x0147, 0x00d3, 0x00d4, 0x0150, 0x00d6, 0x00d7, 
+	0x0158, 0x016e, 0x00da, 0x0170, 0x00dc, 0x00dd, 0x0162, 0x00df, 
+	0x0155, 0x00e1, 0x00e2, 0x0103, 0x00e4, 0x013a, 0x0107, 0x00e7, 
+	0x010d, 0x00e9, 0x0119, 0x00eb, 0x011b, 0x00ed, 0x00ee, 0x010f, 
+	0x0111, 0x0144, 0x0148, 0x00f3, 0x00f4, 0x0151, 0x00f6, 0x00f7, 
+	0x0159, 0x016f, 0x00fa, 0x0171, 0x00fc, 0x00fd, 0x0163, 0x02d9, 
+};
+
+/**
+ * \internal Zamienia tekst kodowany CP1250 na UTF-8.
+ *
+ * \param b Tekst źródłowy w CP1250.
+ *
+ * \return Zaalokowany bufor z tekstem w UTF-8.
+ */
+char *gg_cp_to_utf8(const char *b)
+{
+	unsigned char *buf = (unsigned char *) b;
+	char *newbuf;
+	int newlen = 0;
+	int i, j;
+
+	for (i = 0; buf[i]; i++) {
+		uint16_t znak = (buf[i] < 0x80) ? buf[i] : table_cp1250[buf[i]-0x80];
+
+		if (znak < 0x80)	newlen += 1;
+		else if (znak < 0x800)	newlen += 2;
+		else			newlen += 3;
+	}
+
+	if (!(newbuf = malloc(newlen+1))) {
+		gg_debug(GG_DEBUG_MISC, "// gg_cp_to_utf8() not enough memory\n");
+		return NULL;
+	}
+
+	for (i = 0, j = 0; buf[i]; i++) {
+		uint16_t znak = (buf[i] < 0x80) ? buf[i] : table_cp1250[buf[i]-0x80];
+		int count;
+
+		if (znak < 0x80)	count = 1;
+		else if (znak < 0x800)	count = 2;
+		else			count = 3;
+
+		switch (count) {
+			case 3: newbuf[j+2] = 0x80 | (znak & 0x3f); znak = znak >> 6; znak |= 0x800;
+			case 2: newbuf[j+1] = 0x80 | (znak & 0x3f); znak = znak >> 6; znak |= 0xc0;
+			case 1: newbuf[j] = znak;
+		}
+		j += count;
+	}
+	newbuf[j] = '\0';
+
+	return newbuf;
+}
+
+/**
+ * \internal Dekoduje jeden znak UTF-8.
+ *
+ * \note Funkcja nie jest kompletnÄ… implementacjÄ… UTF-8, a wersjÄ… uproszczonÄ…
+ * do potrzeb kodowania CP1250.
+ *
+ * \param s Tekst źródłowy.
+ * \param n Długość tekstu źródłowego.
+ * \param ch WskaĹşnik na wynik dekodowania.
+ *
+ * \return Długość zdekodowanej sekwencji w bajtach lub wartość mniejsza
+ * od zera w przypadku błędu.
+ */
+static int gg_utf8_helper(unsigned char *s, int n, uint16_t *ch)
+{
+	unsigned char c = s[0];
+
+	if (c < 0x80) {
+		*ch = c;
+		return 1;
+	}
+
+	if (c < 0xc2) 
+		return -1;
+
+	if (c < 0xe0) {
+		if (n < 2)
+			return -2;
+		if (!((s[1] ^ 0x80) < 0x40))
+			return -1;
+		*ch = ((uint16_t) (c & 0x1f) << 6) | (uint16_t) (s[1] ^ 0x80);
+		return 2;
+	} 
+	
+	if (c < 0xf0) {
+		if (n < 3)
+			return -2;
+		if (!((s[1] ^ 0x80) < 0x40 && (s[2] ^ 0x80) < 0x40 && (c >= 0xe1 || s[1] >= 0xa0)))
+			return -1;
+		*ch = ((uint16_t) (c & 0x0f) << 12) | ((uint16_t) (s[1] ^ 0x80) << 6) | (uint16_t) (s[2] ^ 0x80);
+		return 3;
+	}
+
+	return -1;
+}
+
+/**
+ * \internal Zamienia tekst kodowany UTF-8 na CP1250.
+ *
+ * \param b Tekst źródłowy w UTF-8.
+ *
+ * \return Zaalokowany bufor z tekstem w CP1250.
+ */
+char *gg_utf8_to_cp(const char *b)
+{
+	unsigned char *buf = (unsigned char *) b;
+	char *newbuf;
+	int newlen = 0;
+	int len;
+	int i, j;
+
+	len = strlen(b);
+
+	for (i = 0; i < len; newlen++) {
+		uint16_t discard;
+		int ret;
+		
+		ret = gg_utf8_helper(&buf[i], len - i, &discard);
+
+		if (ret > 0)
+			i += ret;
+		else
+			i++;
+	}
+
+	if (!(newbuf = malloc(newlen+1))) {
+		gg_debug(GG_DEBUG_MISC, "// gg_utf8_to_cp() not enough memory\n");
+		return NULL;
+	}
+
+	for (i = 0, j = 0; buf[i]; j++) {
+		uint16_t znak;
+		int ret, k;
+
+		ret = gg_utf8_helper(&buf[i], len - i, &znak);
+
+		if (ret > 0) {
+			i += ret;
+		} else {
+			znak = '?';
+			i++;
+		}
+
+		if (znak < 0x80) {
+			newbuf[j] = znak;
+			continue;
+		}
+
+		newbuf[j] = '?';
+
+		for (k = 0; k < (sizeof(table_cp1250)/sizeof(table_cp1250[0])); k++) {
+			if (table_cp1250[k] == znak) {
+				newbuf[j] = (0x80 | k);
+				break;
+			}
+		}
+	}
+	newbuf[j] = '\0';
+
+	return newbuf;
+}
 
 /*
  * Local variables: