Mercurial > pidgin
annotate src/protocols/gg/lib/common.c @ 13967:99b9b58b19dd
[gaim-migrate @ 16523]
Fix a crazy MSN crash. Basically it's possible to have more than one
slplink associated with a given switchboard, but our code did not
allow for that. I think it happens when you're in a multi-user
chat and you do stuff with multiple users that involves slplinks.
Like maybe file transfer and buddy icon related stuff.
Tracking this down took an ungodly amount of time, but thanks to
Meebo for letting me do it :-)
committer: Tailor Script <tailor@pidgin.im>
author | Mark Doliner <mark@kingant.net> |
---|---|
date | Thu, 20 Jul 2006 07:31:15 +0000 |
parents | 3c536224f0d0 |
children |
rev | line source |
---|---|
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
1 /* $Id: common.c 13801 2005-09-14 19:10:39Z datallah $ */ |
11360 | 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 | |
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
22 #ifndef _WIN32 |
11360 | 23 #include <sys/types.h> |
24 #include <sys/ioctl.h> | |
25 #include <sys/socket.h> | |
26 #include <netinet/in.h> | |
27 #include <arpa/inet.h> | |
28 #ifdef sun | |
29 # include <sys/filio.h> | |
30 #endif | |
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
31 #endif |
11360 | 32 |
33 #include <errno.h> | |
34 #include <fcntl.h> | |
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
35 #ifndef _WIN32 |
11360 | 36 #include <netdb.h> |
11546
3c536224f0d0
[gaim-migrate @ 13801]
Daniel Atallah <daniel.atallah@gmail.com>
parents:
11360
diff
changeset
|
37 #endif |
11360 | 38 #include <stdarg.h> |
39 #include <stdio.h> | |
40 #include <stdlib.h> | |
41 #include <string.h> | |
42 #include <unistd.h> | |
43 | |
44 #include "libgadu.h" | |
45 | |
46 FILE *gg_debug_file = NULL; | |
47 | |
48 #ifndef GG_DEBUG_DISABLE | |
49 | |
50 /* | |
51 * gg_debug() // funkcja wewnętrzna | |
52 * | |
53 * wyświetla komunikat o danym poziomie, o ile użytkownik sobie tego życzy. | |
54 * | |
55 * - level - poziom wiadomości | |
56 * - format... - treść wiadomości (kompatybilna z printf()) | |
57 */ | |
58 void gg_debug(int level, const char *format, ...) | |
59 { | |
60 va_list ap; | |
61 int old_errno = errno; | |
62 | |
63 if (gg_debug_handler) { | |
64 va_start(ap, format); | |
65 (*gg_debug_handler)(level, format, ap); | |
66 va_end(ap); | |
67 | |
68 goto cleanup; | |
69 } | |
70 | |
71 if ((gg_debug_level & level)) { | |
72 va_start(ap, format); | |
73 vfprintf((gg_debug_file) ? gg_debug_file : stderr, format, ap); | |
74 va_end(ap); | |
75 } | |
76 | |
77 cleanup: | |
78 errno = old_errno; | |
79 } | |
80 | |
81 #endif | |
82 | |
83 /* | |
84 * gg_vsaprintf() // funkcja pomocnicza | |
85 * | |
86 * robi dokładnie to samo, co vsprintf(), tyle że alokuje sobie wcześniej | |
87 * miejsce na dane. powinno działać na tych maszynach, które mają funkcję | |
88 * vsnprintf() zgodną z C99, jak i na wcześniejszych. | |
89 * | |
90 * - format - opis wyświetlanego tekstu jak dla printf() | |
91 * - ap - lista argumentów dla printf() | |
92 * | |
93 * zaalokowany bufor, który należy później zwolnić, lub NULL | |
94 * jeśli nie udało się wykonać zadania. | |
95 */ | |
96 char *gg_vsaprintf(const char *format, va_list ap) | |
97 { | |
98 int size = 0; | |
99 const char *start; | |
100 char *buf = NULL; | |
101 | |
102 #ifdef __GG_LIBGADU_HAVE_VA_COPY | |
103 va_list aq; | |
104 | |
105 va_copy(aq, ap); | |
106 #else | |
107 # ifdef __GG_LIBGADU_HAVE___VA_COPY | |
108 va_list aq; | |
109 | |
110 __va_copy(aq, ap); | |
111 # endif | |
112 #endif | |
113 | |
114 start = format; | |
115 | |
116 #ifndef __GG_LIBGADU_HAVE_C99_VSNPRINTF | |
117 { | |
118 int res; | |
119 char *tmp; | |
120 | |
121 size = 128; | |
122 do { | |
123 size *= 2; | |
124 if (!(tmp = realloc(buf, size))) { | |
125 free(buf); | |
126 return NULL; | |
127 } | |
128 buf = tmp; | |
129 res = vsnprintf(buf, size, format, ap); | |
130 } while (res == size - 1 || res == -1); | |
131 } | |
132 #else | |
133 { | |
134 char tmp[2]; | |
135 | |
136 /* libce Solarisa przy buforze NULL zawsze zwracają -1, więc | |
137 * musimy podać coś istniejącego jako cel printf()owania. */ | |
138 size = vsnprintf(tmp, sizeof(tmp), format, ap); | |
139 if (!(buf = malloc(size + 1))) | |
140 return NULL; | |
141 } | |
142 #endif | |
143 | |
144 format = start; | |
145 | |
146 #ifdef __GG_LIBGADU_HAVE_VA_COPY | |
147 vsnprintf(buf, size + 1, format, aq); | |
148 va_end(aq); | |
149 #else | |
150 # ifdef __GG_LIBGADU_HAVE___VA_COPY | |
151 vsnprintf(buf, size + 1, format, aq); | |
152 va_end(aq); | |
153 # else | |
154 vsnprintf(buf, size + 1, format, ap); | |
155 # endif | |
156 #endif | |
157 | |
158 return buf; | |
159 } | |
160 | |
161 /* | |
162 * gg_saprintf() // funkcja pomocnicza | |
163 * | |
164 * robi dokładnie to samo, co sprintf(), tyle że alokuje sobie wcześniej | |
165 * miejsce na dane. powinno działać na tych maszynach, które mają funkcję | |
166 * vsnprintf() zgodną z C99, jak i na wcześniejszych. | |
167 * | |
168 * - format... - treść taka sama jak w funkcji printf() | |
169 * | |
170 * zaalokowany bufor, który należy później zwolnić, lub NULL | |
171 * jeśli nie udało się wykonać zadania. | |
172 */ | |
173 char *gg_saprintf(const char *format, ...) | |
174 { | |
175 va_list ap; | |
176 char *res; | |
177 | |
178 va_start(ap, format); | |
179 res = gg_vsaprintf(format, ap); | |
180 va_end(ap); | |
181 | |
182 return res; | |
183 } | |
184 | |
185 /* | |
186 * gg_get_line() // funkcja pomocnicza | |
187 * | |
188 * podaje kolejną linię z bufora tekstowego. niszczy go bezpowrotnie, dzieląc | |
189 * na kolejne stringi. zdarza się, nie ma potrzeby pisania funkcji dublującej | |
190 * bufor żeby tylko mieć nieruszone dane wejściowe, skoro i tak nie będą nam | |
191 * poźniej potrzebne. obcina `\r\n'. | |
192 * | |
193 * - ptr - wskaźnik do zmiennej, która przechowuje aktualną pozycję | |
194 * w przemiatanym buforze | |
195 * | |
196 * wskaźnik do kolejnej linii tekstu lub NULL, jeśli to już koniec bufora. | |
197 */ | |
198 char *gg_get_line(char **ptr) | |
199 { | |
200 char *foo, *res; | |
201 | |
202 if (!ptr || !*ptr || !strcmp(*ptr, "")) | |
203 return NULL; | |
204 | |
205 res = *ptr; | |
206 | |
207 if (!(foo = strchr(*ptr, '\n'))) | |
208 *ptr += strlen(*ptr); | |
209 else { | |
210 *ptr = foo + 1; | |
211 *foo = 0; | |
212 if (strlen(res) > 1 && res[strlen(res) - 1] == '\r') | |
213 res[strlen(res) - 1] = 0; | |
214 } | |
215 | |
216 return res; | |
217 } | |
218 | |
219 /* | |
220 * gg_connect() // funkcja pomocnicza | |
221 * | |
222 * łączy się z serwerem. pierwszy argument jest typu (void *), żeby nie | |
223 * musieć niczego inkludować w libgadu.h i nie psuć jakiś głupich zależności | |
224 * na dziwnych systemach. | |
225 * | |
226 * - addr - adres serwera (struct in_addr *) | |
227 * - port - port serwera | |
228 * - async - asynchroniczne połączenie | |
229 * | |
230 * deskryptor gniazda lub -1 w przypadku błędu (kod błędu w zmiennej errno). | |
231 */ | |
232 int gg_connect(void *addr, int port, int async) | |
233 { | |
234 int sock, one = 1, errno2; | |
235 struct sockaddr_in sin; | |
236 struct in_addr *a = addr; | |
237 struct sockaddr_in myaddr; | |
238 | |
239 gg_debug(GG_DEBUG_FUNCTION, "** gg_connect(%s, %d, %d);\n", inet_ntoa(*a), port, async); | |
240 | |
241 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { | |
242 gg_debug(GG_DEBUG_MISC, "// gg_connect() socket() failed (errno=%d, %s)\n", errno, strerror(errno)); | |
243 return -1; | |
244 } | |
245 | |
246 memset(&myaddr, 0, sizeof(myaddr)); | |
247 myaddr.sin_family = AF_INET; | |
248 | |
249 myaddr.sin_addr.s_addr = gg_local_ip; | |
250 | |
251 if (bind(sock, (struct sockaddr *) &myaddr, sizeof(myaddr)) == -1) { | |
252 gg_debug(GG_DEBUG_MISC, "// gg_connect() bind() failed (errno=%d, %s)\n", errno, strerror(errno)); | |
253 return -1; | |
254 } | |
255 | |
256 #ifdef ASSIGN_SOCKETS_TO_THREADS | |
257 gg_win32_thread_socket(0, sock); | |
258 #endif | |
259 | |
260 if (async) { | |
261 #ifdef FIONBIO | |
262 if (ioctl(sock, FIONBIO, &one) == -1) { | |
263 #else | |
264 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) { | |
265 #endif | |
266 gg_debug(GG_DEBUG_MISC, "// gg_connect() ioctl() failed (errno=%d, %s)\n", errno, strerror(errno)); | |
267 errno2 = errno; | |
268 close(sock); | |
269 errno = errno2; | |
270 return -1; | |
271 } | |
272 } | |
273 | |
274 sin.sin_port = htons(port); | |
275 sin.sin_family = AF_INET; | |
276 sin.sin_addr.s_addr = a->s_addr; | |
277 | |
278 if (connect(sock, (struct sockaddr*) &sin, sizeof(sin)) == -1) { | |
279 if (errno && (!async || errno != EINPROGRESS)) { | |
280 gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() failed (errno=%d, %s)\n", errno, strerror(errno)); | |
281 errno2 = errno; | |
282 close(sock); | |
283 errno = errno2; | |
284 return -1; | |
285 } | |
286 gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() in progress\n"); | |
287 } | |
288 | |
289 return sock; | |
290 } | |
291 | |
292 /* | |
293 * gg_read_line() // funkcja pomocnicza | |
294 * | |
295 * czyta jedną linię tekstu z gniazda. | |
296 * | |
297 * - sock - deskryptor gniazda | |
298 * - buf - wskaźnik do bufora | |
299 * - length - długość bufora | |
300 * | |
301 * jeśli trafi na błąd odczytu lub podano nieprawidłowe parametry, zwraca NULL. | |
302 * inaczej zwraca buf. | |
303 */ | |
304 char *gg_read_line(int sock, char *buf, int length) | |
305 { | |
306 int ret; | |
307 | |
308 if (!buf || length < 0) | |
309 return NULL; | |
310 | |
311 for (; length > 1; buf++, length--) { | |
312 do { | |
313 if ((ret = read(sock, buf, 1)) == -1 && errno != EINTR) { | |
314 gg_debug(GG_DEBUG_MISC, "// gg_read_line() error on read (errno=%d, %s)\n", errno, strerror(errno)); | |
315 *buf = 0; | |
316 return NULL; | |
317 } else if (ret == 0) { | |
318 gg_debug(GG_DEBUG_MISC, "// gg_read_line() eof reached\n"); | |
319 *buf = 0; | |
320 return NULL; | |
321 } | |
322 } while (ret == -1 && errno == EINTR); | |
323 | |
324 if (*buf == '\n') { | |
325 buf++; | |
326 break; | |
327 } | |
328 } | |
329 | |
330 *buf = 0; | |
331 return buf; | |
332 } | |
333 | |
334 /* | |
335 * gg_chomp() // funkcja pomocnicza | |
336 * | |
337 * ucina "\r\n" lub "\n" z końca linii. | |
338 * | |
339 * - line - linia do przycięcia | |
340 */ | |
341 void gg_chomp(char *line) | |
342 { | |
343 int len; | |
344 | |
345 if (!line) | |
346 return; | |
347 | |
348 len = strlen(line); | |
349 | |
350 if (len > 0 && line[len - 1] == '\n') | |
351 line[--len] = 0; | |
352 if (len > 0 && line[len - 1] == '\r') | |
353 line[--len] = 0; | |
354 } | |
355 | |
356 /* | |
357 * gg_urlencode() // funkcja wewnętrzna | |
358 * | |
359 * zamienia podany tekst na ciąg znaków do formularza http. przydaje się | |
360 * przy różnych usługach katalogu publicznego. | |
361 * | |
362 * - str - ciąg znaków do zakodowania | |
363 * | |
364 * zaalokowany bufor, który należy później zwolnić albo NULL | |
365 * w przypadku błędu. | |
366 */ | |
367 char *gg_urlencode(const char *str) | |
368 { | |
369 char *q, *buf, hex[] = "0123456789abcdef"; | |
370 const char *p; | |
371 unsigned int size = 0; | |
372 | |
373 if (!str) | |
374 str = ""; | |
375 | |
376 for (p = str; *p; p++, size++) { | |
377 if (!((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == ' ') || (*p == '@') || (*p == '.') || (*p == '-')) | |
378 size += 2; | |
379 } | |
380 | |
381 if (!(buf = malloc(size + 1))) | |
382 return NULL; | |
383 | |
384 for (p = str, q = buf; *p; p++, q++) { | |
385 if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || (*p == '@') || (*p == '.') || (*p == '-')) | |
386 *q = *p; | |
387 else { | |
388 if (*p == ' ') | |
389 *q = '+'; | |
390 else { | |
391 *q++ = '%'; | |
392 *q++ = hex[*p >> 4 & 15]; | |
393 *q = hex[*p & 15]; | |
394 } | |
395 } | |
396 } | |
397 | |
398 *q = 0; | |
399 | |
400 return buf; | |
401 } | |
402 | |
403 /* | |
404 * gg_http_hash() // funkcja wewnętrzna | |
405 * | |
406 * funkcja licząca hash dla adresu e-mail, hasła i paru innych. | |
407 * | |
408 * - format... - format kolejnych parametrów ('s' jeśli dany parametr jest | |
409 * ciągiem znaków lub 'u' jeśli numerem GG) | |
410 * | |
411 * hash wykorzystywany przy rejestracji i wszelkich manipulacjach własnego | |
412 * wpisu w katalogu publicznym. | |
413 */ | |
414 int gg_http_hash(const char *format, ...) | |
415 { | |
416 unsigned int a, c, i, j; | |
417 va_list ap; | |
418 int b = -1; | |
419 | |
420 va_start(ap, format); | |
421 | |
422 for (j = 0; j < strlen(format); j++) { | |
423 char *arg, buf[16]; | |
424 | |
425 if (format[j] == 'u') { | |
426 snprintf(buf, sizeof(buf), "%d", va_arg(ap, uin_t)); | |
427 arg = buf; | |
428 } else { | |
429 if (!(arg = va_arg(ap, char*))) | |
430 arg = ""; | |
431 } | |
432 | |
433 i = 0; | |
434 while ((c = (unsigned char) arg[i++]) != 0) { | |
435 a = (c ^ b) + (c << 8); | |
436 b = (a >> 24) | (a << 8); | |
437 } | |
438 } | |
439 | |
440 va_end(ap); | |
441 | |
442 return (b < 0 ? -b : b); | |
443 } | |
444 | |
445 /* | |
446 * gg_gethostbyname() // funkcja pomocnicza | |
447 * | |
448 * odpowiednik gethostbyname() troszczący się o współbieżność, gdy mamy do | |
449 * dyspozycji funkcję gethostbyname_r(). | |
450 * | |
451 * - hostname - nazwa serwera | |
452 * | |
453 * zwraca wskaźnik na strukturę in_addr, którą należy zwolnić. | |
454 */ | |
455 struct in_addr *gg_gethostbyname(const char *hostname) | |
456 { | |
457 struct in_addr *addr = NULL; | |
458 | |
459 #ifdef HAVE_GETHOSTBYNAME_R | |
460 char *tmpbuf = NULL, *buf = NULL; | |
461 struct hostent *hp = NULL, *hp2 = NULL; | |
462 int h_errnop, ret; | |
463 size_t buflen = 1024; | |
464 int new_errno; | |
465 | |
466 new_errno = ENOMEM; | |
467 | |
468 if (!(addr = malloc(sizeof(struct in_addr)))) | |
469 goto cleanup; | |
470 | |
471 if (!(hp = calloc(1, sizeof(*hp)))) | |
472 goto cleanup; | |
473 | |
474 if (!(buf = malloc(buflen))) | |
475 goto cleanup; | |
476 | |
477 tmpbuf = buf; | |
478 | |
479 while ((ret = gethostbyname_r(hostname, hp, buf, buflen, &hp2, &h_errnop)) == ERANGE) { | |
480 buflen *= 2; | |
481 | |
482 if (!(tmpbuf = realloc(buf, buflen))) | |
483 break; | |
484 | |
485 buf = tmpbuf; | |
486 } | |
487 | |
488 if (ret) | |
489 new_errno = h_errnop; | |
490 | |
491 if (ret || !hp2 || !tmpbuf) | |
492 goto cleanup; | |
493 | |
494 memcpy(addr, hp->h_addr, sizeof(struct in_addr)); | |
495 | |
496 free(buf); | |
497 free(hp); | |
498 | |
499 return addr; | |
500 | |
501 cleanup: | |
502 errno = new_errno; | |
503 | |
504 if (addr) | |
505 free(addr); | |
506 if (hp) | |
507 free(hp); | |
508 if (buf) | |
509 free(buf); | |
510 | |
511 return NULL; | |
512 #else | |
513 struct hostent *hp; | |
514 | |
515 if (!(addr = malloc(sizeof(struct in_addr)))) { | |
516 goto cleanup; | |
517 } | |
518 | |
519 if (!(hp = gethostbyname(hostname))) | |
520 goto cleanup; | |
521 | |
522 memcpy(addr, hp->h_addr, sizeof(struct in_addr)); | |
523 | |
524 return addr; | |
525 | |
526 cleanup: | |
527 if (addr) | |
528 free(addr); | |
529 | |
530 return NULL; | |
531 #endif | |
532 } | |
533 | |
534 #ifdef ASSIGN_SOCKETS_TO_THREADS | |
535 | |
536 typedef struct gg_win32_thread { | |
537 int id; | |
538 int socket; | |
539 struct gg_win32_thread *next; | |
540 } gg_win32_thread; | |
541 | |
542 struct gg_win32_thread *gg_win32_threads = 0; | |
543 | |
544 /* | |
545 * gg_win32_thread_socket() // funkcja pomocnicza, tylko dla win32 | |
546 * | |
547 * zwraca deskryptor gniazda, które było ostatnio tworzone dla wątku | |
548 * o podanym identyfikatorze. | |
549 * | |
550 * jeśli na win32 przy połączeniach synchronicznych zapamiętamy w jakim | |
551 * wątku uruchomiliśmy funkcję, która się z czymkolwiek łączy, to z osobnego | |
552 * wątku możemy anulować połączenie poprzez gg_win32_thread_socket(watek, -1); | |
553 * | |
554 * - thread_id - id wątku. jeśli jest równe 0, brany jest aktualny wątek, | |
555 * jeśli równe -1, usuwa wpis o podanym sockecie. | |
556 * - socket - deskryptor gniazda. jeśli równe 0, zwraca deskryptor gniazda | |
557 * dla podanego wątku, jeśli równe -1, usuwa wpis, jeśli coś | |
558 * innego, ustawia dla podanego wątku dany numer deskryptora. | |
559 * | |
560 * jeśli socket jest równe 0, zwraca deskryptor gniazda dla podanego wątku. | |
561 */ | |
562 int gg_win32_thread_socket(int thread_id, int socket) | |
563 { | |
564 char close = (thread_id == -1) || socket == -1; | |
565 gg_win32_thread *wsk = gg_win32_threads; | |
566 gg_win32_thread **p_wsk = &gg_win32_threads; | |
567 | |
568 if (!thread_id) | |
569 thread_id = GetCurrentThreadId(); | |
570 | |
571 while (wsk) { | |
572 if ((thread_id == -1 && wsk->socket == socket) || wsk->id == thread_id) { | |
573 if (close) { | |
574 /* socket zostaje usuniety */ | |
575 closesocket(wsk->socket); | |
576 *p_wsk = wsk->next; | |
577 free(wsk); | |
578 return 1; | |
579 } else if (!socket) { | |
580 /* socket zostaje zwrocony */ | |
581 return wsk->socket; | |
582 } else { | |
583 /* socket zostaje ustawiony */ | |
584 wsk->socket = socket; | |
585 return socket; | |
586 } | |
587 } | |
588 p_wsk = &(wsk->next); | |
589 wsk = wsk->next; | |
590 } | |
591 | |
592 if (close && socket != -1) | |
593 closesocket(socket); | |
594 if (close || !socket) | |
595 return 0; | |
596 | |
597 /* Dodaje nowy element */ | |
598 wsk = malloc(sizeof(gg_win32_thread)); | |
599 wsk->id = thread_id; | |
600 wsk->socket = socket; | |
601 wsk->next = 0; | |
602 *p_wsk = wsk; | |
603 | |
604 return socket; | |
605 } | |
606 | |
607 #endif /* ASSIGN_SOCKETS_TO_THREADS */ | |
608 | |
609 static char gg_base64_charset[] = | |
610 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
611 | |
612 /* | |
613 * gg_base64_encode() | |
614 * | |
615 * zapisuje ciąg znaków w base64. | |
616 * | |
617 * - buf - ciąg znaków. | |
618 * | |
619 * zaalokowany bufor. | |
620 */ | |
621 char *gg_base64_encode(const char *buf) | |
622 { | |
623 char *out, *res; | |
624 unsigned int i = 0, j = 0, k = 0, len = strlen(buf); | |
625 | |
626 res = out = malloc((len / 3 + 1) * 4 + 2); | |
627 | |
628 if (!res) | |
629 return NULL; | |
630 | |
631 while (j <= len) { | |
632 switch (i % 4) { | |
633 case 0: | |
634 k = (buf[j] & 252) >> 2; | |
635 break; | |
636 case 1: | |
637 if (j < len) | |
638 k = ((buf[j] & 3) << 4) | ((buf[j + 1] & 240) >> 4); | |
639 else | |
640 k = (buf[j] & 3) << 4; | |
641 | |
642 j++; | |
643 break; | |
644 case 2: | |
645 if (j < len) | |
646 k = ((buf[j] & 15) << 2) | ((buf[j + 1] & 192) >> 6); | |
647 else | |
648 k = (buf[j] & 15) << 2; | |
649 | |
650 j++; | |
651 break; | |
652 case 3: | |
653 k = buf[j++] & 63; | |
654 break; | |
655 } | |
656 *out++ = gg_base64_charset[k]; | |
657 i++; | |
658 } | |
659 | |
660 if (i % 4) | |
661 for (j = 0; j < 4 - (i % 4); j++, out++) | |
662 *out = '='; | |
663 | |
664 *out = 0; | |
665 | |
666 return res; | |
667 } | |
668 | |
669 /* | |
670 * gg_base64_decode() | |
671 * | |
672 * dekoduje ciąg znaków z base64. | |
673 * | |
674 * - buf - ciąg znaków. | |
675 * | |
676 * zaalokowany bufor. | |
677 */ | |
678 char *gg_base64_decode(const char *buf) | |
679 { | |
680 char *res, *save, *foo, val; | |
681 const char *end; | |
682 unsigned int index = 0; | |
683 | |
684 if (!buf) | |
685 return NULL; | |
686 | |
687 save = res = calloc(1, (strlen(buf) / 4 + 1) * 3 + 2); | |
688 | |
689 if (!save) | |
690 return NULL; | |
691 | |
692 end = buf + strlen(buf); | |
693 | |
694 while (*buf && buf < end) { | |
695 if (*buf == '\r' || *buf == '\n') { | |
696 buf++; | |
697 continue; | |
698 } | |
699 if (!(foo = strchr(gg_base64_charset, *buf))) | |
700 foo = gg_base64_charset; | |
701 val = (int)(foo - gg_base64_charset); | |
702 buf++; | |
703 switch (index) { | |
704 case 0: | |
705 *res |= val << 2; | |
706 break; | |
707 case 1: | |
708 *res++ |= val >> 4; | |
709 *res |= val << 4; | |
710 break; | |
711 case 2: | |
712 *res++ |= val >> 2; | |
713 *res |= val << 6; | |
714 break; | |
715 case 3: | |
716 *res++ |= val; | |
717 break; | |
718 } | |
719 index++; | |
720 index %= 4; | |
721 } | |
722 *res = 0; | |
723 | |
724 return save; | |
725 } | |
726 | |
727 /* | |
728 * gg_proxy_auth() // funkcja wewnętrzna | |
729 * | |
730 * tworzy nagłówek autoryzacji dla proxy. | |
731 * | |
732 * zaalokowany tekst lub NULL, jeśli proxy nie jest włączone lub nie wymaga | |
733 * autoryzacji. | |
734 */ | |
735 char *gg_proxy_auth() | |
736 { | |
737 char *tmp, *enc, *out; | |
738 unsigned int tmp_size; | |
739 | |
740 if (!gg_proxy_enabled || !gg_proxy_username || !gg_proxy_password) | |
741 return NULL; | |
742 | |
743 if (!(tmp = malloc((tmp_size = strlen(gg_proxy_username) + strlen(gg_proxy_password) + 2)))) | |
744 return NULL; | |
745 | |
746 snprintf(tmp, tmp_size, "%s:%s", gg_proxy_username, gg_proxy_password); | |
747 | |
748 if (!(enc = gg_base64_encode(tmp))) { | |
749 free(tmp); | |
750 return NULL; | |
751 } | |
752 | |
753 free(tmp); | |
754 | |
755 if (!(out = malloc(strlen(enc) + 40))) { | |
756 free(enc); | |
757 return NULL; | |
758 } | |
759 | |
760 snprintf(out, strlen(enc) + 40, "Proxy-Authorization: Basic %s\r\n", enc); | |
761 | |
762 free(enc); | |
763 | |
764 return out; | |
765 } | |
766 | |
767 static uint32_t gg_crc32_table[256]; | |
768 static int gg_crc32_initialized = 0; | |
769 | |
770 /* | |
771 * gg_crc32_make_table() // funkcja wewnętrzna | |
772 */ | |
773 static void gg_crc32_make_table() | |
774 { | |
775 uint32_t h = 1; | |
776 unsigned int i, j; | |
777 | |
778 memset(gg_crc32_table, 0, sizeof(gg_crc32_table)); | |
779 | |
780 for (i = 128; i; i >>= 1) { | |
781 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0); | |
782 | |
783 for (j = 0; j < 256; j += 2 * i) | |
784 gg_crc32_table[i + j] = gg_crc32_table[j] ^ h; | |
785 } | |
786 | |
787 gg_crc32_initialized = 1; | |
788 } | |
789 | |
790 /* | |
791 * gg_crc32() | |
792 * | |
793 * wyznacza sumę kontrolną CRC32 danego bloku danych. | |
794 * | |
795 * - crc - suma kontrola poprzedniego bloku danych lub 0 jeśli pierwszy | |
796 * - buf - bufor danych | |
797 * - size - ilość danych | |
798 * | |
799 * suma kontrolna CRC32. | |
800 */ | |
801 uint32_t gg_crc32(uint32_t crc, const unsigned char *buf, int len) | |
802 { | |
803 if (!gg_crc32_initialized) | |
804 gg_crc32_make_table(); | |
805 | |
806 if (!buf || len < 0) | |
807 return crc; | |
808 | |
809 crc ^= 0xffffffffL; | |
810 | |
811 while (len--) | |
812 crc = (crc >> 8) ^ gg_crc32_table[(crc ^ *buf++) & 0xff]; | |
813 | |
814 return crc ^ 0xffffffffL; | |
815 } | |
816 | |
817 | |
818 /* | |
819 * Local variables: | |
820 * c-indentation-style: k&r | |
821 * c-basic-offset: 8 | |
822 * indent-tabs-mode: notnil | |
823 * End: | |
824 * | |
825 * vim: shiftwidth=8: | |
826 */ |