diff -r fdd1f3a3c6df -r e83a87761544 libpurple/protocols/gg/lib/common.c --- a/libpurple/protocols/gg/lib/common.c Thu Feb 13 04:27:27 2014 +0100 +++ b/libpurple/protocols/gg/lib/common.c Thu Feb 13 18:29:10 2014 +0100 @@ -1,4 +1,4 @@ -/* $Id: common.c 1101 2011-05-05 21:17:28Z wojtekka $ */ +/* $Id$ */ /* * (C) Copyright 2001-2002 Wojtek Kaniewski @@ -24,21 +24,34 @@ * * \brief Funkcje wykorzystywane przez różne moduły biblioteki */ -#include "compat.h" -#include + +#include "network.h" +#include "strman.h" #ifdef sun # include #endif #include -#include #include -#include #include #include -#include +#include +#include + +#include "config.h" +#include "libgadu.h" +#include "internal.h" -#include "libgadu.h" +#ifndef GG_CONFIG_HAVE_VA_COPY +# ifdef GG_CONFIG_HAVE___VA_COPY +# define va_copy(dest, src) __va_copy((dest), (src)) +# else +/* Taka wersja va_copy() działa poprawnie tylko na platformach, które + * va_copy() de facto wcale nie potrzebują, np. MSVC. Definicja tylko dla + * przejrzystości kodu. */ +# define va_copy(dest, src) (dest) = (src) +# endif +#endif /** * \internal Odpowiednik funkcji \c vsprintf alokujący miejsce na wynik. @@ -55,59 +68,54 @@ */ char *gg_vsaprintf(const char *format, va_list ap) { - int size = 0; + int size; char *buf = NULL; - -#ifdef GG_CONFIG_HAVE_VA_COPY va_list aq; - va_copy(aq, ap); -#else -# ifdef GG_CONFIG_HAVE___VA_COPY - va_list aq; - - __va_copy(aq, ap); -# endif -#endif - -#ifndef GG_CONFIG_HAVE_C99_VSNPRINTF +#if !defined(GG_CONFIG_HAVE_C99_VSNPRINTF) && !defined(HAVE__VSCPRINTF) { - int res; + int res = 0; char *tmp; size = 128; do { - size *= 2; - if (!(tmp = realloc(buf, size + 1))) { + if (res > size) { + /* Jednak zachowanie zgodne z C99. */ + size = res + 1; + } else { + size *= 2; + } + + if (!(tmp = realloc(buf, size))) { free(buf); return NULL; } + buf = tmp; - res = vsnprintf(buf, size, format, ap); - } while (res >= size - 1 || res == -1); + va_copy(aq, ap); + res = vsnprintf(buf, size, format, aq); + va_end(aq); + } while (res >= size || res < 0); } #else + va_copy(aq, ap); + +# ifdef HAVE__VSCPRINTF + size = _vscprintf(format, aq) + 1; +# else { char tmp[2]; /* libce Solarisa przy buforze NULL zawsze zwracają -1, więc * musimy podać coś istniejącego jako cel printf()owania. */ - size = vsnprintf(tmp, sizeof(tmp), format, ap); - if (!(buf = malloc(size + 1))) - return NULL; + size = vsnprintf(tmp, sizeof(tmp), format, aq) + 1; } -#endif +# endif + va_end(aq); + if (!(buf = malloc(size))) + return NULL; -#ifdef GG_CONFIG_HAVE_VA_COPY - vsnprintf(buf, size + 1, format, aq); - va_end(aq); -#else -# ifdef GG_CONFIG_HAVE___VA_COPY - vsnprintf(buf, size + 1, format, aq); - va_end(aq); -# else - vsnprintf(buf, size + 1, format, ap); -# endif + vsnprintf(buf, size, format, ap); #endif return buf; @@ -146,6 +154,8 @@ * \param ptr Wskaźnik do zmiennej, która przechowuje aktualne położenie * w analizowanym buforze * + * \note Funkcja nie jest już używana. Pozostała dla zachowania ABI. + * * \return Wskaźnik do kolejnej linii tekstu lub NULL, jeśli to już koniec * bufora. */ @@ -180,11 +190,15 @@ * Funkcja czyta tekst znak po znaku, więc nie jest efektywna, ale dzięki * brakowi buforowania, nie koliduje z innymi funkcjami odczytu. * + * \note W przypadku zakończenia połączenia przez drugą stronę, ostatnia + * linia nie jest zwracana. + * * \param sock Deskryptor gniazda * \param buf Wskaźnik do bufora * \param length Długość bufora * - * \return Zwraca \c buf jeśli się powiodło, lub \c NULL w przypadku błędu. + * \return Zwraca wskaźnik na koniec odebranej linii jeśli się powiodło, + * lub \c NULL w przypadku błędu. */ char *gg_read_line(int sock, char *buf, int length) { @@ -195,7 +209,7 @@ for (; length > 1; buf++, length--) { do { - if ((ret = read(sock, buf, 1)) == -1 && errno != EINTR && errno != EAGAIN) { + if ((ret = recv(sock, buf, 1, 0)) == -1 && errno != EINTR && errno != EAGAIN) { gg_debug(GG_DEBUG_MISC, "// gg_read_line() error on read (errno=%d, %s)\n", errno, strerror(errno)); *buf = 0; return NULL; @@ -229,7 +243,7 @@ */ int gg_connect(void *addr, int port, int async) { - int sock, one = 1, errno2; + int sock, errno2; struct sockaddr_in sin; struct in_addr *a = addr; struct sockaddr_in myaddr; @@ -256,11 +270,13 @@ if (async) { #ifdef FIONBIO + int one = 1; + if (ioctl(sock, FIONBIO, &one) == -1) { #else if (fcntl(sock, F_SETFL, O_NONBLOCK) == -1) { #endif - gg_debug(GG_DEBUG_MISC, "// gg_connect() ioctl() failed (errno=%d, %s)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, "// gg_connect() can't set nonblocking (errno=%d, %s)\n", errno, strerror(errno)); errno2 = errno; close(sock); errno = errno2; @@ -384,7 +400,8 @@ va_start(ap, format); for (j = 0; j < strlen(format); j++) { - char *arg, buf[16]; + const char *arg; + char buf[16]; if (format[j] == 'u') { snprintf(buf, sizeof(buf), "%d", va_arg(ap, uin_t)); @@ -486,7 +503,7 @@ { char *res, *save, *foo, val; const char *end; - unsigned int index = 0; + unsigned int idx = 0; if (!buf) return NULL; @@ -503,11 +520,11 @@ buf++; continue; } - if (!(foo = strchr(gg_base64_charset, *buf))) + if (!(foo = memchr(gg_base64_charset, *buf, sizeof(gg_base64_charset)))) foo = gg_base64_charset; val = (int)(foo - gg_base64_charset); buf++; - switch (index) { + switch (idx) { case 0: *res |= val << 2; break; @@ -523,8 +540,8 @@ *res++ |= val; break; } - index++; - index %= 4; + idx++; + idx %= 4; } *res = 0; @@ -666,6 +683,179 @@ return crc ^ 0xffffffffL; } +/** + * \internal Parsuje identyfikator użytkownika. + * + * \param str Ciąg tekstowy, zawierający identyfikator + * \param len Długość identyfikatora + * + * \return Identyfikator, lub 0, jeżeli nie udało się odczytać + */ +uin_t gg_str_to_uin(const char *str, int len) +{ + char buff[11]; + char *endptr; + uin_t uin; + + if (len < 0) + len = strlen(str); + if (len > 10) + return 0; + memcpy(buff, str, len); + buff[len] = '\0'; + + errno = 0; + uin = strtoul(buff, &endptr, 10); + if (errno == ERANGE || endptr[0] != '\0') + return 0; + + return uin; +} + +/** + * Szuka informacji o konferencji o podanym identyfikatorze. + * + * \param sess Struktura sesji + * \param id Identyfikator konferencji + * + * \return Struktura z informacjami o konferencji + */ +gg_chat_list_t *gg_chat_find(struct gg_session *sess, uint64_t id) +{ + gg_chat_list_t *chat_list = sess->private_data->chat_list; + + while (chat_list != NULL) + { + if (chat_list->id == id) + return chat_list; + chat_list = chat_list->next; + } + + return NULL; +} + +/** + * \internal Aktualizuje informacje o konferencji. + * + * \param sess Struktura sesji + * \param id Identyfikator konferencji + * \param version Wersja informacji o konferencji + * \param participants Lista uczestników konferencji + * \param participants_count Ilość uczestników konferencji + * + * \return Wartość równa 0, jeżeli zakończono powodzeniem + */ +int gg_chat_update(struct gg_session *sess, uint64_t id, uint32_t version, + const uin_t *participants, unsigned int participants_count) +{ + gg_chat_list_t *chat; + uin_t *participants_new; + + if (participants_count >= ~0 / sizeof(uin_t)) + return -1; + + chat = gg_chat_find(sess, id); + + if (!chat) { + chat = malloc(sizeof(gg_chat_list_t)); + + if (!chat) + return -1; + + memset(chat, 0, sizeof(gg_chat_list_t)); + chat->id = id; + chat->next = sess->private_data->chat_list; + sess->private_data->chat_list = chat; + } + + participants_new = realloc(chat->participants, + sizeof(uin_t) * participants_count); + + if (participants_new == NULL) + return -1; + + chat->version = version; + chat->participants = participants_new; + chat->participants_count = participants_count; + memcpy(chat->participants, participants, + sizeof(uin_t) * participants_count); + + return 0; +} + +void gg_connection_failure(struct gg_session *gs, struct gg_event *ge, + enum gg_failure_t failure) +{ + gg_close(gs); + + if (ge != NULL) { + ge->type = GG_EVENT_CONN_FAILED; + ge->event.failure = failure; + } + gs->state = GG_STATE_IDLE; +} + +time_t gg_server_time(struct gg_session *gs) +{ + time_t now = time(NULL); + + if (gs == NULL || gs->private_data == NULL) { + gg_debug_session(gs, GG_DEBUG_ERROR, "time diff data is not " + "accessible\n"); + return now; + } + + return now + gs->private_data->time_diff; +} + +void gg_strarr_free(char **strarr) +{ + char **it; + + if (strarr == NULL) + return; + + for (it = strarr; *it != NULL; it++) + free(*it); + free(strarr); +} + +char ** gg_strarr_dup(char **strarr) +{ + if (strarr == NULL) + return NULL; + + size_t i, len, size; + char **it, **out; + + len = 0; + for (it = strarr; *it != NULL; it++) + len++; + + size = (len + 1) * sizeof(char*); + out = malloc(size); + + if (out == NULL) { + gg_debug(GG_DEBUG_MISC | GG_DEBUG_ERROR, "// gg_strarr_dup() " + "not enough memory for the array\n"); + return NULL; + } + memset(out, 0, size); + + for (i = 0; i < len; i++) { + out[i] = strdup(strarr[i]); + if (out[i] == NULL) { + gg_debug(GG_DEBUG_MISC | GG_DEBUG_ERROR, + "// gg_strarr_dup() " + "not enough memory for the array element\n"); + gg_strarr_free(out); + return NULL; + } + } + + return out; +} + /* * Local variables: * c-indentation-style: k&r