libpurple/protocols/gg/lib/common.c

changeset 38882
bea4cc95b40f
parent 38881
25cb836b9cec
parent 38182
783878958371
child 38883
90462fef3dd8
equal deleted inserted replaced
38881:25cb836b9cec 38882:bea4cc95b40f
1 /* $Id$ */
2
3 /*
4 * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl>
5 * Robert J. Woźny <speedy@ziew.org>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License Version
9 * 2.1 as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
19 * USA.
20 */
21
22 /**
23 * \file common.c
24 *
25 * \brief Funkcje wykorzystywane przez różne moduły biblioteki
26 */
27
28 #include "network.h"
29 #include "strman.h"
30 #include "fileio.h"
31
32 #include <errno.h>
33 #include <stdarg.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <time.h>
38
39 #include "config.h"
40 #include "libgadu.h"
41 #include "internal.h"
42
43 #ifndef GG_CONFIG_HAVE_VA_COPY
44 # ifdef GG_CONFIG_HAVE___VA_COPY
45 # define va_copy(dest, src) __va_copy((dest), (src))
46 # else
47 /* Taka wersja va_copy() działa poprawnie tylko na platformach, które
48 * va_copy() de facto wcale nie potrzebują, np. MSVC. Definicja tylko dla
49 * przejrzystości kodu. */
50 # define va_copy(dest, src) (dest) = (src)
51 # endif
52 #endif
53
54 /**
55 * \internal Odpowiednik funkcji \c vsprintf alokujący miejsce na wynik.
56 *
57 * Funkcja korzysta z funkcji \c vsnprintf, sprawdzając czy dostępna funkcja
58 * systemowa jest zgodna ze standardem C99 czy wcześniejszymi.
59 *
60 * \param format Format wiadomości (zgodny z \c printf)
61 * \param ap Lista argumentów (zgodna z \c printf)
62 *
63 * \return Zaalokowany bufor lub NULL, jeśli zabrakło pamięci.
64 *
65 * \ingroup helper
66 */
67 char *gg_vsaprintf(const char *format, va_list ap)
68 {
69 int size;
70 char *buf = NULL;
71 va_list aq;
72
73 #if !defined(GG_CONFIG_HAVE_C99_VSNPRINTF) && !defined(HAVE__VSCPRINTF)
74 {
75 int res = 0;
76 char *tmp;
77
78 size = 128;
79 do {
80 if (res > size) {
81 /* Jednak zachowanie zgodne z C99. */
82 size = res + 1;
83 } else {
84 size *= 2;
85 }
86
87 if (!(tmp = realloc(buf, size))) {
88 free(buf);
89 return NULL;
90 }
91
92 buf = tmp;
93 va_copy(aq, ap);
94 res = vsnprintf(buf, size, format, aq);
95 va_end(aq);
96 } while (res >= size || res < 0);
97 }
98 #else
99 va_copy(aq, ap);
100
101 # ifdef HAVE__VSCPRINTF
102 size = _vscprintf(format, aq) + 1;
103 # else
104 {
105 char tmp[2];
106
107 /* libce Solarisa przy buforze NULL zawsze zwracają -1, więc
108 * musimy podać coś istniejącego jako cel printf()owania. */
109 size = vsnprintf(tmp, sizeof(tmp), format, aq) + 1;
110 }
111 # endif
112 va_end(aq);
113 if (!(buf = malloc(size)))
114 return NULL;
115
116 vsnprintf(buf, size, format, ap);
117 #endif
118
119 return buf;
120 }
121
122 /**
123 * \internal Odpowiednik funkcji \c sprintf alokujący miejsce na wynik.
124 *
125 * Funkcja korzysta z funkcji \c vsnprintf, sprawdzając czy dostępna funkcja
126 * systemowa jest zgodna ze standardem C99 czy wcześniejszymi.
127 *
128 * \param format Format wiadomości (zgodny z \c printf)
129 *
130 * \return Zaalokowany bufor lub NULL, jeśli zabrakło pamięci.
131 *
132 * \ingroup helper
133 */
134 char *gg_saprintf(const char *format, ...)
135 {
136 va_list ap;
137 char *res;
138
139 va_start(ap, format);
140 res = gg_vsaprintf(format, ap);
141 va_end(ap);
142
143 return res;
144 }
145
146 /**
147 * \internal Pobiera linię tekstu z bufora.
148 *
149 * Funkcja niszczy bufor źródłowy bezpowrotnie, dzieląc go na kolejne ciągi
150 * znaków i obcina znaki końca linii.
151 *
152 * \param ptr Wskaźnik do zmiennej, która przechowuje aktualne położenie
153 * w analizowanym buforze
154 *
155 * \note Funkcja nie jest już używana. Pozostała dla zachowania ABI.
156 *
157 * \return Wskaźnik do kolejnej linii tekstu lub NULL, jeśli to już koniec
158 * bufora.
159 */
160 char *gg_get_line(char **ptr)
161 {
162 char *foo, *res;
163
164 if (!ptr || !*ptr || !strcmp(*ptr, ""))
165 return NULL;
166
167 res = *ptr;
168
169 if (!(foo = strchr(*ptr, '\n')))
170 *ptr += strlen(*ptr);
171 else {
172 size_t len;
173 *ptr = foo + 1;
174 *foo = 0;
175
176 len = strlen(res);
177
178 if (len > 1 && res[len - 1] == '\r')
179 res[len - 1] = 0;
180 }
181
182 return res;
183 }
184
185 /**
186 * \internal Czyta linię tekstu z gniazda.
187 *
188 * Funkcja czyta tekst znak po znaku, więc nie jest efektywna, ale dzięki
189 * brakowi buforowania, nie koliduje z innymi funkcjami odczytu.
190 *
191 * \note W przypadku zakończenia połączenia przez drugą stronę, ostatnia
192 * linia nie jest zwracana.
193 *
194 * \param sock Deskryptor gniazda
195 * \param buf Wskaźnik do bufora
196 * \param length Długość bufora
197 *
198 * \return Zwraca wskaźnik na koniec odebranej linii jeśli się powiodło,
199 * lub \c NULL w przypadku błędu.
200 */
201 char *gg_read_line(int sock, char *buf, int length)
202 {
203 int ret;
204
205 if (!buf || length < 0)
206 return NULL;
207
208 for (; length > 1; buf++, length--) {
209 do {
210 if ((ret = recv(sock, buf, 1, 0)) == -1 &&
211 errno != EINTR && errno != EAGAIN)
212 {
213 gg_debug(GG_DEBUG_MISC, "// gg_read_line() "
214 "error on read (errno=%d, %s)\n",
215 errno, strerror(errno));
216 *buf = 0;
217 return NULL;
218 } else if (ret == 0) {
219 gg_debug(GG_DEBUG_MISC, "// gg_read_line() "
220 "eof reached\n");
221 *buf = 0;
222 return NULL;
223 }
224 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
225
226 if (*buf == '\n') {
227 buf++;
228 break;
229 }
230 }
231
232 *buf = 0;
233 return buf;
234 }
235
236 /**
237 * \internal Nawiązuje połączenie TCP.
238 *
239 * \param addr Wskaźnik na strukturę \c in_addr z adresem serwera
240 * \param port Port serwera
241 * \param async Flaga asynchronicznego połączenia
242 *
243 * \return Deskryptor gniazda lub -1 w przypadku błędu
244 *
245 * \ingroup helper
246 */
247 int gg_connect(void *addr, int port, int async)
248 {
249 int sock, errno2;
250 struct sockaddr_in sin;
251 struct in_addr *a = addr;
252 struct sockaddr_in myaddr;
253
254 gg_debug(GG_DEBUG_FUNCTION, "** gg_connect(%s, %d, %d);\n",
255 inet_ntoa(*a), port, async);
256
257 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
258 gg_debug(GG_DEBUG_MISC, "// gg_connect() socket() failed "
259 "(errno=%d, %s)\n", errno, strerror(errno));
260 return -1;
261 }
262
263 memset(&myaddr, 0, sizeof(myaddr));
264 myaddr.sin_family = AF_INET;
265
266 myaddr.sin_addr.s_addr = gg_local_ip;
267
268 if (bind(sock, (struct sockaddr *) &myaddr, sizeof(myaddr)) == -1) {
269 gg_debug(GG_DEBUG_MISC, "// gg_connect() bind() failed "
270 "(errno=%d, %s)\n", errno, strerror(errno));
271 errno2 = errno;
272 close(sock);
273 errno = errno2;
274 return -1;
275 }
276
277 if (async) {
278 if (!gg_fd_set_nonblocking(sock)) {
279 gg_debug(GG_DEBUG_MISC, "// gg_connect() can't set "
280 "nonblocking (errno=%d, %s)\n",
281 errno, strerror(errno));
282 errno2 = errno;
283 close(sock);
284 errno = errno2;
285 return -1;
286 }
287 }
288
289 memset(&sin, 0, sizeof(sin));
290 sin.sin_port = htons(port);
291 sin.sin_family = AF_INET;
292 sin.sin_addr.s_addr = a->s_addr;
293
294 if (connect(sock, (struct sockaddr*) &sin, sizeof(sin)) == -1) {
295 if (errno && (!async || errno != EINPROGRESS)) {
296 gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() "
297 "failed (errno=%d, %s)\n",
298 errno, strerror(errno));
299 errno2 = errno;
300 close(sock);
301 errno = errno2;
302 return -1;
303 }
304 gg_debug(GG_DEBUG_MISC,
305 "// gg_connect() connect() in progress\n");
306 }
307
308 return sock;
309 }
310
311 /**
312 * \internal Usuwa znaki końca linii.
313 *
314 * Funkcja działa bezpośrednio na buforze.
315 *
316 * \param line Bufor z tekstem
317 *
318 * \ingroup helper
319 */
320 void gg_chomp(char *line)
321 {
322 int len;
323
324 if (!line)
325 return;
326
327 len = strlen(line);
328
329 if (len > 0 && line[len - 1] == '\n')
330 line[--len] = 0;
331 if (len > 0 && line[len - 1] == '\r')
332 line[--len] = 0;
333 }
334
335 /**
336 * \internal Koduje ciąg znaków do postacji adresu HTTP.
337 *
338 * Zamienia znaki niedrukowalne, spoza ASCII i mające specjalne znaczenie
339 * dla protokołu HTTP na encje postaci \c %XX, gdzie \c XX jest szesnastkową
340 * wartością znaku.
341 *
342 * \param str Ciąg znaków do zakodowania
343 *
344 * \return Zaalokowany bufor lub \c NULL w przypadku błędu.
345 *
346 * \ingroup helper
347 */
348 char *gg_urlencode(const char *str)
349 {
350 char *q, *buf;
351 const char hex[] = "0123456789abcdef";
352 const char *p;
353 unsigned int size = 0;
354
355 if (!str)
356 str = "";
357
358 for (p = str; *p; p++, size++) {
359 if (!((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') ||
360 (*p >= '0' && *p <= '9') || *p == ' ') || (*p == '@') ||
361 (*p == '.') || (*p == '-'))
362 {
363 size += 2;
364 }
365 }
366
367 if (!(buf = malloc(size + 1)))
368 return NULL;
369
370 for (p = str, q = buf; *p; p++, q++) {
371 if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') ||
372 (*p >= '0' && *p <= '9') || (*p == '@') ||
373 (*p == '.') || (*p == '-'))
374 {
375 *q = *p;
376 } else {
377 if (*p == ' ')
378 *q = '+';
379 else {
380 *q++ = '%';
381 *q++ = hex[*p >> 4 & 15];
382 *q = hex[*p & 15];
383 }
384 }
385 }
386
387 *q = 0;
388
389 return buf;
390 }
391
392 /**
393 * \internal Wyznacza skrót dla usług HTTP.
394 *
395 * Funkcja jest wykorzystywana do wyznaczania skrótu adresu e-mail, hasła
396 * i innych wartości przekazywanych jako parametry usług HTTP.
397 *
398 * W parametrze \c format należy umieścić znaki określające postać kolejnych
399 * parametrów: \c 's' jeśli parametr jest ciągiem znaków, \c 'u' jeśli jest
400 * liczbą.
401 *
402 * \param format Format kolejnych parametrów (niezgodny z \c printf)
403 *
404 * \return Wartość skrótu
405 */
406 int gg_http_hash(const char *format, ...)
407 {
408 unsigned int a, c, i, j;
409 va_list ap;
410 int b = -1;
411
412 va_start(ap, format);
413
414 for (j = 0; j < strlen(format); j++) {
415 const char *arg;
416 char buf[16];
417
418 if (format[j] == 'u') {
419 snprintf(buf, sizeof(buf), "%d", va_arg(ap, uin_t));
420 arg = buf;
421 } else {
422 if (!(arg = va_arg(ap, char*)))
423 arg = "";
424 }
425
426 i = 0;
427 while ((c = (unsigned char) arg[i++]) != 0) {
428 a = (c ^ b) + (c << 8);
429 b = (a >> 24) | (a << 8);
430 }
431 }
432
433 va_end(ap);
434
435 return (b < 0 ? -b : b);
436 }
437
438 /**
439 * \internal Zestaw znaków kodowania base64.
440 */
441 static char gg_base64_charset[] =
442 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
443
444 /**
445 * \internal Koduje ciąg znaków do base64.
446 *
447 * Wynik funkcji należy zwolnić za pomocą \c free.
448 *
449 * \param buf Bufor z danami do zakodowania
450 *
451 * \return Zaalokowany bufor z zakodowanymi danymi
452 *
453 * \ingroup helper
454 */
455 char *gg_base64_encode(const char *buf)
456 {
457 char *out, *res;
458 unsigned int i = 0, j = 0, k = 0, len = strlen(buf);
459
460 res = out = malloc((len / 3 + 1) * 4 + 2);
461
462 if (!res)
463 return NULL;
464
465 while (j <= len) {
466 switch (i % 4) {
467 case 0:
468 k = (buf[j] & 252) >> 2;
469 break;
470 case 1:
471 if (j < len)
472 k = ((buf[j] & 3) << 4) | ((buf[j + 1] & 240) >> 4);
473 else
474 k = (buf[j] & 3) << 4;
475
476 j++;
477 break;
478 case 2:
479 if (j < len)
480 k = ((buf[j] & 15) << 2) | ((buf[j + 1] & 192) >> 6);
481 else
482 k = (buf[j] & 15) << 2;
483
484 j++;
485 break;
486 case 3:
487 k = buf[j++] & 63;
488 break;
489 }
490 *out++ = gg_base64_charset[k];
491 i++;
492 }
493
494 if (i % 4)
495 for (j = 0; j < 4 - (i % 4); j++, out++)
496 *out = '=';
497
498 *out = 0;
499
500 return res;
501 }
502
503 /**
504 * \internal Dekoduje ciąg znaków zapisany w base64.
505 *
506 * Wynik funkcji należy zwolnić za pomocą \c free.
507 *
508 * \param buf Bufor źródłowy z danymi do zdekodowania
509 *
510 * \return Zaalokowany bufor ze zdekodowanymi danymi
511 *
512 * \ingroup helper
513 */
514 char *gg_base64_decode(const char *buf)
515 {
516 char *res, *save, *foo, val;
517 const char *end;
518 unsigned int idx = 0;
519
520 if (!buf)
521 return NULL;
522
523 save = res = calloc(1, (strlen(buf) / 4 + 1) * 3 + 2);
524
525 if (!save)
526 return NULL;
527
528 end = buf + strlen(buf);
529
530 while (*buf && buf < end) {
531 if (*buf == '\r' || *buf == '\n') {
532 buf++;
533 continue;
534 }
535 if (!(foo = memchr(gg_base64_charset, *buf, sizeof(gg_base64_charset))))
536 foo = gg_base64_charset;
537 val = (int)(foo - gg_base64_charset);
538 buf++;
539 switch (idx) {
540 case 0:
541 *res |= val << 2;
542 break;
543 case 1:
544 *res++ |= val >> 4;
545 *res |= val << 4;
546 break;
547 case 2:
548 *res++ |= val >> 2;
549 *res |= val << 6;
550 break;
551 case 3:
552 *res++ |= val;
553 break;
554 }
555 idx++;
556 idx %= 4;
557 }
558 *res = 0;
559
560 return save;
561 }
562
563 /**
564 * \internal Tworzy nagłówek autoryzacji serwera pośredniczącego.
565 *
566 * Dane pobiera ze zmiennych globalnych \c gg_proxy_username i
567 * \c gg_proxy_password.
568 *
569 * \return Zaalokowany bufor z tekstem lub NULL, jeśli serwer pośredniczący
570 * nie jest używany lub nie wymaga autoryzacji.
571 */
572 char *gg_proxy_auth(void)
573 {
574 char *tmp, *enc, *out;
575 unsigned int tmp_size;
576
577 if (!gg_proxy_enabled || !gg_proxy_username || !gg_proxy_password)
578 return NULL;
579
580 tmp_size = strlen(gg_proxy_username) + strlen(gg_proxy_password) + 2;
581 tmp = malloc(tmp_size);
582 if (!tmp)
583 return NULL;
584
585 snprintf(tmp, tmp_size, "%s:%s", gg_proxy_username, gg_proxy_password);
586
587 enc = gg_base64_encode(tmp);
588 if (!enc) {
589 free(tmp);
590 return NULL;
591 }
592
593 free(tmp);
594
595 out = malloc(strlen(enc) + 40);
596 if (!out) {
597 free(enc);
598 return NULL;
599 }
600
601 snprintf(out, strlen(enc) + 40, "Proxy-Authorization: Basic %s\r\n", enc);
602
603 free(enc);
604
605 return out;
606 }
607
608 /**
609 * \internal Tablica pomocnicza do wyznaczania sumy kontrolnej.
610 */
611 static const uint32_t gg_crc32_table[256] =
612 {
613 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
614 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
615 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
616 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
617 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
618 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
619 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
620 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
621 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
622 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
623 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
624 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
625 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
626 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
627 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
628 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
629 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
630 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
631 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
632 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
633 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
634 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
635 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
636 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
637 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
638 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
639 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
640 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
641 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
642 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
643 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
644 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
645 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
646 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
647 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
648 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
649 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
650 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
651 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
652 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
653 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
654 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
655 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
656 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
657 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
658 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
659 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
660 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
661 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
662 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
663 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
664 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
665 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
666 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
667 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
668 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
669 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
670 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
671 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
672 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
673 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
674 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
675 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
676 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
677 };
678
679 /**
680 * Wyznacza sumę kontrolną CRC32.
681 *
682 * \param crc Suma kontrola poprzedniego bloku danych lub 0 jeśli liczona
683 * jest suma kontrolna pierwszego bloku
684 * \param buf Bufor danych
685 * \param len Długość bufora danych
686 *
687 * \return Suma kontrolna.
688 */
689 uint32_t gg_crc32(uint32_t crc, const unsigned char *buf, int len)
690 {
691 if (buf == NULL || len < 0)
692 return crc;
693
694 crc ^= 0xffffffffL;
695
696 while (len--)
697 crc = (crc >> 8) ^ gg_crc32_table[(crc ^ *buf++) & 0xff];
698
699 return crc ^ 0xffffffffL;
700 }
701
702 /**
703 * \internal Parsuje identyfikator użytkownika.
704 *
705 * \param str Ciąg tekstowy, zawierający identyfikator
706 * \param len Długość identyfikatora
707 *
708 * \return Identyfikator, lub 0, jeżeli nie udało się odczytać
709 */
710 uin_t gg_str_to_uin(const char *str, int len)
711 {
712 char buff[11];
713 char *endptr;
714 uin_t uin;
715
716 if (len < 0)
717 len = strlen(str);
718 if (len > 10)
719 return 0;
720 memcpy(buff, str, len);
721 buff[len] = '\0';
722
723 errno = 0;
724 uin = strtoul(buff, &endptr, 10);
725 if (errno == ERANGE || endptr[0] != '\0')
726 return 0;
727
728 return uin;
729 }
730
731 /**
732 * Szuka informacji o konferencji o podanym identyfikatorze.
733 *
734 * \param sess Struktura sesji
735 * \param id Identyfikator konferencji
736 *
737 * \return Struktura z informacjami o konferencji
738 */
739 gg_chat_list_t *gg_chat_find(struct gg_session *sess, uint64_t id)
740 {
741 gg_chat_list_t *chat_list = sess->private_data->chat_list;
742
743 while (chat_list != NULL) {
744 if (chat_list->id == id)
745 return chat_list;
746 chat_list = chat_list->next;
747 }
748
749 return NULL;
750 }
751
752 /**
753 * \internal Aktualizuje informacje o konferencji.
754 *
755 * \param sess Struktura sesji
756 * \param id Identyfikator konferencji
757 * \param version Wersja informacji o konferencji
758 * \param participants Lista uczestników konferencji
759 * \param participants_count Ilość uczestników konferencji
760 *
761 * \return Wartość równa 0, jeżeli zakończono powodzeniem
762 */
763 int gg_chat_update(struct gg_session *sess, uint64_t id, uint32_t version,
764 const uin_t *participants, unsigned int participants_count)
765 {
766 gg_chat_list_t *chat;
767 uin_t *participants_new;
768
769 if (participants_count >= ~(unsigned int)0 / sizeof(uin_t))
770 return -1;
771
772 chat = gg_chat_find(sess, id);
773
774 if (!chat) {
775 chat = malloc(sizeof(gg_chat_list_t));
776
777 if (!chat)
778 return -1;
779
780 memset(chat, 0, sizeof(gg_chat_list_t));
781 chat->id = id;
782 chat->next = sess->private_data->chat_list;
783 sess->private_data->chat_list = chat;
784 }
785
786 participants_new = realloc(chat->participants,
787 sizeof(uin_t) * participants_count);
788
789 if (participants_new == NULL)
790 return -1;
791
792 chat->version = version;
793 chat->participants = participants_new;
794 chat->participants_count = participants_count;
795 memcpy(chat->participants, participants,
796 sizeof(uin_t) * participants_count);
797
798 return 0;
799 }
800
801 void gg_connection_failure(struct gg_session *gs, struct gg_event *ge,
802 enum gg_failure_t failure)
803 {
804 gg_close(gs);
805
806 if (ge != NULL) {
807 ge->type = GG_EVENT_CONN_FAILED;
808 ge->event.failure = failure;
809 }
810 gs->state = GG_STATE_IDLE;
811 }
812
813 time_t gg_server_time(struct gg_session *gs)
814 {
815 time_t now = time(NULL);
816
817 if (gs == NULL || gs->private_data == NULL) {
818 gg_debug_session(gs, GG_DEBUG_ERROR, "time diff data is not "
819 "accessible\n");
820 return now;
821 }
822
823 return now + gs->private_data->time_diff;
824 }
825
826 void gg_strarr_free(char **strarr)
827 {
828 char **it;
829
830 if (strarr == NULL)
831 return;
832
833 for (it = strarr; *it != NULL; it++)
834 free(*it);
835 free(strarr);
836 }
837
838 char ** gg_strarr_dup(char **strarr)
839 {
840 size_t i, len, size;
841 char **it, **out;
842
843 if (strarr == NULL)
844 return NULL;
845
846 len = 0;
847 for (it = strarr; *it != NULL; it++)
848 len++;
849
850 size = (len + 1) * sizeof(char*);
851 out = malloc(size);
852
853 if (out == NULL) {
854 gg_debug(GG_DEBUG_MISC | GG_DEBUG_ERROR, "// gg_strarr_dup() "
855 "not enough memory for the array\n");
856 return NULL;
857 }
858 memset(out, 0, size);
859
860 for (i = 0; i < len; i++) {
861 out[i] = strdup(strarr[i]);
862 if (out[i] == NULL) {
863 gg_debug(GG_DEBUG_MISC | GG_DEBUG_ERROR,
864 "// gg_strarr_dup() "
865 "not enough memory for the array element\n");
866 gg_strarr_free(out);
867 return NULL;
868 }
869 }
870
871 return out;
872 }
873
874 /*
875 * Local variables:
876 * c-indentation-style: k&r
877 * c-basic-offset: 8
878 * indent-tabs-mode: notnil
879 * End:
880 *
881 * vim: shiftwidth=8:
882 */

mercurial