comparison libpurple/protocols/gg/lib/libgadu.c @ 31410:93b08d43f684

matekm and kkszysiu collaborated on this patch to update our internal libgadu to version 1.10.1.
author John Bailey <rekkanoryo@rekkanoryo.org>
date Thu, 24 Mar 2011 20:53:13 +0000
parents a8cc50c2279f
children 3a90a59ddea2
comparison
equal deleted inserted replaced
31409:5043fc53f957 31410:93b08d43f684
1 /* $Id: libgadu.c 878 2009-11-16 23:48:19Z wojtekka $ */ 1 /* $Id: libgadu.c 1062 2011-03-13 18:10:24Z wojtekka $ */
2 2
3 /* 3 /*
4 * (C) Copyright 2001-2009 Wojtek Kaniewski <wojtekka@irc.pl> 4 * (C) Copyright 2001-2010 Wojtek Kaniewski <wojtekka@irc.pl>
5 * Robert J. Woźny <speedy@ziew.org> 5 * Robert J. Woźny <speedy@ziew.org>
6 * Arkadiusz Miśkiewicz <arekm@pld-linux.org> 6 * Arkadiusz Miśkiewicz <arekm@pld-linux.org>
7 * Tomasz Chiliński <chilek@chilan.com> 7 * Tomasz Chiliński <chilek@chilan.com>
8 * Adam Wysocki <gophi@ekg.chmurka.net> 8 * Adam Wysocki <gophi@ekg.chmurka.net>
9 * 9 *
29 */ 29 */
30 30
31 #include "libgadu.h" 31 #include "libgadu.h"
32 #include "libgadu-config.h" 32 #include "libgadu-config.h"
33 #include "libgadu-internal.h" 33 #include "libgadu-internal.h"
34 #include "libgadu-debug.h"
34 35
35 #include <sys/types.h> 36 #include <sys/types.h>
36 37
37 #ifdef _WIN32 38 #ifdef _WIN32
38 # include <io.h> 39 # include <io.h>
49 #endif 50 #endif
50 51
51 #include "compat.h" 52 #include "compat.h"
52 #include "protocol.h" 53 #include "protocol.h"
53 #include "resolver.h" 54 #include "resolver.h"
55 #include "encoding.h"
56 #include "session.h"
54 57
55 #ifndef _WIN32 58 #ifndef _WIN32
56 # include <errno.h> /* on Win32 this is included above */ 59 # include <errno.h> /* on Win32 this is included above */
57 # include <netdb.h> 60 # include <netdb.h>
58 #endif 61 #endif
62 #include <stdlib.h> 65 #include <stdlib.h>
63 #include <string.h> 66 #include <string.h>
64 #include <signal.h> 67 #include <signal.h>
65 #include <time.h> 68 #include <time.h>
66 #include <unistd.h> 69 #include <unistd.h>
70 #ifdef GG_CONFIG_HAVE_GNUTLS
71 # include <gnutls/gnutls.h>
72 #endif
67 #ifdef GG_CONFIG_HAVE_OPENSSL 73 #ifdef GG_CONFIG_HAVE_OPENSSL
68 # include <openssl/err.h> 74 # include <openssl/err.h>
69 # include <openssl/rand.h> 75 # include <openssl/rand.h>
70 #endif 76 #endif
71 77
72 #define GG_LIBGADU_VERSION "1.9.0" 78 #define GG_LIBGADU_VERSION "1.10.1"
73
74 /**
75 * Poziom rejestracji informacji odpluskwiających. Zmienna jest maską bitową
76 * składającą się ze stałych \c GG_DEBUG_...
77 *
78 * \ingroup debug
79 */
80 int gg_debug_level = 0;
81
82 /**
83 * Funkcja, do której są przekazywane informacje odpluskwiające. Jeśli zarówno
84 * ten \c gg_debug_handler, jak i \c gg_debug_handler_session, są równe
85 * \c NULL, informacje są wysyłane do standardowego wyjścia błędu (\c stderr).
86 *
87 * \param level Poziom rejestracji
88 * \param format Format wiadomości (zgodny z \c printf)
89 * \param ap Lista argumentów (zgodna z \c printf)
90 *
91 * \note Funkcja jest przesłaniana przez \c gg_debug_handler_session.
92 *
93 * \ingroup debug
94 */
95 void (*gg_debug_handler)(int level, const char *format, va_list ap) = NULL;
96
97 /**
98 * Funkcja, do której są przekazywane informacje odpluskwiające. Jeśli zarówno
99 * ten \c gg_debug_handler, jak i \c gg_debug_handler_session, są równe
100 * \c NULL, informacje są wysyłane do standardowego wyjścia błędu.
101 *
102 * \param sess Sesja której dotyczy informacja lub \c NULL
103 * \param level Poziom rejestracji
104 * \param format Format wiadomości (zgodny z \c printf)
105 * \param ap Lista argumentów (zgodna z \c printf)
106 *
107 * \note Funkcja przesłania przez \c gg_debug_handler_session.
108 *
109 * \ingroup debug
110 */
111 void (*gg_debug_handler_session)(struct gg_session *sess, int level, const char *format, va_list ap) = NULL;
112 79
113 /** 80 /**
114 * Port gniazda nasłuchującego dla połączeń bezpośrednich. 81 * Port gniazda nasłuchującego dla połączeń bezpośrednich.
115 * 82 *
116 * \ingroup ip 83 * \ingroup ip
178 #ifndef lint 145 #ifndef lint
179 static char rcsid[] 146 static char rcsid[]
180 #ifdef __GNUC__ 147 #ifdef __GNUC__
181 __attribute__ ((unused)) 148 __attribute__ ((unused))
182 #endif 149 #endif
183 = "$Id: libgadu.c 923 2010-03-09 20:03:29Z wojtekka $"; 150 = "$Id: libgadu.c 1062 2011-03-13 18:10:24Z wojtekka $";
184 #endif 151 #endif
185 152
186 #endif /* DOXYGEN */ 153 #endif /* DOXYGEN */
187 154
188 /** 155 /**
194 */ 161 */
195 const char *gg_libgadu_version() 162 const char *gg_libgadu_version()
196 { 163 {
197 return GG_LIBGADU_VERSION; 164 return GG_LIBGADU_VERSION;
198 } 165 }
166
167 #ifdef GG_CONFIG_HAVE_UINT64_T
168 /**
169 * \internal Zamienia kolejność bajtów w 64-bitowym słowie.
170 *
171 * Ze względu na little-endianowość protokołu Gadu-Gadu, na maszynach
172 * big-endianowych odwraca kolejność bajtów w słowie.
173 *
174 * \param x Liczba do zamiany
175 *
176 * \return Liczba z odpowiednią kolejnością bajtów
177 *
178 * \ingroup helper
179 */
180 uint64_t gg_fix64(uint64_t x)
181 {
182 #ifndef GG_CONFIG_BIGENDIAN
183 return x;
184 #else
185 return (uint64_t)
186 (((x & (uint64_t) 0x00000000000000ffULL) << 56) |
187 ((x & (uint64_t) 0x000000000000ff00ULL) << 40) |
188 ((x & (uint64_t) 0x0000000000ff0000ULL) << 24) |
189 ((x & (uint64_t) 0x00000000ff000000ULL) << 8) |
190 ((x & (uint64_t) 0x000000ff00000000ULL) >> 8) |
191 ((x & (uint64_t) 0x0000ff0000000000ULL) >> 24) |
192 ((x & (uint64_t) 0x00ff000000000000ULL) >> 40) |
193 ((x & (uint64_t) 0xff00000000000000ULL) >> 56));
194 #endif
195 }
196 #endif /* GG_CONFIG_HAVE_UINT64_T */
199 197
200 /** 198 /**
201 * \internal Zamienia kolejność bajtów w 32-bitowym słowie. 199 * \internal Zamienia kolejność bajtów w 32-bitowym słowie.
202 * 200 *
203 * Ze względu na little-endianowość protokołu Gadu-Gadu, na maszynach 201 * Ze względu na little-endianowość protokołu Gadu-Gadu, na maszynach
278 } 276 }
279 277
280 /** 278 /**
281 * \internal Odbiera od serwera dane binarne. 279 * \internal Odbiera od serwera dane binarne.
282 * 280 *
283 * Funkcja odbiera dane od serwera zajmując się TLS w razie konieczności. 281 * Funkcja odbiera dane od serwera zajmując się SSL/TLS w razie konieczności.
282 * Obsługuje EINTR, więc użytkownik nie musi się przejmować przerwanymi
283 * wywołaniami systemowymi.
284 * 284 *
285 * \param sess Struktura sesji 285 * \param sess Struktura sesji
286 * \param buf Bufor na danymi 286 * \param buf Bufor na danymi
287 * \param length Długość bufora 287 * \param length Długość bufora
288 * 288 *
289 * \return To samo co funkcja systemowa \c read 289 * \return To samo co funkcja systemowa \c read
290 */ 290 */
291 int gg_read(struct gg_session *sess, char *buf, int length) 291 int gg_read(struct gg_session *sess, char *buf, int length)
292 { 292 {
293 int res; 293 #ifdef GG_CONFIG_HAVE_GNUTLS
294 if (sess->ssl != NULL) {
295 for (;;) {
296 int res;
297
298 res = gnutls_record_recv(GG_SESSION_GNUTLS(sess), buf, length);
299
300 if (res < 0) {
301 if (!gnutls_error_is_fatal(res) || res == GNUTLS_E_INTERRUPTED)
302 continue;
303
304 if (res == GNUTLS_E_AGAIN)
305 errno = EAGAIN;
306 else
307 errno = EINVAL;
308
309 return -1;
310 }
311
312 return res;
313 }
314 }
315 #endif
294 316
295 #ifdef GG_CONFIG_HAVE_OPENSSL 317 #ifdef GG_CONFIG_HAVE_OPENSSL
296 if (sess->ssl) { 318 if (sess->ssl != NULL) {
297 int err; 319 for (;;) {
298 320 int res, err;
299 res = SSL_read(sess->ssl, buf, length); 321
300 322 res = SSL_read(sess->ssl, buf, length);
301 if (res < 0) { 323
302 err = SSL_get_error(sess->ssl, res); 324 if (res < 0) {
303 325 err = SSL_get_error(sess->ssl, res);
304 if (err == SSL_ERROR_WANT_READ) 326
305 errno = EAGAIN; 327 if (err == SSL_ERROR_SYSCALL && errno == EINTR)
306 328 continue;
307 return -1; 329
308 } 330 if (err == SSL_ERROR_WANT_READ)
309 } else 331 errno = EAGAIN;
332 else if (err != SSL_ERROR_SYSCALL)
333 errno = EINVAL;
334
335 return -1;
336 }
337
338 return res;
339 }
340 }
310 #endif 341 #endif
311 res = read(sess->fd, buf, length); 342
312 343 return read(sess->fd, buf, length);
313 return res;
314 } 344 }
315 345
316 /** 346 /**
317 * \internal Wysyła do serwera dane binarne. 347 * \internal Wysyła do serwera dane binarne.
318 * 348 *
319 * Funkcja wysyła dane do serwera zajmując się TLS w razie konieczności. 349 * Funkcja wysyła dane do serwera zajmując się SSL/TLS w razie konieczności.
350 * Obsługuje EINTR, więc użytkownik nie musi się przejmować przerwanymi
351 * wywołaniami systemowymi.
352 *
353 * \note Funkcja nie zajmuje się buforowaniem wysyłanych danych (patrz
354 * gg_write()).
320 * 355 *
321 * \param sess Struktura sesji 356 * \param sess Struktura sesji
322 * \param buf Bufor z danymi 357 * \param buf Bufor z danymi
323 * \param length Długość bufora 358 * \param length Długość bufora
324 * 359 *
325 * \return To samo co funkcja systemowa \c write 360 * \return To samo co funkcja systemowa \c write
326 */ 361 */
362 static int gg_write_common(struct gg_session *sess, const char *buf, int length)
363 {
364 #ifdef GG_CONFIG_HAVE_GNUTLS
365 if (sess->ssl != NULL) {
366 for (;;) {
367 int res;
368
369 res = gnutls_record_send(GG_SESSION_GNUTLS(sess), buf, length);
370
371 if (res < 0) {
372 if (!gnutls_error_is_fatal(res) || res == GNUTLS_E_INTERRUPTED)
373 continue;
374
375 if (res == GNUTLS_E_AGAIN)
376 errno = EAGAIN;
377 else
378 errno = EINVAL;
379
380 return -1;
381 }
382
383 return res;
384 }
385 }
386 #endif
387
388 #ifdef GG_CONFIG_HAVE_OPENSSL
389 if (sess->ssl != NULL) {
390 for (;;) {
391 int res, err;
392
393 res = SSL_write(sess->ssl, buf, length);
394
395 if (res < 0) {
396 err = SSL_get_error(sess->ssl, res);
397
398 if (err == SSL_ERROR_SYSCALL && errno == EINTR)
399 continue;
400
401 if (err == SSL_ERROR_WANT_WRITE)
402 errno = EAGAIN;
403 else if (err != SSL_ERROR_SYSCALL)
404 errno = EINVAL;
405
406 return -1;
407 }
408
409 return res;
410 }
411 }
412 #endif
413
414 return write(sess->fd, buf, length);
415 }
416
417
418
419 /**
420 * \internal Wysyła do serwera dane binarne.
421 *
422 * Funkcja wysyła dane do serwera zajmując się TLS w razie konieczności.
423 *
424 * \param sess Struktura sesji
425 * \param buf Bufor z danymi
426 * \param length Długość bufora
427 *
428 * \return To samo co funkcja systemowa \c write
429 */
327 int gg_write(struct gg_session *sess, const char *buf, int length) 430 int gg_write(struct gg_session *sess, const char *buf, int length)
328 { 431 {
329 int res = 0; 432 int res = 0;
330 433
331 #ifdef GG_CONFIG_HAVE_OPENSSL 434 if (!sess->async) {
332 if (sess->ssl) { 435 int written = 0;
333 int err; 436
334 437 while (written < length) {
335 res = SSL_write(sess->ssl, buf, length); 438 res = gg_write_common(sess, buf + written, length - written);
336 439
337 if (res < 0) { 440 if (res == -1)
338 err = SSL_get_error(sess->ssl, res); 441 return -1;
339 442
340 if (err == SSL_ERROR_WANT_WRITE) 443 written += res;
341 errno = EAGAIN; 444 res = written;
342 445 }
343 return -1; 446 } else {
344 } 447 res = 0;
345 } else 448
346 #endif 449 if (sess->send_buf == NULL) {
347 { 450 res = gg_write_common(sess, buf, length);
348 if (!sess->async) { 451
349 int written = 0; 452 if (res == -1)
350 453 return -1;
351 while (written < length) { 454 }
352 res = write(sess->fd, buf + written, length - written); 455
353 456 if (res < length) {
354 if (res == -1) { 457 char *tmp;
355 if (errno != EINTR) 458
356 break; 459 if (!(tmp = realloc(sess->send_buf, sess->send_left + length - res))) {
357 460 errno = ENOMEM;
358 continue; 461 return -1;
359 }
360
361 written += res;
362 res = written;
363 } 462 }
364 } else { 463
365 if (!sess->send_buf) 464 sess->send_buf = tmp;
366 res = write(sess->fd, buf, length); 465
367 else 466 memcpy(sess->send_buf + sess->send_left, buf + res, length - res);
368 res = 0; 467
369 468 sess->send_left += length - res;
370 if (res == -1) {
371 if (errno != EAGAIN)
372 return res;
373
374 res = 0;
375 }
376
377 if (res < length) {
378 char *tmp;
379
380 if (!(tmp = realloc(sess->send_buf, sess->send_left + length - res))) {
381 errno = ENOMEM;
382 return -1;
383 }
384
385 sess->send_buf = tmp;
386
387 memcpy(sess->send_buf + sess->send_left, buf + res, length - res);
388
389 sess->send_left += length - res;
390 }
391 } 469 }
392 } 470 }
393 471
394 return res; 472 return res;
395 } 473 }
441 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: connection broken\n"); 519 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: connection broken\n");
442 return NULL; 520 return NULL;
443 } 521 }
444 522
445 if (ret == -1) { 523 if (ret == -1) {
446 if (errno == EINTR) {
447 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() interrupted system call, resuming\n");
448 continue;
449 }
450
451 if (errno == EAGAIN) { 524 if (errno == EAGAIN) {
452 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() incomplete header received\n"); 525 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() incomplete header received\n");
453 526
454 if (!(sess->header_buf = malloc(sess->header_done))) { 527 if (!(sess->header_buf = malloc(sess->header_done))) {
455 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() not enough memory\n"); 528 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() header recv() not enough memory\n");
511 } 584 }
512 if (ret > -1 && ret <= size) { 585 if (ret > -1 && ret <= size) {
513 offset += ret; 586 offset += ret;
514 size -= ret; 587 size -= ret;
515 } else if (ret == -1) { 588 } else if (ret == -1) {
516 int errno2 = errno;
517
518 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed (errno=%d, %s)\n", errno, strerror(errno)); 589 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed (errno=%d, %s)\n", errno, strerror(errno));
519 errno = errno2;
520 590
521 if (errno == EAGAIN) { 591 if (errno == EAGAIN) {
522 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() %d bytes received, %d left\n", offset, size); 592 gg_debug_session(sess, GG_DEBUG_MISC, "// gg_recv_packet() %d bytes received, %d left\n", offset, size);
523 sess->recv_buf = buf; 593 sess->recv_buf = buf;
524 sess->recv_left = size; 594 sess->recv_left = size;
525 sess->recv_done = offset; 595 sess->recv_done = offset;
526 return NULL; 596 return NULL;
527 } 597 }
528 if (errno != EINTR) { 598
529 free(buf); 599 free(buf);
530 return NULL; 600 return NULL;
531 }
532 } 601 }
533 } 602 }
534 603
535 sess->recv_left = 0; 604 sess->recv_left = 0;
536 605
537 if ((gg_debug_level & GG_DEBUG_DUMP)) { 606 gg_debug_session(sess, GG_DEBUG_DUMP, "// gg_recv_packet(type=0x%.2x, length=%d)\n", h.type, h.length);
538 unsigned int i; 607 gg_debug_dump(sess, GG_DEBUG_DUMP, buf, sizeof(h) + h.length);
539
540 gg_debug_session(sess, GG_DEBUG_DUMP, "// gg_recv_packet(%.2x)", h.type);
541 for (i = 0; i < sizeof(h) + h.length; i++)
542 gg_debug_session(sess, GG_DEBUG_DUMP, " %.2x", (unsigned char) buf[i]);
543 gg_debug_session(sess, GG_DEBUG_DUMP, "\n");
544 }
545 608
546 return buf; 609 return buf;
547 } 610 }
548 611
549 /** 612 /**
607 670
608 h = (struct gg_header*) tmp; 671 h = (struct gg_header*) tmp;
609 h->type = gg_fix32(type); 672 h->type = gg_fix32(type);
610 h->length = gg_fix32(tmp_length - sizeof(struct gg_header)); 673 h->length = gg_fix32(tmp_length - sizeof(struct gg_header));
611 674
612 if ((gg_debug_level & GG_DEBUG_DUMP)) { 675 gg_debug_session(sess, GG_DEBUG_DUMP, "// gg_send_packet(type=0x%.2x, length=%d)\n", gg_fix32(h->type), gg_fix32(h->length));
613 unsigned int i; 676 gg_debug_dump(sess, GG_DEBUG_DUMP, tmp, tmp_length);
614
615 gg_debug_session(sess, GG_DEBUG_DUMP, "// gg_send_packet(0x%.2x)", gg_fix32(h->type));
616 for (i = 0; i < tmp_length; ++i)
617 gg_debug_session(sess, GG_DEBUG_DUMP, " %.2x", (unsigned char) tmp[i]);
618 gg_debug_session(sess, GG_DEBUG_DUMP, "\n");
619 }
620 677
621 res = gg_write(sess, tmp, tmp_length); 678 res = gg_write(sess, tmp, tmp_length);
622 679
623 free(tmp); 680 free(tmp);
624 681
737 sess->destroy = gg_free_session; 794 sess->destroy = gg_free_session;
738 sess->port = (p->server_port) ? p->server_port : ((gg_proxy_enabled) ? GG_HTTPS_PORT : GG_DEFAULT_PORT); 795 sess->port = (p->server_port) ? p->server_port : ((gg_proxy_enabled) ? GG_HTTPS_PORT : GG_DEFAULT_PORT);
739 sess->server_addr = p->server_addr; 796 sess->server_addr = p->server_addr;
740 sess->external_port = p->external_port; 797 sess->external_port = p->external_port;
741 sess->external_addr = p->external_addr; 798 sess->external_addr = p->external_addr;
742 799 sess->client_port = p->client_port;
743 sess->protocol_features = (p->protocol_features & ~(GG_FEATURE_STATUS77 | GG_FEATURE_MSG77)); 800
744 801 if (p->protocol_features == 0) {
745 if (!(p->protocol_features & GG_FEATURE_STATUS77)) 802 sess->protocol_features = GG_FEATURE_MSG80 | GG_FEATURE_STATUS80 | GG_FEATURE_DND_FFC | GG_FEATURE_IMAGE_DESCR | GG_FEATURE_UNKNOWN_100 | GG_FEATURE_USER_DATA | GG_FEATURE_MSG_ACK | GG_FEATURE_TYPING_NOTIFICATION;
746 sess->protocol_features |= GG_FEATURE_STATUS80; 803 } else {
747 804 sess->protocol_features = (p->protocol_features & ~(GG_FEATURE_STATUS77 | GG_FEATURE_MSG77));
748 if (!(p->protocol_features & GG_FEATURE_MSG77)) 805
749 sess->protocol_features |= GG_FEATURE_MSG80; 806 if (!(p->protocol_features & GG_FEATURE_STATUS77))
807 sess->protocol_features |= GG_FEATURE_STATUS80;
808
809 if (!(p->protocol_features & GG_FEATURE_MSG77))
810 sess->protocol_features |= GG_FEATURE_MSG80;
811 }
812
813 if (!(sess->status_flags = p->status_flags))
814 sess->status_flags = GG_STATUS_FLAG_UNKNOWN | GG_STATUS_FLAG_SPAM;
750 815
751 sess->protocol_version = (p->protocol_version) ? p->protocol_version : GG_DEFAULT_PROTOCOL_VERSION; 816 sess->protocol_version = (p->protocol_version) ? p->protocol_version : GG_DEFAULT_PROTOCOL_VERSION;
752 817
753 if (p->era_omnix) 818 if (p->era_omnix)
754 sess->protocol_flags |= GG_ERA_OMNIX_MASK; 819 sess->protocol_flags |= GG_ERA_OMNIX_MASK;
772 if (sess->protocol_version >= 0x2d) 837 if (sess->protocol_version >= 0x2d)
773 max_length = GG_STATUS_DESCR_MAXSIZE; 838 max_length = GG_STATUS_DESCR_MAXSIZE;
774 else 839 else
775 max_length = GG_STATUS_DESCR_MAXSIZE_PRE_8_0; 840 max_length = GG_STATUS_DESCR_MAXSIZE_PRE_8_0;
776 841
777 if (sess->protocol_version >= 0x2d && p->encoding != GG_ENCODING_UTF8) 842 if (sess->protocol_version >= 0x2d)
778 sess->initial_descr = gg_cp_to_utf8(p->status_descr); 843 sess->initial_descr = gg_encoding_convert(p->status_descr, p->encoding, GG_ENCODING_UTF8, -1, -1);
779 else 844 else
780 sess->initial_descr = strdup(p->status_descr); 845 sess->initial_descr = strdup(p->status_descr);
781 846
782 if (!sess->initial_descr) { 847 if (!sess->initial_descr) {
783 gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for status\n"); 848 gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for status\n");
789 if (strlen(sess->initial_descr) > max_length) 854 if (strlen(sess->initial_descr) > max_length)
790 sess->initial_descr[max_length] = 0; 855 sess->initial_descr[max_length] = 0;
791 } 856 }
792 857
793 if (p->tls == 1) { 858 if (p->tls == 1) {
794 #ifdef GG_CONFIG_HAVE_OPENSSL 859 #ifdef GG_CONFIG_HAVE_GNUTLS
860 gg_session_gnutls_t *tmp;
861
862 tmp = malloc(sizeof(gg_session_gnutls_t));
863
864 if (tmp == NULL) {
865 gg_debug(GG_DEBUG_MISC, "// gg_login() out of memory for GnuTLS session\n");
866 goto fail;
867 }
868
869 sess->ssl = tmp;
870
871 gnutls_global_init();
872 gnutls_certificate_allocate_credentials(&tmp->xcred);
873 gnutls_init(&tmp->session, GNUTLS_CLIENT);
874 gnutls_priority_set_direct(tmp->session, "NORMAL:-VERS-TLS", NULL);
875 // gnutls_priority_set_direct(tmp->session, "NONE:+VERS-SSL3.0:+AES-128-CBC:+RSA:+SHA1:+COMP-NULL", NULL);
876 gnutls_credentials_set(tmp->session, GNUTLS_CRD_CERTIFICATE, tmp->xcred);
877 #elif defined(GG_CONFIG_HAVE_OPENSSL)
795 char buf[1024]; 878 char buf[1024];
796 879
797 OpenSSL_add_ssl_algorithms(); 880 OpenSSL_add_ssl_algorithms();
798 881
799 if (!RAND_status()) { 882 if (!RAND_status()) {
808 891
809 RAND_seed((void *) rdata, sizeof(rdata)); 892 RAND_seed((void *) rdata, sizeof(rdata));
810 RAND_seed((void *) &rstruct, sizeof(rstruct)); 893 RAND_seed((void *) &rstruct, sizeof(rstruct));
811 } 894 }
812 895
813 sess->ssl_ctx = SSL_CTX_new(TLSv1_client_method()); 896 sess->ssl_ctx = SSL_CTX_new(SSLv3_client_method());
814 897
815 if (!sess->ssl_ctx) { 898 if (!sess->ssl_ctx) {
816 ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); 899 ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
817 gg_debug(GG_DEBUG_MISC, "// gg_login() SSL_CTX_new() failed: %s\n", buf); 900 gg_debug(GG_DEBUG_MISC, "// gg_login() SSL_CTX_new() failed: %s\n", buf);
818 goto fail; 901 goto fail;
848 if (!p->async) { 931 if (!p->async) {
849 struct in_addr addr; 932 struct in_addr addr;
850 933
851 if (!sess->server_addr) { 934 if (!sess->server_addr) {
852 if ((addr.s_addr = inet_addr(hostname)) == INADDR_NONE) { 935 if ((addr.s_addr = inet_addr(hostname)) == INADDR_NONE) {
853 if (gg_gethostbyname_real(hostname, &addr, 0) == -1) { 936 struct in_addr *addr_list = NULL;
937 int addr_count;
938
939 if (gg_gethostbyname_real(hostname, &addr_list, &addr_count, 0) == -1 || addr_count == 0) {
854 gg_debug(GG_DEBUG_MISC, "// gg_login() host \"%s\" not found\n", hostname); 940 gg_debug(GG_DEBUG_MISC, "// gg_login() host \"%s\" not found\n", hostname);
941 free(addr_list);
855 goto fail; 942 goto fail;
856 } 943 }
944
945 addr = addr_list[0];
946
947 free(addr_list);
857 } 948 }
858 } else { 949 } else {
859 addr.s_addr = sess->server_addr; 950 addr.s_addr = sess->server_addr;
860 port = sess->port; 951 port = sess->port;
861 } 952 }
974 * wcześniej wywołać funkcję \c gg_change_status_descr() lub 1065 * wcześniej wywołać funkcję \c gg_change_status_descr() lub
975 * \c gg_change_status_descr_time(). 1066 * \c gg_change_status_descr_time().
976 * 1067 *
977 * \note Jeśli w buforze nadawczym połączenia z serwerem znajdują się jeszcze 1068 * \note Jeśli w buforze nadawczym połączenia z serwerem znajdują się jeszcze
978 * dane (np. z powodu strat pakietów na łączu), prawdopodobnie zostaną one 1069 * dane (np. z powodu strat pakietów na łączu), prawdopodobnie zostaną one
979 * utracone przy zrywaniu połączenia. 1070 * utracone przy zrywaniu połączenia. Aby mieć pewność, że opis statusu
1071 * zostanie zachowany, należy ustawić stan \c GG_STATUS_NOT_AVAIL_DESCR
1072 * za pomocą funkcji \c gg_change_status_descr() i poczekać na zdarzenie
1073 * \c GG_EVENT_DISCONNECT_ACK.
980 * 1074 *
981 * \param sess Struktura sesji 1075 * \param sess Struktura sesji
982 * 1076 *
983 * \ingroup login 1077 * \ingroup login
984 */ 1078 */
987 if (!sess) 1081 if (!sess)
988 return; 1082 return;
989 1083
990 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_logoff(%p);\n", sess); 1084 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_logoff(%p);\n", sess);
991 1085
992 if (GG_S_NA(sess->status)) 1086 #ifdef GG_CONFIG_HAVE_GNUTLS
993 gg_change_status(sess, GG_STATUS_NOT_AVAIL); 1087 if (sess->ssl != NULL)
1088 gnutls_bye(GG_SESSION_GNUTLS(sess), GNUTLS_SHUT_RDWR);
1089 #endif
994 1090
995 #ifdef GG_CONFIG_HAVE_OPENSSL 1091 #ifdef GG_CONFIG_HAVE_OPENSSL
996 if (sess->ssl) 1092 if (sess->ssl != NULL)
997 SSL_shutdown(sess->ssl); 1093 SSL_shutdown(sess->ssl);
998 #endif 1094 #endif
999 1095
1000 sess->resolver_cleanup(&sess->resolver, 1); 1096 sess->resolver_cleanup(&sess->resolver, 1);
1001 1097
1002 if (sess->fd != -1) { 1098 if (sess->fd != -1) {
1003 shutdown(sess->fd, SHUT_RDWR); 1099 shutdown(sess->fd, SHUT_RDWR);
1004 close(sess->fd); 1100 close(sess->fd);
1005 sess->fd = -1; 1101 sess->fd = -1;
1006 } 1102 }
1103
1104 #ifdef GG_CONFIG_HAVE_GNUTLS
1105 if (sess->ssl != NULL) {
1106 gg_session_gnutls_t *tmp;
1107
1108 tmp = (gg_session_gnutls_t*) sess->ssl;
1109 gnutls_deinit(tmp->session);
1110 gnutls_certificate_free_credentials(tmp->xcred);
1111 gnutls_global_deinit();
1112 free(sess->ssl);
1113 }
1114 #endif
1007 1115
1008 if (sess->send_buf) { 1116 if (sess->send_buf) {
1009 free(sess->send_buf); 1117 free(sess->send_buf);
1010 sess->send_buf = NULL; 1118 sess->send_buf = NULL;
1011 sess->send_left = 0; 1119 sess->send_left = 0;
1101 1209
1102 sess->status = status; 1210 sess->status = status;
1103 1211
1104 if (sess->protocol_version >= 0x2d) { 1212 if (sess->protocol_version >= 0x2d) {
1105 if (descr != NULL && sess->encoding != GG_ENCODING_UTF8) { 1213 if (descr != NULL && sess->encoding != GG_ENCODING_UTF8) {
1106 new_descr = gg_cp_to_utf8(descr); 1214 new_descr = gg_encoding_convert(descr, GG_ENCODING_CP1250, GG_ENCODING_UTF8, -1, -1);
1107 1215
1108 if (!new_descr) 1216 if (!new_descr)
1109 return -1; 1217 return -1;
1110 } 1218 }
1111 1219
1138 1246
1139 if (packet_type == GG_NEW_STATUS80) { 1247 if (packet_type == GG_NEW_STATUS80) {
1140 struct gg_new_status80 p; 1248 struct gg_new_status80 p;
1141 1249
1142 p.status = gg_fix32(status); 1250 p.status = gg_fix32(status);
1143 p.flags = gg_fix32(0x00800001); 1251 p.flags = gg_fix32(sess->status_flags);
1144 p.description_size = gg_fix32(descr_len); 1252 p.description_size = gg_fix32(descr_len);
1145 res = gg_send_packet(sess, 1253 res = gg_send_packet(sess,
1146 packet_type, 1254 packet_type,
1147 &p, 1255 &p,
1148 sizeof(p), 1256 sizeof(p),
1166 (time) ? sizeof(new_time) : 0, 1274 (time) ? sizeof(new_time) : 0,
1167 NULL); 1275 NULL);
1168 } 1276 }
1169 1277
1170 free(new_descr); 1278 free(new_descr);
1279
1280 if (GG_S_NA(status))
1281 sess->state = GG_STATE_DISCONNECTING;
1282
1171 return res; 1283 return res;
1172 } 1284 }
1173 1285
1174 #endif /* DOXYGEN */ 1286 #endif /* DOXYGEN */
1175 1287
1223 int gg_change_status_descr_time(struct gg_session *sess, int status, const char *descr, int time) 1335 int gg_change_status_descr_time(struct gg_session *sess, int status, const char *descr, int time)
1224 { 1336 {
1225 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_change_status_descr_time(%p, %d, \"%s\", %d);\n", sess, status, descr, time); 1337 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_change_status_descr_time(%p, %d, \"%s\", %d);\n", sess, status, descr, time);
1226 1338
1227 return gg_change_status_common(sess, status, descr, time); 1339 return gg_change_status_common(sess, status, descr, time);
1340 }
1341
1342 /**
1343 * Funkcja zmieniająca flagi statusu.
1344 *
1345 * \param sess Struktura sesji
1346 * \param flags Nowe flagi statusu
1347 *
1348 * \return 0 jeśli się powiodło, -1 w przypadku błędu
1349 *
1350 * \note Aby zmiany weszły w życie, należy ponownie ustawić status za pomocą
1351 * funkcji z rodziny \c gg_change_status().
1352 *
1353 * \ingroup status
1354 */
1355 int gg_change_status_flags(struct gg_session *sess, int flags)
1356 {
1357 gg_debug_session(sess, GG_DEBUG_FUNCTION, "** gg_change_status_flags(%p, 0x%08x);\n", sess, flags);
1358
1359 if (sess == NULL) {
1360 errno = EFAULT;
1361 return -1;
1362 }
1363
1364 sess->status_flags = flags;
1365
1366 return 0;
1228 } 1367 }
1229 1368
1230 /** 1369 /**
1231 * Wysyła wiadomość do użytkownika. 1370 * Wysyła wiadomość do użytkownika.
1232 * 1371 *
1375 if (src[i] == 0) 1514 if (src[i] == 0)
1376 attr &= ~(GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR); 1515 attr &= ~(GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR);
1377 1516
1378 format_idx += 3; 1517 format_idx += 3;
1379 1518
1380 if ((attr & (GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR)) != 0) { 1519 if ((attr & (GG_FONT_BOLD | GG_FONT_ITALIC | GG_FONT_UNDERLINE | GG_FONT_COLOR)) != 0 || (attr == 0 && old_attr != 0)) {
1381 if (char_pos != 0) { 1520 if (char_pos != 0) {
1382 if ((old_attr & GG_FONT_UNDERLINE) != 0) 1521 if ((old_attr & GG_FONT_UNDERLINE) != 0)
1383 gg_append(dst, &len, "</u>", 4); 1522 gg_append(dst, &len, "</u>", 4);
1384 1523
1385 if ((old_attr & GG_FONT_ITALIC) != 0) 1524 if ((old_attr & GG_FONT_ITALIC) != 0)
1386 gg_append(dst, &len, "</i>", 4); 1525 gg_append(dst, &len, "</i>", 4);
1387 1526
1388 if ((old_attr & GG_FONT_BOLD) != 0) 1527 if ((old_attr & GG_FONT_BOLD) != 0)
1389 gg_append(dst, &len, "</b>", 4); 1528 gg_append(dst, &len, "</b>", 4);
1390 1529
1391 gg_append(dst, &len, "</span>", 7); 1530 if (src[i] != 0)
1531 gg_append(dst, &len, "</span>", 7);
1392 } 1532 }
1393 1533
1394 if (((attr & GG_FONT_COLOR) != 0) && (format_idx + 3 <= format_len)) { 1534 if (((attr & GG_FONT_COLOR) != 0) && (format_idx + 3 <= format_len)) {
1395 color = &format[format_idx]; 1535 color = &format[format_idx];
1396 format_idx += 3; 1536 format_idx += 3;
1397 } else { 1537 } else {
1398 color = (const unsigned char*) "\x00\x00\x00"; 1538 color = (const unsigned char*) "\x00\x00\x00";
1399 } 1539 }
1400 1540
1401 if (dst != NULL) 1541 if (src[i] != 0) {
1402 sprintf(&dst[len], span_fmt, color[0], color[1], color[2]); 1542 if (dst != NULL)
1403 len += span_len; 1543 sprintf(&dst[len], span_fmt, color[0], color[1], color[2]);
1544 len += span_len;
1545 }
1404 } else if (char_pos == 0 && src[0] != 0) { 1546 } else if (char_pos == 0 && src[0] != 0) {
1405 if (dst != NULL) 1547 if (dst != NULL)
1406 sprintf(&dst[len], span_fmt, 0, 0, 0); 1548 sprintf(&dst[len], span_fmt, 0, 0, 0);
1407 len += span_len; 1549 len += span_len;
1408 } 1550 }
1541 errno = EINVAL; 1683 errno = EINVAL;
1542 return -1; 1684 return -1;
1543 } 1685 }
1544 1686
1545 if (sess->encoding == GG_ENCODING_UTF8) { 1687 if (sess->encoding == GG_ENCODING_UTF8) {
1546 if (!(cp_msg = gg_utf8_to_cp((const char *) message))) 1688 if (!(cp_msg = gg_encoding_convert((const char *) message, GG_ENCODING_UTF8, GG_ENCODING_CP1250, -1, -1)))
1547 return -1; 1689 return -1;
1548 1690
1549 utf_msg = (char*) message; 1691 utf_msg = (char*) message;
1550 } else { 1692 } else {
1551 if (sess->protocol_version >= 0x2d) { 1693 if (sess->protocol_version >= 0x2d) {
1552 if (!(utf_msg = gg_cp_to_utf8((const char *) message))) 1694 if (!(utf_msg = gg_encoding_convert((const char *) message, GG_ENCODING_CP1250, GG_ENCODING_UTF8, -1, -1)))
1553 return -1; 1695 return -1;
1554 } 1696 }
1555 1697
1556 cp_msg = (char*) message; 1698 cp_msg = (char*) message;
1557 } 1699 }
2190 sess->userlist_blocks++; 2332 sess->userlist_blocks++;
2191 2333
2192 return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), request, len, NULL); 2334 return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), request, len, NULL);
2193 } 2335 }
2194 2336
2337 /**
2338 * Informuje rozmówcę o pisaniu wiadomości.
2339 *
2340 * \param sess Struktura sesji
2341 * \param recipient Numer adresata
2342 * \param length Długość wiadomości lub 0 jeśli jest pusta
2343 *
2344 * \return 0 jeśli się powiodło, -1 w przypadku błędu
2345 *
2346 * \ingroup messages
2347 */
2348 int gg_typing_notification(struct gg_session *sess, uin_t recipient, int length){
2349 struct gg_typing_notification pkt;
2350 uin_t uin;
2351
2352 pkt.length = gg_fix16(length);
2353 uin = gg_fix32(recipient);
2354 memcpy(&pkt.uin, &uin, sizeof(uin_t));
2355
2356 return gg_send_packet(sess, GG_TYPING_NOTIFICATION, &pkt, sizeof(pkt), NULL);
2357 }
2358
2359 /**
2360 * Rozłącza inną sesję multilogowania.
2361 *
2362 * \param gs Struktura sesji
2363 * \param conn_id Sesja do rozłączenia
2364 *
2365 * \return 0 jeśli się powiodło, -1 w przypadku błędu
2366 *
2367 * \ingroup login
2368 */
2369 int gg_multilogon_disconnect(struct gg_session *gs, gg_multilogon_id_t conn_id)
2370 {
2371 struct gg_multilogon_disconnect pkt;
2372
2373 pkt.conn_id = conn_id;
2374
2375 return gg_send_packet(gs, GG_MULTILOGON_DISCONNECT, &pkt, sizeof(pkt), NULL);
2376 }
2377
2195 /* @} */ 2378 /* @} */
2196 2379
2197 /* 2380 /*
2198 * Local variables: 2381 * Local variables:
2199 * c-indentation-style: k&r 2382 * c-indentation-style: k&r