| 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 */ |
|