libpurple/protocols/gg/lib/common.c

changeset 35557
e83a87761544
parent 33710
0d7ead568881
child 35573
d9a333109990
equal deleted inserted replaced
35554:fdd1f3a3c6df 35557:e83a87761544
1 /* $Id: common.c 1101 2011-05-05 21:17:28Z wojtekka $ */ 1 /* $Id$ */
2 2
3 /* 3 /*
4 * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl> 4 * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl>
5 * Robert J. Woźny <speedy@ziew.org> 5 * Robert J. Woźny <speedy@ziew.org>
6 * 6 *
22 /** 22 /**
23 * \file common.c 23 * \file common.c
24 * 24 *
25 * \brief Funkcje wykorzystywane przez różne moduły biblioteki 25 * \brief Funkcje wykorzystywane przez różne moduły biblioteki
26 */ 26 */
27 #include "compat.h" 27
28 #include <sys/types.h> 28 #include "network.h"
29 #include "strman.h"
29 #ifdef sun 30 #ifdef sun
30 # include <sys/filio.h> 31 # include <sys/filio.h>
31 #endif 32 #endif
32 33
33 #include <errno.h> 34 #include <errno.h>
34 #include <fcntl.h>
35 #include <stdarg.h> 35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h> 36 #include <stdlib.h>
38 #include <string.h> 37 #include <string.h>
39 #include <unistd.h> 38 #include <ctype.h>
40 39 #include <time.h>
40
41 #include "config.h"
41 #include "libgadu.h" 42 #include "libgadu.h"
43 #include "internal.h"
44
45 #ifndef GG_CONFIG_HAVE_VA_COPY
46 # ifdef GG_CONFIG_HAVE___VA_COPY
47 # define va_copy(dest, src) __va_copy((dest), (src))
48 # else
49 /* Taka wersja va_copy() działa poprawnie tylko na platformach, które
50 * va_copy() de facto wcale nie potrzebują, np. MSVC. Definicja tylko dla
51 * przejrzystości kodu. */
52 # define va_copy(dest, src) (dest) = (src)
53 # endif
54 #endif
42 55
43 /** 56 /**
44 * \internal Odpowiednik funkcji \c vsprintf alokujący miejsce na wynik. 57 * \internal Odpowiednik funkcji \c vsprintf alokujący miejsce na wynik.
45 * 58 *
46 * Funkcja korzysta z funkcji \c vsnprintf, sprawdzając czy dostępna funkcja 59 * Funkcja korzysta z funkcji \c vsnprintf, sprawdzając czy dostępna funkcja
53 * 66 *
54 * \ingroup helper 67 * \ingroup helper
55 */ 68 */
56 char *gg_vsaprintf(const char *format, va_list ap) 69 char *gg_vsaprintf(const char *format, va_list ap)
57 { 70 {
58 int size = 0; 71 int size;
59 char *buf = NULL; 72 char *buf = NULL;
60
61 #ifdef GG_CONFIG_HAVE_VA_COPY
62 va_list aq; 73 va_list aq;
63 74
64 va_copy(aq, ap); 75 #if !defined(GG_CONFIG_HAVE_C99_VSNPRINTF) && !defined(HAVE__VSCPRINTF)
65 #else
66 # ifdef GG_CONFIG_HAVE___VA_COPY
67 va_list aq;
68
69 __va_copy(aq, ap);
70 # endif
71 #endif
72
73 #ifndef GG_CONFIG_HAVE_C99_VSNPRINTF
74 { 76 {
75 int res; 77 int res = 0;
76 char *tmp; 78 char *tmp;
77 79
78 size = 128; 80 size = 128;
79 do { 81 do {
80 size *= 2; 82 if (res > size) {
81 if (!(tmp = realloc(buf, size + 1))) { 83 /* Jednak zachowanie zgodne z C99. */
84 size = res + 1;
85 } else {
86 size *= 2;
87 }
88
89 if (!(tmp = realloc(buf, size))) {
82 free(buf); 90 free(buf);
83 return NULL; 91 return NULL;
84 } 92 }
93
85 buf = tmp; 94 buf = tmp;
86 res = vsnprintf(buf, size, format, ap); 95 va_copy(aq, ap);
87 } while (res >= size - 1 || res == -1); 96 res = vsnprintf(buf, size, format, aq);
97 va_end(aq);
98 } while (res >= size || res < 0);
88 } 99 }
89 #else 100 #else
101 va_copy(aq, ap);
102
103 # ifdef HAVE__VSCPRINTF
104 size = _vscprintf(format, aq) + 1;
105 # else
90 { 106 {
91 char tmp[2]; 107 char tmp[2];
92 108
93 /* libce Solarisa przy buforze NULL zawsze zwracają -1, więc 109 /* libce Solarisa przy buforze NULL zawsze zwracają -1, więc
94 * musimy podać coś istniejącego jako cel printf()owania. */ 110 * musimy podać coś istniejącego jako cel printf()owania. */
95 size = vsnprintf(tmp, sizeof(tmp), format, ap); 111 size = vsnprintf(tmp, sizeof(tmp), format, aq) + 1;
96 if (!(buf = malloc(size + 1))) 112 }
97 return NULL; 113 # endif
98 }
99 #endif
100
101 #ifdef GG_CONFIG_HAVE_VA_COPY
102 vsnprintf(buf, size + 1, format, aq);
103 va_end(aq); 114 va_end(aq);
104 #else 115 if (!(buf = malloc(size)))
105 # ifdef GG_CONFIG_HAVE___VA_COPY 116 return NULL;
106 vsnprintf(buf, size + 1, format, aq); 117
107 va_end(aq); 118 vsnprintf(buf, size, format, ap);
108 # else
109 vsnprintf(buf, size + 1, format, ap);
110 # endif
111 #endif 119 #endif
112 120
113 return buf; 121 return buf;
114 } 122 }
115 123
143 * Funkcja niszczy bufor źródłowy bezpowrotnie, dzieląc go na kolejne ciągi 151 * Funkcja niszczy bufor źródłowy bezpowrotnie, dzieląc go na kolejne ciągi
144 * znaków i obcina znaki końca linii. 152 * znaków i obcina znaki końca linii.
145 * 153 *
146 * \param ptr Wskaźnik do zmiennej, która przechowuje aktualne położenie 154 * \param ptr Wskaźnik do zmiennej, która przechowuje aktualne położenie
147 * w analizowanym buforze 155 * w analizowanym buforze
156 *
157 * \note Funkcja nie jest już używana. Pozostała dla zachowania ABI.
148 * 158 *
149 * \return Wskaźnik do kolejnej linii tekstu lub NULL, jeśli to już koniec 159 * \return Wskaźnik do kolejnej linii tekstu lub NULL, jeśli to już koniec
150 * bufora. 160 * bufora.
151 */ 161 */
152 char *gg_get_line(char **ptr) 162 char *gg_get_line(char **ptr)
178 * \internal Czyta linię tekstu z gniazda. 188 * \internal Czyta linię tekstu z gniazda.
179 * 189 *
180 * Funkcja czyta tekst znak po znaku, więc nie jest efektywna, ale dzięki 190 * Funkcja czyta tekst znak po znaku, więc nie jest efektywna, ale dzięki
181 * brakowi buforowania, nie koliduje z innymi funkcjami odczytu. 191 * brakowi buforowania, nie koliduje z innymi funkcjami odczytu.
182 * 192 *
193 * \note W przypadku zakończenia połączenia przez drugą stronę, ostatnia
194 * linia nie jest zwracana.
195 *
183 * \param sock Deskryptor gniazda 196 * \param sock Deskryptor gniazda
184 * \param buf Wskaźnik do bufora 197 * \param buf Wskaźnik do bufora
185 * \param length Długość bufora 198 * \param length Długość bufora
186 * 199 *
187 * \return Zwraca \c buf jeśli się powiodło, lub \c NULL w przypadku błędu. 200 * \return Zwraca wskaźnik na koniec odebranej linii jeśli się powiodło,
201 * lub \c NULL w przypadku błędu.
188 */ 202 */
189 char *gg_read_line(int sock, char *buf, int length) 203 char *gg_read_line(int sock, char *buf, int length)
190 { 204 {
191 int ret; 205 int ret;
192 206
193 if (!buf || length < 0) 207 if (!buf || length < 0)
194 return NULL; 208 return NULL;
195 209
196 for (; length > 1; buf++, length--) { 210 for (; length > 1; buf++, length--) {
197 do { 211 do {
198 if ((ret = read(sock, buf, 1)) == -1 && errno != EINTR && errno != EAGAIN) { 212 if ((ret = recv(sock, buf, 1, 0)) == -1 && errno != EINTR && errno != EAGAIN) {
199 gg_debug(GG_DEBUG_MISC, "// gg_read_line() error on read (errno=%d, %s)\n", errno, strerror(errno)); 213 gg_debug(GG_DEBUG_MISC, "// gg_read_line() error on read (errno=%d, %s)\n", errno, strerror(errno));
200 *buf = 0; 214 *buf = 0;
201 return NULL; 215 return NULL;
202 } else if (ret == 0) { 216 } else if (ret == 0) {
203 gg_debug(GG_DEBUG_MISC, "// gg_read_line() eof reached\n"); 217 gg_debug(GG_DEBUG_MISC, "// gg_read_line() eof reached\n");
227 * 241 *
228 * \ingroup helper 242 * \ingroup helper
229 */ 243 */
230 int gg_connect(void *addr, int port, int async) 244 int gg_connect(void *addr, int port, int async)
231 { 245 {
232 int sock, one = 1, errno2; 246 int sock, errno2;
233 struct sockaddr_in sin; 247 struct sockaddr_in sin;
234 struct in_addr *a = addr; 248 struct in_addr *a = addr;
235 struct sockaddr_in myaddr; 249 struct sockaddr_in myaddr;
236 250
237 gg_debug(GG_DEBUG_FUNCTION, "** gg_connect(%s, %d, %d);\n", inet_ntoa(*a), port, async); 251 gg_debug(GG_DEBUG_FUNCTION, "** gg_connect(%s, %d, %d);\n", inet_ntoa(*a), port, async);
254 return -1; 268 return -1;
255 } 269 }
256 270
257 if (async) { 271 if (async) {
258 #ifdef FIONBIO 272 #ifdef FIONBIO
273 int one = 1;
274
259 if (ioctl(sock, FIONBIO, &one) == -1) { 275 if (ioctl(sock, FIONBIO, &one) == -1) {
260 #else 276 #else
261 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) { 277 if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) {
262 #endif 278 #endif
263 gg_debug(GG_DEBUG_MISC, "// gg_connect() ioctl() failed (errno=%d, %s)\n", errno, strerror(errno)); 279 gg_debug(GG_DEBUG_MISC, "// gg_connect() can't set nonblocking (errno=%d, %s)\n", errno, strerror(errno));
264 errno2 = errno; 280 errno2 = errno;
265 close(sock); 281 close(sock);
266 errno = errno2; 282 errno = errno2;
267 return -1; 283 return -1;
268 } 284 }
382 int b = -1; 398 int b = -1;
383 399
384 va_start(ap, format); 400 va_start(ap, format);
385 401
386 for (j = 0; j < strlen(format); j++) { 402 for (j = 0; j < strlen(format); j++) {
387 char *arg, buf[16]; 403 const char *arg;
404 char buf[16];
388 405
389 if (format[j] == 'u') { 406 if (format[j] == 'u') {
390 snprintf(buf, sizeof(buf), "%d", va_arg(ap, uin_t)); 407 snprintf(buf, sizeof(buf), "%d", va_arg(ap, uin_t));
391 arg = buf; 408 arg = buf;
392 } else { 409 } else {
484 */ 501 */
485 char *gg_base64_decode(const char *buf) 502 char *gg_base64_decode(const char *buf)
486 { 503 {
487 char *res, *save, *foo, val; 504 char *res, *save, *foo, val;
488 const char *end; 505 const char *end;
489 unsigned int index = 0; 506 unsigned int idx = 0;
490 507
491 if (!buf) 508 if (!buf)
492 return NULL; 509 return NULL;
493 510
494 save = res = calloc(1, (strlen(buf) / 4 + 1) * 3 + 2); 511 save = res = calloc(1, (strlen(buf) / 4 + 1) * 3 + 2);
501 while (*buf && buf < end) { 518 while (*buf && buf < end) {
502 if (*buf == '\r' || *buf == '\n') { 519 if (*buf == '\r' || *buf == '\n') {
503 buf++; 520 buf++;
504 continue; 521 continue;
505 } 522 }
506 if (!(foo = strchr(gg_base64_charset, *buf))) 523 if (!(foo = memchr(gg_base64_charset, *buf, sizeof(gg_base64_charset))))
507 foo = gg_base64_charset; 524 foo = gg_base64_charset;
508 val = (int)(foo - gg_base64_charset); 525 val = (int)(foo - gg_base64_charset);
509 buf++; 526 buf++;
510 switch (index) { 527 switch (idx) {
511 case 0: 528 case 0:
512 *res |= val << 2; 529 *res |= val << 2;
513 break; 530 break;
514 case 1: 531 case 1:
515 *res++ |= val >> 4; 532 *res++ |= val >> 4;
521 break; 538 break;
522 case 3: 539 case 3:
523 *res++ |= val; 540 *res++ |= val;
524 break; 541 break;
525 } 542 }
526 index++; 543 idx++;
527 index %= 4; 544 idx %= 4;
528 } 545 }
529 *res = 0; 546 *res = 0;
530 547
531 return save; 548 return save;
532 } 549 }
664 crc = (crc >> 8) ^ gg_crc32_table[(crc ^ *buf++) & 0xff]; 681 crc = (crc >> 8) ^ gg_crc32_table[(crc ^ *buf++) & 0xff];
665 682
666 return crc ^ 0xffffffffL; 683 return crc ^ 0xffffffffL;
667 } 684 }
668 685
686 /**
687 * \internal Parsuje identyfikator użytkownika.
688 *
689 * \param str Ciąg tekstowy, zawierający identyfikator
690 * \param len Długość identyfikatora
691 *
692 * \return Identyfikator, lub 0, jeżeli nie udało się odczytać
693 */
694 uin_t gg_str_to_uin(const char *str, int len)
695 {
696 char buff[11];
697 char *endptr;
698 uin_t uin;
699
700 if (len < 0)
701 len = strlen(str);
702 if (len > 10)
703 return 0;
704 memcpy(buff, str, len);
705 buff[len] = '\0';
706
707 errno = 0;
708 uin = strtoul(buff, &endptr, 10);
709 if (errno == ERANGE || endptr[0] != '\0')
710 return 0;
711
712 return uin;
713 }
714
715 /**
716 * Szuka informacji o konferencji o podanym identyfikatorze.
717 *
718 * \param sess Struktura sesji
719 * \param id Identyfikator konferencji
720 *
721 * \return Struktura z informacjami o konferencji
722 */
723 gg_chat_list_t *gg_chat_find(struct gg_session *sess, uint64_t id)
724 {
725 gg_chat_list_t *chat_list = sess->private_data->chat_list;
726
727 while (chat_list != NULL)
728 {
729 if (chat_list->id == id)
730 return chat_list;
731 chat_list = chat_list->next;
732 }
733
734 return NULL;
735 }
736
737 /**
738 * \internal Aktualizuje informacje o konferencji.
739 *
740 * \param sess Struktura sesji
741 * \param id Identyfikator konferencji
742 * \param version Wersja informacji o konferencji
743 * \param participants Lista uczestników konferencji
744 * \param participants_count Ilość uczestników konferencji
745 *
746 * \return Wartość równa 0, jeżeli zakończono powodzeniem
747 */
748 int gg_chat_update(struct gg_session *sess, uint64_t id, uint32_t version,
749 const uin_t *participants, unsigned int participants_count)
750 {
751 gg_chat_list_t *chat;
752 uin_t *participants_new;
753
754 if (participants_count >= ~0 / sizeof(uin_t))
755 return -1;
756
757 chat = gg_chat_find(sess, id);
758
759 if (!chat) {
760 chat = malloc(sizeof(gg_chat_list_t));
761
762 if (!chat)
763 return -1;
764
765 memset(chat, 0, sizeof(gg_chat_list_t));
766 chat->id = id;
767 chat->next = sess->private_data->chat_list;
768 sess->private_data->chat_list = chat;
769 }
770
771 participants_new = realloc(chat->participants,
772 sizeof(uin_t) * participants_count);
773
774 if (participants_new == NULL)
775 return -1;
776
777 chat->version = version;
778 chat->participants = participants_new;
779 chat->participants_count = participants_count;
780 memcpy(chat->participants, participants,
781 sizeof(uin_t) * participants_count);
782
783 return 0;
784 }
785
786 void gg_connection_failure(struct gg_session *gs, struct gg_event *ge,
787 enum gg_failure_t failure)
788 {
789 gg_close(gs);
790
791 if (ge != NULL) {
792 ge->type = GG_EVENT_CONN_FAILED;
793 ge->event.failure = failure;
794 }
795 gs->state = GG_STATE_IDLE;
796 }
797
798 time_t gg_server_time(struct gg_session *gs)
799 {
800 time_t now = time(NULL);
801
802 if (gs == NULL || gs->private_data == NULL) {
803 gg_debug_session(gs, GG_DEBUG_ERROR, "time diff data is not "
804 "accessible\n");
805 return now;
806 }
807
808 return now + gs->private_data->time_diff;
809 }
810
811 void gg_strarr_free(char **strarr)
812 {
813 char **it;
814
815 if (strarr == NULL)
816 return;
817
818 for (it = strarr; *it != NULL; it++)
819 free(*it);
820 free(strarr);
821 }
822
823 char ** gg_strarr_dup(char **strarr)
824 {
825 if (strarr == NULL)
826 return NULL;
827
828 size_t i, len, size;
829 char **it, **out;
830
831 len = 0;
832 for (it = strarr; *it != NULL; it++)
833 len++;
834
835 size = (len + 1) * sizeof(char*);
836 out = malloc(size);
837
838 if (out == NULL) {
839 gg_debug(GG_DEBUG_MISC | GG_DEBUG_ERROR, "// gg_strarr_dup() "
840 "not enough memory for the array\n");
841 return NULL;
842 }
843 memset(out, 0, size);
844
845 for (i = 0; i < len; i++) {
846 out[i] = strdup(strarr[i]);
847 if (out[i] == NULL) {
848 gg_debug(GG_DEBUG_MISC | GG_DEBUG_ERROR,
849 "// gg_strarr_dup() "
850 "not enough memory for the array element\n");
851 gg_strarr_free(out);
852 return NULL;
853 }
854 }
855
856 return out;
857 }
858
669 /* 859 /*
670 * Local variables: 860 * Local variables:
671 * c-indentation-style: k&r 861 * c-indentation-style: k&r
672 * c-basic-offset: 8 862 * c-basic-offset: 8
673 * indent-tabs-mode: notnil 863 * indent-tabs-mode: notnil

mercurial