src/protocols/gg/lib/libgadu.c

branch
gaim
changeset 20470
77693555855f
parent 13071
b98e72d4089a
parent 20469
b2836a24d81e
child 20471
1966704b3e42
equal deleted inserted replaced
13071:b98e72d4089a 20470:77693555855f
1 /* $Id: libgadu.c 14520 2005-11-25 00:32:45Z rlaager $ */
2
3 /*
4 * (C) Copyright 2001-2003 Wojtek Kaniewski <wojtekka@irc.pl>
5 * Robert J. Woźny <speedy@ziew.org>
6 * Arkadiusz Miśkiewicz <arekm@pld-linux.org>
7 * Tomasz Chiliński <chilek@chilan.com>
8 *
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.
12 *
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.
17 *
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
21 * USA.
22 */
23
24 #include <sys/types.h>
25 #ifndef _WIN32
26 #include <sys/wait.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #ifdef sun
31 # include <sys/filio.h>
32 #endif
33 #else
34 #include <io.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #define SHUT_RDWR SD_BOTH
38 #endif
39
40 #include "libgadu-config.h"
41
42 #include <errno.h>
43 #ifndef _WIN32
44 #include <netdb.h>
45 #endif
46 #ifdef __GG_LIBGADU_HAVE_PTHREAD
47 # include <pthread.h>
48 #endif
49 #include <stdarg.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54 #ifdef __GG_LIBGADU_HAVE_OPENSSL
55 # include <openssl/err.h>
56 # include <openssl/rand.h>
57 #endif
58
59 #include "compat.h"
60 #include "libgadu.h"
61
62 int gg_debug_level = 0;
63 void (*gg_debug_handler)(int level, const char *format, va_list ap) = NULL;
64
65 int gg_dcc_port = 0;
66 unsigned long gg_dcc_ip = 0;
67
68 unsigned long gg_local_ip = 0;
69 /*
70 * zmienne opisujące parametry proxy http.
71 */
72 char *gg_proxy_host = NULL;
73 int gg_proxy_port = 0;
74 int gg_proxy_enabled = 0;
75 int gg_proxy_http_only = 0;
76 char *gg_proxy_username = NULL;
77 char *gg_proxy_password = NULL;
78
79 #ifndef lint
80 static char rcsid[]
81 #ifdef __GNUC__
82 __attribute__ ((unused))
83 #endif
84 = "$Id: libgadu.c 14520 2005-11-25 00:32:45Z rlaager $";
85 #endif
86
87 #ifdef _WIN32
88 /**
89 * Deal with the fact that you can't select() on a win32 file fd.
90 * This makes it practically impossible to tie into gaim's event loop.
91 *
92 * -This is thanks to Tor Lillqvist.
93 * XXX - Move this to where the rest of the the win32 compatiblity stuff goes when we push the changes back to libgadu.
94 */
95 static int
96 socket_pipe (int *fds)
97 {
98 SOCKET temp, socket1 = -1, socket2 = -1;
99 struct sockaddr_in saddr;
100 int len;
101 u_long arg;
102 fd_set read_set, write_set;
103 struct timeval tv;
104
105 temp = socket(AF_INET, SOCK_STREAM, 0);
106
107 if (temp == INVALID_SOCKET) {
108 goto out0;
109 }
110
111 arg = 1;
112 if (ioctlsocket(temp, FIONBIO, &arg) == SOCKET_ERROR) {
113 goto out0;
114 }
115
116 memset(&saddr, 0, sizeof(saddr));
117 saddr.sin_family = AF_INET;
118 saddr.sin_port = 0;
119 saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
120
121 if (bind(temp, (struct sockaddr *)&saddr, sizeof (saddr))) {
122 goto out0;
123 }
124
125 if (listen(temp, 1) == SOCKET_ERROR) {
126 goto out0;
127 }
128
129 len = sizeof(saddr);
130 if (getsockname(temp, (struct sockaddr *)&saddr, &len)) {
131 goto out0;
132 }
133
134 socket1 = socket(AF_INET, SOCK_STREAM, 0);
135
136 if (socket1 == INVALID_SOCKET) {
137 goto out0;
138 }
139
140 arg = 1;
141 if (ioctlsocket(socket1, FIONBIO, &arg) == SOCKET_ERROR) {
142 goto out1;
143 }
144
145 if (connect(socket1, (struct sockaddr *)&saddr, len) != SOCKET_ERROR ||
146 WSAGetLastError() != WSAEWOULDBLOCK) {
147 goto out1;
148 }
149
150 FD_ZERO(&read_set);
151 FD_SET(temp, &read_set);
152
153 tv.tv_sec = 0;
154 tv.tv_usec = 0;
155
156 if (select(0, &read_set, NULL, NULL, NULL) == SOCKET_ERROR) {
157 goto out1;
158 }
159
160 if (!FD_ISSET(temp, &read_set)) {
161 goto out1;
162 }
163
164 socket2 = accept(temp, (struct sockaddr *) &saddr, &len);
165 if (socket2 == INVALID_SOCKET) {
166 goto out1;
167 }
168
169 FD_ZERO(&write_set);
170 FD_SET(socket1, &write_set);
171
172 tv.tv_sec = 0;
173 tv.tv_usec = 0;
174
175 if (select(0, NULL, &write_set, NULL, NULL) == SOCKET_ERROR) {
176 goto out2;
177 }
178
179 if (!FD_ISSET(socket1, &write_set)) {
180 goto out2;
181 }
182
183 arg = 0;
184 if (ioctlsocket(socket1, FIONBIO, &arg) == SOCKET_ERROR) {
185 goto out2;
186 }
187
188 arg = 0;
189 if (ioctlsocket(socket2, FIONBIO, &arg) == SOCKET_ERROR) {
190 goto out2;
191 }
192
193 fds[0] = socket1;
194 fds[1] = socket2;
195
196 closesocket (temp);
197
198 return 0;
199
200 out2:
201 closesocket (socket2);
202 out1:
203 closesocket (socket1);
204 out0:
205 closesocket (temp);
206 errno = EIO; /* XXX */
207
208 return -1;
209 }
210 #endif
211
212 /*
213 * gg_libgadu_version()
214 *
215 * zwraca wersję libgadu.
216 *
217 * - brak
218 *
219 * wersja libgadu.
220 */
221 const char *gg_libgadu_version()
222 {
223 return GG_LIBGADU_VERSION;
224 }
225
226 /*
227 * gg_fix32()
228 *
229 * zamienia kolejność bajtów w liczbie 32-bitowej tak, by odpowiadała
230 * kolejności bajtów w protokole GG. ze względu na LE-owość serwera,
231 * zamienia tylko na maszynach BE-wych.
232 *
233 * - x - liczba do zamiany
234 *
235 * liczba z odpowiednią kolejnością bajtów.
236 */
237 uint32_t gg_fix32(uint32_t x)
238 {
239 #ifndef __GG_LIBGADU_BIGENDIAN
240 return x;
241 #else
242 return (uint32_t)
243 (((x & (uint32_t) 0x000000ffU) << 24) |
244 ((x & (uint32_t) 0x0000ff00U) << 8) |
245 ((x & (uint32_t) 0x00ff0000U) >> 8) |
246 ((x & (uint32_t) 0xff000000U) >> 24));
247 #endif
248 }
249
250 /*
251 * gg_fix16()
252 *
253 * zamienia kolejność bajtów w liczbie 16-bitowej tak, by odpowiadała
254 * kolejności bajtów w protokole GG. ze względu na LE-owość serwera,
255 * zamienia tylko na maszynach BE-wych.
256 *
257 * - x - liczba do zamiany
258 *
259 * liczba z odpowiednią kolejnością bajtów.
260 */
261 uint16_t gg_fix16(uint16_t x)
262 {
263 #ifndef __GG_LIBGADU_BIGENDIAN
264 return x;
265 #else
266 return (uint16_t)
267 (((x & (uint16_t) 0x00ffU) << 8) |
268 ((x & (uint16_t) 0xff00U) >> 8));
269 #endif
270 }
271
272 /*
273 * gg_login_hash() // funkcja wewnętrzna
274 *
275 * liczy hash z hasła i danego seeda.
276 *
277 * - password - hasło do hashowania
278 * - seed - wartość podana przez serwer
279 *
280 * hash.
281 */
282 unsigned int gg_login_hash(const unsigned char *password, unsigned int seed)
283 {
284 unsigned int x, y, z;
285
286 y = seed;
287
288 for (x = 0; *password; password++) {
289 x = (x & 0xffffff00) | *password;
290 y ^= x;
291 y += x;
292 x <<= 8;
293 y ^= x;
294 x <<= 8;
295 y -= x;
296 x <<= 8;
297 y ^= x;
298
299 z = y & 0x1F;
300 y = (y << z) | (y >> (32 - z));
301 }
302
303 return y;
304 }
305
306 #ifndef _WIN32
307
308 /*
309 * gg_resolve() // funkcja wewnętrzna
310 *
311 * tworzy potok, forkuje się i w drugim procesie zaczyna resolvować
312 * podanego hosta. zapisuje w sesji deskryptor potoku. jeśli coś tam
313 * będzie gotowego, znaczy, że można wczytać struct in_addr. jeśli
314 * nie znajdzie, zwraca INADDR_NONE.
315 *
316 * - fd - wskaźnik gdzie wrzucić deskryptor
317 * - pid - gdzie wrzucić pid procesu potomnego
318 * - hostname - nazwa hosta do zresolvowania
319 *
320 * 0, -1.
321 */
322 int gg_resolve(int *fd, int *pid, const char *hostname)
323 {
324 int pipes[2], res;
325 struct in_addr a;
326 int errno2;
327
328 gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve(%p, %p, \"%s\");\n", fd, pid, hostname);
329
330 if (!fd || !pid) {
331 errno = EFAULT;
332 return -1;
333 }
334
335 if (pipe(pipes) == -1)
336 return -1;
337
338 if ((res = fork()) == -1) {
339 errno2 = errno;
340 close(pipes[0]);
341 close(pipes[1]);
342 errno = errno2;
343 return -1;
344 }
345
346 if (!res) {
347 if ((a.s_addr = inet_addr(hostname)) == INADDR_NONE) {
348 struct in_addr *hn;
349
350 if (!(hn = gg_gethostbyname(hostname)))
351 a.s_addr = INADDR_NONE;
352 else {
353 a.s_addr = hn->s_addr;
354 free(hn);
355 }
356 }
357
358 write(pipes[1], &a, sizeof(a));
359
360 exit(0);
361 }
362
363 close(pipes[1]);
364
365 *fd = pipes[0];
366 *pid = res;
367
368 return 0;
369 }
370 #endif
371
372 #ifdef __GG_LIBGADU_HAVE_PTHREAD
373
374 struct gg_resolve_pthread_data {
375 char *hostname;
376 int fd;
377 };
378
379 static void *gg_resolve_pthread_thread(void *arg)
380 {
381 struct gg_resolve_pthread_data *d = arg;
382 struct in_addr a;
383
384 pthread_detach(pthread_self());
385
386 if ((a.s_addr = inet_addr(d->hostname)) == INADDR_NONE) {
387 struct in_addr *hn;
388
389 if (!(hn = gg_gethostbyname(d->hostname)))
390 a.s_addr = INADDR_NONE;
391 else {
392 a.s_addr = hn->s_addr;
393 free(hn);
394 }
395 }
396
397 write(d->fd, &a, sizeof(a));
398 close(d->fd);
399
400 free(d->hostname);
401 d->hostname = NULL;
402
403 free(d);
404
405 pthread_exit(NULL);
406
407 return NULL; /* żeby kompilator nie marudził */
408 }
409
410 /*
411 * gg_resolve_pthread() // funkcja wewnętrzna
412 *
413 * tworzy potok, nowy wątek i w nim zaczyna resolvować podanego hosta.
414 * zapisuje w sesji deskryptor potoku. jeśli coś tam będzie gotowego,
415 * znaczy, że można wczytać struct in_addr. jeśli nie znajdzie, zwraca
416 * INADDR_NONE.
417 *
418 * - fd - wskaźnik do zmiennej przechowującej desktyptor resolvera
419 * - resolver - wskaźnik do wskaźnika resolvera
420 * - hostname - nazwa hosta do zresolvowania
421 *
422 * 0, -1.
423 */
424 int gg_resolve_pthread(int *fd, void **resolver, const char *hostname)
425 {
426 struct gg_resolve_pthread_data *d = NULL;
427 pthread_t *tmp;
428 int pipes[2], new_errno;
429
430 gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve_pthread(%p, %p, \"%s\");\n", fd, resolver, hostname);
431
432 if (!resolver || !fd || !hostname) {
433 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() invalid arguments\n");
434 errno = EFAULT;
435 return -1;
436 }
437
438 if (!(tmp = malloc(sizeof(pthread_t)))) {
439 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory for pthread id\n");
440 return -1;
441 }
442
443 if (pipe(pipes) == -1) {
444 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno));
445 free(tmp);
446 return -1;
447 }
448
449 if (!(d = malloc(sizeof(*d)))) {
450 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory\n");
451 new_errno = errno;
452 goto cleanup;
453 }
454
455 d->hostname = NULL;
456
457 if (!(d->hostname = strdup(hostname))) {
458 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory\n");
459 new_errno = errno;
460 goto cleanup;
461 }
462
463 d->fd = pipes[1];
464
465 if (pthread_create(tmp, NULL, gg_resolve_pthread_thread, d)) {
466 gg_debug(GG_DEBUG_MISC, "// gg_resolve_phread() unable to create thread\n");
467 new_errno = errno;
468 goto cleanup;
469 }
470
471 gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() %p\n", tmp);
472
473 *resolver = tmp;
474
475 *fd = pipes[0];
476
477 return 0;
478
479 cleanup:
480 if (d) {
481 free(d->hostname);
482 free(d);
483 }
484
485 close(pipes[0]);
486 close(pipes[1]);
487
488 free(tmp);
489
490 errno = new_errno;
491
492 return -1;
493 }
494
495 #elif defined _WIN32
496
497 struct gg_resolve_win32thread_data {
498 char *hostname;
499 int fd;
500 };
501
502 static DWORD WINAPI gg_resolve_win32thread_thread(LPVOID arg)
503 {
504 struct gg_resolve_win32thread_data *d = arg;
505 struct in_addr a;
506
507 if ((a.s_addr = inet_addr(d->hostname)) == INADDR_NONE) {
508 struct in_addr *hn;
509
510 if (!(hn = gg_gethostbyname(d->hostname)))
511 a.s_addr = INADDR_NONE;
512 else {
513 a.s_addr = hn->s_addr;
514 free(hn);
515 }
516 }
517
518 write(d->fd, &a, sizeof(a));
519 close(d->fd);
520
521 free(d->hostname);
522 d->hostname = NULL;
523
524 free(d);
525
526 return 0;
527 }
528
529
530 int gg_resolve_win32thread(int *fd, void **resolver, const char *hostname)
531 {
532 struct gg_resolve_win32thread_data *d = NULL;
533 HANDLE h;
534 DWORD dwTId;
535 int pipes[2], new_errno;
536
537 gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve_win32thread(%p, %p, \"%s\");\n", fd, resolver, hostname);
538
539 if (!resolver || !fd || !hostname) {
540 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() invalid arguments\n");
541 errno = EFAULT;
542 return -1;
543 }
544
545 if (socket_pipe(pipes) == -1) {
546 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() unable to create pipes (errno=%d, %s)\n", errno, strerror(errno));
547 return -1;
548 }
549
550 if (!(d = malloc(sizeof(*d)))) {
551 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() out of memory\n");
552 new_errno = GetLastError();
553 goto cleanup;
554 }
555
556 d->hostname = NULL;
557
558 if (!(d->hostname = strdup(hostname))) {
559 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() out of memory\n");
560 new_errno = GetLastError();
561 goto cleanup;
562 }
563
564 d->fd = pipes[1];
565
566 h = CreateThread(NULL, 0, gg_resolve_win32thread_thread,
567 d, 0, &dwTId);
568
569 if (h == NULL) {
570 gg_debug(GG_DEBUG_MISC, "// gg_resolve_win32thread() unable to create thread\n");
571 new_errno = GetLastError();
572 goto cleanup;
573 }
574
575 *resolver = h;
576 *fd = pipes[0];
577
578 return 0;
579
580 cleanup:
581 if (d) {
582 free(d->hostname);
583 free(d);
584 }
585
586 close(pipes[0]);
587 close(pipes[1]);
588
589 errno = new_errno;
590
591 return -1;
592
593 }
594 #endif
595
596 /*
597 * gg_read() // funkcja pomocnicza
598 *
599 * czyta z gniazda określoną ilość bajtów. bierze pod uwagę, czy mamy
600 * połączenie zwykłe czy TLS.
601 *
602 * - sess - sesja,
603 * - buf - bufor,
604 * - length - ilość bajtów,
605 *
606 * takie same wartości jak read().
607 */
608 int gg_read(struct gg_session *sess, char *buf, int length)
609 {
610 int res;
611
612 #ifdef __GG_LIBGADU_HAVE_OPENSSL
613 if (sess->ssl) {
614 int err;
615
616 res = SSL_read(sess->ssl, buf, length);
617
618 if (res < 0) {
619 err = SSL_get_error(sess->ssl, res);
620
621 if (err == SSL_ERROR_WANT_READ)
622 errno = EAGAIN;
623
624 return -1;
625 }
626 } else
627 #endif
628 res = read(sess->fd, buf, length);
629
630 return res;
631 }
632
633 /*
634 * gg_write() // funkcja pomocnicza
635 *
636 * zapisuje do gniazda określoną ilość bajtów. bierze pod uwagę, czy mamy
637 * połączenie zwykłe czy TLS.
638 *
639 * - sess - sesja,
640 * - buf - bufor,
641 * - length - ilość bajtów,
642 *
643 * takie same wartości jak write().
644 */
645 int gg_write(struct gg_session *sess, const char *buf, int length)
646 {
647 int res = 0;
648
649 #ifdef __GG_LIBGADU_HAVE_OPENSSL
650 if (sess->ssl) {
651 int err;
652
653 res = SSL_write(sess->ssl, buf, length);
654
655 if (res < 0) {
656 err = SSL_get_error(sess->ssl, res);
657
658 if (err == SSL_ERROR_WANT_WRITE)
659 errno = EAGAIN;
660
661 return -1;
662 }
663 } else
664 #endif
665 {
666 int written = 0;
667
668 while (written < length) {
669 res = write(sess->fd, buf + written, length - written);
670
671 if (res == -1) {
672 if (errno == EAGAIN)
673 continue;
674 else
675 break;
676 } else {
677 written += res;
678 res = written;
679 }
680 }
681 }
682
683 return res;
684 }
685
686 /*
687 * gg_recv_packet() // funkcja wewnętrzna
688 *
689 * odbiera jeden pakiet i zwraca wskaźnik do niego. pamięć po nim
690 * należy zwolnić za pomocą free().
691 *
692 * - sess - opis sesji
693 *
694 * w przypadku błędu NULL, kod błędu w errno. należy zwrócić uwagę, że gdy
695 * połączenie jest nieblokujące, a kod błędu wynosi EAGAIN, nie udało się
696 * odczytać całego pakietu i nie należy tego traktować jako błąd.
697 */
698 void *gg_recv_packet(struct gg_session *sess)
699 {
700 struct gg_header h;
701 char *buf = NULL;
702 int ret = 0, offset, size = 0;
703
704 gg_debug(GG_DEBUG_FUNCTION, "** gg_recv_packet(%p);\n", sess);
705
706 if (!sess) {
707 errno = EFAULT;
708 return NULL;
709 }
710
711 if (sess->recv_left < 1) {
712 if (sess->header_buf) {
713 memcpy(&h, sess->header_buf, sess->header_done);
714 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv: resuming last read (%d bytes left)\n", sizeof(h) - sess->header_done);
715 free(sess->header_buf);
716 sess->header_buf = NULL;
717 } else
718 sess->header_done = 0;
719
720 while (sess->header_done < sizeof(h)) {
721 ret = gg_read(sess, (char*) &h + sess->header_done, sizeof(h) - sess->header_done);
722
723 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);
724
725 if (!ret) {
726 errno = ECONNRESET;
727 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: connection broken\n");
728 return NULL;
729 }
730
731 if (ret == -1) {
732 if (errno == EINTR) {
733 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() interrupted system call, resuming\n");
734 continue;
735 }
736
737 if (errno == EAGAIN) {
738 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() incomplete header received\n");
739
740 if (!(sess->header_buf = malloc(sess->header_done))) {
741 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() not enough memory\n");
742 return NULL;
743 }
744
745 memcpy(sess->header_buf, &h, sess->header_done);
746
747 return NULL;
748 }
749
750 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: errno=%d, %s\n", errno, strerror(errno));
751
752 return NULL;
753 }
754
755 sess->header_done += ret;
756
757 }
758
759 h.type = gg_fix32(h.type);
760 h.length = gg_fix32(h.length);
761 } else
762 memcpy(&h, sess->recv_buf, sizeof(h));
763
764 /* jakieś sensowne limity na rozmiar pakietu */
765 if (h.length > 65535) {
766 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() invalid packet length (%d)\n", h.length);
767 errno = ERANGE;
768 return NULL;
769 }
770
771 if (sess->recv_left > 0) {
772 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() resuming last gg_recv_packet()\n");
773 size = sess->recv_left;
774 offset = sess->recv_done;
775 buf = sess->recv_buf;
776 } else {
777 if (!(buf = malloc(sizeof(h) + h.length + 1))) {
778 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() not enough memory for packet data\n");
779 return NULL;
780 }
781
782 memcpy(buf, &h, sizeof(h));
783
784 offset = 0;
785 size = h.length;
786 }
787
788 while (size > 0) {
789 ret = gg_read(sess, buf + sizeof(h) + offset, size);
790 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv(%d,%p,%d) = %d\n", sess->fd, buf + sizeof(h) + offset, size, ret);
791 if (!ret) {
792 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed: connection broken\n");
793 errno = ECONNRESET;
794 return NULL;
795 }
796 if (ret > -1 && ret <= size) {
797 offset += ret;
798 size -= ret;
799 } else if (ret == -1) {
800 int errno2 = errno;
801
802 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed (errno=%d, %s)\n", errno, strerror(errno));
803 errno = errno2;
804
805 if (errno == EAGAIN) {
806 gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() %d bytes received, %d left\n", offset, size);
807 sess->recv_buf = buf;
808 sess->recv_left = size;
809 sess->recv_done = offset;
810 return NULL;
811 }
812 if (errno != EINTR) {
813 free(buf);
814 return NULL;
815 }
816 }
817 }
818
819 sess->recv_left = 0;
820
821 if ((gg_debug_level & GG_DEBUG_DUMP)) {
822 unsigned int i;
823
824 gg_debug(GG_DEBUG_DUMP, "// gg_recv_packet(%.2x)", h.type);
825 for (i = 0; i < sizeof(h) + h.length; i++)
826 gg_debug(GG_DEBUG_DUMP, " %.2x", (unsigned char) buf[i]);
827 gg_debug(GG_DEBUG_DUMP, "\n");
828 }
829
830 return buf;
831 }
832
833 /*
834 * gg_send_packet() // funkcja wewnętrzna
835 *
836 * konstruuje pakiet i wysyła go do serwera.
837 *
838 * - sock - deskryptor gniazda
839 * - type - typ pakietu
840 * - payload_1 - pierwsza część pakietu
841 * - payload_length_1 - długość pierwszej części
842 * - payload_2 - druga część pakietu
843 * - payload_length_2 - długość drugiej części
844 * - ... - kolejne części pakietu i ich długości
845 * - NULL - końcowym parametr (konieczny!)
846 *
847 * jeśli się powiodło, zwraca 0, w przypadku błędu -1. jeśli errno == ENOMEM,
848 * zabrakło pamięci. inaczej był błąd przy wysyłaniu pakietu. dla errno == 0
849 * nie wysłano całego pakietu.
850 */
851 int gg_send_packet(struct gg_session *sess, int type, ...)
852 {
853 struct gg_header *h;
854 char *tmp;
855 int tmp_length;
856 void *payload;
857 unsigned int payload_length;
858 va_list ap;
859 int res;
860
861 gg_debug(GG_DEBUG_FUNCTION, "** gg_send_packet(%p, 0x%.2x, ...)\n", sess, type);
862
863 tmp_length = sizeof(struct gg_header);
864
865 if (!(tmp = malloc(tmp_length))) {
866 gg_debug(GG_DEBUG_MISC, "// gg_send_packet() not enough memory for packet header\n");
867 return -1;
868 }
869
870 va_start(ap, type);
871
872 payload = va_arg(ap, void *);
873
874 while (payload) {
875 char *tmp2;
876
877 payload_length = va_arg(ap, unsigned int);
878
879 if (!(tmp2 = realloc(tmp, tmp_length + payload_length))) {
880 gg_debug(GG_DEBUG_MISC, "// gg_send_packet() not enough memory for payload\n");
881 free(tmp);
882 va_end(ap);
883 return -1;
884 }
885
886 tmp = tmp2;
887
888 memcpy(tmp + tmp_length, payload, payload_length);
889 tmp_length += payload_length;
890
891 payload = va_arg(ap, void *);
892 }
893
894 va_end(ap);
895
896 h = (struct gg_header*) tmp;
897 h->type = gg_fix32(type);
898 h->length = gg_fix32(tmp_length - sizeof(struct gg_header));
899
900 if ((gg_debug_level & GG_DEBUG_DUMP)) {
901 int i;
902
903 gg_debug(GG_DEBUG_DUMP, "// gg_send_packet(0x%.2x)", gg_fix32(h->type));
904 for (i = 0; i < tmp_length; ++i)
905 gg_debug(GG_DEBUG_DUMP, " %.2x", (unsigned char) tmp[i]);
906 gg_debug(GG_DEBUG_DUMP, "\n");
907 }
908
909 if ((res = gg_write(sess, tmp, tmp_length)) < tmp_length) {
910 gg_debug(GG_DEBUG_MISC, "// gg_send_packet() write() failed. res = %d, errno = %d (%s)\n", res, errno, strerror(errno));
911 free(tmp);
912 return -1;
913 }
914
915 free(tmp);
916 return 0;
917 }
918
919 /*
920 * gg_session_callback() // funkcja wewnętrzna
921 *
922 * wywoływany z gg_session->callback, wykonuje gg_watch_fd() i pakuje
923 * do gg_session->event jego wynik.
924 */
925 static int gg_session_callback(struct gg_session *s)
926 {
927 if (!s) {
928 errno = EFAULT;
929 return -1;
930 }
931
932 return ((s->event = gg_watch_fd(s)) != NULL) ? 0 : -1;
933 }
934
935 /*
936 * gg_login()
937 *
938 * rozpoczyna procedurę łączenia się z serwerem. resztę obsługuje się przez
939 * gg_watch_fd().
940 *
941 * UWAGA! program musi obsłużyć SIGCHLD, jeśli łączy się asynchronicznie,
942 * żeby poprawnie zamknąć proces resolvera.
943 *
944 * - p - struktura opisująca początkowy stan. wymagane pola: uin,
945 * password
946 *
947 * w przypadku błędu NULL, jeśli idzie dobrze (async) albo poszło
948 * dobrze (sync), zwróci wskaźnik do zaalokowanej struct gg_session.
949 */
950 struct gg_session *gg_login(const struct gg_login_params *p)
951 {
952 struct gg_session *sess = NULL;
953 char *hostname;
954 int port;
955
956 if (!p) {
957 gg_debug(GG_DEBUG_FUNCTION, "** gg_login(%p);\n", p);
958 errno = EFAULT;
959 return NULL;
960 }
961
962 gg_debug(GG_DEBUG_FUNCTION, "** gg_login(%p: [uin=%u, async=%d, ...]);\n", p, p->uin, p->async);
963
964 if (!(sess = malloc(sizeof(struct gg_session)))) {
965 gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for session data\n");
966 goto fail;
967 }
968
969 memset(sess, 0, sizeof(struct gg_session));
970
971 if (!p->password || !p->uin) {
972 gg_debug(GG_DEBUG_MISC, "// gg_login() invalid arguments. uin and password needed\n");
973 errno = EFAULT;
974 goto fail;
975 }
976
977 if (!(sess->password = strdup(p->password))) {
978 gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for password\n");
979 goto fail;
980 }
981
982 if (p->status_descr && !(sess->initial_descr = strdup(p->status_descr))) {
983 gg_debug(GG_DEBUG_MISC, "// gg_login() not enough memory for status\n");
984 goto fail;
985 }
986
987 sess->uin = p->uin;
988 sess->state = GG_STATE_RESOLVING;
989 sess->check = GG_CHECK_READ;
990 sess->timeout = GG_DEFAULT_TIMEOUT;
991 sess->async = p->async;
992 sess->type = GG_SESSION_GG;
993 sess->initial_status = p->status;
994 sess->callback = gg_session_callback;
995 sess->destroy = gg_free_session;
996 sess->port = (p->server_port) ? p->server_port : ((gg_proxy_enabled) ? GG_HTTPS_PORT : GG_DEFAULT_PORT);
997 sess->server_addr = p->server_addr;
998 sess->external_port = p->external_port;
999 sess->external_addr = p->external_addr;
1000 sess->protocol_version = (p->protocol_version) ? p->protocol_version : GG_DEFAULT_PROTOCOL_VERSION;
1001 if (p->era_omnix)
1002 sess->protocol_version |= GG_ERA_OMNIX_MASK;
1003 if (p->has_audio)
1004 sess->protocol_version |= GG_HAS_AUDIO_MASK;
1005 sess->client_version = (p->client_version) ? strdup(p->client_version) : NULL;
1006 sess->last_sysmsg = p->last_sysmsg;
1007 sess->image_size = p->image_size;
1008 sess->pid = -1;
1009
1010 if (p->tls == 1) {
1011 #ifdef __GG_LIBGADU_HAVE_OPENSSL
1012 char buf[1024];
1013
1014 OpenSSL_add_ssl_algorithms();
1015
1016 if (!RAND_status()) {
1017 char rdata[1024];
1018 struct {
1019 time_t time;
1020 void *ptr;
1021 } rstruct;
1022
1023 time(&rstruct.time);
1024 rstruct.ptr = (void *) &rstruct;
1025
1026 RAND_seed((void *) rdata, sizeof(rdata));
1027 RAND_seed((void *) &rstruct, sizeof(rstruct));
1028 }
1029
1030 sess->ssl_ctx = SSL_CTX_new(TLSv1_client_method());
1031
1032 if (!sess->ssl_ctx) {
1033 ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
1034 gg_debug(GG_DEBUG_MISC, "// gg_login() SSL_CTX_new() failed: %s\n", buf);
1035 goto fail;
1036 }
1037
1038 SSL_CTX_set_verify(sess->ssl_ctx, SSL_VERIFY_NONE, NULL);
1039
1040 sess->ssl = SSL_new(sess->ssl_ctx);
1041
1042 if (!sess->ssl) {
1043 ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
1044 gg_debug(GG_DEBUG_MISC, "// gg_login() SSL_new() failed: %s\n", buf);
1045 goto fail;
1046 }
1047 #else
1048 gg_debug(GG_DEBUG_MISC, "// gg_login() client requested TLS but no support compiled in\n");
1049 #endif
1050 }
1051
1052 if (gg_proxy_enabled) {
1053 hostname = gg_proxy_host;
1054 sess->proxy_port = port = gg_proxy_port;
1055 } else {
1056 hostname = GG_APPMSG_HOST;
1057 port = GG_APPMSG_PORT;
1058 }
1059
1060 if (!p->async) {
1061 struct in_addr a;
1062
1063 if (!p->server_addr || !p->server_port) {
1064 if ((a.s_addr = inet_addr(hostname)) == INADDR_NONE) {
1065 struct in_addr *hn;
1066
1067 if (!(hn = gg_gethostbyname(hostname))) {
1068 gg_debug(GG_DEBUG_MISC, "// gg_login() host \"%s\" not found\n", hostname);
1069 goto fail;
1070 } else {
1071 a.s_addr = hn->s_addr;
1072 free(hn);
1073 }
1074 }
1075 } else {
1076 a.s_addr = p->server_addr;
1077 port = p->server_port;
1078 }
1079
1080 sess->hub_addr = a.s_addr;
1081
1082 if (gg_proxy_enabled)
1083 sess->proxy_addr = a.s_addr;
1084
1085 if ((sess->fd = gg_connect(&a, port, 0)) == -1) {
1086 gg_debug(GG_DEBUG_MISC, "// gg_login() connection failed (errno=%d, %s)\n", errno, strerror(errno));
1087 goto fail;
1088 }
1089
1090 if (p->server_addr && p->server_port)
1091 sess->state = GG_STATE_CONNECTING_GG;
1092 else
1093 sess->state = GG_STATE_CONNECTING_HUB;
1094
1095 while (sess->state != GG_STATE_CONNECTED) {
1096 struct gg_event *e;
1097
1098 if (!(e = gg_watch_fd(sess))) {
1099 gg_debug(GG_DEBUG_MISC, "// gg_login() critical error in gg_watch_fd()\n");
1100 goto fail;
1101 }
1102
1103 if (e->type == GG_EVENT_CONN_FAILED) {
1104 errno = EACCES;
1105 gg_debug(GG_DEBUG_MISC, "// gg_login() could not login\n");
1106 gg_event_free(e);
1107 goto fail;
1108 }
1109
1110 gg_event_free(e);
1111 }
1112
1113 return sess;
1114 }
1115
1116 if (!sess->server_addr || gg_proxy_enabled) {
1117 #ifdef __GG_LIBGADU_HAVE_PTHREAD
1118 if (gg_resolve_pthread(&sess->fd, &sess->resolver, hostname)) {
1119 #elif defined _WIN32
1120 if (gg_resolve_win32thread(&sess->fd, &sess->resolver, hostname)) {
1121 #else
1122 if (gg_resolve(&sess->fd, &sess->pid, hostname)) {
1123 #endif
1124 gg_debug(GG_DEBUG_MISC, "// gg_login() resolving failed (errno=%d, %s)\n", errno, strerror(errno));
1125 goto fail;
1126 }
1127 } else {
1128 if ((sess->fd = gg_connect(&sess->server_addr, sess->port, sess->async)) == -1) {
1129 gg_debug(GG_DEBUG_MISC, "// gg_login() direct connection failed (errno=%d, %s)\n", errno, strerror(errno));
1130 goto fail;
1131 }
1132 sess->state = GG_STATE_CONNECTING_GG;
1133 sess->check = GG_CHECK_WRITE;
1134 }
1135
1136 return sess;
1137
1138 fail:
1139 if (sess) {
1140 if (sess->password)
1141 free(sess->password);
1142 if (sess->initial_descr)
1143 free(sess->initial_descr);
1144 free(sess);
1145 }
1146
1147 return NULL;
1148 }
1149
1150 /*
1151 * gg_free_session()
1152 *
1153 * próbuje zamknąć połączenia i zwalnia pamięć zajmowaną przez sesję.
1154 *
1155 * - sess - opis sesji
1156 */
1157 void gg_free_session(struct gg_session *sess)
1158 {
1159 if (!sess)
1160 return;
1161
1162 /* XXX dopisać zwalnianie i zamykanie wszystkiego, co mogło zostać */
1163
1164 if (sess->password)
1165 free(sess->password);
1166
1167 if (sess->initial_descr)
1168 free(sess->initial_descr);
1169
1170 if (sess->client_version)
1171 free(sess->client_version);
1172
1173 if (sess->header_buf)
1174 free(sess->header_buf);
1175
1176 #ifdef __GG_LIBGADU_HAVE_OPENSSL
1177 if (sess->ssl)
1178 SSL_free(sess->ssl);
1179
1180 if (sess->ssl_ctx)
1181 SSL_CTX_free(sess->ssl_ctx);
1182 #endif
1183
1184 #ifdef __GG_LIBGADU_HAVE_PTHREAD
1185 if (sess->resolver) {
1186 pthread_cancel(*((pthread_t*) sess->resolver));
1187 free(sess->resolver);
1188 sess->resolver = NULL;
1189 }
1190 #elif defined _WIN32
1191 if (sess->resolver) {
1192 HANDLE h = sess->resolver;
1193 TerminateThread(h, 0);
1194 CloseHandle(h);
1195 sess->resolver = NULL;
1196 }
1197 #else
1198 if (sess->pid != -1)
1199 waitpid(sess->pid, NULL, WNOHANG);
1200 #endif
1201
1202 if (sess->fd != -1)
1203 close(sess->fd);
1204
1205 while (sess->images)
1206 gg_image_queue_remove(sess, sess->images, 1);
1207
1208 free(sess);
1209 }
1210
1211 /*
1212 * gg_change_status()
1213 *
1214 * zmienia status użytkownika. przydatne do /away i /busy oraz /quit.
1215 *
1216 * - sess - opis sesji
1217 * - status - nowy status użytkownika
1218 *
1219 * 0, -1.
1220 */
1221 int gg_change_status(struct gg_session *sess, int status)
1222 {
1223 struct gg_new_status p;
1224
1225 gg_debug(GG_DEBUG_FUNCTION, "** gg_change_status(%p, %d);\n", sess, status);
1226
1227 if (!sess) {
1228 errno = EFAULT;
1229 return -1;
1230 }
1231
1232 if (sess->state != GG_STATE_CONNECTED) {
1233 errno = ENOTCONN;
1234 return -1;
1235 }
1236
1237 p.status = gg_fix32(status);
1238
1239 sess->status = status;
1240
1241 return gg_send_packet(sess, GG_NEW_STATUS, &p, sizeof(p), NULL);
1242 }
1243
1244 /*
1245 * gg_change_status_descr()
1246 *
1247 * zmienia status użytkownika na opisowy.
1248 *
1249 * - sess - opis sesji
1250 * - status - nowy status użytkownika
1251 * - descr - opis statusu
1252 *
1253 * 0, -1.
1254 */
1255 int gg_change_status_descr(struct gg_session *sess, int status, const char *descr)
1256 {
1257 struct gg_new_status p;
1258
1259 gg_debug(GG_DEBUG_FUNCTION, "** gg_change_status_descr(%p, %d, \"%s\");\n", sess, status, descr);
1260
1261 if (!sess || !descr) {
1262 errno = EFAULT;
1263 return -1;
1264 }
1265
1266 if (sess->state != GG_STATE_CONNECTED) {
1267 errno = ENOTCONN;
1268 return -1;
1269 }
1270
1271 p.status = gg_fix32(status);
1272
1273 sess->status = status;
1274
1275 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);
1276 }
1277
1278 /*
1279 * gg_change_status_descr_time()
1280 *
1281 * zmienia status użytkownika na opisowy z godziną powrotu.
1282 *
1283 * - sess - opis sesji
1284 * - status - nowy status użytkownika
1285 * - descr - opis statusu
1286 * - time - czas w formacie uniksowym
1287 *
1288 * 0, -1.
1289 */
1290 int gg_change_status_descr_time(struct gg_session *sess, int status, const char *descr, int time)
1291 {
1292 struct gg_new_status p;
1293 uint32_t newtime;
1294
1295 gg_debug(GG_DEBUG_FUNCTION, "** gg_change_status_descr_time(%p, %d, \"%s\", %d);\n", sess, status, descr, time);
1296
1297 if (!sess || !descr || !time) {
1298 errno = EFAULT;
1299 return -1;
1300 }
1301
1302 if (sess->state != GG_STATE_CONNECTED) {
1303 errno = ENOTCONN;
1304 return -1;
1305 }
1306
1307 p.status = gg_fix32(status);
1308
1309 sess->status = status;
1310
1311 newtime = gg_fix32(time);
1312
1313 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);
1314 }
1315
1316 /*
1317 * gg_logoff()
1318 *
1319 * wylogowuje użytkownika i zamyka połączenie, ale nie zwalnia pamięci.
1320 *
1321 * - sess - opis sesji
1322 */
1323 void gg_logoff(struct gg_session *sess)
1324 {
1325 if (!sess)
1326 return;
1327
1328 gg_debug(GG_DEBUG_FUNCTION, "** gg_logoff(%p);\n", sess);
1329
1330 if (GG_S_NA(sess->status & ~GG_STATUS_FRIENDS_MASK))
1331 gg_change_status(sess, GG_STATUS_NOT_AVAIL);
1332
1333 #ifdef __GG_LIBGADU_HAVE_OPENSSL
1334 if (sess->ssl)
1335 SSL_shutdown(sess->ssl);
1336 #endif
1337
1338 #ifdef __GG_LIBGADU_HAVE_PTHREAD
1339 if (sess->resolver) {
1340 pthread_cancel(*((pthread_t*) sess->resolver));
1341 free(sess->resolver);
1342 sess->resolver = NULL;
1343 }
1344 #elif defined _WIN32
1345 if (sess->resolver) {
1346 HANDLE h = sess->resolver;
1347 TerminateThread(h, 0);
1348 CloseHandle(h);
1349 sess->resolver = NULL;
1350 }
1351 #else
1352 if (sess->pid != -1) {
1353 waitpid(sess->pid, NULL, WNOHANG);
1354 sess->pid = -1;
1355 }
1356 #endif
1357
1358 if (sess->fd != -1) {
1359 shutdown(sess->fd, SHUT_RDWR);
1360 close(sess->fd);
1361 sess->fd = -1;
1362 }
1363 }
1364
1365 /*
1366 * gg_image_request()
1367 *
1368 * wysyła żądanie wysłania obrazka o podanych parametrach.
1369 *
1370 * - sess - opis sesji
1371 * - recipient - numer adresata
1372 * - size - rozmiar obrazka
1373 * - crc32 - suma kontrolna obrazka
1374 *
1375 * 0/-1
1376 */
1377 int gg_image_request(struct gg_session *sess, uin_t recipient, int size, uint32_t crc32)
1378 {
1379 struct gg_send_msg s;
1380 struct gg_msg_image_request r;
1381 char dummy = 0;
1382 int res;
1383
1384 gg_debug(GG_DEBUG_FUNCTION, "** gg_image_request(%p, %d, %u, 0x%.4x);\n", sess, recipient, size, crc32);
1385
1386 if (!sess) {
1387 errno = EFAULT;
1388 return -1;
1389 }
1390
1391 if (sess->state != GG_STATE_CONNECTED) {
1392 errno = ENOTCONN;
1393 return -1;
1394 }
1395
1396 if (size < 0) {
1397 errno = EINVAL;
1398 return -1;
1399 }
1400
1401 s.recipient = gg_fix32(recipient);
1402 s.seq = gg_fix32(0);
1403 s.msgclass = gg_fix32(GG_CLASS_MSG);
1404
1405 r.flag = 0x04;
1406 r.size = gg_fix32(size);
1407 r.crc32 = gg_fix32(crc32);
1408
1409 res = gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), &dummy, 1, &r, sizeof(r), NULL);
1410
1411 if (!res) {
1412 struct gg_image_queue *q = malloc(sizeof(*q));
1413 char *buf;
1414
1415 if (!q) {
1416 gg_debug(GG_DEBUG_MISC, "// gg_image_request() not enough memory for image queue\n");
1417 return -1;
1418 }
1419
1420 buf = malloc(size);
1421 if (size && !buf)
1422 {
1423 gg_debug(GG_DEBUG_MISC, "// gg_image_request() not enough memory for image\n");
1424 free(q);
1425 return -1;
1426 }
1427
1428 memset(q, 0, sizeof(*q));
1429
1430 q->sender = recipient;
1431 q->size = size;
1432 q->crc32 = crc32;
1433 q->image = buf;
1434
1435 if (!sess->images)
1436 sess->images = q;
1437 else {
1438 struct gg_image_queue *qq;
1439
1440 for (qq = sess->images; qq->next; qq = qq->next)
1441 ;
1442
1443 qq->next = q;
1444 }
1445 }
1446
1447 return res;
1448 }
1449
1450 /*
1451 * gg_image_reply()
1452 *
1453 * wysyła żądany obrazek.
1454 *
1455 * - sess - opis sesji
1456 * - recipient - numer adresata
1457 * - filename - nazwa pliku
1458 * - image - bufor z obrazkiem
1459 * - size - rozmiar obrazka
1460 *
1461 * 0/-1
1462 */
1463 int gg_image_reply(struct gg_session *sess, uin_t recipient, const char *filename, const unsigned char *image, int size)
1464 {
1465 struct gg_msg_image_reply *r;
1466 struct gg_send_msg s;
1467 const char *tmp;
1468 char buf[1910];
1469 int res = -1;
1470
1471 gg_debug(GG_DEBUG_FUNCTION, "** gg_image_reply(%p, %d, \"%s\", %p, %d);\n", sess, recipient, filename, image, size);
1472
1473 if (!sess || !filename || !image) {
1474 errno = EFAULT;
1475 return -1;
1476 }
1477
1478 if (sess->state != GG_STATE_CONNECTED) {
1479 errno = ENOTCONN;
1480 return -1;
1481 }
1482
1483 if (size < 0) {
1484 errno = EINVAL;
1485 return -1;
1486 }
1487
1488 /* wytnij ścieżki, zostaw tylko nazwę pliku */
1489 while ((tmp = strrchr(filename, '/')) || (tmp = strrchr(filename, '\\')))
1490 filename = tmp + 1;
1491
1492 if (strlen(filename) < 1 || strlen(filename) > 1024) {
1493 errno = EINVAL;
1494 return -1;
1495 }
1496
1497 s.recipient = gg_fix32(recipient);
1498 s.seq = gg_fix32(0);
1499 s.msgclass = gg_fix32(GG_CLASS_MSG);
1500
1501 buf[0] = 0;
1502 r = (void*) &buf[1];
1503
1504 r->flag = 0x05;
1505 r->size = gg_fix32(size);
1506 r->crc32 = gg_fix32(gg_crc32(0, image, size));
1507
1508 while (size > 0) {
1509 size_t buflen, chunklen;
1510
1511 /* \0 + struct gg_msg_image_reply */
1512 buflen = sizeof(struct gg_msg_image_reply) + 1;
1513
1514 /* w pierwszym kawałku jest nazwa pliku */
1515 if (r->flag == 0x05) {
1516 strcpy(buf + buflen, filename);
1517 buflen += strlen(filename) + 1;
1518 }
1519
1520 chunklen = ((size_t)size >= sizeof(buf) - buflen) ? (sizeof(buf) - buflen) : (size_t)size;
1521
1522 memcpy(buf + buflen, image, chunklen);
1523 size -= chunklen;
1524 image += chunklen;
1525
1526 res = gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), buf, buflen + chunklen, NULL);
1527
1528 if (res == -1)
1529 break;
1530
1531 r->flag = 0x06;
1532 }
1533
1534 return res;
1535 }
1536
1537 /*
1538 * gg_send_message_ctcp()
1539 *
1540 * wysyła wiadomość do innego użytkownika. zwraca losowy numer
1541 * sekwencyjny, który można zignorować albo wykorzystać do potwierdzenia.
1542 *
1543 * - sess - opis sesji
1544 * - msgclass - rodzaj wiadomości
1545 * - recipient - numer adresata
1546 * - message - treść wiadomości
1547 * - message_len - długość
1548 *
1549 * numer sekwencyjny wiadomości lub -1 w przypadku błędu.
1550 */
1551 int gg_send_message_ctcp(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, int message_len)
1552 {
1553 struct gg_send_msg s;
1554
1555 gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message_ctcp(%p, %d, %u, ...);\n", sess, msgclass, recipient);
1556
1557 if (!sess) {
1558 errno = EFAULT;
1559 return -1;
1560 }
1561
1562 if (sess->state != GG_STATE_CONNECTED) {
1563 errno = ENOTCONN;
1564 return -1;
1565 }
1566
1567 s.recipient = gg_fix32(recipient);
1568 s.seq = gg_fix32(0);
1569 s.msgclass = gg_fix32(msgclass);
1570
1571 return gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), message, message_len, NULL);
1572 }
1573
1574 /*
1575 * gg_send_message()
1576 *
1577 * wysyła wiadomość do innego użytkownika. zwraca losowy numer
1578 * sekwencyjny, który można zignorować albo wykorzystać do potwierdzenia.
1579 *
1580 * - sess - opis sesji
1581 * - msgclass - rodzaj wiadomości
1582 * - recipient - numer adresata
1583 * - message - treść wiadomości
1584 *
1585 * numer sekwencyjny wiadomości lub -1 w przypadku błędu.
1586 */
1587 int gg_send_message(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message)
1588 {
1589 gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message(%p, %d, %u, %p)\n", sess, msgclass, recipient, message);
1590
1591 return gg_send_message_richtext(sess, msgclass, recipient, message, NULL, 0);
1592 }
1593
1594 /*
1595 * gg_send_message_richtext()
1596 *
1597 * wysyła kolorową wiadomość do innego użytkownika. zwraca losowy numer
1598 * sekwencyjny, który można zignorować albo wykorzystać do potwierdzenia.
1599 *
1600 * - sess - opis sesji
1601 * - msgclass - rodzaj wiadomości
1602 * - recipient - numer adresata
1603 * - message - treść wiadomości
1604 * - format - informacje o formatowaniu
1605 * - formatlen - długość informacji o formatowaniu
1606 *
1607 * numer sekwencyjny wiadomości lub -1 w przypadku błędu.
1608 */
1609 int gg_send_message_richtext(struct gg_session *sess, int msgclass, uin_t recipient, const unsigned char *message, const unsigned char *format, int formatlen)
1610 {
1611 struct gg_send_msg s;
1612
1613 gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message_richtext(%p, %d, %u, %p, %p, %d);\n", sess, msgclass, recipient, message, format, formatlen);
1614
1615 if (!sess) {
1616 errno = EFAULT;
1617 return -1;
1618 }
1619
1620 if (sess->state != GG_STATE_CONNECTED) {
1621 errno = ENOTCONN;
1622 return -1;
1623 }
1624
1625 if (!message) {
1626 errno = EFAULT;
1627 return -1;
1628 }
1629
1630 s.recipient = gg_fix32(recipient);
1631 if (!sess->seq)
1632 sess->seq = 0x01740000 | (rand() & 0xffff);
1633 s.seq = gg_fix32(sess->seq);
1634 s.msgclass = gg_fix32(msgclass);
1635 sess->seq += (rand() % 0x300) + 0x300;
1636
1637 if (gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), message, strlen((const char *)message) + 1, format, formatlen, NULL) == -1)
1638 return -1;
1639
1640 return gg_fix32(s.seq);
1641 }
1642
1643 /*
1644 * gg_send_message_confer()
1645 *
1646 * wysyła wiadomość do kilku użytkownikow (konferencja). zwraca losowy numer
1647 * sekwencyjny, który można zignorować albo wykorzystać do potwierdzenia.
1648 *
1649 * - sess - opis sesji
1650 * - msgclass - rodzaj wiadomości
1651 * - recipients_count - ilość adresatów
1652 * - recipients - numerki adresatów
1653 * - message - treść wiadomości
1654 *
1655 * numer sekwencyjny wiadomości lub -1 w przypadku błędu.
1656 */
1657 int gg_send_message_confer(struct gg_session *sess, int msgclass, int recipients_count, uin_t *recipients, const unsigned char *message)
1658 {
1659 gg_debug(GG_DEBUG_FUNCTION, "** gg_send_message_confer(%p, %d, %d, %p, %p);\n", sess, msgclass, recipients_count, recipients, message);
1660
1661 return gg_send_message_confer_richtext(sess, msgclass, recipients_count, recipients, message, NULL, 0);
1662 }
1663
1664 /*
1665 * gg_send_message_confer_richtext()
1666 *
1667 * wysyła kolorową wiadomość do kilku użytkownikow (konferencja). zwraca
1668 * losowy numer sekwencyjny, który można zignorować albo wykorzystać do
1669 * potwierdzenia.
1670 *
1671 * - sess - opis sesji
1672 * - msgclass - rodzaj wiadomości
1673 * - recipients_count - ilość adresatów
1674 * - recipients - numerki adresatów
1675 * - message - treść wiadomości
1676 * - format - informacje o formatowaniu
1677 * - formatlen - długość informacji o formatowaniu
1678 *
1679 * numer sekwencyjny wiadomości lub -1 w przypadku błędu.
1680 */
1681 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)
1682 {
1683 struct gg_send_msg s;
1684 struct gg_msg_recipients r;
1685 int i, j, k;
1686 uin_t *recps;
1687
1688 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);
1689
1690 if (!sess) {
1691 errno = EFAULT;
1692 return -1;
1693 }
1694
1695 if (sess->state != GG_STATE_CONNECTED) {
1696 errno = ENOTCONN;
1697 return -1;
1698 }
1699
1700 if (!message || recipients_count <= 0 || recipients_count > 0xffff || !recipients) {
1701 errno = EINVAL;
1702 return -1;
1703 }
1704
1705 r.flag = 0x01;
1706 r.count = gg_fix32(recipients_count - 1);
1707
1708 if (!sess->seq)
1709 sess->seq = 0x01740000 | (rand() & 0xffff);
1710 s.seq = gg_fix32(sess->seq);
1711 s.msgclass = gg_fix32(msgclass);
1712
1713 recps = malloc(sizeof(uin_t) * recipients_count);
1714 if (!recps)
1715 return -1;
1716
1717 for (i = 0; i < recipients_count; i++) {
1718
1719 s.recipient = gg_fix32(recipients[i]);
1720
1721 for (j = 0, k = 0; j < recipients_count; j++)
1722 if (recipients[j] != recipients[i]) {
1723 recps[k] = gg_fix32(recipients[j]);
1724 k++;
1725 }
1726
1727 if (!i)
1728 sess->seq += (rand() % 0x300) + 0x300;
1729
1730 if (gg_send_packet(sess, GG_SEND_MSG, &s, sizeof(s), message, strlen((const char *)message) + 1, &r, sizeof(r), recps, (recipients_count - 1) * sizeof(uin_t), format, formatlen, NULL) == -1) {
1731 free(recps);
1732 return -1;
1733 }
1734 }
1735
1736 free(recps);
1737
1738 return gg_fix32(s.seq);
1739 }
1740
1741 /*
1742 * gg_ping()
1743 *
1744 * wysyła do serwera pakiet ping.
1745 *
1746 * - sess - opis sesji
1747 *
1748 * 0, -1.
1749 */
1750 int gg_ping(struct gg_session *sess)
1751 {
1752 gg_debug(GG_DEBUG_FUNCTION, "** gg_ping(%p);\n", sess);
1753
1754 if (!sess) {
1755 errno = EFAULT;
1756 return -1;
1757 }
1758
1759 if (sess->state != GG_STATE_CONNECTED) {
1760 errno = ENOTCONN;
1761 return -1;
1762 }
1763
1764 return gg_send_packet(sess, GG_PING, NULL);
1765 }
1766
1767 /*
1768 * gg_notify_ex()
1769 *
1770 * wysyła serwerowi listę kontaktów (wraz z odpowiadającymi im typami userów),
1771 * dzięki czemu wie, czyj stan nas interesuje.
1772 *
1773 * - sess - opis sesji
1774 * - userlist - wskaźnik do tablicy numerów
1775 * - types - wskaźnik do tablicy typów użytkowników
1776 * - count - ilość numerków
1777 *
1778 * 0, -1.
1779 */
1780 int gg_notify_ex(struct gg_session *sess, uin_t *userlist, char *types, int count)
1781 {
1782 struct gg_notify *n;
1783 uin_t *u;
1784 char *t;
1785 int i, res = 0;
1786
1787 gg_debug(GG_DEBUG_FUNCTION, "** gg_notify_ex(%p, %p, %p, %d);\n", sess, userlist, types, count);
1788
1789 if (!sess) {
1790 errno = EFAULT;
1791 return -1;
1792 }
1793
1794 if (sess->state != GG_STATE_CONNECTED) {
1795 errno = ENOTCONN;
1796 return -1;
1797 }
1798
1799 if (!userlist || !count)
1800 return gg_send_packet(sess, GG_LIST_EMPTY, NULL);
1801
1802 while (count > 0) {
1803 int part_count, packet_type;
1804
1805 if (count > 400) {
1806 part_count = 400;
1807 packet_type = GG_NOTIFY_FIRST;
1808 } else {
1809 part_count = count;
1810 packet_type = GG_NOTIFY_LAST;
1811 }
1812
1813 if (!(n = (struct gg_notify*) malloc(sizeof(*n) * part_count)))
1814 return -1;
1815
1816 for (u = userlist, t = types, i = 0; i < part_count; u++, t++, i++) {
1817 n[i].uin = gg_fix32(*u);
1818 n[i].dunno1 = *t;
1819 }
1820
1821 if (gg_send_packet(sess, packet_type, n, sizeof(*n) * part_count, NULL) == -1) {
1822 free(n);
1823 res = -1;
1824 break;
1825 }
1826
1827 count -= part_count;
1828 userlist += part_count;
1829 types += part_count;
1830
1831 free(n);
1832 }
1833
1834 return res;
1835 }
1836
1837 /*
1838 * gg_notify()
1839 *
1840 * wysyła serwerowi listę kontaktów, dzięki czemu wie, czyj stan nas
1841 * interesuje.
1842 *
1843 * - sess - opis sesji
1844 * - userlist - wskaźnik do tablicy numerów
1845 * - count - ilość numerków
1846 *
1847 * 0, -1.
1848 */
1849 int gg_notify(struct gg_session *sess, uin_t *userlist, int count)
1850 {
1851 struct gg_notify *n;
1852 uin_t *u;
1853 int i, res = 0;
1854
1855 gg_debug(GG_DEBUG_FUNCTION, "** gg_notify(%p, %p, %d);\n", sess, userlist, count);
1856
1857 if (!sess) {
1858 errno = EFAULT;
1859 return -1;
1860 }
1861
1862 if (sess->state != GG_STATE_CONNECTED) {
1863 errno = ENOTCONN;
1864 return -1;
1865 }
1866
1867 if (!userlist || !count)
1868 return gg_send_packet(sess, GG_LIST_EMPTY, NULL);
1869
1870 while (count > 0) {
1871 int part_count, packet_type;
1872
1873 if (count > 400) {
1874 part_count = 400;
1875 packet_type = GG_NOTIFY_FIRST;
1876 } else {
1877 part_count = count;
1878 packet_type = GG_NOTIFY_LAST;
1879 }
1880
1881 if (!(n = (struct gg_notify*) malloc(sizeof(*n) * part_count)))
1882 return -1;
1883
1884 for (u = userlist, i = 0; i < part_count; u++, i++) {
1885 n[i].uin = gg_fix32(*u);
1886 n[i].dunno1 = GG_USER_NORMAL;
1887 }
1888
1889 if (gg_send_packet(sess, packet_type, n, sizeof(*n) * part_count, NULL) == -1) {
1890 res = -1;
1891 free(n);
1892 break;
1893 }
1894
1895 free(n);
1896
1897 userlist += part_count;
1898 count -= part_count;
1899 }
1900
1901 return res;
1902 }
1903
1904 /*
1905 * gg_add_notify_ex()
1906 *
1907 * dodaje do listy kontaktów dany numer w trakcie połączenia.
1908 * dodawanemu użytkownikowi określamy jego typ (patrz protocol.html)
1909 *
1910 * - sess - opis sesji
1911 * - uin - numer
1912 * - type - typ
1913 *
1914 * 0, -1.
1915 */
1916 int gg_add_notify_ex(struct gg_session *sess, uin_t uin, char type)
1917 {
1918 struct gg_add_remove a;
1919
1920 gg_debug(GG_DEBUG_FUNCTION, "** gg_add_notify_ex(%p, %u, %d);\n", sess, uin, type);
1921
1922 if (!sess) {
1923 errno = EFAULT;
1924 return -1;
1925 }
1926
1927 if (sess->state != GG_STATE_CONNECTED) {
1928 errno = ENOTCONN;
1929 return -1;
1930 }
1931
1932 a.uin = gg_fix32(uin);
1933 a.dunno1 = type;
1934
1935 return gg_send_packet(sess, GG_ADD_NOTIFY, &a, sizeof(a), NULL);
1936 }
1937
1938 /*
1939 * gg_add_notify()
1940 *
1941 * dodaje do listy kontaktów dany numer w trakcie połączenia.
1942 *
1943 * - sess - opis sesji
1944 * - uin - numer
1945 *
1946 * 0, -1.
1947 */
1948 int gg_add_notify(struct gg_session *sess, uin_t uin)
1949 {
1950 return gg_add_notify_ex(sess, uin, GG_USER_NORMAL);
1951 }
1952
1953 /*
1954 * gg_remove_notify_ex()
1955 *
1956 * usuwa z listy kontaktów w trakcie połączenia.
1957 * usuwanemu użytkownikowi określamy jego typ (patrz protocol.html)
1958 *
1959 * - sess - opis sesji
1960 * - uin - numer
1961 * - type - typ
1962 *
1963 * 0, -1.
1964 */
1965 int gg_remove_notify_ex(struct gg_session *sess, uin_t uin, char type)
1966 {
1967 struct gg_add_remove a;
1968
1969 gg_debug(GG_DEBUG_FUNCTION, "** gg_remove_notify_ex(%p, %u, %d);\n", sess, uin, type);
1970
1971 if (!sess) {
1972 errno = EFAULT;
1973 return -1;
1974 }
1975
1976 if (sess->state != GG_STATE_CONNECTED) {
1977 errno = ENOTCONN;
1978 return -1;
1979 }
1980
1981 a.uin = gg_fix32(uin);
1982 a.dunno1 = type;
1983
1984 return gg_send_packet(sess, GG_REMOVE_NOTIFY, &a, sizeof(a), NULL);
1985 }
1986
1987 /*
1988 * gg_remove_notify()
1989 *
1990 * usuwa z listy kontaktów w trakcie połączenia.
1991 *
1992 * - sess - opis sesji
1993 * - uin - numer
1994 *
1995 * 0, -1.
1996 */
1997 int gg_remove_notify(struct gg_session *sess, uin_t uin)
1998 {
1999 return gg_remove_notify_ex(sess, uin, GG_USER_NORMAL);
2000 }
2001
2002 /*
2003 * gg_userlist_request()
2004 *
2005 * wysyła żądanie/zapytanie listy kontaktów na serwerze.
2006 *
2007 * - sess - opis sesji
2008 * - type - rodzaj zapytania/żądania
2009 * - request - treść zapytania/żądania (może być NULL)
2010 *
2011 * 0, -1
2012 */
2013 int gg_userlist_request(struct gg_session *sess, char type, const char *request)
2014 {
2015 int len;
2016
2017 if (!sess) {
2018 errno = EFAULT;
2019 return -1;
2020 }
2021
2022 if (sess->state != GG_STATE_CONNECTED) {
2023 errno = ENOTCONN;
2024 return -1;
2025 }
2026
2027 if (!request) {
2028 sess->userlist_blocks = 1;
2029 return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), NULL);
2030 }
2031
2032 len = strlen(request);
2033
2034 sess->userlist_blocks = 0;
2035
2036 while (len > 2047) {
2037 sess->userlist_blocks++;
2038
2039 if (gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), request, 2047, NULL) == -1)
2040 return -1;
2041
2042 if (type == GG_USERLIST_PUT)
2043 type = GG_USERLIST_PUT_MORE;
2044
2045 request += 2047;
2046 len -= 2047;
2047 }
2048
2049 sess->userlist_blocks++;
2050
2051 return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), request, len, NULL);
2052 }
2053
2054 /*
2055 * Local variables:
2056 * c-indentation-style: k&r
2057 * c-basic-offset: 8
2058 * indent-tabs-mode: notnil
2059 * End:
2060 *
2061 * vim: shiftwidth=8:
2062 */

mercurial