connwrap - initialize gnutls session in cw_connect
[centerim.git] / libgadu / common.c
blobae21d2866e25f28e89c08cc4df9745cb160dee47
1 /* $Id: common.c,v 1.3 2004/07/31 10:47:20 konst Exp $ */
3 /*
4 * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl>
5 * Robert J. Wo¼ny <speedy@ziew.org>
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.
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.
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., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #include <sys/types.h>
22 #include <sys/ioctl.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #ifdef sun
27 # include <sys/filio.h>
28 #endif
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <netdb.h>
33 #include <stdarg.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
39 #include "libgadu.h"
41 FILE *gg_debug_file = NULL;
43 #ifndef GG_DEBUG_DISABLE
46 * gg_debug() // funkcja wewnêtrzna
48 * wy¶wietla komunikat o danym poziomie, o ile u¿ytkownik sobie tego ¿yczy.
50 * - level - poziom wiadomo¶ci
51 * - format... - tre¶æ wiadomo¶ci (kompatybilna z printf())
53 void gg_debug(int level, const char *format, ...)
55 va_list ap;
56 int old_errno = errno;
58 if (gg_debug_handler) {
59 va_start(ap, format);
60 (*gg_debug_handler)(level, format, ap);
61 va_end(ap);
63 goto cleanup;
66 if ((gg_debug_level & level)) {
67 va_start(ap, format);
68 vfprintf((gg_debug_file) ? gg_debug_file : stderr, format, ap);
69 va_end(ap);
72 cleanup:
73 errno = old_errno;
76 #endif
79 * gg_vsaprintf() // funkcja pomocnicza
81 * robi dok³adnie to samo, co vsprintf(), tyle ¿e alokuje sobie wcze¶niej
82 * miejsce na dane. powinno dzia³aæ na tych maszynach, które maj± funkcjê
83 * vsnprintf() zgodn± z C99, jak i na wcze¶niejszych.
85 * - format - opis wy¶wietlanego tekstu jak dla printf()
86 * - ap - lista argumentów dla printf()
88 * zaalokowany bufor, który nale¿y pó¼niej zwolniæ, lub NULL
89 * je¶li nie uda³o siê wykonaæ zadania.
91 char *gg_vsaprintf(const char *format, va_list ap)
93 int size = 0;
94 const char *start;
95 char *buf = NULL;
97 #ifdef __GG_LIBGADU_HAVE_VA_COPY
98 va_list aq;
100 va_copy(aq, ap);
101 #else
102 # ifdef __GG_LIBGADU_HAVE___VA_COPY
103 va_list aq;
105 __va_copy(aq, ap);
106 # endif
107 #endif
109 start = format;
111 #ifndef __GG_LIBGADU_HAVE_C99_VSNPRINTF
113 int res;
114 char *tmp;
116 size = 256;
117 do {
118 size *= 2;
119 if (!(tmp = realloc(buf, size))) {
120 free(buf);
121 return NULL;
123 buf = tmp;
124 res = vsnprintf(buf, size, format, ap);
125 } while (res == size - 1 || res == -1);
127 #else
129 char tmp[2];
131 /* libce Solarisa przy buforze NULL zawsze zwracaj± -1, wiêc
132 * musimy podaæ co¶ istniej±cego jako cel printf()owania. */
133 size = vsnprintf(tmp, sizeof(tmp), format, ap);
134 if (!(buf = malloc(size + 1)))
135 return NULL;
137 #endif
139 format = start;
141 #ifdef __GG_LIBGADU_HAVE_VA_COPY
142 vsnprintf(buf, size + 1, format, aq);
143 va_end(aq);
144 #else
145 # ifdef __GG_LIBGADU_HAVE___VA_COPY
146 vsnprintf(buf, size + 1, format, aq);
147 va_end(aq);
148 # else
149 vsnprintf(buf, size + 1, format, ap);
150 # endif
151 #endif
153 return buf;
157 * gg_saprintf() // funkcja pomocnicza
159 * robi dok³adnie to samo, co sprintf(), tyle ¿e alokuje sobie wcze¶niej
160 * miejsce na dane. powinno dzia³aæ na tych maszynach, które maj± funkcjê
161 * vsnprintf() zgodn± z C99, jak i na wcze¶niejszych.
163 * - format... - tre¶æ taka sama jak w funkcji printf()
165 * zaalokowany bufor, który nale¿y pó¼niej zwolniæ, lub NULL
166 * je¶li nie uda³o siê wykonaæ zadania.
168 char *gg_saprintf(const char *format, ...)
170 va_list ap;
171 char *res;
173 va_start(ap, format);
174 res = gg_vsaprintf(format, ap);
175 va_end(ap);
177 return res;
181 * gg_get_line() // funkcja pomocnicza
183 * podaje kolejn± liniê z bufora tekstowego. niszczy go bezpowrotnie, dziel±c
184 * na kolejne stringi. zdarza siê, nie ma potrzeby pisania funkcji dubluj±cej
185 * bufor ¿eby tylko mieæ nieruszone dane wej¶ciowe, skoro i tak nie bêd± nam
186 * po¼niej potrzebne. obcina `\r\n'.
188 * - ptr - wska¼nik do zmiennej, która przechowuje aktualn± pozycjê
189 * w przemiatanym buforze
191 * wska¼nik do kolejnej linii tekstu lub NULL, je¶li to ju¿ koniec bufora.
193 char *gg_get_line(char **ptr)
195 char *foo, *res;
197 if (!ptr || !*ptr || !strcmp(*ptr, ""))
198 return NULL;
200 res = *ptr;
202 if (!(foo = strchr(*ptr, '\n')))
203 *ptr += strlen(*ptr);
204 else {
205 *ptr = foo + 1;
206 *foo = 0;
207 if (strlen(res) > 1 && res[strlen(res) - 1] == '\r')
208 res[strlen(res) - 1] = 0;
211 return res;
215 * gg_connect() // funkcja pomocnicza
217 * ³±czy siê z serwerem. pierwszy argument jest typu (void *), ¿eby nie
218 * musieæ niczego inkludowaæ w libgadu.h i nie psuæ jaki¶ g³upich zale¿no¶ci
219 * na dziwnych systemach.
221 * - addr - adres serwera (struct in_addr *)
222 * - port - port serwera
223 * - async - asynchroniczne po³±czenie
225 * deskryptor gniazda lub -1 w przypadku b³êdu (kod b³êdu w zmiennej errno).
227 int gg_connect(void *addr, int port, int async)
229 int sock, one = 1;
230 struct sockaddr_in sin;
231 struct in_addr *a = addr;
233 gg_debug(GG_DEBUG_FUNCTION, "** gg_connect(%s, %d, %d);\n", inet_ntoa(*a), port, async);
235 if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
236 gg_debug(GG_DEBUG_MISC, "// gg_connect() socket() failed (errno=%d, %s)\n", errno, strerror(errno));
237 return -1;
240 #ifdef ASSIGN_SOCKETS_TO_THREADS
241 gg_win32_thread_socket(0, sock);
242 #endif
244 if (async) {
245 #ifdef FIONBIO
246 if (ioctl(sock, FIONBIO, &one) == -1) {
247 #else
248 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
249 #endif
250 gg_debug(GG_DEBUG_MISC, "// gg_connect() ioctl() failed (errno=%d, %s)\n", errno, strerror(errno));
251 close(sock);
252 return -1;
256 sin.sin_port = htons(port);
257 sin.sin_family = AF_INET;
258 sin.sin_addr.s_addr = a->s_addr;
260 if(cw_connect(sock, (struct sockaddr*) &sin, sizeof(sin), 0) == -1) {
261 if (errno && (!async || errno != EINPROGRESS)) {
262 gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() failed (errno=%d, %s)\n", errno, strerror(errno));
263 close(sock);
264 return -1;
266 gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() in progress\n");
269 return sock;
273 * gg_read_line() // funkcja pomocnicza
275 * czyta jedn± liniê tekstu z gniazda.
277 * - sock - deskryptor gniazda
278 * - buf - wska¼nik do bufora
279 * - length - d³ugo¶æ bufora
281 * je¶li trafi na b³±d odczytu, zwraca NULL. inaczej zwraca buf.
283 char *gg_read_line(int sock, char *buf, int length)
285 int ret;
287 if (!buf || length < 0)
288 return NULL;
289 for (; length > 1; buf++, length--) {
290 do {
291 if ((ret = read(sock, buf, 1)) == -1 && errno != EINTR) {
292 gg_debug(GG_DEBUG_MISC, "// gg_read_line() error on read (errno=%d, %s)\n", errno, strerror(errno));
293 *buf = 0;
294 return NULL;
295 } else if (ret == 0) {
296 gg_debug(GG_DEBUG_MISC, "// gg_read_line() eof reached\n");
297 *buf = 0;
298 return NULL;
300 } while (ret == -1 && errno == EINTR);
302 if (*buf == '\n') {
303 buf++;
304 break;
308 *buf = 0;
309 return buf;
313 * gg_chomp() // funkcja pomocnicza
315 * ucina "\r\n" lub "\n" z koñca linii.
317 * - line - linia do przyciêcia
319 void gg_chomp(char *line)
321 if (!line || strlen(line) < 1)
322 return;
324 if (line[strlen(line) - 1] == '\n')
325 line[strlen(line) - 1] = 0;
326 if (line[strlen(line) - 1] == '\r')
327 line[strlen(line) - 1] = 0;
331 * gg_urlencode() // funkcja wewnêtrzna
333 * zamienia podany tekst na ci±g znaków do formularza http. przydaje siê
334 * przy ró¿nych us³ugach katalogu publicznego.
336 * - str - ci±g znaków do zakodowania
338 * zaalokowany bufor, który nale¿y pó¼niej zwolniæ albo NULL
339 * w przypadku b³êdu.
341 char *gg_urlencode(const char *str)
343 char *q, *buf, hex[] = "0123456789abcdef";
344 const char *p;
345 unsigned int size = 0;
347 if (!str && !(str = strdup("")))
348 return NULL;
350 for (p = str; *p; p++, size++) {
351 if (!((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == ' ') || (*p == '@') || (*p == '.') || (*p == '-'))
352 size += 2;
355 if (!(buf = malloc(size + 1)))
356 return NULL;
358 for (p = str, q = buf; *p; p++, q++) {
359 if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || (*p == '@') || (*p == '.') || (*p == '-'))
360 *q = *p;
361 else {
362 if (*p == ' ')
363 *q = '+';
364 else {
365 *q++ = '%';
366 *q++ = hex[*p >> 4 & 15];
367 *q = hex[*p & 15];
372 *q = 0;
374 return buf;
378 * gg_http_hash() // funkcja wewnêtrzna
380 * funkcja licz±ca hash dla adresu e-mail, has³a i paru innych.
382 * - format... - format kolejnych parametrów ('s' je¶li dany parametr jest
383 * ci±giem znaków lub 'u' je¶li numerem GG)
385 * hash wykorzystywany przy rejestracji i wszelkich manipulacjach w³asnego
386 * wpisu w katalogu publicznym.
388 int gg_http_hash(const char *format, ...)
390 unsigned int a, c, i, j;
391 va_list ap;
392 int b = -1;
394 va_start(ap, format);
396 for (j = 0; j < strlen(format); j++) {
397 char *arg, buf[16];
399 if (format[j] == 'u') {
400 snprintf(buf, sizeof(buf), "%d", va_arg(ap, uin_t));
401 arg = buf;
402 } else {
403 if (!(arg = va_arg(ap, char*)))
404 arg = "";
407 i = 0;
408 while ((c = (unsigned char) arg[i++]) != 0) {
409 a = (c ^ b) + (c << 8);
410 b = (a >> 24) | (a << 8);
414 va_end(ap);
416 return (b < 0 ? -b : b);
420 * gg_gethostbyname() // funkcja pomocnicza
422 * odpowiednik gethostbyname() u¿ywaj±cy gethostbyname_r(), gdy potrzebna
423 * jest wielobie¿no¶æ. chwilowo korzysta ze zwyk³ego gethostbyname().
425 * - hostname - nazwa serwera
427 * zaalokowany bufor, który nale¿y zwolniæ lub NULL w przypadku b³êdu.
429 struct hostent *gg_gethostbyname(const char *hostname)
431 /* XXX u¿yæ gethostbyname_r() */
433 struct hostent *hp, *hp2;
435 if (!(hp = gethostbyname(hostname)))
436 return NULL;
438 if (!(hp2 = calloc(1, sizeof(*hp))))
439 return NULL;
441 memcpy(hp2, hp, sizeof(*hp));
443 return hp2;
446 #ifdef ASSIGN_SOCKETS_TO_THREADS
448 typedef struct gg_win32_thread {
449 int id;
450 int socket;
451 struct gg_win32_thread *next;
452 } gg_win32_thread;
454 struct gg_win32_thread *gg_win32_threads = 0;
457 * gg_win32_thread_socket() // funkcja pomocnicza, tylko dla win32
459 * zwraca deskryptor gniazda, które by³o ostatnio tworzone dla w±tku
460 * o podanym identyfikatorze.
462 * je¶li na win32 przy po³±czeniach synchronicznych zapamiêtamy w jakim
463 * w±tku uruchomili¶my funkcjê, która siê z czymkolwiek ³±czy, to z osobnego
464 * w±tku mo¿emy anulowaæ po³±czenie poprzez gg_win32_thread_socket(watek, -1);
466 * - thread_id - id w±tku. je¶li jest równe 0, brany jest aktualny w±tek,
467 * je¶li równe -1, usuwa wpis o podanym sockecie.
468 * - socket - deskryptor gniazda. je¶li równe 0, zwraca deskryptor gniazda
469 * dla podanego w±tku, je¶li równe -1, usuwa wpis, je¶li co¶
470 * innego, ustawia dla podanego w±tku dany numer deskryptora.
472 * je¶li socket jest równe 0, zwraca deskryptor gniazda dla podanego w±tku.
474 int gg_win32_thread_socket(int thread_id, int socket)
476 char close = (thread_id == -1) || socket == -1;
477 gg_win32_thread *wsk = gg_win32_threads;
478 gg_win32_thread **p_wsk = &gg_win32_threads;
480 if (!thread_id)
481 thread_id = GetCurrentThreadId();
483 while (wsk) {
484 if ((thread_id == -1 && wsk->socket == socket) || wsk->id == thread_id) {
485 if (close) {
486 /* socket zostaje usuniety */
487 closesocket(wsk->socket);
488 *p_wsk = wsk->next;
489 free(wsk);
490 return 1;
491 } else if (!socket) {
492 /* socket zostaje zwrocony */
493 return wsk->socket;
494 } else {
495 /* socket zostaje ustawiony */
496 wsk->socket = socket;
497 return socket;
501 p_wsk = &(wsk->next);
502 wsk = wsk->next;
505 if (close && socket != -1)
506 closesocket(socket);
507 if (close || !socket)
508 return 0;
510 /* Dodaje nowy element */
511 wsk = malloc(sizeof(gg_win32_thread));
512 wsk->id = thread_id;
513 wsk->socket = socket;
514 wsk->next = 0;
515 *p_wsk = wsk;
517 return socket;
520 #endif /* ASSIGN_SOCKETS_TO_THREADS */
522 static char gg_base64_charset[] =
523 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
526 * gg_base64_encode()
528 * zapisuje ci±g znaków w base64.
530 * - buf - ci±g znaków.
532 * zaalokowany bufor.
534 char *gg_base64_encode(const char *buf)
536 char *out, *res;
537 unsigned int i = 0, j = 0, k = 0, len = strlen(buf);
539 res = out = malloc((len / 3 + 1) * 4 + 2);
541 if (!res)
542 return NULL;
544 while (j <= len) {
545 switch (i % 4) {
546 case 0:
547 k = (buf[j] & 252) >> 2;
548 break;
549 case 1:
550 if (j < len)
551 k = ((buf[j] & 3) << 4) | ((buf[j + 1] & 240) >> 4);
552 else
553 k = (buf[j] & 3) << 4;
555 j++;
556 break;
557 case 2:
558 if (j < len)
559 k = ((buf[j] & 15) << 2) | ((buf[j + 1] & 192) >> 6);
560 else
561 k = (buf[j] & 15) << 2;
563 j++;
564 break;
565 case 3:
566 k = buf[j++] & 63;
567 break;
569 *out++ = gg_base64_charset[k];
570 i++;
573 if (i % 4)
574 for (j = 0; j < 4 - (i % 4); j++, out++)
575 *out = '=';
577 *out = 0;
579 return res;
583 * gg_base64_decode()
585 * dekoduje ci±g znaków z base64.
587 * - buf - ci±g znaków.
589 * zaalokowany bufor.
591 char *gg_base64_decode(const char *buf)
593 char *res, *save, *foo, val;
594 const char *end;
595 unsigned int index = 0;
597 if (!buf)
598 return NULL;
600 save = res = calloc(1, (strlen(buf) / 4 + 1) * 3 + 2);
602 if (!save)
603 return NULL;
605 end = buf + strlen(buf);
607 while (*buf && buf < end) {
608 if (*buf == '\r' || *buf == '\n') {
609 buf++;
610 continue;
612 if (!(foo = strchr(gg_base64_charset, *buf)))
613 foo = gg_base64_charset;
614 val = (int)(foo - gg_base64_charset);
615 buf++;
616 switch (index) {
617 case 0:
618 *res |= val << 2;
619 break;
620 case 1:
621 *res++ |= val >> 4;
622 *res |= val << 4;
623 break;
624 case 2:
625 *res++ |= val >> 2;
626 *res |= val << 6;
627 break;
628 case 3:
629 *res++ |= val;
630 break;
632 index++;
633 index %= 4;
635 *res = 0;
637 return save;
641 * gg_proxy_auth() // funkcja wewnêtrzna
643 * tworzy nag³ówek autoryzacji dla proxy.
645 * zaalokowany tekst lub NULL, je¶li proxy nie jest w³±czone lub nie wymaga
646 * autoryzacji.
648 char *gg_proxy_auth()
650 char *tmp, *enc, *out;
651 unsigned int tmp_size;
653 if (!gg_proxy_enabled || !gg_proxy_username || !gg_proxy_password)
654 return NULL;
656 if (!(tmp = malloc((tmp_size = strlen(gg_proxy_username) + strlen(gg_proxy_password) + 2))))
657 return NULL;
659 snprintf(tmp, tmp_size, "%s:%s", gg_proxy_username, gg_proxy_password);
661 if (!(enc = gg_base64_encode(tmp))) {
662 free(tmp);
663 return NULL;
666 free(tmp);
668 if (!(out = malloc(strlen(enc) + 40))) {
669 free(enc);
670 return NULL;
673 snprintf(out, strlen(enc) + 40, "Proxy-Authorization: Basic %s\r\n", enc);
675 free(enc);
677 return out;
680 static uint32_t gg_crc32_table[256];
681 static int gg_crc32_initialized = 0;
684 * gg_crc32_make_table() // funkcja wewnêtrzna
686 static void gg_crc32_make_table()
688 uint32_t h = 0;
689 unsigned int i, j;
691 memset(gg_crc32_table, 0, sizeof(gg_crc32_table));
693 for (i = 128; i; i >>= 1) {
694 h = (h >> 1) ^ ((h & 1) ? 0xedb88320L : 0);
696 for (j = 0; j < 256; j += 2 * i)
697 gg_crc32_table[i + j] = gg_crc32_table[j] ^ h;
700 gg_crc32_initialized = 1;
704 * gg_crc32()
706 * wyznacza sumê kontroln± CRC32 danego bloku danych.
708 * - crc - suma kontrola poprzedniego bloku danych lub 0 je¶li pierwszy
709 * - buf - bufor danych
710 * - size - ilo¶æ danych
712 * suma kontrolna CRC32.
714 uint32_t gg_crc32(uint32_t crc, const unsigned char *buf, int len)
716 if (!gg_crc32_initialized)
717 gg_crc32_make_table();
718 if (!buf || len < 0)
719 return crc;
721 crc ^= 0xffffffffL;
723 while (len--)
724 crc = (crc >> 8) ^ gg_crc32_table[(crc ^ *buf++) & 0xff];
726 return crc ^ 0xffffffffL;
731 * Local variables:
732 * c-indentation-style: k&r
733 * c-basic-offset: 8
734 * indent-tabs-mode: notnil
735 * End:
737 * vim: shiftwidth=8: