wrong coded blanks in German translation updated
[centerim.git] / libgadu / libgadu.c
blobdc69727353fd7860864fbd520cd0ced11a06e4bf
1 /* $Id: libgadu.c,v 1.2 2004/03/30 22:44:07 konst Exp $ */
3 /*
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>
24 #include <sys/wait.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #ifdef sun
29 # include <sys/filio.h>
30 #endif
32 #include "libgadu-config.h"
34 #include <errno.h>
35 #include <netdb.h>
36 #ifdef __GG_LIBGADU_HAVE_PTHREAD
37 # include <pthread.h>
38 #endif
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 #ifdef HAVE_OPENSSL
45 #define OPENSSL_NO_KRB5 1
46 # include <openssl/err.h>
47 # include <openssl/rand.h>
48 #elif HAVE_GNUTLS
49 #include <gnutls/gnutls.h>
50 #endif
52 #include "compat.h"
53 #include "libgadu.h"
55 int gg_debug_level = 0;
56 void (*gg_debug_handler)(int level, const char *format, va_list ap) = NULL;
58 int gg_dcc_port = 0;
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;
71 #ifndef lint
72 static char rcsid[]
73 #ifdef __GNUC__
74 __attribute__ ((unused))
75 #endif
76 = "$Id: libgadu.c,v 1.2 2004/03/30 22:44:07 konst Exp $";
77 #endif
80 * gg_libgadu_version()
82 * zwraca wersjê libgadu.
84 * - brak
86 * wersja libgadu.
88 const char *gg_libgadu_version()
90 return GG_LIBGADU_VERSION;
94 * gg_fix32()
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
107 return x;
108 #else
109 return (uint32_t)
110 (((x & (uint32_t) 0x000000ffU) << 24) |
111 ((x & (uint32_t) 0x0000ff00U) << 8) |
112 ((x & (uint32_t) 0x00ff0000U) >> 8) |
113 ((x & (uint32_t) 0xff000000U) >> 24));
114 #endif
118 * gg_fix16()
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
131 return x;
132 #else
133 return (uint16_t)
134 (((x & (uint16_t) 0x00ffU) << 8) |
135 ((x & (uint16_t) 0xff00U) >> 8));
136 #endif
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
147 * hash.
149 unsigned int gg_login_hash(const unsigned char *password, unsigned int seed)
151 unsigned int x, y, z;
153 y = seed;
155 for (x = 0; *password; password++) {
156 x = (x & 0xffffff00) | *password;
157 y ^= x;
158 y += x;
159 x <<= 8;
160 y ^= x;
161 x <<= 8;
162 y -= x;
163 x <<= 8;
164 y ^= x;
166 z = y & 0x1F;
167 y = (y << z) | (y >> (32 - z));
170 return y;
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
185 * 0, -1.
187 int gg_resolve(int *fd, int *pid, const char *hostname)
189 int pipes[2], res;
190 struct in_addr a;
192 gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve(%p, %p, \"%s\");\n", fd, pid, hostname);
194 if (!fd || !pid) {
195 errno = EFAULT;
196 return -1;
199 if (pipe(pipes) == -1)
200 return -1;
202 if ((res = fork()) == -1)
203 return -1;
205 if (!res) {
206 if ((a.s_addr = inet_addr(hostname)) == INADDR_NONE) {
207 struct hostent *he;
209 if (!(he = gg_gethostbyname(hostname)))
210 a.s_addr = INADDR_NONE;
211 else {
212 memcpy((char*) &a, he->h_addr, sizeof(a));
213 free(he);
217 write(pipes[1], &a, sizeof(a));
219 _exit(0);
222 close(pipes[1]);
224 *fd = pipes[0];
225 *pid = res;
227 return 0;
230 #ifdef __GG_LIBGADU_HAVE_PTHREAD
232 struct gg_resolve_pthread_data {
233 char *hostname;
234 int fd;
237 static void *gg_resolve_pthread_thread(void *arg)
239 struct gg_resolve_pthread_data *d = arg;
240 struct in_addr a;
242 if ((a.s_addr = inet_addr(d->hostname)) == INADDR_NONE) {
243 struct hostent *he;
245 if (!(he = gg_gethostbyname(d->hostname)))
246 a.s_addr = INADDR_NONE;
247 else {
248 memcpy((char*) &a, he->h_addr, sizeof(a));
249 free(he);
253 write(d->fd, &a, sizeof(a));
254 close(d->fd);
256 free(d->hostname);
257 d->hostname = NULL;
259 free(d);
261 pthread_exit(NULL);
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
272 * INADDR_NONE.
274 * - fd - wska¼nik do zmiennej przechowuj±cej desktyptor resolvera
275 * - resolver - wska¼nik do wska¼nika resolvera
276 * - hostname - nazwa hosta do zresolvowania
278 * 0, -1.
280 int gg_resolve_pthread(int *fd, void **resolver, const char *hostname)
282 struct gg_resolve_pthread_data *d;
283 pthread_t *tmp;
284 int pipes[2];
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");
290 errno = EFAULT;
291 return -1;
294 if (!(tmp = malloc(sizeof(pthread_t)))) {
295 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory for pthread id\n");
296 return -1;
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));
301 free(tmp);
302 return -1;
305 if (!(d = malloc(sizeof(*d))) || !(d->hostname = strdup(hostname))) {
306 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory\n");
307 free(tmp);
308 return -1;
311 d->fd = pipes[1];
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");
315 close(pipes[0]);
316 close(pipes[1]);
317 free(tmp);
318 return -1;
321 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() %p\n", tmp);
323 *resolver = tmp;
325 *fd = pipes[0];
327 return 0;
330 #endif
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.
338 * - sess - sesja,
339 * - buf - bufor,
340 * - length - ilo¶æ bajtów,
342 * takie same warto¶ci jak read().
344 int gg_read(struct gg_session *sess, char *buf, int length)
346 int res;
348 #ifdef HAVE_OPENSSL
349 if (sess->ssl) {
350 int err;
352 res = SSL_read(sess->ssl, buf, length);
354 if (res < 0) {
355 err = SSL_get_error(sess->ssl, res);
357 if (err == SSL_ERROR_WANT_READ)
358 errno = EAGAIN;
360 return -1;
362 } else
363 #elif HAVE_GNUTLS
364 if (sess->session) {
365 do {
366 res = gnutls_record_recv(sess->session, buf, length);
367 } while ( res < 0 && (res == GNUTLS_E_INTERRUPTED || res == GNUTLS_E_AGAIN) );
368 } else
369 #endif
370 res = read(sess->fd, buf, length);
372 return res;
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.
381 * - sess - sesja,
382 * - buf - bufor,
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)
389 int res = 0;
391 #ifdef HAVE_OPENSSL
392 if (sess->ssl) {
393 int err;
395 res = SSL_write(sess->ssl, buf, length);
397 if (res < 0) {
398 err = SSL_get_error(sess->ssl, res);
400 if (err == SSL_ERROR_WANT_WRITE)
401 errno = EAGAIN;
403 return -1;
405 } else
406 #elif HAVE_GNUTLS
407 if (sess->session) {
408 if(res = gnutls_record_send( sess->session, buf, length) < 0)
409 fprintf(stderr,"Can't write to server");
410 } else
411 #endif
412 res = write(sess->fd, buf, length);
414 return res;
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)
429 struct gg_header h;
430 char *buf = NULL;
431 int ret = 0;
432 unsigned int offset, size = 0;
434 gg_debug(GG_DEBUG_FUNCTION, "** gg_recv_packet(%p);\n", sess);
436 if (!sess) {
437 errno = EFAULT;
438 return NULL;
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;
447 } else
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);
455 if (!ret) {
456 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: connection broken\n");
457 return NULL;
460 if (ret == -1) {
461 if (errno == EINTR) {
462 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() interrupted system call, resuming\n");
463 continue;
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");
471 return NULL;
474 memcpy(sess->header_buf, &h, sess->header_done);
476 return NULL;
479 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: errno=%d, %s\n", errno, strerror(errno));
481 return NULL;
484 sess->header_done += ret;
488 h.type = gg_fix32(h.type);
489 h.length = gg_fix32(h.length);
490 } else
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);
496 errno = ERANGE;
497 return NULL;
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;
505 } else {
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");
508 return NULL;
511 memcpy(buf, &h, sizeof(h));
513 offset = 0;
514 size = h.length;
517 while (size > 0) {
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);
520 if (!ret) {
521 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() failed: connection broken\n");
522 errno = ECONNRESET;
523 return NULL;
525 if (ret > -1 && ret <= size) {
526 offset += ret;
527 size -= ret;
528 } else if (ret == -1) {
529 int errno2 = errno;
530 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed (errno=%d, %s)\n", errno, strerror(errno));
531 errno = errno2;
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;
537 return NULL;
539 if (errno != EINTR) {
540 free(buf);
541 return NULL;
546 sess->recv_left = 0;
548 if ((gg_debug_level & GG_DEBUG_DUMP)) {
549 unsigned int i;
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");
557 return buf;
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, ...)
580 struct gg_header *h;
581 char *tmp;
582 unsigned int tmp_length;
583 void *payload;
584 unsigned int payload_length;
585 va_list ap;
586 int res;
588 gg_debug(GG_DEBUG_FUNCTION, "** gg_send_packet(%p, 0x%.2x, ...)\n", sess, type);
590 tmp_length = 0;
592 if (!(tmp = malloc(sizeof(struct gg_header)))) {
593 gg_debug(GG_DEBUG_MISC, "// gg_send_packet() not enough memory for packet header\n");
594 return -1;
597 h = (struct gg_header*) tmp;
598 h->type = gg_fix32(type);
599 h->length = gg_fix32(0);
601 va_start(ap, type);
603 payload = va_arg(ap, void *);
605 while (payload) {
606 char *tmp2;
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");
617 free(tmp);
618 va_end(ap);
619 return -1;
622 tmp = tmp2;
624 memcpy(tmp + sizeof(struct gg_header) + tmp_length, payload, payload_length);
625 tmp_length += payload_length;
627 payload = va_arg(ap, void *);
630 va_end(ap);
632 h = (struct gg_header*) tmp;
633 h->length = gg_fix32(tmp_length);
635 if ((gg_debug_level & GG_DEBUG_DUMP)) {
636 unsigned int i;
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));
648 free(tmp);
649 return -1;
652 free(tmp);
653 return 0;
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)
664 if (!s) {
665 errno = EINVAL;
666 return -1;
669 return ((s->event = gg_watch_fd(s)) != NULL) ? 0 : -1;
673 * gg_login()
675 * rozpoczyna procedurê ³±czenia siê z serwerem. resztê obs³uguje siê przez
676 * gg_watch_fd().
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,
682 * password
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;
690 char *hostname;
691 int port;
693 if (!p) {
694 gg_debug(GG_DEBUG_FUNCTION, "** gg_login(%p);\n", p);
695 errno = EINVAL;
696 return NULL;
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");
703 goto fail;
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");
710 errno = EINVAL;
711 goto fail;
714 if (!(sess->password = strdup(p->password))) {
715 gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for password\n");
716 goto fail;
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");
721 goto fail;
724 sess->uin = p->uin;
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;
738 if (p->has_audio)
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;
743 sess->pid = -1;
745 if (p->tls == 1) {
746 #ifdef HAVE_OPENSSL
747 char buf[1024];
749 OpenSSL_add_ssl_algorithms();
751 if (!RAND_status()) {
752 char rdata[1024];
753 struct {
754 time_t time;
755 void *ptr;
756 } rstruct;
758 time(&rstruct.time);
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);
770 goto fail;
773 SSL_CTX_set_verify(sess->ssl_ctx, SSL_VERIFY_NONE, NULL);
775 sess->ssl = SSL_new(sess->ssl_ctx);
777 if (!sess->ssl) {
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);
780 goto fail;
782 #elif HAVE_GNUTLS
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);
789 #endif
792 if (gg_proxy_enabled) {
793 hostname = gg_proxy_host;
794 sess->proxy_port = port = gg_proxy_port;
795 } else {
796 hostname = GG_APPMSG_HOST;
797 port = GG_APPMSG_PORT;
800 if (!p->async) {
801 struct in_addr a;
803 if (!p->server_addr || !p->server_port) {
804 if ((a.s_addr = inet_addr(hostname)) == INADDR_NONE) {
805 struct hostent *he;
807 if (!(he = gg_gethostbyname(hostname))) {
808 gg_debug(GG_DEBUG_MISC, "// gg_login() host \"%s\" not found\n", hostname);
809 goto fail;
810 } else {
811 memcpy((char*) &a, he->h_addr, sizeof(a));
812 free(he);
815 } else {
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));
824 goto fail;
827 if (p->server_addr && p->server_port)
828 sess->state = GG_STATE_CONNECTING_GG;
829 else
830 sess->state = GG_STATE_CONNECTING_HUB;
832 while (sess->state != GG_STATE_CONNECTED) {
833 struct gg_event *e;
835 if (!(e = gg_watch_fd(sess))) {
836 gg_debug(GG_DEBUG_MISC, "// gg_login() critical error in gg_watch_fd()\n");
837 goto fail;
840 if (e->type == GG_EVENT_CONN_FAILED) {
841 errno = EACCES;
842 gg_debug(GG_DEBUG_MISC, "// gg_login() could not login\n");
843 gg_event_free(e);
844 goto fail;
847 gg_event_free(e);
850 return sess;
853 if (!sess->server_addr || gg_proxy_enabled) {
854 #ifndef __GG_LIBGADU_HAVE_PTHREAD
855 if (gg_resolve(&sess->fd, &sess->pid, hostname)) {
856 #else
857 if (gg_resolve_pthread(&sess->fd, &sess->resolver, hostname)) {
858 #endif
859 gg_debug(GG_DEBUG_MISC, "// gg_login() resolving failed (errno=%d, %s)\n", errno, strerror(errno));
860 goto fail;
862 } else {
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));
865 goto fail;
868 sess->state = GG_STATE_CONNECTING_HUB;
869 sess->check = GG_CHECK_WRITE;
870 sess->timeout = GG_DEFAULT_TIMEOUT;
873 return sess;
875 fail:
876 if (sess) {
877 if (sess->password)
878 free(sess->password);
879 if (sess->initial_descr)
880 free(sess->initial_descr);
881 free(sess);
884 return NULL;
888 * gg_free_session()
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)
896 if (!sess)
897 return;
899 /* XXX dopisaæ zwalnianie i zamykanie wszystkiego, co mog³o zostaæ */
901 if (sess->password)
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);
913 #ifdef HAVE_OPENSSL
914 if (sess->ssl)
915 SSL_free(sess->ssl);
917 if (sess->ssl_ctx)
918 SSL_CTX_free(sess->ssl_ctx);
919 #elif HAVE_GNUTLS
920 if (sess->session){
921 gnutls_bye(sess->session, GNUTLS_SHUT_WR);
922 gnutls_deinit(sess->session);
924 #endif
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;
932 #else
933 if (sess->pid != -1)
934 waitpid(sess->pid, NULL, WNOHANG);
935 #endif
937 if (sess->fd != -1)
938 close(sess->fd);
940 while (sess->images)
941 gg_image_queue_remove(sess, sess->images, 1);
943 free(sess);
947 * gg_change_status()
949 * zmienia status u¿ytkownika. przydatne do /away i /busy oraz /quit.
951 * - sess - opis sesji
952 * - status - nowy status u¿ytkownika
954 * 0, -1.
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);
962 if (!sess) {
963 errno = EFAULT;
964 return -1;
967 if (sess->state != GG_STATE_CONNECTED) {
968 errno = ENOTCONN;
969 return -1;
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
988 * 0, -1.
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) {
997 errno = EFAULT;
998 return -1;
1001 if (sess->state != GG_STATE_CONNECTED) {
1002 errno = ENOTCONN;
1003 return -1;
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
1023 * 0, -1.
1025 int gg_change_status_descr_time(struct gg_session *sess, int status, const char *descr, int time)
1027 struct gg_new_status p;
1028 uint32_t newtime;
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) {
1033 errno = EFAULT;
1034 return -1;
1037 if (sess->state != GG_STATE_CONNECTED) {
1038 errno = ENOTCONN;
1039 return -1;
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);
1052 * gg_logoff()
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)
1060 if (!sess)
1061 return;
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);
1068 #ifdef HAVE_OPENSSL
1069 if (sess->ssl)
1070 SSL_shutdown(sess->ssl);
1071 #elif HAVE_GNUTLS
1072 if (sess->session){
1073 gnutls_bye(sess->session, GNUTLS_SHUT_WR);
1074 gnutls_deinit(sess->session);
1076 #endif
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;
1084 #else
1085 if (sess->pid != -1) {
1086 waitpid(sess->pid, NULL, WNOHANG);
1087 sess->pid = -1;
1089 #endif
1091 if (sess->fd != -1) {
1092 shutdown(sess->fd, 2);
1093 close(sess->fd);
1094 sess->fd = -1;
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
1108 * 0/-1
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;
1114 char dummy = 0;
1115 int res;
1117 gg_debug(GG_DEBUG_FUNCTION, "** gg_image_request(%p, %d, %u, 0x%.4x);\n", sess, recipient, size, crc32);
1119 if (!sess) {
1120 errno = EFAULT;
1121 return -1;
1124 if (sess->state != GG_STATE_CONNECTED) {
1125 errno = ENOTCONN;
1126 return -1;
1129 s.recipient = gg_fix32(recipient);
1130 s.seq = gg_fix32(0);
1131 s.msgclass = gg_fix32(GG_CLASS_MSG);
1133 r.flag = 0x04;
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);
1139 if (!res) {
1140 struct gg_image_queue *q = malloc(sizeof(*q));
1141 char *buf = malloc(size);
1143 if (!q) {
1144 gg_debug(GG_DEBUG_MISC, "// gg_image_request() not enough memory for image queue\n");
1145 free(buf);
1146 errno = ENOMEM;
1147 return -1;
1150 memset(q, 0, sizeof(*q));
1152 q->sender = recipient;
1153 q->size = size;
1154 q->crc32 = crc32;
1155 q->image = buf;
1157 if (!sess->images)
1158 sess->images = q;
1159 else {
1160 struct gg_image_queue *qq;
1162 for (qq = sess->images; qq->next; qq = qq->next)
1165 qq->next = q;
1169 return res;
1173 * gg_image_reply()
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
1183 * 0/-1
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;
1189 const char *tmp;
1190 char buf[1910];
1191 int res = -1;
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) {
1196 errno = EFAULT;
1197 return -1;
1200 /* wytnij ¶cie¿ki, zostaw tylko nazwê pliku */
1201 while ((tmp = rindex(filename, '/')) || (tmp = rindex(filename, '\\')))
1202 filename = tmp + 1;
1204 if (strlen(filename) < 1 || strlen(filename) > 1024) {
1205 errno = EINVAL;
1206 return -1;
1209 if (sess->state != GG_STATE_CONNECTED) {
1210 errno = ENOTCONN;
1211 return -1;
1214 s.recipient = gg_fix32(recipient);
1215 s.seq = gg_fix32(0);
1216 s.msgclass = gg_fix32(GG_CLASS_MSG);
1218 buf[0] = 0;
1219 r = (void*) &buf[1];
1221 r->flag = 0x05;
1222 r->size = gg_fix32(size);
1223 r->crc32 = gg_fix32(gg_crc32(0, image, size));
1225 while (size > 0) {
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);
1240 size -= chunklen;
1241 image += chunklen;
1243 res = gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), buf, buflen + chunklen, NULL);
1245 if (res == -1)
1246 break;
1248 r->flag = 0x06;
1251 return res;
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);
1274 if (!sess) {
1275 errno = EFAULT;
1276 return -1;
1279 if (sess->state != GG_STATE_CONNECTED) {
1280 errno = ENOTCONN;
1281 return -1;
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);
1292 * gg_send_message()
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);
1332 if (!sess) {
1333 errno = EFAULT;
1334 return -1;
1337 if (sess->state != GG_STATE_CONNECTED) {
1338 errno = ENOTCONN;
1339 return -1;
1342 s.recipient = gg_fix32(recipient);
1343 if (!sess->seq)
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)
1350 return -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
1381 * potwierdzenia.
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;
1397 int i, j, k;
1398 uin_t *recps;
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);
1402 if (!sess) {
1403 errno = EFAULT;
1404 return -1;
1407 if (sess->state != GG_STATE_CONNECTED) {
1408 errno = ENOTCONN;
1409 return -1;
1412 r.flag = 0x01;
1413 r.count = gg_fix32(recipients_count - 1);
1415 if (!sess->seq)
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]);
1428 k++;
1431 if (!i)
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) {
1435 free(recps);
1436 return -1;
1440 free(recps);
1442 return gg_fix32(s.seq);
1446 * gg_ping()
1448 * wysy³a do serwera pakiet ping.
1450 * - sess - opis sesji
1452 * 0, -1.
1454 int gg_ping(struct gg_session *sess)
1456 gg_debug(GG_DEBUG_FUNCTION, "** gg_ping(%p);\n", sess);
1458 if (!sess) {
1459 errno = EFAULT;
1460 return -1;
1463 if (sess->state != GG_STATE_CONNECTED) {
1464 errno = ENOTCONN;
1465 return -1;
1468 return gg_send_packet(sess, GG_PING, NULL);
1472 * gg_notify_ex()
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
1482 * 0, -1.
1484 int gg_notify_ex(struct gg_session *sess, uin_t *userlist, char *types, int count)
1486 struct gg_notify *n;
1487 uin_t *u;
1488 char *t;
1489 int i, res = 0;
1491 gg_debug(GG_DEBUG_FUNCTION, "** gg_notify_ex(%p, %p, %p, %d);\n", sess, userlist, types, count);
1493 if (!sess) {
1494 errno = EFAULT;
1495 return -1;
1498 if (sess->state != GG_STATE_CONNECTED) {
1499 errno = ENOTCONN;
1500 return -1;
1503 if (!userlist || !count)
1504 return gg_send_packet(sess, GG_LIST_EMPTY, NULL);
1506 if (!(n = (struct gg_notify*) malloc(sizeof(*n) * count)))
1507 return -1;
1509 for (u = userlist, t = types, i = 0; i < count; u++, t++, i++) {
1510 n[i].uin = gg_fix32(*u);
1511 n[i].dunno1 = *t;
1514 if (gg_send_packet(sess, GG_NOTIFY, n, sizeof(*n) * count, NULL) == -1)
1515 res = -1;
1517 free(n);
1519 return res;
1523 * gg_notify()
1525 * wysy³a serwerowi listê kontaktów, dziêki czemu wie, czyj stan nas
1526 * interesuje.
1528 * - sess - opis sesji
1529 * - userlist - wska¼nik do tablicy numerów
1530 * - count - ilo¶æ numerków
1532 * 0, -1.
1534 int gg_notify(struct gg_session *sess, uin_t *userlist, int count)
1536 struct gg_notify *n;
1537 uin_t *u;
1538 int i, res = 0;
1540 gg_debug(GG_DEBUG_FUNCTION, "** gg_notify(%p, %p, %d);\n", sess, userlist, count);
1542 if (!sess) {
1543 errno = EFAULT;
1544 return -1;
1547 if (sess->state != GG_STATE_CONNECTED) {
1548 errno = ENOTCONN;
1549 return -1;
1552 if (!userlist || !count)
1553 return 0;
1555 if (!(n = (struct gg_notify*) malloc(sizeof(*n) * count)))
1556 return -1;
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)
1564 res = -1;
1566 free(n);
1568 return res;
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
1578 * - uin - numer
1579 * - type - typ
1581 * 0, -1.
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);
1589 if (!sess) {
1590 errno = EFAULT;
1591 return -1;
1594 if (sess->state != GG_STATE_CONNECTED) {
1595 errno = ENOTCONN;
1596 return -1;
1599 a.uin = gg_fix32(uin);
1600 a.dunno1 = type;
1602 return gg_send_packet(sess, GG_ADD_NOTIFY, &a, sizeof(a), NULL);
1606 * gg_add_notify()
1608 * dodaje do listy kontaktów dany numer w trakcie po³±czenia.
1610 * - sess - opis sesji
1611 * - uin - numer
1613 * 0, -1.
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
1627 * - uin - numer
1628 * - type - typ
1630 * 0, -1.
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);
1638 if (!sess) {
1639 errno = EFAULT;
1640 return -1;
1643 if (sess->state != GG_STATE_CONNECTED) {
1644 errno = ENOTCONN;
1645 return -1;
1648 a.uin = gg_fix32(uin);
1649 a.dunno1 = type;
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
1660 * - uin - numer
1662 * 0, -1.
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)
1678 * 0, -1
1680 int gg_userlist_request(struct gg_session *sess, char type, const char *request)
1682 int len;
1684 if (!sess) {
1685 errno = EINVAL;
1686 return -1;
1689 if (!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)
1702 return -1;
1704 if (type == GG_USERLIST_PUT)
1705 type = GG_USERLIST_PUT_MORE;
1707 request += 2047;
1708 len -= 2047;
1711 sess->userlist_blocks++;
1713 return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), request, len, NULL);
1717 * Local variables:
1718 * c-indentation-style: k&r
1719 * c-basic-offset: 8
1720 * indent-tabs-mode: notnil
1721 * End:
1723 * vim: shiftwidth=8: