1 /* $Id: libgadu.c,v 1.2 2004/03/30 22:44:07 konst Exp $ */
4 * (C) Copyright 2001-2003 Wojtek Kaniewski <wojtekka@irc.pl>
5 * Robert J. Wo¼ny <speedy@ziew.org>
6 * Arkadiusz Mi¶kiewicz <misiek@pld.org.pl>
7 * Tomasz Chiliñski <chilek@chilan.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License Version
11 * 2.1 as published by the Free Software Foundation.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
29 # include <sys/filio.h>
32 #include "libgadu-config.h"
36 #ifdef __GG_LIBGADU_HAVE_PTHREAD
45 #define OPENSSL_NO_KRB5 1
46 # include <openssl/err.h>
47 # include <openssl/rand.h>
49 #include <gnutls/gnutls.h>
55 int gg_debug_level
= 0;
56 void (*gg_debug_handler
)(int level
, const char *format
, va_list ap
) = NULL
;
59 unsigned long gg_dcc_ip
= 0;
62 * zmienne opisuj±ce parametry proxy http.
64 char *gg_proxy_host
= NULL
;
65 int gg_proxy_port
= 0;
66 int gg_proxy_enabled
= 0;
67 int gg_proxy_http_only
= 0;
68 char *gg_proxy_username
= NULL
;
69 char *gg_proxy_password
= NULL
;
74 __attribute__ ((unused
))
76 = "$Id: libgadu.c,v 1.2 2004/03/30 22:44:07 konst Exp $";
80 * gg_libgadu_version()
82 * zwraca wersjê libgadu.
88 const char *gg_libgadu_version()
90 return GG_LIBGADU_VERSION
;
96 * zamienia kolejno¶æ bajtów w liczbie 32-bitowej tak, by odpowiada³a
97 * kolejno¶ci bajtów w protokole GG. ze wzglêdu na LE-owo¶æ serwera,
98 * zamienia tylko na maszynach BE-wych.
100 * - x - liczba do zamiany
102 * liczba z odpowiedni± kolejno¶ci± bajtów.
104 uint32_t gg_fix32(uint32_t x
)
106 #ifndef __GG_LIBGADU_BIGENDIAN
110 (((x
& (uint32_t) 0x000000ffU
) << 24) |
111 ((x
& (uint32_t) 0x0000ff00U
) << 8) |
112 ((x
& (uint32_t) 0x00ff0000U
) >> 8) |
113 ((x
& (uint32_t) 0xff000000U
) >> 24));
120 * zamienia kolejno¶æ bajtów w liczbie 16-bitowej tak, by odpowiada³a
121 * kolejno¶ci bajtów w protokole GG. ze wzglêdu na LE-owo¶æ serwera,
122 * zamienia tylko na maszynach BE-wych.
124 * - x - liczba do zamiany
126 * liczba z odpowiedni± kolejno¶ci± bajtów.
128 uint16_t gg_fix16(uint16_t x
)
130 #ifndef __GG_LIBGADU_BIGENDIAN
134 (((x
& (uint16_t) 0x00ffU
) << 8) |
135 ((x
& (uint16_t) 0xff00U
) >> 8));
140 * gg_login_hash() // funkcja wewnêtrzna
142 * liczy hash z has³a i danego seeda.
144 * - password - has³o do hashowania
145 * - seed - warto¶æ podana przez serwer
149 unsigned int gg_login_hash(const unsigned char *password
, unsigned int seed
)
151 unsigned int x
, y
, z
;
155 for (x
= 0; *password
; password
++) {
156 x
= (x
& 0xffffff00) | *password
;
167 y
= (y
<< z
) | (y
>> (32 - z
));
174 * gg_resolve() // funkcja wewnêtrzna
176 * tworzy potok, forkuje siê i w drugim procesie zaczyna resolvowaæ
177 * podanego hosta. zapisuje w sesji deskryptor potoku. je¶li co¶ tam
178 * bêdzie gotowego, znaczy, ¿e mo¿na wczytaæ struct in_addr. je¶li
179 * nie znajdzie, zwraca INADDR_NONE.
181 * - fd - wska¼nik gdzie wrzuciæ deskryptor
182 * - pid - gdzie wrzuciæ pid procesu potomnego
183 * - hostname - nazwa hosta do zresolvowania
187 int gg_resolve(int *fd
, int *pid
, const char *hostname
)
192 gg_debug(GG_DEBUG_FUNCTION
, "** gg_resolve(%p, %p, \"%s\");\n", fd
, pid
, hostname
);
199 if (pipe(pipes
) == -1)
202 if ((res
= fork()) == -1)
206 if ((a
.s_addr
= inet_addr(hostname
)) == INADDR_NONE
) {
209 if (!(he
= gg_gethostbyname(hostname
)))
210 a
.s_addr
= INADDR_NONE
;
212 memcpy((char*) &a
, he
->h_addr
, sizeof(a
));
217 write(pipes
[1], &a
, sizeof(a
));
230 #ifdef __GG_LIBGADU_HAVE_PTHREAD
232 struct gg_resolve_pthread_data
{
237 static void *gg_resolve_pthread_thread(void *arg
)
239 struct gg_resolve_pthread_data
*d
= arg
;
242 if ((a
.s_addr
= inet_addr(d
->hostname
)) == INADDR_NONE
) {
245 if (!(he
= gg_gethostbyname(d
->hostname
)))
246 a
.s_addr
= INADDR_NONE
;
248 memcpy((char*) &a
, he
->h_addr
, sizeof(a
));
253 write(d
->fd
, &a
, sizeof(a
));
263 return NULL
; /* ¿eby kompilator nie marudzi³ */
267 * gg_resolve_pthread() // funkcja wewnêtrzna
269 * tworzy potok, nowy w±tek i w nim zaczyna resolvowaæ podanego hosta.
270 * zapisuje w sesji deskryptor potoku. je¶li co¶ tam bêdzie gotowego,
271 * znaczy, ¿e mo¿na wczytaæ struct in_addr. je¶li nie znajdzie, zwraca
274 * - fd - wska¼nik do zmiennej przechowuj±cej desktyptor resolvera
275 * - resolver - wska¼nik do wska¼nika resolvera
276 * - hostname - nazwa hosta do zresolvowania
280 int gg_resolve_pthread(int *fd
, void **resolver
, const char *hostname
)
282 struct gg_resolve_pthread_data
*d
;
286 gg_debug(GG_DEBUG_FUNCTION
, "** gg_resolve_pthread(%p, %p, \"%s\");\n", fd
, resolver
, hostname
);
288 if (!resolver
|| !fd
|| !hostname
) {
289 gg_debug(GG_DEBUG_MISC
, "// gg_resolve_pthread() invalid arguments\n");
294 if (!(tmp
= malloc(sizeof(pthread_t
)))) {
295 gg_debug(GG_DEBUG_MISC
, "// gg_resolve_pthread() out of memory for pthread id\n");
299 if (pipe(pipes
) == -1) {
300 gg_debug(GG_DEBUG_MISC
, "// gg_resolve_pthread() unable to create pipes (errno=%d, %s)\n", errno
, strerror(errno
));
305 if (!(d
= malloc(sizeof(*d
))) || !(d
->hostname
= strdup(hostname
))) {
306 gg_debug(GG_DEBUG_MISC
, "// gg_resolve_pthread() out of memory\n");
313 if (pthread_create(tmp
, NULL
, gg_resolve_pthread_thread
, d
)) {
314 gg_debug(GG_DEBUG_MISC
, "// gg_resolve_phread() unable to create thread\n");
321 gg_debug(GG_DEBUG_MISC
, "// gg_resolve_pthread() %p\n", tmp
);
333 * gg_read() // funkcja pomocnicza
335 * czyta z gniazda okre¶lon± ilo¶æ bajtów. bierze pod uwagê, czy mamy
336 * po³±czenie zwyk³e czy TLS.
340 * - length - ilo¶æ bajtów,
342 * takie same warto¶ci jak read().
344 int gg_read(struct gg_session
*sess
, char *buf
, int length
)
352 res
= SSL_read(sess
->ssl
, buf
, length
);
355 err
= SSL_get_error(sess
->ssl
, res
);
357 if (err
== SSL_ERROR_WANT_READ
)
366 res
= gnutls_record_recv(sess
->session
, buf
, length
);
367 } while ( res
< 0 && (res
== GNUTLS_E_INTERRUPTED
|| res
== GNUTLS_E_AGAIN
) );
370 res
= read(sess
->fd
, buf
, length
);
376 * gg_write() // funkcja pomocnicza
378 * zapisuje do gniazda okre¶lon± ilo¶æ bajtów. bierze pod uwagê, czy mamy
379 * po³±czenie zwyk³e czy TLS.
383 * - length - ilo¶æ bajtów,
385 * takie same warto¶ci jak write().
387 int gg_write(struct gg_session
*sess
, const char *buf
, int length
)
395 res
= SSL_write(sess
->ssl
, buf
, length
);
398 err
= SSL_get_error(sess
->ssl
, res
);
400 if (err
== SSL_ERROR_WANT_WRITE
)
408 if(res
= gnutls_record_send( sess
->session
, buf
, length
) < 0)
409 fprintf(stderr
,"Can't write to server");
412 res
= write(sess
->fd
, buf
, length
);
418 * gg_recv_packet() // funkcja wewnêtrzna
420 * odbiera jeden pakiet i zwraca wska¼nik do niego. pamiêæ po nim
421 * nale¿y zwolniæ za pomoc± free().
423 * - sess - opis sesji
425 * w przypadku b³êdu NULL, kod b³êdu w errno.
427 void *gg_recv_packet(struct gg_session
*sess
)
432 unsigned int offset
, size
= 0;
434 gg_debug(GG_DEBUG_FUNCTION
, "** gg_recv_packet(%p);\n", sess
);
441 if (sess
->recv_left
< 1) {
442 if (sess
->header_buf
) {
443 memcpy(&h
, sess
->header_buf
, sess
->header_done
);
444 gg_debug(GG_DEBUG_MISC
, "// gg_recv_packet() header recv: resuming last read (%d bytes left)\n", sizeof(h
) - sess
->header_done
);
445 free(sess
->header_buf
);
446 sess
->header_buf
= NULL
;
448 sess
->header_done
= 0;
450 while (sess
->header_done
< sizeof(h
)) {
451 ret
= gg_read(sess
, (char*) &h
+ sess
->header_done
, sizeof(h
) - sess
->header_done
);
453 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
);
456 gg_debug(GG_DEBUG_MISC
, "// gg_recv_packet() header recv() failed: connection broken\n");
461 if (errno
== EINTR
) {
462 gg_debug(GG_DEBUG_MISC
, "// gg_recv_packet() header recv() interrupted system call, resuming\n");
466 if (errno
== EAGAIN
) {
467 gg_debug(GG_DEBUG_MISC
, "// gg_recv_packet() header recv() incomplete header received\n");
469 if (!(sess
->header_buf
= malloc(sess
->header_done
))) {
470 gg_debug(GG_DEBUG_MISC
, "// gg_recv_packet() header recv() not enough memory\n");
474 memcpy(sess
->header_buf
, &h
, sess
->header_done
);
479 gg_debug(GG_DEBUG_MISC
, "// gg_recv_packet() header recv() failed: errno=%d, %s\n", errno
, strerror(errno
));
484 sess
->header_done
+= ret
;
488 h
.type
= gg_fix32(h
.type
);
489 h
.length
= gg_fix32(h
.length
);
491 memcpy(&h
, sess
->recv_buf
, sizeof(h
));
493 /* jakie¶ sensowne limity na rozmiar pakietu */
494 if (h
.length
> 65535) {
495 gg_debug(GG_DEBUG_MISC
, "// gg_recv_packet() invalid packet length (%d)\n", h
.length
);
500 if (sess
->recv_left
> 0) {
501 gg_debug(GG_DEBUG_MISC
, "// gg_recv_packet() resuming last gg_recv_packet()\n");
502 size
= sess
->recv_left
;
503 offset
= sess
->recv_done
;
504 buf
= sess
->recv_buf
;
506 if (!(buf
= malloc(sizeof(h
) + h
.length
+ 1))) {
507 gg_debug(GG_DEBUG_MISC
, "// gg_recv_packet() not enough memory for packet data\n");
511 memcpy(buf
, &h
, sizeof(h
));
518 ret
= gg_read(sess
, buf
+ sizeof(h
) + offset
, size
);
519 gg_debug(GG_DEBUG_MISC
, "// gg_recv_packet() body recv(%d,%p,%d) = %d\n", sess
->fd
, buf
+ sizeof(h
) + offset
, size
, ret
);
521 gg_debug(GG_DEBUG_MISC
, "// gg_recv_packet() failed: connection broken\n");
525 if (ret
> -1 && ret
<= size
) {
528 } else if (ret
== -1) {
530 gg_debug(GG_DEBUG_MISC
, "// gg_recv_packet() body recv() failed (errno=%d, %s)\n", errno
, strerror(errno
));
532 if (errno
== EAGAIN
) {
533 gg_debug(GG_DEBUG_MISC
, "// gg_recv_packet() %d bytes received, %d left\n", offset
, size
);
534 sess
->recv_buf
= buf
;
535 sess
->recv_left
= size
;
536 sess
->recv_done
= offset
;
539 if (errno
!= EINTR
) {
548 if ((gg_debug_level
& GG_DEBUG_DUMP
)) {
551 gg_debug(GG_DEBUG_DUMP
, "// gg_recv_packet(%.2x)", h
.type
);
552 for (i
= 0; i
< sizeof(h
) + h
.length
; i
++)
553 gg_debug(GG_DEBUG_DUMP
, " %.2x", (unsigned char) buf
[i
]);
554 gg_debug(GG_DEBUG_DUMP
, "\n");
561 * gg_send_packet() // funkcja wewnêtrzna
563 * konstruuje pakiet i wysy³a go do serwera.
565 * - sock - deskryptor gniazda
566 * - type - typ pakietu
567 * - payload_1 - pierwsza czê¶æ pakietu
568 * - payload_length_1 - d³ugo¶æ pierwszej czê¶ci
569 * - payload_2 - druga czê¶æ pakietu
570 * - payload_length_2 - d³ugo¶æ drugiej czê¶ci
571 * - ... - kolejne czê¶ci pakietu i ich d³ugo¶ci
572 * - NULL - koñcowym parametr (konieczny!)
574 * je¶li siê powiod³o, zwraca 0, w przypadku b³êdu -1. je¶li errno == ENOMEM,
575 * zabrak³o pamiêci. inaczej by³ b³±d przy wysy³aniu pakietu. dla errno == 0
576 * nie wys³ano ca³ego pakietu.
578 int gg_send_packet(struct gg_session
*sess
, int type
, ...)
582 unsigned int tmp_length
;
584 unsigned int payload_length
;
588 gg_debug(GG_DEBUG_FUNCTION
, "** gg_send_packet(%p, 0x%.2x, ...)\n", sess
, type
);
592 if (!(tmp
= malloc(sizeof(struct gg_header
)))) {
593 gg_debug(GG_DEBUG_MISC
, "// gg_send_packet() not enough memory for packet header\n");
597 h
= (struct gg_header
*) tmp
;
598 h
->type
= gg_fix32(type
);
599 h
->length
= gg_fix32(0);
603 payload
= va_arg(ap
, void *);
608 if (payload_length
< 0)
609 gg_debug(GG_DEBUG_MISC
, "// gg_send_packet() invalid payload length (%d)\n", payload_length
);
610 payload_length
= va_arg(ap
, unsigned int);
612 if (payload_length
< 0)
613 gg_debug(GG_DEBUG_MISC
, "// gg_send_packet() invalid payload length (%d)\n", payload_length
);
615 if (!(tmp2
= realloc(tmp
, sizeof(struct gg_header
) + tmp_length
+ payload_length
))) {
616 gg_debug(GG_DEBUG_MISC
, "// gg_send_packet() not enough memory for payload\n");
624 memcpy(tmp
+ sizeof(struct gg_header
) + tmp_length
, payload
, payload_length
);
625 tmp_length
+= payload_length
;
627 payload
= va_arg(ap
, void *);
632 h
= (struct gg_header
*) tmp
;
633 h
->length
= gg_fix32(tmp_length
);
635 if ((gg_debug_level
& GG_DEBUG_DUMP
)) {
638 gg_debug(GG_DEBUG_DUMP
, "// gg_send_packet(0x%.2x)", gg_fix32(h
->type
));
639 for (i
= 0; i
< sizeof(struct gg_header
) + gg_fix32(h
->length
); i
++)
640 gg_debug(GG_DEBUG_DUMP
, " %.2x", (unsigned char) tmp
[i
]);
641 gg_debug(GG_DEBUG_DUMP
, "\n");
644 tmp_length
+= sizeof(struct gg_header
);
646 if ((res
= gg_write(sess
, tmp
, tmp_length
)) < tmp_length
) {
647 gg_debug(GG_DEBUG_MISC
, "// gg_send_packet() write() failed. res = %d, errno = %d (%s)\n", res
, errno
, strerror(errno
));
657 * gg_session_callback() // funkcja wewnêtrzna
659 * wywo³ywany z gg_session->callback, wykonuje gg_watch_fd() i pakuje
660 * do gg_session->event jego wynik.
662 static int gg_session_callback(struct gg_session
*s
)
669 return ((s
->event
= gg_watch_fd(s
)) != NULL
) ? 0 : -1;
675 * rozpoczyna procedurê ³±czenia siê z serwerem. resztê obs³uguje siê przez
678 * UWAGA! program musi obs³u¿yæ SIGCHLD, je¶li ³±czy siê asynchronicznie,
679 * ¿eby poprawnie zamkn±æ proces resolvera.
681 * - p - struktura opisuj±ca pocz±tkowy stan. wymagane pola: uin,
684 * w przypadku b³êdu NULL, je¶li idzie dobrze (async) albo posz³o
685 * dobrze (sync), zwróci wska¼nik do zaalokowanej struct gg_session.
687 struct gg_session
*gg_login(const struct gg_login_params
*p
)
689 struct gg_session
*sess
= NULL
;
694 gg_debug(GG_DEBUG_FUNCTION
, "** gg_login(%p);\n", p
);
699 gg_debug(GG_DEBUG_FUNCTION
, "** gg_login(%p: [uin=%u, async=%d, ...]);\n", p
, p
->uin
, p
->async
);
701 if (!(sess
= malloc(sizeof(struct gg_session
)))) {
702 gg_debug(GG_DEBUG_MISC
, "// gg_login() not enough memory for session data\n");
706 memset(sess
, 0, sizeof(struct gg_session
));
708 if (!p
->password
|| !p
->uin
) {
709 gg_debug(GG_DEBUG_MISC
, "// gg_login() invalid arguments. uin and password needed\n");
714 if (!(sess
->password
= strdup(p
->password
))) {
715 gg_debug(GG_DEBUG_MISC
, "// gg_login() not enough memory for password\n");
719 if (p
->status_descr
&& !(sess
->initial_descr
= strdup(p
->status_descr
))) {
720 gg_debug(GG_DEBUG_MISC
, "// gg_login() not enough memory for status\n");
725 sess
->state
= GG_STATE_RESOLVING
;
726 sess
->check
= GG_CHECK_READ
;
727 sess
->timeout
= GG_DEFAULT_TIMEOUT
;
728 sess
->async
= p
->async
;
729 sess
->type
= GG_SESSION_GG
;
730 sess
->initial_status
= p
->status
;
731 sess
->callback
= gg_session_callback
;
732 sess
->destroy
= gg_free_session
;
733 sess
->port
= (p
->server_port
) ? p
->server_port
: GG_DEFAULT_PORT
;
734 sess
->server_addr
= p
->server_addr
;
735 sess
->external_port
= p
->external_port
;
736 sess
->external_addr
= p
->external_addr
;
737 sess
->protocol_version
= (p
->protocol_version
) ? p
->protocol_version
: GG_DEFAULT_PROTOCOL_VERSION
;
739 sess
->protocol_version
|= GG_HAS_AUDIO_MASK
;
740 sess
->client_version
= (p
->client_version
) ? strdup(p
->client_version
) : NULL
;
741 sess
->last_sysmsg
= p
->last_sysmsg
;
742 sess
->image_size
= p
->image_size
;
749 OpenSSL_add_ssl_algorithms();
751 if (!RAND_status()) {
759 rstruct
.ptr
= (void *) &rstruct
;
761 RAND_seed((void *) rdata
, sizeof(rdata
));
762 RAND_seed((void *) &rstruct
, sizeof(rstruct
));
765 sess
->ssl_ctx
= SSL_CTX_new(TLSv1_client_method());
767 if (!sess
->ssl_ctx
) {
768 ERR_error_string_n(ERR_get_error(), buf
, sizeof(buf
));
769 gg_debug(GG_DEBUG_MISC
, "// gg_login() SSL_CTX_new() failed: %s\n", buf
);
773 SSL_CTX_set_verify(sess
->ssl_ctx
, SSL_VERIFY_NONE
, NULL
);
775 sess
->ssl
= SSL_new(sess
->ssl_ctx
);
778 ERR_error_string_n(ERR_get_error(), buf
, sizeof(buf
));
779 gg_debug(GG_DEBUG_MISC
, "// gg_login() SSL_new() failed: %s\n", buf
);
783 gnutls_global_init ();
784 gnutls_certificate_allocate_credentials (&sess
->xcred
);
785 gnutls_init (&(sess
->session
), GNUTLS_CLIENT
);
786 gnutls_set_default_priority (sess
->session
);
787 gnutls_credentials_set (sess
->session
, GNUTLS_CRD_CERTIFICATE
, sess
->xcred
);
792 if (gg_proxy_enabled
) {
793 hostname
= gg_proxy_host
;
794 sess
->proxy_port
= port
= gg_proxy_port
;
796 hostname
= GG_APPMSG_HOST
;
797 port
= GG_APPMSG_PORT
;
803 if (!p
->server_addr
|| !p
->server_port
) {
804 if ((a
.s_addr
= inet_addr(hostname
)) == INADDR_NONE
) {
807 if (!(he
= gg_gethostbyname(hostname
))) {
808 gg_debug(GG_DEBUG_MISC
, "// gg_login() host \"%s\" not found\n", hostname
);
811 memcpy((char*) &a
, he
->h_addr
, sizeof(a
));
816 a
.s_addr
= p
->server_addr
;
817 port
= p
->server_port
;
820 sess
->hub_addr
= a
.s_addr
;
822 if ((sess
->fd
= gg_connect(&a
, port
, 0)) == -1) {
823 gg_debug(GG_DEBUG_MISC
, "// gg_login() connection failed (errno=%d, %s)\n", errno
, strerror(errno
));
827 if (p
->server_addr
&& p
->server_port
)
828 sess
->state
= GG_STATE_CONNECTING_GG
;
830 sess
->state
= GG_STATE_CONNECTING_HUB
;
832 while (sess
->state
!= GG_STATE_CONNECTED
) {
835 if (!(e
= gg_watch_fd(sess
))) {
836 gg_debug(GG_DEBUG_MISC
, "// gg_login() critical error in gg_watch_fd()\n");
840 if (e
->type
== GG_EVENT_CONN_FAILED
) {
842 gg_debug(GG_DEBUG_MISC
, "// gg_login() could not login\n");
853 if (!sess
->server_addr
|| gg_proxy_enabled
) {
854 #ifndef __GG_LIBGADU_HAVE_PTHREAD
855 if (gg_resolve(&sess
->fd
, &sess
->pid
, hostname
)) {
857 if (gg_resolve_pthread(&sess
->fd
, &sess
->resolver
, hostname
)) {
859 gg_debug(GG_DEBUG_MISC
, "// gg_login() resolving failed (errno=%d, %s)\n", errno
, strerror(errno
));
863 if ((sess
->fd
= gg_connect(&sess
->server_addr
, sess
->port
, sess
->async
)) == -1) {
864 gg_debug(GG_DEBUG_MISC
, "// gg_login() direct connection failed (errno=%d, %s)\n", errno
, strerror(errno
));
868 sess
->state
= GG_STATE_CONNECTING_HUB
;
869 sess
->check
= GG_CHECK_WRITE
;
870 sess
->timeout
= GG_DEFAULT_TIMEOUT
;
878 free(sess
->password
);
879 if (sess
->initial_descr
)
880 free(sess
->initial_descr
);
890 * próbuje zamkn±æ po³±czenia i zwalnia pamiêæ zajmowan± przez sesjê.
892 * - sess - opis sesji
894 void gg_free_session(struct gg_session
*sess
)
899 /* XXX dopisaæ zwalnianie i zamykanie wszystkiego, co mog³o zostaæ */
902 free(sess
->password
);
904 if (sess
->initial_descr
)
905 free(sess
->initial_descr
);
907 if (sess
->client_version
)
908 free(sess
->client_version
);
910 if (sess
->header_buf
)
911 free(sess
->header_buf
);
918 SSL_CTX_free(sess
->ssl_ctx
);
921 gnutls_bye(sess
->session
, GNUTLS_SHUT_WR
);
922 gnutls_deinit(sess
->session
);
926 #ifdef __GG_LIBGADU_HAVE_PTHREAD
927 if (sess
->resolver
) {
928 pthread_cancel(*((pthread_t
*) sess
->resolver
));
929 free(sess
->resolver
);
930 sess
->resolver
= NULL
;
934 waitpid(sess
->pid
, NULL
, WNOHANG
);
941 gg_image_queue_remove(sess
, sess
->images
, 1);
949 * zmienia status u¿ytkownika. przydatne do /away i /busy oraz /quit.
951 * - sess - opis sesji
952 * - status - nowy status u¿ytkownika
956 int gg_change_status(struct gg_session
*sess
, int status
)
958 struct gg_new_status p
;
960 gg_debug(GG_DEBUG_FUNCTION
, "** gg_change_status(%p, %d);\n", sess
, status
);
967 if (sess
->state
!= GG_STATE_CONNECTED
) {
972 p
.status
= gg_fix32(status
);
974 sess
->status
= status
;
976 return gg_send_packet(sess
, GG_NEW_STATUS
, &p
, sizeof(p
), NULL
);
980 * gg_change_status_descr()
982 * zmienia status u¿ytkownika na opisowy.
984 * - sess - opis sesji
985 * - status - nowy status u¿ytkownika
986 * - descr - opis statusu
990 int gg_change_status_descr(struct gg_session
*sess
, int status
, const char *descr
)
992 struct gg_new_status p
;
994 gg_debug(GG_DEBUG_FUNCTION
, "** gg_change_status_descr(%p, %d, \"%s\");\n", sess
, status
, descr
);
996 if (!sess
|| !descr
) {
1001 if (sess
->state
!= GG_STATE_CONNECTED
) {
1006 p
.status
= gg_fix32(status
);
1008 sess
->status
= status
;
1010 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
);
1014 * gg_change_status_descr_time()
1016 * zmienia status u¿ytkownika na opisowy z godzin± powrotu.
1018 * - sess - opis sesji
1019 * - status - nowy status u¿ytkownika
1020 * - descr - opis statusu
1021 * - time - czas w formacie uniksowym
1025 int gg_change_status_descr_time(struct gg_session
*sess
, int status
, const char *descr
, int time
)
1027 struct gg_new_status p
;
1030 gg_debug(GG_DEBUG_FUNCTION
, "** gg_change_status_descr_time(%p, %d, \"%s\", %d);\n", sess
, status
, descr
, time
);
1032 if (!sess
|| !descr
|| !time
) {
1037 if (sess
->state
!= GG_STATE_CONNECTED
) {
1042 p
.status
= gg_fix32(status
);
1044 sess
->status
= status
;
1046 newtime
= gg_fix32(time
);
1048 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
);
1054 * wylogowuje u¿ytkownika i zamyka po³±czenie, ale nie zwalnia pamiêci.
1056 * - sess - opis sesji
1058 void gg_logoff(struct gg_session
*sess
)
1063 gg_debug(GG_DEBUG_FUNCTION
, "** gg_logoff(%p);\n", sess
);
1065 if (GG_S_NA(sess
->status
& ~GG_STATUS_FRIENDS_MASK
))
1066 gg_change_status(sess
, GG_STATUS_NOT_AVAIL
);
1070 SSL_shutdown(sess
->ssl
);
1073 gnutls_bye(sess
->session
, GNUTLS_SHUT_WR
);
1074 gnutls_deinit(sess
->session
);
1078 #ifdef __GG_LIBGADU_HAVE_PTHREAD
1079 if (sess
->resolver
) {
1080 pthread_cancel(*((pthread_t
*) sess
->resolver
));
1081 free(sess
->resolver
);
1082 sess
->resolver
= NULL
;
1085 if (sess
->pid
!= -1) {
1086 waitpid(sess
->pid
, NULL
, WNOHANG
);
1091 if (sess
->fd
!= -1) {
1092 shutdown(sess
->fd
, 2);
1099 * gg_image_request()
1101 * wysy³a ¿±danie wys³ania obrazka o podanych parametrach.
1103 * - sess - opis sesji
1104 * - recipient - numer adresata
1105 * - size - rozmiar obrazka
1106 * - crc32 - suma kontrolna obrazka
1110 int gg_image_request(struct gg_session
*sess
, uin_t recipient
, int size
, uint32_t crc32
)
1112 struct gg_send_msg s
;
1113 struct gg_msg_image_request r
;
1117 gg_debug(GG_DEBUG_FUNCTION
, "** gg_image_request(%p, %d, %u, 0x%.4x);\n", sess
, recipient
, size
, crc32
);
1124 if (sess
->state
!= GG_STATE_CONNECTED
) {
1129 s
.recipient
= gg_fix32(recipient
);
1130 s
.seq
= gg_fix32(0);
1131 s
.msgclass
= gg_fix32(GG_CLASS_MSG
);
1134 r
.size
= gg_fix32(size
);
1135 r
.crc32
= gg_fix32(crc32
);
1137 res
= gg_send_packet(sess
, GG_SEND_MSG
, &s
, sizeof(s
), &dummy
, 1, &r
, sizeof(r
), NULL
);
1140 struct gg_image_queue
*q
= malloc(sizeof(*q
));
1141 char *buf
= malloc(size
);
1144 gg_debug(GG_DEBUG_MISC
, "// gg_image_request() not enough memory for image queue\n");
1150 memset(q
, 0, sizeof(*q
));
1152 q
->sender
= recipient
;
1160 struct gg_image_queue
*qq
;
1162 for (qq
= sess
->images
; qq
->next
; qq
= qq
->next
)
1175 * wysy³a ¿±dany obrazek.
1177 * - sess - opis sesji
1178 * - recipient - numer adresata
1179 * - filename - nazwa pliku
1180 * - image - bufor z obrazkiem
1181 * - size - rozmiar obrazka
1185 int gg_image_reply(struct gg_session
*sess
, uin_t recipient
, const char *filename
, const char *image
, int size
)
1187 struct gg_msg_image_reply
*r
;
1188 struct gg_send_msg s
;
1193 gg_debug(GG_DEBUG_FUNCTION
, "** gg_image_reply(%p, %d, \"%s\", %p, %d);\n", sess
, recipient
, filename
, image
, size
);
1195 if (!sess
|| !filename
|| !image
) {
1200 /* wytnij ¶cie¿ki, zostaw tylko nazwê pliku */
1201 while ((tmp
= rindex(filename
, '/')) || (tmp
= rindex(filename
, '\\')))
1204 if (strlen(filename
) < 1 || strlen(filename
) > 1024) {
1209 if (sess
->state
!= GG_STATE_CONNECTED
) {
1214 s
.recipient
= gg_fix32(recipient
);
1215 s
.seq
= gg_fix32(0);
1216 s
.msgclass
= gg_fix32(GG_CLASS_MSG
);
1219 r
= (void*) &buf
[1];
1222 r
->size
= gg_fix32(size
);
1223 r
->crc32
= gg_fix32(gg_crc32(0, image
, size
));
1226 int buflen
, chunklen
;
1228 /* \0 + struct gg_msg_image_reply */
1229 buflen
= sizeof(struct gg_msg_image_reply
) + 1;
1231 /* w pierwszym kawa³ku jest nazwa pliku */
1232 if (r
->flag
== 0x05) {
1233 strcpy(buf
+ buflen
, filename
);
1234 buflen
+= strlen(filename
) + 1;
1237 chunklen
= (size
>= sizeof(buf
) - buflen
) ? (sizeof(buf
) - buflen
) : size
;
1239 memcpy(buf
+ buflen
, image
, chunklen
);
1243 res
= gg_send_packet(sess
, GG_SEND_MSG
, &s
, sizeof(s
), buf
, buflen
+ chunklen
, NULL
);
1255 * gg_send_message_ctcp()
1257 * wysy³a wiadomo¶æ do innego u¿ytkownika. zwraca losowy numer
1258 * sekwencyjny, który mo¿na zignorowaæ albo wykorzystaæ do potwierdzenia.
1260 * - sess - opis sesji
1261 * - msgclass - rodzaj wiadomo¶ci
1262 * - recipient - numer adresata
1263 * - message - tre¶æ wiadomo¶ci
1264 * - message_len - d³ugo¶æ
1266 * numer sekwencyjny wiadomo¶ci lub -1 w przypadku b³êdu.
1268 int gg_send_message_ctcp(struct gg_session
*sess
, int msgclass
, uin_t recipient
, const unsigned char *message
, int message_len
)
1270 struct gg_send_msg s
;
1272 gg_debug(GG_DEBUG_FUNCTION
, "** gg_send_message_ctcp(%p, %d, %u, ...);\n", sess
, msgclass
, recipient
);
1279 if (sess
->state
!= GG_STATE_CONNECTED
) {
1284 s
.recipient
= gg_fix32(recipient
);
1285 s
.seq
= gg_fix32(0);
1286 s
.msgclass
= gg_fix32(msgclass
);
1288 return gg_send_packet(sess
, GG_SEND_MSG
, &s
, sizeof(s
), message
, message_len
, NULL
);
1294 * wysy³a wiadomo¶æ do innego u¿ytkownika. zwraca losowy numer
1295 * sekwencyjny, który mo¿na zignorowaæ albo wykorzystaæ do potwierdzenia.
1297 * - sess - opis sesji
1298 * - msgclass - rodzaj wiadomo¶ci
1299 * - recipient - numer adresata
1300 * - message - tre¶æ wiadomo¶ci
1302 * numer sekwencyjny wiadomo¶ci lub -1 w przypadku b³êdu.
1304 int gg_send_message(struct gg_session
*sess
, int msgclass
, uin_t recipient
, const unsigned char *message
)
1306 gg_debug(GG_DEBUG_FUNCTION
, "** gg_send_message(%p, %d, %u, %p)\n", sess
, msgclass
, recipient
, message
);
1308 return gg_send_message_richtext(sess
, msgclass
, recipient
, message
, NULL
, 0);
1312 * gg_send_message_richtext()
1314 * wysy³a kolorow± wiadomo¶æ do innego u¿ytkownika. zwraca losowy numer
1315 * sekwencyjny, który mo¿na zignorowaæ albo wykorzystaæ do potwierdzenia.
1317 * - sess - opis sesji
1318 * - msgclass - rodzaj wiadomo¶ci
1319 * - recipient - numer adresata
1320 * - message - tre¶æ wiadomo¶ci
1321 * - format - informacje o formatowaniu
1322 * - formatlen - d³ugo¶æ informacji o formatowaniu
1324 * numer sekwencyjny wiadomo¶ci lub -1 w przypadku b³êdu.
1326 int gg_send_message_richtext(struct gg_session
*sess
, int msgclass
, uin_t recipient
, const unsigned char *message
, const unsigned char *format
, int formatlen
)
1328 struct gg_send_msg s
;
1330 gg_debug(GG_DEBUG_FUNCTION
, "** gg_send_message_richtext(%p, %d, %u, %p, %p, %d);\n", sess
, msgclass
, recipient
, message
, format
, formatlen
);
1337 if (sess
->state
!= GG_STATE_CONNECTED
) {
1342 s
.recipient
= gg_fix32(recipient
);
1344 sess
->seq
= 0x01740000 | (rand() & 0xffff);
1345 s
.seq
= gg_fix32(sess
->seq
);
1346 s
.msgclass
= gg_fix32(msgclass
);
1347 sess
->seq
+= (rand() % 0x300) + 0x300;
1349 if (gg_send_packet(sess
, GG_SEND_MSG
, &s
, sizeof(s
), message
, strlen(message
) + 1, format
, formatlen
, NULL
) == -1)
1352 return gg_fix32(s
.seq
);
1356 * gg_send_message_confer()
1358 * wysy³a wiadomo¶æ do kilku u¿ytkownikow (konferencja). zwraca losowy numer
1359 * sekwencyjny, który mo¿na zignorowaæ albo wykorzystaæ do potwierdzenia.
1361 * - sess - opis sesji
1362 * - msgclass - rodzaj wiadomo¶ci
1363 * - recipients_count - ilo¶æ adresatów
1364 * - recipients - numerki adresatów
1365 * - message - tre¶æ wiadomo¶ci
1367 * numer sekwencyjny wiadomo¶ci lub -1 w przypadku b³êdu.
1369 int gg_send_message_confer(struct gg_session
*sess
, int msgclass
, int recipients_count
, uin_t
*recipients
, const unsigned char *message
)
1371 gg_debug(GG_DEBUG_FUNCTION
, "** gg_send_message_confer(%p, %d, %d, %p, %p);\n", sess
, msgclass
, recipients_count
, recipients
, message
);
1373 return gg_send_message_confer_richtext(sess
, msgclass
, recipients_count
, recipients
, message
, NULL
, 0);
1377 * gg_send_message_confer_richtext()
1379 * wysy³a kolorow± wiadomo¶æ do kilku u¿ytkownikow (konferencja). zwraca
1380 * losowy numer sekwencyjny, który mo¿na zignorowaæ albo wykorzystaæ do
1383 * - sess - opis sesji
1384 * - msgclass - rodzaj wiadomo¶ci
1385 * - recipients_count - ilo¶æ adresatów
1386 * - recipients - numerki adresatów
1387 * - message - tre¶æ wiadomo¶ci
1388 * - format - informacje o formatowaniu
1389 * - formatlen - d³ugo¶æ informacji o formatowaniu
1391 * numer sekwencyjny wiadomo¶ci lub -1 w przypadku b³êdu.
1393 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
)
1395 struct gg_send_msg s
;
1396 struct gg_msg_recipients r
;
1400 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
);
1407 if (sess
->state
!= GG_STATE_CONNECTED
) {
1413 r
.count
= gg_fix32(recipients_count
- 1);
1416 sess
->seq
= 0x01740000 | (rand() & 0xffff);
1417 s
.seq
= gg_fix32(sess
->seq
);
1418 s
.msgclass
= gg_fix32(msgclass
);
1420 recps
= malloc(sizeof(uin_t
) * recipients_count
);
1421 for (i
= 0; i
< recipients_count
; i
++) {
1423 s
.recipient
= gg_fix32(recipients
[i
]);
1425 for (j
= 0, k
= 0; j
< recipients_count
; j
++)
1426 if (recipients
[j
] != recipients
[i
]) {
1427 recps
[k
] = gg_fix32(recipients
[j
]);
1432 sess
->seq
+= (rand() % 0x300) + 0x300;
1434 if (gg_send_packet(sess
, GG_SEND_MSG
, &s
, sizeof(s
), message
, strlen(message
) + 1, &r
, sizeof(r
), recps
, (recipients_count
- 1) * sizeof(uin_t
), format
, formatlen
, NULL
) == -1) {
1442 return gg_fix32(s
.seq
);
1448 * wysy³a do serwera pakiet ping.
1450 * - sess - opis sesji
1454 int gg_ping(struct gg_session
*sess
)
1456 gg_debug(GG_DEBUG_FUNCTION
, "** gg_ping(%p);\n", sess
);
1463 if (sess
->state
!= GG_STATE_CONNECTED
) {
1468 return gg_send_packet(sess
, GG_PING
, NULL
);
1474 * wysy³a serwerowi listê kontaktów (wraz z odpowiadaj±cymi im typami userów),
1475 * dziêki czemu wie, czyj stan nas interesuje.
1477 * - sess - opis sesji
1478 * - userlist - wska¼nik do tablicy numerów
1479 * - types - wska¼nik do tablicy typów u¿ytkowników
1480 * - count - ilo¶æ numerków
1484 int gg_notify_ex(struct gg_session
*sess
, uin_t
*userlist
, char *types
, int count
)
1486 struct gg_notify
*n
;
1491 gg_debug(GG_DEBUG_FUNCTION
, "** gg_notify_ex(%p, %p, %p, %d);\n", sess
, userlist
, types
, count
);
1498 if (sess
->state
!= GG_STATE_CONNECTED
) {
1503 if (!userlist
|| !count
)
1504 return gg_send_packet(sess
, GG_LIST_EMPTY
, NULL
);
1506 if (!(n
= (struct gg_notify
*) malloc(sizeof(*n
) * count
)))
1509 for (u
= userlist
, t
= types
, i
= 0; i
< count
; u
++, t
++, i
++) {
1510 n
[i
].uin
= gg_fix32(*u
);
1514 if (gg_send_packet(sess
, GG_NOTIFY
, n
, sizeof(*n
) * count
, NULL
) == -1)
1525 * wysy³a serwerowi listê kontaktów, dziêki czemu wie, czyj stan nas
1528 * - sess - opis sesji
1529 * - userlist - wska¼nik do tablicy numerów
1530 * - count - ilo¶æ numerków
1534 int gg_notify(struct gg_session
*sess
, uin_t
*userlist
, int count
)
1536 struct gg_notify
*n
;
1540 gg_debug(GG_DEBUG_FUNCTION
, "** gg_notify(%p, %p, %d);\n", sess
, userlist
, count
);
1547 if (sess
->state
!= GG_STATE_CONNECTED
) {
1552 if (!userlist
|| !count
)
1555 if (!(n
= (struct gg_notify
*) malloc(sizeof(*n
) * count
)))
1558 for (u
= userlist
, i
= 0; i
< count
; u
++, i
++) {
1559 n
[i
].uin
= gg_fix32(*u
);
1560 n
[i
].dunno1
= GG_USER_NORMAL
;
1563 if (gg_send_packet(sess
, GG_NOTIFY
, n
, sizeof(*n
) * count
, NULL
) == -1)
1572 * gg_add_notify_ex()
1574 * dodaje do listy kontaktów dany numer w trakcie po³±czenia.
1575 * dodawanemu u¿ytkownikowi okre¶lamy jego typ (patrz protocol.html)
1577 * - sess - opis sesji
1583 int gg_add_notify_ex(struct gg_session
*sess
, uin_t uin
, char type
)
1585 struct gg_add_remove a
;
1587 gg_debug(GG_DEBUG_FUNCTION
, "** gg_add_notify_ex(%p, %u, %d);\n", sess
, uin
, type
);
1594 if (sess
->state
!= GG_STATE_CONNECTED
) {
1599 a
.uin
= gg_fix32(uin
);
1602 return gg_send_packet(sess
, GG_ADD_NOTIFY
, &a
, sizeof(a
), NULL
);
1608 * dodaje do listy kontaktów dany numer w trakcie po³±czenia.
1610 * - sess - opis sesji
1615 int gg_add_notify(struct gg_session
*sess
, uin_t uin
)
1617 return gg_add_notify_ex(sess
, uin
, GG_USER_NORMAL
);
1621 * gg_remove_notify_ex()
1623 * usuwa z listy kontaktów w trakcie po³±czenia.
1624 * usuwanemu u¿ytkownikowi okre¶lamy jego typ (patrz protocol.html)
1626 * - sess - opis sesji
1632 int gg_remove_notify_ex(struct gg_session
*sess
, uin_t uin
, char type
)
1634 struct gg_add_remove a
;
1636 gg_debug(GG_DEBUG_FUNCTION
, "** gg_remove_notify_ex(%p, %u, %d);\n", sess
, uin
, type
);
1643 if (sess
->state
!= GG_STATE_CONNECTED
) {
1648 a
.uin
= gg_fix32(uin
);
1651 return gg_send_packet(sess
, GG_REMOVE_NOTIFY
, &a
, sizeof(a
), NULL
);
1655 * gg_remove_notify()
1657 * usuwa z listy kontaktów w trakcie po³±czenia.
1659 * - sess - opis sesji
1664 int gg_remove_notify(struct gg_session
*sess
, uin_t uin
)
1666 return gg_remove_notify_ex(sess
, uin
, GG_USER_NORMAL
);
1670 * gg_userlist_request()
1672 * wysy³a ¿±danie/zapytanie listy kontaktów na serwerze.
1674 * - sess - opis sesji
1675 * - type - rodzaj zapytania/¿±dania
1676 * - request - tre¶æ zapytania/¿±dania (mo¿e byæ NULL)
1680 int gg_userlist_request(struct gg_session
*sess
, char type
, const char *request
)
1690 sess
->userlist_blocks
= 1;
1691 return gg_send_packet(sess
, GG_USERLIST_REQUEST
, &type
, sizeof(type
), NULL
);
1694 len
= strlen(request
);
1696 sess
->userlist_blocks
= 0;
1698 while (len
> 2047) {
1699 sess
->userlist_blocks
++;
1701 if (gg_send_packet(sess
, GG_USERLIST_REQUEST
, &type
, sizeof(type
), request
, 2047, NULL
) == -1)
1704 if (type
== GG_USERLIST_PUT
)
1705 type
= GG_USERLIST_PUT_MORE
;
1711 sess
->userlist_blocks
++;
1713 return gg_send_packet(sess
, GG_USERLIST_REQUEST
, &type
, sizeof(type
), request
, len
, NULL
);
1718 * c-indentation-style: k&r
1720 * indent-tabs-mode: notnil
1723 * vim: shiftwidth=8: