Mercurial > pidgin.yaz
changeset 29941:19610ea45ff3
propagate from branch 'im.pidgin.pidgin' (head 91a6721a97381551e47347b98c8f7b596e60e3ae)
to branch 'im.pidgin.cpw.rekkanoryo.ggupdate' (head d21119dede49bb8c2a1cfb45634f4d976f6f0e8b)
author | John Bailey <rekkanoryo@rekkanoryo.org> |
---|---|
date | Mon, 01 Mar 2010 03:46:33 +0000 (2010-03-01) |
parents | 89120a5b285a (current diff) c0d337670835 (diff) |
children | c84ee0ff4fe6 |
files | |
diffstat | 19 files changed, 7770 insertions(+), 3149 deletions(-) [+] |
line wrap: on
line diff
--- a/configure.ac Sun Feb 28 23:42:12 2010 +0000 +++ b/configure.ac Mon Mar 01 03:46:33 2010 +0000 @@ -2583,6 +2583,7 @@ echo Build with Cyrus SASL support. : $enable_cyrus_sasl echo Use kerberos 4 with zephyr.... : $kerberos echo Use external libzephyr........ : $zephyr +echo Use external libgadu.......... : $gadu_libs echo Install pixmaps............... : $enable_pixmaps echo Install translations.......... : $enable_i18n echo Has you....................... : yes
--- a/libpurple/protocols/gg/Makefile.am Sun Feb 28 23:42:12 2010 +0000 +++ b/libpurple/protocols/gg/Makefile.am Mon Mar 01 03:46:33 2010 +0000 @@ -4,14 +4,19 @@ lib/compat.h \ lib/COPYING \ lib/dcc.c \ + lib/dcc7.c \ lib/events.c \ lib/http.c \ lib/libgadu.c \ lib/libgadu-config.h \ lib/libgadu.h \ lib/obsolete.c \ + lib/protocol.h \ + lib/pubdir.c \ lib/pubdir50.c \ - lib/pubdir.c + lib/resolver.c \ + lib/resolver.h \ + lib/sha1.c pkgdir = $(libdir)/purple-$(PURPLE_MAJOR_VERSION) @@ -20,16 +25,21 @@ lib/common.c \ lib/compat.h \ lib/dcc.c \ + lib/dcc7.c \ lib/events.c \ lib/http.c \ lib/libgadu.c \ lib/libgadu-config.h \ lib/libgadu.h \ lib/obsolete.c \ + lib/protocol.h \ + lib/pubdir.c \ lib/pubdir50.c \ - lib/pubdir.c + lib/resolver.c \ + lib/resolver.h \ + lib/sha1.c -INTGG_CFLAGS = -I$(top_srcdir)/libpurple/protocols/gg/lib +INTGG_CFLAGS = -I$(top_srcdir)/libpurple/protocols/gg/lib -DGG_IGNORE_DEPRECATED endif GGSOURCES = \
--- a/libpurple/protocols/gg/Makefile.mingw Sun Feb 28 23:42:12 2010 +0000 +++ b/libpurple/protocols/gg/Makefile.mingw Mon Mar 01 03:46:33 2010 +0000 @@ -8,7 +8,7 @@ include $(PIDGIN_TREE_TOP)/libpurple/win32/global.mak TARGET = libgg -CFLAGS += -include win32dep.h +CFLAGS += -include win32dep.h -DGG_IGNORE_DEPRECATED TYPE = PLUGIN # Static or Plugin... @@ -41,12 +41,15 @@ ## C_SRC = \ lib/common.c \ + lib/dcc.c \ + lib/dcc7.c \ lib/events.c \ lib/http.c \ lib/libgadu.c \ lib/obsolete.c \ lib/pubdir.c \ lib/pubdir50.c \ + lib/resolver.c \ buddylist.c \ confer.c \ gg.c \
--- a/libpurple/protocols/gg/lib/common.c Sun Feb 28 23:42:12 2010 +0000 +++ b/libpurple/protocols/gg/lib/common.c Mon Mar 01 03:46:33 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,109 +15,180 @@ * * 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. */ +/* + * 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. + */ + +/** + * \file common.c + * + * \brief Funkcje wykorzystywane przez r坦甜ne modu�y biblioteki + */ + #include "libgadu.h" +#include "libgadu-internal.h" #ifndef _WIN32 -#include <sys/types.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#ifdef sun -# include <sys/filio.h> -#endif +# include <sys/types.h> +# include <sys/ioctl.h> +# include <sys/socket.h> +# include <netinet/in.h> +# include <arpa/inet.h> +# ifdef sun +# include <sys/filio.h> +# endif #endif #include <errno.h> #include <fcntl.h> + #ifndef _WIN32 -#include <netdb.h> +# include <netdb.h> #endif + #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.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 +203,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 +213,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 +253,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 +277,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 +332,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 +479,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 +510,7 @@ } else { if (!(arg = va_arg(ap, char*))) arg = ""; - } + } i = 0; while ((c = (unsigned char) arg[i++]) != 0) { @@ -442,95 +524,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 +534,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 +559,7 @@ if (!thread_id) thread_id = GetCurrentThreadId(); - + while (wsk) { if ((thread_id == -1 && wsk->socket == socket) || wsk->id == thread_id) { if (close) { @@ -593,7 +585,7 @@ closesocket(socket); if (close || !socket) return 0; - + /* Dodaje nowy element */ wsk = malloc(sizeof(gg_win32_thread)); wsk->id = thread_id; @@ -606,28 +598,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 +657,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 +682,7 @@ if (!buf) return NULL; - + save = res = calloc(1, (strlen(buf) / 4 + 1) * 3 + 2); if (!save) @@ -720,23 +719,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 +749,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 +764,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 +795,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 +821,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:
--- a/libpurple/protocols/gg/lib/compat.h Sun Feb 28 23:42:12 2010 +0000 +++ b/libpurple/protocols/gg/lib/compat.h Mon Mar 01 03:46:33 2010 +0000 @@ -1,8 +1,8 @@ -/* $Id: compat.h 16856 2006-08-19 01:13:25Z evands $ */ +/* $Id: compat.h 506 2008-01-14 22:15:05Z 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,10 +15,16 @@ * * 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. */ +/** + * \file compat.h + * + * \brief Makra zapewniaj�ce kompatybilno�� API na r坦甜nych systemach + */ + #ifndef __COMPAT_H #define __COMPAT_H
--- a/libpurple/protocols/gg/lib/dcc.c Sun Feb 28 23:42:12 2010 +0000 +++ b/libpurple/protocols/gg/lib/dcc.c Mon Mar 01 03:46:33 2010 +0000 @@ -1,8 +1,9 @@ -/* $Id: dcc.c 16856 2006-08-19 01:13:25Z evands $ */ +/* $Id: dcc.c 711 2009-04-16 00:52:47Z darkjames $ */ /* - * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl> - * Tomasz Chili�ski <chilek@chilan.com> + * (C) Copyright 2001-2008 Wojtek Kaniewski <wojtekka@irc.pl> + * Tomasz Chili�ski <chilek@chilan.com> + * Adam Wysocki <gophi@ekg.chmurka.net> * * 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,22 +16,28 @@ * * 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. */ +/** + * \file dcc.c + * + * \brief Obs�uga po��cze� bezpo�rednich do wersji Gadu-Gadu 6.x + */ #include "libgadu.h" #include <sys/types.h> #include <sys/stat.h> + #ifndef _WIN32 -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#ifdef sun -# include <sys/filio.h> -#endif +# include <sys/ioctl.h> +# include <sys/socket.h> +# include <netinet/in.h> +# include <arpa/inet.h> +# ifdef sun +# include <sys/filio.h> +# endif #endif #include <ctype.h> @@ -43,67 +50,71 @@ #include <unistd.h> #include "compat.h" + #ifndef GG_DEBUG_DISABLE -/* - * gg_dcc_debug_data() // funkcja wewn�trzna + +/** + * \internal Przekazuje zawarto�� pakietu do odpluskwiania. * - * wy�wietla zrzut pakietu w hexie. - * - * - prefix - prefiks zrzutu pakietu - * - fd - deskryptor gniazda - * - buf - bufor z danymi - * - size - rozmiar danych + * \param prefix Prefiks informacji + * \param fd Deskryptor gniazda + * \param buf Bufor z danumi + * \param size Rozmiar bufora z danymi */ static void gg_dcc_debug_data(const char *prefix, int fd, const void *buf, unsigned int size) { unsigned int i; - + gg_debug(GG_DEBUG_MISC, "++ gg_dcc %s (fd=%d,len=%d)", prefix, fd, size); - + for (i = 0; i < size; i++) gg_debug(GG_DEBUG_MISC, " %.2x", ((unsigned char*) buf)[i]); - + gg_debug(GG_DEBUG_MISC, "\n"); } #else #define gg_dcc_debug_data(a,b,c,d) do { } while (0) #endif -/* +/** + * Wysy�a 甜�danie zwrotnego po��czenia bezpo�redniego. + * + * Funkcj� wykorzystuje si�, je�li nie ma mo甜liwo�ci po��czenia si� z odbiorc� + * pliku lub rozmowy g�osowej. Po otrzymaniu 甜�dania druga strona spr坦buje + * nawi�za� zwrotne po��czenie bezpo�rednie z nadawc�. * gg_dcc_request() * - * wysy�a informacj� o tym, �e dany klient powinien si� z nami po咳czy�. - * wykorzystywane, kiedy druga strona, kt�rej chcemy co� wys�a� jest za - * maskarad�. + * \param sess Struktura sesji + * \param uin Numer odbiorcy * - * - sess - struktura opisuj�ca sesj� GG - * - uin - numerek odbiorcy + * \return Patrz \c gg_send_message_ctcp() * - * patrz gg_send_message_ctcp(). + * \ingroup dcc6 */ int gg_dcc_request(struct gg_session *sess, uin_t uin) { - return gg_send_message_ctcp(sess, GG_CLASS_CTCP, uin, (const unsigned char *)"\002", 1); + return gg_send_message_ctcp(sess, GG_CLASS_CTCP, uin, (unsigned char*) "\002", 1); } -/* - * gg_dcc_fill_filetime() // funkcja wewn�trzna +/** + * \internal Zamienia znacznik czasu w postaci uniksowej na format API WIN32. * - * zamienia czas w postaci unixowej na windowsowy. + * \note Funkcja dzia�a jedynie gdy kompilator obs�uguje typ danych + * \c long \c long. * - * - unix - czas w postaci unixowej - * - filetime - czas w postaci windowsowej + * \param ut Czas w postaci uniksowej + * \param ft Czas w postaci API WIN32 */ static void gg_dcc_fill_filetime(uint32_t ut, uint32_t *ft) { -#ifdef __GG_LIBGADU_HAVE_LONG_LONG +#ifdef GG_CONFIG_HAVE_LONG_LONG unsigned long long tmp; tmp = ut; tmp += 11644473600LL; tmp *= 10000000LL; -#ifndef __GG_LIBGADU_BIGENDIAN +#ifndef GG_CONFIG_BIGENDIAN ft[0] = (uint32_t) tmp; ft[1] = (uint32_t) (tmp >> 32); #else @@ -114,31 +125,33 @@ #endif } -/* - * gg_dcc_fill_file_info() +/** + * Wype�nia pola struktury \c gg_dcc niezb�dne do wys�ania pliku. * - * wype�nia pola struct gg_dcc niezb�dne do wys�ania pliku. + * \note Wi�ksz� funkcjonalno�� zapewnia funkcja \c gg_dcc_fill_file_info2(). * - * - d - struktura opisuj�ca po咳czenie DCC - * - filename - nazwa pliku + * \param d Struktura po��czenia + * \param filename Nazwa pliku * - * 0, -1. + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup dcc6 */ int gg_dcc_fill_file_info(struct gg_dcc *d, const char *filename) { return gg_dcc_fill_file_info2(d, filename, filename); } -/* - * gg_dcc_fill_file_info2() - * - * wype�nia pola struct gg_dcc niezb�dne do wys�ania pliku. +/** + * Wype�nia pola struktury \c gg_dcc niezb�dne do wys�ania pliku. * - * - d - struktura opisuj�ca po咳czenie DCC - * - filename - nazwa pliku - * - local_filename - nazwa na lokalnym systemie plik�w + * \param d Struktura po��czenia + * \param filename Nazwa pliku zapisywana w strukturze + * \param local_filename Nazwa pliku w lokalnym systemie plik坦w * - * 0, -1. + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup dcc6 */ int gg_dcc_fill_file_info2(struct gg_dcc *d, const char *filename, const char *local_filename) { @@ -225,25 +238,23 @@ *q = 175; } } - + gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() short name \"%s\", dos name \"%s\"\n", name, d->file_info.short_filename); - strncpy((char *)d->file_info.filename, name, sizeof(d->file_info.filename) - 1); + strncpy((char*) d->file_info.filename, name, sizeof(d->file_info.filename) - 1); return 0; } -/* - * gg_dcc_transfer() // funkcja wewn�trzna - * - * inicjuje proces wymiany pliku z danym klientem. +/** + * \internal Rozpoczyna po��czenie bezpo�rednie z danym klientem. * - * - ip - adres ip odbiorcy - * - port - port odbiorcy - * - my_uin - w�asny numer - * - peer_uin - numer obiorcy - * - type - rodzaj wymiany (GG_SESSION_DCC_SEND lub GG_SESSION_DCC_GET) + * \param ip Adres IP odbiorcy + * \param port Port odbiorcy + * \param my_uin W�asny numer + * \param peer_uin Numer odbiorcy + * \param type Rodzaj po��czenia (\c GG_SESSION_DCC_SEND lub \c GG_SESSION_DCC_GET) * - * zaalokowana struct gg_dcc lub NULL je�li wyst�pi� b咳d. + * \return Struktura \c gg_dcc lub \c NULL w przypadku b��du */ static struct gg_dcc *gg_dcc_transfer(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin, int type) { @@ -251,9 +262,9 @@ struct in_addr addr; addr.s_addr = ip; - + gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_transfer(%s, %d, %ld, %ld, %s);\n", inet_ntoa(addr), port, my_uin, peer_uin, (type == GG_SESSION_DCC_SEND) ? "SEND" : "GET"); - + if (!ip || ip == INADDR_NONE || !port || !my_uin || !peer_uin) { gg_debug(GG_DEBUG_MISC, "// gg_dcc_transfer() invalid arguments\n"); errno = EINVAL; @@ -284,18 +295,17 @@ return d; } -/* - * gg_dcc_get_file() - * - * inicjuje proces odbierania pliku od danego klienta, gdy ten wys�a� do - * nas 娠danie po咳czenia. +/** + * Rozpoczyna odbieranie pliku przez zwrotne po��czenie bezpo�rednie. * - * - ip - adres ip odbiorcy - * - port - port odbiorcy - * - my_uin - w�asny numer - * - peer_uin - numer obiorcy + * \param ip Adres IP nadawcy + * \param port Port nadawcy + * \param my_uin W�asny numer + * \param peer_uin Numer nadawcy * - * zaalokowana struct gg_dcc lub NULL je�li wyst�pi� b咳d. + * \return Struktura \c gg_dcc lub \c NULL w przypadku b��du + * + * \ingroup dcc6 */ struct gg_dcc *gg_dcc_get_file(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin) { @@ -304,17 +314,17 @@ return gg_dcc_transfer(ip, port, my_uin, peer_uin, GG_SESSION_DCC_GET); } -/* - * gg_dcc_send_file() - * - * inicjuje proces wysy�ania pliku do danego klienta. +/** + * Rozpoczyna wysy�anie pliku. * - * - ip - adres ip odbiorcy - * - port - port odbiorcy - * - my_uin - w�asny numer - * - peer_uin - numer obiorcy + * \param ip Adres IP odbiorcy + * \param port Port odbiorcy + * \param my_uin W�asny numer + * \param peer_uin Numer odbiorcy * - * zaalokowana struct gg_dcc lub NULL je�li wyst�pi� b咳d. + * \return Struktura \c gg_dcc lub \c NULL w przypadku b��du + * + * \ingroup dcc6 */ struct gg_dcc *gg_dcc_send_file(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin) { @@ -323,17 +333,17 @@ return gg_dcc_transfer(ip, port, my_uin, peer_uin, GG_SESSION_DCC_SEND); } -/* - * gg_dcc_voice_chat() - * - * pr�buje nawi�za� po咳czenie g�osowe. +/** + * Rozpoczyna po��czenie g�osowe. * - * - ip - adres ip odbiorcy - * - port - port odbiorcy - * - my_uin - w�asny numer - * - peer_uin - numer obiorcy + * \param ip Adres IP odbiorcy + * \param port Port odbiorcy + * \param my_uin W�asny numer + * \param peer_uin Numer odbiorcy * - * zaalokowana struct gg_dcc lub NULL je�li wyst�pi� b咳d. + * \return Struktura \c gg_dcc lub \c NULL w przypadku b��du + * + * \ingroup dcc6 */ struct gg_dcc *gg_dcc_voice_chat(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin) { @@ -342,30 +352,34 @@ return gg_dcc_transfer(ip, port, my_uin, peer_uin, GG_SESSION_DCC_VOICE); } -/* - * gg_dcc_set_type() +/** + * Ustawia typ przychodz�cego po��czenia bezpo�redniego. + * + * Funkcj� nale甜y wywo�a� po otrzymaniu zdarzenia \c GG_EVENT_DCC_CALLBACK. * - * po zdarzeniu GG_EVENT_DCC_CALLBACK nale�y ustawi� typ po咳czenia za - * pomoc� tej funkcji. + * \param d Struktura po��czenia + * \param type Rodzaj po��czenia (\c GG_SESSION_DCC_SEND lub + * \c GG_SESSION_DCC_VOICE) * - * - d - struktura opisuj�ca po咳czenie - * - type - typ po咳czenia (GG_SESSION_DCC_SEND lub GG_SESSION_DCC_VOICE) + * \ingroup dcc6 */ void gg_dcc_set_type(struct gg_dcc *d, int type) { d->type = type; d->state = (type == GG_SESSION_DCC_SEND) ? GG_STATE_SENDING_FILE_INFO : GG_STATE_SENDING_VOICE_REQUEST; } - -/* - * gg_dcc_callback() // funkcja wewn�trzna + +/** + * \internal Funkcja zwrotna po��czenia bezpo�redniego. * - * wywo�ywana z struct gg_dcc->callback, odpala gg_dcc_watch_fd i umieszcza - * rezultat w struct gg_dcc->event. + * Pole \c callback struktury \c gg_dcc zawiera wska添nik do tej funkcji. + * Wywo�uje ona \c gg_watch_fd() i zachowuje wynik w polu \c event. * - * - d - structura opisuj�ca po咳czenie + * \note Funkcjonalno�� funkcjo zwrotnej nie jest ju甜 wspierana. * - * 0, -1. + * \param d Struktura po��czenia + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du */ static int gg_dcc_callback(struct gg_dcc *d) { @@ -376,25 +390,26 @@ return (e != NULL) ? 0 : -1; } -/* - * gg_dcc_socket_create() +/** + * Tworzy gniazdo nas�uchuj�ce dla po��cze� bezpo�rednich. * - * tworzy gniazdo dla bezpo�redniej komunikacji mi�dzy klientami. + * Funkcja przywi�zuje gniazdo do pierwszego wolnego portu TCP. * - * - uin - w�asny numer - * - port - preferowany port, je�li r�wny 0 lub -1, pr�buje domy�lnego + * \param uin W�asny numer + * \param port Preferowany port (je�li r坦wny 0 lub -1, pr坦buje si� domy�lnego) * - * zaalokowana struct gg_dcc, kt�r� po�niej nale�y zwolni� funkcj� - * gg_dcc_free(), albo NULL je�li wyst�pi� b咳d. + * \return Struktura \c gg_dcc lub \c NULL w przypadku b��du + * + * \ingroup dcc6 */ struct gg_dcc *gg_dcc_socket_create(uin_t uin, uint16_t port) { struct gg_dcc *c; struct sockaddr_in sin; int sock, bound = 0, errno2; - + gg_debug(GG_DEBUG_FUNCTION, "** gg_create_dcc_socket(%d, %d);\n", uin, port); - + if (!uin) { gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() invalid arguments\n"); errno = EINVAL; @@ -408,12 +423,12 @@ if (!port) port = GG_DEFAULT_DCC_PORT; - + while (!bound) { sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(port); - + gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() trying port %d\n", port); if (!bind(sock, (struct sockaddr*) &sin, sizeof(sin))) bound = 1; @@ -433,7 +448,7 @@ errno = errno2; return NULL; } - + gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() bound to port %d\n", port); if (!(c = malloc(sizeof(*c)))) { @@ -452,20 +467,20 @@ c->check = GG_CHECK_READ; c->callback = gg_dcc_callback; c->destroy = gg_dcc_free; - + return c; } -/* - * gg_dcc_voice_send() - * - * wysy�a ramk� danych dla rozmowy g�osowej. +/** + * Wysy�a ramk� danych po��czenia g�osowego. * - * - d - struktura opisuj�ca po咳czenie dcc - * - buf - bufor z danymi - * - length - rozmiar ramki + * \param d Struktura po��czenia + * \param buf Bufor z danymi + * \param length D�ugo�� bufora z danymi * - * 0, -1. + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup dcc6 */ int gg_dcc_voice_send(struct gg_dcc *d, char *buf, int length) { @@ -500,7 +515,14 @@ return 0; } -#define gg_read(fd, buf, size) \ +/** + * \internal Odbiera dane z po��czenia bezpo�redniego z obs�ug� b��d坦w. + * + * \param fd Deskryptor gniazda + * \param buf Bufor na dane + * \param size Rozmiar bufora na dane + */ +#define gg_dcc_read(fd, buf, size) \ { \ int tmp = read(fd, buf, size); \ \ @@ -517,9 +539,16 @@ return e; \ } \ gg_dcc_debug_data("read", fd, buf, size); \ -} +} -#define gg_write(fd, buf, size) \ +/** + * \internal Wysy�a dane do po��czenia bezpo�redniego z obs�ug� b��d坦w. + * + * \param fd Deskryptor gniazda + * \param buf Bufor z danymi + * \param size Rozmiar bufora z danymi + */ +#define gg_dcc_write(fd, buf, size) \ { \ int tmp; \ gg_dcc_debug_data("write", fd, buf, size); \ @@ -536,14 +565,18 @@ } \ } -/* - * gg_dcc_watch_fd() +/** + * Funkcja wywo�ywana po zaobserwowaniu zmian na deskryptorze po��czenia. * - * funkcja, kt�r� nale�y wywo�a�, gdy co� si� zmieni na gg_dcc->fd. + * Funkcja zwraca struktur� zdarzenia \c gg_event. Je�li rodzaj zdarzenia + * to \c GG_EVENT_NONE, nie wydarzy�o si� jeszcze nic wartego odnotowania. + * Struktur� zdarzenia nale甜y zwolni� funkcja \c gg_event_free. * - * - h - struktura zwr�cona przez gg_create_dcc_socket() + * \param h Struktura po��czenia * - * zaalokowana struct gg_event lub NULL, je�li zabrak�o pami�ci na ni�. + * \return Struktura zdarzenia lub \c NULL je�li wyst�pi� b��d + * + * \ingroup dcc6 */ struct gg_event *gg_dcc_watch_fd(struct gg_dcc *h) { @@ -551,7 +584,7 @@ int foo; gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_watch_fd(%p);\n", h); - + if (!h || (h->type != GG_SESSION_DCC && h->type != GG_SESSION_DCC_SOCKET && h->type != GG_SESSION_DCC_SEND && h->type != GG_SESSION_DCC_GET && h->type != GG_SESSION_DCC_VOICE)) { gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() invalid argument\n"); errno = EINVAL; @@ -568,10 +601,9 @@ if (h->type == GG_SESSION_DCC_SOCKET) { struct sockaddr_in sin; struct gg_dcc *c; - int fd; - socklen_t sin_len = sizeof(sin); - int one = 1; - + int fd, one = 1; + unsigned int sin_len = sizeof(sin); + if ((fd = accept(h->fd, (struct sockaddr*) &sin, &sin_len)) == -1) { gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() can't accept() new connection (errno=%d, %s)\n", errno, strerror(errno)); return e; @@ -607,7 +639,7 @@ c->file_fd = -1; c->remote_addr = sin.sin_addr.s_addr; c->remote_port = ntohs(sin.sin_port); - + e->type = GG_EVENT_DCC_NEW; e->event.dcc_new = c; @@ -617,8 +649,7 @@ struct gg_dcc_small_packet small; struct gg_dcc_big_packet big; int size, tmp, res; - socklen_t res_size = sizeof(res); - unsigned int utmp; + unsigned int utmp, res_size = sizeof(res); char buf[1024], ack[] = "UDAG"; struct gg_dcc_file_info_packet { @@ -634,8 +665,8 @@ uin_t uin; gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_READING_UIN_%d\n", (h->state == GG_STATE_READING_UIN_1) ? 1 : 2); - - gg_read(h->fd, &uin, sizeof(uin)); + + gg_dcc_read(h->fd, &uin, sizeof(uin)); if (h->state == GG_STATE_READING_UIN_1) { h->state = GG_STATE_READING_UIN_2; @@ -656,7 +687,7 @@ case GG_STATE_SENDING_ACK: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_SENDING_ACK\n"); - gg_write(h->fd, ack, 4); + gg_dcc_write(h->fd, ack, 4); h->state = GG_STATE_READING_TYPE; h->check = GG_CHECK_READ; @@ -666,8 +697,8 @@ case GG_STATE_READING_TYPE: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_TYPE\n"); - - gg_read(h->fd, &small, sizeof(small)); + + gg_dcc_read(h->fd, &small, sizeof(small)); small.type = gg_fix32(small.type); @@ -680,7 +711,7 @@ h->timeout = GG_DEFAULT_TIMEOUT; e->type = GG_EVENT_DCC_CALLBACK; - + break; case 0x0002: /* XXX */ @@ -703,8 +734,8 @@ case GG_STATE_READING_REQUEST: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_REQUEST\n"); - - gg_read(h->fd, &small, sizeof(small)); + + gg_dcc_read(h->fd, &small, sizeof(small)); small.type = gg_fix32(small.type); @@ -715,7 +746,7 @@ h->check = GG_CHECK_READ; h->timeout = GG_DEFAULT_TIMEOUT; break; - + case 0x0003: /* XXX */ gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() voice chat request\n"); h->state = GG_STATE_SENDING_VOICE_ACK; @@ -725,22 +756,22 @@ e->type = GG_EVENT_DCC_NEED_VOICE_ACK; break; - + default: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() unknown dcc request (%.4x) from %ld\n", small.type, h->peer_uin); e->type = GG_EVENT_DCC_ERROR; e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; } - + return e; case GG_STATE_READING_FILE_INFO: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_INFO\n"); - - gg_read(h->fd, &file_info_packet, sizeof(file_info_packet)); + + gg_dcc_read(h->fd, &file_info_packet, sizeof(file_info_packet)); memcpy(&h->file_info, &file_info_packet.file_info, sizeof(h->file_info)); - + h->file_info.mode = gg_fix32(h->file_info.mode); h->file_info.size = gg_fix32(h->file_info.size); @@ -749,17 +780,17 @@ h->timeout = GG_DCC_TIMEOUT_FILE_ACK; e->type = GG_EVENT_DCC_NEED_FILE_ACK; - + return e; case GG_STATE_SENDING_FILE_ACK: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_ACK\n"); - + big.type = gg_fix32(0x0006); /* XXX */ big.dunno1 = gg_fix32(h->offset); big.dunno2 = 0; - gg_write(h->fd, &big, sizeof(big)); + gg_dcc_write(h->fd, &big, sizeof(big)); h->state = GG_STATE_READING_FILE_HEADER; h->chunk_size = sizeof(big); @@ -773,25 +804,25 @@ h->timeout = GG_DEFAULT_TIMEOUT; return e; - + case GG_STATE_SENDING_VOICE_ACK: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_VOICE_ACK\n"); - + tiny.type = 0x01; /* XXX */ - gg_write(h->fd, &tiny, sizeof(tiny)); + gg_dcc_write(h->fd, &tiny, sizeof(tiny)); h->state = GG_STATE_READING_VOICE_HEADER; h->check = GG_CHECK_READ; h->timeout = GG_DEFAULT_TIMEOUT; h->offset = 0; - + return e; - + case GG_STATE_READING_FILE_HEADER: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_HEADER\n"); - + tmp = read(h->fd, h->chunk_buf + h->chunk_offset, h->chunk_size - h->chunk_offset); if (tmp == -1) { @@ -802,7 +833,7 @@ } gg_dcc_debug_data("read", h->fd, h->chunk_buf + h->chunk_offset, h->chunk_size - h->chunk_offset); - + h->chunk_offset += tmp; if (h->chunk_offset < h->chunk_size) @@ -823,7 +854,7 @@ return e; } - if (h->chunk_size == 0) { + if (h->chunk_size == 0) { gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() empty chunk, EOF\n"); e->type = GG_EVENT_DCC_DONE; return e; @@ -833,13 +864,13 @@ h->check = GG_CHECK_READ; h->timeout = GG_DEFAULT_TIMEOUT; h->established = 1; - + return e; case GG_STATE_READING_VOICE_HEADER: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_HEADER\n"); - - gg_read(h->fd, &tiny, sizeof(tiny)); + + gg_dcc_read(h->fd, &tiny, sizeof(tiny)); switch (tiny.type) { case 0x03: /* XXX */ @@ -850,19 +881,19 @@ break; case 0x04: /* XXX */ gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() peer breaking connection\n"); - /* XXX zwraca� odpowiedni event */ + /* XXX zwraca� odpowiedni event */ default: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() unknown request (%.2x)\n", tiny.type); e->type = GG_EVENT_DCC_ERROR; e->event.dcc_error = GG_ERROR_DCC_HANDSHAKE; } - + return e; case GG_STATE_READING_VOICE_SIZE: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_SIZE\n"); - - gg_read(h->fd, &small, sizeof(small)); + + gg_dcc_read(h->fd, &small, sizeof(small)); small.type = gg_fix32(small.type); @@ -870,7 +901,7 @@ gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() invalid voice frame size (%d)\n", small.type); e->type = GG_EVENT_DCC_ERROR; e->event.dcc_error = GG_ERROR_DCC_NET; - + return e; } @@ -879,18 +910,19 @@ if (!(h->voice_buf = malloc(h->chunk_size))) { gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() out of memory for voice frame\n"); + free(e); return NULL; } h->state = GG_STATE_READING_VOICE_DATA; h->check = GG_CHECK_READ; h->timeout = GG_DEFAULT_TIMEOUT; - + return e; case GG_STATE_READING_VOICE_DATA: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_DATA\n"); - + tmp = read(h->fd, h->voice_buf + h->chunk_offset, h->chunk_size - h->chunk_offset); if (tmp < 1) { if (tmp == -1) { @@ -909,7 +941,7 @@ if (h->chunk_offset >= h->chunk_size) { e->type = GG_EVENT_DCC_VOICE_DATA; - e->event.dcc_voice_data.data = h->voice_buf; + e->event.dcc_voice_data.data = (unsigned char*) h->voice_buf; e->event.dcc_voice_data.length = h->chunk_size; h->state = GG_STATE_READING_VOICE_HEADER; h->voice_buf = NULL; @@ -917,7 +949,7 @@ h->check = GG_CHECK_READ; h->timeout = GG_DEFAULT_TIMEOUT; - + return e; case GG_STATE_CONNECTING: @@ -925,7 +957,7 @@ uin_t uins[2]; gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_CONNECTING\n"); - + res = 0; if ((foo = getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &res, &res_size)) || res) { gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() connection failed (fd=%d,errno=%d(%s),foo=%d,res=%d(%s))\n", h->fd, errno, strerror(errno), foo, res, strerror(res)); @@ -935,23 +967,23 @@ } gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() connected, sending uins\n"); - + uins[0] = gg_fix32(h->uin); uins[1] = gg_fix32(h->peer_uin); - gg_write(h->fd, uins, sizeof(uins)); - + gg_dcc_write(h->fd, uins, sizeof(uins)); + h->state = GG_STATE_READING_ACK; h->check = GG_CHECK_READ; h->timeout = GG_DEFAULT_TIMEOUT; - + return e; } case GG_STATE_READING_ACK: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_ACK\n"); - - gg_read(h->fd, buf, 4); + + gg_dcc_read(h->fd, buf, 4); if (strncmp(buf, ack, 4)) { gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() did't get ack\n"); @@ -964,29 +996,29 @@ h->check = GG_CHECK_WRITE; h->timeout = GG_DEFAULT_TIMEOUT; h->state = GG_STATE_SENDING_REQUEST; - + return e; case GG_STATE_SENDING_VOICE_REQUEST: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_VOICE_REQUEST\n"); small.type = gg_fix32(0x0003); - - gg_write(h->fd, &small, sizeof(small)); + + gg_dcc_write(h->fd, &small, sizeof(small)); h->state = GG_STATE_READING_VOICE_ACK; h->check = GG_CHECK_READ; h->timeout = GG_DEFAULT_TIMEOUT; - + return e; - + case GG_STATE_SENDING_REQUEST: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_REQUEST\n"); small.type = (h->type == GG_SESSION_DCC_GET) ? gg_fix32(0x0003) : gg_fix32(0x0002); /* XXX */ - - gg_write(h->fd, &small, sizeof(small)); - + + gg_dcc_write(h->fd, &small, sizeof(small)); + switch (h->type) { case GG_SESSION_DCC_GET: h->state = GG_STATE_READING_REQUEST; @@ -1002,7 +1034,7 @@ if (h->file_fd == -1) e->type = GG_EVENT_DCC_NEED_FILE_INFO; break; - + case GG_SESSION_DCC_VOICE: h->state = GG_STATE_SENDING_VOICE_REQUEST; h->check = GG_CHECK_WRITE; @@ -1011,7 +1043,7 @@ } return e; - + case GG_STATE_SENDING_FILE_INFO: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_INFO\n"); @@ -1021,8 +1053,8 @@ } small.type = gg_fix32(0x0001); /* XXX */ - - gg_write(h->fd, &small, sizeof(small)); + + gg_dcc_write(h->fd, &small, sizeof(small)); file_info_packet.big.type = gg_fix32(0x0003); /* XXX */ file_info_packet.big.dunno1 = 0; @@ -1030,26 +1062,26 @@ memcpy(&file_info_packet.file_info, &h->file_info, sizeof(h->file_info)); - /* zostaj� teraz u nas, wi�c odwracamy z powrotem */ + /* zostaj� teraz u nas, wi�c odwracamy z powrotem */ h->file_info.size = gg_fix32(h->file_info.size); h->file_info.mode = gg_fix32(h->file_info.mode); - - gg_write(h->fd, &file_info_packet, sizeof(file_info_packet)); + + gg_dcc_write(h->fd, &file_info_packet, sizeof(file_info_packet)); h->state = GG_STATE_READING_FILE_ACK; h->check = GG_CHECK_READ; h->timeout = GG_DCC_TIMEOUT_FILE_ACK; return e; - + case GG_STATE_READING_FILE_ACK: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_FILE_ACK\n"); - - gg_read(h->fd, &big, sizeof(big)); + + gg_dcc_read(h->fd, &big, sizeof(big)); - /* XXX sprawdza� wynik */ + /* XXX sprawdza� wynik */ h->offset = gg_fix32(big.dunno1); - + h->state = GG_STATE_SENDING_FILE_HEADER; h->check = GG_CHECK_WRITE; h->timeout = GG_DEFAULT_TIMEOUT; @@ -1060,8 +1092,8 @@ case GG_STATE_READING_VOICE_ACK: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_READING_VOICE_ACK\n"); - - gg_read(h->fd, &tiny, sizeof(tiny)); + + gg_dcc_read(h->fd, &tiny, sizeof(tiny)); if (tiny.type != 0x01) { gg_debug(GG_DEBUG_MISC, "// invalid reply (%.2x), connection refused\n", tiny.type); @@ -1075,14 +1107,14 @@ h->timeout = GG_DEFAULT_TIMEOUT; e->type = GG_EVENT_DCC_ACK; - + return e; case GG_STATE_SENDING_FILE_HEADER: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE_HEADER\n"); - + h->chunk_offset = 0; - + if ((h->chunk_size = h->file_info.size - h->offset) > 4096) { h->chunk_size = 4096; big.type = gg_fix32(0x0003); /* XXX */ @@ -1091,8 +1123,8 @@ big.dunno1 = gg_fix32(h->chunk_size); big.dunno2 = 0; - - gg_write(h->fd, &big, sizeof(big)); + + gg_dcc_write(h->fd, &big, sizeof(big)); h->state = GG_STATE_SENDING_FILE; h->check = GG_CHECK_WRITE; @@ -1100,13 +1132,13 @@ h->established = 1; return e; - + case GG_STATE_SENDING_FILE: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_SENDING_FILE\n"); - + if ((utmp = h->chunk_size - h->chunk_offset) > sizeof(buf)) utmp = sizeof(buf); - + gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() offset=%d, size=%d\n", h->offset, h->file_info.size); /* koniec pliku? */ @@ -1117,11 +1149,17 @@ return e; } + if (h->offset >= h->file_info.size) { + gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() offset >= size, finished\n"); + e->type = GG_EVENT_DCC_DONE; + return e; + } + lseek(h->file_fd, h->offset, SEEK_SET); size = read(h->file_fd, buf, utmp); - /* b咳d */ + /* b��d */ if (size == -1) { gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed. (errno=%d, %s)\n", errno, strerror(errno)); @@ -1139,8 +1177,8 @@ return e; } - - /* je�li wczytali�my wi�cej, utnijmy. */ + + /* je�li wczytali�my wi�cej, utnijmy. */ if (h->offset + size > h->file_info.size) { gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() too much (read=%d, ofs=%d, size=%d)\n", size, h->offset, h->file_info.size); size = h->file_info.size - h->offset; @@ -1161,15 +1199,22 @@ return e; } - h->offset += size; - + if (tmp == 0) { + gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() failed (connection reset)\n"); + e->type = GG_EVENT_DCC_ERROR; + e->event.dcc_error = GG_ERROR_DCC_NET; + return e; + } + + h->offset += tmp; + if (h->offset >= h->file_info.size) { e->type = GG_EVENT_DCC_DONE; return e; } - - h->chunk_offset += size; - + + h->chunk_offset += tmp; + if (h->chunk_offset >= h->chunk_size) { gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() chunk finished\n"); h->state = GG_STATE_SENDING_FILE_HEADER; @@ -1178,22 +1223,28 @@ h->state = GG_STATE_SENDING_FILE; h->timeout = GG_DCC_TIMEOUT_SEND; } - + h->check = GG_CHECK_WRITE; return e; case GG_STATE_GETTING_FILE: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_GETTING_FILE\n"); - + if ((utmp = h->chunk_size - h->chunk_offset) > sizeof(buf)) utmp = sizeof(buf); - + + if (h->offset >= h->file_info.size) { + gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() offset >= size, finished\n"); + e->type = GG_EVENT_DCC_DONE; + return e; + } + size = read(h->fd, buf, utmp); gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() ofs=%d, size=%d, read()=%d\n", h->offset, h->file_info.size, size); - - /* b咳d */ + + /* b��d */ if (size == -1) { gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() failed. (errno=%d, %s)\n", errno, strerror(errno)); @@ -1211,9 +1262,9 @@ return e; } - + tmp = write(h->file_fd, buf, size); - + if (tmp == -1 || tmp < size) { gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() write() failed (%d:fd=%d:res=%d:%s)\n", tmp, h->file_fd, size, strerror(errno)); e->type = GG_EVENT_DCC_ERROR; @@ -1222,14 +1273,14 @@ } h->offset += size; - + if (h->offset >= h->file_info.size) { e->type = GG_EVENT_DCC_DONE; return e; } h->chunk_offset += size; - + if (h->chunk_offset >= h->chunk_size) { gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() chunk finished\n"); h->state = GG_STATE_READING_FILE_HEADER; @@ -1245,11 +1296,11 @@ h->state = GG_STATE_GETTING_FILE; h->timeout = GG_DCC_TIMEOUT_GET; } - + h->check = GG_CHECK_READ; return e; - + default: gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() GG_STATE_???\n"); e->type = GG_EVENT_DCC_ERROR; @@ -1258,35 +1309,28 @@ return e; } } - + return e; } -#undef gg_read -#undef gg_write - -/* - * gg_dcc_free() +/** + * Zwalnia zasoby u甜ywane przez po��czenie bezpo�rednie. * - * zwalnia pami裝 po strukturze po咳czenia dcc. + * \param d Struktura po��czenia * - * - d - zwalniana struktura + * \ingroup dcc6 */ void gg_dcc_free(struct gg_dcc *d) { gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_free(%p);\n", d); - + if (!d) return; if (d->fd != -1) close(d->fd); - if (d->chunk_buf) { - free(d->chunk_buf); - d->chunk_buf = NULL; - } - + free(d->chunk_buf); free(d); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/gg/lib/dcc7.c Mon Mar 01 03:46:33 2010 +0000 @@ -0,0 +1,1217 @@ +/* $Id: dcc7.c 711 2009-04-16 00:52:47Z darkjames $ */ + +/* + * (C) Copyright 2001-2008 Wojtek Kaniewski <wojtekka@irc.pl> + * Tomasz Chili�ski <chilek@chilan.com> + * Adam Wysocki <gophi@ekg.chmurka.net> + * + * Thanks to Jakub Zawadzki <darkjames@darkjames.ath.cx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License Version + * 2.1 as published by the Free Software Foundation. + * + * This program 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 Lesser General Public License for more details. + * + * 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 St, Fifth Floor, Boston, MA 02110, + * USA. + */ + +/** + * \file dcc7.c + * + * \brief Obs�uga po��cze� bezpo�rednich od wersji Gadu-Gadu 7.x + */ + +#include "libgadu.h" + +#include <sys/types.h> +#include <sys/stat.h> + +#ifndef _WIN32 +# include <sys/ioctl.h> +# include <sys/socket.h> +# include <netinet/in.h> +# include <arpa/inet.h> +# ifdef sun +# include <sys/filio.h> +# endif +#endif + +#include <time.h> + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> +#include <string.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "compat.h" + +#define gg_debug_dcc(dcc, fmt...) \ + gg_debug_session((dcc) ? (dcc)->sess : NULL, fmt) + +/** + * \internal Dodaje po��czenie bezpo�rednie do sesji. + * + * \param sess Struktura sesji + * \param dcc Struktura po��czenia + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +static int gg_dcc7_session_add(struct gg_session *sess, struct gg_dcc7 *dcc) +{ + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_session_add(%p, %p)\n", sess, dcc); + + if (!sess || !dcc || dcc->next) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_session_remove() invalid parameters\n"); + errno = EINVAL; + return -1; + } + + dcc->next = sess->dcc7_list; + sess->dcc7_list = dcc; + + return 0; +} + +/** + * \internal Usuwa po��czenie bezpo�rednie z sesji. + * + * \param sess Struktura sesji + * \param dcc Struktura po��czenia + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +static int gg_dcc7_session_remove(struct gg_session *sess, struct gg_dcc7 *dcc) +{ + struct gg_dcc7 *tmp; + + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_session_remove(%p, %p)\n", sess, dcc); + + if (!sess || !dcc) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_session_remove() invalid parameters\n"); + errno = EINVAL; + return -1; + } + + if (sess->dcc7_list == dcc) { + sess->dcc7_list = dcc->next; + dcc->next = NULL; + return 0; + } + + for (tmp = sess->dcc7_list; tmp; tmp = tmp->next) { + if (tmp->next == dcc) { + tmp = dcc->next; + dcc->next = NULL; + return 0; + } + } + + errno = ENOENT; + return -1; +} + +/** + * \internal Zwraca struktur� po��czenia o danym identyfikatorze. + * + * \param sess Struktura sesji + * \param id Identyfikator po��czenia + * \param uin Numer nadawcy lub odbiorcy + * + * \return Struktura po��czenia lub \c NULL je�li nie znaleziono + */ +static struct gg_dcc7 *gg_dcc7_session_find(struct gg_session *sess, gg_dcc7_id_t id, uin_t uin) +{ + struct gg_dcc7 *tmp; + int empty; + + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_session_find(%p, ..., %d)\n", sess, (int) uin); + + empty = !memcmp(&id, "\0\0\0\0\0\0\0\0", 8); + + for (tmp = sess->dcc7_list; tmp; tmp = tmp->next) { + if (empty) { + if (tmp->peer_uin == uin && !tmp->state == GG_STATE_WAITING_FOR_ACCEPT) + return tmp; + } else { + if (!memcmp(&tmp->cid, &id, sizeof(id))) + return tmp; + } + } + + return NULL; +} + +/** + * \internal Nawi�zuje po��czenie bezpo�rednie + * + * \param sess Struktura sesji + * \param dcc Struktura po��czenia + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +static int gg_dcc7_connect(struct gg_session *sess, struct gg_dcc7 *dcc) +{ + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_connect(%p, %p)\n", sess, dcc); + + if (!sess || !dcc) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_connect() invalid parameters\n"); + errno = EINVAL; + return -1; + } + + if ((dcc->fd = gg_connect(&dcc->remote_addr, dcc->remote_port, 1)) == -1) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_connect() connection failed\n"); + return -1; + } + + dcc->state = GG_STATE_CONNECTING; + dcc->check = GG_CHECK_WRITE; + dcc->timeout = GG_DCC7_TIMEOUT_CONNECT; + dcc->soft_timeout = 1; + + return 0; +} + +/** + * \internal Tworzy gniazdo nas�uchuj�ce dla po��czenia bezpo�redniego + * + * \param dcc Struktura po��czenia + * \param port Preferowany port (je�li r坦wny 0 lub -1, pr坦buje si� domy�lnego) + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +static int gg_dcc7_listen(struct gg_dcc7 *dcc, uint16_t port) +{ + struct sockaddr_in sin; + int fd; + + gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_listen(%p, %d)\n", dcc, port); + + if (!dcc) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() invalid parameters\n"); + errno = EINVAL; + return -1; + } + + if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() can't create socket (%s)\n", strerror(errno)); + return -1; + } + + // XXX losowa� porty? + + if (!port) + port = GG_DEFAULT_DCC_PORT; + + while (1) { + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = INADDR_ANY; + sin.sin_port = htons(port); + + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() trying port %d\n", port); + + if (!bind(fd, (struct sockaddr*) &sin, sizeof(sin))) + break; + + if (port++ == 65535) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() no free port found\n"); + close(fd); + errno = ENOENT; + return -1; + } + } + + if (listen(fd, 1)) { + int errsv = errno; + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_listen() unable to listen (%s)\n", strerror(errno)); + close(fd); + errno = errsv; + return -1; + } + + dcc->fd = fd; + dcc->local_port = port; + + dcc->state = GG_STATE_LISTENING; + dcc->check = GG_CHECK_READ; + dcc->timeout = GG_DCC7_TIMEOUT_FILE_ACK; + + return 0; +} + +/** + * \internal Tworzy gniazdo nas�uchuj�ce i wysy�a jego parametry + * + * \param dcc Struktura po��czenia + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +static int gg_dcc7_listen_and_send_info(struct gg_dcc7 *dcc) +{ + struct gg_dcc7_info pkt; + + gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_listen_and_send_info(%p)\n", dcc); + + // XXX da� mo甜liwo�� konfiguracji? + + dcc->local_addr = dcc->sess->client_addr; + + if (gg_dcc7_listen(dcc, 0) == -1) + return -1; + + memset(&pkt, 0, sizeof(pkt)); + pkt.uin = gg_fix32(dcc->peer_uin); + pkt.type = GG_DCC7_TYPE_P2P; + pkt.id = dcc->cid; + snprintf((char*) pkt.info, sizeof(pkt.info), "%s %d", inet_ntoa(*((struct in_addr*) &dcc->local_addr)), dcc->local_port); + + return gg_send_packet(dcc->sess, GG_DCC7_INFO, &pkt, sizeof(pkt), NULL); +} + +/** + * \internal Odwraca po��czenie po nieudanym connect() + * + * \param dcc Struktura po��czenia + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +static int gg_dcc7_reverse_connect(struct gg_dcc7 *dcc) +{ + gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_reverse_connect(%p)\n", dcc); + + if (dcc->reverse) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_reverse_connect() already reverse connection\n"); + return -1; + } + + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_reverse_connect() timeout, trying reverse connection\n"); + close(dcc->fd); + dcc->fd = -1; + dcc->reverse = 1; + + return gg_dcc7_listen_and_send_info(dcc); +} + +/** + * \internal Wysy�a do serwera 甜�danie nadania identyfikatora sesji + * + * \param sess Struktura sesji + * \param type Rodzaj po��czenia (\c GG_DCC7_TYPE_FILE lub \c GG_DCC7_TYPE_VOICE) + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +static int gg_dcc7_request_id(struct gg_session *sess, uint32_t type) +{ + struct gg_dcc7_id_request pkt; + + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_request_id(%p, %d)\n", sess, type); + + if (!sess) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_request_id() invalid parameters\n"); + errno = EFAULT; + return -1; + } + + if (sess->state != GG_STATE_CONNECTED) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_request_id() not connected\n"); + errno = ENOTCONN; + return -1; + } + + if (type != GG_DCC7_TYPE_VOICE && type != GG_DCC7_TYPE_FILE) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_request_id() invalid transfer type (%d)\n", type); + errno = EINVAL; + return -1; + } + + memset(&pkt, 0, sizeof(pkt)); + pkt.type = gg_fix32(type); + + return gg_send_packet(sess, GG_DCC7_ID_REQUEST, &pkt, sizeof(pkt), NULL); +} + +/** + * \internal Rozpoczyna wysy�anie pliku. + * + * Funkcja jest wykorzystywana przez \c gg_dcc7_send_file() oraz + * \c gg_dcc_send_file_fd(). + * + * \param sess Struktura sesji + * \param rcpt Numer odbiorcy + * \param fd Deskryptor pliku + * \param size Rozmiar pliku + * \param filename1250 Nazwa pliku w kodowaniu CP-1250 + * \param hash Skr坦t SHA-1 pliku + * \param seek Flaga m坦wi�ca, czy mo甜na u甜ywa� lseek() + * + * \return Struktura \c gg_dcc7 lub \c NULL w przypadku b��du + * + * \ingroup dcc7 + */ +static struct gg_dcc7 *gg_dcc7_send_file_common(struct gg_session *sess, uin_t rcpt, int fd, size_t size, const char *filename1250, const char *hash, int seek) +{ + struct gg_dcc7 *dcc = NULL; + + if (!sess || !rcpt || !filename1250 || !hash || fd == -1) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file_common() invalid parameters\n"); + errno = EINVAL; + goto fail; + } + + if (!(dcc = malloc(sizeof(struct gg_dcc7)))) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file_common() not enough memory\n"); + goto fail; + } + + if (gg_dcc7_request_id(sess, GG_DCC7_TYPE_FILE) == -1) + goto fail; + + memset(dcc, 0, sizeof(struct gg_dcc7)); + dcc->type = GG_SESSION_DCC7_SEND; + dcc->dcc_type = GG_DCC7_TYPE_FILE; + dcc->state = GG_STATE_REQUESTING_ID; + dcc->timeout = GG_DEFAULT_TIMEOUT; + dcc->sess = sess; + dcc->fd = -1; + dcc->uin = sess->uin; + dcc->peer_uin = rcpt; + dcc->file_fd = fd; + dcc->size = size; + dcc->seek = seek; + + strncpy((char*) dcc->filename, filename1250, GG_DCC7_FILENAME_LEN - 1); + dcc->filename[GG_DCC7_FILENAME_LEN] = 0; + + memcpy(dcc->hash, hash, GG_DCC7_HASH_LEN); + + if (gg_dcc7_session_add(sess, dcc) == -1) + goto fail; + + return dcc; + +fail: + free(dcc); + return NULL; +} + +/** + * Rozpoczyna wysy�anie pliku o danej nazwie. + * + * \param sess Struktura sesji + * \param rcpt Numer odbiorcy + * \param filename Nazwa pliku w lokalnym systemie plik坦w + * \param filename1250 Nazwa pliku w kodowaniu CP-1250 + * \param hash Skr坦t SHA-1 pliku (lub \c NULL je�li ma by� wyznaczony) + * + * \return Struktura \c gg_dcc7 lub \c NULL w przypadku b��du + * + * \ingroup dcc7 + */ +struct gg_dcc7 *gg_dcc7_send_file(struct gg_session *sess, uin_t rcpt, const char *filename, const char *filename1250, const char *hash) +{ + struct gg_dcc7 *dcc = NULL; + const char *tmp; + char hash_buf[GG_DCC7_HASH_LEN]; + struct stat st; + int fd = -1; + + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_send_file(%p, %d, \"%s\", %p)\n", sess, rcpt, filename, hash); + + if (!sess || !rcpt || !filename) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file() invalid parameters\n"); + errno = EINVAL; + goto fail; + } + + if (!filename1250) + filename1250 = filename; + + if (stat(filename, &st) == -1) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file() stat() failed (%s)\n", strerror(errno)); + goto fail; + } + + if ((st.st_mode & S_IFDIR)) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file() that's a directory\n"); + errno = EINVAL; + goto fail; + } + + if ((fd = open(filename, O_RDONLY)) == -1) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_send_file() open() failed (%s)\n", strerror(errno)); + goto fail; + } + + if (!hash) { + if (gg_file_hash_sha1(fd, (uint8_t*) hash_buf) == -1) + goto fail; + + hash = hash_buf; + } + + if ((tmp = strrchr(filename1250, '/'))) + filename1250 = tmp + 1; + + if (!(dcc = gg_dcc7_send_file_common(sess, rcpt, fd, st.st_size, filename1250, hash, 1))) + goto fail; + + return dcc; + +fail: + if (fd != -1) { + int errsv = errno; + close(fd); + errno = errsv; + } + + free(dcc); + return NULL; +} + +/** + * \internal Rozpoczyna wysy�anie pliku o danym deskryptorze. + * + * \note Wysy�anie pliku nie b�dzie dzia�a� poprawnie, je�li deskryptor + * 添r坦d�owy jest w trybie nieblokuj�cym i w pewnym momencie zabraknie danych. + * + * \param sess Struktura sesji + * \param rcpt Numer odbiorcy + * \param fd Deskryptor pliku + * \param size Rozmiar pliku + * \param filename1250 Nazwa pliku w kodowaniu CP-1250 + * \param hash Skr坦t SHA-1 pliku + * + * \return Struktura \c gg_dcc7 lub \c NULL w przypadku b��du + * + * \ingroup dcc7 + */ +struct gg_dcc7 *gg_dcc7_send_file_fd(struct gg_session *sess, uin_t rcpt, int fd, size_t size, const char *filename1250, const char *hash) +{ + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_send_file_fd(%p, %d, %d, %u, \"%s\", %p)\n", sess, rcpt, fd, size, filename1250, hash); + + return gg_dcc7_send_file_common(sess, rcpt, fd, size, filename1250, hash, 0); +} + + +/** + * Potwierdza ch�� odebrania pliku. + * + * \param dcc Struktura po��czenia + * \param offset Pocz�tkowy offset przy wznawianiu przesy�ania pliku + * + * \note Biblioteka nie zmienia po�o甜enia w odbieranych plikach. Je�li offset + * pocz�tkowy jest r坦甜ny od zera, nale甜y ustawi� go funkcj� \c lseek() lub + * podobn�. + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup dcc7 + */ +int gg_dcc7_accept(struct gg_dcc7 *dcc, unsigned int offset) +{ + struct gg_dcc7_accept pkt; + + gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_accept(%p, %d)\n", dcc, offset); + + if (!dcc || !dcc->sess) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_accept() invalid parameters\n"); + errno = EFAULT; + return -1; + } + + memset(&pkt, 0, sizeof(pkt)); + pkt.uin = gg_fix32(dcc->peer_uin); + pkt.id = dcc->cid; + pkt.offset = gg_fix32(offset); + + if (gg_send_packet(dcc->sess, GG_DCC7_ACCEPT, &pkt, sizeof(pkt), NULL) == -1) + return -1; + + dcc->offset = offset; + + return gg_dcc7_listen_and_send_info(dcc); +} + +/** + * Odrzuca pr坦b� przes�ania pliku. + * + * \param dcc Struktura po��czenia + * \param reason Pow坦d odrzucenia + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup dcc7 + */ +int gg_dcc7_reject(struct gg_dcc7 *dcc, int reason) +{ + struct gg_dcc7_reject pkt; + + gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_reject(%p, %d)\n", dcc, reason); + + if (!dcc || !dcc->sess) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_reject() invalid parameters\n"); + errno = EFAULT; + return -1; + } + + memset(&pkt, 0, sizeof(pkt)); + pkt.uin = gg_fix32(dcc->peer_uin); + pkt.id = dcc->cid; + pkt.reason = gg_fix32(reason); + + return gg_send_packet(dcc->sess, GG_DCC7_REJECT, &pkt, sizeof(pkt), NULL); +} + +/** + * \internal Obs�uguje pakiet identyfikatora po��czenia bezpo�redniego. + * + * \param sess Struktura sesji + * \param e Struktura zdarzenia + * \param payload Tre�� pakietu + * \param len D�ugo�� pakietu + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +int gg_dcc7_handle_id(struct gg_session *sess, struct gg_event *e, void *payload, int len) +{ + struct gg_dcc7_id_reply *p = payload; + struct gg_dcc7 *tmp; + + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_handle_id(%p, %p, %p, %d)\n", sess, e, payload, len); + + for (tmp = sess->dcc7_list; tmp; tmp = tmp->next) { + gg_debug_session(sess, GG_DEBUG_MISC, "// checking dcc %p, state %d, type %d\n", tmp, tmp->state, tmp->dcc_type); + + if (tmp->state != GG_STATE_REQUESTING_ID || tmp->dcc_type != gg_fix32(p->type)) + continue; + + tmp->cid = p->id; + + switch (tmp->dcc_type) { + case GG_DCC7_TYPE_FILE: + { + struct gg_dcc7_new s; + + memset(&s, 0, sizeof(s)); + s.id = tmp->cid; + s.type = gg_fix32(GG_DCC7_TYPE_FILE); + s.uin_from = gg_fix32(tmp->uin); + s.uin_to = gg_fix32(tmp->peer_uin); + s.size = gg_fix32(tmp->size); + + strncpy((char*) s.filename, (char*) tmp->filename, GG_DCC7_FILENAME_LEN); + + tmp->state = GG_STATE_WAITING_FOR_ACCEPT; + tmp->timeout = GG_DCC7_TIMEOUT_FILE_ACK; + + return gg_send_packet(sess, GG_DCC7_NEW, &s, sizeof(s), NULL); + } + } + } + + return 0; +} + +/** + * \internal Obs�uguje pakiet akceptacji po��czenia bezpo�redniego. + * + * \param sess Struktura sesji + * \param e Struktura zdarzenia + * \param payload Tre�� pakietu + * \param len D�ugo�� pakietu + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +int gg_dcc7_handle_accept(struct gg_session *sess, struct gg_event *e, void *payload, int len) +{ + struct gg_dcc7_accept *p = payload; + struct gg_dcc7 *dcc; + + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_handle_accept(%p, %p, %p, %d)\n", sess, e, payload, len); + + if (!(dcc = gg_dcc7_session_find(sess, p->id, gg_fix32(p->uin)))) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_accept() unknown dcc session\n"); + // XXX wys�a� reject? + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE; + return 0; + } + + if (dcc->state != GG_STATE_WAITING_FOR_ACCEPT) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_accept() invalid state\n"); + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE; + return 0; + } + + // XXX czy dla odwrotnego po��czenia powinni�my wywo�a� ju甜 zdarzenie GG_DCC7_ACCEPT? + + dcc->offset = gg_fix32(p->offset); + dcc->state = GG_STATE_WAITING_FOR_INFO; + + return 0; +} + +/** + * \internal Obs�uguje pakiet informacji o po��czeniu bezpo�rednim. + * + * \param sess Struktura sesji + * \param e Struktura zdarzenia + * \param payload Tre�� pakietu + * \param len D�ugo�� pakietu + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +int gg_dcc7_handle_info(struct gg_session *sess, struct gg_event *e, void *payload, int len) +{ + struct gg_dcc7_info *p = payload; + struct gg_dcc7 *dcc; + char *tmp; + + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_handle_info(%p, %p, %p, %d)\n", sess, e, payload, len); + + if (!(dcc = gg_dcc7_session_find(sess, p->id, gg_fix32(p->uin)))) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() unknown dcc session\n"); + return 0; + } + + if (p->type != GG_DCC7_TYPE_P2P) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() unhandled transfer type (%d)\n", p->type); + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE; + return 0; + } + + if ((dcc->remote_addr = inet_addr(p->info)) == INADDR_NONE) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() invalid IP address\n"); + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE; + return 0; + } + + if (!(tmp = strchr(p->info, ' ')) || !(dcc->remote_port = atoi(tmp + 1))) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() invalid IP port\n"); + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE; + return 0; + } + + // je�li nadal czekamy na po��czenie przychodz�ce, a druga strona nie + // daje rady i oferuje namiary na siebie, bierzemy co daj�. + + if (dcc->state != GG_STATE_WAITING_FOR_INFO && (dcc->state != GG_STATE_LISTENING || dcc->reverse)) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_info() invalid state\n"); + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE; + return 0; + } + + if (dcc->state == GG_STATE_LISTENING) { + close(dcc->fd); + dcc->fd = -1; + dcc->reverse = 1; + } + + if (dcc->type == GG_SESSION_DCC7_SEND) { + e->type = GG_EVENT_DCC7_ACCEPT; + e->event.dcc7_accept.dcc7 = dcc; + e->event.dcc7_accept.type = gg_fix32(p->type); + e->event.dcc7_accept.remote_ip = dcc->remote_addr; + e->event.dcc7_accept.remote_port = dcc->remote_port; + } else { + e->type = GG_EVENT_DCC7_PENDING; + } + + if (gg_dcc7_connect(sess, dcc) == -1) { + if (gg_dcc7_reverse_connect(dcc) == -1) { + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc7_error = GG_ERROR_DCC7_NET; + return 0; + } + } + + return 0; +} + +/** + * \internal Obs�uguje pakiet odrzucenia po��czenia bezpo�redniego. + * + * \param sess Struktura sesji + * \param e Struktura zdarzenia + * \param payload Tre�� pakietu + * \param len D�ugo�� pakietu + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +int gg_dcc7_handle_reject(struct gg_session *sess, struct gg_event *e, void *payload, int len) +{ + struct gg_dcc7_reject *p = payload; + struct gg_dcc7 *dcc; + + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_handle_reject(%p, %p, %p, %d)\n", sess, e, payload, len); + + if (!(dcc = gg_dcc7_session_find(sess, p->id, gg_fix32(p->uin)))) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_reject() unknown dcc session\n"); + return 0; + } + + if (dcc->state != GG_STATE_WAITING_FOR_ACCEPT) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_reject() invalid state\n"); + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc7_error = GG_ERROR_DCC7_HANDSHAKE; + return 0; + } + + e->type = GG_EVENT_DCC7_REJECT; + e->event.dcc7_reject.dcc7 = dcc; + e->event.dcc7_reject.reason = gg_fix32(p->reason); + + // XXX ustawi� state na rejected? + + return 0; +} + +/** + * \internal Obs�uguje pakiet nowego po��czenia bezpo�redniego. + * + * \param sess Struktura sesji + * \param e Struktura zdarzenia + * \param payload Tre�� pakietu + * \param len D�ugo�� pakietu + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +int gg_dcc7_handle_new(struct gg_session *sess, struct gg_event *e, void *payload, int len) +{ + struct gg_dcc7_new *p = payload; + struct gg_dcc7 *dcc; + + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_dcc7_handle_new(%p, %p, %p, %d)\n", sess, e, payload, len); + + switch (gg_fix32(p->type)) { + case GG_DCC7_TYPE_FILE: + if (!(dcc = malloc(sizeof(struct gg_dcc7)))) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_new() not enough memory\n"); + return -1; + } + + memset(dcc, 0, sizeof(struct gg_dcc7)); + dcc->type = GG_SESSION_DCC7_GET; + dcc->dcc_type = GG_DCC7_TYPE_FILE; + dcc->fd = -1; + dcc->file_fd = -1; + dcc->uin = sess->uin; + dcc->peer_uin = gg_fix32(p->uin_from); + dcc->cid = p->id; + dcc->sess = sess; + + if (gg_dcc7_session_add(sess, dcc) == -1) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_new() unable to add to session\n"); + gg_dcc7_free(dcc); + return -1; + } + + dcc->size = gg_fix32(p->size); + strncpy((char*) dcc->filename, (char*) p->filename, GG_DCC7_FILENAME_LEN - 1); + dcc->filename[GG_DCC7_FILENAME_LEN] = 0; + memcpy(dcc->hash, p->hash, GG_DCC7_HASH_LEN); + + e->type = GG_EVENT_DCC7_NEW; + e->event.dcc7_new = dcc; + + break; + + case GG_DCC7_TYPE_VOICE: + if (!(dcc = malloc(sizeof(struct gg_dcc7)))) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_packet() not enough memory\n"); + return -1; + } + + memset(dcc, 0, sizeof(struct gg_dcc7)); + + dcc->type = GG_SESSION_DCC7_VOICE; + dcc->dcc_type = GG_DCC7_TYPE_VOICE; + dcc->fd = -1; + dcc->file_fd = -1; + dcc->uin = sess->uin; + dcc->peer_uin = gg_fix32(p->uin_from); + dcc->cid = p->id; + dcc->sess = sess; + + if (gg_dcc7_session_add(sess, dcc) == -1) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_new() unable to add to session\n"); + gg_dcc7_free(dcc); + return -1; + } + + e->type = GG_EVENT_DCC7_NEW; + e->event.dcc7_new = dcc; + + break; + + default: + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_dcc7_handle_new() unknown dcc type (%d) from %ld\n", gg_fix32(p->type), gg_fix32(p->uin_from)); + + break; + } + + return 0; +} + +/** + * \internal Ustawia odpowiednie stany wewn�trzne w zale甜no�ci od rodzaju + * po��czenia. + * + * \param dcc Struktura po��czenia + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du. + */ +static int gg_dcc7_postauth_fixup(struct gg_dcc7 *dcc) +{ + gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_postauth_fixup(%p)\n", dcc); + + if (!dcc) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_postauth_fixup() invalid parameters\n"); + errno = EINVAL; + return -1; + } + + switch (dcc->type) { + case GG_SESSION_DCC7_GET: + dcc->state = GG_STATE_GETTING_FILE; + dcc->check = GG_CHECK_READ; + return 0; + + case GG_SESSION_DCC7_SEND: + dcc->state = GG_STATE_SENDING_FILE; + dcc->check = GG_CHECK_WRITE; + return 0; + + case GG_SESSION_DCC7_VOICE: + dcc->state = GG_STATE_READING_VOICE_DATA; + dcc->check = GG_CHECK_READ; + return 0; + } + + errno = EINVAL; + + return -1; +} + +/** + * Funkcja wywo�ywana po zaobserwowaniu zmian na deskryptorze po��czenia. + * + * Funkcja zwraca struktur� zdarzenia \c gg_event. Je�li rodzaj zdarzenia + * to \c GG_EVENT_NONE, nie wydarzy�o si� jeszcze nic wartego odnotowania. + * Struktur� zdarzenia nale甜y zwolni� funkcja \c gg_event_free(). + * + * \param dcc Struktura po��czenia + * + * \return Struktura zdarzenia lub \c NULL je�li wyst�pi� b��d + * + * \ingroup dcc7 + */ +struct gg_event *gg_dcc7_watch_fd(struct gg_dcc7 *dcc) +{ + struct gg_event *e; + + gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_watch_fd(%p)\n", dcc); + + if (!dcc || (dcc->type != GG_SESSION_DCC7_SEND && dcc->type != GG_SESSION_DCC7_GET && dcc->type != GG_SESSION_DCC7_VOICE)) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() invalid parameters\n"); + errno = EINVAL; + return NULL; + } + + if (!(e = malloc(sizeof(struct gg_event)))) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() not enough memory\n"); + return NULL; + } + + memset(e, 0, sizeof(struct gg_event)); + e->type = GG_EVENT_NONE; + + switch (dcc->state) { + case GG_STATE_LISTENING: + { + struct sockaddr_in sin; + int fd, one = 1; + socklen_t sin_len = sizeof(sin); + + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_LISTENING\n"); + + if ((fd = accept(dcc->fd, (struct sockaddr*) &sin, &sin_len)) == -1) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() accept() failed (%s)\n", strerror(errno)); + return e; + } + + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() connection from %s:%d\n", inet_ntoa(sin.sin_addr), htons(sin.sin_port)); + +#ifdef FIONBIO + if (ioctl(fd, FIONBIO, &one) == -1) { +#else + if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { +#endif + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() can't set nonblocking (%s)\n", strerror(errno)); + close(fd); + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE; + return e; + } + + close(dcc->fd); + dcc->fd = fd; + + dcc->state = GG_STATE_READING_ID; + dcc->check = GG_CHECK_READ; + dcc->timeout = GG_DEFAULT_TIMEOUT; + dcc->incoming = 1; + + dcc->remote_port = ntohs(sin.sin_port); + dcc->remote_addr = sin.sin_addr.s_addr; + + e->type = GG_EVENT_DCC7_CONNECTED; + e->event.dcc7_connected.dcc7 = dcc; + + return e; + } + + case GG_STATE_CONNECTING: + { + int res = 0, error = 0; + unsigned int error_size = sizeof(error); + + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_CONNECTING\n"); + + dcc->soft_timeout = 0; + + if (dcc->timeout == 0) + error = ETIMEDOUT; + + if (error || (res = getsockopt(dcc->fd, SOL_SOCKET, SO_ERROR, &error, &error_size)) == -1 || error != 0) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() connection failed (%s)\n", (res == -1) ? strerror(errno) : strerror(error)); + + if (gg_dcc7_reverse_connect(dcc) != -1) { + e->type = GG_EVENT_DCC7_PENDING; + } else { + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc_error = GG_ERROR_DCC7_NET; + } + + return e; + } + + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() connected, sending id\n"); + + dcc->state = GG_STATE_SENDING_ID; + dcc->check = GG_CHECK_WRITE; + dcc->timeout = GG_DEFAULT_TIMEOUT; + dcc->incoming = 0; + + return e; + } + + case GG_STATE_READING_ID: + { + gg_dcc7_id_t id; + int res; + + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_READING_ID\n"); + + if ((res = read(dcc->fd, &id, sizeof(id))) != sizeof(id)) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() read() failed (%d, %s)\n", res, strerror(errno)); + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE; + return e; + } + + if (memcmp(&id, &dcc->cid, sizeof(id))) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() invalid id\n"); + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE; + return e; + } + + if (dcc->incoming) { + dcc->state = GG_STATE_SENDING_ID; + dcc->check = GG_CHECK_WRITE; + dcc->timeout = GG_DEFAULT_TIMEOUT; + } else { + gg_dcc7_postauth_fixup(dcc); + dcc->timeout = GG_DEFAULT_TIMEOUT; + } + + return e; + } + + case GG_STATE_SENDING_ID: + { + int res; + + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_SENDING_ID\n"); + + if ((res = write(dcc->fd, &dcc->cid, sizeof(dcc->cid))) != sizeof(dcc->cid)) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() write() failed (%d, %s)", res, strerror(errno)); + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE; + return e; + } + + if (dcc->incoming) { + gg_dcc7_postauth_fixup(dcc); + dcc->timeout = GG_DEFAULT_TIMEOUT; + } else { + dcc->state = GG_STATE_READING_ID; + dcc->check = GG_CHECK_READ; + dcc->timeout = GG_DEFAULT_TIMEOUT; + } + + return e; + } + + case GG_STATE_SENDING_FILE: + { + char buf[1024]; + int chunk, res; + + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_SENDING_FILE (offset=%d, size=%d)\n", dcc->offset, dcc->size); + + if (dcc->offset >= dcc->size) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() offset >= size, finished\n"); + e->type = GG_EVENT_DCC7_DONE; + return e; + } + + if (dcc->seek && lseek(dcc->file_fd, dcc->offset, SEEK_SET) == (off_t) -1) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() lseek() failed (%s)\n", strerror(errno)); + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc_error = GG_ERROR_DCC7_FILE; + return e; + } + + if ((chunk = dcc->size - dcc->offset) > sizeof(buf)) + chunk = sizeof(buf); + + if ((res = read(dcc->file_fd, buf, chunk)) < 1) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() read() failed (res=%d, %s)\n", res, strerror(errno)); + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc_error = (res == -1) ? GG_ERROR_DCC7_FILE : GG_ERROR_DCC7_EOF; + return e; + } + + if ((res = write(dcc->fd, buf, res)) == -1) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() write() failed (%s)\n", strerror(errno)); + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc_error = GG_ERROR_DCC7_NET; + return e; + } + + dcc->offset += res; + + if (dcc->offset >= dcc->size) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() finished\n"); + e->type = GG_EVENT_DCC7_DONE; + return e; + } + + dcc->state = GG_STATE_SENDING_FILE; + dcc->check = GG_CHECK_WRITE; + dcc->timeout = GG_DCC7_TIMEOUT_SEND; + + return e; + } + + case GG_STATE_GETTING_FILE: + { + char buf[1024]; + int res, wres; + + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_GETTING_FILE (offset=%d, size=%d)\n", dcc->offset, dcc->size); + + if (dcc->offset >= dcc->size) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() finished\n"); + e->type = GG_EVENT_DCC7_DONE; + return e; + } + + if ((res = read(dcc->fd, buf, sizeof(buf))) < 1) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() read() failed (fd=%d, res=%d, %s)\n", dcc->fd, res, strerror(errno)); + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc_error = (res == -1) ? GG_ERROR_DCC7_NET : GG_ERROR_DCC7_EOF; + return e; + } + + // XXX zapisywa� do skutku? + + if ((wres = write(dcc->file_fd, buf, res)) < res) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() write() failed (fd=%d, res=%d, %s)\n", dcc->file_fd, wres, strerror(errno)); + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc_error = GG_ERROR_DCC7_FILE; + return e; + } + + dcc->offset += res; + + if (dcc->offset >= dcc->size) { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() finished\n"); + e->type = GG_EVENT_DCC7_DONE; + return e; + } + + dcc->state = GG_STATE_GETTING_FILE; + dcc->check = GG_CHECK_READ; + dcc->timeout = GG_DCC7_TIMEOUT_GET; + + return e; + } + + default: + { + gg_debug_dcc(dcc, GG_DEBUG_MISC, "// gg_dcc7_watch_fd() GG_STATE_???\n"); + e->type = GG_EVENT_DCC7_ERROR; + e->event.dcc_error = GG_ERROR_DCC7_HANDSHAKE; + + return e; + } + } + + return e; +} + +/** + * Zwalnia zasoby u甜ywane przez po��czenie bezpo�rednie. + * + * \param dcc Struktura po��czenia + * + * \ingroup dcc7 + */ +void gg_dcc7_free(struct gg_dcc7 *dcc) +{ + gg_debug_dcc(dcc, GG_DEBUG_FUNCTION, "** gg_dcc7_free(%p)\n", dcc); + + if (!dcc) + return; + + if (dcc->fd != -1) + close(dcc->fd); + + if (dcc->file_fd != -1) + close(dcc->file_fd); + + if (dcc->sess) + gg_dcc7_session_remove(dcc->sess, dcc); + + free(dcc); +} +
--- a/libpurple/protocols/gg/lib/events.c Sun Feb 28 23:42:12 2010 +0000 +++ b/libpurple/protocols/gg/lib/events.c Mon Mar 01 03:46:33 2010 +0000 @@ -1,9 +1,10 @@ -/* $Id: events.c 16856 2006-08-19 01:13:25Z evands $ */ +/* $Id: events.c 855 2009-10-12 21:42:51Z wojtekka $ */ /* - * (C) Copyright 2001-2003 Wojtek Kaniewski <wojtekka@irc.pl> - * Robert J. Wo�ny <speedy@ziew.org> - * Arkadiusz Mi�kiewicz <arekm@pld-linux.org> + * (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka@irc.pl> + * Robert J. Wo添ny <speedy@ziew.org> + * Arkadiusz Mi�kiewicz <arekm@pld-linux.org> + * Adam Wysocki <gophi@ekg.chmurka.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License Version @@ -16,71 +17,78 @@ * * 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. */ +/** + * \file events.c + * + * \brief Obs�uga zdarze� + */ + #include "libgadu.h" +#include "libgadu-internal.h" #include <sys/types.h> + #ifndef _WIN32 -#include <sys/wait.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> +# include <sys/ioctl.h> +# include <sys/socket.h> +# include <netinet/in.h> +# include <arpa/inet.h> #endif -#include "libgadu-config.h" +#include "compat.h" +#include "protocol.h" #include <errno.h> -#ifdef __GG_LIBGADU_HAVE_PTHREAD -# include <pthread.h> -#endif #include <stdio.h> #include <string.h> #include <stdlib.h> #include <time.h> #include <unistd.h> -#ifdef __GG_LIBGADU_HAVE_OPENSSL +#include <ctype.h> +#ifdef GG_CONFIG_HAVE_OPENSSL # include <openssl/err.h> # include <openssl/x509.h> #endif -#include "compat.h" - -/* - * gg_event_free() +/** + * Zwalnia pami�� zajmowan� przez informacj� o zdarzeniu. * - * zwalnia pami裝 zajmowan� przez informacj� o zdarzeniu. + * Funkcj� nale甜y wywo�ywa� za ka甜dym razem gdy funkcja biblioteki zwr坦ci + * struktur� \c gg_event. * - * - e - wska�nik do informacji o zdarzeniu + * \param e Struktura zdarzenia + * + * \ingroup events */ void gg_event_free(struct gg_event *e) { gg_debug(GG_DEBUG_FUNCTION, "** gg_event_free(%p);\n", e); - + if (!e) return; - + switch (e->type) { case GG_EVENT_MSG: free(e->event.msg.message); free(e->event.msg.formats); free(e->event.msg.recipients); break; - + case GG_EVENT_NOTIFY: free(e->event.notify); break; - + case GG_EVENT_NOTIFY60: { int i; for (i = 0; e->event.notify60[i].uin; i++) free(e->event.notify60[i].descr); - + free(e->event.notify60); break; @@ -89,7 +97,7 @@ case GG_EVENT_STATUS60: free(e->event.status60.descr); break; - + case GG_EVENT_STATUS: free(e->event.status.descr); break; @@ -112,26 +120,30 @@ case GG_EVENT_USERLIST: free(e->event.userlist.reply); break; - + case GG_EVENT_IMAGE_REPLY: free(e->event.image_reply.filename); free(e->event.image_reply.image); break; + + case GG_EVENT_XML_EVENT: + free(e->event.xml_event.data); + break; } free(e); } -/* - * gg_image_queue_remove() - * - * usuwa z kolejki dany wpis. +/** \cond internal */ + +/** + * \internal Usuwa obrazek z kolejki do wys�ania. * - * - s - sesja - * - q - kolejka - * - freeq - czy zwolni� kolejk� + * \param s Struktura sesji + * \param q Struktura obrazka + * \param freeq Flaga zwolnienia elementu kolejki * - * 0/-1 + * \return 0 je�li si� powiod�o, -1 je�li wyst�pi� b��d */ int gg_image_queue_remove(struct gg_session *s, struct gg_image_queue *q, int freeq) { @@ -162,13 +174,14 @@ return 0; } -/* - * gg_image_queue_parse() // funkcja wewn�trzna +/** + * \internal Analizuje przychodz�cy pakiet z obrazkiem. * - * parsuje przychodz�cy pakiet z obrazkiem. - * - * - e - opis zdarzenia - * - + * \param e Struktura zdarzenia + * \param p Bufor z danymi + * \param len D�ugo�� bufora + * \param sess Struktura sesji + * \param sender Numer nadawcy */ static void gg_image_queue_parse(struct gg_event *e, char *p, unsigned int len, struct gg_session *sess, uin_t sender) { @@ -180,8 +193,8 @@ return; } - /* znajd� dany obrazek w kolejce danej sesji */ - + /* znajd添 dany obrazek w kolejce danej sesji */ + for (qq = sess->images, q = NULL; qq; qq = qq->next) { if (sender == qq->sender && i->size == qq->size && i->crc32 == qq->crc32) { q = qq; @@ -190,34 +203,23 @@ } if (!q) { - gg_debug(GG_DEBUG_MISC, "// gg_image_queue_parse() unknown image from %d, size=%d, crc32=%.8x\n", sender, i->size, i->crc32); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_image_queue_parse() unknown image from %d, size=%d, crc32=%.8x\n", sender, i->size, i->crc32); return; } if (p[0] == 0x05) { - unsigned int i, ok = 0; - q->done = 0; len -= sizeof(struct gg_msg_image_reply); p += sizeof(struct gg_msg_image_reply); - /* sprawd�, czy mamy tekst zako�czony \0 */ - - for (i = 0; i < len; i++) { - if (!p[i]) { - ok = 1; - break; - } - } - - if (!ok) { - gg_debug(GG_DEBUG_MISC, "// gg_image_queue_parse() malformed packet from %d, unlimited filename\n", sender); + if (memchr(p, 0, len) == NULL) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_image_queue_parse() malformed packet from %d, unlimited filename\n", sender); return; } if (!(q->filename = strdup(p))) { - gg_debug(GG_DEBUG_MISC, "// gg_image_queue_parse() not enough memory for filename\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_image_queue_parse() not enough memory for filename\n"); return; } @@ -230,11 +232,11 @@ if (q->done + len > q->size) len = q->size - q->done; - + memcpy(q->image + q->done, p, len); q->done += len; - /* je�li sko�czono odbiera� obrazek, wygeneruj zdarzenie */ + /* je�li sko�czono odbiera� obrazek, wygeneruj zdarzenie */ if (q->done >= q->size) { e->type = GG_EVENT_IMAGE_REPLY; @@ -250,78 +252,55 @@ } } -/* - * gg_handle_recv_msg() // funkcja wewn�trzna - * - * obs�uguje pakiet z przychodz�c� wiadomo�ci�, rozbijaj�c go na dodatkowe - * struktury (konferencje, kolorki) w razie potrzeby. +/** + * \internal Analizuje informacje rozszerzone wiadomo�ci. + * + * \param sess Struktura sesji. + * \param e Struktura zdarzenia. + * \param sender Numer nadawcy. + * \param p Wska添nik na dane rozszerzone. + * \param packet_end Wska添nik na koniec pakietu. * - * - h - nag鞄wek pakietu - * - e - opis zdarzenia - * - * 0, -1. + * \return 0 je�li si� powiod�o, -1 je�li wiadomo�� obs�u甜ono i wynik ma + * zosta� przekazany aplikacji, -2 je�li wyst�pi� b��d og坦lny, -3 je�li + * wiadomo�� jest niepoprawna. */ -static int gg_handle_recv_msg(struct gg_header *h, struct gg_event *e, struct gg_session *sess) +static int gg_handle_recv_msg_options(struct gg_session *sess, struct gg_event *e, uin_t sender, char *p, char *packet_end) { - struct gg_recv_msg *r = (struct gg_recv_msg*) ((char*) h + sizeof(struct gg_header)); - char *p, *packet_end = (char*) r + h->length; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_handle_recv_msg(%p, %p);\n", h, e); - - if (!r->seq && !r->msgclass) { - gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() oops, silently ignoring the bait\n"); - e->type = GG_EVENT_NONE; - return 0; - } - - for (p = (char*) r + sizeof(*r); *p; p++) { - if (*p == 0x02 && p == packet_end - 1) { - gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() received ctcp packet\n"); - break; - } - if (p >= packet_end) { - gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() malformed packet, message out of bounds (0)\n"); - goto malformed; - } - } - - p++; - - /* przeanalizuj dodatkowe opcje */ while (p < packet_end) { switch (*p) { case 0x01: /* konferencja */ { struct gg_msg_recipients *m = (void*) p; uint32_t i, count; - + p += sizeof(*m); - + if (p > packet_end) { - gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (1)\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (1)\n"); goto malformed; } count = gg_fix32(m->count); if (p + count * sizeof(uin_t) > packet_end || p + count * sizeof(uin_t) < p || count > 0xffff) { - gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (1.5)\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (1.5)\n"); goto malformed; } - + if (!(e->event.msg.recipients = (void*) malloc(count * sizeof(uin_t)))) { - gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() not enough memory for recipients data\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() not enough memory for recipients data\n"); goto fail; } - + for (i = 0; i < count; i++, p += sizeof(uint32_t)) { uint32_t u; memcpy(&u, p, sizeof(uint32_t)); e->event.msg.recipients[i] = gg_fix32(u); } - + e->event.msg.recipients_count = count; - + break; } @@ -329,9 +308,9 @@ { uint16_t len; char *buf; - + if (p + 3 > packet_end) { - gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (2)\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (2)\n"); goto malformed; } @@ -339,18 +318,18 @@ len = gg_fix16(len); if (!(buf = malloc(len))) { - gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() not enough memory for richtext data\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() not enough memory for richtext data\n"); goto fail; } p += 3; if (p + len > packet_end) { - gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (3)\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (3)\n"); free(buf); goto malformed; } - + memcpy(buf, p, len); e->event.msg.formats = buf; @@ -366,17 +345,17 @@ struct gg_msg_image_request *i = (void*) p; if (p + sizeof(*i) > packet_end) { - gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (3)\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (3)\n"); goto malformed; } - e->event.image_request.sender = gg_fix32(r->sender); + e->event.image_request.sender = sender; e->event.image_request.size = gg_fix32(i->size); e->event.image_request.crc32 = gg_fix32(i->crc32); e->type = GG_EVENT_IMAGE_REQUEST; - return 0; + goto handled; } case 0x05: /* image_reply */ @@ -386,75 +365,347 @@ if (p + sizeof(struct gg_msg_image_reply) == packet_end) { - /* pusta odpowied� - klient po drugiej stronie nie ma 娠danego obrazka */ + /* pusta odpowied添 - klient po drugiej stronie nie ma 甜�danego obrazka */ e->type = GG_EVENT_IMAGE_REPLY; - e->event.image_reply.sender = gg_fix32(r->sender); + e->event.image_reply.sender = sender; e->event.image_reply.size = 0; e->event.image_reply.crc32 = gg_fix32(rep->crc32); e->event.image_reply.filename = NULL; e->event.image_reply.image = NULL; - return 0; + goto handled; } else if (p + sizeof(struct gg_msg_image_reply) + 1 > packet_end) { - gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (4)\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (4)\n"); goto malformed; } rep->size = gg_fix32(rep->size); rep->crc32 = gg_fix32(rep->crc32); - gg_image_queue_parse(e, p, (unsigned int)(packet_end - p), sess, gg_fix32(r->sender)); - - return 0; + gg_image_queue_parse(e, p, (unsigned int)(packet_end - p), sess, sender); + + goto handled; } default: { - gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() unknown payload 0x%.2x\n", *p); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() unknown payload 0x%.2x\n", *p); p = packet_end; } } } + return 0; + +handled: + return -1; + +fail: + return -2; + +malformed: + return -3; +} + +/** + * \internal Analizuje przychodz�cy pakiet z wiadomo�ci�. + * + * Rozbija pakiet na poszczeg坦lne sk�adniki -- tekst, informacje + * o konferencjach, formatowani itd. + * + * \param h Wska添nik do odebranego pakietu + * \param e Struktura zdarzenia + * \param sess Struktura sesji + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +static int gg_handle_recv_msg(struct gg_header *h, struct gg_event *e, struct gg_session *sess) +{ + struct gg_recv_msg *r = (struct gg_recv_msg*) ((char*) h + sizeof(struct gg_header)); + char *p, *packet_end = (char*) r + h->length; + + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_handle_recv_msg(%p, %p);\n", h, e); + + if (!r->seq && !r->msgclass) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() oops, silently ignoring the bait\n"); + e->type = GG_EVENT_NONE; + return 0; + } + + /* znajd添 \0 */ + for (p = (char*) r + sizeof(*r); ; p++) { + if (p >= packet_end) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() malformed packet, message out of bounds (0)\n"); + goto malformed; + } + + if (*p == 0x02 && p == packet_end - 1) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg() received ctcp packet\n"); + break; + } + + if (!*p) + break; + } + + p++; + + switch (gg_handle_recv_msg_options(sess, e, gg_fix32(r->sender), p, packet_end)) { + case -1: // handled + return 0; + + case -2: // failed + goto fail; + + case -3: // malformed + goto malformed; + } + e->type = GG_EVENT_MSG; e->event.msg.msgclass = gg_fix32(r->msgclass); e->event.msg.sender = gg_fix32(r->sender); e->event.msg.time = gg_fix32(r->time); - e->event.msg.message = (unsigned char *)strdup((char*) r + sizeof(*r)); + e->event.msg.seq = gg_fix32(r->seq); + e->event.msg.message = (unsigned char*) strdup((char*) r + sizeof(*r)); return 0; malformed: e->type = GG_EVENT_NONE; - + free(e->event.msg.message); free(e->event.msg.recipients); free(e->event.msg.formats); return 0; fail: + free(e->event.msg.message); free(e->event.msg.recipients); free(e->event.msg.formats); return -1; } -/* - * gg_watch_fd_connected() // funkcja wewn�trzna +/** + * \internal Zamienia tekst w formacie HTML na czysty tekst. + * + * \param dst Bufor wynikowy (mo甜e by� \c NULL) + * \param html Tekst 添r坦d�owy + * + * \note Dokleja \c \\0 na ko�cu bufora wynikowego. * - * patrzy na gniazdo, odbiera pakiet i wype�nia struktur� zdarzenia. + * \return D�ugo�� tekstu wynikowego bez \c \\0 (nawet je�li \c dst to \c NULL). + */ +static int gg_convert_from_html(char *dst, const char *html) +{ + const char *src, *entity, *tag; + int len, in_tag, in_entity; + + len = 0; + in_tag = 0; + tag = NULL; + in_entity = 0; + entity = NULL; + + for (src = html; *src != 0; src++) { + if (*src == '<') { + tag = src; + in_tag = 1; + continue; + } + + if (in_tag && (*src == '>')) { + if (strncmp(tag, "<br", 3) == 0) { + if (dst != NULL) + dst[len] = '\n'; + len++; + } + in_tag = 0; + continue; + } + + if (in_tag) + continue; + + if (*src == '&') { + in_entity = 1; + entity = src; + continue; + } + + if (in_entity && *src == ';') { + in_entity = 0; + if (dst != NULL) { + if (strncmp(entity, "<", 4) == 0) + dst[len] = '<'; + else if (strncmp(entity, ">", 4) == 0) + dst[len] = '>'; + else if (strncmp(entity, """, 6) == 0) + dst[len] = '"'; + else if (strncmp(entity, "'", 6) == 0) + dst[len] = '\''; + else if (strncmp(entity, "&", 5) == 0) + dst[len] = '&'; + else + dst[len] = '?'; + } + len++; + continue; + } + + if (in_entity && !(isalnum(*src) || *src == '#')) + in_entity = 0; + + if (in_entity) + continue; + + if (dst != NULL) + dst[len] = *src; + + len++; + } + + if (dst != NULL) + dst[len] = 0; + + return len; +} + +/** + * \internal Analizuje przychodz�cy pakiet z wiadomo�ci� protoko�u Gadu-Gadu 8.0. + * + * Rozbija pakiet na poszczeg坦lne sk�adniki -- tekst, informacje + * o konferencjach, formatowani itd. + * + * \param h Wska添nik do odebranego pakietu + * \param e Struktura zdarzenia + * \param sess Struktura sesji * - * - sess - struktura opisuj�ca sesj� - * - e - opis zdarzenia + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +static int gg_handle_recv_msg80(struct gg_header *h, struct gg_event *e, struct gg_session *sess) +{ + char *packet = (char*) h + sizeof(struct gg_header); + struct gg_recv_msg80 *r = (struct gg_recv_msg80*) packet; + uint32_t offset_plain; + uint32_t offset_attr; + + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_handle_recv_msg80(%p, %p);\n", h, e); + + if (!r->seq && !r->msgclass) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg80() oops, silently ignoring the bait\n"); + goto malformed; + } + + offset_plain = gg_fix32(r->offset_plain); + offset_attr = gg_fix32(r->offset_attr); + + if (offset_plain < sizeof(struct gg_recv_msg80) || offset_plain >= h->length) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg80() malformed packet, message out of bounds (0)\n"); + goto malformed; + } + + if (offset_attr < sizeof(struct gg_recv_msg80) || offset_attr > h->length) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg80() malformed packet, attr out of bounds (1)\n"); + offset_attr = 0; /* nie parsuj attr. */ + /* goto ignore; */ + } + + /* Normalna sytuacja, wi�c nie podpada pod powy甜szy warunek. */ + if (offset_attr == h->length) + offset_attr = 0; + + if (memchr(packet + offset_plain, 0, h->length - offset_plain) == NULL) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg80() malformed packet, message out of bounds (2)\n"); + goto malformed; + } + + if (offset_plain > sizeof(struct gg_recv_msg80) && memchr(packet + sizeof(struct gg_recv_msg80), 0, offset_plain - sizeof(struct gg_recv_msg80)) == NULL) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_handle_recv_msg80() malformed packet, message out of bounds (3)\n"); + goto malformed; + } + + e->type = GG_EVENT_MSG; + e->event.msg.msgclass = gg_fix32(r->msgclass); + e->event.msg.sender = gg_fix32(r->sender); + e->event.msg.time = gg_fix32(r->time); + e->event.msg.seq = gg_fix32(r->seq); + + if (sess->encoding == GG_ENCODING_CP1250) { + e->event.msg.message = (unsigned char*) strdup(packet + offset_plain); + } else { + if (offset_plain > sizeof(struct gg_recv_msg80)) { + int len; + + len = gg_convert_from_html(NULL, packet + sizeof(struct gg_recv_msg80)); + + e->event.msg.message = malloc(len + 1); + + if (e->event.msg.message == NULL) + goto fail; + + gg_convert_from_html((char*) e->event.msg.message, packet + sizeof(struct gg_recv_msg80)); + } else { + e->event.msg.message = (unsigned char*) gg_cp_to_utf8(packet + offset_plain); + } + } + + if (offset_plain > sizeof(struct gg_recv_msg80)) { + if (sess->encoding == GG_ENCODING_UTF8) + e->event.msg.xhtml_message = strdup(packet + sizeof(struct gg_recv_msg80)); + else + e->event.msg.xhtml_message = gg_utf8_to_cp(packet + sizeof(struct gg_recv_msg80)); + } else { + e->event.msg.xhtml_message = NULL; + } + + if (offset_attr != 0) { + switch (gg_handle_recv_msg_options(sess, e, gg_fix32(r->sender), packet + offset_attr, packet + h->length)) { + case -1: // handled + return 0; + + case -2: // failed + goto fail; + + case -3: // malformed + goto malformed; + } + } + + return 0; + +fail: + free(e->event.msg.message); + free(e->event.msg.xhtml_message); + free(e->event.msg.recipients); + free(e->event.msg.formats); + return -1; + +malformed: + e->type = GG_EVENT_NONE; + free(e->event.msg.message); + free(e->event.msg.xhtml_message); + free(e->event.msg.recipients); + free(e->event.msg.formats); + return 0; +} + +/** + * \internal Odbiera pakiet od serwera. * - * 0, -1. + * Analizuje pakiet i wype�nia struktur� zdarzenia. + * + * \param sess Struktura sesji + * \param e Struktura zdarzenia + * + * \return 0 je�li si� powiod�o, -1 je�li wyst�pi� b��d */ static int gg_watch_fd_connected(struct gg_session *sess, struct gg_event *e) { struct gg_header *h = NULL; char *p; - gg_debug(GG_DEBUG_FUNCTION, "** gg_watch_fd_connected(%p, %p);\n", sess, e); + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_watch_fd_connected(%p, %p);\n", sess, e); if (!sess) { errno = EFAULT; @@ -462,76 +713,86 @@ } if (!(h = gg_recv_packet(sess))) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() gg_recv_packet failed (errno=%d, %s)\n", errno, strerror(errno)); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() gg_recv_packet failed (errno=%d, %s)\n", errno, strerror(errno)); goto fail; } p = (char*) h + sizeof(struct gg_header); - + switch (h->type) { case GG_RECV_MSG: { if (h->length >= sizeof(struct gg_recv_msg)) if (gg_handle_recv_msg(h, e, sess)) goto fail; - + break; } + case GG_RECV_MSG80: + { + if (h->length >= sizeof(struct gg_recv_msg80)) + if (gg_handle_recv_msg80(h, e, sess)) + goto fail; + + break; + } + + case GG_NOTIFY_REPLY: { struct gg_notify_reply *n = (void*) p; unsigned int count, i; char *tmp; - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n"); if (h->length < sizeof(*n)) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() incomplete packet\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() incomplete packet\n"); errno = EINVAL; goto fail; } if (gg_fix32(n->status) == GG_STATUS_BUSY_DESCR || gg_fix32(n->status) == GG_STATUS_NOT_AVAIL_DESCR || gg_fix32(n->status) == GG_STATUS_AVAIL_DESCR) { e->type = GG_EVENT_NOTIFY_DESCR; - + if (!(e->event.notify_descr.notify = (void*) malloc(sizeof(*n) * 2))) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); goto fail; } e->event.notify_descr.notify[1].uin = 0; memcpy(e->event.notify_descr.notify, p, sizeof(*n)); e->event.notify_descr.notify[0].uin = gg_fix32(e->event.notify_descr.notify[0].uin); e->event.notify_descr.notify[0].status = gg_fix32(e->event.notify_descr.notify[0].status); - e->event.notify_descr.notify[0].remote_ip = e->event.notify_descr.notify[0].remote_ip; e->event.notify_descr.notify[0].remote_port = gg_fix16(e->event.notify_descr.notify[0].remote_port); + e->event.notify_descr.notify[0].version = gg_fix32(e->event.notify_descr.notify[0].version); count = h->length - sizeof(*n); if (!(tmp = malloc(count + 1))) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); goto fail; } memcpy(tmp, p + sizeof(*n), count); tmp[count] = 0; e->event.notify_descr.descr = tmp; - + } else { e->type = GG_EVENT_NOTIFY; - + if (!(e->event.notify = (void*) malloc(h->length + 2 * sizeof(*n)))) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); goto fail; } - + memcpy(e->event.notify, p, h->length); count = h->length / sizeof(*n); e->event.notify[count].uin = 0; - + for (i = 0; i < count; i++) { e->event.notify[i].uin = gg_fix32(e->event.notify[i].uin); e->event.notify[i].status = gg_fix32(e->event.notify[i].status); - e->event.notify[i].remote_ip = e->event.notify[i].remote_ip; e->event.notify[i].remote_port = gg_fix16(e->event.notify[i].remote_port); + e->event.notify[i].version = gg_fix32(e->event.notify[i].version); } } @@ -542,7 +803,7 @@ { struct gg_status *s = (void*) p; - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n"); if (h->length >= sizeof(*s)) { e->type = GG_EVENT_STATUS; @@ -564,23 +825,176 @@ break; } - case GG_NOTIFY_REPLY60: + case GG_NOTIFY_REPLY77: + case GG_NOTIFY_REPLY80BETA: { - struct gg_notify_reply60 *n = (void*) p; + struct gg_notify_reply77 *n = (void*) p; unsigned int length = h->length, i = 0; - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n"); e->type = GG_EVENT_NOTIFY60; e->event.notify60 = malloc(sizeof(*e->event.notify60)); if (!e->event.notify60) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); goto fail; } e->event.notify60[0].uin = 0; - + + while (length >= sizeof(struct gg_notify_reply77)) { + uin_t uin = gg_fix32(n->uin); + char *tmp; + + e->event.notify60[i].uin = uin & 0x00ffffff; + e->event.notify60[i].status = n->status; + e->event.notify60[i].remote_ip = n->remote_ip; + e->event.notify60[i].remote_port = gg_fix16(n->remote_port); + e->event.notify60[i].version = n->version; + e->event.notify60[i].image_size = n->image_size; + e->event.notify60[i].descr = NULL; + e->event.notify60[i].time = 0; + + if (uin & 0x40000000) + e->event.notify60[i].version |= GG_HAS_AUDIO_MASK; + if (uin & 0x20000000) + e->event.notify60[i].version |= GG_HAS_AUDIO7_MASK; + if (uin & 0x08000000) + e->event.notify60[i].version |= GG_ERA_OMNIX_MASK; + + if (GG_S_D(n->status)) { + unsigned char descr_len = *((char*) n + sizeof(struct gg_notify_reply77)); + + if (sizeof(struct gg_notify_reply77) + descr_len <= length) { + char *descr; + + if (!(descr = malloc(descr_len + 1))) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); + goto fail; + } + + memcpy(descr, (char*) n + sizeof(struct gg_notify_reply77) + 1, descr_len); + descr[descr_len] = 0; + + if (h->type == GG_NOTIFY_REPLY80BETA && sess->encoding != GG_ENCODING_UTF8) { + char *cp_descr = gg_utf8_to_cp(descr); + + if (!cp_descr) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); + free(descr); + goto fail; + } + + free(descr); + descr = cp_descr; + } + + e->event.notify60[i].descr = descr; + + /* XXX czas */ + + length -= sizeof(struct gg_notify_reply77) + descr_len + 1; + n = (void*) ((char*) n + sizeof(struct gg_notify_reply77) + descr_len + 1); + } else { + length = 0; + } + + } else { + length -= sizeof(struct gg_notify_reply77); + n = (void*) ((char*) n + sizeof(struct gg_notify_reply77)); + } + + if (!(tmp = realloc(e->event.notify60, (i + 2) * sizeof(*e->event.notify60)))) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); + free(e->event.notify60); + goto fail; + } + + e->event.notify60 = (void*) tmp; + e->event.notify60[++i].uin = 0; + } + + break; + } + + case GG_STATUS77: + case GG_STATUS80BETA: + { + struct gg_status77 *s = (void*) p; + uint32_t uin; + + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n"); + + if (h->length < sizeof(*s)) + break; + + uin = gg_fix32(s->uin); + + e->type = GG_EVENT_STATUS60; + e->event.status60.uin = uin & 0x00ffffff; + e->event.status60.status = s->status; + e->event.status60.remote_ip = s->remote_ip; + e->event.status60.remote_port = gg_fix16(s->remote_port); + e->event.status60.version = s->version; + e->event.status60.image_size = s->image_size; + e->event.status60.descr = NULL; + e->event.status60.time = 0; + + if (uin & 0x40000000) + e->event.status60.version |= GG_HAS_AUDIO_MASK; + if (uin & 0x20000000) + e->event.status60.version |= GG_HAS_AUDIO7_MASK; + if (uin & 0x08000000) + e->event.status60.version |= GG_ERA_OMNIX_MASK; + + if (h->length > sizeof(*s)) { + int len = h->length - sizeof(*s); + char *buf = malloc(len + 1); + + /* XXX, jesli malloc() sie nie uda to robic tak samo jak przy GG_NOTIFY_REPLY* ? + * - goto fail; (?) + */ + if (buf) { + memcpy(buf, (char*) p + sizeof(*s), len); + buf[len] = 0; + + if (h->type == GG_STATUS80BETA && sess->encoding != GG_ENCODING_UTF8) { + char *cp_buf = gg_utf8_to_cp(buf); + free(buf); + buf = cp_buf; + } + } + + e->event.status60.descr = buf; + + if (len > 4 && p[h->length - 5] == 0) { + uint32_t t; + memcpy(&t, p + h->length - 4, sizeof(uint32_t)); + e->event.status60.time = gg_fix32(t); + } + } + + break; + } + + case GG_NOTIFY_REPLY60: + { + struct gg_notify_reply60 *n = (void*) p; + unsigned int length = h->length, i = 0; + + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n"); + + e->type = GG_EVENT_NOTIFY60; + e->event.notify60 = malloc(sizeof(*e->event.notify60)); + + if (!e->event.notify60) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); + goto fail; + } + + e->event.notify60[0].uin = 0; + while (length >= sizeof(struct gg_notify_reply60)) { uin_t uin = gg_fix32(n->uin); char *tmp; @@ -602,9 +1016,9 @@ if (GG_S_D(n->status)) { unsigned char descr_len = *((char*) n + sizeof(struct gg_notify_reply60)); - if (descr_len < length) { + if (sizeof(struct gg_notify_reply60) + descr_len <= length) { if (!(e->event.notify60[i].descr = malloc(descr_len + 1))) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); goto fail; } @@ -612,17 +1026,20 @@ e->event.notify60[i].descr[descr_len] = 0; /* XXX czas */ + + length -= sizeof(struct gg_notify_reply60) + descr_len + 1; + n = (void*) ((char*) n + sizeof(struct gg_notify_reply60) + descr_len + 1); + } else { + length = 0; } - - length -= sizeof(struct gg_notify_reply60) + descr_len + 1; - n = (void*) ((char*) n + sizeof(struct gg_notify_reply60) + descr_len + 1); + } else { length -= sizeof(struct gg_notify_reply60); n = (void*) ((char*) n + sizeof(struct gg_notify_reply60)); } if (!(tmp = realloc(e->event.notify60, (i + 2) * sizeof(*e->event.notify60)))) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); free(e->event.notify60); goto fail; } @@ -633,13 +1050,13 @@ break; } - + case GG_STATUS60: { struct gg_status60 *s = (void*) p; uint32_t uin; - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n"); if (h->length < sizeof(*s)) break; @@ -682,11 +1099,132 @@ break; } + case GG_STATUS80: + { + struct gg_notify_reply80 *s = (void*) p; + uint32_t descr_len; + + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a status change\n"); + + if (h->length < sizeof(*s)) + break; + + e->type = GG_EVENT_STATUS60; + e->event.status60.uin = gg_fix32(s->uin); + e->event.status60.status = gg_fix32(s->status); + e->event.status60.remote_ip = s->remote_ip; + e->event.status60.remote_port = gg_fix16(s->remote_port); + e->event.status60.image_size = s->image_size; + e->event.status60.descr = NULL; + e->event.status60.version = 0x00; /* not-supported */ + e->event.status60.time = 0; /* not-supported */ + + descr_len = gg_fix32(s->descr_len); + + if (descr_len > 0 && h->length-sizeof(*s) >= descr_len) { + char *buf = malloc(descr_len + 1); + + if (buf) { + memcpy(buf, (char*) p + sizeof(*s), descr_len); + buf[descr_len] = 0; + + if (sess->encoding != GG_ENCODING_UTF8) { + char *cp_buf = gg_utf8_to_cp(buf); + free(buf); + buf = cp_buf; + } + } + + e->event.status60.descr = buf; + } + break; + } + + case GG_NOTIFY_REPLY80: + { + struct gg_notify_reply80 *n = (void*) p; + unsigned int length = h->length, i = 0; + + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n"); + + e->type = GG_EVENT_NOTIFY60; + e->event.notify60 = malloc(sizeof(*e->event.notify60)); + + if (!e->event.notify60) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); + goto fail; + } + + e->event.notify60[0].uin = 0; + + while (length >= sizeof(struct gg_notify_reply80)) { + uint32_t descr_len; + char *tmp; + + e->event.notify60[i].uin = gg_fix32(n->uin); + e->event.notify60[i].status = gg_fix32(n->status); + e->event.notify60[i].remote_ip = n->remote_ip; + e->event.notify60[i].remote_port= gg_fix16(n->remote_port); + e->event.notify60[i].image_size = n->image_size; + e->event.notify60[i].descr = NULL; + e->event.notify60[i].version = 0x00; /* not-supported */ + e->event.notify60[i].time = 0; /* not-supported */ + + descr_len = gg_fix32(n->descr_len); + + length -= sizeof(struct gg_notify_reply80); + n = (void*) ((char*) n + sizeof(struct gg_notify_reply80)); + + if (descr_len) { + if (length >= descr_len) { + /* XXX, GG_S_D(n->status) */ + char *descr; + + if (!(descr = malloc(descr_len + 1))) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); + goto fail; + } + + memcpy(descr, n, descr_len); + descr[descr_len] = 0; + + if (sess->encoding != GG_ENCODING_UTF8) { + char *cp_descr = gg_utf8_to_cp(descr); + + if (!cp_descr) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); + free(descr); + goto fail; + } + + free(descr); + descr = cp_descr; + } + e->event.notify60[i].descr = descr; + + length -= descr_len; + n = (void*) ((char*) n + descr_len); + } else + length = 0; + } + + if (!(tmp = realloc(e->event.notify60, (i + 2) * sizeof(*e->event.notify60)))) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); + free(e->event.notify60); + goto fail; + } + + e->event.notify60 = (void*) tmp; + e->event.notify60[++i].uin = 0; + } + break; + } + case GG_SEND_MSG_ACK: { struct gg_send_msg_ack *s = (void*) p; - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a message ack\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a message ack\n"); if (h->length < sizeof(*s)) break; @@ -699,9 +1237,9 @@ break; } - case GG_PONG: + case GG_PONG: { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a pong\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received a pong\n"); e->type = GG_EVENT_PONG; sess->last_pong = time(NULL); @@ -711,27 +1249,47 @@ case GG_DISCONNECTING: { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received disconnection warning\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received disconnection warning\n"); e->type = GG_EVENT_DISCONNECT; break; } + case GG_DISCONNECT_ACK: + { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received disconnection acknowledge\n"); + e->type = GG_EVENT_DISCONNECT_ACK; + break; + } + + case GG_XML_EVENT: + { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received XML event\n"); + e->type = GG_EVENT_XML_EVENT; + if (!(e->event.xml_event.data = (char *) malloc(h->length + 1))) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for XML event data\n"); + goto fail; + } + memcpy(e->event.xml_event.data, p, h->length); + e->event.xml_event.data[h->length] = 0; + break; + } + case GG_PUBDIR50_REPLY: { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received pubdir/search reply\n"); - if (gg_pubdir50_handle_reply(e, p, h->length) == -1) + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received pubdir/search reply\n"); + if (gg_pubdir50_handle_reply_sess(sess, e, p, h->length) == -1) goto fail; break; } case GG_USERLIST_REPLY: { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received userlist reply\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received userlist reply\n"); if (h->length < 1) break; - /* je�li odpowied� na eksport, wywo�aj zdarzenie tylko + /* je�li odpowied添 na eksport, wywo�aj zdarzenie tylko * gdy otrzymano wszystkie odpowiedzi */ if (p[0] == GG_USERLIST_PUT_REPLY || p[0] == GG_USERLIST_PUT_MORE_REPLY) { if (--sess->userlist_blocks) @@ -743,11 +1301,11 @@ if (h->length > 1) { char *tmp; unsigned int len = (sess->userlist_reply) ? strlen(sess->userlist_reply) : 0; - - gg_debug(GG_DEBUG_MISC, "userlist_reply=%p, len=%d\n", sess->userlist_reply, len); - + + gg_debug_session(sess, GG_DEBUG_MISC, "userlist_reply=%p, len=%d\n", sess->userlist_reply, len); + if (!(tmp = realloc(sess->userlist_reply, len + h->length))) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for userlist reply\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for userlist reply\n"); free(sess->userlist_reply); sess->userlist_reply = NULL; goto fail; @@ -769,10 +1327,75 @@ break; } + case GG_DCC7_ID_REPLY: + { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 id packet\n"); + + if (h->length < sizeof(struct gg_dcc7_id_reply)) + break; + + if (gg_dcc7_handle_id(sess, e, p, h->length) == -1) + goto fail; + + break; + } + + case GG_DCC7_ACCEPT: + { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 accept\n"); + + if (h->length < sizeof(struct gg_dcc7_accept)) + break; + + if (gg_dcc7_handle_accept(sess, e, p, h->length) == -1) + goto fail; + + break; + } + + case GG_DCC7_NEW: + { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 request\n"); + + if (h->length < sizeof(struct gg_dcc7_new)) + break; + + if (gg_dcc7_handle_new(sess, e, p, h->length) == -1) + goto fail; + + break; + } + + case GG_DCC7_REJECT: + { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 reject\n"); + + if (h->length < sizeof(struct gg_dcc7_reject)) + break; + + if (gg_dcc7_handle_reject(sess, e, p, h->length) == -1) + goto fail; + + break; + } + + case GG_DCC7_INFO: + { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received dcc7 info\n"); + + if (h->length < sizeof(struct gg_dcc7_info)) + break; + + if (gg_dcc7_handle_info(sess, e, p, h->length) == -1) + goto fail; + + break; + } + default: - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received unknown packet 0x%.2x\n", h->type); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd_connected() received unknown packet 0x%.2x\n", h->type); } - + free(h); return 0; @@ -781,19 +1404,20 @@ return -1; } -/* - * gg_watch_fd() - * - * funkcja, kt�r� nale�y wywo�a�, gdy co� si� stanie z obserwowanym - * deskryptorem. zwraca klientowi informacj� o tym, co si� dzieje. +/** \endcond */ + +/** + * Funkcja wywo�ywana po zaobserwowaniu zmian na deskryptorze sesji. * - * - sess - opis sesji + * Funkcja zwraca struktur� zdarzenia \c gg_event. Je�li rodzaj zdarzenia + * to \c GG_EVENT_NONE, nie wydarzy�o si� jeszcze nic wartego odnotowania. + * Struktur� zdarzenia nale甜y zwolni� funkcja \c gg_event_free(). * - * wska�nik do struktury gg_event, kt�r� trzeba zwolni� p鷦niej - * za pomoc� gg_event_free(). jesli rodzaj zdarzenia jest r�wny - * GG_EVENT_NONE, nale�y je zignorowa�. je�li zwr�ci�o NULL, - * sta�o si� co� niedobrego -- albo zabrak�o pami�ci albo zerwa�o - * po咳czenie. + * \param sess Struktura sesji + * + * \return Struktura zdarzenia lub \c NULL je�li wyst�pi� b��d + * + * \ingroup events */ struct gg_event *gg_watch_fd(struct gg_session *sess) { @@ -802,68 +1426,79 @@ int port = 0; int errno2 = 0; - gg_debug(GG_DEBUG_FUNCTION, "** gg_watch_fd(%p);\n", sess); - + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_watch_fd(%p);\n", sess); + if (!sess) { errno = EFAULT; return NULL; } if (!(e = (void*) calloc(1, sizeof(*e)))) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() not enough memory for event data\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() not enough memory for event data\n"); return NULL; } e->type = GG_EVENT_NONE; + if (sess->send_buf && (sess->state == GG_STATE_READING_REPLY || sess->state == GG_STATE_CONNECTED)) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() sending %d bytes of queued data\n", sess->send_left); + + res = write(sess->fd, sess->send_buf, sess->send_left); + + if (res == -1 && errno != EAGAIN) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() write() failed (errno=%d, %s)\n", errno, strerror(errno)); + + if (sess->state == GG_STATE_READING_REPLY) + goto fail_connecting; + else + goto done; + } + + if (res == sess->send_left) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() sent all queued data\n"); + free(sess->send_buf); + sess->send_buf = NULL; + sess->send_left = 0; + } else if (res > 0) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() sent %d bytes of queued data, %d bytes left\n", res, sess->send_left - res); + + memmove(sess->send_buf, sess->send_buf + res, sess->send_left - res); + sess->send_left -= res; + } + } + switch (sess->state) { case GG_STATE_RESOLVING: { struct in_addr addr; int failed = 0; - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_RESOLVING\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_RESOLVING\n"); if (read(sess->fd, &addr, sizeof(addr)) < (signed)sizeof(addr) || addr.s_addr == INADDR_NONE) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() resolving failed\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() resolving failed\n"); failed = 1; errno2 = errno; } - + close(sess->fd); sess->fd = -1; -#ifdef __GG_LIBGADU_HAVE_PTHREAD - if (sess->resolver) { - pthread_cancel(*((pthread_t*) sess->resolver)); - free(sess->resolver); - sess->resolver = NULL; - } -#elif defined _WIN32 - if (sess->resolver) { - HANDLE h = sess->resolver; - TerminateThread(h, 0); - CloseHandle(h); - sess->resolver = NULL; - } -#else - waitpid(sess->pid, NULL, 0); - sess->pid = -1; -#endif + sess->resolver_cleanup(&sess->resolver, 0); if (failed) { errno = errno2; goto fail_resolving; } - /* je�li jeste�my w resolverze i mamy ustawiony port - * proxy, znaczy, �e resolvowali�my proxy. zatem + /* je�li jeste�my w resolverze i mamy ustawiony port + * proxy, znaczy, 甜e resolvowali�my proxy. zatem * wpiszmy jego adres. */ if (sess->proxy_port) sess->proxy_addr = addr.s_addr; /* zapiszmy sobie adres huba i adres serwera (do - * bezpo�redniego po咳czenia, je�li hub le�y) + * bezpo�redniego po��czenia, je�li hub le甜y) * z resolvera. */ if (sess->proxy_addr && sess->proxy_port) port = sess->proxy_port; @@ -872,21 +1507,27 @@ port = GG_APPMSG_PORT; } - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() resolved, connecting to %s:%d\n", inet_ntoa(addr), port); - - /* 咳czymy si� albo z hubem, albo z proxy, zale�nie - * od tego, co resolvowali�my. */ + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() resolved, connecting to %s:%d\n", inet_ntoa(addr), port); + + /* ��czymy si� albo z hubem, albo z proxy, zale甜nie + * od tego, co resolvowali�my. */ if ((sess->fd = gg_connect(&addr, port, sess->async)) == -1) { - /* je�li w trybie asynchronicznym gg_connect() - * zwr�ci b咳d, nie ma sensu pr�bowa� dalej. */ - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), critical\n", errno, strerror(errno)); + /* je�li w trybie asynchronicznym gg_connect() + * zwr坦ci b��d, nie ma sensu pr坦bowa� dalej. */ + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), critical\n", errno, strerror(errno)); goto fail_connecting; } - /* je�li podano serwer i 咳czmy si� przez proxy, - * jest to bezpo�rednie po咳czenie, inaczej jest + /* je�li podano serwer i ��czmy si� przez proxy, + * jest to bezpo�rednie po��czenie, inaczej jest * do huba. */ - sess->state = (sess->proxy_addr && sess->proxy_port && sess->server_addr) ? GG_STATE_CONNECTING_GG : GG_STATE_CONNECTING_HUB; + + if (sess->proxy_addr && sess->proxy_port && sess->server_addr) { + sess->state = GG_STATE_CONNECTING_GG; + sess->soft_timeout = 1; + } else + sess->state = GG_STATE_CONNECTING_HUB; + sess->check = GG_CHECK_WRITE; sess->timeout = GG_DEFAULT_TIMEOUT; @@ -898,42 +1539,25 @@ char buf[1024], *client, *auth; int res = 0; socklen_t res_size = sizeof(res); - const char *host, *appmsg; - - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTING_HUB\n"); - - /* je�li asynchroniczne, sprawdzamy, czy nie wyst�pi� - * przypadkiem jaki� b咳d. */ + const char *host; + + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTING_HUB\n"); + + /* je�li asynchroniczne, sprawdzamy, czy nie wyst�pi� + * przypadkiem jaki� b��d. */ if (sess->async && (getsockopt(sess->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) { - /* no tak, nie uda�o si� po咳czy� z proxy. nawet - * nie pr�bujemy dalej. */ - if (sess->proxy_addr && sess->proxy_port) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", res, strerror(res)); - goto fail_connecting; - } - - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to hub failed (errno=%d, %s), trying direct connection\n", res, strerror(res)); - close(sess->fd); - - if ((sess->fd = gg_connect(&sess->hub_addr, GG_DEFAULT_PORT, sess->async)) == -1) { - /* przy asynchronicznych, gg_connect() - * zwraca -1 przy b滑dach socket(), - * ioctl(), braku routingu itd. dlatego - * nawet nie pr�bujemy dalej. */ - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() direct connection failed (errno=%d, %s), critical\n", errno, strerror(errno)); - goto fail_connecting; - } - - sess->state = GG_STATE_CONNECTING_GG; - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - break; + if (sess->proxy_addr && sess->proxy_port) + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", res, strerror(res)); + else + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to hub failed (errno=%d, %s)\n", res, strerror(res)); + + goto fail_connecting; } - - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connected to hub, sending query\n"); + + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connected to hub, sending query\n"); if (!(client = gg_urlencode((sess->client_version) ? sess->client_version : GG_DEFAULT_CLIENT_VERSION))) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() out of memory for client version\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of memory for client version\n"); goto fail_connecting; } @@ -942,41 +1566,43 @@ else host = ""; -#ifdef __GG_LIBGADU_HAVE_OPENSSL - if (sess->ssl) - appmsg = "appmsg3.asp"; - else + auth = gg_proxy_auth(); + +#ifdef GG_CONFIG_HAVE_OPENSSL + if (sess->ssl) { + snprintf(buf, sizeof(buf) - 1, + "GET %s/appsvc/appmsg3.asp?fmnumber=%u&version=%s&lastmsg=%d HTTP/1.0\r\n" + "Host: " GG_APPMSG_HOST "\r\n" + "User-Agent: " GG_HTTP_USERAGENT "\r\n" + "Pragma: no-cache\r\n" + "%s" + "\r\n", host, sess->uin, client, sess->last_sysmsg, (auth) ? auth : ""); + } else #endif - appmsg = "appmsg2.asp"; - - auth = gg_proxy_auth(); - - snprintf(buf, sizeof(buf) - 1, - "GET %s/appsvc/%s?fmnumber=%u&version=%s&lastmsg=%d HTTP/1.0\r\n" - "Host: " GG_APPMSG_HOST "\r\n" - "User-Agent: " GG_HTTP_USERAGENT "\r\n" - "Pragma: no-cache\r\n" - "%s" - "\r\n", host, appmsg, sess->uin, client, sess->last_sysmsg, (auth) ? auth : ""); - - if (auth) - free(auth); - + { + snprintf(buf, sizeof(buf) - 1, + "GET %s/appsvc/appmsg_ver8.asp?fmnumber=%u&fmt=2&lastmsg=%d&version=%s HTTP/1.0\r\n" + "Host: " GG_APPMSG_HOST "\r\n" + "%s" + "\r\n", host, sess->uin, sess->last_sysmsg, client, (auth) ? auth : ""); + } + + free(auth); free(client); - /* zwolnij pami裝 po wersji klienta. */ + /* zwolnij pami�� po wersji klienta. */ if (sess->client_version) { free(sess->client_version); sess->client_version = NULL; } - gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", buf); - - /* zapytanie jest kr�tkie, wi�c zawsze zmie�ci si� - * do bufora gniazda. je�li write() zwr�ci mniej, - * sta�o si� co� z�ego. */ + gg_debug_session(sess, GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", buf); + + /* zapytanie jest kr坦tkie, wi�c zawsze zmie�ci si� + * do bufora gniazda. je�li write() zwr坦ci mniej, + * sta�o si� co� z�ego. */ if (write(sess->fd, buf, strlen(buf)) < (signed)strlen(buf)) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() sending query failed\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() sending query failed\n"); e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_WRITING; @@ -999,72 +1625,36 @@ int port = GG_DEFAULT_PORT; struct in_addr addr; - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_DATA\n"); - - /* czytamy lini� z gniazda i obcinamy \r\n. */ + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_DATA\n"); + + /* czytamy lini� z gniazda i obcinamy \r\n. */ gg_read_line(sess->fd, buf, sizeof(buf) - 1); gg_chomp(buf); - gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() received http header (%s)\n", buf); - - /* sprawdzamy, czy wszystko w porz�dku. */ + gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// gg_watch_fd() received http header (%s)\n", buf); + + /* sprawdzamy, czy wszystko w porz�dku. */ if (strncmp(buf, "HTTP/1.", 7) || strncmp(buf + 9, "200", 3)) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() that's not what we've expected, trying direct connection\n"); - - close(sess->fd); - - /* je�li otrzymali�my jakie� dziwne informacje, - * pr�bujemy si� 咳czy� z pomini�ciem huba. */ - if (sess->proxy_addr && sess->proxy_port) { - if ((sess->fd = gg_connect(&sess->proxy_addr, sess->proxy_port, sess->async)) == -1) { - /* trudno. nie wysz�o. */ - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", errno, strerror(errno)); - goto fail_connecting; - } - - sess->state = GG_STATE_CONNECTING_GG; - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - break; - } - - sess->port = GG_DEFAULT_PORT; - - /* 咳czymy si� na port 8074 huba. */ - if ((sess->fd = gg_connect(&sess->hub_addr, sess->port, sess->async)) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), trying https\n", errno, strerror(errno)); - - sess->port = GG_HTTPS_PORT; - - /* 咳czymy si� na port 443. */ - if ((sess->fd = gg_connect(&sess->hub_addr, sess->port, sess->async)) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno)); - goto fail_connecting; - } - } - - sess->state = GG_STATE_CONNECTING_GG; - sess->check = GG_CHECK_WRITE; - sess->timeout = GG_DEFAULT_TIMEOUT; - break; + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() invalid http reply, connection failed\n"); + goto fail_connecting; } - - /* ignorujemy reszt� nag鞄wka. */ + + /* ignorujemy reszt� nag�坦wka. */ while (strcmp(buf, "\r\n") && strcmp(buf, "")) gg_read_line(sess->fd, buf, sizeof(buf) - 1); - /* czytamy pierwsz� lini� danych. */ + /* czytamy pierwsz� lini� danych. */ gg_read_line(sess->fd, buf, sizeof(buf) - 1); gg_chomp(buf); - - /* je�li pierwsza liczba w linii nie jest r�wna zeru, - * oznacza to, �e mamy wiadomo倶 systemow�. */ + + /* je�li pierwsza liczba w linii nie jest r坦wna zeru, + * oznacza to, 甜e mamy wiadomo�� systemow�. */ if (atoi(buf)) { char tmp[1024], *foo, *sysmsg_buf = NULL; int len = 0; - + while (gg_read_line(sess->fd, tmp, sizeof(tmp) - 1)) { if (!(foo = realloc(sysmsg_buf, len + strlen(tmp) + 2))) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() out of memory for system message, ignoring\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() out of memory for system message, ignoring\n"); break; } @@ -1074,23 +1664,32 @@ strcpy(sysmsg_buf, tmp); else strcat(sysmsg_buf, tmp); - + len += strlen(tmp); } - + e->type = GG_EVENT_MSG; e->event.msg.msgclass = atoi(buf); e->event.msg.sender = 0; - e->event.msg.message = (unsigned char *)sysmsg_buf; + e->event.msg.message = (unsigned char*) sysmsg_buf; } - + close(sess->fd); - - gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() received http data (%s)\n", buf); + + gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// gg_watch_fd() received http data (%s)\n", buf); /* analizujemy otrzymane dane. */ tmp = buf; - + +#ifdef GG_CONFIG_HAVE_OPENSSL + if (!sess->ssl) +#endif + { + while (*tmp && *tmp != ' ') + tmp++; + while (*tmp && *tmp == ' ') + tmp++; + } while (*tmp && *tmp != ' ') tmp++; while (*tmp && *tmp == ' ') @@ -1105,36 +1704,43 @@ port = atoi(tmp + 1); } + if (!strcmp(host, "notoperating")) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() service unavailable\n", errno, strerror(errno)); + sess->fd = -1; + goto fail_unavailable; + } + addr.s_addr = inet_addr(host); sess->server_addr = addr.s_addr; if (!gg_proxy_http_only && sess->proxy_addr && sess->proxy_port) { - /* je�li mamy proxy, 咳czymy si� z nim. */ + /* je�li mamy proxy, ��czymy si� z nim. */ if ((sess->fd = gg_connect(&sess->proxy_addr, sess->proxy_port, sess->async)) == -1) { - /* nie wysz�o? trudno. */ - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", errno, strerror(errno)); + /* nie wysz�o? trudno. */ + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", errno, strerror(errno)); goto fail_connecting; } - + sess->state = GG_STATE_CONNECTING_GG; sess->check = GG_CHECK_WRITE; sess->timeout = GG_DEFAULT_TIMEOUT; + sess->soft_timeout = 1; break; } sess->port = port; - /* 咳czymy si� z w�a�ciwym serwerem. */ + /* ��czymy si� z w�a�ciwym serwerem. */ if ((sess->fd = gg_connect(&addr, sess->port, sess->async)) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), trying https\n", errno, strerror(errno)); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), trying https\n", errno, strerror(errno)); sess->port = GG_HTTPS_PORT; - /* nie wysz�o? pr�bujemy portu 443. */ + /* nie wysz�o? pr坦bujemy portu 443. */ if ((sess->fd = gg_connect(&addr, GG_HTTPS_PORT, sess->async)) == -1) { - /* ostatnia deska ratunku zawiod�a? + /* ostatnia deska ratunku zawiod�a? * w takim razie zwijamy manatki. */ - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno)); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno)); goto fail_connecting; } } @@ -1142,7 +1748,8 @@ sess->state = GG_STATE_CONNECTING_GG; sess->check = GG_CHECK_WRITE; sess->timeout = GG_DEFAULT_TIMEOUT; - + sess->soft_timeout = 1; + break; } @@ -1151,14 +1758,16 @@ int res = 0; socklen_t res_size = sizeof(res); - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTING_GG\n"); - - /* je�li wyst�pi� b咳d podczas 咳czenia si�... */ + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTING_GG\n"); + + sess->soft_timeout = 0; + + /* je�li wyst�pi� b��d podczas ��czenia si�... */ if (sess->async && (sess->timeout == 0 || getsockopt(sess->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) { - /* je�li nie uda�o si� po咳czenie z proxy, - * nie mamy czego pr�bowa� wi�cej. */ + /* je�li nie uda�o si� po��czenie z proxy, + * nie mamy czego pr坦bowa� wi�cej. */ if (sess->proxy_addr && sess->proxy_port) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", res, strerror(res)); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", res, strerror(res)); goto fail_connecting; } @@ -1170,36 +1779,46 @@ errno = ETIMEDOUT; #endif -#ifdef __GG_LIBGADU_HAVE_OPENSSL - /* je�li logujemy si� po TLS, nie pr�bujemy - * si� 咳czy� ju� z niczym innym w przypadku - * b滑du. nie do倶, �e nie ma sensu, to i - * trzeba by si� bawi� w tworzenie na nowo +#ifdef GG_CONFIG_HAVE_OPENSSL + /* je�li logujemy si� po TLS, nie pr坦bujemy + * si� ��czy� ju甜 z niczym innym w przypadku + * b��du. nie do��, 甜e nie ma sensu, to i + * trzeba by si� bawi� w tworzenie na nowo * SSL i SSL_CTX. */ if (sess->ssl) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", res, strerror(res)); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", res, strerror(res)); goto fail_connecting; } #endif - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), trying https\n", res, strerror(res)); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), trying https\n", res, strerror(res)); + + if (sess->port == GG_HTTPS_PORT) + goto fail_connecting; sess->port = GG_HTTPS_PORT; - /* pr�bujemy na port 443. */ + /* pr坦bujemy na port 443. */ if ((sess->fd = gg_connect(&sess->server_addr, sess->port, sess->async)) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno)); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno)); goto fail_connecting; } + + sess->state = GG_STATE_CONNECTING_GG; + sess->check = GG_CHECK_WRITE; + sess->timeout = GG_DEFAULT_TIMEOUT; + sess->soft_timeout = 1; + + break; } - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connected\n"); - + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() connected\n"); + if (gg_proxy_http_only) sess->proxy_port = 0; - /* je�li mamy proxy, wy�lijmy zapytanie. */ + /* je�li mamy proxy, wy�lijmy zapytanie. */ if (sess->proxy_addr && sess->proxy_port) { char buf[100], *auth = gg_proxy_auth(); struct in_addr addr; @@ -1211,20 +1830,22 @@ snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.0\r\n", inet_ntoa(addr), sess->port); - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() proxy request:\n// %s", buf); - - /* wysy�amy zapytanie. jest ono na tyle kr�tkie, - * �e musi si� zmie�ci� w buforze gniazda. je�li - * write() zawiedzie, sta�o si� co� z�ego. */ + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() proxy request:\n// %s", buf); + + /* wysy�amy zapytanie. jest ono na tyle kr坦tkie, + * 甜e musi si� zmie�ci� w buforze gniazda. je�li + * write() zawiedzie, sta�o si� co� z�ego. */ if (write(sess->fd, buf, strlen(buf)) < (signed)strlen(buf)) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n"); + free(auth); goto fail_connecting; } if (auth) { - gg_debug(GG_DEBUG_MISC, "// %s", auth); + gg_debug_session(sess, GG_DEBUG_MISC, "// %s", auth); if (write(sess->fd, auth, strlen(auth)) < (signed)strlen(auth)) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n"); + free(auth); goto fail_connecting; } @@ -1232,12 +1853,12 @@ } if (write(sess->fd, "\r\n", 2) < 2) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() can't send proxy request\n"); goto fail_connecting; } } -#ifdef __GG_LIBGADU_HAVE_OPENSSL +#ifdef GG_CONFIG_HAVE_OPENSSL if (sess->ssl) { SSL_set_fd(sess->ssl, sess->fd); @@ -1256,19 +1877,19 @@ break; } -#ifdef __GG_LIBGADU_HAVE_OPENSSL +#ifdef GG_CONFIG_HAVE_OPENSSL case GG_STATE_TLS_NEGOTIATION: { int res; X509 *peer; - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_TLS_NEGOTIATION\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_TLS_NEGOTIATION\n"); if ((res = SSL_connect(sess->ssl)) <= 0) { int err = SSL_get_error(sess->ssl, res); if (res == 0) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() disconnected during TLS negotiation\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() disconnected during TLS negotiation\n"); e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_TLS; @@ -1277,9 +1898,9 @@ sess->fd = -1; break; } - + if (err == SSL_ERROR_WANT_READ) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() wants to read\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() wants to read\n"); sess->state = GG_STATE_TLS_NEGOTIATION; sess->check = GG_CHECK_READ; @@ -1287,7 +1908,7 @@ break; } else if (err == SSL_ERROR_WANT_WRITE) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() wants to write\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() wants to write\n"); sess->state = GG_STATE_TLS_NEGOTIATION; sess->check = GG_CHECK_WRITE; @@ -1299,8 +1920,8 @@ ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() bailed out: %s\n", buf); - + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() bailed out: %s\n", buf); + e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_TLS; sess->state = GG_STATE_IDLE; @@ -1310,20 +1931,20 @@ } } - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() TLS negotiation succeded:\n// cipher: %s\n", SSL_get_cipher_name(sess->ssl)); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() TLS negotiation succeded:\n// cipher: %s\n", SSL_get_cipher_name(sess->ssl)); peer = SSL_get_peer_certificate(sess->ssl); if (!peer) - gg_debug(GG_DEBUG_MISC, "// WARNING! unable to get peer certificate!\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// WARNING! unable to get peer certificate!\n"); else { char buf[1024]; X509_NAME_oneline(X509_get_subject_name(peer), buf, sizeof(buf)); - gg_debug(GG_DEBUG_MISC, "// cert subject: %s\n", buf); + gg_debug_session(sess, GG_DEBUG_MISC, "// cert subject: %s\n", buf); X509_NAME_oneline(X509_get_issuer_name(peer), buf, sizeof(buf)); - gg_debug(GG_DEBUG_MISC, "// cert issuer: %s\n", buf); + gg_debug_session(sess, GG_DEBUG_MISC, "// cert issuer: %s\n", buf); } sess->state = GG_STATE_READING_KEY; @@ -1336,45 +1957,48 @@ case GG_STATE_READING_KEY: { - struct gg_header *h; + struct gg_header *h; struct gg_welcome *w; - struct gg_login60 l; - unsigned int hash; - char *password = sess->password; + unsigned char *password = (unsigned char*) sess->password; int ret; - - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_KEY\n"); - - memset(&l, 0, sizeof(l)); - l.dunno2 = 0xbe; - - /* XXX bardzo, bardzo, bardzo g�upi pomys� na pozbycie - * si� tekstu wrzucanego przez proxy. */ + uint8_t login_hash[64]; + + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_KEY\n"); + + memset(login_hash, 0, sizeof(login_hash)); + + /* XXX bardzo, bardzo, bardzo g�upi pomys� na pozbycie + * si� tekstu wrzucanego przez proxy. */ if (sess->proxy_addr && sess->proxy_port) { char buf[100]; strcpy(buf, ""); gg_read_line(sess->fd, buf, sizeof(buf) - 1); gg_chomp(buf); - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() proxy response:\n// %s\n", buf); - + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() proxy response:\n// %s\n", buf); + while (strcmp(buf, "")) { gg_read_line(sess->fd, buf, sizeof(buf) - 1); gg_chomp(buf); if (strcmp(buf, "")) - gg_debug(GG_DEBUG_MISC, "// %s\n", buf); + gg_debug_session(sess, GG_DEBUG_MISC, "// %s\n", buf); } /* XXX niech czeka jeszcze raz w tej samej - * fazie. g�upio, ale dzia�a. */ + * fazie. g�upio, ale dzia�a. */ sess->proxy_port = 0; - + break; } /* czytaj pierwszy pakiet. */ if (!(h = gg_recv_packet(sess))) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() didn't receive packet (errno=%d, %s)\n", errno, strerror(errno)); + if (errno == EAGAIN) { + sess->check = GG_CHECK_READ; + break; + } + + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() didn't receive packet (errno=%d, %s)\n", errno, strerror(errno)); e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_READING; @@ -1387,7 +2011,7 @@ } if (h->type != GG_WELCOME) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() invalid packet received\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() invalid packet received\n"); free(h); close(sess->fd); sess->fd = -1; @@ -1397,61 +2021,127 @@ sess->state = GG_STATE_IDLE; break; } - + w = (struct gg_welcome*) ((char*) h + sizeof(struct gg_header)); w->key = gg_fix32(w->key); - hash = gg_login_hash((unsigned char *)password, w->key); - - gg_debug(GG_DEBUG_DUMP, "// gg_watch_fd() challenge %.4x --> hash %.8x\n", w->key, hash); - + switch (sess->hash_type) { + case GG_LOGIN_HASH_GG32: + { + unsigned int hash; + + hash = gg_fix32(gg_login_hash(password, w->key)); + gg_debug_session(sess, GG_DEBUG_DUMP, "// gg_watch_fd() challenge %.4x --> GG32 hash %.8x\n", w->key, hash); + memcpy(login_hash, &hash, sizeof(hash)); + + break; + } + + case GG_LOGIN_HASH_SHA1: + { + char tmp[41]; + int i; + + gg_login_hash_sha1((char*) password, w->key, login_hash); + for (i = 0; i < 40; i += 2) + snprintf(tmp + i, sizeof(tmp) - i, "%02x", login_hash[i / 2]); + + gg_debug_session(sess, GG_DEBUG_DUMP, "// gg_watch_fd() challenge %.4x --> SHA1 hash: %s\n", w->key, tmp); + + break; + } + } + free(h); - free(sess->password); sess->password = NULL; - { - struct in_addr dcc_ip; - dcc_ip.s_addr = gg_dcc_ip; - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() gg_dcc_ip = %s\n", inet_ntoa(dcc_ip)); - } - if (gg_dcc_ip == (unsigned long) inet_addr("255.255.255.255")) { struct sockaddr_in sin; socklen_t sin_len = sizeof(sin); - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() detecting address\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() detecting address\n"); if (!getsockname(sess->fd, (struct sockaddr*) &sin, &sin_len)) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() detected address to %s\n", inet_ntoa(sin.sin_addr)); - l.local_ip = sin.sin_addr.s_addr; + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() detected address to %s\n", inet_ntoa(sin.sin_addr)); + sess->client_addr = sin.sin_addr.s_addr; } else { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() unable to detect address\n"); - l.local_ip = 0; + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() unable to detect address\n"); + sess->client_addr = 0; } - } else - l.local_ip = gg_dcc_ip; - - l.uin = gg_fix32(sess->uin); - l.hash = gg_fix32(hash); - l.status = gg_fix32(sess->initial_status ? sess->initial_status : GG_STATUS_AVAIL); - l.version = gg_fix32(sess->protocol_version); - l.local_port = gg_fix16(gg_dcc_port); - l.image_size = sess->image_size; - - if (sess->external_addr && sess->external_port > 1023) { - l.external_ip = sess->external_addr; - l.external_port = gg_fix16(sess->external_port); + } else + sess->client_addr = gg_dcc_ip; + + if (sess->protocol_version >= 0x2e) { + struct gg_login80 l; + + uint32_t tmp_version_len = gg_fix32(strlen(GG8_VERSION)); + uint32_t tmp_descr_len = gg_fix32((sess->initial_descr) ? strlen(sess->initial_descr) : 0); + + memset(&l, 0, sizeof(l)); + l.uin = gg_fix32(sess->uin); + memcpy(l.language, GG8_LANG, sizeof(l.language)); + l.hash_type = sess->hash_type; + memcpy(l.hash, login_hash, sizeof(login_hash)); + l.status = gg_fix32(sess->initial_status ? sess->initial_status : GG_STATUS_AVAIL); + l.flags = gg_fix32(0x00800001); + l.features = gg_fix32(sess->protocol_features); + l.image_size = sess->image_size; + l.dunno2 = 0x64; + + gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// gg_watch_fd() sending GG_LOGIN80 packet\n"); + ret = gg_send_packet(sess, GG_LOGIN80, + &l, sizeof(l), + &tmp_version_len, sizeof(uint32_t), GG8_VERSION, strlen(GG8_VERSION), + &tmp_descr_len, sizeof(uint32_t), sess->initial_descr, (sess->initial_descr) ? strlen(sess->initial_descr) : 0, + NULL); + + } else if (sess->protocol_version == 0x2d) { + struct gg_login70 l; + + memset(&l, 0, sizeof(l)); + l.uin = gg_fix32(sess->uin); + l.local_ip = (sess->external_addr) ? sess->external_addr : sess->client_addr; + l.local_port = gg_fix16((sess->external_port > 1023) ? sess->external_port : gg_dcc_port); + l.hash_type = sess->hash_type; + memcpy(l.hash, login_hash, sizeof(login_hash)); + l.image_size = sess->image_size; + l.dunno2 = 0x64; + l.status = gg_fix32(sess->initial_status ? sess->initial_status : GG_STATUS_AVAIL); + l.version = gg_fix32(sess->protocol_version | sess->protocol_flags); + + gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// gg_watch_fd() sending GG_LOGIN80BETA packet\n"); + ret = gg_send_packet(sess, GG_LOGIN80BETA, + &l, sizeof(l), + sess->initial_descr, (sess->initial_descr) ? strlen(sess->initial_descr) : 0, + (sess->initial_descr) ? "\0" : NULL, (sess->initial_descr) ? 1 : 0, + NULL); + } else { + struct gg_login70 l; + + memset(&l, 0, sizeof(l)); + l.local_ip = (sess->external_addr) ? sess->external_addr : sess->client_addr; + l.uin = gg_fix32(sess->uin); + l.local_port = gg_fix16((sess->external_port > 1023) ? sess->external_port : gg_dcc_port); + l.hash_type = sess->hash_type; + memcpy(l.hash, login_hash, sizeof(login_hash)); + l.image_size = sess->image_size; + l.dunno2 = 0xbe; + l.status = gg_fix32(sess->initial_status ? sess->initial_status : GG_STATUS_AVAIL); + l.version = gg_fix32(sess->protocol_version | sess->protocol_flags); + + gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// gg_watch_fd() sending GG_LOGIN70 packet\n"); + ret = gg_send_packet(sess, GG_LOGIN70, + &l, sizeof(l), + sess->initial_descr, (sess->initial_descr) ? strlen(sess->initial_descr) : 0, + NULL); } - gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() sending GG_LOGIN60 packet\n"); - ret = gg_send_packet(sess, GG_LOGIN60, &l, sizeof(l), sess->initial_descr, (sess->initial_descr) ? strlen(sess->initial_descr) : 0, NULL); - free(sess->initial_descr); sess->initial_descr = NULL; if (ret == -1) { - gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() sending packet failed. (errno=%d, %s)\n", errno, strerror(errno)); + gg_debug_session(sess, GG_DEBUG_TRAFFIC, "// gg_watch_fd() sending packet failed. (errno=%d, %s)\n", errno, strerror(errno)); errno2 = errno; close(sess->fd); errno = errno2; @@ -1461,8 +2151,9 @@ sess->state = GG_STATE_IDLE; break; } - + sess->state = GG_STATE_READING_REPLY; + sess->check = GG_CHECK_READ; break; } @@ -1471,10 +2162,15 @@ { struct gg_header *h; - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_REPLY\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_REPLY\n"); if (!(h = gg_recv_packet(sess))) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() didn't receive packet (errno=%d, %s)\n", errno, strerror(errno)); + if (errno == EAGAIN) { + sess->check = GG_CHECK_READ; + break; + } + + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() didn't receive packet (errno=%d, %s)\n", errno, strerror(errno)); e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_READING; sess->state = GG_STATE_IDLE; @@ -1484,11 +2180,12 @@ sess->fd = -1; break; } - - if (h->type == GG_LOGIN_OK) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() login succeded\n"); + + if (h->type == GG_LOGIN_OK || h->type == GG_NEED_EMAIL || h->type == GG_LOGIN80_OK) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() login succeded\n"); e->type = GG_EVENT_CONN_SUCCESS; sess->state = GG_STATE_CONNECTED; + sess->check = GG_CHECK_READ; sess->timeout = -1; sess->status = (sess->initial_status) ? sess->initial_status : GG_STATUS_AVAIL; free(h); @@ -1496,15 +2193,15 @@ } if (h->type == GG_LOGIN_FAILED) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() login failed\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() login failed\n"); e->event.failure = GG_FAILURE_PASSWORD; errno = EACCES; - } else if (h->type == GG_NEED_EMAIL) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() email change needed\n"); - e->event.failure = GG_FAILURE_NEED_EMAIL; + } else if (h->type == GG_DISCONNECTING) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() too many incorrect password attempts\n"); + e->event.failure = GG_FAILURE_INTRUDER; errno = EACCES; } else { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() invalid packet\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() invalid packet\n"); e->event.failure = GG_FAILURE_INVALID; errno = EINVAL; } @@ -1522,13 +2219,13 @@ case GG_STATE_CONNECTED: { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTED\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTED\n"); sess->last_event = time(NULL); - + if ((res = gg_watch_fd_connected(sess, e)) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() watch_fd_connected failed (errno=%d, %s)\n", errno, strerror(errno)); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_watch_fd() watch_fd_connected failed (errno=%d, %s)\n", errno, strerror(errno)); if (errno == EAGAIN) { e->type = GG_EVENT_NONE; @@ -1536,6 +2233,9 @@ } else res = -1; } + + sess->check = GG_CHECK_READ; + break; } } @@ -1544,10 +2244,13 @@ if (res == -1) { free(e); e = NULL; + } else { + if (sess->send_buf && (sess->state == GG_STATE_READING_REPLY || sess->state == GG_STATE_CONNECTED)) + sess->check |= GG_CHECK_WRITE; } return e; - + fail_connecting: if (sess->fd != -1) { errno2 = errno; @@ -1565,6 +2268,12 @@ e->event.failure = GG_FAILURE_RESOLVING; sess->state = GG_STATE_IDLE; goto done; + +fail_unavailable: + e->type = GG_EVENT_CONN_FAILED; + e->event.failure = GG_FAILURE_UNAVAILABLE; + sess->state = GG_STATE_IDLE; + goto done; } /*
--- a/libpurple/protocols/gg/lib/http.c Sun Feb 28 23:42:12 2010 +0000 +++ b/libpurple/protocols/gg/lib/http.c Mon Mar 01 03:46:33 2010 +0000 @@ -1,4 +1,4 @@ -/* $Id: http.c 16856 2006-08-19 01:13:25Z evands $ */ +/* $Id: http.c 833 2009-10-01 20:48:01Z wojtekka $ */ /* * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl> @@ -14,52 +14,68 @@ * * 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. */ +/** + * \file http.c + * + * \brief Obs�uga po��cze� HTTP + */ + #include "libgadu.h" #include <sys/types.h> + #ifndef _WIN32 -#include <sys/wait.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> +# include <sys/socket.h> +# include <netinet/in.h> +# include <arpa/inet.h> #endif -#include "libgadu-config.h" +#include "compat.h" +#include "resolver.h" #include <ctype.h> #include <errno.h> + #ifndef _WIN32 -#include <netdb.h> +# include <netdb.h> #endif -#ifdef __GG_LIBGADU_HAVE_PTHREAD -# include <pthread.h> -#endif + +#include <signal.h> #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> -#include "compat.h" - -/* - * gg_http_connect() // funkcja pomocnicza +/** + * Rozpoczyna po��czenie HTTP. * - * rozpoczyna po咳czenie po http. + * Funkcja przeprowadza po��czenie HTTP przy po��czeniu synchronicznym, + * zwracaj�c wynik w polach struktury \c gg_http, lub b��d, gdy sesja si� + * nie powiedzie. + * + * Przy po��czeniu asynchronicznym, funkcja rozpoczyna po��czenie, a dalsze + * etapy b�d� przeprowadzane po wykryciu zmian (\c watch) na obserwowanym + * deskryptorze (\c fd) i wywo�aniu funkcji \c gg_http_watch_fd(). * - * - hostname - adres serwera - * - port - port serwera - * - async - asynchroniczne po咳czenie - * - method - metoda http (GET, POST, cokolwiek) - * - path - �cie�ka do zasobu (musi by� poprzedzona ,,/'') - * - header - nag鞄wek zapytania plus ewentualne dane dla POST + * Po zako�czeniu, nale甜y zwolni� struktur� za pomoc� funkcji + * \c gg_http_free(). Po��czenie asynchroniczne mo甜na zatrzyma� w ka甜dej + * chwili za pomoc� \c gg_http_stop(). * - * zaalokowana struct gg_http, kt�r� po�niej nale�y - * zwolni� funkcj� gg_http_free(), albo NULL je�li wyst�pi� b咳d. + * \param hostname Adres serwera + * \param port Port serwera + * \param async Flaga asynchronicznego po��czenia + * \param method Metoda HTTP + * \param path �cie甜ka do zasobu (musi by� poprzedzona znakiem '/') + * \param header Nag�坦wek zapytania plus ewentualne dane dla POST + * + * \return Zaalokowana struktura \c gg_http lub NULL, je�li wyst�pi� b��d. + * + * \ingroup http */ struct gg_http *gg_http_connect(const char *hostname, int port, int async, const char *method, const char *path, const char *header) { @@ -70,7 +86,7 @@ errno = EFAULT; return NULL; } - + if (!(h = malloc(sizeof(*h)))) return NULL; memset(h, 0, sizeof(*h)); @@ -80,6 +96,8 @@ h->fd = -1; h->type = GG_SESSION_HTTP; + gg_http_set_resolver(h, GG_RESOLVER_DEFAULT); + if (gg_proxy_enabled) { char *auth = gg_proxy_auth(); @@ -88,9 +106,8 @@ "", header); hostname = gg_proxy_host; h->port = port = gg_proxy_port; + free(auth); - if (auth) - free(auth); } else { h->query = gg_saprintf("%s %s HTTP/1.0\r\n%s", method, path, header); @@ -102,17 +119,11 @@ errno = ENOMEM; return NULL; } - + gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", h->query); if (async) { -#ifdef __GG_LIBGADU_HAVE_PTHREAD - if (gg_resolve_pthread(&h->fd, &h->resolver, hostname)) { -#elif defined _WIN32 - if (gg_resolve_win32thread(&h->fd, &h->resolver, hostname)) { -#else - if (gg_resolve(&h->fd, &h->pid, hostname)) { -#endif + if (h->resolver_start(&h->fd, &h->resolver, hostname) == -1) { gg_debug(GG_DEBUG_MISC, "// gg_http_connect() resolver failed\n"); gg_http_free(h); errno = ENOENT; @@ -125,19 +136,16 @@ h->check = GG_CHECK_READ; h->timeout = GG_DEFAULT_TIMEOUT; } else { - struct in_addr *hn, a; + struct in_addr addr; - if (!(hn = gg_gethostbyname(hostname))) { + if (gg_gethostbyname_real(hostname, &addr, 0) == -1) { gg_debug(GG_DEBUG_MISC, "// gg_http_connect() host not found\n"); gg_http_free(h); errno = ENOENT; return NULL; - } else { - a.s_addr = hn->s_addr; - free(hn); } - if (!(h->fd = gg_connect(&a, port, 0)) == -1) { + if ((h->fd = gg_connect(&addr, port, 0)) == -1) { gg_debug(GG_DEBUG_MISC, "// gg_http_connect() connection failed (errno=%d, %s)\n", errno, strerror(errno)); gg_http_free(h); return NULL; @@ -159,10 +167,12 @@ h->callback = gg_http_watch_fd; h->destroy = gg_http_free; - + return h; } +#ifndef DOXYGEN + #define gg_http_error(x) \ close(h->fd); \ h->fd = -1; \ @@ -170,17 +180,22 @@ h->error = x; \ return 0; -/* - * gg_http_watch_fd() - * - * przy asynchronicznej obs�udze HTTP funkcj� t� nale�y wywo�a�, je�li - * zmieni�o si� co� na obserwowanym deskryptorze. +#endif /* DOXYGEN */ + +/** + * Funkcja wywo�ywana po zaobserwowaniu zmian na deskryptorze po��czenia. * - * - h - struktura opisuj�ca po咳czenie + * Operacja b�dzie zako�czona, gdy pole \c state b�dzie r坦wne + * \c GG_STATE_PARSING. W tym miejscu dzia�anie przejmuje zwykle funkcja + * korzystaj�ca z \c gg_http_watch_fd(). W przypadku b��du po��czenia, + * pole \c state b�dzie r坦wne \c GG_STATE_ERROR, a kod b��du znajdzie si� + * w polu \c error. * - * je�li wszystko posz�o dobrze to 0, inaczej -1. po咳czenie b�dzie - * zako�czone, je�li h->state == GG_STATE_PARSING. je�li wyst�pi jaki� - * b咳d, to b�dzie tam GG_STATE_ERROR i odpowiedni kod b滑du w h->error. + * \param h Struktura po��czenia + * + * \return \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup http */ int gg_http_watch_fd(struct gg_http *h) { @@ -205,22 +220,7 @@ close(h->fd); h->fd = -1; -#ifdef __GG_LIBGADU_HAVE_PTHREAD - if (h->resolver) { - pthread_cancel(*((pthread_t *) h->resolver)); - free(h->resolver); - h->resolver = NULL; - } -#elif defined _WIN32 - if (h->resolver) { - HANDLE hnd = h->resolver; - TerminateThread(hnd, 0); - CloseHandle(hnd); - h->resolver = NULL; - } -#else - waitpid(h->pid, NULL, 0); -#endif + h->resolver_cleanup(&h->resolver, 0); gg_debug(GG_DEBUG_MISC, "=> http, connecting to %s:%d\n", inet_ntoa(a), h->port); @@ -264,7 +264,7 @@ gg_http_error(GG_ERROR_WRITING); } - if (res < 0 || (size_t)res < strlen(h->query)) { + if (res < strlen(h->query)) { gg_debug(GG_DEBUG_MISC, "=> http, partial header sent (led=%d, sent=%d)\n", strlen(h->query), res); memmove(h->query, h->query + res, strlen(h->query) - res + 1); @@ -346,7 +346,7 @@ h->body_size = 0; line = h->header; *tmp = 0; - + gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-HEADER-----\n%s\n=> -----END-HTTP-HEADER-----\n", h->header); while (line) { @@ -449,7 +449,7 @@ return 0; } - + if (h->fd != -1) close(h->fd); @@ -460,14 +460,14 @@ return -1; } -#undef gg_http_error - -/* - * gg_http_stop() +/** + * Ko�czy asynchroniczne po��czenie HTTP. * - * je�li po咳czenie jest w trakcie, przerywa je. nie zwalnia h->data. - * - * - h - struktura opisuj�ca po咳czenie + * Po zatrzymaniu nale甜y zwolni� zasoby funkcj� \c gg_http_free(). + * + * \param h Struktura po��czenia + * + * \ingroup http */ void gg_http_stop(struct gg_http *h) { @@ -477,15 +477,20 @@ if (h->state == GG_STATE_ERROR || h->state == GG_STATE_DONE) return; - if (h->fd != -1) + if (h->fd != -1) { close(h->fd); - h->fd = -1; + h->fd = -1; + } + + h->resolver_cleanup(&h->resolver, 1); } -/* - * gg_http_free_fields() // funkcja wewn�trzna +/** + * \internal Zwalnia pola struktury \c gg_http. * - * zwalnia pola struct gg_http, ale nie zwalnia samej struktury. + * Funkcja zwalnia same pola, nie zwalnia struktury. + * + * \param h Struktura po��czenia */ void gg_http_free_fields(struct gg_http *h) { @@ -501,19 +506,21 @@ free(h->query); h->query = NULL; } - + if (h->header) { free(h->header); h->header = NULL; } } -/* - * gg_http_free() +/** + * Zwalnia zasoby po po��czeniu HTTP. * - * pr�buje zamkn掩 po咳czenie i zwalnia pami裝 po nim. + * Je�li po��czenie nie zosta�o jeszcze zako�czone, jest przerywane. * - * - h - struktura, kt�r� nale�y zlikwidowa� + * \param h Struktura po��czenia + * + * \ingroup http */ void gg_http_free(struct gg_http *h) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/gg/lib/libgadu-internal.h Mon Mar 01 03:46:33 2010 +0000 @@ -0,0 +1,30 @@ +/* $Id$ */ + +/* + * (C) Copyright 2009 Jakub Zawadzki <darkjames@darkjames.ath.cx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License Version + * 2.1 as published by the Free Software Foundation. + * + * This program 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 Lesser General Public License for more details. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef LIBGADU_INTERNAL_H +#define LIBGADU_INTERNAL_H + +#include "libgadu.h" + +char *gg_cp_to_utf8(const char *b); +char *gg_utf8_to_cp(const char *b); +int gg_pubdir50_handle_reply_sess(struct gg_session *sess, struct gg_event *e, const char *packet, int length); + +#endif /* LIBGADU_INTERNAL_H */
--- a/libpurple/protocols/gg/lib/libgadu.c Sun Feb 28 23:42:12 2010 +0000 +++ b/libpurple/protocols/gg/lib/libgadu.c Mon Mar 01 03:46:33 2010 +0000 @@ -1,10 +1,11 @@ -/* $Id: libgadu.c 16856 2006-08-19 01:13:25Z evands $ */ +/* $Id: libgadu.c 878 2009-11-16 23:48:19Z wojtekka $ */ /* - * (C) Copyright 2001-2003 Wojtek Kaniewski <wojtekka@irc.pl> - * Robert J. Wo�ny <speedy@ziew.org> - * Arkadiusz Mi�kiewicz <arekm@pld-linux.org> - * Tomasz Chili�ski <chilek@chilan.com> + * (C) Copyright 2001-2009 Wojtek Kaniewski <wojtekka@irc.pl> + * Robert J. Wo添ny <speedy@ziew.org> + * Arkadiusz Mi�kiewicz <arekm@pld-linux.org> + * Tomasz Chili�ski <chilek@chilan.com> + * Adam Wysocki <gophi@ekg.chmurka.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License Version @@ -17,227 +18,199 @@ * * 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. */ +/** + * \file libgadu.c + * + * \brief G�坦wny modu� biblioteki + */ + #include "libgadu.h" +#include "libgadu-internal.h" #include <sys/types.h> -#ifndef _WIN32 -#include <sys/wait.h> -#include <sys/socket.h> -#include <netinet/in.h> -#include <arpa/inet.h> -#ifdef sun -# include <sys/filio.h> -#endif + +#ifdef _WIN32 +# include <io.h> +# include <fcntl.h> +# include <errno.h> +# define SHUT_RDWR SD_BOTH #else -#include <io.h> -#include <fcntl.h> -#include <errno.h> -#define SHUT_RDWR SD_BOTH +# include <sys/socket.h> +# include <netinet/in.h> +# include <arpa/inet.h> +# ifdef sun +# include <sys/filio.h> +# endif #endif -#include "libgadu-config.h" +#include "compat.h" +#include "protocol.h" +#include "resolver.h" -#include <errno.h> #ifndef _WIN32 -#include <netdb.h> +# include <errno.h> /* on Win32 this is included above */ +# include <netdb.h> #endif -#ifdef __GG_LIBGADU_HAVE_PTHREAD -# include <pthread.h> -#endif + #include <stdarg.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <signal.h> +#include <time.h> #include <unistd.h> -#ifdef __GG_LIBGADU_HAVE_OPENSSL +#ifdef GG_CONFIG_HAVE_OPENSSL # include <openssl/err.h> # include <openssl/rand.h> #endif -#include "compat.h" +#define GG_LIBGADU_VERSION "1.9.0-rc2" + +/** + * Poziom rejestracji informacji odpluskwiaj�cych. Zmienna jest mask� bitow� + * sk�adaj�c� si� ze sta�ych \c GG_DEBUG_... + * + * \ingroup debug + */ +int gg_debug_level = 0; -int gg_debug_level = 0; +/** + * Funkcja, do kt坦rej s� przekazywane informacje odpluskwiaj�ce. Je�li zar坦wno + * ten \c gg_debug_handler, jak i \c gg_debug_handler_session, s� r坦wne + * \c NULL, informacje s� wysy�ane do standardowego wyj�cia b��du (\c stderr). + * + * \param level Poziom rejestracji + * \param format Format wiadomo�ci (zgodny z \c printf) + * \param ap Lista argument坦w (zgodna z \c printf) + * + * \note Funkcja jest przes�aniana przez \c gg_debug_handler_session. + * + * \ingroup debug + */ void (*gg_debug_handler)(int level, const char *format, va_list ap) = NULL; +/** + * Funkcja, do kt坦rej s� przekazywane informacje odpluskwiaj�ce. Je�li zar坦wno + * ten \c gg_debug_handler, jak i \c gg_debug_handler_session, s� r坦wne + * \c NULL, informacje s� wysy�ane do standardowego wyj�cia b��du. + * + * \param sess Sesja kt坦rej dotyczy informacja lub \c NULL + * \param level Poziom rejestracji + * \param format Format wiadomo�ci (zgodny z \c printf) + * \param ap Lista argument坦w (zgodna z \c printf) + * + * \note Funkcja przes�ania przez \c gg_debug_handler_session. + * + * \ingroup debug + */ +void (*gg_debug_handler_session)(struct gg_session *sess, int level, const char *format, va_list ap) = NULL; + +/** + * Port gniazda nas�uchuj�cego dla po��cze� bezpo�rednich. + * + * \ingroup ip + */ int gg_dcc_port = 0; + +/** + * Adres IP gniazda nas�uchuj�cego dla po��cze� bezpo�rednich. + * + * \ingroup ip + */ unsigned long gg_dcc_ip = 0; +/** + * Adres lokalnego interfejsu IP, z kt坦rego wywo�ywane s� wszystkie po��czenia. + * + * \ingroup ip + */ unsigned long gg_local_ip = 0; -/* - * zmienne opisuj�ce parametry proxy http. + +/** + * Flaga w��czenia po��cze� przez serwer po�rednicz�cy. + * + * \ingroup proxy + */ +int gg_proxy_enabled = 0; + +/** + * Adres serwera po�rednicz�cego. + * + * \ingroup proxy */ char *gg_proxy_host = NULL; + +/** + * Port serwera po�rednicz�cego. + * + * \ingroup proxy + */ int gg_proxy_port = 0; -int gg_proxy_enabled = 0; + +/** + * Flaga u甜ywania serwera po�rednicz�cego jedynie dla us�ug HTTP. + * + * \ingroup proxy + */ int gg_proxy_http_only = 0; + +/** + * Nazwa u甜ytkownika do autoryzacji serwera po�rednicz�cego. + * + * \ingroup proxy + */ char *gg_proxy_username = NULL; + +/** + * Has�o u甜ytkownika do autoryzacji serwera po�rednicz�cego. + * + * \ingroup proxy + */ char *gg_proxy_password = NULL; -#ifndef lint +#ifndef DOXYGEN + +#ifndef lint static char rcsid[] #ifdef __GNUC__ __attribute__ ((unused)) #endif -= "$Id: libgadu.c 16856 2006-08-19 01:13:25Z evands $"; -#endif - -#ifdef _WIN32 -/** - * Deal with the fact that you can't select() on a win32 file fd. - * This makes it practically impossible to tie into purple's event loop. - * - * -This is thanks to Tor Lillqvist. - * XXX - Move this to where the rest of the the win32 compatiblity stuff goes when we push the changes back to libgadu. - */ -static int -socket_pipe (int *fds) -{ - SOCKET temp, socket1 = -1, socket2 = -1; - struct sockaddr_in saddr; - int len; - u_long arg; - fd_set read_set, write_set; - struct timeval tv; - - temp = socket(AF_INET, SOCK_STREAM, 0); - - if (temp == INVALID_SOCKET) { - goto out0; - } - - arg = 1; - if (ioctlsocket(temp, FIONBIO, &arg) == SOCKET_ERROR) { - goto out0; - } - - memset(&saddr, 0, sizeof(saddr)); - saddr.sin_family = AF_INET; - saddr.sin_port = 0; - saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); - - if (bind(temp, (struct sockaddr *)&saddr, sizeof (saddr))) { - goto out0; - } - - if (listen(temp, 1) == SOCKET_ERROR) { - goto out0; - } - - len = sizeof(saddr); - if (getsockname(temp, (struct sockaddr *)&saddr, &len)) { - goto out0; - } - - socket1 = socket(AF_INET, SOCK_STREAM, 0); - - if (socket1 == INVALID_SOCKET) { - goto out0; - } - - arg = 1; - if (ioctlsocket(socket1, FIONBIO, &arg) == SOCKET_ERROR) { - goto out1; - } - - if (connect(socket1, (struct sockaddr *)&saddr, len) != SOCKET_ERROR || - WSAGetLastError() != WSAEWOULDBLOCK) { - goto out1; - } - - FD_ZERO(&read_set); - FD_SET(temp, &read_set); - - tv.tv_sec = 0; - tv.tv_usec = 0; - - if (select(0, &read_set, NULL, NULL, NULL) == SOCKET_ERROR) { - goto out1; - } - - if (!FD_ISSET(temp, &read_set)) { - goto out1; - } - - socket2 = accept(temp, (struct sockaddr *) &saddr, &len); - if (socket2 == INVALID_SOCKET) { - goto out1; - } - - FD_ZERO(&write_set); - FD_SET(socket1, &write_set); - - tv.tv_sec = 0; - tv.tv_usec = 0; - - if (select(0, NULL, &write_set, NULL, NULL) == SOCKET_ERROR) { - goto out2; - } - - if (!FD_ISSET(socket1, &write_set)) { - goto out2; - } - - arg = 0; - if (ioctlsocket(socket1, FIONBIO, &arg) == SOCKET_ERROR) { - goto out2; - } - - arg = 0; - if (ioctlsocket(socket2, FIONBIO, &arg) == SOCKET_ERROR) { - goto out2; - } - - fds[0] = socket1; - fds[1] = socket2; - - closesocket (temp); - - return 0; - -out2: - closesocket (socket2); -out1: - closesocket (socket1); -out0: - closesocket (temp); - errno = EIO; /* XXX */ - - return -1; -} += "$Id: libgadu.c 878 2009-11-16 23:48:19Z wojtekka $"; #endif -/* - * gg_libgadu_version() +#endif /* DOXYGEN */ + +/** + * Zwraca wersj� biblioteki. * - * zwraca wersj� libgadu. + * \return Wska添nik na statyczny bufor z wersj� biblioteki. * - * - brak - * - * wersja libgadu. + * \ingroup version */ const char *gg_libgadu_version() { return GG_LIBGADU_VERSION; } -/* - * gg_fix32() +/** + * \internal Zamienia kolejno�� bajt坦w w 32-bitowym s�owie. + * + * Ze wzgl�du na little-endianowo�� protoko�u Gadu-Gadu, na maszynach + * big-endianowych odwraca kolejno�� bajt坦w w s�owie. * - * zamienia kolejno倶 bajt�w w liczbie 32-bitowej tak, by odpowiada�a - * kolejno�ci bajt�w w protokole GG. ze wzgl�du na LE-owo倶 serwera, - * zamienia tylko na maszynach BE-wych. + * \param x Liczba do zamiany * - * - x - liczba do zamiany + * \return Liczba z odpowiedni� kolejno�ci� bajt坦w * - * liczba z odpowiedni� kolejno�ci� bajt�w. + * \ingroup helper */ uint32_t gg_fix32(uint32_t x) { -#ifndef __GG_LIBGADU_BIGENDIAN +#ifndef GG_CONFIG_BIGENDIAN return x; #else return (uint32_t) @@ -248,20 +221,21 @@ #endif } -/* - * gg_fix16() +/** + * \internal Zamienia kolejno�� bajt坦w w 16-bitowym s�owie. + * + * Ze wzgl�du na little-endianowo�� protoko�u Gadu-Gadu, na maszynach + * big-endianowych zamienia kolejno�� bajt坦w w s�owie. * - * zamienia kolejno倶 bajt�w w liczbie 16-bitowej tak, by odpowiada�a - * kolejno�ci bajt�w w protokole GG. ze wzgl�du na LE-owo倶 serwera, - * zamienia tylko na maszynach BE-wych. + * \param x Liczba do zamiany * - * - x - liczba do zamiany + * \return Liczba z odpowiedni� kolejno�ci� bajt坦w * - * liczba z odpowiedni� kolejno�ci� bajt�w. + * \ingroup helper */ uint16_t gg_fix16(uint16_t x) { -#ifndef __GG_LIBGADU_BIGENDIAN +#ifndef GG_CONFIG_BIGENDIAN return x; #else return (uint16_t) @@ -270,15 +244,13 @@ #endif } -/* - * gg_login_hash() // funkcja wewn�trzna - * - * liczy hash z has�a i danego seeda. - * - * - password - has�o do hashowania - * - seed - warto倶 podana przez serwer +/** + * \internal Liczy skr坦t z has�a i ziarna. * - * hash. + * \param password Has�o + * \param seed Ziarno podane przez serwer + * + * \return Warto�� skr坦tu */ unsigned int gg_login_hash(const unsigned char *password, unsigned int seed) { @@ -304,313 +276,22 @@ return y; } -#ifndef _WIN32 - -/* - * gg_resolve() // funkcja wewn�trzna - * - * tworzy potok, forkuje si� i w drugim procesie zaczyna resolvowa� - * podanego hosta. zapisuje w sesji deskryptor potoku. je�li co� tam - * b�dzie gotowego, znaczy, �e mo�na wczyta� struct in_addr. je�li - * nie znajdzie, zwraca INADDR_NONE. - * - * - fd - wska�nik gdzie wrzuci� deskryptor - * - pid - gdzie wrzuci� pid procesu potomnego - * - hostname - nazwa hosta do zresolvowania +/** + * \internal Odbiera od serwera dane binarne. * - * 0, -1. - */ -int gg_resolve(int *fd, int *pid, const char *hostname) -{ - int pipes[2], res; - struct in_addr a; - int errno2; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve(%p, %p, \"%s\");\n", fd, pid, hostname); - - if (!fd || !pid) { - errno = EFAULT; - return -1; - } - - if (pipe(pipes) == -1) - return -1; - - if ((res = fork()) == -1) { - errno2 = errno; - close(pipes[0]); - close(pipes[1]); - errno = errno2; - return -1; - } - - if (!res) { - if ((a.s_addr = inet_addr(hostname)) == INADDR_NONE) { - struct in_addr *hn; - - if (!(hn = gg_gethostbyname(hostname))) - a.s_addr = INADDR_NONE; - else { - a.s_addr = hn->s_addr; - free(hn); - } - } - - write(pipes[1], &a, sizeof(a)); - - _exit(0); - } - - close(pipes[1]); - - *fd = pipes[0]; - *pid = res; - - return 0; -} -#endif - -#ifdef __GG_LIBGADU_HAVE_PTHREAD - -struct gg_resolve_pthread_data { - char *hostname; - int fd; -}; - -static void *gg_resolve_pthread_thread(void *arg) -{ - struct gg_resolve_pthread_data *d = arg; - struct in_addr a; - - pthread_detach(pthread_self()); - - if ((a.s_addr = inet_addr(d->hostname)) == INADDR_NONE) { - struct in_addr *hn; - - if (!(hn = gg_gethostbyname(d->hostname))) - a.s_addr = INADDR_NONE; - else { - a.s_addr = hn->s_addr; - free(hn); - } - } - - write(d->fd, &a, sizeof(a)); - close(d->fd); - - free(d->hostname); - d->hostname = NULL; - - free(d); - - pthread_exit(NULL); - - return NULL; /* �eby kompilator nie marudzi� */ -} - -/* - * gg_resolve_pthread() // funkcja wewn�trzna - * - * tworzy potok, nowy w�tek i w nim zaczyna resolvowa� podanego hosta. - * zapisuje w sesji deskryptor potoku. je�li co� tam b�dzie gotowego, - * znaczy, �e mo�na wczyta� struct in_addr. je�li nie znajdzie, zwraca - * INADDR_NONE. - * - * - fd - wska�nik do zmiennej przechowuj�cej desktyptor resolvera - * - resolver - wska�nik do wska�nika resolvera - * - hostname - nazwa hosta do zresolvowania + * Funkcja odbiera dane od serwera zajmuj�c si� TLS w razie konieczno�ci. * - * 0, -1. - */ -int gg_resolve_pthread(int *fd, void **resolver, const char *hostname) -{ - struct gg_resolve_pthread_data *d = NULL; - pthread_t *tmp; - int pipes[2], new_errno; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve_pthread(%p, %p, \"%s\");\n", fd, resolver, hostname); - - if (!resolver || !fd || !hostname) { - gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() invalid arguments\n"); - errno = EFAULT; - return -1; - } - - if (!(tmp = malloc(sizeof(pthread_t)))) { - gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory for pthread id\n"); - return -1; - } - - if (pipe(pipes) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno)); - free(tmp); - return -1; - } - - if (!(d = malloc(sizeof(*d)))) { - gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory\n"); - new_errno = errno; - goto cleanup; - } - - d->hostname = NULL; - - if (!(d->hostname = strdup(hostname))) { - gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory\n"); - new_errno = errno; - goto cleanup; - } - - d->fd = pipes[1]; - - if (pthread_create(tmp, NULL, gg_resolve_pthread_thread, d)) { - gg_debug(GG_DEBUG_MISC, "// gg_resolve_phread() unable to create thread\n"); - new_errno = errno; - goto cleanup; - } - - gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() %p\n", tmp); - - *resolver = tmp; - - *fd = pipes[0]; - - return 0; - -cleanup: - if (d) { - free(d->hostname); - free(d); - } - - close(pipes[0]); - close(pipes[1]); - - free(tmp); - - errno = new_errno; - - return -1; -} - -#elif defined _WIN32 - -struct gg_resolve_win32thread_data { - char *hostname; - int fd; -}; - -static DWORD WINAPI gg_resolve_win32thread_thread(LPVOID arg) -{ - struct gg_resolve_win32thread_data *d = arg; - struct in_addr a; - - if ((a.s_addr = inet_addr(d->hostname)) == INADDR_NONE) { - struct in_addr *hn; - - if (!(hn = gg_gethostbyname(d->hostname))) - a.s_addr = INADDR_NONE; - else { - a.s_addr = hn->s_addr; - free(hn); - } - } - - write(d->fd, &a, sizeof(a)); - close(d->fd); - - free(d->hostname); - d->hostname = NULL; - - free(d); - - return 0; -} - - -int gg_resolve_win32thread(int *fd, void **resolver, const char *hostname) -{ - struct gg_resolve_win32thread_data *d = NULL; - HANDLE h; - DWORD dwTId; - int pipes[2], new_errno; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve_win32thread(%p, %p, \"%s\");\n", fd, resolver, hostname); - - if (!resolver || !fd || !hostname) { - gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() invalid arguments\n"); - errno = EFAULT; - return -1; - } - - if (socket_pipe(pipes) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno)); - return -1; - } - - if (!(d = malloc(sizeof(*d)))) { - gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() out of memory\n"); - new_errno = GetLastError(); - goto cleanup; - } - - d->hostname = NULL; - - if (!(d->hostname = strdup(hostname))) { - gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() out of memory\n"); - new_errno = GetLastError(); - goto cleanup; - } - - d->fd = pipes[1]; - - h = CreateThread(NULL, 0, gg_resolve_win32thread_thread, - d, 0, &dwTId); - - if (h == NULL) { - gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() unable to create thread\n"); - new_errno = GetLastError(); - goto cleanup; - } - - *resolver = h; - *fd = pipes[0]; - - return 0; - -cleanup: - if (d) { - free(d->hostname); - free(d); - } - - close(pipes[0]); - close(pipes[1]); - - errno = new_errno; - - return -1; - -} -#endif - -/* - * gg_read() // funkcja pomocnicza + * \param sess Struktura sesji + * \param buf Bufor na danymi + * \param length D�ugo�� bufora * - * czyta z gniazda okre�lon� ilo倶 bajt�w. bierze pod uwag�, czy mamy - * po咳czenie zwyk�e czy TLS. - * - * - sess - sesja, - * - buf - bufor, - * - length - ilo倶 bajt�w, - * - * takie same warto�ci jak read(). + * \return To samo co funkcja systemowa \c read */ int gg_read(struct gg_session *sess, char *buf, int length) { int res; -#ifdef __GG_LIBGADU_HAVE_OPENSSL +#ifdef GG_CONFIG_HAVE_OPENSSL if (sess->ssl) { int err; @@ -631,23 +312,22 @@ return res; } -/* - * gg_write() // funkcja pomocnicza +/** + * \internal Wysy�a do serwera dane binarne. * - * zapisuje do gniazda okre�lon� ilo倶 bajt�w. bierze pod uwag�, czy mamy - * po咳czenie zwyk�e czy TLS. + * Funkcja wysy�a dane do serwera zajmuj�c si� TLS w razie konieczno�ci. * - * - sess - sesja, - * - buf - bufor, - * - length - ilo倶 bajt�w, + * \param sess Struktura sesji + * \param buf Bufor z danymi + * \param length D�ugo�� bufora * - * takie same warto�ci jak write(). + * \return To samo co funkcja systemowa \c write */ int gg_write(struct gg_session *sess, const char *buf, int length) { int res = 0; -#ifdef __GG_LIBGADU_HAVE_OPENSSL +#ifdef GG_CONFIG_HAVE_OPENSSL if (sess->ssl) { int err; @@ -664,19 +344,48 @@ } else #endif { - int written = 0; - - while (written < length) { - res = write(sess->fd, buf + written, length - written); + if (!sess->async) { + int written = 0; + + while (written < length) { + res = write(sess->fd, buf + written, length - written); + + if (res == -1) { + if (errno != EINTR) + break; + + continue; + } + + written += res; + res = written; + } + } else { + if (!sess->send_buf) + res = write(sess->fd, buf, length); + else + res = 0; if (res == -1) { - if (errno == EAGAIN) - continue; - else - break; - } else { - written += res; - res = written; + if (errno != EAGAIN) + return res; + + res = 0; + } + + if (res < length) { + char *tmp; + + if (!(tmp = realloc(sess->send_buf, sess->send_left + length - res))) { + errno = ENOMEM; + return -1; + } + + sess->send_buf = tmp; + + memcpy(sess->send_buf + sess->send_left, buf + res, length - res); + + sess->send_left += length - res; } } } @@ -684,26 +393,29 @@ return res; } -/* - * gg_recv_packet() // funkcja wewn�trzna +/** + * \internal Odbiera pakiet od serwera. * - * odbiera jeden pakiet i zwraca wska�nik do niego. pami裝 po nim - * nale�y zwolni� za pomoc� free(). + * Funkcja odczytuje nag�坦wek pakietu, a nast�pnie jego zawarto�� i zwraca + * w zaalokowanym buforze. * - * - sess - opis sesji + * Przy po��czeniach asynchronicznych, funkcja mo甜e nie by� w stanie + * skompletowa� ca�ego pakietu -- w takim przypadku zwr坦ci -1, a kodem b��du + * b�dzie \c EAGAIN. * - * w przypadku b滑du NULL, kod b滑du w errno. nale�y zwr�ci� uwag�, �e gdy - * po咳czenie jest nieblokuj�ce, a kod b滑du wynosi EAGAIN, nie uda�o si� - * odczyta� ca�ego pakietu i nie nale�y tego traktowa� jako b咳d. + * \param sess Struktura sesji + * + * \return Wska添nik do zaalokowanego bufora */ void *gg_recv_packet(struct gg_session *sess) { struct gg_header h; char *buf = NULL; - int ret = 0, offset, size = 0; + int ret = 0; + unsigned int offset, size = 0; - gg_debug(GG_DEBUG_FUNCTION, "** gg_recv_packet(%p);\n", sess); - + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_recv_packet(%p);\n", sess); + if (!sess) { errno = EFAULT; return NULL; @@ -712,7 +424,7 @@ if (sess->recv_left < 1) { if (sess->header_buf) { memcpy(&h, sess->header_buf, sess->header_done); - gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv: resuming last read (%d bytes left)\n", sizeof(h) - sess->header_done); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv: resuming last read (%d bytes left)\n", sizeof(h) - sess->header_done); free(sess->header_buf); sess->header_buf = NULL; } else @@ -721,34 +433,36 @@ while (sess->header_done < sizeof(h)) { ret = gg_read(sess, (char*) &h + sess->header_done, sizeof(h) - sess->header_done); - gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv(%d,%p,%d) = %d\n", sess->fd, &h + sess->header_done, sizeof(h) - sess->header_done, ret); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv(%d,%p,%d) = %d\n", sess->fd, &h + sess->header_done, sizeof(h) - sess->header_done, ret); if (!ret) { errno = ECONNRESET; - gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: connection broken\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: connection broken\n"); return NULL; } if (ret == -1) { if (errno == EINTR) { - gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() interrupted system call, resuming\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() interrupted system call, resuming\n"); continue; } if (errno == EAGAIN) { - gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() incomplete header received\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() incomplete header received\n"); if (!(sess->header_buf = malloc(sess->header_done))) { - gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() not enough memory\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() not enough memory\n"); return NULL; } memcpy(sess->header_buf, &h, sess->header_done); + errno = EAGAIN; + return NULL; } - gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: errno=%d, %s\n", errno, strerror(errno)); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: errno=%d, %s\n", errno, strerror(errno)); return NULL; } @@ -761,22 +475,22 @@ h.length = gg_fix32(h.length); } else memcpy(&h, sess->recv_buf, sizeof(h)); - - /* jakie� sensowne limity na rozmiar pakietu */ + + /* jakie� sensowne limity na rozmiar pakietu */ if (h.length > 65535) { - gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() invalid packet length (%d)\n", h.length); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() invalid packet length (%d)\n", h.length); errno = ERANGE; return NULL; } if (sess->recv_left > 0) { - gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() resuming last gg_recv_packet()\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() resuming last gg_recv_packet()\n"); size = sess->recv_left; offset = sess->recv_done; buf = sess->recv_buf; } else { if (!(buf = malloc(sizeof(h) + h.length + 1))) { - gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() not enough memory for packet data\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() not enough memory for packet data\n"); return NULL; } @@ -788,24 +502,23 @@ while (size > 0) { ret = gg_read(sess, buf + sizeof(h) + offset, size); - gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv(%d,%p,%d) = %d\n", sess->fd, buf + sizeof(h) + offset, size, ret); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() body recv(%d,%p,%d) = %d\n", sess->fd, buf + sizeof(h) + offset, size, ret); if (!ret) { - gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed: connection broken\n"); - free(buf); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed: connection broken\n"); errno = ECONNRESET; return NULL; } if (ret > -1 && ret <= size) { offset += ret; size -= ret; - } else if (ret == -1) { + } else if (ret == -1) { int errno2 = errno; - gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed (errno=%d, %s)\n", errno, strerror(errno)); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed (errno=%d, %s)\n", errno, strerror(errno)); errno = errno2; if (errno == EAGAIN) { - gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() %d bytes received, %d left\n", offset, size); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() %d bytes received, %d left\n", offset, size); sess->recv_buf = buf; sess->recv_left = size; sess->recv_done = offset; @@ -823,49 +536,45 @@ if ((gg_debug_level & GG_DEBUG_DUMP)) { unsigned int i; - gg_debug(GG_DEBUG_DUMP, "// gg_recv_packet(%.2x)", h.type); - for (i = 0; i < sizeof(h) + h.length; i++) - gg_debug(GG_DEBUG_DUMP, " %.2x", (unsigned char) buf[i]); - gg_debug(GG_DEBUG_DUMP, "\n"); + gg_debug_session(sess, GG_DEBUG_DUMP, "// gg_recv_packet(%.2x)", h.type); + for (i = 0; i < sizeof(h) + h.length; i++) + gg_debug_session(sess, GG_DEBUG_DUMP, " %.2x", (unsigned char) buf[i]); + gg_debug_session(sess, GG_DEBUG_DUMP, "\n"); } return buf; } -/* - * gg_send_packet() // funkcja wewn�trzna +/** + * \internal Wysy�a pakiet do serwera. * - * konstruuje pakiet i wysy�a go do serwera. + * Funkcja konstruuje pakiet do wys�ania z dowolnej liczby fragment坦w. Je�li + * rozmiar pakietu jest za du甜y, by m坦c go wys�a� za jednym razem, pozosta�a + * cz��� zostanie zakolejkowana i wys�ana, gdy b�dzie to mo甜liwe. * - * - sock - deskryptor gniazda - * - type - typ pakietu - * - payload_1 - pierwsza cz蟠� pakietu - * - payload_length_1 - d�ugo倶 pierwszej cz蟠ci - * - payload_2 - druga cz蟠� pakietu - * - payload_length_2 - d�ugo倶 drugiej cz蟠ci - * - ... - kolejne cz蟠ci pakietu i ich d�ugo�ci - * - NULL - ko�cowym parametr (konieczny!) + * \param sess Struktura sesji + * \param type Rodzaj pakietu + * \param ... Lista kolejnych cz��ci pakietu (wska添nik na bufor i d�ugo�� + * typu \c int) zako�czona \c NULL * - * je�li si� powiod�o, zwraca 0, w przypadku b滑du -1. je�li errno == ENOMEM, - * zabrak�o pami�ci. inaczej by� b咳d przy wysy�aniu pakietu. dla errno == 0 - * nie wys�ano ca�ego pakietu. + * \return 0 je�li si� powiod�o, -1 w przypadku b��du */ int gg_send_packet(struct gg_session *sess, int type, ...) { struct gg_header *h; char *tmp; - int tmp_length; + unsigned int tmp_length; void *payload; unsigned int payload_length; va_list ap; int res; - gg_debug(GG_DEBUG_FUNCTION, "** gg_send_packet(%p, 0x%.2x, ...)\n", sess, type); + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_packet(%p, 0x%.2x, ...);\n", sess, type); tmp_length = sizeof(struct gg_header); if (!(tmp = malloc(tmp_length))) { - gg_debug(GG_DEBUG_MISC, "// gg_send_packet() not enough memory for packet header\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_send_packet() not enough memory for packet header\n"); return -1; } @@ -879,14 +588,14 @@ payload_length = va_arg(ap, unsigned int); if (!(tmp2 = realloc(tmp, tmp_length + payload_length))) { - gg_debug(GG_DEBUG_MISC, "// gg_send_packet() not enough memory for payload\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_send_packet() not enough memory for payload\n"); free(tmp); va_end(ap); return -1; } tmp = tmp2; - + memcpy(tmp + tmp_length, payload, payload_length); tmp_length += payload_length; @@ -900,54 +609,83 @@ h->length = gg_fix32(tmp_length - sizeof(struct gg_header)); if ((gg_debug_level & GG_DEBUG_DUMP)) { - int i; + unsigned int i; - gg_debug(GG_DEBUG_DUMP, "// gg_send_packet(0x%.2x)", gg_fix32(h->type)); + gg_debug_session(sess, GG_DEBUG_DUMP, "// gg_send_packet(0x%.2x)", gg_fix32(h->type)); for (i = 0; i < tmp_length; ++i) - gg_debug(GG_DEBUG_DUMP, " %.2x", (unsigned char) tmp[i]); - gg_debug(GG_DEBUG_DUMP, "\n"); + gg_debug_session(sess, GG_DEBUG_DUMP, " %.2x", (unsigned char) tmp[i]); + gg_debug_session(sess, GG_DEBUG_DUMP, "\n"); } - - if ((res = gg_write(sess, tmp, tmp_length)) < tmp_length) { - gg_debug(GG_DEBUG_MISC, "// gg_send_packet() write() failed. res = %d, errno = %d (%s)\n", res, errno, strerror(errno)); - free(tmp); + + res = gg_write(sess, tmp, tmp_length); + + free(tmp); + + if (res == -1) { + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_send_packet() write() failed. res = %d, errno = %d (%s)\n", res, errno, strerror(errno)); return -1; } - - free(tmp); + + if (sess->async) + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_send_packet() partial write(), %d sent, %d left, %d total left\n", res, tmp_length - res, sess->send_left); + + if (sess->send_buf) + sess->check |= GG_CHECK_WRITE; + return 0; } -/* - * gg_session_callback() // funkcja wewn�trzna +/** + * \internal Funkcja zwrotna sesji. + * + * Pole \c callback struktury \c gg_session zawiera wska添nik do tej funkcji. + * Wywo�uje ona \c gg_watch_fd i zachowuje wynik w polu \c event. + * + * \note Korzystanie z tej funkcjonalno�ci nie jest ju甜 zalecane. * - * wywo�ywany z gg_session->callback, wykonuje gg_watch_fd() i pakuje - * do gg_session->event jego wynik. + * \param sess Struktura sesji + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du */ -static int gg_session_callback(struct gg_session *s) +static int gg_session_callback(struct gg_session *sess) { - if (!s) { + if (!sess) { errno = EFAULT; return -1; } - return ((s->event = gg_watch_fd(s)) != NULL) ? 0 : -1; + return ((sess->event = gg_watch_fd(sess)) != NULL) ? 0 : -1; } -/* - * gg_login() +/** + * ��czy si� z serwerem Gadu-Gadu. * - * rozpoczyna procedur� 咳czenia si� z serwerem. reszt� obs�uguje si� przez - * gg_watch_fd(). + * Przy po��czeniu synchronicznym funkcja zako�czy dzia�anie po nawi�zaniu + * po��czenia lub gdy wyst�pi b��d. Po udanym po��czeniu nale甜y wywo�ywa� + * funkcj� \c gg_watch_fd(), kt坦ra odbiera informacje od serwera i zwraca + * informacje o zdarzeniach. * - * UWAGA! program musi obs�u�y� SIGCHLD, je�li 咳czy si� asynchronicznie, - * �eby poprawnie zamkn掩 proces resolvera. + * Przy po��czeniu asynchronicznym funkcja rozpocznie procedur� po��czenia + * i zwr坦ci zaalokowan� struktur�. Pole \c fd struktury \c gg_session zawiera + * deskryptor, kt坦ry nale甜y obserwowa� funkcj� \c select, \c poll lub za + * pomoc� mechanizm坦w u甜ytej p�tli zdarze� (Glib, Qt itp.). Pole \c check + * jest mask� bitow� m坦wi�c�, czy biblioteka chce by� informowana o mo甜liwo�ci + * odczytu danych (\c GG_CHECK_READ) czy zapisu danych (\c GG_CHECK_WRITE). + * Po zaobserwowaniu zmian na deskryptorze nale甜y wywo�a� funkcj� + * \c gg_watch_fd(). Podczas korzystania z po��cze� asynchronicznych, w trakcie + * po��czenia mo甜e zosta� stworzony dodatkowy proces rozwi�zuj�cy nazw� + * serwera -- z tego powodu program musi poprawnie obs�u甜y� sygna� SIGCHLD. * - * - p - struktura opisuj�ca pocz�tkowy stan. wymagane pola: uin, - * password + * \note Po nawi�zaniu po��czenia z serwerem nale甜y wys�a� list� kontakt坦w + * za pomoc� funkcji \c gg_notify() lub \c gg_notify_ex(). * - * w przypadku b滑du NULL, je�li idzie dobrze (async) albo posz�o - * dobrze (sync), zwr�ci wska�nik do zaalokowanej struct gg_session. + * \param p Struktura opisuj�ca parametry po��czenia. Wymagane pola: uin, + * password, async. + * + * \return Wska添nik do zaalokowanej struktury sesji \c gg_session lub NULL + * w przypadku b��du. + * + * \ingroup login */ struct gg_session *gg_login(const struct gg_login_params *p) { @@ -981,8 +719,9 @@ goto fail; } - if (p->status_descr && !(sess->initial_descr = strdup(p->status_descr))) { - gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for status\n"); + if (p->hash_type < 0 || p->hash_type > GG_LOGIN_HASH_SHA1) { + gg_debug(GG_DEBUG_MISC, "// gg_login() invalid arguments. unknown hash type (%d)\n", p->hash_type); + errno = EFAULT; goto fail; } @@ -999,18 +738,59 @@ sess->server_addr = p->server_addr; sess->external_port = p->external_port; sess->external_addr = p->external_addr; + + sess->protocol_features = (p->protocol_features & ~(GG_FEATURE_STATUS77 | GG_FEATURE_MSG77)); + + if (!(p->protocol_features & GG_FEATURE_STATUS77)) + sess->protocol_features |= GG_FEATURE_STATUS80; + + if (!(p->protocol_features & GG_FEATURE_MSG77)) + sess->protocol_features |= GG_FEATURE_MSG80; + sess->protocol_version = (p->protocol_version) ? p->protocol_version : GG_DEFAULT_PROTOCOL_VERSION; + if (p->era_omnix) - sess->protocol_version |= GG_ERA_OMNIX_MASK; + sess->protocol_flags |= GG_ERA_OMNIX_MASK; if (p->has_audio) - sess->protocol_version |= GG_HAS_AUDIO_MASK; + sess->protocol_flags |= GG_HAS_AUDIO_MASK; sess->client_version = (p->client_version) ? strdup(p->client_version) : NULL; sess->last_sysmsg = p->last_sysmsg; sess->image_size = p->image_size; sess->pid = -1; + sess->encoding = p->encoding; + + if (gg_session_set_resolver(sess, p->resolver) == -1) { + gg_debug(GG_DEBUG_MISC, "// gg_login() invalid arguments. unsupported resolver type (%d)\n", p->resolver); + errno = EFAULT; + goto fail; + } + + if (p->status_descr) { + int max_length; + + if (sess->protocol_version >= 0x2d) + max_length = GG_STATUS_DESCR_MAXSIZE; + else + max_length = GG_STATUS_DESCR_MAXSIZE_PRE_8_0; + + if (sess->protocol_version >= 0x2d && p->encoding != GG_ENCODING_UTF8) + sess->initial_descr = gg_cp_to_utf8(p->status_descr); + else + sess->initial_descr = strdup(p->status_descr); + + if (!sess->initial_descr) { + gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for status\n"); + goto fail; + } + + // XXX pami�ta�, 甜eby nie ci�� w �rodku znaku utf-8 + + if (strlen(sess->initial_descr) > max_length) + sess->initial_descr[max_length] = 0; + } if (p->tls == 1) { -#ifdef __GG_LIBGADU_HAVE_OPENSSL +#ifdef GG_CONFIG_HAVE_OPENSSL char buf[1024]; OpenSSL_add_ssl_algorithms(); @@ -1023,7 +803,7 @@ } rstruct; time(&rstruct.time); - rstruct.ptr = (void *) &rstruct; + rstruct.ptr = (void *) &rstruct; RAND_seed((void *) rdata, sizeof(rdata)); RAND_seed((void *) &rstruct, sizeof(rstruct)); @@ -1050,7 +830,7 @@ gg_debug(GG_DEBUG_MISC, "// gg_login() client requested TLS but no support compiled in\n"); #endif } - + if (gg_proxy_enabled) { hostname = gg_proxy_host; sess->proxy_port = port = gg_proxy_port; @@ -1059,37 +839,50 @@ port = GG_APPMSG_PORT; } - if (!p->async) { - struct in_addr a; + if (p->hash_type) + sess->hash_type = p->hash_type; + else + sess->hash_type = GG_LOGIN_HASH_SHA1; - if (!p->server_addr || !p->server_port) { - if ((a.s_addr = inet_addr(hostname)) == INADDR_NONE) { - struct in_addr *hn; - - if (!(hn = gg_gethostbyname(hostname))) { + if (!p->async) { + struct in_addr addr; + + if (!sess->server_addr) { + if ((addr.s_addr = inet_addr(hostname)) == INADDR_NONE) { + if (gg_gethostbyname_real(hostname, &addr, 0) == -1) { gg_debug(GG_DEBUG_MISC, "// gg_login() host \"%s\" not found\n", hostname); goto fail; - } else { - a.s_addr = hn->s_addr; - free(hn); } } } else { - a.s_addr = p->server_addr; - port = p->server_port; + addr.s_addr = sess->server_addr; + port = sess->port; } - sess->hub_addr = a.s_addr; + sess->hub_addr = addr.s_addr; if (gg_proxy_enabled) - sess->proxy_addr = a.s_addr; + sess->proxy_addr = addr.s_addr; + + if ((sess->fd = gg_connect(&addr, port, 0)) == -1) { + gg_debug(GG_DEBUG_MISC, "// gg_login() connection failed (errno=%d, %s)\n", errno, strerror(errno)); + + /* nie wysz�o? pr坦bujemy portu 443. */ + if (sess->server_addr) { + sess->port = GG_HTTPS_PORT; - if ((sess->fd = gg_connect(&a, port, 0)) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_login() connection failed (errno=%d, %s)\n", errno, strerror(errno)); - goto fail; + if ((sess->fd = gg_connect(&addr, GG_HTTPS_PORT, 0)) == -1) { + /* ostatnia deska ratunku zawiod�a? + * w takim razie zwijamy manatki. */ + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_login() connection failed (errno=%d, %s)\n", errno, strerror(errno)); + goto fail; + } + } else { + goto fail; + } } - if (p->server_addr && p->server_port) + if (sess->server_addr) sess->state = GG_STATE_CONNECTING_GG; else sess->state = GG_STATE_CONNECTING_HUB; @@ -1114,15 +907,9 @@ return sess; } - + if (!sess->server_addr || gg_proxy_enabled) { -#ifdef __GG_LIBGADU_HAVE_PTHREAD - if (gg_resolve_pthread(&sess->fd, &sess->resolver, hostname)) { -#elif defined _WIN32 - if (gg_resolve_win32thread(&sess->fd, &sess->resolver, hostname)) { -#else - if (gg_resolve(&sess->fd, &sess->pid, hostname)) { -#endif + if (sess->resolver_start(&sess->fd, &sess->resolver, hostname) == -1) { gg_debug(GG_DEBUG_MISC, "// gg_login() resolving failed (errno=%d, %s)\n", errno, strerror(errno)); goto fail; } @@ -1133,49 +920,121 @@ } sess->state = GG_STATE_CONNECTING_GG; sess->check = GG_CHECK_WRITE; + sess->soft_timeout = 1; } return sess; fail: if (sess) { - if (sess->password) - free(sess->password); - if (sess->initial_descr) - free(sess->initial_descr); + free(sess->password); + free(sess->initial_descr); free(sess); } - + return NULL; } -/* - * gg_free_session() +/** + * Wysy�a do serwera pakiet utrzymania po��czenia. + * + * Klient powinien regularnie co minut� wysy�a� pakiet utrzymania po��czenia, + * inaczej serwer uzna, 甜e klient straci� ��czno�� z sieci� i zerwie + * po��czenie. + * + * \param sess Struktura sesji + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du * - * pr�buje zamkn掩 po咳czenia i zwalnia pami裝 zajmowan� przez sesj�. + * \ingroup login + */ +int gg_ping(struct gg_session *sess) +{ + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_ping(%p);\n", sess); + + if (!sess) { + errno = EFAULT; + return -1; + } + + if (sess->state != GG_STATE_CONNECTED) { + errno = ENOTCONN; + return -1; + } + + return gg_send_packet(sess, GG_PING, NULL); +} + +/** + * Ko�czy po��czenie z serwerem. * - * - sess - opis sesji + * Funkcja nie zwalnia zasob坦w, wi�c po jej wywo�aniu nale甜y u甜y� + * \c gg_free_session(). Je�li chce si� ustawi� opis niedost�pno�ci, nale甜y + * wcze�niej wywo�a� funkcj� \c gg_change_status_descr() lub + * \c gg_change_status_descr_time(). + * + * \note Je�li w buforze nadawczym po��czenia z serwerem znajduj� si� jeszcze + * dane (np. z powodu strat pakiet坦w na ��czu), prawdopodobnie zostan� one + * utracone przy zrywaniu po��czenia. + * + * \param sess Struktura sesji + * + * \ingroup login */ -void gg_free_session(struct gg_session *sess) +void gg_logoff(struct gg_session *sess) { if (!sess) return; - /* XXX dopisa� zwalnianie i zamykanie wszystkiego, co mog�o zosta� */ + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_logoff(%p);\n", sess); + + if (GG_S_NA(sess->status)) + gg_change_status(sess, GG_STATUS_NOT_AVAIL); + +#ifdef GG_CONFIG_HAVE_OPENSSL + if (sess->ssl) + SSL_shutdown(sess->ssl); +#endif + + sess->resolver_cleanup(&sess->resolver, 1); - if (sess->password) - free(sess->password); - - if (sess->initial_descr) - free(sess->initial_descr); + if (sess->fd != -1) { + shutdown(sess->fd, SHUT_RDWR); + close(sess->fd); + sess->fd = -1; + } + + if (sess->send_buf) { + free(sess->send_buf); + sess->send_buf = NULL; + sess->send_left = 0; + } +} - if (sess->client_version) - free(sess->client_version); +/** + * Zwalnia zasoby u甜ywane przez po��czenie z serwerem. Funkcj� nale甜y wywo�a� + * po zamkni�ciu po��czenia z serwerem, by nie doprowadzi� do wycieku zasob坦w + * systemowych. + * + * \param sess Struktura sesji + * + * \ingroup login + */ +void gg_free_session(struct gg_session *sess) +{ + struct gg_dcc7 *dcc; - if (sess->header_buf) - free(sess->header_buf); + if (!sess) + return; + + /* XXX dopisa� zwalnianie i zamykanie wszystkiego, co mog�o zosta� */ -#ifdef __GG_LIBGADU_HAVE_OPENSSL + free(sess->password); + free(sess->initial_descr); + free(sess->client_version); + free(sess->header_buf); + +#ifdef GG_CONFIG_HAVE_OPENSSL if (sess->ssl) SSL_free(sess->ssl); @@ -1183,23 +1042,7 @@ SSL_CTX_free(sess->ssl_ctx); #endif -#ifdef __GG_LIBGADU_HAVE_PTHREAD - if (sess->resolver) { - pthread_cancel(*((pthread_t*) sess->resolver)); - free(sess->resolver); - sess->resolver = NULL; - } -#elif defined _WIN32 - if (sess->resolver) { - HANDLE h = sess->resolver; - TerminateThread(h, 0); - CloseHandle(h); - sess->resolver = NULL; - } -#else - if (sess->pid != -1) - waitpid(sess->pid, NULL, WNOHANG); -#endif + sess->resolver_cleanup(&sess->resolver, 1); if (sess->fd != -1) close(sess->fd); @@ -1207,24 +1050,37 @@ while (sess->images) gg_image_queue_remove(sess, sess->images, 1); + free(sess->send_buf); + + for (dcc = sess->dcc7_list; dcc; dcc = dcc->next) + dcc->sess = NULL; + free(sess); } -/* - * gg_change_status() +#ifndef DOXYGEN + +/** + * \internal Funkcja wysy�aj�ca pakiet zmiany statusu u甜ytkownika. * - * zmienia status u�ytkownika. przydatne do /away i /busy oraz /quit. + * \param sess Struktura sesji + * \param status Nowy status u甜ytkownika + * \param descr Opis statusu u甜ytkownika (lub \c NULL) + * \param time Czas powrotu w postaci uniksowego znacznika czasu (lub 0) * - * - sess - opis sesji - * - status - nowy status u�ytkownika + * \return 0 je�li si� powiod�o, -1 w przypadku b��du * - * 0, -1. + * \ingroup status */ -int gg_change_status(struct gg_session *sess, int status) +static int gg_change_status_common(struct gg_session *sess, int status, const char *descr, int time) { - struct gg_new_status p; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_change_status(%p, %d);\n", sess, status); + char *new_descr = NULL; + uint32_t new_time; + int descr_len = 0; + int descr_len_max; + int packet_type; + int append_null = 0; + int res; if (!sess) { errno = EFAULT; @@ -1236,67 +1092,422 @@ return -1; } - p.status = gg_fix32(status); + /* XXX, obcina� stany kt坦rych stary protok坦� niezna (czyt. dnd->aw; ffc->av) */ + + /* dodaj flag� obs�ugi po��cze� g�osowych zgodn� z GG 7.x */ + if ((sess->protocol_version >= 0x2a) && (sess->protocol_version < 0x2d /* ? */ ) && (sess->protocol_flags & GG_HAS_AUDIO_MASK) && !GG_S_I(status)) + status |= GG_STATUS_VOICE_MASK; sess->status = status; - return gg_send_packet(sess, GG_NEW_STATUS, &p, sizeof(p), NULL); + if (sess->protocol_version >= 0x2d) { + if (descr != NULL && sess->encoding != GG_ENCODING_UTF8) { + new_descr = gg_cp_to_utf8(descr); + + if (!new_descr) + return -1; + } + + if (sess->protocol_version >= 0x2e) + packet_type = GG_NEW_STATUS80; + else /* sess->protocol_version == 0x2d */ + packet_type = GG_NEW_STATUS80BETA; + descr_len_max = GG_STATUS_DESCR_MAXSIZE; + append_null = 1; + + } else { + packet_type = GG_NEW_STATUS; + descr_len_max = GG_STATUS_DESCR_MAXSIZE_PRE_8_0; + + if (time != 0) + append_null = 1; + } + + if (descr) { + descr_len = strlen((new_descr) ? new_descr : descr); + + if (descr_len > descr_len_max) + descr_len = descr_len_max; + + // XXX pami�ta� o tym, 甜eby nie ucina� w �rodku znaku utf-8 + } + + if (time) + new_time = gg_fix32(time); + + if (packet_type == GG_NEW_STATUS80) { + struct gg_new_status80 p; + + p.status = gg_fix32(status); + p.flags = gg_fix32(0x00800001); + p.description_size = gg_fix32(descr_len); + res = gg_send_packet(sess, + packet_type, + &p, + sizeof(p), + (new_descr) ? new_descr : descr, + descr_len, + NULL); + + } else { + struct gg_new_status p; + + p.status = gg_fix32(status); + res = gg_send_packet(sess, + packet_type, + &p, + sizeof(p), + (new_descr) ? new_descr : descr, + descr_len, + (append_null) ? "\0" : NULL, + (append_null) ? 1 : 0, + (time) ? &new_time : NULL, + (time) ? sizeof(new_time) : 0, + NULL); + } + + free(new_descr); + return res; } -/* - * gg_change_status_descr() +#endif /* DOXYGEN */ + +/** + * Zmienia status u甜ytkownika. * - * zmienia status u�ytkownika na opisowy. + * \param sess Struktura sesji + * \param status Nowy status u甜ytkownika + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du * - * - sess - opis sesji - * - status - nowy status u�ytkownika - * - descr - opis statusu + * \ingroup status + */ +int gg_change_status(struct gg_session *sess, int status) +{ + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_change_status(%p, %d);\n", sess, status); + + return gg_change_status_common(sess, status, NULL, 0); +} + +/** + * Zmienia status u甜ytkownika na status opisowy. * - * 0, -1. + * \param sess Struktura sesji + * \param status Nowy status u甜ytkownika + * \param descr Opis statusu u甜ytkownika + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup status */ int gg_change_status_descr(struct gg_session *sess, int status, const char *descr) { - struct gg_new_status p; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_change_status_descr(%p, %d, \"%s\");\n", sess, status, descr); - - if (!sess || !descr) { - errno = EFAULT; - return -1; - } + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_change_status_descr(%p, %d, \"%s\");\n", sess, status, descr); - if (sess->state != GG_STATE_CONNECTED) { - errno = ENOTCONN; - return -1; - } - - p.status = gg_fix32(status); - - sess->status = status; - - return gg_send_packet(sess, GG_NEW_STATUS, &p, sizeof(p), descr, (strlen(descr) > GG_STATUS_DESCR_MAXSIZE) ? GG_STATUS_DESCR_MAXSIZE : strlen(descr), NULL); + return gg_change_status_common(sess, status, descr, 0); } -/* - * gg_change_status_descr_time() - * - * zmienia status u�ytkownika na opisowy z godzin� powrotu. +/** + * Zmienia status u甜ytkownika na status opisowy z podanym czasem powrotu. * - * - sess - opis sesji - * - status - nowy status u�ytkownika - * - descr - opis statusu - * - time - czas w formacie uniksowym + * \param sess Struktura sesji + * \param status Nowy status u甜ytkownika + * \param descr Opis statusu u甜ytkownika + * \param time Czas powrotu w postaci uniksowego znacznika czasu * - * 0, -1. + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup status */ int gg_change_status_descr_time(struct gg_session *sess, int status, const char *descr, int time) { - struct gg_new_status p; - uint32_t newtime; + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_change_status_descr_time(%p, %d, \"%s\", %d);\n", sess, status, descr, time); + + return gg_change_status_common(sess, status, descr, time); +} + +/** + * Wysy�a wiadomo�� do u甜ytkownika. + * + * Zwraca losowy numer sekwencyjny, kt坦ry mo甜na zignorowa� albo wykorzysta� + * do potwierdzenia. + * + * \param sess Struktura sesji + * \param msgclass Klasa wiadomo�ci + * \param recipient Numer adresata + * \param message Tre�� wiadomo�ci + * + * \return Numer sekwencyjny wiadomo�ci lub -1 w przypadku b��du. + * + * \ingroup messages + */ +int gg_send_message(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message) +{ + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_message(%p, %d, %u, %p)\n", sess, msgclass, recipient, message); + + return gg_send_message_confer_richtext(sess, msgclass, 1, &recipient, message, NULL, 0); +} + +/** + * Wysy�a wiadomo�� formatowan�. + * + * Zwraca losowy numer sekwencyjny, kt坦ry mo甜na zignorowa� albo wykorzysta� + * do potwierdzenia. + * + * \param sess Struktura sesji + * \param msgclass Klasa wiadomo�ci + * \param recipient Numer adresata + * \param message Tre�� wiadomo�ci + * \param format Informacje o formatowaniu + * \param formatlen D�ugo�� informacji o formatowaniu + * + * \return Numer sekwencyjny wiadomo�ci lub -1 w przypadku b��du. + * + * \ingroup messages + */ +int gg_send_message_richtext(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, const unsigned char *format, int formatlen) +{ + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_message_richtext(%p, %d, %u, %p, %p, %d);\n", sess, msgclass, recipient, message, format, formatlen); + + return gg_send_message_confer_richtext(sess, msgclass, 1, &recipient, message, format, formatlen); +} + +/** + * Wysy�a wiadomo�� w ramach konferencji. + * + * Zwraca losowy numer sekwencyjny, kt坦ry mo甜na zignorowa� albo wykorzysta� + * do potwierdzenia. + * + * \param sess Struktura sesji + * \param msgclass Klasa wiadomo�ci + * \param recipients_count Liczba adresat坦w + * \param recipients Wska添nik do tablicy z numerami adresat坦w + * \param message Tre�� wiadomo�ci + * + * \return Numer sekwencyjny wiadomo�ci lub -1 w przypadku b��du. + * + * \ingroup messages + */ +int gg_send_message_confer(struct gg_session *sess, int msgclass, int recipients_count, uin_t *recipients, const unsigned char *message) +{ + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_message_confer(%p, %d, %d, %p, %p);\n", sess, msgclass, recipients_count, recipients, message); + + return gg_send_message_confer_richtext(sess, msgclass, recipients_count, recipients, message, NULL, 0); +} + +/** + * \internal Dodaje tekst na koniec bufora. + * + * \param dst Wska添nik na bufor roboczy + * \param pos Wska添nik na aktualne po�o甜enie w buforze roboczym + * \param src Dodawany tekst + * \param len D�ugo�� dodawanego tekstu + */ +static void gg_append(char *dst, int *pos, const void *src, int len) +{ + if (dst != NULL) + memcpy(&dst[*pos], src, len); + + *pos += len; +} + +/** + * \internal Zamienia tekst z formatowaniem Gadu-Gadu na HTML. + * + * \param dst Bufor wynikowy (mo甜e by� \c NULL) + * \param utf_msg Tekst 添r坦d�owy + * \param format Atrybuty tekstu 添r坦d�owego + * \param format_len D�ugo�� bloku atrybut坦w tekstu 添r坦d�owego + * + * \note Dokleja \c \\0 na ko�cu bufora wynikowego. + * + * \return D�ugo�� tekstu wynikowego bez \c \\0 (nawet je�li \c dst to \c NULL). + */ +static int gg_convert_to_html(char *dst, const char *utf_msg, const unsigned char *format, int format_len) +{ + const char span_fmt[] = "<span style=\"color:#%02x%02x%02x; font-family:'MS Shell Dlg 2'; font-size:9pt; \">"; + const int span_len = 75; + const char img_fmt[] = "<img src=\"%02x%02x%02x%02x%02x%02x%02x%02x\">"; + const int img_len = 28; + int char_pos = 0; + int format_idx = 3; + unsigned char old_attr = 0; + const unsigned char *color = (const unsigned char*) "\x00\x00\x00"; + int len, i; + + len = 0; + + for (i = 0; utf_msg[i] != 0; i++) { + unsigned char attr; + int attr_pos; + + if (format_idx + 3 <= format_len) { + attr_pos = format[format_idx] | (format[format_idx + 1] << 8); + attr = format[format_idx + 2]; + } else { + attr_pos = -1; + attr = 0; + } + + if (attr_pos == char_pos) { + format_idx += 3; + + if ((attr & (GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR)) != 0) { + if (char_pos != 0) { + if ((old_attr & GG_FONT_UNDERLINE) != 0) + gg_append(dst, &len, "</u>", 4); + + if ((old_attr & GG_FONT_ITALIC) != 0) + gg_append(dst, &len, "</i>", 4); + + if ((old_attr & GG_FONT_BOLD) != 0) + gg_append(dst, &len, "</b>", 4); - gg_debug(GG_DEBUG_FUNCTION, "** gg_change_status_descr_time(%p, %d, \"%s\", %d);\n", sess, status, descr, time); + gg_append(dst, &len, "</span>", 7); + } + + if (((attr & GG_FONT_COLOR) != 0) && (format_idx + 3 <= format_len)) { + color = &format[format_idx]; + format_idx += 3; + } else { + color = (const unsigned char*) "\x00\x00\x00"; + } + + if (dst != NULL) + sprintf(&dst[len], span_fmt, color[0], color[1], color[2]); + len += span_len; + } else if (char_pos == 0) { + if (dst != NULL) + sprintf(&dst[len], span_fmt, 0, 0, 0); + len += span_len; + } + + if ((attr & GG_FONT_BOLD) != 0) + gg_append(dst, &len, "<b>", 3); + + if ((attr & GG_FONT_ITALIC) != 0) + gg_append(dst, &len, "<i>", 3); + + if ((attr & GG_FONT_UNDERLINE) != 0) + gg_append(dst, &len, "<u>", 3); + + if (((attr & GG_FONT_IMAGE) != 0) && (format_idx + 10 <= format_len)) { + if (dst != NULL) { + sprintf(&dst[len], img_fmt, + format[format_idx + 9], + format[format_idx + 8], + format[format_idx + 7], + format[format_idx + 6], + format[format_idx + 5], + format[format_idx + 4], + format[format_idx + 3], + format[format_idx + 2]); + } + + len += img_len; + format_idx += 10; + } + + old_attr = attr; + } else if (i == 0) { + if (dst != NULL) + sprintf(&dst[len], span_fmt, 0, 0, 0); + + len += span_len; + } - if (!sess || !descr || !time) { + switch (utf_msg[i]) { + case '&': + gg_append(dst, &len, "&", 5); + break; + case '<': + gg_append(dst, &len, "<", 4); + break; + case '>': + gg_append(dst, &len, ">", 4); + break; + case '\'': + gg_append(dst, &len, "'", 6); + break; + case '\"': + gg_append(dst, &len, """, 6); + break; + case '\n': + gg_append(dst, &len, "<br>", 4); + break; + case '\r': + break; + default: + if (dst != NULL) + dst[len] = utf_msg[i]; + len++; + } + + /* Sprawd添, czy bajt nie jest kontynuacj� znaku unikodowego. */ + + if ((utf_msg[i] & 0xc0) != 0xc0) + char_pos++; + } + + if ((old_attr & GG_FONT_UNDERLINE) != 0) + gg_append(dst, &len, "</u>", 4); + + if ((old_attr & GG_FONT_ITALIC) != 0) + gg_append(dst, &len, "</i>", 4); + + if ((old_attr & GG_FONT_BOLD) != 0) + gg_append(dst, &len, "</b>", 4); + + /* Dla pustych tekst坦w dodaj pusty <span>. */ + + if (i == 0) { + if (dst != NULL) + sprintf(&dst[len], span_fmt, 0, 0, 0); + + len += span_len; + } + + gg_append(dst, &len, "</span>", 7); + + if (dst != NULL) + dst[len] = 0; + + return len; +} + +/** + * Wysy�a wiadomo�� formatowan� w ramach konferencji. + * + * Zwraca losowy numer sekwencyjny, kt坦ry mo甜na zignorowa� albo wykorzysta� + * do potwierdzenia. + * + * \param sess Struktura sesji + * \param msgclass Klasa wiadomo�ci + * \param recipients_count Liczba adresat坦w + * \param recipients Wska添nik do tablicy z numerami adresat坦w + * \param message Tre�� wiadomo�ci + * \param format Informacje o formatowaniu + * \param formatlen D�ugo�� informacji o formatowaniu + * + * \return Numer sekwencyjny wiadomo�ci lub -1 w przypadku b��du. + * + * \ingroup messages + */ +int gg_send_message_confer_richtext(struct gg_session *sess, int msgclass, int recipients_count, uin_t *recipients, const unsigned char *message, const unsigned char *format, int formatlen) +{ + struct gg_send_msg s; + struct gg_send_msg80 s80; + struct gg_msg_recipients r; + char *cp_msg = NULL; + char *utf_msg = NULL; + char *html_msg = NULL; + int seq_no; + int i, j, k; + uin_t *recps; + + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_message_confer_richtext(%p, %d, %d, %p, %p, %p, %d);\n", sess, msgclass, recipients_count, recipients, message, format, formatlen); + + if (!sess) { errno = EFAULT; return -1; } @@ -1306,75 +1517,184 @@ return -1; } - p.status = gg_fix32(status); + if (message == NULL || recipients_count <= 0 || recipients_count > 0xffff || (recipients_count != 1 && recipients == NULL)) { + errno = EINVAL; + return -1; + } + + if (sess->encoding == GG_ENCODING_UTF8) { + if (!(cp_msg = gg_utf8_to_cp((const char *) message))) + return -1; + + utf_msg = (char*) message; + } else { + if (sess->protocol_version >= 0x2d) { + if (!(utf_msg = gg_cp_to_utf8((const char *) message))) + return -1; + } + + cp_msg = (char*) message; + } + + if (sess->protocol_version < 0x2d) { + if (!sess->seq) + sess->seq = 0x01740000 | (rand() & 0xffff); + seq_no = sess->seq; + sess->seq += (rand() % 0x300) + 0x300; - sess->status = status; + s.msgclass = gg_fix32(msgclass); + s.seq = gg_fix32(seq_no); + } else { + int len; + + // Drobne odchylenie od protoko�u. Je�li wysy�amy kilka + // wiadomo�ci w ci�gu jednej sekundy, zwi�kszamy poprzedni� + // warto��, 甜eby ka甜da wiadomo�� mia�a unikalny numer. + + seq_no = time(NULL); + + if (seq_no <= sess->seq) + seq_no = sess->seq + 1; + + sess->seq = seq_no; + + if (format == NULL || formatlen < 3) { + format = (unsigned char*) "\x02\x06\x00\x00\x00\x08\x00\x00\x00"; + formatlen = 9; + } + + len = gg_convert_to_html(NULL, utf_msg, format, formatlen); + + html_msg = malloc(len + 1); + + if (html_msg == NULL) { + seq_no = -1; + goto cleanup; + } + + gg_convert_to_html(html_msg, utf_msg, format, formatlen); - newtime = gg_fix32(time); + s80.seq = gg_fix32(seq_no); + s80.msgclass = gg_fix32(msgclass); + s80.offset_plain = gg_fix32(sizeof(s80) + strlen(html_msg) + 1); + s80.offset_attr = gg_fix32(sizeof(s80) + strlen(html_msg) + 1 + strlen(cp_msg) + 1); + } + + if (recipients_count > 1) { + r.flag = 0x01; + r.count = gg_fix32(recipients_count - 1); + + recps = malloc(sizeof(uin_t) * recipients_count); + + if (!recps) { + seq_no = -1; + goto cleanup; + } + + for (i = 0; i < recipients_count; i++) { + for (j = 0, k = 0; j < recipients_count; j++) { + if (recipients[j] != recipients[i]) { + recps[k] = gg_fix32(recipients[j]); + k++; + } + } + + if (sess->protocol_version < 0x2d) { + s.recipient = gg_fix32(recipients[i]); - return gg_send_packet(sess, GG_NEW_STATUS, &p, sizeof(p), descr, (strlen(descr) > GG_STATUS_DESCR_MAXSIZE) ? GG_STATUS_DESCR_MAXSIZE : strlen(descr), &newtime, sizeof(newtime), NULL); + if (gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), cp_msg, strlen(cp_msg) + 1, &r, sizeof(r), recps, (recipients_count - 1) * sizeof(uin_t), format, formatlen, NULL) == -1) + seq_no = -1; + } else { + s80.recipient = gg_fix32(recipients[i]); + + if (gg_send_packet(sess, GG_SEND_MSG80, &s80, sizeof(s80), html_msg, strlen(html_msg) + 1, cp_msg, strlen(cp_msg) + 1, &r, sizeof(r), recps, (recipients_count - 1) * sizeof(uin_t), format, formatlen, NULL) == -1) + seq_no = -1; + } + } + + free(recps); + } else { + if (sess->protocol_version < 0x2d) { + s.recipient = gg_fix32(recipients[0]); + + if (gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), cp_msg, strlen(cp_msg) + 1, format, formatlen, NULL) == -1) + seq_no = -1; + } else { + s80.recipient = gg_fix32(recipients[0]); + + if (gg_send_packet(sess, GG_SEND_MSG80, &s80, sizeof(s80), html_msg, strlen(html_msg) + 1, cp_msg, strlen(cp_msg) + 1, format, formatlen, NULL) == -1) + seq_no = -1; + } + } + +cleanup: + if (cp_msg != (char*) message) + free(cp_msg); + + if (utf_msg != (char*) message) + free(utf_msg); + + free(html_msg); + + return seq_no; } -/* - * gg_logoff() +/** + * Wysy�a wiadomo�� binarn� przeznaczon� dla klienta. + * + * Wiadomo�ci mi�dzy klientami przesy�a si� np. w celu wywo�ania zwrotnego + * po��czenia bezpo�redniego. Funkcja zwraca losowy numer sekwencyjny, + * kt坦ry mo甜na zignorowa� albo wykorzysta� do potwierdzenia. * - * wylogowuje u�ytkownika i zamyka po咳czenie, ale nie zwalnia pami�ci. + * \param sess Struktura sesji + * \param msgclass Klasa wiadomo�ci + * \param recipient Numer adresata + * \param message Tre�� wiadomo�ci + * \param message_len D�ugo�� wiadomo�ci * - * - sess - opis sesji + * \return Numer sekwencyjny wiadomo�ci lub -1 w przypadku b��du. + * + * \ingroup messages */ -void gg_logoff(struct gg_session *sess) +int gg_send_message_ctcp(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, int message_len) { - if (!sess) - return; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_logoff(%p);\n", sess); - - if (GG_S_NA(sess->status & ~GG_STATUS_FRIENDS_MASK)) - gg_change_status(sess, GG_STATUS_NOT_AVAIL); - -#ifdef __GG_LIBGADU_HAVE_OPENSSL - if (sess->ssl) - SSL_shutdown(sess->ssl); -#endif + struct gg_send_msg s; -#ifdef __GG_LIBGADU_HAVE_PTHREAD - if (sess->resolver) { - pthread_cancel(*((pthread_t*) sess->resolver)); - free(sess->resolver); - sess->resolver = NULL; - } -#elif defined _WIN32 - if (sess->resolver) { - HANDLE h = sess->resolver; - TerminateThread(h, 0); - CloseHandle(h); - sess->resolver = NULL; + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_send_message_ctcp(%p, %d, %u, ...);\n", sess, msgclass, recipient); + + if (!sess) { + errno = EFAULT; + return -1; } -#else - if (sess->pid != -1) { - waitpid(sess->pid, NULL, WNOHANG); - sess->pid = -1; + + if (sess->state != GG_STATE_CONNECTED) { + errno = ENOTCONN; + return -1; } -#endif - - if (sess->fd != -1) { - shutdown(sess->fd, SHUT_RDWR); - close(sess->fd); - sess->fd = -1; - } + + s.recipient = gg_fix32(recipient); + s.seq = gg_fix32(0); + s.msgclass = gg_fix32(msgclass); + + return gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), message, message_len, NULL); } -/* - * gg_image_request() +/** + * Wysy�a 甜�danie obrazka o podanych parametrach. * - * wysy�a 娠danie wys�ania obrazka o podanych parametrach. + * Wiadomo�ci obrazkowe nie zawieraj� samych obrazk坦w, a tylko ich rozmiary + * i sumy kontrolne. Odbiorca najpierw szuka obrazk坦w w swojej pami�ci + * podr�cznej i dopiero gdy ich nie znajdzie, wysy�a 甜�danie do nadawcy. + * Wynik zostanie przekazany zdarzeniem \c GG_EVENT_IMAGE_REPLY. * - * - sess - opis sesji - * - recipient - numer adresata - * - size - rozmiar obrazka - * - crc32 - suma kontrolna obrazka + * \param sess Struktura sesji + * \param recipient Numer adresata + * \param size Rozmiar obrazka w bajtach + * \param crc32 Suma kontrola obrazka * - * 0/-1 + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup messages */ int gg_image_request(struct gg_session *sess, uin_t recipient, int size, uint32_t crc32) { @@ -1383,13 +1703,13 @@ char dummy = 0; int res; - gg_debug(GG_DEBUG_FUNCTION, "** gg_image_request(%p, %d, %u, 0x%.4x);\n", sess, recipient, size, crc32); + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_image_request(%p, %d, %u, 0x%.4x);\n", sess, recipient, size, crc32); if (!sess) { errno = EFAULT; return -1; } - + if (sess->state != GG_STATE_CONNECTED) { errno = ENOTCONN; return -1; @@ -1407,7 +1727,7 @@ r.flag = 0x04; r.size = gg_fix32(size); r.crc32 = gg_fix32(crc32); - + res = gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), &dummy, 1, &r, sizeof(r), NULL); if (!res) { @@ -1415,14 +1735,14 @@ char *buf; if (!q) { - gg_debug(GG_DEBUG_MISC, "// gg_image_request() not enough memory for image queue\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_image_request() not enough memory for image queue\n"); return -1; } buf = malloc(size); if (size && !buf) { - gg_debug(GG_DEBUG_MISC, "// gg_image_request() not enough memory for image\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_image_request() not enough memory for image\n"); free(q); return -1; } @@ -1449,20 +1769,20 @@ return res; } -/* - * gg_image_reply() - * - * wysy�a 娠dany obrazek. +/** + * Wysy�a 甜�dany obrazek. * - * - sess - opis sesji - * - recipient - numer adresata - * - filename - nazwa pliku - * - image - bufor z obrazkiem - * - size - rozmiar obrazka + * \param sess Struktura sesji + * \param recipient Numer adresata + * \param filename Nazwa pliku + * \param image Bufor z obrazkiem + * \param size Rozmiar obrazka * - * 0/-1 + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup messages */ -int gg_image_reply(struct gg_session *sess, uin_t recipient, const char *filename, const unsigned char *image, int size) +int gg_image_reply(struct gg_session *sess, uin_t recipient, const char *filename, const char *image, int size) { struct gg_msg_image_reply *r; struct gg_send_msg s; @@ -1470,7 +1790,7 @@ char buf[1910]; int res = -1; - gg_debug(GG_DEBUG_FUNCTION, "** gg_image_reply(%p, %d, \"%s\", %p, %d);\n", sess, recipient, filename, image, size); + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_image_reply(%p, %d, \"%s\", %p, %d);\n", sess, recipient, filename, image, size); if (!sess || !filename || !image) { errno = EFAULT; @@ -1487,7 +1807,7 @@ return -1; } - /* wytnij �cie�ki, zostaw tylko nazw� pliku */ + /* wytnij �cie甜ki, zostaw tylko nazw� pliku */ while ((tmp = strrchr(filename, '/')) || (tmp = strrchr(filename, '\\'))) filename = tmp + 1; @@ -1495,7 +1815,7 @@ errno = EINVAL; return -1; } - + s.recipient = gg_fix32(recipient); s.seq = gg_fix32(0); s.msgclass = gg_fix32(GG_CLASS_MSG); @@ -1505,26 +1825,26 @@ r->flag = 0x05; r->size = gg_fix32(size); - r->crc32 = gg_fix32(gg_crc32(0, image, size)); + r->crc32 = gg_fix32(gg_crc32(0, (unsigned char*) image, size)); while (size > 0) { - size_t buflen, chunklen; - + int buflen, chunklen; + /* \0 + struct gg_msg_image_reply */ buflen = sizeof(struct gg_msg_image_reply) + 1; - /* w pierwszym kawa�ku jest nazwa pliku */ + /* w pierwszym kawa�ku jest nazwa pliku */ if (r->flag == 0x05) { strcpy(buf + buflen, filename); buflen += strlen(filename) + 1; } - chunklen = ((size_t)size >= sizeof(buf) - buflen) ? (sizeof(buf) - buflen) : (size_t)size; + chunklen = (size >= sizeof(buf) - buflen) ? (sizeof(buf) - buflen) : size; memcpy(buf + buflen, image, chunklen); size -= chunklen; image += chunklen; - + res = gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), buf, buflen + chunklen, NULL); if (res == -1) @@ -1536,83 +1856,34 @@ return res; } -/* - * gg_send_message_ctcp() +/** + * Wysy�a do serwera list� kontakt坦w. * - * wysy�a wiadomo倶 do innego u�ytkownika. zwraca losowy numer - * sekwencyjny, kt�ry mo�na zignorowa� albo wykorzysta� do potwierdzenia. + * Funkcja informuje serwer o li�cie kontakt坦w, kt坦rych statusy b�d� + * obserwowane lub kontakt坦w, kt坦re bed� blokowane. Dla ka甜dego z \c count + * kontakt坦w tablica \c userlist zawiera numer, a tablica \c types rodzaj + * kontaktu (\c GG_USER_NORMAL, \c GG_USER_OFFLINE, \c GG_USER_BLOCKED). + * + * List� kontakt坦w nale甜y \b zawsze wysy�a� po po��czeniu, nawet je�li + * jest pusta. * - * - sess - opis sesji - * - msgclass - rodzaj wiadomo�ci - * - recipient - numer adresata - * - message - tre倶 wiadomo�ci - * - message_len - d�ugo倶 + * \param sess Struktura sesji + * \param userlist Wska添nik do tablicy numer坦w kontakt坦w + * \param types Wska添nik do tablicy rodzaj坦w kontakt坦w + * \param count Liczba kontakt坦w * - * numer sekwencyjny wiadomo�ci lub -1 w przypadku b滑du. + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup contacts */ -int gg_send_message_ctcp(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, int message_len) +int gg_notify_ex(struct gg_session *sess, uin_t *userlist, char *types, int count) { - struct gg_send_msg s; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message_ctcp(%p, %d, %u, ...);\n", sess, msgclass, recipient); - - if (!sess) { - errno = EFAULT; - return -1; - } - - if (sess->state != GG_STATE_CONNECTED) { - errno = ENOTCONN; - return -1; - } - - s.recipient = gg_fix32(recipient); - s.seq = gg_fix32(0); - s.msgclass = gg_fix32(msgclass); - - return gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), message, message_len, NULL); -} + struct gg_notify *n; + uin_t *u; + char *t; + int i, res = 0; -/* - * gg_send_message() - * - * wysy�a wiadomo倶 do innego u�ytkownika. zwraca losowy numer - * sekwencyjny, kt�ry mo�na zignorowa� albo wykorzysta� do potwierdzenia. - * - * - sess - opis sesji - * - msgclass - rodzaj wiadomo�ci - * - recipient - numer adresata - * - message - tre倶 wiadomo�ci - * - * numer sekwencyjny wiadomo�ci lub -1 w przypadku b滑du. - */ -int gg_send_message(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message) -{ - gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message(%p, %d, %u, %p)\n", sess, msgclass, recipient, message); - - return gg_send_message_richtext(sess, msgclass, recipient, message, NULL, 0); -} - -/* - * gg_send_message_richtext() - * - * wysy�a kolorow� wiadomo倶 do innego u�ytkownika. zwraca losowy numer - * sekwencyjny, kt�ry mo�na zignorowa� albo wykorzysta� do potwierdzenia. - * - * - sess - opis sesji - * - msgclass - rodzaj wiadomo�ci - * - recipient - numer adresata - * - message - tre倶 wiadomo�ci - * - format - informacje o formatowaniu - * - formatlen - d�ugo倶 informacji o formatowaniu - * - * numer sekwencyjny wiadomo�ci lub -1 w przypadku b滑du. - */ -int gg_send_message_richtext(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, const unsigned char *format, int formatlen) -{ - struct gg_send_msg s; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message_richtext(%p, %d, %u, %p, %p, %d);\n", sess, msgclass, recipient, message, format, formatlen); + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_notify_ex(%p, %p, %p, %d);\n", sess, userlist, types, count); if (!sess) { errno = EFAULT; @@ -1624,186 +1895,12 @@ return -1; } - if (!message) { - errno = EFAULT; - return -1; - } - - s.recipient = gg_fix32(recipient); - if (!sess->seq) - sess->seq = 0x01740000 | (rand() & 0xffff); - s.seq = gg_fix32(sess->seq); - s.msgclass = gg_fix32(msgclass); - sess->seq += (rand() % 0x300) + 0x300; - - if (gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), message, strlen((const char *)message) + 1, format, formatlen, NULL) == -1) - return -1; - - return gg_fix32(s.seq); -} - -/* - * gg_send_message_confer() - * - * wysy�a wiadomo倶 do kilku u�ytkownikow (konferencja). zwraca losowy numer - * sekwencyjny, kt�ry mo�na zignorowa� albo wykorzysta� do potwierdzenia. - * - * - sess - opis sesji - * - msgclass - rodzaj wiadomo�ci - * - recipients_count - ilo倶 adresat�w - * - recipients - numerki adresat�w - * - message - tre倶 wiadomo�ci - * - * numer sekwencyjny wiadomo�ci lub -1 w przypadku b滑du. - */ -int gg_send_message_confer(struct gg_session *sess, int msgclass, int recipients_count, uin_t *recipients, const unsigned char *message) -{ - gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message_confer(%p, %d, %d, %p, %p);\n", sess, msgclass, recipients_count, recipients, message); - - return gg_send_message_confer_richtext(sess, msgclass, recipients_count, recipients, message, NULL, 0); -} - -/* - * gg_send_message_confer_richtext() - * - * wysy�a kolorow� wiadomo倶 do kilku u�ytkownikow (konferencja). zwraca - * losowy numer sekwencyjny, kt�ry mo�na zignorowa� albo wykorzysta� do - * potwierdzenia. - * - * - sess - opis sesji - * - msgclass - rodzaj wiadomo�ci - * - recipients_count - ilo倶 adresat�w - * - recipients - numerki adresat�w - * - message - tre倶 wiadomo�ci - * - format - informacje o formatowaniu - * - formatlen - d�ugo倶 informacji o formatowaniu - * - * numer sekwencyjny wiadomo�ci lub -1 w przypadku b滑du. - */ -int gg_send_message_confer_richtext(struct gg_session *sess, int msgclass, int recipients_count, uin_t *recipients, const unsigned char *message, const unsigned char *format, int formatlen) -{ - struct gg_send_msg s; - struct gg_msg_recipients r; - int i, j, k; - uin_t *recps; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message_confer_richtext(%p, %d, %d, %p, %p, %p, %d);\n", sess, msgclass, recipients_count, recipients, message, format, formatlen); - - if (!sess) { - errno = EFAULT; - return -1; - } - - if (sess->state != GG_STATE_CONNECTED) { - errno = ENOTCONN; - return -1; - } - - if (!message || recipients_count <= 0 || recipients_count > 0xffff || !recipients) { - errno = EINVAL; - return -1; - } - - r.flag = 0x01; - r.count = gg_fix32(recipients_count - 1); - - if (!sess->seq) - sess->seq = 0x01740000 | (rand() & 0xffff); - s.seq = gg_fix32(sess->seq); - s.msgclass = gg_fix32(msgclass); - - recps = malloc(sizeof(uin_t) * recipients_count); - if (!recps) - return -1; - - for (i = 0; i < recipients_count; i++) { - - s.recipient = gg_fix32(recipients[i]); - - for (j = 0, k = 0; j < recipients_count; j++) - if (recipients[j] != recipients[i]) { - recps[k] = gg_fix32(recipients[j]); - k++; - } - - if (!i) - sess->seq += (rand() % 0x300) + 0x300; - - if (gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), message, strlen((const char *)message) + 1, &r, sizeof(r), recps, (recipients_count - 1) * sizeof(uin_t), format, formatlen, NULL) == -1) { - free(recps); - return -1; - } - } - - free(recps); - - return gg_fix32(s.seq); -} - -/* - * gg_ping() - * - * wysy�a do serwera pakiet ping. - * - * - sess - opis sesji - * - * 0, -1. - */ -int gg_ping(struct gg_session *sess) -{ - gg_debug(GG_DEBUG_FUNCTION, "** gg_ping(%p);\n", sess); - - if (!sess) { - errno = EFAULT; - return -1; - } - - if (sess->state != GG_STATE_CONNECTED) { - errno = ENOTCONN; - return -1; - } - - return gg_send_packet(sess, GG_PING, NULL); -} - -/* - * gg_notify_ex() - * - * wysy�a serwerowi list� kontakt�w (wraz z odpowiadaj�cymi im typami user�w), - * dzi�ki czemu wie, czyj stan nas interesuje. - * - * - sess - opis sesji - * - userlist - wska�nik do tablicy numer�w - * - types - wska�nik do tablicy typ�w u�ytkownik�w - * - count - ilo倶 numerk�w - * - * 0, -1. - */ -int gg_notify_ex(struct gg_session *sess, uin_t *userlist, char *types, int count) -{ - struct gg_notify *n; - uin_t *u; - char *t; - int i, res = 0; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_notify_ex(%p, %p, %p, %d);\n", sess, userlist, types, count); - - if (!sess) { - errno = EFAULT; - return -1; - } - - if (sess->state != GG_STATE_CONNECTED) { - errno = ENOTCONN; - return -1; - } - if (!userlist || !count) return gg_send_packet(sess, GG_LIST_EMPTY, NULL); - + while (count > 0) { int part_count, packet_type; - + if (count > 400) { part_count = 400; packet_type = GG_NOTIFY_FIRST; @@ -1814,12 +1911,12 @@ if (!(n = (struct gg_notify*) malloc(sizeof(*n) * part_count))) return -1; - - for (u = userlist, t = types, i = 0; i < part_count; u++, t++, i++) { + + for (u = userlist, t = types, i = 0; i < part_count; u++, t++, i++) { n[i].uin = gg_fix32(*u); n[i].dunno1 = *t; } - + if (gg_send_packet(sess, packet_type, n, sizeof(*n) * part_count, NULL) == -1) { free(n); res = -1; @@ -1836,17 +1933,19 @@ return res; } -/* - * gg_notify() +/** + * Wysy�a do serwera list� kontakt坦w. * - * wysy�a serwerowi list� kontakt�w, dzi�ki czemu wie, czyj stan nas - * interesuje. + * Funkcja jest odpowiednikiem \c gg_notify_ex(), gdzie wszystkie kontakty + * s� rodzaju \c GG_USER_NORMAL. * - * - sess - opis sesji - * - userlist - wska�nik do tablicy numer�w - * - count - ilo倶 numerk�w + * \param sess Struktura sesji + * \param userlist Wska添nik do tablicy numer坦w kontakt坦w + * \param count Liczba kontakt坦w * - * 0, -1. + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup contacts */ int gg_notify(struct gg_session *sess, uin_t *userlist, int count) { @@ -1854,13 +1953,13 @@ uin_t *u; int i, res = 0; - gg_debug(GG_DEBUG_FUNCTION, "** gg_notify(%p, %p, %d);\n", sess, userlist, count); - + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_notify(%p, %p, %d);\n", sess, userlist, count); + if (!sess) { errno = EFAULT; return -1; } - + if (sess->state != GG_STATE_CONNECTED) { errno = ENOTCONN; return -1; @@ -1868,10 +1967,10 @@ if (!userlist || !count) return gg_send_packet(sess, GG_LIST_EMPTY, NULL); - + while (count > 0) { int part_count, packet_type; - + if (count > 400) { part_count = 400; packet_type = GG_NOTIFY_FIRST; @@ -1879,15 +1978,15 @@ part_count = count; packet_type = GG_NOTIFY_LAST; } - + if (!(n = (struct gg_notify*) malloc(sizeof(*n) * part_count))) return -1; - - for (u = userlist, i = 0; i < part_count; u++, i++) { + + for (u = userlist, i = 0; i < part_count; u++, i++) { n[i].uin = gg_fix32(*u); n[i].dunno1 = GG_USER_NORMAL; } - + if (gg_send_packet(sess, packet_type, n, sizeof(*n) * part_count, NULL) == -1) { res = -1; free(n); @@ -1903,73 +2002,27 @@ return res; } -/* - * gg_add_notify_ex() +/** + * Dodaje kontakt. * - * dodaje do listy kontakt�w dany numer w trakcie po咳czenia. - * dodawanemu u�ytkownikowi okre�lamy jego typ (patrz protocol.html) + * Dodaje do listy kontakt坦w dany numer w trakcie po��czenia. Aby zmieni� + * rodzaj kontaktu (np. z normalnego na zablokowany), nale甜y najpierw usun�� + * poprzedni rodzaj, poniewa甜 serwer operuje na maskach bitowych. * - * - sess - opis sesji - * - uin - numer - * - type - typ + * \param sess Struktura sesji + * \param uin Numer kontaktu + * \param type Rodzaj kontaktu * - * 0, -1. + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup contacts */ int gg_add_notify_ex(struct gg_session *sess, uin_t uin, char type) { struct gg_add_remove a; - gg_debug(GG_DEBUG_FUNCTION, "** gg_add_notify_ex(%p, %u, %d);\n", sess, uin, type); - - if (!sess) { - errno = EFAULT; - return -1; - } - - if (sess->state != GG_STATE_CONNECTED) { - errno = ENOTCONN; - return -1; - } - - a.uin = gg_fix32(uin); - a.dunno1 = type; - - return gg_send_packet(sess, GG_ADD_NOTIFY, &a, sizeof(a), NULL); -} + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_add_notify_ex(%p, %u, %d);\n", sess, uin, type); -/* - * gg_add_notify() - * - * dodaje do listy kontakt�w dany numer w trakcie po咳czenia. - * - * - sess - opis sesji - * - uin - numer - * - * 0, -1. - */ -int gg_add_notify(struct gg_session *sess, uin_t uin) -{ - return gg_add_notify_ex(sess, uin, GG_USER_NORMAL); -} - -/* - * gg_remove_notify_ex() - * - * usuwa z listy kontakt�w w trakcie po咳czenia. - * usuwanemu u�ytkownikowi okre�lamy jego typ (patrz protocol.html) - * - * - sess - opis sesji - * - uin - numer - * - type - typ - * - * 0, -1. - */ -int gg_remove_notify_ex(struct gg_session *sess, uin_t uin, char type) -{ - struct gg_add_remove a; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_remove_notify_ex(%p, %u, %d);\n", sess, uin, type); - if (!sess) { errno = EFAULT; return -1; @@ -1982,35 +2035,101 @@ a.uin = gg_fix32(uin); a.dunno1 = type; - + + return gg_send_packet(sess, GG_ADD_NOTIFY, &a, sizeof(a), NULL); +} + +/** + * Dodaje kontakt. + * + * Funkcja jest odpowiednikiem \c gg_add_notify_ex(), gdzie rodzaj wszystkich + * kontakt坦w to \c GG_USER_NORMAL. + * + * \param sess Struktura sesji + * \param uin Numer kontaktu + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup contacts + */ +int gg_add_notify(struct gg_session *sess, uin_t uin) +{ + return gg_add_notify_ex(sess, uin, GG_USER_NORMAL); +} + +/** + * Usuwa kontakt. + * + * Usuwa z listy kontakt坦w dany numer w trakcie po��czenia. + * + * \param sess Struktura sesji + * \param uin Numer kontaktu + * \param type Rodzaj kontaktu + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup contacts + */ +int gg_remove_notify_ex(struct gg_session *sess, uin_t uin, char type) +{ + struct gg_add_remove a; + + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_remove_notify_ex(%p, %u, %d);\n", sess, uin, type); + + if (!sess) { + errno = EFAULT; + return -1; + } + + if (sess->state != GG_STATE_CONNECTED) { + errno = ENOTCONN; + return -1; + } + + a.uin = gg_fix32(uin); + a.dunno1 = type; + return gg_send_packet(sess, GG_REMOVE_NOTIFY, &a, sizeof(a), NULL); } -/* - * gg_remove_notify() +/** + * Usuwa kontakt. * - * usuwa z listy kontakt�w w trakcie po咳czenia. + * Funkcja jest odpowiednikiem \c gg_add_notify_ex(), gdzie rodzaj wszystkich + * kontakt坦w to \c GG_USER_NORMAL. * - * - sess - opis sesji - * - uin - numer + * \param sess Struktura sesji + * \param uin Numer kontaktu * - * 0, -1. + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup contacts */ int gg_remove_notify(struct gg_session *sess, uin_t uin) { return gg_remove_notify_ex(sess, uin, GG_USER_NORMAL); } -/* - * gg_userlist_request() +/** + * Wysy�a do serwera zapytanie dotycz�ce listy kontakt坦w. * - * wysy�a 娠danie/zapytanie listy kontakt�w na serwerze. + * Funkcja s�u甜y do importu lub eksportu listy kontakt坦w do serwera. + * W odr坦甜nieniu od funkcji \c gg_notify(), ta lista kontakt坦w jest przez + * serwer jedynie przechowywana i nie ma wp�ywu na po��czenie. Format + * listy kontakt坦w jest ignorowany przez serwer, ale ze wzgl�du na + * kompatybilno�� z innymi klientami, nale甜y przechowywa� dane w tym samym + * formacie co oryginalny klient Gadu-Gadu. * - * - sess - opis sesji - * - type - rodzaj zapytania/娠dania - * - request - tre倶 zapytania/娠dania (mo�e by� NULL) + * Program nie musi si� przejmowa� fragmentacj� listy kontakt坦w wynikaj�c� + * z protoko�u -- wysy�a i odbiera kompletn� list�. * - * 0, -1 + * \param sess Struktura sesji + * \param type Rodzaj zapytania + * \param request Tre�� zapytania (mo甜e by� r坦wne NULL) + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup importexport */ int gg_userlist_request(struct gg_session *sess, char type, const char *request) { @@ -2020,7 +2139,7 @@ errno = EFAULT; return -1; } - + if (sess->state != GG_STATE_CONNECTED) { errno = ENOTCONN; return -1; @@ -2030,7 +2149,7 @@ sess->userlist_blocks = 1; return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), NULL); } - + len = strlen(request); sess->userlist_blocks = 0; @@ -2053,6 +2172,8 @@ return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), request, len, NULL); } +/* @} */ + /* * Local variables: * c-indentation-style: k&r
--- a/libpurple/protocols/gg/lib/libgadu.h Sun Feb 28 23:42:12 2010 +0000 +++ b/libpurple/protocols/gg/lib/libgadu.h Mon Mar 01 03:46:33 2010 +0000 @@ -1,12 +1,13 @@ -/* $Id: libgadu.h 16856 2006-08-19 01:13:25Z evands $ */ +/* $Id: libgadu.h.in 878 2009-11-16 23:48:19Z wojtekka $ */ /* - * (C) Copyright 2001-2003 Wojtek Kaniewski <wojtekka@irc.pl> - * Robert J. Wo�ny <speedy@ziew.org> - * Arkadiusz Mi�kiewicz <arekm@pld-linux.org> - * Tomasz Chili�ski <chilek@chilan.com> + * (C) Copyright 2001-2009 Wojtek Kaniewski <wojtekka@irc.pl> + * Robert J. Wo添ny <speedy@ziew.org> + * Arkadiusz Mi�kiewicz <arekm@pld-linux.org> + * Tomasz Chili�ski <chilek@chilan.com> * Piotr Wysocki <wysek@linux.bydg.org> * Dawid Jarosz <dawjar@poczta.onet.pl> + * Jakub Zawadzki <darkjames@darkjames.ath.cx> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License Version @@ -19,338 +20,567 @@ * * 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. */ +/** + * \file libgadu.h + * + * \brief G�坦wny plik nag�坦wkowy biblioteki + */ + #ifndef __GG_LIBGADU_H #define __GG_LIBGADU_H #ifdef __cplusplus -#ifdef _MSC_VER +#ifdef _WIN32 #pragma pack(push, 1) #endif extern "C" { #endif -#include <libgadu-config.h> #include <sys/types.h> #include <stdio.h> #include <stdarg.h> -#ifdef __GG_LIBGADU_HAVE_OPENSSL +/** \cond ignore */ + +/* Defined if libgadu was compiled for bigendian machine. */ +#undef GG_CONFIG_BIGENDIAN + +/* Defined if this machine has gethostbyname_r(). */ +#undef GG_CONFIG_HAVE_GETHOSTBYNAME_R + +/* Defined if libgadu was compiled and linked with pthread support. */ +#undef GG_CONFIG_HAVE_PTHREAD + +/* Defined if pthread resolver is the default one. */ +#undef GG_CONFIG_PTHREAD_DEFAULT + +/* Defined if this machine has C99-compiliant vsnprintf(). */ +#undef GG_CONFIG_HAVE_C99_VSNPRINTF + +/* Defined if this machine has va_copy(). */ +#undef GG_CONFIG_HAVE_VA_COPY + +/* Defined if this machine has __va_copy(). */ +#undef GG_CONFIG_HAVE___VA_COPY + +/* Defined if this machine supports long long. */ +#undef GG_CONFIG_HAVE_LONG_LONG + +/* Defined if libgadu was compiled and linked with TLS support. */ +#undef GG_CONFIG_HAVE_OPENSSL + +/* Defined if uintX_t types are defined in <stdint.h>. */ +#undef GG_CONFIG_HAVE_STDINT_H + +/* Defined if uintX_t types are defined in <inttypes.h>. */ +#undef GG_CONFIG_HAVE_INTTYPES_H + +/* Defined if uintX_t types are defined in <sys/inttypes.h>. */ +#undef GG_CONFIG_HAVE_SYS_INTTYPES_H + +/* Defined if uintX_t types are defined in <sys/int_types.h>. */ +#undef GG_CONFIG_HAVE_SYS_INT_TYPES_H + +/* Defined if uintX_t types are defined in <sys/types.h>. */ +#undef GG_CONFIG_HAVE_SYS_TYPES_H + +#ifdef GG_CONFIG_HAVE_OPENSSL #include <openssl/ssl.h> #endif -/* - * typedef uin_t - * - * typ reprezentuj�cy numer osoby. +#ifdef GG_CONFIG_HAVE_STDINT_H +#include <stdint.h> +#else +# ifdef GG_CONFIG_HAVE_INTTYPES_H +# include <inttypes.h> +# else +# ifdef GG_CONFIG_HAVE_SYS_INTTYPES_H +# include <sys/inttypes.h> +# else +# ifdef GG_CONFIG_HAVE_SYS_INT_TYPES_H +# include <sys/int_types.h> +# else +# ifdef GG_CONFIG_HAVE_SYS_TYPES_H +# include <sys/types.h> +# else + +#ifndef __AC_STDINT_H +#define __AC_STDINT_H + +/* ISO C 9X: 7.18 Integer types <stdint.h> */ + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; + +#ifndef __CYGWIN__ +#define __int8_t_defined +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +#endif + +#endif /* __AC_STDINT_H */ + +# endif +# endif +# endif +# endif +#endif + +/** \endcond */ + +/** + * Numer Gadu-Gadu. */ typedef uint32_t uin_t; -/* - * og�lna struktura opisuj�ca r鷽ne sesje. przydatna w klientach. +/** + * Identyfikator po��czenia bezpo�redniego Gadu-Gadu 7.x. + */ +typedef struct { + uint8_t id[8]; +} gg_dcc7_id_t; + +/** + * Makro deklaruj�ce pola wsp坦lne dla struktur sesji. */ #define gg_common_head(x) \ - int fd; /* podgl�dany deskryptor */ \ - int check; /* sprawdzamy zapis czy odczyt */ \ - int state; /* aktualny stan maszynki */ \ - int error; /* kod b滑du dla GG_STATE_ERROR */ \ - int type; /* rodzaj sesji */ \ - int id; /* identyfikator */ \ - int timeout; /* sugerowany timeout w sekundach */ \ - int (*callback)(x*); /* callback przy zmianach */ \ - void (*destroy)(x*); /* funkcja niszczenia */ + int fd; /**< Obserwowany deskryptor */ \ + int check; /**< Informacja o 甜�daniu odczytu/zapisu (patrz \ref gg_check_t) */ \ + int state; /**< Aktualny stan po��czenia (patrz \ref gg_state_t) */ \ + int error; /**< Kod b��du dla \c GG_STATE_ERROR (patrz \ref gg_error_t) */ \ + int type; /**< Rodzaj sesji (patrz \ref gg_session_t) */ \ + int id; /**< Identyfikator sesji */ \ + int timeout; /**< Czas pozosta�y do zako�czenia stanu */ \ + int (*callback)(x*); /**< Funkcja zwrotna */ \ + void (*destroy)(x*); /**< Funkcja zwalniania zasob坦w */ +/** + * Struktura wsp坦lna dla wszystkich sesji i po��cze�. Pozwala na proste + * rzutowanie niezale甜ne od rodzaju po��czenia. + */ struct gg_common { gg_common_head(struct gg_common) }; struct gg_image_queue; -/* - * struct gg_session +struct gg_dcc7; + +/** + * Spos坦b rozwi�zywania nazw serwer坦w. + */ +typedef enum { + GG_RESOLVER_DEFAULT = 0, /**< Domy�lny spos坦b rozwi�zywania nazw (jeden z poni甜szych) */ + GG_RESOLVER_FORK, /**< Rozwi�zywanie nazw bazuj�ce na procesach */ + GG_RESOLVER_PTHREAD, /**< Rozwi�zywanie nazw bazuj�ce na w�tkach */ + GG_RESOLVER_CUSTOM, /**< Funkcje rozwi�zywania nazw dostarczone przed aplikacj� */ + GG_RESOLVER_INVALID = -1 /**< Nieprawid�owy spos坦b rozwi�zywania nazw (wynik \c gg_session_get_resolver) */ +} gg_resolver_t; + +/** + * Rodzaj kodowania znak坦w. + */ +typedef enum { + GG_ENCODING_CP1250 = 0, /**< Kodowanie CP1250 */ + GG_ENCODING_UTF8, /**< Kodowanie UTF-8 */ + GG_ENCODING_INVALID = -1 /**< Nieprawid�owe kodowanie */ +} gg_encoding_t; + +/** + * Sesja Gadu-Gadu. * - * struktura opisuj�ca dan� sesj�. tworzona przez gg_login(), zwalniana - * przez gg_free_session(). + * Tworzona przez funkcj� \c gg_login(), zwalniana przez \c gg_free_session(). + * + * \ingroup login */ struct gg_session { gg_common_head(struct gg_session) - int async; /* czy po咳czenie jest asynchroniczne */ - int pid; /* pid procesu resolvera */ - int port; /* port, z kt�rym si� 咳czymy */ - int seq; /* numer sekwencyjny ostatniej wiadomo�ci */ - int last_pong; /* czas otrzymania ostatniego ping/pong */ - int last_event; /* czas otrzymania ostatniego pakietu */ + int async; /**< Flaga po��czenia asynchronicznego */ + int pid; /**< Numer procesu rozwi�zuj�cego nazw� serwera */ + int port; /**< Port serwera */ + int seq; /**< Numer sekwencyjny ostatniej wiadomo�ci */ + int last_pong; /**< Czas otrzymania ostatniej ramki utrzymaniowej */ + int last_event; /**< Czas otrzymania ostatniego pakietu */ - struct gg_event *event; /* zdarzenie po ->callback() */ + struct gg_event *event; /**< Zdarzenie po wywo�aniu \c callback */ - uint32_t proxy_addr; /* adres proxy, keszowany */ - uint16_t proxy_port; /* port proxy */ + uint32_t proxy_addr; /**< Adres serwera po�rednicz�cego */ + uint16_t proxy_port; /**< Port serwera po�rednicz�cego */ - uint32_t hub_addr; /* adres huba po resolvni�ciu */ - uint32_t server_addr; /* adres serwera, od huba */ + uint32_t hub_addr; /**< Adres huba po rozwi�zaniu nazwy */ + uint32_t server_addr; /**< Adres serwera otrzymany od huba */ - uint32_t client_addr; /* adres klienta */ - uint16_t client_port; /* port, na kt�rym klient s�ucha */ + uint32_t client_addr; /**< Adres gniazda dla po��cze� bezpo�rednich do wersji Gadu-Gadu 6.x */ + uint16_t client_port; /**< Port gniazda dla po��cze� bezpo�rednich do wersji Gadu-Gadu 6.x */ - uint32_t external_addr; /* adres zewnetrzny klienta */ - uint16_t external_port; /* port zewnetrzny klienta */ + uint32_t external_addr; /**< Publiczny adres dla po��cze� bezpo�rednich do wersji Gadu-Gadu 6.x */ + uint16_t external_port; /**< Publiczny port dla po��cze� bezpo�rednich do wersji Gadu-Gadu 6.x */ - uin_t uin; /* numerek klienta */ - char *password; /* i jego has�o. zwalniane automagicznie */ + uin_t uin; /**< W�asny numer Gadu-Gadu */ + char *password; /**< Has�o (zwalniane po u甜yciu) */ - int initial_status; /* pocz�tkowy stan klienta */ - int status; /* aktualny stan klienta */ + int initial_status; /**< Pocz�tkowy status */ + int status; /**< Aktualny status */ - char *recv_buf; /* bufor na otrzymywane pakiety */ - int recv_done; /* ile ju� wczytano do bufora */ - int recv_left; /* i ile jeszcze trzeba wczyta� */ + char *recv_buf; /**< Bufor na odbierany pakiety */ + int recv_done; /**< Liczba wczytanych bajt坦w pakietu */ + int recv_left; /**< Liczba pozosta�ych do wczytania bajt坦w pakietu */ - int protocol_version; /* wersja u�ywanego protoko�u */ - char *client_version; /* wersja u�ywanego klienta */ - int last_sysmsg; /* ostatnia wiadomo倶 systemowa */ + int protocol_version; /**< Wersja protoko�u (bez flag) */ + char *client_version; /**< Wersja klienta */ + int last_sysmsg; /**< Numer ostatniej wiadomo�ci systemowej */ - char *initial_descr; /* pocz�tkowy opis stanu klienta */ + char *initial_descr; /**< Pocz�tkowy opis statusu */ - void *resolver; /* wska�nik na informacje resolvera */ + void *resolver; /**< Dane prywatne procesu lub w�tku rozwi�zuj�cego nazw� serwera */ - char *header_buf; /* bufor na pocz�tek nag鞄wka */ - unsigned int header_done;/* ile ju� mamy */ + char *header_buf; /**< Bufor na pocz�tek nag�坦wka pakietu */ + unsigned int header_done; /**< Liczba wczytanych bajt坦w nag�坦wka pakietu */ -#ifdef __GG_LIBGADU_HAVE_OPENSSL - SSL *ssl; /* sesja TLS */ - SSL_CTX *ssl_ctx; /* kontekst sesji? */ +#ifdef GG_CONFIG_HAVE_OPENSSL + SSL *ssl; /**< Struktura TLS */ + SSL_CTX *ssl_ctx; /**< Kontekst sesji TLS */ #else - void *ssl; /* zachowujemy ABI */ - void *ssl_ctx; + void *ssl; /**< Struktura TLS */ + void *ssl_ctx; /**< Kontekst sesji TLS */ #endif - int image_size; /* maksymalny rozmiar obrazk�w w KiB */ + int image_size; /**< Maksymalny rozmiar obs�ugiwanych obrazk坦w w KiB */ + + char *userlist_reply; /**< Bufor z odbieran� list� kontakt坦w */ + + int userlist_blocks; /**< Liczba cz��ci listy kontakt坦w */ - char *userlist_reply; /* fragment odpowiedzi listy kontakt�w */ + struct gg_image_queue *images; /**< Lista wczytywanych obrazk坦w */ + + int hash_type; /**< Rodzaj funkcji skr坦tu has�a (\c GG_LOGIN_HASH_GG32 lub \c GG_LOGIN_HASH_SHA1) */ + + char *send_buf; /**< Bufor z danymi do wys�ania */ + int send_left; /**< Liczba bajt坦w do wys�ania */ - int userlist_blocks; /* na ile kawa�k�w podzielono list� kontakt�w */ + struct gg_dcc7 *dcc7_list; /**< Lista po��cze� bezpo�rednich skojarzonych z sesj� */ + + int soft_timeout; /**< Flaga m坦wi�ca, 甜e po przekroczeniu \c timeout nale甜y wywo�a� \c gg_watch_fd() */ + + int protocol_flags; /**< Flagi protoko�u */ - struct gg_image_queue *images; /* aktualnie wczytywane obrazki */ + gg_encoding_t encoding; /**< Rodzaj kodowania znak坦w */ + + gg_resolver_t resolver_type; /**< Spos坦b rozwi�zywania nazw serwer坦w */ + int (*resolver_start)(int *fd, void **private_data, const char *hostname); /**< Funkcja rozpoczynaj�ca rozwi�zywanie nazwy */ + void (*resolver_cleanup)(void **private_data, int force); /**< Funkcja zwalniaj�ca zasoby po rozwi�zaniu nazwy */ + + int protocol_features; /**< Opcje protoko�u */ }; -/* - * struct gg_http +/** + * Po��czenie HTTP. * - * og�lna struktura opisuj�ca stan wszystkich operacji HTTP. tworzona - * przez gg_http_connect(), zwalniana przez gg_http_free(). + * Tworzone przez \c gg_http_connect(), zwalniane przez \c gg_http_free(). + * + * \ingroup http */ struct gg_http { gg_common_head(struct gg_http) - int async; /* czy po咳czenie asynchroniczne */ - int pid; /* pid procesu resolvera */ - int port; /* port, z kt�rym si� 咳czymy */ + int async; /**< Flaga po��czenia asynchronicznego */ + int pid; /**< Identyfikator procesu rozwi�zuj�cego nazw� serwera */ + int port; /**< Port */ + + char *query; /**< Zapytanie HTTP */ + char *header; /**< Odebrany nag�坦wek */ + int header_size; /**< Rozmiar wczytanego nag�坦wka */ + char *body; /**< Odebrana strona */ + unsigned int body_size; /**< Rozmiar strony */ + + void *data; /**< Dane prywatne us�ugi HTTP */ - char *query; /* bufor zapytania http */ - char *header; /* bufor nag鞄wka */ - int header_size; /* rozmiar wczytanego nag鞄wka */ - char *body; /* bufor otrzymanych informacji */ - unsigned int body_size; /* oczekiwana ilo倶 informacji */ + char *user_data; /**< Dane prywatne u甜ytkownika (nie s� zwalniane) */ + + void *resolver; /**< Dane prywatne procesu lub w�tku rozwi�zuj�cego nazw� */ + + unsigned int body_done; /**< Liczba odebranych bajt坦w strony */ - void *data; /* dane danej operacji http */ - - char *user_data; /* dane u�ytkownika, nie s� zwalniane przez gg_http_free() */ + gg_resolver_t resolver_type; /**< Spos坦b rozwi�zywania nazw serwer坦w */ + int (*resolver_start)(int *fd, void **private_data, const char *hostname); /**< Funkcja rozpoczynaj�ca rozwi�zywanie nazwy */ + void (*resolver_cleanup)(void **private_data, int force); /**< Funkcja zwalniaj�ca zasoby po rozwi�zaniu nazwy */ +}; - void *resolver; /* wska�nik na informacje resolvera */ - - unsigned int body_done; /* ile ju� tre�ci odebrano? */ -}; +/** \cond ignore */ #ifdef __GNUC__ #define GG_PACKED __attribute__ ((packed)) +#ifndef GG_IGNORE_DEPRECATED +#define GG_DEPRECATED __attribute__ ((deprecated)) +#else +#define GG_DEPRECATED +#endif #else #define GG_PACKED +#define GG_DEPRECATED #endif -#define GG_MAX_PATH 276 +/** \endcond */ + +#define GG_MAX_PATH 276 /**< Maksymalny rozmiar nazwy pliku w strukturze \c gg_file_info */ -/* - * struct gg_file_info +/** + * Odpowiednik struktury WIN32_FIND_DATA z API WIN32. * - * odpowiednik windowsowej struktury WIN32_FIND_DATA niezb�dnej przy - * wysy�aniu plik�w. + * Wykorzystywana przy po��czeniach bezpo�rednich do wersji Gadu-Gadu 6.x. */ struct gg_file_info { - uint32_t mode; /* dwFileAttributes */ - uint32_t ctime[2]; /* ftCreationTime */ - uint32_t atime[2]; /* ftLastAccessTime */ - uint32_t mtime[2]; /* ftLastWriteTime */ - uint32_t size_hi; /* nFileSizeHigh */ - uint32_t size; /* nFileSizeLow */ - uint32_t reserved0; /* dwReserved0 */ - uint32_t reserved1; /* dwReserved1 */ - unsigned char filename[GG_MAX_PATH - 14]; /* cFileName */ - unsigned char short_filename[14]; /* cAlternateFileName */ -} GG_PACKED; + uint32_t mode; /**< dwFileAttributes */ + uint32_t ctime[2]; /**< ftCreationTime */ + uint32_t atime[2]; /**< ftLastAccessTime */ + uint32_t mtime[2]; /**< ftLastWriteTime */ + uint32_t size_hi; /**< nFileSizeHigh */ + uint32_t size; /**< nFileSizeLow */ + uint32_t reserved0; /**< dwReserved0 */ + uint32_t reserved1; /**< dwReserved1 */ + unsigned char filename[GG_MAX_PATH - 14]; /**< cFileName */ + unsigned char short_filename[14]; /**< cAlternateFileName */ +} /** \cond ignore */ GG_PACKED /** \endcond */; -/* - * struct gg_dcc +/** + * Po��czenie bezpo�rednie do wersji Gadu-Gadu 6.x. * - * struktura opisuj�ca nas�uchuj�ce gniazdo po咳cze� mi�dzy klientami. - * tworzona przez gg_dcc_socket_create(), zwalniana przez gg_dcc_free(). + * Tworzone przez \c gg_dcc_socket_create(), \c gg_dcc_get_file(), + * \c gg_dcc_send_file() lub \c gg_dcc_voice_chat(), zwalniane przez + * \c gg_dcc_free(). + * + * \ingroup dcc6 */ struct gg_dcc { gg_common_head(struct gg_dcc) - struct gg_event *event; /* opis zdarzenia */ + struct gg_event *event; /**< Zdarzenie po wywo�aniu \c callback */ - int active; /* czy to my si� 咳czymy? */ - int port; /* port, na kt�rym siedzi */ - uin_t uin; /* uin klienta */ - uin_t peer_uin; /* uin drugiej strony */ - int file_fd; /* deskryptor pliku */ - unsigned int offset; /* offset w pliku */ - unsigned int chunk_size;/* rozmiar kawa�ka */ - unsigned int chunk_offset;/* offset w aktualnym kawa�ku */ + int active; /**< Flaga po��czenia aktywnego (nieu甜ywana) */ + int port; /**< Port gniazda nas�uchuj�cego */ + uin_t uin; /**< W�asny numer Gadu-Gadu */ + uin_t peer_uin; /**< Numer Gadu-Gadu drugiej strony po��czenia */ + int file_fd; /**< deskryptor pliku */ + unsigned int offset; /**< Po�o甜enie w pliku */ + unsigned int chunk_size; + /**< Rozmiar kawa�ka pliku */ + unsigned int chunk_offset; + /**< Po�o甜enie w aktualnym kawa�ku pliku */ struct gg_file_info file_info; - /* informacje o pliku */ - int established; /* po咳czenie ustanowione */ - uint8_t *voice_buf; /* bufor na pakiet po咳czenia g�osowego */ - int incoming; /* po咳czenie przychodz�ce */ - char *chunk_buf; /* bufor na kawa�ek danych */ - uint32_t remote_addr; /* adres drugiej strony */ - uint16_t remote_port; /* port drugiej strony */ + /**< Informacje o pliku */ + int established; /**< Flaga ustanowienia po��czenia */ + char *voice_buf; /**< Bufor na pakiet po��czenia g�osowego */ + int incoming; /**< Flaga po��czenia przychodz�cego */ + char *chunk_buf; /**< Bufor na fragment danych */ + uint32_t remote_addr; /**< Adres drugiej strony */ + uint16_t remote_port; /**< Port drugiej strony */ }; -/* - * enum gg_session_t +#define GG_DCC7_HASH_LEN 20 /**< Maksymalny rozmiar skr坦tu pliku w po��czeniach bezpo�renich */ +#define GG_DCC7_FILENAME_LEN 255 /**< Maksymalny rozmiar nazwy pliku w po��czeniach bezpo�rednich */ +#define GG_DCC7_INFO_LEN 64 /**< Maksymalny rozmiar informacji o po��czeniach bezpo�rednich */ + +/** + * Po��czenie bezpo�rednie od wersji Gadu-Gadu 7.x. * - * rodzaje sesji. + * \ingroup dcc7 + */ +struct gg_dcc7 { + gg_common_head(struct gg_dcc7) + + gg_dcc7_id_t cid; /**< Identyfikator po��czenia */ + + struct gg_event *event; /**< Struktura zdarzenia */ + + uin_t uin; /**< W�asny numer Gadu-Gadu */ + uin_t peer_uin; /**< Numer Gadu-Gadu drugiej strony po��czenia */ + + int file_fd; /**< Deskryptor przesy�anego pliku */ + unsigned int offset; /**< Aktualne po�o甜enie w przesy�anym pliku */ + unsigned int size; /**< Rozmiar przesy�anego pliku */ + unsigned char filename[GG_DCC7_FILENAME_LEN + 1]; + /**< Nazwa przesy�anego pliku */ + unsigned char hash[GG_DCC7_HASH_LEN]; + /**< Skr坦t SHA1 przesy�anego pliku */ + + int dcc_type; /**< Rodzaj po��czenia bezpo�redniego */ + int established; /**< Flaga ustanowienia po��czenia */ + int incoming; /**< Flaga po��czenia przychodz�cego */ + int reverse; /**< Flaga po��czenia zwrotnego */ + + uint32_t local_addr; /**< Adres lokalny */ + uint16_t local_port; /**< Port lokalny */ + + uint32_t remote_addr; /**< Adres drugiej strony */ + uint16_t remote_port; /**< Port drugiej strony */ + + struct gg_session *sess; + /**< Sesja do kt坦rej przypisano po��czenie */ + struct gg_dcc7 *next; /**< Nast�pne po��czenie w li�cie */ + + int soft_timeout; /**< Flaga m坦wi�ca, 甜e po przekroczeniu \c timeout nale甜y wywo�a� \c gg_dcc7_watch_fd() */ + int seek; /**< Flaga m坦wi�ca, 甜e mo甜na zmienia� po�o甜enie w wysy�anym pliku */ +}; + +/** + * Rodzaj sesji. */ enum gg_session_t { - GG_SESSION_GG = 1, /* po咳czenie z serwerem gg */ - GG_SESSION_HTTP, /* og�lna sesja http */ - GG_SESSION_SEARCH, /* szukanie */ - GG_SESSION_REGISTER, /* rejestrowanie */ - GG_SESSION_REMIND, /* przypominanie has�a */ - GG_SESSION_PASSWD, /* zmiana has�a */ - GG_SESSION_CHANGE, /* zmiana informacji o sobie */ - GG_SESSION_DCC, /* og�lne po咳czenie DCC */ - GG_SESSION_DCC_SOCKET, /* nas�uchuj�cy socket */ - GG_SESSION_DCC_SEND, /* wysy�anie pliku */ - GG_SESSION_DCC_GET, /* odbieranie pliku */ - GG_SESSION_DCC_VOICE, /* rozmowa g�osowa */ - GG_SESSION_USERLIST_GET, /* pobieranie userlisty */ - GG_SESSION_USERLIST_PUT, /* wysy�anie userlisty */ - GG_SESSION_UNREGISTER, /* usuwanie konta */ - GG_SESSION_USERLIST_REMOVE, /* usuwanie userlisty */ - GG_SESSION_TOKEN, /* pobieranie tokenu */ + GG_SESSION_GG = 1, /**< Po��czenie z serwerem Gadu-Gadu */ + GG_SESSION_HTTP, /**< Po��czenie HTTP */ + GG_SESSION_SEARCH, /**< Wyszukiwanie w katalogu publicznym (nieaktualne) */ + GG_SESSION_REGISTER, /**< Rejestracja nowego konta */ + GG_SESSION_REMIND, /**< Przypominanie has�a */ + GG_SESSION_PASSWD, /**< Zmiana has�a */ + GG_SESSION_CHANGE, /**< Zmiana informacji w katalogu publicznym (nieaktualne) */ + GG_SESSION_DCC, /**< Po��czenie bezpo�rednie (do wersji 6.x) */ + GG_SESSION_DCC_SOCKET, /**< Gniazdo nas�uchuj�ce (do wersji 6.x) */ + GG_SESSION_DCC_SEND, /**< Wysy�anie pliku (do wersji 6.x) */ + GG_SESSION_DCC_GET, /**< Odbieranie pliku (do wersji 6.x) */ + GG_SESSION_DCC_VOICE, /**< Rozmowa g�osowa (do wersji 6.x) */ + GG_SESSION_USERLIST_GET, /**< Import listy kontakt坦w z serwera (nieaktualne) */ + GG_SESSION_USERLIST_PUT, /**< Eksport listy kontakt坦w do serwera (nieaktualne) */ + GG_SESSION_UNREGISTER, /**< Usuwanie konta */ + GG_SESSION_USERLIST_REMOVE, /**< Usuwanie listy kontakt坦w z serwera (nieaktualne) */ + GG_SESSION_TOKEN, /**< Pobieranie tokenu */ + GG_SESSION_DCC7_SOCKET, /**< Gniazdo nas�uchuj�ce (od wersji 7.x) */ + GG_SESSION_DCC7_SEND, /**< Wysy�anie pliku (od wersji 7.x) */ + GG_SESSION_DCC7_GET, /**< Odbieranie pliku (od wersji 7.x) */ + GG_SESSION_DCC7_VOICE, /**< Rozmowa g�osowa (od wersji 7.x) */ - GG_SESSION_USER0 = 256, /* zdefiniowana dla u�ytkownika */ - GG_SESSION_USER1, /* j.w. */ - GG_SESSION_USER2, /* j.w. */ - GG_SESSION_USER3, /* j.w. */ - GG_SESSION_USER4, /* j.w. */ - GG_SESSION_USER5, /* j.w. */ - GG_SESSION_USER6, /* j.w. */ - GG_SESSION_USER7 /* j.w. */ + GG_SESSION_USER0 = 256, /**< Rodzaj zadeklarowany dla u甜ytkownika */ + GG_SESSION_USER1, /**< Rodzaj zadeklarowany dla u甜ytkownika */ + GG_SESSION_USER2, /**< Rodzaj zadeklarowany dla u甜ytkownika */ + GG_SESSION_USER3, /**< Rodzaj zadeklarowany dla u甜ytkownika */ + GG_SESSION_USER4, /**< Rodzaj zadeklarowany dla u甜ytkownika */ + GG_SESSION_USER5, /**< Rodzaj zadeklarowany dla u甜ytkownika */ + GG_SESSION_USER6, /**< Rodzaj zadeklarowany dla u甜ytkownika */ + GG_SESSION_USER7 /**< Rodzaj zadeklarowany dla u甜ytkownika */ }; -/* - * enum gg_state_t - * - * opisuje stan asynchronicznej maszyny. +/** + * Aktualny stan sesji. */ enum gg_state_t { - /* wsp�lne */ - GG_STATE_IDLE = 0, /* nie powinno wyst�pi�. */ - GG_STATE_RESOLVING, /* wywo�a� gethostbyname() */ - GG_STATE_CONNECTING, /* wywo�a� connect() */ - GG_STATE_READING_DATA, /* czeka na dane http */ - GG_STATE_ERROR, /* wyst�pi� b咳d. kod w x->error */ + /* wsp坦lne */ + GG_STATE_IDLE = 0, /**< Nie dzieje si� nic */ + GG_STATE_RESOLVING, /**< Oczekiwanie na rozwi�zanie nazwy serwera */ + GG_STATE_CONNECTING, /**< Oczekiwanie na po��czenie */ + GG_STATE_READING_DATA, /**< Oczekiwanie na dane */ + GG_STATE_ERROR, /**< Kod b��du w polu \c error */ - /* gg_session */ - GG_STATE_CONNECTING_HUB, /* wywo�a� connect() na huba */ - GG_STATE_CONNECTING_GG, /* wywo�a� connect() na serwer */ - GG_STATE_READING_KEY, /* czeka na klucz */ - GG_STATE_READING_REPLY, /* czeka na odpowied� */ - GG_STATE_CONNECTED, /* po咳czy� si� */ + /* gg_session */ + GG_STATE_CONNECTING_HUB, /**< Oczekiwanie na po��czenie z hubem */ + GG_STATE_CONNECTING_GG, /**< Oczekiwanie na po��czenie z serwerem */ + GG_STATE_READING_KEY, /**< Oczekiwanie na klucz */ + GG_STATE_READING_REPLY, /**< Oczekiwanie na odpowied添 serwera */ + GG_STATE_CONNECTED, /**< Po��czono z serwerem */ - /* gg_http */ - GG_STATE_SENDING_QUERY, /* wysy�a zapytanie http */ - GG_STATE_READING_HEADER, /* czeka na nag鞄wek http */ - GG_STATE_PARSING, /* przetwarza dane */ - GG_STATE_DONE, /* sko�czy� */ + /* gg_http */ + GG_STATE_SENDING_QUERY, /**< Wys�ano zapytanie HTTP */ + GG_STATE_READING_HEADER, /**< Oczekiwanie na nag�坦wek HTTP */ + GG_STATE_PARSING, /**< Przetwarzanie danych */ + GG_STATE_DONE, /**< Po��czenie zako�czone */ - /* gg_dcc */ - GG_STATE_LISTENING, /* czeka na po咳czenia */ + /* gg_dcc */ + GG_STATE_LISTENING, /* czeka na po��czenia */ GG_STATE_READING_UIN_1, /* czeka na uin peera */ - GG_STATE_READING_UIN_2, /* czeka na sw�j uin */ - GG_STATE_SENDING_ACK, /* wysy�a potwierdzenie dcc */ + GG_STATE_READING_UIN_2, /* czeka na sw坦j uin */ + GG_STATE_SENDING_ACK, /* wysy�a potwierdzenie dcc */ GG_STATE_READING_ACK, /* czeka na potwierdzenie dcc */ - GG_STATE_READING_REQUEST, /* czeka na komend� */ - GG_STATE_SENDING_REQUEST, /* wysy�a komend� */ - GG_STATE_SENDING_FILE_INFO, /* wysy�a informacje o pliku */ + GG_STATE_READING_REQUEST, /* czeka na komend� */ + GG_STATE_SENDING_REQUEST, /* wysy�a komend� */ + GG_STATE_SENDING_FILE_INFO, /* wysy�a informacje o pliku */ GG_STATE_READING_PRE_FILE_INFO, /* czeka na pakiet przed file_info */ GG_STATE_READING_FILE_INFO, /* czeka na informacje o pliku */ - GG_STATE_SENDING_FILE_ACK, /* wysy�a potwierdzenie pliku */ + GG_STATE_SENDING_FILE_ACK, /* wysy�a potwierdzenie pliku */ GG_STATE_READING_FILE_ACK, /* czeka na potwierdzenie pliku */ - GG_STATE_SENDING_FILE_HEADER, /* wysy�a nag鞄wek pliku */ - GG_STATE_READING_FILE_HEADER, /* czeka na nag鞄wek */ + GG_STATE_SENDING_FILE_HEADER, /* wysy�a nag�坦wek pliku */ + GG_STATE_READING_FILE_HEADER, /* czeka na nag�坦wek */ GG_STATE_GETTING_FILE, /* odbiera plik */ - GG_STATE_SENDING_FILE, /* wysy�a plik */ + GG_STATE_SENDING_FILE, /* wysy�a plik */ GG_STATE_READING_VOICE_ACK, /* czeka na potwierdzenie voip */ GG_STATE_READING_VOICE_HEADER, /* czeka na rodzaj bloku voip */ GG_STATE_READING_VOICE_SIZE, /* czeka na rozmiar bloku voip */ GG_STATE_READING_VOICE_DATA, /* czeka na dane voip */ - GG_STATE_SENDING_VOICE_ACK, /* wysy�a potwierdzenie voip */ - GG_STATE_SENDING_VOICE_REQUEST, /* wysy�a 娠danie voip */ - GG_STATE_READING_TYPE, /* czeka na typ po咳czenia */ + GG_STATE_SENDING_VOICE_ACK, /* wysy�a potwierdzenie voip */ + GG_STATE_SENDING_VOICE_REQUEST, /* wysy�a 甜�danie voip */ + GG_STATE_READING_TYPE, /* czeka na typ po��czenia */ /* nowe. bez sensu jest to API. */ - GG_STATE_TLS_NEGOTIATION /* negocjuje po咳czenie TLS */ + GG_STATE_TLS_NEGOTIATION, /**< Negocjacja po��czenia szyfrowanego */ + + GG_STATE_REQUESTING_ID, /**< Oczekiwanie na nadanie identyfikatora po��czenia bezpo�redniego */ + GG_STATE_WAITING_FOR_ACCEPT, /**< Oczekiwanie na potwierdzenie lub odrzucenie po��czenia bezpo�redniego */ + GG_STATE_WAITING_FOR_INFO, /**< Oczekiwanie na informacje o po��czeniu bezpo�rednim */ + + GG_STATE_READING_ID, /**< Odebranie identyfikatora po��czenia bezpo�redniego */ + GG_STATE_SENDING_ID /**< Wys�ano identyfikatora po��czenia bezpo�redniego */ }; -/* - * enum gg_check_t +/** + * Informacja o tym, czy biblioteka chce zapisywa� i/lub czyta� + * z deskryptora. Maska bitowa. * - * informuje, co proces klienta powinien sprawdzi� na deskryptorze danego - * po咳czenia. + * \ingroup events */ enum gg_check_t { - GG_CHECK_NONE = 0, /* nic. nie powinno wyst�pi� */ - GG_CHECK_WRITE = 1, /* sprawdzamy mo�liwo倶 zapisu */ - GG_CHECK_READ = 2 /* sprawdzamy mo�liwo倶 odczytu */ + GG_CHECK_NONE = 0, /**< Nie sprawdzaj niczego */ + GG_CHECK_WRITE = 1, /**< Sprawd添 mo甜liwo�� zapisu */ + GG_CHECK_READ = 2 /**< Sprawd添 mo甜liwo�� odczytu */ }; -/* - * struct gg_login_params +/** + * Parametry po��czenia z serwerem Gadu-Gadu. Parametry zosta�y przeniesione + * do struktury, by unikn�� zmian API po rozszerzeniu protoko�u i dodaniu + * kolejnych opcji po��czenia. Cz��� parametr坦w, kt坦re nie s� ju甜 aktualne + * lub nie maj� znaczenia, zosta�a usuni�ta z dokumentacji. * - * parametry gg_login(). przeniesiono do struktury, �eby unikn掩 problem�w - * z ci�g�ymi zmianami API, gdy dodano co� nowego do protoko�u. + * \ingroup login */ struct gg_login_params { - uin_t uin; /* numerek */ - char *password; /* has�o */ - int async; /* asynchroniczne sockety? */ - int status; /* pocz�tkowy status klienta */ - char *status_descr; /* opis statusu */ - uint32_t server_addr; /* adres serwera gg */ - uint16_t server_port; /* port serwera gg */ - uint32_t client_addr; /* adres dcc klienta */ - uint16_t client_port; /* port dcc klienta */ - int protocol_version; /* wersja protoko�u */ - char *client_version; /* wersja klienta */ - int has_audio; /* czy ma d�wi�k? */ - int last_sysmsg; /* ostatnia wiadomo倶 systemowa */ - uint32_t external_addr; /* adres widziany na zewnatrz */ - uint16_t external_port; /* port widziany na zewnatrz */ - int tls; /* czy 咳czymy po TLS? */ - int image_size; /* maksymalny rozmiar obrazka w KiB */ - int era_omnix; /* czy udawa� klienta era omnix? */ + uin_t uin; /**< Numer Gadu-Gadu */ + char *password; /**< Has�o */ + int async; /**< Flaga asynchronicznego po��czenia (domy�lnie nie) */ + int status; /**< Pocz�tkowy status u甜ytkownika (domy�lnie \c GG_STATUS_AVAIL) */ + char *status_descr; /**< Pocz�tkowy opis u甜ytkownika (domy�lnie brak) */ + uint32_t server_addr; /**< Adres serwera Gadu-Gadu (domy�lnie pobierany automatycznie) */ + uint16_t server_port; /**< Port serwera Gadu-Gadu (domy�lnie pobierany automatycznie) */ +#ifndef DOXYGEN + uint32_t client_addr; /**< Adres po��cze� bezpo�rednich (nieaktualne) */ + uint16_t client_port; /**< Port po��cze� bezpo�rednich (nieaktualne) */ +#endif + int protocol_version; /**< Wersja protoko�u wysy�ana do serwera (domy�lnie najnowsza obs�ugiwana) */ + char *client_version; /**< Wersja klienta wysy�ana do serwera (domy�lnie najnowsza znana) */ + int has_audio; /**< Flaga obs�ugi po��cze� g�osowych */ + int last_sysmsg; /**< Numer ostatnio odebranej wiadomo�ci systemowej */ + uint32_t external_addr; /**< Adres publiczny dla po��cze� bezpo�rednich (6.x) */ + uint16_t external_port; /**< Port publiczny dla po��cze� bezpo�rednich (6.x) */ +#ifndef DOXYGEN + int tls; /**< Flaga po��czenia szyfrowanego (nieaktualna) */ +#endif + int image_size; /**< Maksymalny rozmiar obs�ugiwanych obrazk坦w w kilobajtach */ +#ifndef DOXYGEN + int era_omnix; /**< Flaga udawania klienta Era Omnix (nieaktualna) */ +#endif + int hash_type; /**< Rodzaj skr坦tu has�a (\c GG_LOGIN_HASH_GG32 lub \c GG_LOGIN_HASH_SHA1, domy�lnie SHA1) */ + gg_encoding_t encoding; /**< Rodzaj kodowania u甜ywanego w sesji (domy�lnie CP1250) */ + gg_resolver_t resolver; /**< Spos坦b rozwi�zywania nazw (patrz \ref build-resolver) */ + int protocol_features; /**< Opcje protoko�u (flagi GG_FEATURE_*). */ - char dummy[6 * sizeof(int)]; /* miejsce na kolejnych 6 zmiennych, - * �eby z dodaniem parametru nie - * zmienia� si� rozmiar struktury */ +#ifndef DOXYGEN + char dummy[2 * sizeof(int)]; /**< \internal Miejsce na kilka kolejnych + parametr坦w, 甜eby wraz z dodawaniem kolejnych + parametr坦w nie zmienia� si� rozmiar struktury */ +#endif + }; struct gg_session *gg_login(const struct gg_login_params *p); @@ -367,232 +597,337 @@ int gg_ping(struct gg_session *sess); int gg_userlist_request(struct gg_session *sess, char type, const char *request); int gg_image_request(struct gg_session *sess, uin_t recipient, int size, uint32_t crc32); -int gg_image_reply(struct gg_session *sess, uin_t recipient, const char *filename, const unsigned char *image, int size); +int gg_image_reply(struct gg_session *sess, uin_t recipient, const char *filename, const char *image, int size); uint32_t gg_crc32(uint32_t crc, const unsigned char *buf, int len); -struct gg_image_queue { - uin_t sender; /* nadawca obrazka */ - uint32_t size; /* rozmiar */ - uint32_t crc32; /* suma kontrolna */ - char *filename; /* nazwa pliku */ - char *image; /* bufor z obrazem */ - uint32_t done; /* ile ju� wczytano */ +int gg_session_set_resolver(struct gg_session *gs, gg_resolver_t type); +gg_resolver_t gg_session_get_resolver(struct gg_session *gs); +int gg_session_set_custom_resolver(struct gg_session *gs, int (*resolver_start)(int*, void**, const char*), void (*resolver_cleanup)(void**, int)); + +int gg_http_set_resolver(struct gg_http *gh, gg_resolver_t type); +gg_resolver_t gg_http_get_resolver(struct gg_http *gh); +int gg_http_set_custom_resolver(struct gg_http *gh, int (*resolver_start)(int*, void**, const char*), void (*resolver_cleanup)(void**, int)); - struct gg_image_queue *next; /* nast�pny na li�cie */ -}; +int gg_global_set_resolver(gg_resolver_t type); +gg_resolver_t gg_global_get_resolver(void); +int gg_global_set_custom_resolver(int (*resolver_start)(int*, void**, const char*), void (*resolver_cleanup)(void**, int)); -/* - * enum gg_event_t +/** + * Rodzaj zdarzenia. * - * rodzaje zdarze�. + * \ingroup events */ enum gg_event_t { - GG_EVENT_NONE = 0, /* nic si� nie wydarzy�o */ - GG_EVENT_MSG, /* otrzymano wiadomo倶 */ - GG_EVENT_NOTIFY, /* kto� si� pojawi� */ - GG_EVENT_NOTIFY_DESCR, /* kto� si� pojawi� z opisem */ - GG_EVENT_STATUS, /* kto� zmieni� stan */ - GG_EVENT_ACK, /* potwierdzenie wys�ania wiadomo�ci */ - GG_EVENT_PONG, /* pakiet pong */ - GG_EVENT_CONN_FAILED, /* po咳czenie si� nie uda�o */ - GG_EVENT_CONN_SUCCESS, /* po咳czenie si� powiod�o */ - GG_EVENT_DISCONNECT, /* serwer zrywa po咳czenie */ + GG_EVENT_NONE = 0, /**< Nie wydarzy�o si� nic wartego uwagi */ + GG_EVENT_MSG, /**< \brief Otrzymano wiadomo��. Przekazuje r坦wnie甜 wiadomo�ci systemowe od numeru 0. */ + GG_EVENT_NOTIFY, /**< \brief Informacja o statusach os坦b z listy kontakt坦w (przed 6.0). Zdarzenie nale甜y obs�ugiwa�, je�li planuje si� u甜ywa� protoko�u w wersji starszej ni甜 domy�lna. */ + GG_EVENT_NOTIFY_DESCR, /**< \brief Informacja o statusie opisowym osoby z listy kontakt坦w (przed 6.0). Zdarzenie nale甜y obs�ugiwa�, je�li planuje si� u甜ywa� protoko�u w wersji starszej ni甜 domy�lna. */ + GG_EVENT_STATUS, /**< \brief Zmiana statusu osoby z listy kontakt坦w (przed 6.0). Zdarzenie nale甜y obs�ugiwa�, je�li planuje si� u甜ywa� protoko�u w wersji starszej ni甜 domy�lna. */ + GG_EVENT_ACK, /**< Potwierdzenie dor�czenia wiadomo�ci */ + GG_EVENT_PONG, /**< \brief Utrzymanie po��czenia. Obecnie serwer nie wysy�a ju甜 do klienta ramek utrzymania po��czenia, polega wy��cznie na wysy�aniu ramek przez klienta. */ + GG_EVENT_CONN_FAILED, /**< \brief Nie uda�o si� po��czy� */ + GG_EVENT_CONN_SUCCESS, /**< \brief Po��czono z serwerem. Pierwsz� rzecz�, jak� nale甜y zrobi� jest wys�anie listy kontakt坦w. */ + GG_EVENT_DISCONNECT, /**< \brief Serwer zrywa po��czenie. Zdarza si�, gdy r坦wnolegle do serwera pod��czy si� druga sesja i trzeba zerwa� po��czenie z pierwsz�. */ + + GG_EVENT_DCC_NEW, /**< Nowe po��czenie bezpo�rednie (6.x) */ + GG_EVENT_DCC_ERROR, /**< B��d po��czenia bezpo�redniego (6.x) */ + GG_EVENT_DCC_DONE, /**< Zako�czono po��czenie bezpo�rednie (6.x) */ + GG_EVENT_DCC_CLIENT_ACCEPT, /**< Moment akceptacji klienta w po��czeniu bezpo�rednim (6.x) */ + GG_EVENT_DCC_CALLBACK, /**< Zwrotne po��czenie bezpo�rednie (6.x) */ + GG_EVENT_DCC_NEED_FILE_INFO, /**< Nale甜y wype�ni� \c file_info dla po��czenia bezpo�redniego (6.x) */ + GG_EVENT_DCC_NEED_FILE_ACK, /**< Czeka na potwierdzenie pliku w po��czeniu bezpo�rednim (6.x) */ + GG_EVENT_DCC_NEED_VOICE_ACK, /**< Czeka na potwierdzenie rozmowy w po��czeniu bezpo�rednim (6.x) */ + GG_EVENT_DCC_VOICE_DATA, /**< Dane bezpo�redniego po��czenia g�osowego (6.x) */ - GG_EVENT_DCC_NEW, /* nowe po咳czenie mi�dzy klientami */ - GG_EVENT_DCC_ERROR, /* b咳d po咳czenia mi�dzy klientami */ - GG_EVENT_DCC_DONE, /* zako�czono po咳czenie */ - GG_EVENT_DCC_CLIENT_ACCEPT, /* moment akceptacji klienta */ - GG_EVENT_DCC_CALLBACK, /* klient si� po咳czy� na 娠danie */ - GG_EVENT_DCC_NEED_FILE_INFO, /* nale�y wype�ni� file_info */ - GG_EVENT_DCC_NEED_FILE_ACK, /* czeka na potwierdzenie pliku */ - GG_EVENT_DCC_NEED_VOICE_ACK, /* czeka na potwierdzenie rozmowy */ - GG_EVENT_DCC_VOICE_DATA, /* ramka danych rozmowy g�osowej */ + GG_EVENT_PUBDIR50_SEARCH_REPLY, /**< Odpowied添 katalogu publicznego */ + GG_EVENT_PUBDIR50_READ, /**< Odczytano w�asne dane z katalogu publicznego */ + GG_EVENT_PUBDIR50_WRITE, /**< Zmieniono w�asne dane w katalogu publicznym */ + + GG_EVENT_STATUS60, /**< Zmiana statusu osoby z listy kontakt坦w */ + GG_EVENT_NOTIFY60, /**< Informacja o statusach os坦b z listy kontakt坦w */ + GG_EVENT_USERLIST, /**< Wynik importu lub eksportu listy kontakt坦w */ + GG_EVENT_IMAGE_REQUEST, /**< 纏�danie przes�ania obrazka z wiadommo�ci */ + GG_EVENT_IMAGE_REPLY, /**< Przys�ano obrazek z wiadomo�ci */ + GG_EVENT_DCC_ACK, /**< Potwierdzenie transmisji w po��czeniu bezpo�rednim (6.x) */ - GG_EVENT_PUBDIR50_SEARCH_REPLY, /* odpowiedz wyszukiwania */ - GG_EVENT_PUBDIR50_READ, /* odczytano w�asne dane z katalogu */ - GG_EVENT_PUBDIR50_WRITE, /* wpisano w�asne dane do katalogu */ + GG_EVENT_DCC7_NEW, /**< Nowe po��czenie bezpo�rednie (7.x) */ + GG_EVENT_DCC7_ACCEPT, /**< Zaakceptowano po��czenie bezpo�rednie (7.x), nowy deskryptor */ + GG_EVENT_DCC7_REJECT, /**< Odrzucono po��czenie bezpo�rednie (7.x) */ + GG_EVENT_DCC7_CONNECTED, /**< Zestawiono po��czenie bezpo�rednie (7.x), nowy deskryptor */ + GG_EVENT_DCC7_ERROR, /**< B��d po��czenia bezpo�redniego (7.x) */ + GG_EVENT_DCC7_DONE, /**< Zako�czono po��czenie bezpo�rednie (7.x) */ + GG_EVENT_DCC7_PENDING, /**< Trwa pr坦ba po��czenia bezpo�redniego (7.x), nowy deskryptor */ - GG_EVENT_STATUS60, /* kto� zmieni� stan w GG 6.0 */ - GG_EVENT_NOTIFY60, /* kto� si� pojawi� w GG 6.0 */ - GG_EVENT_USERLIST, /* odpowied� listy kontakt�w w GG 6.0 */ - GG_EVENT_IMAGE_REQUEST, /* pro�ba o wys�anie obrazka GG 6.0 */ - GG_EVENT_IMAGE_REPLY, /* podes�any obrazek GG 6.0 */ - GG_EVENT_DCC_ACK /* potwierdzenie transmisji */ + GG_EVENT_XML_EVENT, /**< Otrzymano komunikat systemowy (7.7) */ + GG_EVENT_DISCONNECT_ACK, /**< \brief Potwierdzenie zako�czenia sesji. Informuje o tym, 甜e zmiana stanu na niedost�pny z opisem dotar�a do serwera i mo甜na zako�czy� po��czenie TCP. */ }; #define GG_EVENT_SEARCH50_REPLY GG_EVENT_PUBDIR50_SEARCH_REPLY -/* - * enum gg_failure_t - * - * okre�la pow�d nieudanego po咳czenia. +/** + * Pow坦d nieudanego po��czenia. */ enum gg_failure_t { - GG_FAILURE_RESOLVING = 1, /* nie znaleziono serwera */ - GG_FAILURE_CONNECTING, /* nie mo�na si� po咳czy� */ - GG_FAILURE_INVALID, /* serwer zwr�ci� nieprawid�owe dane */ - GG_FAILURE_READING, /* zerwano po咳czenie podczas odczytu */ - GG_FAILURE_WRITING, /* zerwano po咳czenie podczas zapisu */ - GG_FAILURE_PASSWORD, /* nieprawid�owe has�o */ - GG_FAILURE_404, /* XXX nieu�ywane */ - GG_FAILURE_TLS, /* b咳d negocjacji TLS */ - GG_FAILURE_NEED_EMAIL /* serwer roz咳czy� nas z pro�b� o zmian� emaila */ + GG_FAILURE_RESOLVING = 1, /**< Nie znaleziono serwera */ + GG_FAILURE_CONNECTING, /**< B��d po��czenia */ + GG_FAILURE_INVALID, /**< Serwer zwr坦ci� nieprawid�owe dane */ + GG_FAILURE_READING, /**< Zerwano po��czenie podczas odczytu */ + GG_FAILURE_WRITING, /**< Zerwano po��czenie podczas zapisu */ + GG_FAILURE_PASSWORD, /**< Nieprawid�owe has�o */ + GG_FAILURE_404, /**< Nieu甜ywane */ + GG_FAILURE_TLS, /**< B��d negocjacji szyfrowanego po��czenia */ + GG_FAILURE_NEED_EMAIL, /**< Serwer roz��czy� nas z pro�b� o zmian� adresu e-mail */ + GG_FAILURE_INTRUDER, /**< Zbyt wiele pr坦b po��czenia z nieprawid�owym has�em */ + GG_FAILURE_UNAVAILABLE /**< Serwery s� wy��czone */ }; -/* - * enum gg_error_t +/** + * Kod b��du danej operacji. * - * okre�la rodzaj b滑du wywo�anego przez dan� operacj�. nie zawiera - * przesadnie szczeg鶻owych informacji o powodzie b滑du, by nie komplikowa� - * obs�ugi b滑d�w. je�li wymagana jest wi�ksza dok�adno倶, nale�y sprawdzi� - * zawarto倶 zmiennej errno. + * Nie zawiera przesadnie szczeg坦�owych informacji o powodach b��d坦w, by nie + * komplikowa� ich obs�ugi. Je�li wymagana jest wi�ksza dok�adno��, nale甜y + * sprawdzi� zawarto�� zmiennej systemowej \c errno. */ enum gg_error_t { - GG_ERROR_RESOLVING = 1, /* b咳d znajdowania hosta */ - GG_ERROR_CONNECTING, /* b咳d �aczenia si� */ - GG_ERROR_READING, /* b咳d odczytu */ - GG_ERROR_WRITING, /* b咳d wysy�ania */ + GG_ERROR_RESOLVING = 1, /**< Nie znaleziono hosta */ + GG_ERROR_CONNECTING, /**< B��d po��czenia */ + GG_ERROR_READING, /**< B��d odczytu/odbierania */ + GG_ERROR_WRITING, /**< B��d zapisu/wysy�ania */ - GG_ERROR_DCC_HANDSHAKE, /* b咳d negocjacji */ - GG_ERROR_DCC_FILE, /* b咳d odczytu/zapisu pliku */ - GG_ERROR_DCC_EOF, /* plik si� sko�czy�? */ - GG_ERROR_DCC_NET, /* b咳d wysy�ania/odbierania */ - GG_ERROR_DCC_REFUSED /* po咳czenie odrzucone przez usera */ + GG_ERROR_DCC_HANDSHAKE, /**< B��d negocjacji */ + GG_ERROR_DCC_FILE, /**< B��d odczytu/zapisu pliku */ + GG_ERROR_DCC_EOF, /**< Przedwczesny koniec pliku */ + GG_ERROR_DCC_NET, /**< B��d wysy�ania/odbierania */ + GG_ERROR_DCC_REFUSED, /**< Po��czenie odrzucone */ + + GG_ERROR_DCC7_HANDSHAKE, /**< B��d negocjacji */ + GG_ERROR_DCC7_FILE, /**< B��d odczytu/zapisu pliku */ + GG_ERROR_DCC7_EOF, /**< Przedwczesny koniec pliku */ + GG_ERROR_DCC7_NET, /**< B��d wysy�ania/odbierania */ + GG_ERROR_DCC7_REFUSED /**< Po��czenie odrzucone */ }; -/* - * struktury dotycz�ce wyszukiwania w GG 5.0. NIE NALE�Y SI� DO NICH - * ODWO�YWA� BEZPO�REDNIO! do dost�pu do nich s�u娠 funkcje gg_pubdir50_*() +/** + * Pole zapytania lub odpowiedzi katalogu publicznego. */ struct gg_pubdir50_entry { - int num; - char *field; - char *value; -}; + int num; /**< Numer wyniku */ + char *field; /**< Nazwa pola */ + char *value; /**< Warto�� pola */ +} /* GG_DEPRECATED */; +/** + * Zapytanie lub odpowied添 katalogu publicznego. + * + * Patrz \c gg_pubdir50_t. + */ struct gg_pubdir50_s { - int count; - uin_t next; - int type; - uint32_t seq; - struct gg_pubdir50_entry *entries; - int entries_count; -}; + int count; /**< Liczba wynik坦w odpowiedzi */ + uin_t next; /**< Numer pocz�tkowy nast�pnego zapytania */ + int type; /**< Rodzaj zapytania */ + uint32_t seq; /**< Numer sekwencyjny */ + struct gg_pubdir50_entry *entries; /**< Pola zapytania lub odpowiedzi */ + int entries_count; /**< Liczba p坦l */ +} /* GG_DEPRECATED */; -/* - * typedef gg_pubdir_50_t +/** + * Zapytanie lub odpowied添 katalogu publicznego. * - * typ opisuj�cy zapytanie lub wynik zapytania katalogu publicznego - * z protoko�u GG 5.0. nie nale�y si� odwo�ywa� bezpo�rednio do jego - * p�l -- s�u娠 do tego funkcje gg_pubdir50_*() + * Do p坦l nie nale甜y si� odwo�ywa� bezpo�rednio -- wszystkie niezb�dne + * informacje s� dost�pne za pomoc� funkcji \c gg_pubdir50_* */ typedef struct gg_pubdir50_s *gg_pubdir50_t; -/* - * struct gg_event +/** + * Opis zdarzenia \c GG_EVENT_MSG. + */ +struct gg_event_msg { + uin_t sender; /**< Numer nadawcy */ + int msgclass; /**< Klasa wiadomo�ci */ + time_t time; /**< Czas nadania */ + unsigned char *message; /**< Tre�� wiadomo�ci */ + + int recipients_count; /**< Liczba odbiorc坦w konferencji */ + uin_t *recipients; /**< Odbiorcy konferencji */ + + int formats_length; /**< D�ugo�� informacji o formatowaniu tekstu */ + void *formats; /**< Informacje o formatowaniu tekstu */ + uint32_t seq; /**< Numer sekwencyjny wiadomo�ci */ + + char *xhtml_message; /**< Tre�� wiadomo�ci w formacie XHTML (mo甜e by� r坦wne \c NULL, je�li wiadomo�� nie zawiera tre�ci XHTML) */ +}; + +/** + * Opis zdarzenia \c GG_EVENT_NOTIFY_DESCR. + */ +struct gg_event_notify_descr { + struct gg_notify_reply *notify; /**< Informacje o li�cie kontakt坦w */ + char *descr; /**< Opis status */ +}; + +/** + * Opis zdarzenia \c GG_EVENT_STATUS. + */ +struct gg_event_status { + uin_t uin; /**< Numer Gadu-Gadu */ + uint32_t status; /**< Nowy status */ + char *descr; /**< Opis */ +}; + +/** + * Opis zdarzenia \c GG_EVENT_STATUS60. + */ +struct gg_event_status60 { + uin_t uin; /**< Numer Gadu-Gadu */ + int status; /**< Nowy status */ + uint32_t remote_ip; /**< Adres IP dla po��cze� bezpo�rednich */ + uint16_t remote_port; /**< Port dla po��cze� bezpo�rednich */ + int version; /**< Wersja protoko�u */ + int image_size; /**< Maksymalny rozmiar obs�ugiwanych obrazk坦w w KiB */ + char *descr; /**< Opis statusu */ + time_t time; /**< Czas powrotu */ +}; + +/** + * Opis zdarzenia \c GG_EVENT_NOTIFY_REPLY60. + */ +struct gg_event_notify60 { + uin_t uin; /**< Numer Gadu-Gadu */ + int status; /**< Nowy status */ + uint32_t remote_ip; /**< Adres IP dla po��cze� bezpo�rednich */ + uint16_t remote_port; /**< Port dla po��cze� bezpo�rednich */ + int version; /**< Wersja protoko�u */ + int image_size; /**< Maksymalny rozmiar obs�ugiwanych obrazk坦w w KiB */ + char *descr; /**< Opis statusu */ + time_t time; /**< Czas powrotu */ +}; + +/** + * Opis zdarzenia \c GG_EVENT_ACK. + */ +struct gg_event_ack { + uin_t recipient; /**< Numer odbiorcy */ + int status; /**< Status dor�czenia */ + int seq; /**< Numer sekwencyjny wiadomo�ci */ +}; + +/** + * Opis zdarzenia \c GG_EVENT_USERLIST. + */ +struct gg_event_userlist { + char type; /**< Rodzaj odpowiedzi */ + char *reply; /**< Tre�� odpowiedzi */ +}; + +/** + * Opis zdarzenia \c GG_EVENT_DCC_VOICE_DATA. + */ +struct gg_event_dcc_voice_data { + uint8_t *data; /**< Dane d添wi�kowe */ + int length; /**< Rozmiar danych d添wi�kowych */ +}; + +/** + * Opis zdarzenia \c GG_EVENT_IMAGE_REQUEST. + */ +struct gg_event_image_request { + uin_t sender; /**< Nadawca 甜�dania */ + uint32_t size; /**< Rozmiar obrazka */ + uint32_t crc32; /**< Suma kontrolna CRC32 */ +}; + +/** + * Opis zdarzenia \c GG_EVENT_IMAGE_REPLY. + */ +struct gg_event_image_reply { + uin_t sender; /**< Nadawca obrazka */ + uint32_t size; /**< Rozmiar obrazka */ + uint32_t crc32; /**< Suma kontrolna CRC32 */ + char *filename; /**< Nazwa pliku */ + char *image; /**< Bufor z obrazkiem */ +}; + +/** + * Opis zdarzenia \c GG_EVENT_XML_EVENT. + */ +struct gg_event_xml_event { + char *data; /**< Bufor z komunikatem */ +}; + +/** + * Opis zdarzenia \c GG_EVENT_DCC7_CONNECTED. + */ +struct gg_event_dcc7_connected { + struct gg_dcc7 *dcc7; /**< Struktura po��czenia */ + // XXX czy co� si� przyda? +}; + +/** + * Opis zdarzenia \c GG_EVENT_DCC7_REJECT. + */ +struct gg_event_dcc7_reject { + struct gg_dcc7 *dcc7; /**< Struktura po��czenia */ + int reason; /**< pow坦d odrzucenia */ +}; + +/** + * Opis zdarzenia \c GG_EVENT_DCC7_ACCEPT. + */ +struct gg_event_dcc7_accept { + struct gg_dcc7 *dcc7; /**< Struktura po��czenia */ + int type; /**< Spos坦b po��czenia (P2P, przez serwer) */ + uint32_t remote_ip; /**< Adres zdalnego klienta */ + uint16_t remote_port; /**< Port zdalnego klienta */ +}; + +/** + * Unia wszystkich zdarze� zwracanych przez funkcje \c gg_watch_fd(), + * \c gg_dcc_watch_fd() i \c gg_dcc7_watch_fd(). * - * struktura opisuj�ca rodzaj zdarzenia. wychodzi z gg_watch_fd() lub - * z gg_dcc_watch_fd() + * \ingroup events + */ +union gg_event_union { + enum gg_failure_t failure; /**< B��d po��czenia (\c GG_EVENT_CONN_FAILED) */ + struct gg_notify_reply *notify; /**< Zmiana statusu kontakt坦w (\c GG_EVENT_NOTIFY) */ + struct gg_event_notify_descr notify_descr; /**< Zmiana statusu kontakt坦w (\c GG_EVENT_NOTIFY_DESCR) */ + struct gg_event_status status; /**< Zmiana statusu kontakt坦w (\c GG_EVENT_STATUS) */ + struct gg_event_status60 status60; /**< Zmiana statusu kontakt坦w (\c GG_EVENT_STATUS60) */ + struct gg_event_notify60 *notify60; /**< Zmiana statusu kontakt坦w (\c GG_EVENT_NOTIFY60) */ + struct gg_event_msg msg; /**< Otrzymano wiadomo�� (\c GG_EVENT_MSG) */ + struct gg_event_ack ack; /**< Potwierdzenie wiadomo�ci (\c GG_EVENT_ACK) */ + struct gg_event_image_request image_request; /**< 纏�danie wys�ania obrazka (\c GG_EVENT_IMAGE_REQUEST) */ + struct gg_event_image_reply image_reply; /**< Odpowied添 z obrazkiem (\c GG_EVENT_IMAGE_REPLY) */ + struct gg_event_userlist userlist; /**< Odpowied添 listy kontakt坦w (\c GG_EVENT_USERLIST) */ + gg_pubdir50_t pubdir50; /**< Odpowied添 katalogu publicznego (\c GG_EVENT_PUBDIR50_*) */ + struct gg_event_xml_event xml_event; /**< Zdarzenie systemowe (\c GG_EVENT_XML_EVENT) */ + struct gg_dcc *dcc_new; /**< Nowe po��czenie bezpo�rednie (\c GG_EVENT_DCC_NEW) */ + enum gg_error_t dcc_error; /**< B��d po��czenia bezpo�redniego (\c GG_EVENT_DCC_ERROR) */ + struct gg_event_dcc_voice_data dcc_voice_data; /**< Dane po��czenia g�osowego (\c GG_EVENT_DCC_VOICE_DATA) */ + struct gg_dcc7 *dcc7_new; /**< Nowe po��czenie bezpo�rednie (\c GG_EVENT_DCC7_NEW) */ + enum gg_error_t dcc7_error; /**< B��d po��czenia bezpo�redniego (\c GG_EVENT_DCC7_ERROR) */ + struct gg_event_dcc7_connected dcc7_connected; /**< Informacja o zestawieniu po��czenia bezpo�redniego (\c GG_EVENT_DCC7_CONNECTED) */ + struct gg_event_dcc7_reject dcc7_reject; /**< Odrzucono po��czenia bezpo�redniego (\c GG_EVENT_DCC7_REJECT) */ + struct gg_event_dcc7_accept dcc7_accept; /**< Zaakceptowano po��czenie bezpo�rednie (\c GG_EVENT_DCC7_ACCEPT) */ +}; + +/** + * Opis zdarzenia. + * + * Zwracany przez funkcje \c gg_watch_fd(), \c gg_dcc_watch_fd() + * i \c gg_dcc7_watch_fd(). Po przeanalizowaniu nale甜y zwolni� + * za pomoc� \c gg_event_free(). + * + * \ingroup events */ struct gg_event { - int type; /* rodzaj zdarzenia -- gg_event_t */ - union { /* @event */ - struct gg_notify_reply *notify; /* informacje o li�cie kontakt�w -- GG_EVENT_NOTIFY */ - - enum gg_failure_t failure; /* b咳d po咳czenia -- GG_EVENT_FAILURE */ - - struct gg_dcc *dcc_new; /* nowe po咳czenie bezpo�rednie -- GG_EVENT_DCC_NEW */ - - int dcc_error; /* b咳d po咳czenia bezpo�redniego -- GG_EVENT_DCC_ERROR */ - - gg_pubdir50_t pubdir50; /* wynik operacji zwi�zanej z katalogiem publicznym -- GG_EVENT_PUBDIR50_* */ - - struct { /* @msg odebrano wiadomo倶 -- GG_EVENT_MSG */ - uin_t sender; /* numer nadawcy */ - int msgclass; /* klasa wiadomo�ci */ - time_t time; /* czas nadania */ - unsigned char *message; /* tre倶 wiadomo�ci */ - - int recipients_count; /* ilo倶 odbiorc�w konferencji */ - uin_t *recipients; /* odbiorcy konferencji */ - - int formats_length; /* d�ugo倶 informacji o formatowaniu tekstu */ - void *formats; /* informacje o formatowaniu tekstu */ - } msg; - - struct { /* @notify_descr informacje o li�cie kontakt�w z opisami stanu -- GG_EVENT_NOTIFY_DESCR */ - struct gg_notify_reply *notify; /* informacje o li�cie kontakt�w */ - char *descr; /* opis stanu */ - } notify_descr; - - struct { /* @status zmiana stanu -- GG_EVENT_STATUS */ - uin_t uin; /* numer */ - uint32_t status; /* nowy stan */ - char *descr; /* opis stanu */ - } status; - - struct { /* @status60 zmiana stanu -- GG_EVENT_STATUS60 */ - uin_t uin; /* numer */ - int status; /* nowy stan */ - uint32_t remote_ip; /* adres ip */ - uint16_t remote_port; /* port */ - int version; /* wersja klienta */ - int image_size; /* maksymalny rozmiar grafiki w KiB */ - char *descr; /* opis stanu */ - time_t time; /* czas powrotu */ - } status60; - - struct { /* @notify60 informacja o li�cie kontakt�w -- GG_EVENT_NOTIFY60 */ - uin_t uin; /* numer */ - int status; /* stan */ - uint32_t remote_ip; /* adres ip */ - uint16_t remote_port; /* port */ - int version; /* wersja klienta */ - int image_size; /* maksymalny rozmiar grafiki w KiB */ - char *descr; /* opis stanu */ - time_t time; /* czas powrotu */ - } *notify60; - - struct { /* @ack potwierdzenie wiadomo�ci -- GG_EVENT_ACK */ - uin_t recipient; /* numer odbiorcy */ - int status; /* stan dor�czenia wiadomo�ci */ - int seq; /* numer sekwencyjny wiadomo�ci */ - } ack; - - struct { /* @dcc_voice_data otrzymano dane d�wi�kowe -- GG_EVENT_DCC_VOICE_DATA */ - uint8_t *data; /* dane d�wi�kowe */ - int length; /* ilo倶 danych d�wi�kowych */ - } dcc_voice_data; - - struct { /* @userlist odpowied� listy kontakt�w serwera */ - char type; /* rodzaj odpowiedzi */ - char *reply; /* tre倶 odpowiedzi */ - } userlist; - - struct { /* @image_request pro�ba o obrazek */ - uin_t sender; /* nadawca pro�by */ - uint32_t size; /* rozmiar obrazka */ - uint32_t crc32; /* suma kontrolna */ - } image_request; - - struct { /* @image_reply odpowied� z obrazkiem */ - uin_t sender; /* nadawca odpowiedzi */ - uint32_t size; /* rozmiar obrazka */ - uint32_t crc32; /* suma kontrolna */ - char *filename; /* nazwa pliku */ - char *image; /* bufor z obrazkiem */ - } image_reply; - } event; + int type; /**< Rodzaj zdarzenia */ + union gg_event_union event; /**< Informacja o zdarzeniu */ }; struct gg_event *gg_watch_fd(struct gg_session *sess); void gg_event_free(struct gg_event *e); -#define gg_free_event gg_event_free -/* - * funkcje obs�ugi listy kontakt�w. - */ int gg_notify_ex(struct gg_session *sess, uin_t *userlist, char *types, int count); int gg_notify(struct gg_session *sess, uin_t *userlist, int count); int gg_add_notify_ex(struct gg_session *sess, uin_t uin, char type); @@ -600,76 +935,11 @@ int gg_remove_notify_ex(struct gg_session *sess, uin_t uin, char type); int gg_remove_notify(struct gg_session *sess, uin_t uin); -/* - * funkcje obs�ugi http. - */ struct gg_http *gg_http_connect(const char *hostname, int port, int async, const char *method, const char *path, const char *header); int gg_http_watch_fd(struct gg_http *h); void gg_http_stop(struct gg_http *h); void gg_http_free(struct gg_http *h); -void gg_http_free_fields(struct gg_http *h); -#define gg_free_http gg_http_free -/* - * struktury opisuj�ca kryteria wyszukiwania dla gg_search(). nieaktualne, - * zast�pione przez gg_pubdir50_t. pozostawiono je dla zachowania ABI. - */ -struct gg_search_request { - int active; - unsigned int start; - char *nickname; - char *first_name; - char *last_name; - char *city; - int gender; - int min_birth; - int max_birth; - char *email; - char *phone; - uin_t uin; -}; - -struct gg_search { - int count; - struct gg_search_result *results; -}; - -struct gg_search_result { - uin_t uin; - char *first_name; - char *last_name; - char *nickname; - int born; - int gender; - char *city; - int active; -}; - -#define GG_GENDER_NONE 0 -#define GG_GENDER_FEMALE 1 -#define GG_GENDER_MALE 2 - -/* - * funkcje wyszukiwania. - */ -struct gg_http *gg_search(const struct gg_search_request *r, int async); -int gg_search_watch_fd(struct gg_http *f); -void gg_free_search(struct gg_http *f); -#define gg_search_free gg_free_search - -const struct gg_search_request *gg_search_request_mode_0(char *nickname, char *first_name, char *last_name, char *city, int gender, int min_birth, int max_birth, int active, int start); -const struct gg_search_request *gg_search_request_mode_1(char *email, int active, int start); -const struct gg_search_request *gg_search_request_mode_2(char *phone, int active, int start); -const struct gg_search_request *gg_search_request_mode_3(uin_t uin, int active, int start); -void gg_search_request_free(struct gg_search_request *r); - -/* - * funkcje obs�ugi katalogu publicznego zgodne z GG 5.0. tym razem funkcje - * zachowuj� pewien poziom abstrakcji, �eby unikn掩 zmian ABI przy zmianach - * w protokole. - * - * NIE NALE�Y SI� ODWO�YWA� DO P�L gg_pubdir50_t BEZPO�REDNIO! - */ uint32_t gg_pubdir50(struct gg_session *sess, gg_pubdir50_t req); gg_pubdir50_t gg_pubdir50_new(int type); int gg_pubdir50_add(gg_pubdir50_t req, const char *field, const char *value); @@ -681,6 +951,8 @@ uint32_t gg_pubdir50_seq(gg_pubdir50_t res); void gg_pubdir50_free(gg_pubdir50_t res); +#ifndef DOXYGEN + #define GG_PUBDIR50_UIN "FmNumber" #define GG_PUBDIR50_STATUS "FmStatus" #define GG_PUBDIR50_FIRSTNAME "firstname" @@ -699,110 +971,114 @@ #define GG_PUBDIR50_FAMILYNAME "familyname" #define GG_PUBDIR50_FAMILYCITY "familycity" -int gg_pubdir50_handle_reply(struct gg_event *e, const char *packet, int length); +#else -/* - * struct gg_pubdir +/** + * \ingroup pubdir50 * - * operacje na katalogu publicznym. + * Rodzaj pola zapytania. */ -struct gg_pubdir { - int success; /* czy si� uda�o */ - uin_t uin; /* otrzymany numerek. 0 je�li b咳d */ +enum { + GG_PUBDIR50_UIN, /**< Numer Gadu-Gadu */ + GG_PUBDIR50_STATUS, /**< Status (tylko wynik wyszukiwania) */ + GG_PUBDIR50_FIRSTNAME, /**< Imi� */ + GG_PUBDIR50_LASTNAME, /**< Nazwisko */ + GG_PUBDIR50_NICKNAME, /**< Pseudonim */ + GG_PUBDIR50_BIRTHYEAR, /**< Rok urodzenia lub przedzia� lat oddzielony spacj� */ + GG_PUBDIR50_CITY, /**< Miejscowo�� */ + GG_PUBDIR50_GENDER, /**< P�e� */ + GG_PUBDIR50_ACTIVE, /**< Osoba dost�pna (tylko wyszukiwanie) */ + GG_PUBDIR50_START, /**< Numer pocz�tkowy wyszukiwania (tylko wyszukiwanie) */ + GG_PUBDIR50_FAMILYNAME, /**< Nazwisko rodowe (tylko wysy�anie informacji o sobie) */ + GG_PUBDIR50_FAMILYCITY, /**< Miejscowo�� pochodzenia (tylko wysy�anie informacji o sobie) */ +}; + +/** + * \ingroup pubdir50 + * + * Warto�� pola GG_PUBDIR50_GENDER przy wyszukiwaniu. Brak pola oznacza dowoln� p�e�. + */ +enum { + GG_PUBDIR50_GENDER_FEMALE, /**< Kobieta */ + GG_PUBDIR50_GENDER_MALE, /**< M�甜czyzna */ }; -/* og�lne funkcje, nie powinny by� u�ywane */ +/** + * \ingroup pubdir50 + * + * Warto�� pola GG_PUBDIR50_GENDER przy wysy�aniu informacji o sobie. + */ +enum { + GG_PUBDIR50_GENDER_SET_FEMALE, /**< Kobieta */ + GG_PUBDIR50_GENDER_SET_MALE, /**< M�甜czyzna */ +}; + +/** + * \ingroup pubdir50 + * + * Warto�� pola GG_PUBDIR50_ACTIVE. + */ +enum { + GG_PUBDIR50_ACTIVE_TRUE, /**< Wyszukaj tylko osoby dost�pne */ +}; + +#endif /* DOXYGEN */ + +/** + * Wynik operacji na katalogu publicznym. + * + * \ingroup http + */ +struct gg_pubdir { + int success; /**< Flaga powodzenia operacji */ + uin_t uin; /**< Otrzymany numer lub 0 w przypadku b��du */ +}; + int gg_pubdir_watch_fd(struct gg_http *f); void gg_pubdir_free(struct gg_http *f); -#define gg_free_pubdir gg_pubdir_free +/** + * Token autoryzacji niekt坦rych operacji HTTP. + * + * \ingroup token + */ struct gg_token { - int width; /* szeroko倶 obrazka */ - int height; /* wysoko倶 obrazka */ - int length; /* ilo倶 znak�w w tokenie */ - char *tokenid; /* id tokenu */ + int width; /**< Szeroko�� obrazka */ + int height; /**< Wysoko�� obrazka */ + int length; /**< Liczba znak坦w w tokenie */ + char *tokenid; /**< Identyfikator tokenu */ }; -/* funkcje dotycz�ce token�w */ struct gg_http *gg_token(int async); int gg_token_watch_fd(struct gg_http *h); void gg_token_free(struct gg_http *h); -/* rejestracja nowego numerka */ -struct gg_http *gg_register(const char *email, const char *password, int async); -struct gg_http *gg_register2(const char *email, const char *password, const char *qa, int async); struct gg_http *gg_register3(const char *email, const char *password, const char *tokenid, const char *tokenval, int async); +#ifndef DOXYGEN #define gg_register_watch_fd gg_pubdir_watch_fd #define gg_register_free gg_pubdir_free -#define gg_free_register gg_pubdir_free +#endif -struct gg_http *gg_unregister(uin_t uin, const char *password, const char *email, int async); -struct gg_http *gg_unregister2(uin_t uin, const char *password, const char *qa, int async); struct gg_http *gg_unregister3(uin_t uin, const char *password, const char *tokenid, const char *tokenval, int async); +#ifndef DOXYGEN #define gg_unregister_watch_fd gg_pubdir_watch_fd #define gg_unregister_free gg_pubdir_free +#endif -/* przypomnienie has�a e-mailem */ -struct gg_http *gg_remind_passwd(uin_t uin, int async); -struct gg_http *gg_remind_passwd2(uin_t uin, const char *tokenid, const char *tokenval, int async); struct gg_http *gg_remind_passwd3(uin_t uin, const char *email, const char *tokenid, const char *tokenval, int async); +#ifndef DOXYGEN #define gg_remind_passwd_watch_fd gg_pubdir_watch_fd #define gg_remind_passwd_free gg_pubdir_free -#define gg_free_remind_passwd gg_pubdir_free - -/* zmiana has�a */ -struct gg_http *gg_change_passwd(uin_t uin, const char *passwd, const char *newpasswd, const char *newemail, int async); -struct gg_http *gg_change_passwd2(uin_t uin, const char *passwd, const char *newpasswd, const char *email, const char *newemail, int async); -struct gg_http *gg_change_passwd3(uin_t uin, const char *passwd, const char *newpasswd, const char *qa, int async); -struct gg_http *gg_change_passwd4(uin_t uin, const char *email, const char *passwd, const char *newpasswd, const char *tokenid, const char *tokenval, int async); -#define gg_change_passwd_free gg_pubdir_free -#define gg_free_change_passwd gg_pubdir_free - -/* - * struct gg_change_info_request - * - * opis 娠dania zmiany informacji w katalogu publicznym. - */ -struct gg_change_info_request { - char *first_name; /* imi� */ - char *last_name; /* nazwisko */ - char *nickname; /* pseudonim */ - char *email; /* email */ - int born; /* rok urodzenia */ - int gender; /* p�e� */ - char *city; /* miasto */ -}; - -struct gg_change_info_request *gg_change_info_request_new(const char *first_name, const char *last_name, const char *nickname, const char *email, int born, int gender, const char *city); -void gg_change_info_request_free(struct gg_change_info_request *r); +#endif -struct gg_http *gg_change_info(uin_t uin, const char *passwd, const struct gg_change_info_request *request, int async); -#define gg_change_pubdir_watch_fd gg_pubdir_watch_fd -#define gg_change_pubdir_free gg_pubdir_free -#define gg_free_change_pubdir gg_pubdir_free - -/* - * funkcje dotycz�ce listy kontakt�w na serwerze. - */ -struct gg_http *gg_userlist_get(uin_t uin, const char *password, int async); -int gg_userlist_get_watch_fd(struct gg_http *f); -void gg_userlist_get_free(struct gg_http *f); +struct gg_http *gg_change_passwd4(uin_t uin, const char *email, const char *passwd, const char *newpasswd, const char *tokenid, const char *tokenval, int async); +#ifndef DOXYGEN +#define gg_change_passwd_watch_fd gg_pubdir_watch_fd +#define gg_change_passwd_free gg_pubdir_free +#endif -struct gg_http *gg_userlist_put(uin_t uin, const char *password, const char *contacts, int async); -int gg_userlist_put_watch_fd(struct gg_http *f); -void gg_userlist_put_free(struct gg_http *f); - -struct gg_http *gg_userlist_remove(uin_t uin, const char *password, int async); -int gg_userlist_remove_watch_fd(struct gg_http *f); -void gg_userlist_remove_free(struct gg_http *f); - - - -/* - * funkcje dotycz�ce komunikacji mi�dzy klientami. - */ -extern int gg_dcc_port; /* port, na kt�rym nas�uchuje klient */ -extern unsigned long gg_dcc_ip; /* adres, na kt�rym nas�uchuje klient */ +extern int gg_dcc_port; +extern unsigned long gg_dcc_ip; int gg_dcc_request(struct gg_session *sess, uin_t uin); @@ -814,119 +1090,248 @@ int gg_dcc_fill_file_info2(struct gg_dcc *d, const char *filename, const char *local_filename); int gg_dcc_voice_send(struct gg_dcc *d, char *buf, int length); -#define GG_DCC_VOICE_FRAME_LENGTH 195 -#define GG_DCC_VOICE_FRAME_LENGTH_505 326 +#define GG_DCC_VOICE_FRAME_LENGTH 195 /**< Rozmiar pakietu g�osowego przed wersj� Gadu-Gadu 5.0.5 */ +#define GG_DCC_VOICE_FRAME_LENGTH_505 326 /**< Rozmiar pakietu g�osowego od wersji Gadu-Gadu 5.0.5 */ struct gg_dcc *gg_dcc_socket_create(uin_t uin, uint16_t port); -#define gg_dcc_socket_free gg_free_dcc +#ifndef DOXYGEN +#define gg_dcc_socket_free gg_dcc_free #define gg_dcc_socket_watch_fd gg_dcc_watch_fd +#endif struct gg_event *gg_dcc_watch_fd(struct gg_dcc *d); void gg_dcc_free(struct gg_dcc *c); -#define gg_free_dcc gg_dcc_free - -/* - * je�li chcemy sobie podebugowa�, wystarczy ustawi� `gg_debug_level'. - * niestety w miar� przybywania wpis�w `gg_debug(...)' nie chcia�o mi - * si� ustawia� odpowiednich leveli, wi�c wi�kszo倶 sz�a do _MISC. - */ -extern int gg_debug_level; /* poziom debugowania. mapa bitowa sta�ych GG_DEBUG_* */ -/* - * mo�na poda� wska�nik do funkcji obs�uguj�cej wywo�ania gg_debug(). - * nieoficjalne, nieudokumentowane, mo�e si� zmieni�. je�li kto� jest - * zainteresowany, niech da zna� na ekg-devel. - */ +struct gg_event *gg_dcc7_watch_fd(struct gg_dcc7 *d); +struct gg_dcc7 *gg_dcc7_send_file(struct gg_session *sess, uin_t rcpt, const char *filename, const char *filename1250, const char *hash); +struct gg_dcc7 *gg_dcc7_send_file_fd(struct gg_session *sess, uin_t rcpt, int fd, size_t size, const char *filename1250, const char *hash); +int gg_dcc7_accept(struct gg_dcc7 *dcc, unsigned int offset); +int gg_dcc7_reject(struct gg_dcc7 *dcc, int reason); +void gg_dcc7_free(struct gg_dcc7 *d); + +extern int gg_debug_level; + extern void (*gg_debug_handler)(int level, const char *format, va_list ap); +extern void (*gg_debug_handler_session)(struct gg_session *sess, int level, const char *format, va_list ap); -/* - * mo�na poda� plik, do kt�rego b�d� zapisywane teksty z gg_debug(). - */ extern FILE *gg_debug_file; -#define GG_DEBUG_NET 1 -#define GG_DEBUG_TRAFFIC 2 -#define GG_DEBUG_DUMP 4 -#define GG_DEBUG_FUNCTION 8 -#define GG_DEBUG_MISC 16 +/** + * \ingroup debug + * @{ + */ +#define GG_DEBUG_NET 1 /**< Rejestracja zdarze� zwi�zanych z sieci� */ +#define GG_DEBUG_TRAFFIC 2 /**< Rejestracja ruchu sieciowego */ +#define GG_DEBUG_DUMP 4 /**< Rejestracja zawarto�ci pakiet坦w */ +#define GG_DEBUG_FUNCTION 8 /**< Rejestracja wywo�a� funkcji */ +#define GG_DEBUG_MISC 16 /**< Rejestracja r坦甜nych informacji */ +/** @} */ #ifdef GG_DEBUG_DISABLE #define gg_debug(x, y...) do { } while(0) +#define gg_debug_session(z, x, y...) do { } while(0) #else void gg_debug(int level, const char *format, ...); +void gg_debug_session(struct gg_session *sess, int level, const char *format, ...); #endif const char *gg_libgadu_version(void); -/* - * konfiguracja http proxy. - */ -extern int gg_proxy_enabled; /* w咳cza obs�ug� proxy */ -extern char *gg_proxy_host; /* okre�la adres serwera proxy */ -extern int gg_proxy_port; /* okre�la port serwera proxy */ -extern char *gg_proxy_username; /* okre�la nazw� u�ytkownika przy autoryzacji serwera proxy */ -extern char *gg_proxy_password; /* okre�la has�o u�ytkownika przy autoryzacji serwera proxy */ -extern int gg_proxy_http_only; /* w咳cza obs�ug� proxy wy咳cznie dla us�ug HTTP */ +extern int gg_proxy_enabled; +extern char *gg_proxy_host; +extern int gg_proxy_port; +extern char *gg_proxy_username; +extern char *gg_proxy_password; +extern int gg_proxy_http_only; + +extern unsigned long gg_local_ip; + +#define GG_LOGIN_HASH_GG32 0x01 /**< Algorytm Gadu-Gadu */ +#define GG_LOGIN_HASH_SHA1 0x02 /**< Algorytm SHA1 */ +#ifndef DOXYGEN -/* - * adres, z kt�rego �lemy pakiety (np 咳czymy si� z serwerem) - * u�ywany przy gg_connect() +#define GG_PUBDIR50_WRITE 0x01 +#define GG_PUBDIR50_READ 0x02 +#define GG_PUBDIR50_SEARCH 0x03 +#define GG_PUBDIR50_SEARCH_REQUEST GG_PUBDIR50_SEARCH +#define GG_PUBDIR50_SEARCH_REPLY 0x05 + +#else + +/** + * \ingroup pubdir50 + * + * Rodzaj zapytania lub odpowiedzi katalogu publicznego. */ -extern unsigned long gg_local_ip; -/* - * ------------------------------------------------------------------------- - * poni�ej znajduj� si� wewn�trzne sprawy biblioteki. zwyk�y klient nie - * powinien ich w og�le rusza�, bo i nie ma po co. wszystko mo�na za�atwi� - * procedurami wy�szego poziomu, kt�rych definicje znajduj� si� na pocz�tku - * tego pliku. - * ------------------------------------------------------------------------- - */ +enum { + GG_PUBDIR50_WRITE, /**< Wys�anie do serwera informacji o sobie */ + GG_PUBDIR50_READ, /**< Pobranie z serwera informacji o sobie */ + GG_PUBDIR50_SEARCH, /**< Wyszukiwanie w katalogu publicznym */ + GG_PUBDIR50_SEARCH_REPLY, /**< Wynik wyszukiwania w katalogu publicznym */ +}; + +#endif /* DOXYGEN */ + +/** \cond obsolete */ + +#define gg_free_event gg_event_free +#define gg_free_http gg_http_free +#define gg_free_pubdir gg_pubdir_free +#define gg_free_register gg_pubdir_free +#define gg_free_remind_passwd gg_pubdir_free +#define gg_free_dcc gg_dcc_free +#define gg_free_change_passwd gg_pubdir_free + +struct gg_search_request { + int active; + unsigned int start; + char *nickname; + char *first_name; + char *last_name; + char *city; + int gender; + int min_birth; + int max_birth; + char *email; + char *phone; + uin_t uin; +} /* GG_DEPRECATED */; + +struct gg_search { + int count; + struct gg_search_result *results; +} GG_DEPRECATED; + +struct gg_search_result { + uin_t uin; + char *first_name; + char *last_name; + char *nickname; + int born; + int gender; + char *city; + int active; +} GG_DEPRECATED; + +#define GG_GENDER_NONE 0 +#define GG_GENDER_FEMALE 1 +#define GG_GENDER_MALE 2 + +struct gg_http *gg_search(const struct gg_search_request *r, int async) GG_DEPRECATED; +int gg_search_watch_fd(struct gg_http *f) GG_DEPRECATED; +void gg_free_search(struct gg_http *f) GG_DEPRECATED; +#define gg_search_free gg_free_search -#ifdef __GG_LIBGADU_HAVE_PTHREAD -int gg_resolve_pthread(int *fd, void **resolver, const char *hostname); -#elif defined _WIN32 -int gg_resolve_win32thread(int *fd, void **resolver, const char *hostname); +const struct gg_search_request *gg_search_request_mode_0(char *nickname, char *first_name, char *last_name, char *city, int gender, int min_birth, int max_birth, int active, int start) GG_DEPRECATED; +const struct gg_search_request *gg_search_request_mode_1(char *email, int active, int start) GG_DEPRECATED; +const struct gg_search_request *gg_search_request_mode_2(char *phone, int active, int start) GG_DEPRECATED; +const struct gg_search_request *gg_search_request_mode_3(uin_t uin, int active, int start) GG_DEPRECATED; +void gg_search_request_free(struct gg_search_request *r) GG_DEPRECATED; + +struct gg_http *gg_register(const char *email, const char *password, int async) GG_DEPRECATED; +struct gg_http *gg_register2(const char *email, const char *password, const char *qa, int async) GG_DEPRECATED; + +struct gg_http *gg_unregister(uin_t uin, const char *password, const char *email, int async) GG_DEPRECATED; +struct gg_http *gg_unregister2(uin_t uin, const char *password, const char *qa, int async) GG_DEPRECATED; + +struct gg_http *gg_remind_passwd(uin_t uin, int async) GG_DEPRECATED; +struct gg_http *gg_remind_passwd2(uin_t uin, const char *tokenid, const char *tokenval, int async) GG_DEPRECATED; + +struct gg_http *gg_change_passwd(uin_t uin, const char *passwd, const char *newpasswd, const char *newemail, int async) GG_DEPRECATED; +struct gg_http *gg_change_passwd2(uin_t uin, const char *passwd, const char *newpasswd, const char *email, const char *newemail, int async) GG_DEPRECATED; +struct gg_http *gg_change_passwd3(uin_t uin, const char *passwd, const char *newpasswd, const char *qa, int async) GG_DEPRECATED; + +struct gg_change_info_request { + char *first_name; + char *last_name; + char *nickname; + char *email; + int born; + int gender; + char *city; +} /* GG_DEPRECATED */; + +struct gg_change_info_request *gg_change_info_request_new(const char *first_name, const char *last_name, const char *nickname, const char *email, int born, int gender, const char *city) GG_DEPRECATED; +void gg_change_info_request_free(struct gg_change_info_request *r) GG_DEPRECATED; + +struct gg_http *gg_change_info(uin_t uin, const char *passwd, const struct gg_change_info_request *request, int async) GG_DEPRECATED; +#define gg_change_pubdir_watch_fd gg_pubdir_watch_fd +#define gg_change_pubdir_free gg_pubdir_free +#define gg_free_change_pubdir gg_pubdir_free + +struct gg_http *gg_userlist_get(uin_t uin, const char *password, int async) GG_DEPRECATED; +int gg_userlist_get_watch_fd(struct gg_http *f) GG_DEPRECATED; +void gg_userlist_get_free(struct gg_http *f) GG_DEPRECATED; + +struct gg_http *gg_userlist_put(uin_t uin, const char *password, const char *contacts, int async) GG_DEPRECATED; +int gg_userlist_put_watch_fd(struct gg_http *f) GG_DEPRECATED; +void gg_userlist_put_free(struct gg_http *f) GG_DEPRECATED; + +struct gg_http *gg_userlist_remove(uin_t uin, const char *password, int async) GG_DEPRECATED; +int gg_userlist_remove_watch_fd(struct gg_http *f) GG_DEPRECATED; +void gg_userlist_remove_free(struct gg_http *f) GG_DEPRECATED; + +int gg_pubdir50_handle_reply(struct gg_event *e, const char *packet, int length) GG_DEPRECATED; + +/** \endcond */ + +int gg_file_hash_sha1(int fd, uint8_t *result) GG_DEPRECATED; + +#ifdef __GNUC__ +char *gg_saprintf(const char *format, ...) __attribute__ ((format (printf, 1, 2))) GG_DEPRECATED; +#else +char *gg_saprintf(const char *format, ...) GG_DEPRECATED; #endif -#ifdef _WIN32 -int gg_thread_socket(int thread_id, int socket); -#endif - -int gg_resolve(int *fd, int *pid, const char *hostname); - -#if defined __GNUC__ && !defined _WIN32 -char *gg_saprintf(const char *format, ...) __attribute__ ((format (printf, 1, 2))); -#else -char *gg_saprintf(const char *format, ...); -#endif - -char *gg_vsaprintf(const char *format, va_list ap); +char *gg_vsaprintf(const char *format, va_list ap) GG_DEPRECATED; #define gg_alloc_sprintf gg_saprintf -char *gg_get_line(char **ptr); +char *gg_get_line(char **ptr) GG_DEPRECATED; -int gg_connect(void *addr, int port, int async); -struct in_addr *gg_gethostbyname(const char *hostname); -char *gg_read_line(int sock, char *buf, int length); -void gg_chomp(char *line); -char *gg_urlencode(const char *str); -int gg_http_hash(const char *format, ...); -int gg_read(struct gg_session *sess, char *buf, int length); -int gg_write(struct gg_session *sess, const char *buf, int length); -void *gg_recv_packet(struct gg_session *sess); -int gg_send_packet(struct gg_session *sess, int type, ...); -unsigned int gg_login_hash(const unsigned char *password, unsigned int seed); -uint32_t gg_fix32(uint32_t x); -uint16_t gg_fix16(uint16_t x); +int gg_connect(void *addr, int port, int async) GG_DEPRECATED; +struct in_addr *gg_gethostbyname(const char *hostname) GG_DEPRECATED; +char *gg_read_line(int sock, char *buf, int length) GG_DEPRECATED; +void gg_chomp(char *line) GG_DEPRECATED; +char *gg_urlencode(const char *str) GG_DEPRECATED; +int gg_http_hash(const char *format, ...) GG_DEPRECATED; +void gg_http_free_fields(struct gg_http *h) GG_DEPRECATED; +int gg_read(struct gg_session *sess, char *buf, int length) GG_DEPRECATED; +int gg_write(struct gg_session *sess, const char *buf, int length) GG_DEPRECATED; +void *gg_recv_packet(struct gg_session *sess) GG_DEPRECATED; +int gg_send_packet(struct gg_session *sess, int type, ...) GG_DEPRECATED; +unsigned int gg_login_hash(const unsigned char *password, unsigned int seed) GG_DEPRECATED; +void gg_login_hash_sha1(const char *password, uint32_t seed, uint8_t *result) GG_DEPRECATED; +uint32_t gg_fix32(uint32_t x) GG_DEPRECATED; +uint16_t gg_fix16(uint16_t x) GG_DEPRECATED; #define fix16 gg_fix16 #define fix32 gg_fix32 -char *gg_proxy_auth(void); -char *gg_base64_encode(const char *buf); -char *gg_base64_decode(const char *buf); -int gg_image_queue_remove(struct gg_session *s, struct gg_image_queue *q, int freeq); +char *gg_proxy_auth(void) GG_DEPRECATED; +char *gg_base64_encode(const char *buf) GG_DEPRECATED; +char *gg_base64_decode(const char *buf) GG_DEPRECATED; +int gg_image_queue_remove(struct gg_session *s, struct gg_image_queue *q, int freeq) GG_DEPRECATED; + +/** + * Kolejka odbieranych obrazk坦w. + */ +struct gg_image_queue { + uin_t sender; /**< Nadawca obrazka */ + uint32_t size; /**< Rozmiar obrazka */ + uint32_t crc32; /**< Suma kontrolna CRC32 */ + char *filename; /**< Nazwa pliku */ + char *image; /**< Bufor z odebranymi danymi */ + uint32_t done; /**< Rozmiar odebranych danych */ + + struct gg_image_queue *next; /**< Kolejny element listy */ +} GG_DEPRECATED; + +int gg_dcc7_handle_id(struct gg_session *sess, struct gg_event *e, void *payload, int len) GG_DEPRECATED; +int gg_dcc7_handle_new(struct gg_session *sess, struct gg_event *e, void *payload, int len) GG_DEPRECATED; +int gg_dcc7_handle_info(struct gg_session *sess, struct gg_event *e, void *payload, int len) GG_DEPRECATED; +int gg_dcc7_handle_accept(struct gg_session *sess, struct gg_event *e, void *payload, int len) GG_DEPRECATED; +int gg_dcc7_handle_reject(struct gg_session *sess, struct gg_event *e, void *payload, int len) GG_DEPRECATED; #define GG_APPMSG_HOST "appmsg.gadu-gadu.pl" #define GG_APPMSG_PORT 80 @@ -941,63 +1346,111 @@ #define GG_HTTPS_PORT 443 #define GG_HTTP_USERAGENT "Mozilla/4.7 [en] (Win98; I)" -#define GG_DEFAULT_CLIENT_VERSION "6, 1, 0, 158" -#define GG_DEFAULT_PROTOCOL_VERSION 0x24 +#define GG_DEFAULT_CLIENT_VERSION "8.0.0.7669" +#define GG_DEFAULT_PROTOCOL_VERSION 0x2e #define GG_DEFAULT_TIMEOUT 30 #define GG_HAS_AUDIO_MASK 0x40000000 +#define GG_HAS_AUDIO7_MASK 0x20000000 #define GG_ERA_OMNIX_MASK 0x04000000 -#define GG_LIBGADU_VERSION "1.5.20050718" +#undef GG_LIBGADU_VERSION + +#ifndef DOXYGEN + +#define GG_FEATURE_MSG77 0x01 +#define GG_FEATURE_STATUS77 0x02 +#define GG_FEATURE_DND_FFC 0x10 +#define GG_FEATURE_IMAGE_DESCR 0x20 + +/* Poni甜sze makra zosta�y zachowane dla zgodno�ci API */ +#define GG_FEATURE_MSG80 0 +#define GG_FEATURE_STATUS80 0 +#define GG_FEATURE_STATUS80BETA 0 +#define GG_FEATURE_ALL (GG_FEATURE_DND_FFC | GG_FEATURE_IMAGE_DESCR) + +#else + +/** + * \ingroup login + * + * Flagi opcji protoko�u. + */ +enum { + GG_FEATURE_MSG77, /**< Klient 甜yczy sobie otrzymywa� wiadomo�ci zgodnie z protoko�em 7.7 */ + GG_FEATURE_STATUS77, /**< Klient 甜yczy sobie otrzymywa� zmiany stanu zgodnie z protoko�em 7.7 */ + GG_FEATURE_DND_FFC, /**< Klient obs�uguje statusy "nie przeszkadza�" i "poGGadaj ze mn�" */ + GG_FEATURE_IMAGE_DESCR, /**< Klient obs�uguje opisy graficzne oraz flag� \c GG_STATUS80_DESCR_MASK */ +}; + + +#endif #define GG_DEFAULT_DCC_PORT 1550 struct gg_header { uint32_t type; /* typ pakietu */ - uint32_t length; /* d�ugo倶 reszty pakietu */ + uint32_t length; /* d�ugo�� reszty pakietu */ } GG_PACKED; #define GG_WELCOME 0x0001 #define GG_NEED_EMAIL 0x0014 struct gg_welcome { - uint32_t key; /* klucz szyfrowania has�a */ + uint32_t key; /* klucz szyfrowania has�a */ } GG_PACKED; #define GG_LOGIN 0x000c struct gg_login { - uint32_t uin; /* m�j numerek */ - uint32_t hash; /* hash has�a */ - uint32_t status; /* status na dzie� dobry */ + uint32_t uin; /* m坦j numerek */ + uint32_t hash; /* hash has�a */ + uint32_t status; /* status na dzie� dobry */ uint32_t version; /* moja wersja klienta */ - uint32_t local_ip; /* m�j adres ip */ - uint16_t local_port; /* port, na kt�rym s�ucham */ + uint32_t local_ip; /* m坦j adres ip */ + uint16_t local_port; /* port, na kt坦rym s�ucham */ } GG_PACKED; #define GG_LOGIN_EXT 0x0013 struct gg_login_ext { - uint32_t uin; /* m�j numerek */ - uint32_t hash; /* hash has�a */ - uint32_t status; /* status na dzie� dobry */ + uint32_t uin; /* m坦j numerek */ + uint32_t hash; /* hash has�a */ + uint32_t status; /* status na dzie� dobry */ uint32_t version; /* moja wersja klienta */ - uint32_t local_ip; /* m�j adres ip */ - uint16_t local_port; /* port, na kt�rym s�ucham */ - uint32_t external_ip; /* zewn�trzny adres ip */ - uint16_t external_port; /* zewn�trzny port */ + uint32_t local_ip; /* m坦j adres ip */ + uint16_t local_port; /* port, na kt坦rym s�ucham */ + uint32_t external_ip; /* zewn�trzny adres ip */ + uint16_t external_port; /* zewn�trzny port */ } GG_PACKED; #define GG_LOGIN60 0x0015 struct gg_login60 { - uint32_t uin; /* m�j numerek */ - uint32_t hash; /* hash has�a */ - uint32_t status; /* status na dzie� dobry */ + uint32_t uin; /* m坦j numerek */ + uint32_t hash; /* hash has�a */ + uint32_t status; /* status na dzie� dobry */ uint32_t version; /* moja wersja klienta */ uint8_t dunno1; /* 0x00 */ - uint32_t local_ip; /* m�j adres ip */ - uint16_t local_port; /* port, na kt�rym s�ucham */ - uint32_t external_ip; /* zewn�trzny adres ip */ - uint16_t external_port; /* zewn�trzny port */ + uint32_t local_ip; /* m坦j adres ip */ + uint16_t local_port; /* port, na kt坦rym s�ucham */ + uint32_t external_ip; /* zewn�trzny adres ip */ + uint16_t external_port; /* zewn�trzny port */ + uint8_t image_size; /* maksymalny rozmiar grafiki w KiB */ + uint8_t dunno2; /* 0xbe */ +} GG_PACKED; + +#define GG_LOGIN70 0x0019 + +struct gg_login70 { + uint32_t uin; /* m坦j numerek */ + uint8_t hash_type; /* rodzaj hashowania has�a */ + uint8_t hash[64]; /* hash has�a dope�niony zerami */ + uint32_t status; /* status na dzie� dobry */ + uint32_t version; /* moja wersja klienta */ + uint8_t dunno1; /* 0x00 */ + uint32_t local_ip; /* m坦j adres ip */ + uint16_t local_port; /* port, na kt坦rym s�ucham */ + uint32_t external_ip; /* zewn�trzny adres ip (???) */ + uint16_t external_port; /* zewn�trzny port (???) */ uint8_t image_size; /* maksymalny rozmiar grafiki w KiB */ uint8_t dunno2; /* 0xbe */ } GG_PACKED; @@ -1008,70 +1461,135 @@ #define GG_PUBDIR50_REQUEST 0x0014 -#define GG_PUBDIR50_WRITE 0x01 -#define GG_PUBDIR50_READ 0x02 -#define GG_PUBDIR50_SEARCH 0x03 -#define GG_PUBDIR50_SEARCH_REQUEST GG_PUBDIR50_SEARCH -#define GG_PUBDIR50_SEARCH_REPLY 0x05 - struct gg_pubdir50_request { uint8_t type; /* GG_PUBDIR50_* */ - uint32_t seq; /* czas wys�ania zapytania */ + uint32_t seq; /* czas wys�ania zapytania */ } GG_PACKED; #define GG_PUBDIR50_REPLY 0x000e struct gg_pubdir50_reply { uint8_t type; /* GG_PUBDIR50_* */ - uint32_t seq; /* czas wys�ania zapytania */ + uint32_t seq; /* czas wys�ania zapytania */ } GG_PACKED; #define GG_NEW_STATUS 0x0002 -#define GG_STATUS_NOT_AVAIL 0x0001 /* niedost�pny */ -#define GG_STATUS_NOT_AVAIL_DESCR 0x0015 /* niedost�pny z opisem (4.8) */ -#define GG_STATUS_AVAIL 0x0002 /* dost�pny */ -#define GG_STATUS_AVAIL_DESCR 0x0004 /* dost�pny z opisem (4.9) */ -#define GG_STATUS_BUSY 0x0003 /* zaj�ty */ -#define GG_STATUS_BUSY_DESCR 0x0005 /* zaj�ty z opisem (4.8) */ -#define GG_STATUS_INVISIBLE 0x0014 /* niewidoczny (4.6) */ -#define GG_STATUS_INVISIBLE_DESCR 0x0016 /* niewidoczny z opisem (4.9) */ -#define GG_STATUS_BLOCKED 0x0006 /* zablokowany */ +#ifndef DOXYGEN + +#define GG_STATUS_NOT_AVAIL 0x0001 +#define GG_STATUS_NOT_AVAIL_DESCR 0x0015 +#define GG_STATUS_FFC 0x0017 +#define GG_STATUS_FFC_DESCR 0x0018 +#define GG_STATUS_AVAIL 0x0002 +#define GG_STATUS_AVAIL_DESCR 0x0004 +#define GG_STATUS_BUSY 0x0003 +#define GG_STATUS_BUSY_DESCR 0x0005 +#define GG_STATUS_DND 0x0021 +#define GG_STATUS_DND_DESCR 0x0022 +#define GG_STATUS_INVISIBLE 0x0014 +#define GG_STATUS_INVISIBLE_DESCR 0x0016 +#define GG_STATUS_BLOCKED 0x0006 + +#define GG_STATUS_IMAGE_MASK 0x0100 +#define GG_STATUS_DESCR_MASK 0x4000 +#define GG_STATUS_FRIENDS_MASK 0x8000 + +#else -#define GG_STATUS_FRIENDS_MASK 0x8000 /* tylko dla znajomych (4.6) */ - -#define GG_STATUS_DESCR_MAXSIZE 70 +/** + * Rodzaje status坦w u甜ytkownika. + * + * \ingroup status + */ +enum { + GG_STATUS_NOT_AVAIL, /**< Niedost�pny */ + GG_STATUS_NOT_AVAIL_DESCR, /**< Niedost�pny z opisem */ + GG_STATUS_FFC, /**< PoGGadaj ze mn� */ + GG_STATUS_FFC_DESCR, /**< PoGGadaj ze mn� z opisem */ + GG_STATUS_AVAIL, /**< Dost�pny */ + GG_STATUS_AVAIL_DESCR, /**< Dost�pny z opisem */ + GG_STATUS_BUSY, /**< Zaj�ty */ + GG_STATUS_BUSY_DESCR, /**< Zaj�ty z opisem */ + GG_STATUS_DND, /**< Nie przeszkadza� */ + GG_STATUS_DND_DESCR, /**< Nie przeszakdza� z opisem */ + GG_STATUS_INVISIBLE, /**< Niewidoczny (tylko w�asny status) */ + GG_STATUS_INVISIBLE_DESCR, /**< Niewidoczny z opisem (tylko w�asny status) */ + GG_STATUS_BLOCKED, /**< Zablokowany (tylko status innych) */ + GG_STATUS_IMAGE_MASK, /**< Flaga bitowa oznaczaj�ca opis graficzny (tylko je�li wybrano \c GG_FEATURE_IMAGE_DESCR) */ + GG_STATUS_DESCR_MASK, /**< Flaga bitowa oznaczaj�ca status z opisem (tylko je�li wybrano \c GG_FEATURE_IMAGE_DESCR) */ + GG_STATUS_FRIENDS_MASK, /**< Flaga bitowa dost�pno�ci tylko dla znajomych */ +}; -/* - * makra do �atwego i szybkiego sprawdzania stanu. +#endif /* DOXYGEN */ + +/** + * \ingroup status + * + * Flaga bitowa dostepnosci informujaca ze mozemy voipowac */ +#define GG_STATUS_VOICE_MASK 0x20000 /**< czy ma wlaczone audio (7.7) */ + +/** + * \ingroup status + * + * Maksymalna d�ugo�c opisu. + */ +#define GG_STATUS_DESCR_MAXSIZE 255 +#define GG_STATUS_DESCR_MAXSIZE_PRE_8_0 70 + +#define GG_STATUS_MASK 0xff + /* GG_S_F() tryb tylko dla znajomych */ #define GG_S_F(x) (((x) & GG_STATUS_FRIENDS_MASK) != 0) -/* GG_S() stan bez uwzgl�dnienia trybu tylko dla znajomych */ -#define GG_S(x) ((x) & ~GG_STATUS_FRIENDS_MASK) +/* GG_S() stan bez uwzgl�dnienia dodatkowych flag */ +#define GG_S(x) ((x) & GG_STATUS_MASK) -/* GG_S_A() dost�pny */ -#define GG_S_A(x) (GG_S(x) == GG_STATUS_AVAIL || GG_S(x) == GG_STATUS_AVAIL_DESCR) + +/* GG_S_FF() ch�tny do rozmowy */ +#define GG_S_FF(x) (GG_S(x) == GG_STATUS_FFC || GG_S(x) == GG_STATUS_FFC_DESCR) -/* GG_S_NA() niedost�pny */ -#define GG_S_NA(x) (GG_S(x) == GG_STATUS_NOT_AVAIL || GG_S(x) == GG_STATUS_NOT_AVAIL_DESCR) +/* GG_S_AV() dost�pny */ +#define GG_S_AV(x) (GG_S(x) == GG_STATUS_AVAIL || GG_S(x) == GG_STATUS_AVAIL_DESCR) + +/* GG_S_AW() zaraz wracam */ +#define GG_S_AW(x) (GG_S(x) == GG_STATUS_BUSY || GG_S(x) == GG_STATUS_BUSY_DESCR) -/* GG_S_B() zaj�ty */ -#define GG_S_B(x) (GG_S(x) == GG_STATUS_BUSY || GG_S(x) == GG_STATUS_BUSY_DESCR) +/* GG_S_DD() nie przeszkadza� */ +#define GG_S_DD(x) (GG_S(x) == GG_STATUS_DND || GG_S(x) == GG_STATUS_DND_DESCR) + +/* GG_S_NA() niedost�pny */ +#define GG_S_NA(x) (GG_S(x) == GG_STATUS_NOT_AVAIL || GG_S(x) == GG_STATUS_NOT_AVAIL_DESCR) /* GG_S_I() niewidoczny */ #define GG_S_I(x) (GG_S(x) == GG_STATUS_INVISIBLE || GG_S(x) == GG_STATUS_INVISIBLE_DESCR) + +/* GG_S_A() dost�pny lub ch�tny do rozmowy */ +#define GG_S_A(x) (GG_S_FF(x) || GG_S_AV(x)) + +/* GG_S_B() zaj�ty lub nie przeszkadza� */ +#define GG_S_B(x) (GG_S_AW(x) || GG_S_DD(x)) + + /* GG_S_D() stan opisowy */ -#define GG_S_D(x) (GG_S(x) == GG_STATUS_NOT_AVAIL_DESCR || GG_S(x) == GG_STATUS_AVAIL_DESCR || GG_S(x) == GG_STATUS_BUSY_DESCR || GG_S(x) == GG_STATUS_INVISIBLE_DESCR) +#define GG_S_D(x) (GG_S(x) == GG_STATUS_NOT_AVAIL_DESCR || \ + GG_S(x) == GG_STATUS_FFC_DESCR || \ + GG_S(x) == GG_STATUS_AVAIL_DESCR || \ + GG_S(x) == GG_STATUS_BUSY_DESCR || \ + GG_S(x) == GG_STATUS_DND_DESCR || \ + GG_S(x) == GG_STATUS_INVISIBLE_DESCR) -/* GG_S_BL() blokowany lub blokuj�cy */ +/* GG_S_BL() blokowany lub blokuj�cy */ #define GG_S_BL(x) (GG_S(x) == GG_STATUS_BLOCKED) +/** + * Zmiana statusu (pakiet \c GG_NEW_STATUS i \c GG_NEW_STATUS80BETA) + */ struct gg_new_status { - uint32_t status; /* na jaki zmieni�? */ + uint32_t status; /**< Nowy status */ } GG_PACKED; #define GG_NOTIFY_FIRST 0x000f @@ -1081,12 +1599,29 @@ struct gg_notify { uint32_t uin; /* numerek danej osoby */ - uint8_t dunno1; /* rodzaj wpisu w li�cie */ + uint8_t dunno1; /* rodzaj wpisu w li�cie */ } GG_PACKED; -#define GG_USER_OFFLINE 0x01 /* b�dziemy niewidoczni dla u�ytkownika */ -#define GG_USER_NORMAL 0x03 /* zwyk�y u�ytkownik */ -#define GG_USER_BLOCKED 0x04 /* zablokowany u�ytkownik */ +#ifndef DOXYGEN + +#define GG_USER_OFFLINE 0x01 +#define GG_USER_NORMAL 0x03 +#define GG_USER_BLOCKED 0x04 + +#else + +/** + * \ingroup contacts + * + * Rodzaj kontaktu. + */ +enum { + GG_USER_NORMAL, /**< Zwyk�y kontakt */ + GG_USER_BLOCKED, /**< Zablokowany */ + GG_USER_OFFLINE, /**< Niewidoczny dla kontaktu */ +}; + +#endif /* DOXYGEN */ #define GG_LIST_EMPTY 0x0012 @@ -1096,7 +1631,7 @@ uint32_t uin; /* numerek */ uint32_t status; /* status danej osoby */ uint32_t remote_ip; /* adres ip delikwenta */ - uint16_t remote_port; /* port, na kt�rym s�ucha klient */ + uint16_t remote_port; /* port, na kt坦rym s�ucha klient */ uint32_t version; /* wersja klienta */ uint16_t dunno2; /* znowu port? */ } GG_PACKED; @@ -1107,7 +1642,7 @@ uint32_t uin; /* numerek plus flagi w MSB */ uint8_t status; /* status danej osoby */ uint32_t remote_ip; /* adres ip delikwenta */ - uint16_t remote_port; /* port, na kt�rym s�ucha klient */ + uint16_t remote_port; /* port, na kt坦rym s�ucha klient */ uint8_t version; /* wersja klienta */ uint8_t image_size; /* maksymalny rozmiar grafiki w KiB */ uint8_t dunno1; /* 0x00 */ @@ -1119,12 +1654,38 @@ uint32_t uin; /* numerek plus flagi w MSB */ uint8_t status; /* status danej osoby */ uint32_t remote_ip; /* adres ip delikwenta */ - uint16_t remote_port; /* port, na kt�rym s�ucha klient */ + uint16_t remote_port; /* port, na kt坦rym s�ucha klient */ uint8_t version; /* wersja klienta */ uint8_t image_size; /* maksymalny rozmiar grafiki w KiB */ uint8_t dunno1; /* 0x00 */ } GG_PACKED; +#define GG_NOTIFY_REPLY77 0x0018 + +struct gg_notify_reply77 { + uint32_t uin; /* numerek plus flagi w MSB */ + uint8_t status; /* status danej osoby */ + uint32_t remote_ip; /* adres ip delikwenta */ + uint16_t remote_port; /* port, na kt坦rym s�ucha klient */ + uint8_t version; /* wersja klienta */ + uint8_t image_size; /* maksymalny rozmiar grafiki w KiB */ + uint8_t dunno1; /* 0x00 */ + uint32_t dunno2; /* ? */ +} GG_PACKED; + +#define GG_STATUS77 0x0017 + +struct gg_status77 { + uint32_t uin; /* numerek plus flagi w MSB */ + uint8_t status; /* status danej osoby */ + uint32_t remote_ip; /* adres ip delikwenta */ + uint16_t remote_port; /* port, na kt坦rym s�ucha klient */ + uint8_t version; /* wersja klienta */ + uint8_t image_size; /* maksymalny rozmiar grafiki w KiB */ + uint8_t dunno1; /* 0x00 */ + uint32_t dunno2; /* ? */ +} GG_PACKED; + #define GG_ADD_NOTIFY 0x000d #define GG_REMOVE_NOTIFY 0x000e @@ -1142,15 +1703,41 @@ #define GG_SEND_MSG 0x000b +#ifndef DOXYGEN + #define GG_CLASS_QUEUED 0x0001 #define GG_CLASS_OFFLINE GG_CLASS_QUEUED #define GG_CLASS_MSG 0x0004 #define GG_CLASS_CHAT 0x0008 #define GG_CLASS_CTCP 0x0010 #define GG_CLASS_ACK 0x0020 -#define GG_CLASS_EXT GG_CLASS_ACK /* kompatybilno倶 wstecz */ +#define GG_CLASS_EXT GG_CLASS_ACK /**< Dla kompatybilno�ci wstecz */ + +#else -#define GG_MSG_MAXSIZE 2000 +/** + * Klasy wiadomo�ci. Warto�ci s� maskami bitowymi, kt坦re w wi�kszo�ci + * przypadk坦w mo甜na ��czy� (po��czenie \c GG_CLASS_MSG i \c GG_CLASS_CHAT + * nie ma sensu). + * + * \ingroup messages + */ +enum { + GG_CLASS_MSG, /**< Wiadomo�� ma pojawi� si� w osobnym oknie */ + GG_CLASS_CHAT, /**< Wiadomo�� ma pojawi� si� w oknie rozmowy */ + GG_CLASS_CTCP, /**< Wiadomo�� przeznaczona dla klienta Gadu-Gadu */ + GG_CLASS_ACK, /**< Klient nie 甜yczy sobie potwierdzenia */ + GG_CLASS_QUEUED, /**< Wiadomo�� zakolejkowana na serwerze (tylko przy odbieraniu) */ +}; + +#endif /* DOXYGEN */ + +/** + * Maksymalna d�ugo�� wiadomo�ci. + * + * \ingroup messages + */ +#define GG_MSG_MAXSIZE 1989 struct gg_send_msg { uint32_t recipient; @@ -1163,16 +1750,19 @@ uint16_t length; } GG_PACKED; +/** + * Struktura opisuj�ca formatowanie tekstu. W zale甜no�ci od warto�ci pola + * \c font, zaraz za t� struktur� mo甜e wyst�pi� \c gg_msg_richtext_color + * lub \c gg_msg_richtext_image. + * + * \ingroup messages + */ struct gg_msg_richtext_format { - uint16_t position; - uint8_t font; + uint16_t position; /**< Pocz�tkowy znak formatowania (liczony od 0) */ + uint8_t font; /**< Atrybuty formatowania */ } GG_PACKED; -struct gg_msg_richtext_image { - uint16_t unknown1; - uint32_t size; - uint32_t crc32; -} GG_PACKED; +#ifndef DOXYGEN #define GG_FONT_BOLD 0x01 #define GG_FONT_ITALIC 0x02 @@ -1180,10 +1770,44 @@ #define GG_FONT_COLOR 0x08 #define GG_FONT_IMAGE 0x80 +#else + +/** + * Atrybuty formatowania wiadomo�ci. + * + * \ingroup messages + */ +enum { + GG_FONT_BOLD, + GG_FONT_ITALIC, + GG_FONT_UNDERLINE, + GG_FONT_COLOR, + GG_FONT_IMAGE +}; + +#endif /* DOXYGEN */ + +/** + * Struktura opisuj�c� kolor tekstu dla atrybutu \c GG_FONT_COLOR. + * + * \ingroup messages + */ struct gg_msg_richtext_color { - uint8_t red; - uint8_t green; - uint8_t blue; + uint8_t red; /**< Sk�adowa czerwona koloru */ + uint8_t green; /**< Sk�adowa zielona koloru */ + uint8_t blue; /**< Sk�adowa niebieska koloru */ +} GG_PACKED; + +/** + * Strukturya opisuj�ca obrazek wstawiony do wiadomo�ci dla atrubutu + * \c GG_FONT_IMAGE. + * + * \ingroup messages + */ +struct gg_msg_richtext_image { + uint16_t unknown1; /**< Nieznane pole o warto�ci 0x0109 */ + uint32_t size; /**< Rozmiar obrazka */ + uint32_t crc32; /**< Suma kontrolna CRC32 obrazka */ } GG_PACKED; struct gg_msg_recipients { @@ -1207,12 +1831,32 @@ #define GG_SEND_MSG_ACK 0x0005 +#ifndef DOXYGEN + #define GG_ACK_BLOCKED 0x0001 #define GG_ACK_DELIVERED 0x0002 #define GG_ACK_QUEUED 0x0003 #define GG_ACK_MBOXFULL 0x0004 #define GG_ACK_NOT_DELIVERED 0x0006 +#else + +/** + * Status dor�czenia wiadomo�ci. + * + * \ingroup messages + */ +enum +{ + GG_ACK_DELIVERED, /**< Wiadomo�� dostarczono. */ + GG_ACK_QUEUED, /**< Wiadomo�� zakolejkowano z powodu niedost�pno�ci odbiorcy. */ + GG_ACK_BLOCKED, /**< Wiadomo�� zablokowana przez serwer (spam, �wi�teczne ograniczenia itd.) */ + GG_ACK_MBOXFULL, /**< Wiadomo�ci nie dostarczono z powodu zape�nionej kolejki wiadomo�ci odbiorcy. */ + GG_ACK_NOT_DELIVERED /**< Wiadomo�ci nie dostarczono (tylko dla \c GG_CLASS_CTCP). */ +}; + +#endif /* DOXYGEN */ + struct gg_send_msg_ack { uint32_t status; uint32_t recipient; @@ -1236,29 +1880,59 @@ #define GG_USERLIST_REQUEST 0x0016 +#define GG_XML_EVENT 0x0027 + +#ifndef DOXYGEN + #define GG_USERLIST_PUT 0x00 #define GG_USERLIST_PUT_MORE 0x01 #define GG_USERLIST_GET 0x02 +#else + +/** + * \ingroup importexport + * + * Rodzaj zapytania. + */ +enum { + GG_USERLIST_PUT, /**< Eksport listy kontakt坦w. */ + GG_USERLIST_GET, /**< Import listy kontakt坦w. */ +}; + +#endif /* DOXYGEN */ + struct gg_userlist_request { uint8_t type; } GG_PACKED; #define GG_USERLIST_REPLY 0x0010 +#ifndef DOXYGEN + #define GG_USERLIST_PUT_REPLY 0x00 #define GG_USERLIST_PUT_MORE_REPLY 0x02 #define GG_USERLIST_GET_REPLY 0x06 #define GG_USERLIST_GET_MORE_REPLY 0x04 +#else + +/** + * \ingroup importexport + * + * Rodzaj odpowiedzi. + */ +enum { + GG_USERLIST_PUT_REPLY, /**< Wyeksportowano listy kontakt坦w. */ + GG_USERLIST_GET_REPLY, /**< Zaimportowano list� kontakt坦w. */ +}; + +#endif /* DOXYGEN */ + struct gg_userlist_reply { uint8_t type; } GG_PACKED; -/* - * pakiety, sta�e, struktury dla DCC - */ - struct gg_dcc_tiny_packet { uint8_t type; /* rodzaj pakietu */ } GG_PACKED; @@ -1274,14 +1948,14 @@ } GG_PACKED; /* - * p�ki co, nie znamy dok�adnie protoko�u. nie wiemy, co czemu odpowiada. - * nazwy s� niepowa�ne i tymczasowe. + * p坦ki co, nie znamy dok�adnie protoko�u. nie wiemy, co czemu odpowiada. + * nazwy s� niepowa甜ne i tymczasowe. */ #define GG_DCC_WANT_FILE 0x0003 /* peer chce plik */ -#define GG_DCC_HAVE_FILE 0x0001 /* wi�c mu damy */ +#define GG_DCC_HAVE_FILE 0x0001 /* wi�c mu damy */ #define GG_DCC_HAVE_FILEINFO 0x0003 /* niech ma informacje o pliku */ #define GG_DCC_GIMME_FILE 0x0006 /* peer jest pewny */ -#define GG_DCC_CATCH_FILE 0x0002 /* wysy�amy plik */ +#define GG_DCC_CATCH_FILE 0x0002 /* wysy�amy plik */ #define GG_DCC_FILEATTR_READONLY 0x0020 @@ -1290,11 +1964,88 @@ #define GG_DCC_TIMEOUT_FILE_ACK 300 /* 5 minut */ #define GG_DCC_TIMEOUT_VOICE_ACK 300 /* 5 minut */ +#define GG_DCC7_INFO 0x1f + +struct gg_dcc7_info { + uint32_t uin; /* numer nadawcy */ + uint32_t type; /* spos坦b po��czenia */ + gg_dcc7_id_t id; /* identyfikator po��czenia */ + char info[GG_DCC7_INFO_LEN]; /* informacje o po��czeniu "ip port" */ +} GG_PACKED; + +#define GG_DCC7_NEW 0x20 + +struct gg_dcc7_new { + gg_dcc7_id_t id; /* identyfikator po��czenia */ + uint32_t uin_from; /* numer nadawcy */ + uint32_t uin_to; /* numer odbiorcy */ + uint32_t type; /* rodzaj transmisji */ + unsigned char filename[GG_DCC7_FILENAME_LEN]; /* nazwa pliku */ + uint32_t size; /* rozmiar pliku */ + uint32_t size_hi; /* rozmiar pliku (starsze bajty) */ + unsigned char hash[GG_DCC7_HASH_LEN]; /* hash SHA1 */ +} GG_PACKED; + +#define GG_DCC7_ACCEPT 0x21 + +struct gg_dcc7_accept { + uint32_t uin; /* numer przyjmuj�cego po��czenie */ + gg_dcc7_id_t id; /* identyfikator po��czenia */ + uint32_t offset; /* offset przy wznawianiu transmisji */ + uint32_t dunno1; /* 0x00000000 */ +} GG_PACKED; + +// XXX API +#define GG_DCC7_TYPE_P2P 0x00000001 /**< Po��czenie bezpo�rednie */ +#define GG_DCC7_TYPE_SERVER 0x00000002 /**< Po��czenie przez serwer */ + +#define GG_DCC7_REJECT 0x22 + +struct gg_dcc7_reject { + uint32_t uin; /**< Numer odrzucaj�cego po��czenie */ + gg_dcc7_id_t id; /**< Identyfikator po��czenia */ + uint32_t reason; /**< Pow坦d roz��czenia */ +} GG_PACKED; + +// XXX API +#define GG_DCC7_REJECT_BUSY 0x00000001 /**< Po��czenie bezpo�rednie ju甜 trwa, nie umiem obs�u甜y� wi�cej */ +#define GG_DCC7_REJECT_USER 0x00000002 /**< U甜ytkownik odrzuci� po��czenie */ +#define GG_DCC7_REJECT_VERSION 0x00000006 /**< Druga strona ma wersj� klienta nieobs�uguj�c� po��cze� bezpo�rednich tego typu */ + +#define GG_DCC7_ID_REQUEST 0x23 + +struct gg_dcc7_id_request { + uint32_t type; /**< Rodzaj tranmisji */ +} GG_PACKED; + +// XXX API +#define GG_DCC7_TYPE_VOICE 0x00000001 /**< Transmisja g�osu */ +#define GG_DCC7_TYPE_FILE 0x00000004 /**< transmisja pliku */ + +#define GG_DCC7_ID_REPLY 0x23 + +struct gg_dcc7_id_reply { + uint32_t type; /** Rodzaj transmisji */ + gg_dcc7_id_t id; /** Przyznany identyfikator */ +} GG_PACKED; + +#define GG_DCC7_DUNNO1 0x24 + +struct gg_dcc7_dunno1 { + // XXX +} GG_PACKED; + +#define GG_DCC7_TIMEOUT_CONNECT 10 /* 10 sekund */ +#define GG_DCC7_TIMEOUT_SEND 1800 /* 30 minut */ +#define GG_DCC7_TIMEOUT_GET 1800 /* 30 minut */ +#define GG_DCC7_TIMEOUT_FILE_ACK 300 /* 5 minut */ +#define GG_DCC7_TIMEOUT_VOICE_ACK 300 /* 5 minut */ + #ifdef __cplusplus -#ifdef _MSC_VER +} +#ifdef _WIN32 #pragma pack(pop) #endif -} #endif #endif /* __GG_LIBGADU_H */
--- a/libpurple/protocols/gg/lib/obsolete.c Sun Feb 28 23:42:12 2010 +0000 +++ b/libpurple/protocols/gg/lib/obsolete.c Mon Mar 01 03:46:33 2010 +0000 @@ -1,4 +1,4 @@ -/* $Id: obsolete.c 16856 2006-08-19 01:13:25Z evands $ */ +/* $Id: obsolete.c 854 2009-10-12 21:06:28Z wojtekka $ */ /* * (C) Copyright 2001-2003 Wojtek Kaniewski <wojtekka@irc.pl> @@ -14,16 +14,23 @@ * * 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. */ -/* - * Plik zawiera deklaracje funkcji, kt�re s� ju� nieaktualne ze wzgl�du - * na zmiany w protokole, ale s� wymagane przez aplikacje linkowane ze - * starszymi wersjami bibliotek. +/** + * \file obsolete.c + * + * \brief Nieaktualne funkcje + * + * Plik zawiera definicje funkcji, kt坦re s� ju甜 nieaktualne ze wzgl�du + * na zmiany w protokole. Programy konsolidowane ze starszych wersjami + * bibliotek powinny nadal mie� mo甜liwo�� dzia�ania, mimo ograniczonej + * funkcjonalno�ci. */ +/** \cond obsolete */ + #include <errno.h> #include "libgadu.h" @@ -205,3 +212,25 @@ { } + +int gg_resolve(int *fd, int *pid, const char *hostname) +{ + return -1; +} + +void gg_resolve_pthread_cleanup(void *arg, int kill) +{ + +} + +int gg_resolve_pthread(int *fd, void **resolver, const char *hostname) +{ + return -1; +} + +int gg_pubdir50_handle_reply(struct gg_event *e, const char *packet, int length) +{ + return -1; +} + +/** \endcond */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/gg/lib/protocol.h Mon Mar 01 03:46:33 2010 +0000 @@ -0,0 +1,165 @@ +/* $Id$ */ + +/* + * (C) Copyright 2009 Jakub Zawadzki <darkjames@darkjames.ath.cx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License Version + * 2.1 as published by the Free Software Foundation. + * + * This program 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 Lesser General Public License for more details. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef LIBGADU_PROTOCOL_H +#define LIBGADU_PROTOCOL_H + +#include "libgadu.h" + +#ifdef _WIN32 +#pragma pack(push, 1) +#endif + +#define GG_LOGIN80BETA 0x0029 + +#define GG_LOGIN80 0x0031 + +#undef GG_FEATURE_STATUS80BETA +#undef GG_FEATURE_MSG80 +#undef GG_FEATURE_STATUS80 +#define GG_FEATURE_STATUS80BETA 0x01 +#define GG_FEATURE_MSG80 0x02 +#define GG_FEATURE_STATUS80 0x05 + +#define GG8_LANG "pl" +#define GG8_VERSION "Gadu-Gadu Client Build 8.0.0.8731" + +struct gg_login80 { + uint32_t uin; /* m坦j numerek */ + uint8_t language[2]; /* j�zyk: GG8_LANG */ + uint8_t hash_type; /* rodzaj hashowania has�a */ + uint8_t hash[64]; /* hash has�a dope�niony zerami */ + uint32_t status; /* status na dzie� dobry */ + uint32_t flags; /* flagi (przeznaczenie nieznane) */ + uint32_t features; /* opcje protoko�u (GG8_FEATURES) */ + uint32_t local_ip; /* m坦j adres ip */ + uint16_t local_port; /* port, na kt坦rym s�ucham */ + uint32_t external_ip; /* zewn�trzny adres ip (???) */ + uint16_t external_port; /* zewn�trzny port (???) */ + uint8_t image_size; /* maksymalny rozmiar grafiki w KiB */ + uint8_t dunno2; /* 0x64 */ +} GG_PACKED; + +#define GG_LOGIN_HASH_TYPE_INVALID 0x0016 + +#define GG_LOGIN80_OK 0x0035 + +#define GG_NEW_STATUS80BETA 0x0028 + +#define GG_NEW_STATUS80 0x0038 + +/** + * Zmiana stanu (pakiet \c GG_NEW_STATUS80) + */ +struct gg_new_status80 { + uint32_t status; /**< Nowy status */ + uint32_t flags; /**< flagi (nieznane przeznaczenie) */ + uint32_t description_size; /**< rozmiar opisu */ +} GG_PACKED; + +#define GG_STATUS80BETA 0x002a +#define GG_NOTIFY_REPLY80BETA 0x002b + +#define GG_STATUS80 0x0036 +#define GG_NOTIFY_REPLY80 0x0037 + +struct gg_notify_reply80 { + uint32_t uin; /* numerek plus flagi w najstarszym bajcie */ + uint32_t status; /* status danej osoby */ + uint32_t flags; /* flagi (przeznaczenie nieznane) */ + uint32_t remote_ip; /* adres IP bezpo�rednich po��cze� */ + uint16_t remote_port; /* port bezpo�rednich po��cze� */ + uint8_t image_size; /* maksymalny rozmiar obrazk坦w w KB */ + uint8_t unknown2; /* 0x00 */ + uint32_t unknown3; /* 0x00000000 */ + uint32_t descr_len; /* rozmiar opisu */ +} GG_PACKED; + +#define GG_SEND_MSG80 0x002d + +struct gg_send_msg80 { + uint32_t recipient; + uint32_t seq; + uint32_t msgclass; + uint32_t offset_plain; + uint32_t offset_attr; +} GG_PACKED; + +#define GG_RECV_MSG80 0x002e + +struct gg_recv_msg80 { + uint32_t sender; + uint32_t seq; + uint32_t time; + uint32_t msgclass; + uint32_t offset_plain; + uint32_t offset_attr; +} GG_PACKED; + +#define GG_DISCONNECT_ACK 0x000d + +#define GG_DCC7_VOICE_RETRIES 0x11 /* 17 powtorzen */ + +#define GG_DCC7_RESERVED1 0xdeadc0de +#define GG_DCC7_RESERVED2 0xdeadbeaf + +struct gg_dcc7_voice_auth { + uint8_t type; /* 0x00 -> wysylanie ID + 0x01 -> potwierdzenie ID + */ + gg_dcc7_id_t id; /* identyfikator po��czenia */ + uint32_t reserved1; /* GG_DCC7_RESERVED1 */ + uint32_t reserved2; /* GG_DCC7_RESERVED2 */ +} GG_PACKED; + +struct gg_dcc7_voice_nodata { /* wyciszony mikrofon, ten pakiet jest wysylany co 1s (jesli chcemy podtrzymac polaczenie) */ + uint8_t type; /* 0x02 */ + gg_dcc7_id_t id; /* identyfikator po��czenia */ + uint32_t reserved1; /* GG_DCC7_RESERVED1 */ + uint32_t reserved2; /* GG_DCC7_RESERVED2 */ +} GG_PACKED; + +struct gg_dcc7_voice_data { + uint8_t type; /* 0x03 */ + uint32_t did; /* XXX: co ile zwieksza sie u nas id pakietu [uzywac 0x28] */ + uint32_t len; /* rozmiar strukturki - 1 (sizeof(type)) */ + uint32_t packet_id; /* numerek pakietu */ + uint32_t datalen; /* rozmiar danych */ + /* char data[]; */ /* ramki: albo gsm, albo speex, albo melp, albo inne. */ +} GG_PACKED; + +struct gg_dcc7_voice_init { + uint8_t type; /* 0x04 */ + uint32_t id; /* nr kroku [0x1 - 0x5] */ + uint32_t protocol; /* XXX: wersja protokolu (0x29, 0x2a, 0x2b) */ + uint32_t len; /* rozmiar sizeof(protocol)+sizeof(len)+sizeof(data) = 0x08 + sizeof(data) */ + /* char data[]; */ /* reszta danych */ +} GG_PACKED; + +struct gg_dcc7_voice_init_confirm { + uint8_t type; /* 0x05 */ + uint32_t id; /* id tego co potwierdzamy [0x1 - 0x5] */ +} GG_PACKED; + +#ifdef _WIN32 +#pragma pack(pop) +#endif + +#endif /* LIBGADU_PROTOCOL_H */
--- a/libpurple/protocols/gg/lib/pubdir.c Sun Feb 28 23:42:12 2010 +0000 +++ b/libpurple/protocols/gg/lib/pubdir.c Mon Mar 01 03:46:33 2010 +0000 @@ -1,8 +1,9 @@ -/* $Id: pubdir.c 16856 2006-08-19 01:13:25Z evands $ */ +/* $Id: pubdir.c 502 2008-01-10 23:25:17Z wojtekka $ */ /* - * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl> + * (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka@irc.pl> * Dawid Jarosz <dawjar@poczta.onet.pl> + * Adam Wysocki <gophi@ekg.chmurka.net> * * 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,11 +16,18 @@ * * 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. */ +/** + * \file pubdir.c + * + * \brief Obs�uga katalogu publicznego + */ + #include "libgadu.h" +#include "libgadu-config.h" #include <ctype.h> #include <errno.h> @@ -29,20 +37,20 @@ #include <string.h> #include <unistd.h> -/* - * gg_register3() +/** + * Rejestruje nowego u甜ytkownika. * - * rozpoczyna rejestracj� u�ytkownika protoko�em GG 6.0. wymaga wcze�niejszego - * pobrania tokenu za pomoc� funkcji gg_token(). + * Wymaga wcze�niejszego pobrania tokenu za pomoc� \c gg_token(). * - * - email - adres e-mail klienta - * - password - has�o klienta - * - tokenid - identyfikator tokenu - * - tokenval - warto倶 tokenu - * - async - po咳czenie asynchroniczne + * \param email Adres e-mail + * \param password Has�o + * \param tokenid Identyfikator tokenu + * \param tokenval Zawarto�� tokenu + * \param async Flaga po��czenia asynchronicznego * - * zaalokowana struct gg_http, kt�r� po�niej nale�y zwolni� - * funkcj� gg_register_free(), albo NULL je�li wyst�pi� b咳d. + * \return Struktura \c gg_http lub \c NULL w przypadku b��du + * + * \ingroup register */ struct gg_http *gg_register3(const char *email, const char *password, const char *tokenid, const char *tokenval, int async) { @@ -121,19 +129,59 @@ return h; } -/* - * gg_unregister3() +#ifdef DOXYGEN + +/** + * Funkcja wywo�ywana po zaobserwowaniu zmian na deskryptorze po��czenia. + * + * Operacja b�dzie zako�czona, gdy pole \c state b�dzie r坦wne \c GG_STATE_DONE. + * Je�li wyst�pi b��d, \c state b�dzie r坦wne \c GG_STATE_ERROR, a kod b��du + * znajdzie si� w polu \c error. + * + * \note W rzeczywisto�ci funkcja jest makrem rozwijanym do + * \c gg_pubdir_watch_fd(). * - * usuwa konto u�ytkownika z serwera protoko�em GG 6.0 + * \param h Struktura po��czenia + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup register + */ +int gg_register_watch_fd(struct gg_httpd *h) +{ + return gg_pubdir_watch_fd(h); +} + +/** + * Zwalnia zasoby po operacji. * - * - uin - numerek GG - * - password - has�o klienta - * - tokenid - identyfikator tokenu - * - tokenval - warto倶 tokenu - * - async - po咳czenie asynchroniczne + * \note W rzeczywisto�ci funkcja jest makrem rozwijanym do \c gg_pubdir_free(). + * + * \param h Struktura po��czenia * - * zaalokowana struct gg_http, kt�r� po�niej nale�y zwolni� - * funkcj� gg_unregister_free(), albo NULL je�li wyst�pi� b咳d. + * \ingroup register + */ +void gg_register_free(struct gg_http *h) +{ + return gg_pubdir_free(h); +} + +#endif /* DOXYGEN */ + +/** + * Usuwa u甜ytkownika. + * + * Wymaga wcze�niejszego pobrania tokenu za pomoc� \c gg_token(). + * + * \param uin Numer Gadu-Gadu + * \param password Has�o + * \param tokenid Identyfikator tokenu + * \param tokenval Zawarto�� tokenu + * \param async Flaga po��czenia asynchronicznego + * + * \return Struktura \c gg_http lub \c NULL w przypadku b��du + * + * \ingroup unregister */ struct gg_http *gg_unregister3(uin_t uin, const char *password, const char *tokenid, const char *tokenval, int async) { @@ -145,7 +193,7 @@ errno = EFAULT; return NULL; } - + __pwd = gg_saprintf("%ld", random()); __fmpwd = gg_urlencode(password); __tokenid = gg_urlencode(tokenid); @@ -210,22 +258,61 @@ return h; } -/* - * gg_change_passwd4() +#ifdef DOXYGEN + +/** + * Funkcja wywo�ywana po zaobserwowaniu zmian na deskryptorze po��czenia. + * + * Operacja b�dzie zako�czona, gdy pole \c state b�dzie r坦wne \c GG_STATE_DONE. + * Je�li wyst�pi b��d, \c state b�dzie r坦wne \c GG_STATE_ERROR, a kod b��du + * znajdzie si� w polu \c error. + * + * \note W rzeczywisto�ci funkcja jest makrem rozwijanym do + * \c gg_pubdir_watch_fd(). + * + * \param h Struktura po��czenia * - * wysy�a 娠danie zmiany has�a zgodnie z protoko�em GG 6.0. wymaga - * wcze�niejszego pobrania tokenu za pomoc� funkcji gg_token(). + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup unregister + */ +int gg_unregister_watch_fd(struct gg_httpd *h) +{ + return gg_pubdir_watch_fd(h); +} + +/** + * Zwalnia zasoby po operacji. + * + * \note W rzeczywisto�ci funkcja jest makrem rozwijanym do \c gg_pubdir_free(). * - * - uin - numer - * - email - adres e-mail - * - passwd - stare has�o - * - newpasswd - nowe has�o - * - tokenid - identyfikator tokenu - * - tokenval - warto倶 tokenu - * - async - po咳czenie asynchroniczne + * \param h Struktura po��czenia + * + * \ingroup unregister + */ +void gg_unregister_free(struct gg_http *h) +{ + return gg_pubdir_free(h); +} + +#endif /* DOXYGEN */ + +/** + * Zmienia has�o u甜ytkownika. * - * zaalokowana struct gg_http, kt�r� po�niej nale�y zwolni� - * funkcj� gg_change_passwd_free(), albo NULL je�li wyst�pi� b咳d. + * Wymaga wcze�niejszego pobrania tokenu za pomoc� \c gg_token(). + * + * \param uin Numer Gadu-Gadu + * \param email Adres e-mail + * \param passwd Obecne has�o + * \param newpasswd Nowe has�o + * \param tokenid Identyfikator tokenu + * \param tokenval Zawarto�� tokenu + * \param async Flaga po��czenia asynchronicznego + * + * \return Struktura \c gg_http lub \c NULL w przypadku b��du + * + * \ingroup passwd */ struct gg_http *gg_change_passwd4(uin_t uin, const char *email, const char *passwd, const char *newpasswd, const char *tokenid, const char *tokenval, int async) { @@ -309,19 +396,59 @@ return h; } -/* - * gg_remind_passwd3() +#ifdef DOXYGEN + +/** + * Funkcja wywo�ywana po zaobserwowaniu zmian na deskryptorze po��czenia. + * + * Operacja b�dzie zako�czona, gdy pole \c state b�dzie r坦wne \c GG_STATE_DONE. + * Je�li wyst�pi b��d, \c state b�dzie r坦wne \c GG_STATE_ERROR, a kod b��du + * znajdzie si� w polu \c error. + * + * \note W rzeczywisto�ci funkcja jest makrem rozwijanym do + * \c gg_pubdir_watch_fd(). * - * wysy�a 娠danie przypomnienia has�a e-mailem. + * \param h Struktura po��czenia + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup passwd + */ +int gg_change_passwd_watch_fd(struct gg_httpd *h) +{ + return gg_pubdir_watch_fd(h); +} + +/** + * Zwalnia zasoby po operacji. * - * - uin - numer - * - email - adres e-mail taki, jak ten zapisany na serwerze - * - async - po咳czenie asynchroniczne - * - tokenid - identyfikator tokenu - * - tokenval - warto倶 tokenu + * \note W rzeczywisto�ci funkcja jest makrem rozwijanym do \c gg_pubdir_free(). + * + * \param h Struktura po��czenia * - * zaalokowana struct gg_http, kt�r� po�niej nale�y zwolni� - * funkcj� gg_remind_passwd_free(), albo NULL je�li wyst�pi� b咳d. + * \ingroup passwd + */ +void gg_change_passwd_free(struct gg_http *h) +{ + return gg_pubdir_free(h); +} + +#endif /* DOXYGEN */ + +/** + * Wysy�a has�o u甜ytkownika na e-mail. + * + * Wymaga wcze�niejszego pobrania tokenu za pomoc� \c gg_token(). + * + * \param uin Numer Gadu-Gadu + * \param email Adres e-mail (podany przy rejestracji) + * \param tokenid Identyfikator tokenu + * \param tokenval Zawarto�� tokenu + * \param async Flaga po��czenia asynchronicznego + * + * \return Struktura \c gg_http lub \c NULL w przypadku b��du + * + * \ingroup remind */ struct gg_http *gg_remind_passwd3(uin_t uin, const char *email, const char *tokenid, const char *tokenval, int async) { @@ -396,17 +523,55 @@ return h; } -/* - * gg_pubdir_watch_fd() +#ifdef DOXYGEN + +/** + * Funkcja wywo�ywana po zaobserwowaniu zmian na deskryptorze po��czenia. * - * przy asynchronicznych operacjach na katalogu publicznym nale�y wywo�ywa� - * t� funkcj� przy zmianach na obserwowanym deskryptorze. + * Operacja b�dzie zako�czona, gdy pole \c state b�dzie r坦wne \c GG_STATE_DONE. + * Je�li wyst�pi b��d, \c state b�dzie r坦wne \c GG_STATE_ERROR, a kod b��du + * znajdzie si� w polu \c error. + * + * \note W rzeczywisto�ci funkcja jest makrem rozwijanym do + * \c gg_pubdir_watch_fd(). + * + * \param h Struktura po��czenia + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du * - * - h - struktura opisuj�ca po咳czenie + * \ingroup remind + */ +int gg_remind_watch_fd(struct gg_httpd *h) +{ + return gg_pubdir_watch_fd(h); +} + +/** + * Zwalnia zasoby po operacji. + * + * \note W rzeczywisto�ci funkcja jest makrem rozwijanym do \c gg_pubdir_free(). + * + * \param h Struktura po��czenia * - * je�li wszystko posz�o dobrze to 0, inaczej -1. operacja b�dzie - * zako�czona, je�li h->state == GG_STATE_DONE. je�li wyst�pi jaki� - * b咳d, to b�dzie tam GG_STATE_ERROR i odpowiedni kod b滑du w h->error. + * \ingroup remind + */ +void gg_remind_free(struct gg_http *h) +{ + return gg_pubdir_free(h); +} + +#endif /* DOXYGEN */ + +/** + * Funkcja wywo�ywana po zaobserwowaniu zmian na deskryptorze po��czenia. + * + * Operacja b�dzie zako�czona, gdy pole \c state b�dzie r坦wne \c GG_STATE_DONE. + * Je�li wyst�pi b��d, \c state b�dzie r坦wne \c GG_STATE_ERROR, a kod b��du + * znajdzie si� w polu \c error. + * + * \param h Struktura po��czenia + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du */ int gg_pubdir_watch_fd(struct gg_http *h) { @@ -447,7 +612,11 @@ gg_debug(GG_DEBUG_MISC, "=> pubdir, let's parse \"%s\"\n", h->body); - if ((tmp = strstr(h->body, "success")) || (tmp = strstr(h->body, "results"))) { + if ((tmp = strstr(h->body, "Tokens okregisterreply_packet.reg.dwUserId="))) { + p->success = 1; + p->uin = strtol(tmp + sizeof("Tokens okregisterreply_packet.reg.dwUserId=") - 1, NULL, 0); + gg_debug(GG_DEBUG_MISC, "=> pubdir, success (okregisterreply, uin=%d)\n", p->uin); + } else if ((tmp = strstr(h->body, "success")) || (tmp = strstr(h->body, "results"))) { p->success = 1; if (tmp[7] == ':') p->uin = strtol(tmp + 8, NULL, 0); @@ -458,12 +627,10 @@ return 0; } -/* - * gg_pubdir_free() +/** + * Zwalnia zasoby po operacji na katalogu publicznym. * - * zwalnia pami裝 po efektach operacji na katalogu publicznym. - * - * - h - zwalniana struktura + * \param h Struktura po��czenia */ void gg_pubdir_free(struct gg_http *h) { @@ -474,14 +641,17 @@ gg_http_free(h); } -/* - * gg_token() +/** + * Pobiera token do autoryzacji operacji na katalogu publicznym. + * + * Token jest niezb�dny do tworzenia nowego i usuwania u甜ytkownika, + * zmiany has�a itd. * - * pobiera z serwera token do autoryzacji zak�adania konta, usuwania - * konta i zmiany has�a. + * \param async Flaga po��czenia asynchronicznego * - * zaalokowana struct gg_http, kt�r� po�niej nale�y zwolni� - * funkcj� gg_token_free(), albo NULL je�li wyst�pi� b咳d. + * \return Struktura \c gg_http lub \c NULL w przypadku b��du + * + * \ingroup token */ struct gg_http *gg_token(int async) { @@ -511,17 +681,18 @@ return h; } -/* - * gg_token_watch_fd() - * - * przy asynchronicznych operacjach zwi�zanych z tokenem nale�y wywo�ywa� - * t� funkcj� przy zmianach na obserwowanym deskryptorze. +/** + * Funkcja wywo�ywana po zaobserwowaniu zmian na deskryptorze po��czenia. * - * - h - struktura opisuj�ca po咳czenie + * Operacja b�dzie zako�czona, gdy pole \c state b�dzie r坦wne \c GG_STATE_DONE. + * Je�li wyst�pi b��d, \c state b�dzie r坦wne \c GG_STATE_ERROR, a kod b��du + * znajdzie si� w polu \c error. * - * je�li wszystko posz�o dobrze to 0, inaczej -1. operacja b�dzie - * zako�czona, je�li h->state == GG_STATE_DONE. je�li wyst�pi jaki� - * b咳d, to b�dzie tam GG_STATE_ERROR i odpowiedni kod b滑du w h->error. + * \param h Struktura po��czenia + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup token */ int gg_token_watch_fd(struct gg_http *h) { @@ -547,8 +718,8 @@ if (h->state != GG_STATE_PARSING) return 0; - /* je�li h->data jest puste, to �ci�gali�my tokenid i url do niego, - * ale je�li co� tam jest, to znaczy, �e mamy drugi etap polegaj�cy + /* je�li h->data jest puste, to �ci�gali�my tokenid i url do niego, + * ale je�li co� tam jest, to znaczy, 甜e mamy drugi etap polegaj�cy * na pobieraniu tokenu. */ if (!h->data) { int width, height, length; @@ -573,8 +744,8 @@ return -1; } - /* dostali�my tokenid i wszystkie niezb�dne informacje, - * wi�c pobierzmy obrazek z tokenem */ + /* dostali�my tokenid i wszystkie niezb�dne informacje, + * wi�c pobierzmy obrazek z tokenem */ if (strncmp(url, "http://", 7)) { path = gg_saprintf("%s?tokenid=%s", url, tokenid); @@ -623,6 +794,8 @@ free(path); free(url); + gg_http_free_fields(h); + memcpy(h, h2, sizeof(struct gg_http)); free(h2); @@ -652,12 +825,12 @@ return 0; } -/* - * gg_token_free() +/** + * Zwalnia zasoby po operacji pobierania tokenu. * - * zwalnia pami裝 po efektach pobierania tokenu. + * \param h Struktura po��czenia * - * - h - zwalniana struktura + * \ingroup token */ void gg_token_free(struct gg_http *h) {
--- a/libpurple/protocols/gg/lib/pubdir50.c Sun Feb 28 23:42:12 2010 +0000 +++ b/libpurple/protocols/gg/lib/pubdir50.c Mon Mar 01 03:46:33 2010 +0000 @@ -1,4 +1,4 @@ -/* $Id: pubdir50.c 16856 2006-08-19 01:13:25Z evands $ */ +/* $Id: pubdir50.c 854 2009-10-12 21:06:28Z wojtekka $ */ /* * (C) Copyright 2003 Wojtek Kaniewski <wojtekka@irc.pl> @@ -14,23 +14,32 @@ * * 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" +/** + * \file pubdir50.c + * + * \brief Obs�uga katalogu publicznego od wersji Gadu-Gadu 5.x + */ #include <errno.h> #include <stdlib.h> #include <string.h> #include <time.h> -/* - * gg_pubdir50_new() +#include "libgadu.h" +#include "libgadu-internal.h" + +/** + * Tworzy nowe zapytanie katalogu publicznego. * - * tworzy now� zmienn� typu gg_pubdir50_t. + * \param type Rodzaj zapytania * - * zaalokowana zmienna lub NULL w przypadku braku pami�ci. + * \return Zmienna \c gg_pubdir50_t lub \c NULL w przypadku b��du. + * + * \ingroup pubdir50 */ gg_pubdir50_t gg_pubdir50_new(int type) { @@ -50,17 +59,16 @@ return res; } -/* - * gg_pubdir50_add_n() // funkcja wewn�trzna - * - * funkcja dodaje lub zast�puje istniej�ce pole do zapytania lub odpowiedzi. +/** + * \internal Dodaje lub zast�puje pole zapytania lub odpowiedzi katalogu + * publicznego. * - * - req - wska�nik opisu zapytania, - * - num - numer wyniku (0 dla zapytania), - * - field - nazwa pola, - * - value - warto倶 pola, + * \param req Zapytanie lub odpowied添 + * \param num Numer wyniku odpowiedzi (0 dla zapytania) + * \param field Nazwa pola + * \param value Warto�� pola * - * 0/-1 + * \return 0 je�li si� powiod�o, -1 w przypadku b��du */ static int gg_pubdir50_add_n(gg_pubdir50_t req, int num, const char *field, const char *value) { @@ -110,31 +118,31 @@ return 0; } -/* - * gg_pubdir50_add() - * - * funkcja dodaje pole do zapytania. +/** + * Dodaje pole zapytania. * - * - req - wska�nik opisu zapytania, - * - field - nazwa pola, - * - value - warto倶 pola, + * \param req Zapytanie + * \param field Nazwa pola + * \param value Warto�� pola * - * 0/-1 + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup pubdir50 */ int gg_pubdir50_add(gg_pubdir50_t req, const char *field, const char *value) { return gg_pubdir50_add_n(req, 0, field, value); } -/* - * gg_pubdir50_seq_set() - * - * ustawia numer sekwencyjny zapytania. +/** + * Ustawia numer sekwencyjny zapytania. * - * - req - zapytanie, - * - seq - nowy numer sekwencyjny. + * \param req Zapytanie + * \param seq Numer sekwencyjny * - * 0/-1. + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + * + * \ingroup pubdir50 */ int gg_pubdir50_seq_set(gg_pubdir50_t req, uint32_t seq) { @@ -151,12 +159,12 @@ return 0; } -/* - * gg_pubdir50_free() +/** + * Zwalnia zasoby po zapytaniu lub odpowiedzi katalogu publicznego. * - * zwalnia pami裝 po zapytaniu lub rezultacie szukania u�ytkownika. + * \param s Zapytanie lub odpowied添 * - * - s - zwalniana zmienna, + * \ingroup pubdir50 */ void gg_pubdir50_free(gg_pubdir50_t s) { @@ -174,15 +182,15 @@ free(s); } -/* - * gg_pubdir50() - * - * wysy�a zapytanie katalogu publicznego do serwera. +/** + * Wysy�a zapytanie katalogu publicznego do serwera. * - * - sess - sesja, - * - req - zapytanie. + * \param sess Struktura sesji + * \param req Zapytanie * - * numer sekwencyjny wyszukiwania lub 0 w przypadku b滑du. + * \return Numer sekwencyjny zapytania lub 0 w przypadku b��du + * + * \ingroup pubdir50 */ uint32_t gg_pubdir50(struct gg_session *sess, gg_pubdir50_t req) { @@ -191,16 +199,16 @@ char *buf, *p; struct gg_pubdir50_request *r; - gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50(%p, %p);\n", sess, req); + gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_pubdir50(%p, %p);\n", sess, req); if (!sess || !req) { - gg_debug(GG_DEBUG_MISC, "// gg_pubdir50() invalid arguments\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_pubdir50() invalid arguments\n"); errno = EFAULT; return 0; } if (sess->state != GG_STATE_CONNECTED) { - gg_debug(GG_DEBUG_MISC, "// gg_pubdir50() not connected\n"); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_pubdir50() not connected\n"); errno = ENOTCONN; return 0; } @@ -210,30 +218,81 @@ if (req->entries[i].num) continue; - size += strlen(req->entries[i].field) + 1; - size += strlen(req->entries[i].value) + 1; + if (sess->encoding == GG_ENCODING_CP1250) { + size += strlen(req->entries[i].field) + 1; + size += strlen(req->entries[i].value) + 1; + } else { + char *tmp; + + tmp = gg_utf8_to_cp(req->entries[i].field); + + if (tmp == NULL) + return -1; + + size += strlen(tmp) + 1; + + free(tmp); + + tmp = gg_utf8_to_cp(req->entries[i].value); + + if (tmp == NULL) + return -1; + + size += strlen(tmp) + 1; + + free(tmp); + } } if (!(buf = malloc(size))) { - gg_debug(GG_DEBUG_MISC, "// gg_pubdir50() out of memory (%d bytes)\n", size); + gg_debug_session(sess, GG_DEBUG_MISC, "// gg_pubdir50() out of memory (%d bytes)\n", size); return 0; } + if (!req->seq) + req->seq = time(NULL); + + res = req->seq; + r = (struct gg_pubdir50_request*) buf; - res = time(NULL); r->type = req->type; - r->seq = (req->seq) ? gg_fix32(req->seq) : gg_fix32(time(NULL)); - req->seq = gg_fix32(r->seq); + r->seq = gg_fix32(req->seq); for (i = 0, p = buf + 5; i < req->entries_count; i++) { if (req->entries[i].num) continue; - strcpy(p, req->entries[i].field); - p += strlen(p) + 1; + if (sess->encoding == GG_ENCODING_CP1250) { + strcpy(p, req->entries[i].field); + p += strlen(p) + 1; + + strcpy(p, req->entries[i].value); + p += strlen(p) + 1; + } else { + char *tmp; + + tmp = gg_utf8_to_cp(req->entries[i].field); + + if (tmp == NULL) { + free(buf); + return -1; + } - strcpy(p, req->entries[i].value); - p += strlen(p) + 1; + strcpy(p, tmp); + p += strlen(tmp) + 1; + free(tmp); + + tmp = gg_utf8_to_cp(req->entries[i].value); + + if (tmp == NULL) { + free(buf); + return -1; + } + + strcpy(p, tmp); + p += strlen(tmp) + 1; + free(tmp); + } } if (gg_send_packet(sess, GG_PUBDIR50_REQUEST, buf, size, NULL, 0) == -1) @@ -245,26 +304,26 @@ } /* - * gg_pubdir50_handle_reply() // funkcja wewn�trzna - * - * analizuje przychodz�cy pakiet odpowiedzi i zapisuje wynik w struct gg_event. + * \internal Analizuje przychodz�cy pakiet odpowiedzi i zapisuje wynik + * w strukturze \c gg_event. * - * - e - opis zdarzenia - * - packet - zawarto倶 pakietu odpowiedzi - * - length - d�ugo倶 pakietu odpowiedzi + * \param sess Struktura sesji + * \param e Struktura zdarzenia + * \param packet Pakiet odpowiedzi + * \param length D�ugo�� pakietu odpowiedzi * - * 0/-1 + * \return 0 je�li si� powiod�o, -1 w przypadku b��du */ -int gg_pubdir50_handle_reply(struct gg_event *e, const char *packet, int length) +int gg_pubdir50_handle_reply_sess(struct gg_session *sess, struct gg_event *e, const char *packet, int length) { const char *end = packet + length, *p; struct gg_pubdir50_reply *r = (struct gg_pubdir50_reply*) packet; gg_pubdir50_t res; int num = 0; - gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_handle_reply(%p, %p, %d);\n", e, packet, length); + gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_handle_reply_sess(%p, %p, %p, %d);\n", sess, e, packet, length); - if (!e || !packet) { + if (!sess || !e || !packet) { gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() invalid arguments\n"); errno = EFAULT; return -1; @@ -299,11 +358,11 @@ break; } - /* brak wynik�w? */ + /* brak wynik坦w? */ if (length == 5) return 0; - /* pomi� pocz�tek odpowiedzi */ + /* pomi� pocz�tek odpowiedzi */ p = packet + 5; while (p < end) { @@ -311,7 +370,7 @@ field = p; - /* sprawd�, czy nie mamy podzia�u na kolejne pole */ + /* sprawd添, czy nie mamy podzia�u na kolejne pole */ if (!*field) { num++; field++; @@ -320,22 +379,22 @@ value = NULL; for (p = field; p < end; p++) { - /* je�li mamy koniec tekstu... */ + /* je�li mamy koniec tekstu... */ if (!*p) { - /* ...i jeszcze nie mieli�my warto�ci pola to - * wiemy, �e po tym zerze jest warto倶... */ + /* ...i jeszcze nie mieli�my warto�ci pola to + * wiemy, 甜e po tym zerze jest warto��... */ if (!value) value = p + 1; else /* ...w przeciwym wypadku koniec - * warto�ci i mo�emy wychodzi� - * grzecznie z p�tli */ + * warto�ci i mo甜emy wychodzi� + * grzecznie z p�tli */ break; } } - /* sprawd�my, czy pole nie wychodzi poza pakiet, �eby nie - * mie� segfault�w, je�li serwer przestanie zaka�cza� pakiet�w + /* sprawd添my, czy pole nie wychodzi poza pakiet, 甜eby nie + * mie� segfault坦w, je�li serwer przestanie zaka�cza� pakiet坦w * przez \0 */ if (p == end) { @@ -345,14 +404,30 @@ p++; - /* je�li dostali�my namier na nast�pne wyniki, to znaczy �e - * mamy koniec wynik�w i nie jest to kolejna osoba. */ + /* je�li dostali�my namier na nast�pne wyniki, to znaczy 甜e + * mamy koniec wynik坦w i nie jest to kolejna osoba. */ if (!strcasecmp(field, "nextstart")) { res->next = atoi(value); num--; } else { - if (gg_pubdir50_add_n(res, num, field, value) == -1) - goto failure; + if (sess->encoding == GG_ENCODING_CP1250) { + if (gg_pubdir50_add_n(res, num, field, value) == -1) + goto failure; + } else { + char *tmp; + + tmp = gg_cp_to_utf8(value); + + if (tmp == NULL) + goto failure; + + if (gg_pubdir50_add_n(res, num, field, tmp) == -1) { + free(tmp); + goto failure; + } + + free(tmp); + } } } @@ -365,16 +440,16 @@ return -1; } -/* - * gg_pubdir50_get() - * - * pobiera informacj� z rezultatu wyszukiwania. +/** + * Pobiera pole z odpowiedzi katalogu publicznego. * - * - res - rezultat wyszukiwania, - * - num - numer odpowiedzi, - * - field - nazwa pola (wielko倶 liter nie ma znaczenia). + * \param res Odpowied添 + * \param num Numer wyniku odpowiedzi + * \param field Nazwa pola (wielko�� liter nie ma znaczenia) * - * warto倶 pola lub NULL, je�li nie znaleziono. + * \return Warto�� pola lub \c NULL je�li nie znaleziono + * + * \ingroup pubdir50 */ const char *gg_pubdir50_get(gg_pubdir50_t res, int num, const char *field) { @@ -399,57 +474,61 @@ return value; } -/* - * gg_pubdir50_count() +/** + * Zwraca liczb� wynik坦w odpowiedzi. * - * zwraca ilo倶 wynik�w danego zapytania. + * \param res Odpowied添 * - * - res - odpowied� + * \return Liczba wynik坦w lub -1 w przypadku b��du * - * ilo倶 lub -1 w przypadku b滑du. + * \ingroup pubdir50 */ int gg_pubdir50_count(gg_pubdir50_t res) { return (!res) ? -1 : res->count; } -/* - * gg_pubdir50_type() +/** + * Zwraca rodzaj zapytania lub odpowiedzi. * - * zwraca rodzaj zapytania lub odpowiedzi. + * \param res Zapytanie lub odpowied添 * - * - res - zapytanie lub odpowied� + * \return Rodzaj lub -1 w przypadku b��du * - * ilo倶 lub -1 w przypadku b滑du. + * \ingroup pubdir50 */ int gg_pubdir50_type(gg_pubdir50_t res) { return (!res) ? -1 : res->type; } -/* - * gg_pubdir50_next() +/** + * Zwraca numer, od kt坦rego nale甜y rozpocz�c kolejne wyszukiwanie. * - * zwraca numer, od kt�rego nale�y rozpocz掩 kolejne wyszukiwanie, je�li - * zale�y nam na kolejnych wynikach. + * D�u甜sze odpowiedzi katalogu publicznego s� wysy�ane przez serwer + * w mniejszych paczkach. Po otrzymaniu odpowiedzi, je�li numer kolejnego + * wyszukiwania jest wi�kszy od zera, dalsze wyniki mo甜na otrzyma� przez + * wywo�anie kolejnego zapytania z okre�lonym numerem pocz�tkowym. * - * - res - odpowied� + * \param res Odpowied添 * - * numer lub -1 w przypadku b滑du. + * \return Numer lub -1 w przypadku b��du + * + * \ingroup pubdir50 */ uin_t gg_pubdir50_next(gg_pubdir50_t res) { return (!res) ? (unsigned) -1 : res->next; } -/* - * gg_pubdir50_seq() +/** + * Zwraca numer sekwencyjny zapytania lub odpowiedzi. * - * zwraca numer sekwencyjny zapytania lub odpowiedzi. + * \param res Zapytanie lub odpowied添 * - * - res - zapytanie lub odpowied� + * \return Numer sekwencyjny lub -1 w przypadku b��du * - * numer lub -1 w przypadku b滑du. + * \ingroup pubdir50 */ uint32_t gg_pubdir50_seq(gg_pubdir50_t res) {
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/gg/lib/resolver.c Mon Mar 01 03:46:33 2010 +0000 @@ -0,0 +1,756 @@ +/* $Id$ */ + +/* + * (C) Copyright 2001-2009 Wojtek Kaniewski <wojtekka@irc.pl> + * Robert J. Wo添ny <speedy@ziew.org> + * Arkadiusz Mi�kiewicz <arekm@pld-linux.org> + * Tomasz Chili�ski <chilek@chilan.com> + * Adam Wysocki <gophi@ekg.chmurka.net> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License Version + * 2.1 as published by the Free Software Foundation. + * + * This program 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 Lesser General Public License for more details. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, + * USA. + */ + +/** + * \file resolver.c + * + * \brief Funkcje rozwi�zywania nazw + */ + +#ifndef _WIN32 +# include <sys/wait.h> +# include <netdb.h> +# include <signal.h> +# include <netinet/in.h> +# include <arpa/inet.h> +#endif + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "libgadu.h" +#include "resolver.h" +#include "compat.h" + +/** Spos坦b rozwi�zywania nazw serwer坦w */ +static gg_resolver_t gg_global_resolver_type = GG_RESOLVER_DEFAULT; + +/** Funkcja rozpoczynaj�ca rozwi�zywanie nazwy */ +static int (*gg_global_resolver_start)(int *fd, void **private_data, const char *hostname); + +/** Funkcja zwalniaj�ca zasoby po rozwi�zaniu nazwy */ +static void (*gg_global_resolver_cleanup)(void **private_data, int force); + +#ifdef GG_CONFIG_HAVE_PTHREAD + +#include <pthread.h> + +/** + * \internal Funkcja pomocnicza zwalniaj�ca zasoby po rozwi�zywaniu nazwy + * w w�tku. + * + * \param data Wska添nik na wska添nik bufora zaalokowanego w w�tku + */ +static void gg_gethostbyname_cleaner(void *data) +{ + char **buf_ptr = (char**) data; + + if (buf_ptr != NULL) { + free(*buf_ptr); + *buf_ptr = NULL; + } +} + +#endif /* GG_CONFIG_HAVE_PTHREAD */ + +/** + * \internal Odpowiednik \c gethostbyname zapewniaj�cy wsp坦�bie甜no��. + * + * Je�li dany system dostarcza \c gethostbyname_r, u甜ywa si� tej wersji, je�li + * nie, to zwyk�ej \c gethostbyname. + * + * \param hostname Nazwa serwera + * \param addr Wska添nik na rezultat rozwi�zywania nazwy + * \param pthread Flaga blokowania unicestwiania w�tku podczas alokacji pami�ci + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +int gg_gethostbyname_real(const char *hostname, struct in_addr *addr, int pthread) +{ +#ifdef GG_CONFIG_HAVE_GETHOSTBYNAME_R + char *buf = NULL; + char *new_buf = NULL; + struct hostent he; + struct hostent *he_ptr = NULL; + size_t buf_len = 1024; + int result = -1; + int h_errnop; + int ret = 0; +#ifdef GG_CONFIG_HAVE_PTHREAD + int old_state; +#endif + +#ifdef GG_CONFIG_HAVE_PTHREAD + pthread_cleanup_push(gg_gethostbyname_cleaner, &buf); + + if (pthread) + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); +#endif + + buf = malloc(buf_len); + +#ifdef GG_CONFIG_HAVE_PTHREAD + if (pthread) + pthread_setcancelstate(old_state, NULL); +#endif + + if (buf != NULL) { +#ifndef sun + while ((ret = gethostbyname_r(hostname, &he, buf, buf_len, &he_ptr, &h_errnop)) == ERANGE) { +#else + while (((he_ptr = gethostbyname_r(hostname, &he, buf, buf_len, &h_errnop)) == NULL) && (errno == ERANGE)) { +#endif + buf_len *= 2; + +#ifdef GG_CONFIG_HAVE_PTHREAD + if (pthread) + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); +#endif + + new_buf = realloc(buf, buf_len); + + if (new_buf != NULL) + buf = new_buf; + +#ifdef GG_CONFIG_HAVE_PTHREAD + if (pthread) + pthread_setcancelstate(old_state, NULL); +#endif + + if (new_buf == NULL) { + ret = ENOMEM; + break; + } + } + + if (ret == 0 && he_ptr != NULL) { + memcpy(addr, he_ptr->h_addr, sizeof(struct in_addr)); + result = 0; + } + +#ifdef GG_CONFIG_HAVE_PTHREAD + if (pthread) + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state); +#endif + + free(buf); + buf = NULL; + +#ifdef GG_CONFIG_HAVE_PTHREAD + if (pthread) + pthread_setcancelstate(old_state, NULL); +#endif + } + +#ifdef GG_CONFIG_HAVE_PTHREAD + pthread_cleanup_pop(1); +#endif + + return result; +#else + struct hostent *he; + + he = gethostbyname(hostname); + + if (he == NULL) + return -1; + + memcpy(addr, he->h_addr, sizeof(struct in_addr)); + + return 0; +#endif /* GG_CONFIG_HAVE_GETHOSTBYNAME_R */ +} + +/** + * \internal Odpowiednik \c gethostbyname zapewniaj�cy wsp坦�bie甜no��. + * + * Je�li dany system dostarcza \c gethostbyname_r, u甜ywa si� tej wersji, je�li + * nie, to zwyk�ej \c gethostbyname. + * + * \param hostname Nazwa serwera + * + * \return Zaalokowana struktura \c in_addr lub NULL w przypadku b��du. + */ +struct in_addr *gg_gethostbyname(const char *hostname) +{ + struct in_addr *addr; + + if (!(addr = malloc(sizeof(struct in_addr)))) + return NULL; + + if (gg_gethostbyname_real(hostname, addr, 0)) { + free(addr); + return NULL; + } + return addr; +} + +/** + * \internal Struktura przekazywana do w�tku rozwi�zuj�cego nazw�. + */ +struct gg_resolver_fork_data { + int pid; /*< Identyfikator procesu */ +}; + +/** + * \internal Rozwi�zuje nazw� serwera w osobnym procesie. + * + * Po��czenia asynchroniczne nie mog� blokowa� procesu w trakcie rozwi�zywania + * nazwy serwera. W tym celu tworzony jest potok, nowy proces i dopiero w nim + * przeprowadzane jest rozwi�zywanie nazwy. Deskryptor strony do odczytu + * zapisuje si� w strukturze sieci i czeka na dane w postaci struktury + * \c in_addr. Je�li nie znaleziono nazwy, zwracana jest \c INADDR_NONE. + * + * \param fd Wska添nik na zmienn�, gdzie zostanie umieszczony deskryptor + * potoku + * \param priv_data Wska添nik na zmienn�, gdzie zostanie umieszczony wska添nik + * do numeru procesu potomnego rozwi�zuj�cego nazw� + * \param hostname Nazwa serwera do rozwi�zania + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +static int gg_resolver_fork_start(int *fd, void **priv_data, const char *hostname) +{ + struct gg_resolver_fork_data *data = NULL; + struct in_addr addr; + int pipes[2], new_errno; + + gg_debug(GG_DEBUG_FUNCTION, "** gg_resolver_fork_start(%p, %p, \"%s\");\n", fd, priv_data, hostname); + + if (fd == NULL || priv_data == NULL || hostname == NULL) { + gg_debug(GG_DEBUG_MISC, "// gg_resolver_fork_start() invalid arguments\n"); + errno = EFAULT; + return -1; + } + + data = malloc(sizeof(struct gg_resolver_fork_data)); + + if (data == NULL) { + gg_debug(GG_DEBUG_MISC, "// gg_resolver_fork_start() out of memory for resolver data\n"); + return -1; + } + + if (pipe(pipes) == -1) { + gg_debug(GG_DEBUG_MISC, "// gg_resolver_fork_start() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno)); + free(data); + return -1; + } + + data->pid = fork(); + + if (data->pid == -1) { + new_errno = errno; + goto cleanup; + } + + if (data->pid == 0) { + close(pipes[0]); + + if ((addr.s_addr = inet_addr(hostname)) == INADDR_NONE) { + /* W przypadku b��du gg_gethostbyname_real() zwr坦ci -1 + * i nie zmieni &addr. Tam jest ju甜 INADDR_NONE, + * wi�c nie musimy robi� nic wi�cej. */ + gg_gethostbyname_real(hostname, &addr, 0); + } + + if (write(pipes[1], &addr, sizeof(addr)) != sizeof(addr)) + exit(1); + + exit(0); + } + + close(pipes[1]); + + gg_debug(GG_DEBUG_MISC, "// gg_resolver_fork_start() %p\n", data); + + *fd = pipes[0]; + *priv_data = data; + + return 0; + +cleanup: + free(data); + close(pipes[0]); + close(pipes[1]); + + errno = new_errno; + + return -1; +} + +/** + * \internal Usuwanie zasob坦w po procesie rozwi�zywaniu nazwy. + * + * Funkcja wywo�ywana po zako�czeniu rozwi�zanywania nazwy lub przy zwalnianiu + * zasob坦w sesji podczas rozwi�zywania nazwy. + * + * \param priv_data Wska添nik na zmienn� przechowuj�c� wska添nik do prywatnych + * danych + * \param force Flaga usuwania zasob坦w przed zako�czeniem dzia�ania + */ +void gg_resolver_fork_cleanup(void **priv_data, int force) +{ + struct gg_resolver_fork_data *data; + + if (priv_data == NULL || *priv_data == NULL) + return; + + data = (struct gg_resolver_fork_data*) *priv_data; + *priv_data = NULL; + + if (force) + kill(data->pid, SIGKILL); + + waitpid(data->pid, NULL, WNOHANG); + + free(data); +} + +#ifdef GG_CONFIG_HAVE_PTHREAD + +/** + * \internal Struktura przekazywana do w�tku rozwi�zuj�cego nazw�. + */ +struct gg_resolver_pthread_data { + pthread_t thread; /*< Identyfikator w�tku */ + char *hostname; /*< Nazwa serwera */ + int rfd; /*< Deskryptor do odczytu */ + int wfd; /*< Deskryptor do zapisu */ +}; + +/** + * \internal Usuwanie zasob坦w po w�tku rozwi�zywaniu nazwy. + * + * Funkcja wywo�ywana po zako�czeniu rozwi�zanywania nazwy lub przy zwalnianiu + * zasob坦w sesji podczas rozwi�zywania nazwy. + * + * \param priv_data Wska添nik na zmienn� przechowuj�c� wska添nik do prywatnych + * danych + * \param force Flaga usuwania zasob坦w przed zako�czeniem dzia�ania + */ +static void gg_resolver_pthread_cleanup(void **priv_data, int force) +{ + struct gg_resolver_pthread_data *data; + + if (priv_data == NULL || *priv_data == NULL) + return; + + data = (struct gg_resolver_pthread_data *) *priv_data; + *priv_data = NULL; + + if (force) { + pthread_cancel(data->thread); + pthread_join(data->thread, NULL); + } + + free(data->hostname); + data->hostname = NULL; + + if (data->wfd != -1) { + close(data->wfd); + data->wfd = -1; + } + + free(data); +} + +/** + * \internal W�tek rozwi�zuj�cy nazw�. + * + * \param arg Wska添nik na struktur� \c gg_resolver_pthread_data + */ +static void *gg_resolver_pthread_thread(void *arg) +{ + struct gg_resolver_pthread_data *data = arg; + struct in_addr addr; + + pthread_detach(pthread_self()); + + if ((addr.s_addr = inet_addr(data->hostname)) == INADDR_NONE) { + /* W przypadku b��du gg_gethostbyname_real() zwr坦ci -1 + * i nie zmieni &addr. Tam jest ju甜 INADDR_NONE, + * wi�c nie musimy robi� nic wi�cej. */ + gg_gethostbyname_real(data->hostname, &addr, 1); + } + + if (write(data->wfd, &addr, sizeof(addr)) == sizeof(addr)) + pthread_exit(NULL); + else + pthread_exit((void*) -1); + + return NULL; /* 甜eby kompilator nie marudzi� */ +} + +/** + * \internal Rozwi�zuje nazw� serwera w osobnym w�tku. + * + * Funkcja dzia�a analogicznie do \c gg_resolver_fork_start(), z t� r坦甜nic�, + * 甜e dzia�a na w�tkach, nie procesach. Jest dost�pna wy��cznie gdy podczas + * kompilacji w��czono odpowiedni� opcj�. + * + * \param fd Wska添nik na zmienn�, gdzie zostanie umieszczony deskryptor + * potoku + * \param priv_data Wska添nik na zmienn�, gdzie zostanie umieszczony wska添nik + * do prywatnych danych w�tku rozwi�zuj�cego nazw� + * \param hostname Nazwa serwera do rozwi�zania + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +static int gg_resolver_pthread_start(int *fd, void **priv_data, const char *hostname) +{ + struct gg_resolver_pthread_data *data = NULL; + int pipes[2], new_errno; + + gg_debug(GG_DEBUG_FUNCTION, "** gg_resolver_pthread_start(%p, %p, \"%s\");\n", fd, priv_data, hostname); + + if (fd == NULL || priv_data == NULL || hostname == NULL) { + gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() invalid arguments\n"); + errno = EFAULT; + return -1; + } + + data = malloc(sizeof(struct gg_resolver_pthread_data)); + + if (data == NULL) { + gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() out of memory for resolver data\n"); + return -1; + } + + if (pipe(pipes) == -1) { + gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno)); + free(data); + return -1; + } + + data->hostname = strdup(hostname); + + if (data->hostname == NULL) { + gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() out of memory\n"); + new_errno = errno; + goto cleanup; + } + + data->rfd = pipes[0]; + data->wfd = pipes[1]; + + if (pthread_create(&data->thread, NULL, gg_resolver_pthread_thread, data)) { + gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() unable to create thread\n"); + new_errno = errno; + goto cleanup; + } + + gg_debug(GG_DEBUG_MISC, "// gg_resolver_pthread_start() %p\n", data); + + *fd = pipes[0]; + *priv_data = data; + + return 0; + +cleanup: + if (data) { + free(data->hostname); + free(data); + } + + close(pipes[0]); + close(pipes[1]); + + errno = new_errno; + + return -1; +} + +#endif /* GG_CONFIG_HAVE_PTHREAD */ + +/** + * Ustawia spos坦b rozwi�zywania nazw w sesji. + * + * \param gs Struktura sesji + * \param type Spos坦b rozwi�zywania nazw (patrz \ref build-resolver) + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +int gg_session_set_resolver(struct gg_session *gs, gg_resolver_t type) +{ + if (gs == NULL) { + errno = EINVAL; + return -1; + } + + if (type == GG_RESOLVER_DEFAULT) { + if (gg_global_resolver_type != GG_RESOLVER_DEFAULT) { + gs->resolver_type = gg_global_resolver_type; + gs->resolver_start = gg_global_resolver_start; + gs->resolver_cleanup = gg_global_resolver_cleanup; + return 0; + } + +#if !defined(GG_CONFIG_HAVE_PTHREAD) || !defined(GG_CONFIG_PTHREAD_DEFAULT) + type = GG_RESOLVER_FORK; +#else + type = GG_RESOLVER_PTHREAD; +#endif + } + + switch (type) { + case GG_RESOLVER_FORK: + gs->resolver_type = type; + gs->resolver_start = gg_resolver_fork_start; + gs->resolver_cleanup = gg_resolver_fork_cleanup; + return 0; + +#ifdef GG_CONFIG_HAVE_PTHREAD + case GG_RESOLVER_PTHREAD: + gs->resolver_type = type; + gs->resolver_start = gg_resolver_pthread_start; + gs->resolver_cleanup = gg_resolver_pthread_cleanup; + return 0; +#endif + + default: + errno = EINVAL; + return -1; + } +} + +/** + * Zwraca spos坦b rozwi�zywania nazw w sesji. + * + * \param gs Struktura sesji + * + * \return Spos坦b rozwi�zywania nazw + */ +gg_resolver_t gg_session_get_resolver(struct gg_session *gs) +{ + if (gs == NULL) { + errno = EINVAL; + return GG_RESOLVER_INVALID; + } + + return gs->resolver_type; +} + +/** + * Ustawia w�asny spos坦b rozwi�zywania nazw w sesji. + * + * \param gs Struktura sesji + * \param resolver_start Funkcja rozpoczynaj�ca rozwi�zywanie nazwy + * \param resolver_cleanup Funkcja zwalniaj�ca zasoby + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +int gg_session_set_custom_resolver(struct gg_session *gs, int (*resolver_start)(int*, void**, const char*), void (*resolver_cleanup)(void**, int)) +{ + if (gs == NULL || resolver_start == NULL || resolver_cleanup == NULL) { + errno = EINVAL; + return -1; + } + + gs->resolver_type = GG_RESOLVER_CUSTOM; + gs->resolver_start = resolver_start; + gs->resolver_cleanup = resolver_cleanup; + + return 0; +} + +/** + * Ustawia spos坦b rozwi�zywania nazw po��czenia HTTP. + * + * \param gh Struktura po��czenia + * \param type Spos坦b rozwi�zywania nazw (patrz \ref build-resolver) + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +int gg_http_set_resolver(struct gg_http *gh, gg_resolver_t type) +{ + if (gh == NULL) { + errno = EINVAL; + return -1; + } + + if (type == GG_RESOLVER_DEFAULT) { + if (gg_global_resolver_type != GG_RESOLVER_DEFAULT) { + gh->resolver_type = gg_global_resolver_type; + gh->resolver_start = gg_global_resolver_start; + gh->resolver_cleanup = gg_global_resolver_cleanup; + return 0; + } + +#if !defined(GG_CONFIG_HAVE_PTHREAD) || !defined(GG_CONFIG_PTHREAD_DEFAULT) + type = GG_RESOLVER_FORK; +#else + type = GG_RESOLVER_PTHREAD; +#endif + } + + switch (type) { + case GG_RESOLVER_FORK: + gh->resolver_type = type; + gh->resolver_start = gg_resolver_fork_start; + gh->resolver_cleanup = gg_resolver_fork_cleanup; + return 0; + +#ifdef GG_CONFIG_HAVE_PTHREAD + case GG_RESOLVER_PTHREAD: + gh->resolver_type = type; + gh->resolver_start = gg_resolver_pthread_start; + gh->resolver_cleanup = gg_resolver_pthread_cleanup; + return 0; +#endif + + default: + errno = EINVAL; + return -1; + } +} + +/** + * Zwraca spos坦b rozwi�zywania nazw po��czenia HTTP. + * + * \param gh Struktura po��czenia + * + * \return Spos坦b rozwi�zywania nazw + */ +gg_resolver_t gg_http_get_resolver(struct gg_http *gh) +{ + if (gh == NULL) { + errno = EINVAL; + return GG_RESOLVER_INVALID; + } + + return gh->resolver_type; +} + +/** + * Ustawia w�asny spos坦b rozwi�zywania nazw po��czenia HTTP. + * + * \param gh Struktura sesji + * \param resolver_start Funkcja rozpoczynaj�ca rozwi�zywanie nazwy + * \param resolver_cleanup Funkcja zwalniaj�ca zasoby + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +int gg_http_set_custom_resolver(struct gg_http *gh, int (*resolver_start)(int*, void**, const char*), void (*resolver_cleanup)(void**, int)) +{ + if (gh == NULL || resolver_start == NULL || resolver_cleanup == NULL) { + errno = EINVAL; + return -1; + } + + gh->resolver_type = GG_RESOLVER_CUSTOM; + gh->resolver_start = resolver_start; + gh->resolver_cleanup = resolver_cleanup; + + return 0; +} + +/** + * Ustawia spos坦b rozwi�zywania nazw globalnie dla biblioteki. + * + * \param type Spos坦b rozwi�zywania nazw (patrz \ref build-resolver) + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +int gg_global_set_resolver(gg_resolver_t type) +{ + switch (type) { + case GG_RESOLVER_DEFAULT: + gg_global_resolver_type = type; + gg_global_resolver_start = NULL; + gg_global_resolver_cleanup = NULL; + return 0; + + case GG_RESOLVER_FORK: + gg_global_resolver_type = type; + gg_global_resolver_start = gg_resolver_fork_start; + gg_global_resolver_cleanup = gg_resolver_fork_cleanup; + return 0; + +#ifdef GG_CONFIG_HAVE_PTHREAD + case GG_RESOLVER_PTHREAD: + gg_global_resolver_type = type; + gg_global_resolver_start = gg_resolver_pthread_start; + gg_global_resolver_cleanup = gg_resolver_pthread_cleanup; + return 0; +#endif + + default: + errno = EINVAL; + return -1; + } +} + +/** + * Zwraca spos坦b rozwi�zywania nazw globalnie dla biblioteki. + * + * \return Spos坦b rozwi�zywania nazw + */ +gg_resolver_t gg_global_get_resolver(void) +{ + return gg_global_resolver_type; +} + +/** + * Ustawia w�asny spos坦b rozwi�zywania nazw globalnie dla biblioteki. + * + * \param resolver_start Funkcja rozpoczynaj�ca rozwi�zywanie nazwy + * \param resolver_cleanup Funkcja zwalniaj�ca zasoby + * + * Parametry funkcji rozpoczynaj�cej rozwi�zywanie nazwy wygl�daj� nast�puj�co: + * - \c "int *fd" — wska添nik na zmienn�, gdzie zostanie umieszczony deskryptor potoku + * - \c "void **priv_data" — wska添nik na zmienn�, gdzie mo甜na umie�ci� wska添nik do prywatnych danych na potrzeby rozwi�zywania nazwy + * - \c "const char *name" — nazwa serwera do rozwi�zania + * + * Parametry funkcji zwalniaj�cej zasoby wygl�daj� nast�puj�co: + * - \c "void **priv_data" — wska添nik na zmienn� przechowuj�c� wska添nik do prywatnych danych, nale甜y go ustawi� na \c NULL po zako�czeniu + * - \c "int force" — flaga m坦wi�ca o tym, 甜e zasoby s� zwalniane przed zako�czeniem rozwi�zywania nazwy, np. z powodu zamkni�cia sesji. + * + * W�asny kod rozwi�zywania nazwy powinien stworzy� potok, par� gniazd lub + * inny deskryptor pozwalaj�cy na co najmniej jednostronn� komunikacj� i + * przekaza� go w parametrze \c fd. Po zako�czeniu rozwi�zywania nazwy, + * powinien wys�a� otrzymany adres IP w postaci sieciowej (big-endian) do + * deskryptora. Je�li rozwi�zywanie nazwy si� nie powiedzie, nale甜y wys�a� + * \c INADDR_NONE. Nast�pnie zostanie wywo�ana funkcja zwalniaj�ca zasoby + * z parametrem \c force r坦wnym \c 0. Gdyby sesja zosta�a zako�czona przed + * rozwi�zaniem nazwy, np. za pomoc� funkcji \c gg_logoff(), funkcja + * zwalniaj�ca zasoby zostanie wywo�ana z parametrem \c force r坦wnym \c 1. + * + * \return 0 je�li si� powiod�o, -1 w przypadku b��du + */ +int gg_global_set_custom_resolver(int (*resolver_start)(int*, void**, const char*), void (*resolver_cleanup)(void**, int)) +{ + if (resolver_start == NULL || resolver_cleanup == NULL) { + errno = EINVAL; + return -1; + } + + gg_global_resolver_type = GG_RESOLVER_CUSTOM; + gg_global_resolver_start = resolver_start; + gg_global_resolver_cleanup = resolver_cleanup; + + return 0; +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/gg/lib/resolver.h Mon Mar 01 03:46:33 2010 +0000 @@ -0,0 +1,30 @@ +/* $Id$ */ + +/* + * (C) Copyright 2008 Wojtek Kaniewski <wojtekka@irc.pl> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License Version + * 2.1 as published by the Free Software Foundation. + * + * This program 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 Lesser General Public License for more details. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, + * USA. + */ + +#ifndef LIBGADU_RESOLVER_H +#define LIBGADU_RESOLVER_H + +#ifndef _WIN32 +# include <arpa/inet.h> +#endif + +int gg_gethostbyname_real(const char *hostname, struct in_addr *result, int pthread); + +#endif /* LIBGADU_RESOLVER_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/libpurple/protocols/gg/lib/sha1.c Mon Mar 01 03:46:33 2010 +0000 @@ -0,0 +1,303 @@ +/* $Id: sha1.c 632 2008-07-30 18:40:06Z darkjames $ */ + +/* + * (C) Copyright 2007 Wojtek Kaniewski <wojtekka@irc.pl> + * + * Public domain SHA-1 implementation by Steve Reid <steve@edmweb.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License Version + * 2.1 as published by the Free Software Foundation. + * + * This program 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 Lesser General Public License for more details. + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, + * USA. + */ + +/** + * \file sha1.c + * + * \brief Funkcje wyznaczania skr��tu SHA1 + */ + +#include <string.h> +#include <sys/types.h> +#include <unistd.h> + +#include "libgadu.h" + +/** \cond ignore */ + +#ifdef GG_CONFIG_HAVE_OPENSSL + +#include <openssl/sha.h> + +#else + +/* +SHA-1 in C +By Steve Reid <steve@edmweb.com> +100% Public Domain + +Modified by Wojtek Kaniewski <wojtekka@toxygen.net> for compatibility +with libgadu and OpenSSL API. + +Test Vectors (from FIPS PUB 180-1) +"abc" + A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D +"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 +A million repetitions of "a" + 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F +*/ + +/* #define LITTLE_ENDIAN * This should be #define'd if true. */ +/* #define SHA1HANDSOFF * Copies data before messing with it. */ + +#include <string.h> + +typedef struct { + uint32_t state[5]; + uint32_t count[2]; + unsigned char buffer[64]; +} SHA_CTX; + +static void SHA1_Transform(uint32_t state[5], const unsigned char buffer[64]); +static void SHA1_Init(SHA_CTX* context); +static void SHA1_Update(SHA_CTX* context, const unsigned char* data, unsigned int len); +static void SHA1_Final(unsigned char digest[20], SHA_CTX* context); + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +/* blk0() and blk() perform the initial expand. */ +/* I got the idea of expanding during the round function from SSLeay */ +#ifndef GG_CONFIG_BIGENDIAN +#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ + |(rol(block->l[i],8)&0x00FF00FF)) +#else +#define blk0(i) block->l[i] +#endif +#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ + ^block->l[(i+2)&15]^block->l[i&15],1)) + +/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ +#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); +#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); +#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); +#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); + + +/* Hash a single 512-bit block. This is the core of the algorithm. */ + +static void SHA1_Transform(uint32_t state[5], const unsigned char buffer[64]) +{ +uint32_t a, b, c, d, e; +typedef union { + unsigned char c[64]; + uint32_t l[16]; +} CHAR64LONG16; +CHAR64LONG16* block; +static unsigned char workspace[64]; + block = (CHAR64LONG16*)workspace; + memcpy(block, buffer, 64); + /* Copy context->state[] to working vars */ + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3); + R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7); + R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11); + R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15); + R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19); + R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23); + R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27); + R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31); + R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35); + R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39); + R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43); + R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47); + R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51); + R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55); + R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59); + R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63); + R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67); + R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71); + R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75); + R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79); + /* Add the working vars back into context.state[] */ + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + /* Wipe variables */ + a = b = c = d = e = 0; +} + + +/* SHA1_Init - Initialize new context */ + +static void SHA1_Init(SHA_CTX* context) +{ + /* SHA1 initialization constants */ + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + + +/* Run your data through this. */ + +static void SHA1_Update(SHA_CTX* context, const unsigned char* data, unsigned int len) +{ +unsigned int i, j; + + j = (context->count[0] >> 3) & 63; + if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++; + context->count[1] += (len >> 29); + if ((j + len) > 63) { + memcpy(&context->buffer[j], data, (i = 64-j)); + SHA1_Transform(context->state, context->buffer); + for ( ; i + 63 < len; i += 64) { + SHA1_Transform(context->state, &data[i]); + } + j = 0; + } + else i = 0; + memcpy(&context->buffer[j], &data[i], len - i); +} + + +/* Add padding and return the message digest. */ + +static void SHA1_Final(unsigned char digest[20], SHA_CTX* context) +{ +uint32_t i, j; +unsigned char finalcount[8]; + + for (i = 0; i < 8; i++) { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] + >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ + } + SHA1_Update(context, (unsigned char *)"\200", 1); + while ((context->count[0] & 504) != 448) { + SHA1_Update(context, (unsigned char *)"\0", 1); + } + SHA1_Update(context, finalcount, 8); /* Should cause a SHA1_Transform() */ + for (i = 0; i < 20; i++) { + digest[i] = (unsigned char) + ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); + } + /* Wipe variables */ + i = j = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(&finalcount, 0, 8); +#ifdef SHA1HANDSOFF /* make SHA1_Transform overwrite it's own static vars */ + SHA1_Transform(context->state, context->buffer); +#endif +} + +#endif /* GG_CONFIG_HAVE_OPENSSL */ + +/** \endcond */ + +/** \cond internal */ + +/** + * \internal Liczy skr��t SHA1 z ziarna i has長�a. + * + * \param password Has長�o + * \param seed Ziarno + * \param result Bufor na wynik funkcji skr��tu (20 bajt��w) + */ +void gg_login_hash_sha1(const char *password, uint32_t seed, uint8_t *result) +{ + SHA_CTX ctx; + + SHA1_Init(&ctx); + SHA1_Update(&ctx, (const unsigned char*) password, strlen(password)); + seed = gg_fix32(seed); + SHA1_Update(&ctx, (uint8_t*) &seed, 4); + + SHA1_Final(result, &ctx); +} + +/** + * \internal Liczy skr��t SHA1 z pliku. + * + * \param fd Deskryptor pliku + * \param result Wska長�nik na skr��t + * + * \return 0 lub -1 + */ +int gg_file_hash_sha1(int fd, uint8_t *result) +{ + unsigned char buf[4096]; + SHA_CTX ctx; + off_t pos, len; + int res; + + if ((pos = lseek(fd, 0, SEEK_CUR)) == (off_t) -1) + return -1; + + if ((len = lseek(fd, 0, SEEK_END)) == (off_t) -1) + return -1; + + if (lseek(fd, 0, SEEK_SET) == (off_t) -1) + return -1; + + SHA1_Init(&ctx); + + if (len <= 10485760) { + while ((res = read(fd, buf, sizeof(buf))) > 0) + SHA1_Update(&ctx, buf, res); + } else { + int i; + + for (i = 0; i < 9; i++) { + int j; + + if (lseek(fd, (len - 1048576) / 9 * i, SEEK_SET) == (off_t) - 1) + return -1; + + for (j = 0; j < 1048576 / sizeof(buf); j++) { + if ((res = read(fd, buf, sizeof(buf))) != sizeof(buf)) { + res = -1; + break; + } + + SHA1_Update(&ctx, buf, res); + } + + if (res == -1) + break; + } + } + + if (res == -1) + return -1; + + SHA1_Final(result, &ctx); + + if (lseek(fd, pos, SEEK_SET) == (off_t) -1) + return -1; + + return 0; +} + +/** \endcond */