| 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 |
| 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); |
| 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 |