Index: kopete/protocols/gadu/libgadu/libgadu.h =================================================================== --- kopete/protocols/gadu/libgadu/libgadu.h (revision 417278) +++ kopete/protocols/gadu/libgadu/libgadu.h (working copy) @@ -33,15 +33,15 @@ extern "C" { #endif +#ifdef HAVE_STDINT_H +#include +#endif + #include #include #include #include -#ifdef HAVE_STDINT_H -#include -#endif - #ifdef __GG_LIBGADU_HAVE_OPENSSL #include #endif @@ -57,10 +57,10 @@ * ogólna struktura opisująca różne sesje. przydatna w klientach. */ #define gg_common_head(x) \ - int fd; /* podglądany deskryptor */ \ - int check; /* sprawdzamy zapis czy odczyt */ \ - int state; /* aktualny stan maszynki */ \ - int error; /* kod błędu dla GG_STATE_ERROR */ \ + int fd; /* podglądany deskryptor */ \ + int check; /* sprawdzamy zapis czy odczyt */ \ + int state; /* aktualny stan maszynki */ \ + int error; /* kod błędu dla GG_STATE_ERROR */ \ int type; /* rodzaj sesji */ \ int id; /* identyfikator */ \ int timeout; /* sugerowany timeout w sekundach */ \ @@ -111,7 +111,7 @@ char *recv_buf; /* bufor na otrzymywane pakiety */ int recv_done; /* ile już wczytano do bufora */ - int recv_left; /* i ile jeszcze trzeba wczytać */ + int recv_left; /* i ile jeszcze trzeba wczytać */ int protocol_version; /* wersja używanego protokołu */ char *client_version; /* wersja używanego klienta */ @@ -150,17 +150,17 @@ struct gg_http { gg_common_head(struct gg_http) - int async; /* czy połączenie asynchroniczne */ + int async; /* czy połączenie asynchroniczne */ int pid; /* pid procesu resolvera */ int port; /* port, z którym się łączymy */ - char *query; /* bufor zapytania http */ - char *header; /* bufor nagłówka */ - int header_size; /* rozmiar wczytanego nagłówka */ - char *body; /* bufor otrzymanych informacji */ - unsigned int body_size; /* oczekiwana ilość informacji */ + char *query; /* bufor zapytania http */ + char *header; /* bufor nagłówka */ + int header_size; /* rozmiar wczytanego nagłówka */ + char *body; /* bufor otrzymanych informacji */ + unsigned int body_size; /* oczekiwana ilość informacji */ - void *data; /* dane danej operacji http */ + void *data; /* dane danej operacji http */ char *user_data; /* dane użytkownika, nie są zwalniane przez gg_http_free() */ @@ -265,27 +265,27 @@ * opisuje stan asynchronicznej maszyny. */ enum gg_state_t { - /* wspólne */ - GG_STATE_IDLE = 0, /* nie powinno wystąpić. */ - GG_STATE_RESOLVING, /* wywołał gethostbyname() */ + /* wspólne */ + GG_STATE_IDLE = 0, /* nie powinno wystąpić. */ + GG_STATE_RESOLVING, /* wywołał gethostbyname() */ GG_STATE_CONNECTING, /* wywołał connect() */ GG_STATE_READING_DATA, /* czeka na dane http */ GG_STATE_ERROR, /* wystąpił błąd. kod w x->error */ - /* gg_session */ + /* gg_session */ GG_STATE_CONNECTING_HUB, /* wywołał connect() na huba */ GG_STATE_CONNECTING_GG, /* wywołał connect() na serwer */ GG_STATE_READING_KEY, /* czeka na klucz */ GG_STATE_READING_REPLY, /* czeka na odpowiedź */ GG_STATE_CONNECTED, /* połączył się */ - /* gg_http */ + /* gg_http */ GG_STATE_SENDING_QUERY, /* wysyła zapytanie http */ GG_STATE_READING_HEADER, /* czeka na nagłówek http */ GG_STATE_PARSING, /* przetwarza dane */ GG_STATE_DONE, /* skończył */ - /* gg_dcc */ + /* gg_dcc */ GG_STATE_LISTENING, /* czeka na połączenia */ GG_STATE_READING_UIN_1, /* czeka na uin peera */ GG_STATE_READING_UIN_2, /* czeka na swój uin */ @@ -350,8 +350,9 @@ uint16_t external_port; /* port widziany na zewnatrz */ int tls; /* czy łączymy po TLS? */ int image_size; /* maksymalny rozmiar obrazka w KiB */ + int era_omnix; /* czy udawać klienta era omnix? */ - char dummy[7 * sizeof(int)]; /* miejsce na kolejnych 8 zmiennych, + char dummy[6 * sizeof(int)]; /* miejsce na kolejnych 6 zmiennych, * żeby z dodaniem parametru nie * zmieniał się rozmiar struktury */ }; @@ -500,8 +501,8 @@ */ struct gg_event { int type; /* rodzaj zdarzenia -- gg_event_t */ - union { /* @event */ - struct gg_notify_reply *notify; /* informacje o liście kontaktów -- GG_EVENT_NOTIFY */ + union { /* @event */ + struct gg_notify_reply *notify; /* informacje o liście kontaktów -- GG_EVENT_NOTIFY */ enum gg_failure_t failure; /* błąd połączenia -- GG_EVENT_FAILURE */ @@ -522,20 +523,20 @@ int formats_length; /* długość informacji o formatowaniu tekstu */ void *formats; /* informacje o formatowaniu tekstu */ - } msg; + } msg; struct { /* @notify_descr informacje o liście kontaktów z opisami stanu -- GG_EVENT_NOTIFY_DESCR */ struct gg_notify_reply *notify; /* informacje o liście kontaktów */ char *descr; /* opis stanu */ } notify_descr; - struct { /* @status zmiana stanu -- GG_EVENT_STATUS */ + struct { /* @status zmiana stanu -- GG_EVENT_STATUS */ uin_t uin; /* numer */ uint32_t status; /* nowy stan */ char *descr; /* opis stanu */ } status; - struct { /* @status60 zmiana stanu -- GG_EVENT_STATUS60 */ + struct { /* @status60 zmiana stanu -- GG_EVENT_STATUS60 */ uin_t uin; /* numer */ int status; /* nowy stan */ uint32_t remote_ip; /* adres ip */ @@ -748,6 +749,7 @@ /* przypomnienie hasła e-mailem */ struct gg_http *gg_remind_passwd(uin_t uin, int async); struct gg_http *gg_remind_passwd2(uin_t uin, const char *tokenid, const char *tokenval, int async); +struct gg_http *gg_remind_passwd3(uin_t uin, const char *email, const char *tokenid, const char *tokenval, int async); #define gg_remind_passwd_watch_fd gg_pubdir_watch_fd #define gg_remind_passwd_free gg_pubdir_free #define gg_free_remind_passwd gg_pubdir_free @@ -813,6 +815,7 @@ struct gg_dcc *gg_dcc_voice_chat(uint32_t ip, uint16_t port, uin_t my_uin, uin_t peer_uin); void gg_dcc_set_type(struct gg_dcc *d, int type); int gg_dcc_fill_file_info(struct gg_dcc *d, const char *filename); +int gg_dcc_fill_file_info2(struct gg_dcc *d, const char *filename, const char *local_filename); int gg_dcc_voice_send(struct gg_dcc *d, char *buf, int length); #define GG_DCC_VOICE_FRAME_LENGTH 195 @@ -940,11 +943,12 @@ #define GG_HTTPS_PORT 443 #define GG_HTTP_USERAGENT "Mozilla/4.7 [en] (Win98; I)" -#define GG_DEFAULT_CLIENT_VERSION "6, 0, 0, 132" -#define GG_DEFAULT_PROTOCOL_VERSION 0x20 +#define GG_DEFAULT_CLIENT_VERSION "6, 1, 0, 158" +#define GG_DEFAULT_PROTOCOL_VERSION 0x24 #define GG_DEFAULT_TIMEOUT 30 #define GG_HAS_AUDIO_MASK 0x40000000 -#define GG_LIBGADU_VERSION "20041222" +#define GG_ERA_OMNIX_MASK 0x04000000 +#define GG_LIBGADU_VERSION "CVS" #define GG_DEFAULT_DCC_PORT 1550 Index: kopete/protocols/gadu/libgadu/http.c =================================================================== --- kopete/protocols/gadu/libgadu/http.c (revision 417278) +++ kopete/protocols/gadu/libgadu/http.c (working copy) @@ -12,10 +12,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, + * USA. */ #include @@ -61,19 +61,19 @@ struct gg_http *h; if (!hostname || !port || !method || !path || !header) { - gg_debug(GG_DEBUG_MISC, "// gg_http_connect() invalid arguments\n"); - errno = EINVAL; + gg_debug(GG_DEBUG_MISC, "// gg_http_connect() invalid arguments\n"); + errno = EFAULT; return NULL; } - + if (!(h = malloc(sizeof(*h)))) - return NULL; + return NULL; memset(h, 0, sizeof(*h)); h->async = async; h->port = port; h->fd = -1; - h->type = GG_SESSION_HTTP; + h->type = GG_SESSION_HTTP; if (gg_proxy_enabled) { char *auth = gg_proxy_auth(); @@ -92,12 +92,12 @@ } if (!h->query) { - gg_debug(GG_DEBUG_MISC, "// gg_http_connect() not enough memory for query\n"); + gg_debug(GG_DEBUG_MISC, "// gg_http_connect() not enough memory for query\n"); free(h); - errno = ENOMEM; + errno = ENOMEM; return NULL; } - + gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", h->query); if (async) { @@ -106,9 +106,9 @@ #else if (gg_resolve_pthread(&h->fd, &h->resolver, hostname)) { #endif - gg_debug(GG_DEBUG_MISC, "// gg_http_connect() resolver failed\n"); + gg_debug(GG_DEBUG_MISC, "// gg_http_connect() resolver failed\n"); gg_http_free(h); - errno = ENOENT; + errno = ENOENT; return NULL; } @@ -131,7 +131,7 @@ } if (!(h->fd = gg_connect(&a, port, 0)) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_http_connect() connection failed (errno=%d, %s)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, "// gg_http_connect() connection failed (errno=%d, %s)\n", errno, strerror(errno)); gg_http_free(h); return NULL; } @@ -144,7 +144,7 @@ } if (h->state != GG_STATE_PARSING) { - gg_debug(GG_DEBUG_MISC, "// gg_http_connect() some strange error\n"); + gg_debug(GG_DEBUG_MISC, "// gg_http_connect() some strange error\n"); gg_http_free(h); return NULL; } @@ -152,7 +152,7 @@ h->callback = gg_http_watch_fd; h->destroy = gg_http_free; - + return h; } @@ -181,7 +181,7 @@ if (!h) { gg_debug(GG_DEBUG_MISC, "// gg_http_watch_fd() invalid arguments\n"); - errno = EINVAL; + errno = EFAULT; return -1; } @@ -243,7 +243,7 @@ } if (h->state == GG_STATE_SENDING_QUERY) { - unsigned int res; + int res; if ((res = write(h->fd, h->query, strlen(h->query))) < 1) { gg_debug(GG_DEBUG_MISC, "=> http, write() failed (len=%d, res=%d, errno=%d)\n", strlen(h->query), res, errno); @@ -272,7 +272,7 @@ if (h->state == GG_STATE_READING_HEADER) { char buf[1024], *tmp; - unsigned int res; + int res; if ((res = read(h->fd, buf, sizeof(buf))) == -1) { gg_debug(GG_DEBUG_MISC, "=> http, reading header failed (errno=%d)\n", errno); @@ -321,7 +321,7 @@ /* HTTP/1.1 200 OK */ if (strlen(h->header) < 16 || strncmp(h->header + 9, "200", 3)) { - gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-HEADER-----\n%s\n=> -----END-HTTP-HEADER-----\n", h->header); + gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-HEADER-----\n%s\n=> -----END-HTTP-HEADER-----\n", h->header); gg_debug(GG_DEBUG_MISC, "=> http, didn't get 200 OK -- no results\n"); free(h->header); @@ -332,7 +332,7 @@ h->body_size = 0; line = h->header; *tmp = 0; - + gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-HEADER-----\n%s\n=> -----END-HTTP-HEADER-----\n", h->header); while (line) { @@ -380,7 +380,7 @@ if (h->state == GG_STATE_READING_DATA) { char buf[1024]; - unsigned int res; + int res; if ((res = read(h->fd, buf, sizeof(buf))) == -1) { gg_debug(GG_DEBUG_MISC, "=> http, reading body failed (errno=%d)\n", errno); @@ -435,7 +435,7 @@ return 0; } - + if (h->fd != -1) close(h->fd); @@ -452,7 +452,7 @@ * gg_http_stop() * * jeśli połączenie jest w trakcie, przerywa je. nie zwalnia h->data. - * + * * - h - struktura opisująca połączenie */ void gg_http_stop(struct gg_http *h) @@ -465,7 +465,7 @@ if (h->fd != -1) close(h->fd); - h->fd = -1; + h->fd = -1; } /* @@ -487,7 +487,7 @@ free(h->query); h->query = NULL; } - + if (h->header) { free(h->header); h->header = NULL; Index: kopete/protocols/gadu/libgadu/events.c =================================================================== --- kopete/protocols/gadu/libgadu/events.c (revision 417278) +++ kopete/protocols/gadu/libgadu/events.c (working copy) @@ -14,10 +14,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, + * USA. */ #include @@ -56,28 +56,28 @@ void gg_event_free(struct gg_event *e) { gg_debug(GG_DEBUG_FUNCTION, "** gg_event_free(%p);\n", e); - + if (!e) return; - + switch (e->type) { case GG_EVENT_MSG: free(e->event.msg.message); free(e->event.msg.formats); free(e->event.msg.recipients); break; - + case GG_EVENT_NOTIFY: free(e->event.notify); break; - + case GG_EVENT_NOTIFY60: { int i; for (i = 0; e->event.notify60[i].uin; i++) free(e->event.notify60[i].descr); - + free(e->event.notify60); break; @@ -86,7 +86,7 @@ case GG_EVENT_STATUS60: free(e->event.status60.descr); break; - + case GG_EVENT_STATUS: free(e->event.status.descr); break; @@ -109,7 +109,7 @@ case GG_EVENT_USERLIST: free(e->event.userlist.reply); break; - + case GG_EVENT_IMAGE_REPLY: free(e->event.image_reply.filename); free(e->event.image_reply.image); @@ -133,7 +133,7 @@ int gg_image_queue_remove(struct gg_session *s, struct gg_image_queue *q, int freeq) { if (!s || !q) { - errno = EINVAL; + errno = EFAULT; return -1; } @@ -165,18 +165,20 @@ * parsuje przychodzący pakiet z obrazkiem. * * - e - opis zdarzenia - * - + * - */ -static void gg_image_queue_parse(struct gg_event *e, char *p, int len, struct gg_session *sess, uin_t sender) +static void gg_image_queue_parse(struct gg_event *e, char *p, unsigned int len, struct gg_session *sess, uin_t sender) { struct gg_msg_image_reply *i = (void*) p; struct gg_image_queue *q, *qq; - if (!p || !sess || !e) + if (!p || !sess || !e) { + errno = EFAULT; return; + } /* znajdź dany obrazek w kolejce danej sesji */ - + for (qq = sess->images, q = NULL; qq; qq = qq->next) { if (sender == qq->sender && i->size == qq->size && i->crc32 == qq->crc32) { q = qq; @@ -191,7 +193,7 @@ if (p[0] == 0x05) { int i, ok = 0; - + q->done = 0; len -= sizeof(struct gg_msg_image_reply); @@ -225,7 +227,7 @@ if (q->done + len > q->size) len = q->size - q->done; - + memcpy(q->image + q->done, p, len); q->done += len; @@ -268,7 +270,7 @@ e->type = GG_EVENT_NONE; return 0; } - + for (p = (char*) r + sizeof(*r); *p; p++) { if (*p == 0x02 && p == packet_end - 1) { gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() received ctcp packet\n"); @@ -279,7 +281,7 @@ goto malformed; } } - + p++; /* przeanalizuj dodatkowe opcje */ @@ -289,9 +291,9 @@ { struct gg_msg_recipients *m = (void*) p; uint32_t i, count; - + p += sizeof(*m); - + if (p > packet_end) { gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (1)\n"); goto malformed; @@ -299,40 +301,42 @@ count = gg_fix32(m->count); - if (p + count * sizeof(uin_t) > packet_end) { + if (p + count * sizeof(uin_t) > packet_end || p + count * sizeof(uin_t) < p || count > 0xffff) { gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (1.5)\n"); goto malformed; } - + if (!(e->event.msg.recipients = (void*) malloc(count * sizeof(uin_t)))) { gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() not enough memory for recipients data\n"); - errno = ENOMEM; goto fail; } - - for (i = 0; i < count; i++, p += sizeof(uin_t)) - e->event.msg.recipients[i] = gg_fix32(*((uint32_t*) p)); - + + for (i = 0; i < count; i++, p += sizeof(uint32_t)) { + uint32_t u; + memcpy(&u, p, sizeof(uint32_t)); + e->event.msg.recipients[i] = gg_fix32(u); + } + e->event.msg.recipients_count = count; - + break; } case 0x02: /* richtext */ { - unsigned short len; + uint16_t len; char *buf; - + if (p + 3 > packet_end) { gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (2)\n"); goto malformed; } - len = gg_fix16(*((unsigned short*) (p + 1))); + memcpy(&len, p + 1, sizeof(uint16_t)); + len = gg_fix16(len); if (!(buf = malloc(len))) { gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() not enough memory for richtext data\n"); - errno = ENOMEM; goto fail; } @@ -343,7 +347,7 @@ free(buf); goto malformed; } - + memcpy(buf, p, len); e->event.msg.formats = buf; @@ -375,12 +379,29 @@ case 0x05: /* image_reply */ case 0x06: { - if (p + sizeof(struct gg_msg_image_reply) + 1 > packet_end) { + struct gg_msg_image_reply *rep = (void*) p; + + if (p + sizeof(struct gg_msg_image_reply) == packet_end) { + + /* pusta odpowiedź - klient po drugiej stronie nie ma żądanego obrazka */ + + e->type = GG_EVENT_IMAGE_REPLY; + e->event.image_reply.sender = gg_fix32(r->sender); + e->event.image_reply.size = 0; + e->event.image_reply.crc32 = gg_fix32(rep->crc32); + e->event.image_reply.filename = NULL; + e->event.image_reply.image = NULL; + return 0; + + } else if (p + sizeof(struct gg_msg_image_reply) + 1 > packet_end) { + gg_debug(GG_DEBUG_MISC, "// gg_handle_recv_msg() packet out of bounds (4)\n"); goto malformed; } - gg_image_queue_parse(e, p, (int)(packet_end - p), sess, gg_fix32(r->sender)); + rep->size = gg_fix32(rep->size); + rep->crc32 = gg_fix32(rep->crc32); + gg_image_queue_parse(e, p, (unsigned int)(packet_end - p), sess, gg_fix32(r->sender)); return 0; } @@ -443,21 +464,21 @@ } p = (char*) h + sizeof(struct gg_header); - + switch (h->type) { case GG_RECV_MSG: { if (h->length >= sizeof(struct gg_recv_msg)) if (gg_handle_recv_msg(h, e, sess)) goto fail; - + break; } case GG_NOTIFY_REPLY: { struct gg_notify_reply *n = (void*) p; - int count, i; + unsigned int count, i; char *tmp; gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a notify reply\n"); @@ -468,46 +489,45 @@ goto fail; } - if (gg_fix32(n->status) == GG_STATUS_BUSY_DESCR || gg_fix32(n->status == GG_STATUS_NOT_AVAIL_DESCR) || gg_fix32(n->status) == GG_STATUS_AVAIL_DESCR) { + if (gg_fix32(n->status) == GG_STATUS_BUSY_DESCR || gg_fix32(n->status) == GG_STATUS_NOT_AVAIL_DESCR || gg_fix32(n->status) == GG_STATUS_AVAIL_DESCR) { e->type = GG_EVENT_NOTIFY_DESCR; - + if (!(e->event.notify_descr.notify = (void*) malloc(sizeof(*n) * 2))) { gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); - errno = ENOMEM; goto fail; } e->event.notify_descr.notify[1].uin = 0; memcpy(e->event.notify_descr.notify, p, sizeof(*n)); e->event.notify_descr.notify[0].uin = gg_fix32(e->event.notify_descr.notify[0].uin); e->event.notify_descr.notify[0].status = gg_fix32(e->event.notify_descr.notify[0].status); + e->event.notify_descr.notify[0].remote_ip = e->event.notify_descr.notify[0].remote_ip; e->event.notify_descr.notify[0].remote_port = gg_fix16(e->event.notify_descr.notify[0].remote_port); count = h->length - sizeof(*n); if (!(tmp = malloc(count + 1))) { gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); - errno = ENOMEM; goto fail; } memcpy(tmp, p + sizeof(*n), count); tmp[count] = 0; e->event.notify_descr.descr = tmp; - + } else { e->type = GG_EVENT_NOTIFY; - + if (!(e->event.notify = (void*) malloc(h->length + 2 * sizeof(*n)))) { gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for notify data\n"); - errno = ENOMEM; goto fail; } - + memcpy(e->event.notify, p, h->length); count = h->length / sizeof(*n); e->event.notify[count].uin = 0; - + for (i = 0; i < count; i++) { e->event.notify[i].uin = gg_fix32(e->event.notify[i].uin); e->event.notify[i].status = gg_fix32(e->event.notify[i].status); + e->event.notify[i].remote_ip = e->event.notify[i].remote_ip; e->event.notify[i].remote_port = gg_fix16(e->event.notify[i].remote_port); } } @@ -557,7 +577,7 @@ } e->event.notify60[0].uin = 0; - + while (length >= sizeof(struct gg_notify_reply60)) { uin_t uin = gg_fix32(n->uin); char *tmp; @@ -571,6 +591,11 @@ e->event.notify60[i].descr = NULL; e->event.notify60[i].time = 0; + if (uin & 0x40000000) + e->event.notify60[i].version |= GG_HAS_AUDIO_MASK; + if (uin & 0x08000000) + e->event.notify60[i].version |= GG_ERA_OMNIX_MASK; + if (GG_S_D(n->status)) { unsigned char descr_len = *((char*) n + sizeof(struct gg_notify_reply60)); @@ -585,7 +610,7 @@ /* XXX czas */ } - + length -= sizeof(struct gg_notify_reply60) + descr_len + 1; n = (void*) ((char*) n + sizeof(struct gg_notify_reply60) + descr_len + 1); } else { @@ -605,7 +630,7 @@ break; } - + case GG_STATUS60: { struct gg_status60 *s = (void*) p; @@ -630,6 +655,8 @@ if (uin & 0x40000000) e->event.status60.version |= GG_HAS_AUDIO_MASK; + if (uin & 0x08000000) + e->event.status60.version |= GG_ERA_OMNIX_MASK; if (h->length > sizeof(*s)) { int len = h->length - sizeof(*s); @@ -642,8 +669,11 @@ e->event.status60.descr = buf; - if (len > 4 && p[h->length - 5] == 0) - e->event.status60.time = *((int*) (p + h->length - 4)); + if (len > 4 && p[h->length - 5] == 0) { + uint32_t t; + memcpy(&t, p + h->length - 4, sizeof(uint32_t)); + e->event.status60.time = gg_fix32(t); + } } break; @@ -666,7 +696,7 @@ break; } - case GG_PONG: + case GG_PONG: { gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received a pong\n"); @@ -709,10 +739,10 @@ if (h->length > 1) { char *tmp; - int len = (sess->userlist_reply) ? strlen(sess->userlist_reply) : 0; - + unsigned int len = (sess->userlist_reply) ? strlen(sess->userlist_reply) : 0; + gg_debug(GG_DEBUG_MISC, "userlist_reply=%p, len=%d\n", sess->userlist_reply, len); - + if (!(tmp = realloc(sess->userlist_reply, len + h->length))) { gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() not enough memory for userlist reply\n"); free(sess->userlist_reply); @@ -739,7 +769,7 @@ default: gg_debug(GG_DEBUG_MISC, "// gg_watch_fd_connected() received unknown packet 0x%.2x\n", h->type); } - + free(h); return 0; @@ -767,9 +797,10 @@ struct gg_event *e; int res = 0; int port = 0; + int errno2 = 0; gg_debug(GG_DEBUG_FUNCTION, "** gg_watch_fd(%p);\n", sess); - + if (!sess) { errno = EFAULT; return NULL; @@ -793,8 +824,9 @@ if (read(sess->fd, &addr, sizeof(addr)) < (signed)sizeof(addr) || addr.s_addr == INADDR_NONE) { gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() resolving failed\n"); failed = 1; + errno2 = errno; } - + close(sess->fd); sess->fd = -1; @@ -809,8 +841,10 @@ } #endif - if (failed) + if (failed) { + errno = errno2; goto fail_resolving; + } /* jeśli jesteśmy w resolverze i mamy ustawiony port * proxy, znaczy, że resolvowaliśmy proxy. zatem @@ -829,7 +863,7 @@ } gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() resolved, connecting to %s:%d\n", inet_ntoa(addr), port); - + /* łączymy się albo z hubem, albo z proxy, zależnie * od tego, co resolvowaliśmy. */ if ((sess->fd = gg_connect(&addr, port, sess->async)) == -1) { @@ -866,7 +900,7 @@ gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", res, strerror(res)); goto fail_connecting; } - + gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to hub failed (errno=%d, %s), trying direct connection\n", res, strerror(res)); close(sess->fd); @@ -884,7 +918,7 @@ sess->timeout = GG_DEFAULT_TIMEOUT; break; } - + gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connected to hub, sending query\n"); if (!(client = gg_urlencode((sess->client_version) ? sess->client_version : GG_DEFAULT_CLIENT_VERSION))) { @@ -911,12 +945,12 @@ "Host: " GG_APPMSG_HOST "\r\n" "User-Agent: " GG_HTTP_USERAGENT "\r\n" "Pragma: no-cache\r\n" - "%s" + "%s" "\r\n", host, appmsg, sess->uin, client, sess->last_sysmsg, (auth) ? auth : ""); if (auth) free(auth); - + free(client); /* zwolnij pamięć po wersji klienta. */ @@ -925,8 +959,8 @@ sess->client_version = NULL; } - gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", buf); - + gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", buf); + /* zapytanie jest krótkie, więc zawsze zmieści się * do bufora gniazda. jeśli write() zwróci mniej, * stało się coś złego. */ @@ -960,7 +994,7 @@ gg_read_line(sess->fd, buf, sizeof(buf) - 1); gg_chomp(buf); gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() received http header (%s)\n", buf); - + /* sprawdzamy, czy wszystko w porządku. */ if (strncmp(buf, "HTTP/1.", 7) || strncmp(buf + 9, "200", 3)) { gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() that's not what we've expected, trying direct connection\n"); @@ -981,7 +1015,7 @@ sess->timeout = GG_DEFAULT_TIMEOUT; break; } - + sess->port = GG_DEFAULT_PORT; /* łączymy się na port 8074 huba. */ @@ -989,20 +1023,20 @@ gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s), trying https\n", errno, strerror(errno)); sess->port = GG_HTTPS_PORT; - + /* łączymy się na port 443. */ if ((sess->fd = gg_connect(&sess->hub_addr, sess->port, sess->async)) == -1) { gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection failed (errno=%d, %s)\n", errno, strerror(errno)); goto fail_connecting; } } - + sess->state = GG_STATE_CONNECTING_GG; sess->check = GG_CHECK_WRITE; sess->timeout = GG_DEFAULT_TIMEOUT; break; } - + /* ignorujemy resztę nagłówka. */ while (strcmp(buf, "\r\n") && strcmp(buf, "")) gg_read_line(sess->fd, buf, sizeof(buf) - 1); @@ -1010,13 +1044,13 @@ /* czytamy pierwszą linię danych. */ gg_read_line(sess->fd, buf, sizeof(buf) - 1); gg_chomp(buf); - + /* jeśli pierwsza liczba w linii nie jest równa zeru, * oznacza to, że mamy wiadomość systemową. */ if (atoi(buf)) { char tmp[1024], *foo, *sysmsg_buf = NULL; int len = 0; - + while (gg_read_line(sess->fd, tmp, sizeof(tmp) - 1)) { if (!(foo = realloc(sysmsg_buf, len + strlen(tmp) + 2))) { gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() out of memory for system message, ignoring\n"); @@ -1029,23 +1063,23 @@ strcpy(sysmsg_buf, tmp); else strcat(sysmsg_buf, tmp); - + len += strlen(tmp); } - + e->type = GG_EVENT_MSG; e->event.msg.msgclass = atoi(buf); e->event.msg.sender = 0; e->event.msg.message = sysmsg_buf; } - + close(sess->fd); - + gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() received http data (%s)\n", buf); /* analizujemy otrzymane dane. */ tmp = buf; - + while (*tmp && *tmp != ' ') tmp++; while (*tmp && *tmp == ' ') @@ -1057,7 +1091,7 @@ if ((tmp = strchr(host, ':'))) { *tmp = 0; - port = atoi(tmp+1); + port = atoi(tmp + 1); } addr.s_addr = inet_addr(host); @@ -1070,7 +1104,7 @@ gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connection to proxy failed (errno=%d, %s)\n", errno, strerror(errno)); goto fail_connecting; } - + sess->state = GG_STATE_CONNECTING_GG; sess->check = GG_CHECK_WRITE; sess->timeout = GG_DEFAULT_TIMEOUT; @@ -1097,7 +1131,7 @@ sess->state = GG_STATE_CONNECTING_GG; sess->check = GG_CHECK_WRITE; sess->timeout = GG_DEFAULT_TIMEOUT; - + break; } @@ -1149,18 +1183,24 @@ } gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() connected\n"); - + if (gg_proxy_http_only) sess->proxy_port = 0; /* jeśli mamy proxy, wyślijmy zapytanie. */ if (sess->proxy_addr && sess->proxy_port) { char buf[100], *auth = gg_proxy_auth(); + struct in_addr addr; - snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.0\r\n", inet_ntoa(*((struct in_addr*) &sess->server_addr)), sess->port); + if (sess->server_addr) + addr.s_addr = sess->server_addr; + else + addr.s_addr = sess->hub_addr; + snprintf(buf, sizeof(buf), "CONNECT %s:%d HTTP/1.0\r\n", inet_ntoa(addr), sess->port); + gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() proxy request:\n// %s", buf); - + /* wysyłamy zapytanie. jest ono na tyle krótkie, * że musi się zmieścić w buforze gniazda. jeśli * write() zawiedzie, stało się coś złego. */ @@ -1225,7 +1265,7 @@ sess->fd = -1; break; } - + if (err == SSL_ERROR_WANT_READ) { gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() wants to read\n"); @@ -1248,7 +1288,7 @@ ERR_error_string_n(ERR_get_error(), buf, sizeof(buf)); gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() SSL_connect() bailed out: %s\n", buf); - + e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_TLS; sess->state = GG_STATE_IDLE; @@ -1284,13 +1324,13 @@ case GG_STATE_READING_KEY: { - struct gg_header *h; + struct gg_header *h; struct gg_welcome *w; struct gg_login60 l; unsigned int hash; unsigned char *password = sess->password; int ret; - + gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_READING_KEY\n"); memset(&l, 0, sizeof(l)); @@ -1305,7 +1345,7 @@ gg_read_line(sess->fd, buf, sizeof(buf) - 1); gg_chomp(buf); gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() proxy response:\n// %s\n", buf); - + while (strcmp(buf, "")) { gg_read_line(sess->fd, buf, sizeof(buf) - 1); gg_chomp(buf); @@ -1316,7 +1356,7 @@ /* XXX niech czeka jeszcze raz w tej samej * fazie. głupio, ale działa. */ sess->proxy_port = 0; - + break; } @@ -1327,7 +1367,9 @@ e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_READING; sess->state = GG_STATE_IDLE; + errno2 = errno; close(sess->fd); + errno = errno2; sess->fd = -1; break; } @@ -1343,21 +1385,25 @@ sess->state = GG_STATE_IDLE; break; } - + w = (struct gg_welcome*) ((char*) h + sizeof(struct gg_header)); w->key = gg_fix32(w->key); hash = gg_login_hash(password, w->key); - + gg_debug(GG_DEBUG_DUMP, "// gg_watch_fd() challenge %.4x --> hash %.8x\n", w->key, hash); - + free(h); free(sess->password); sess->password = NULL; - gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() gg_dcc_ip = %s\n", inet_ntoa(*((struct in_addr*) &gg_dcc_ip))); - + { + struct in_addr dcc_ip; + dcc_ip.s_addr = gg_dcc_ip; + gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() gg_dcc_ip = %s\n", inet_ntoa(dcc_ip)); + } + if (gg_dcc_ip == (unsigned long) inet_addr("255.255.255.255")) { struct sockaddr_in sin; int sin_len = sizeof(sin); @@ -1371,19 +1417,19 @@ gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() unable to detect address\n"); l.local_ip = 0; } - } else + } else l.local_ip = gg_dcc_ip; - + l.uin = gg_fix32(sess->uin); l.hash = gg_fix32(hash); l.status = gg_fix32(sess->initial_status ? sess->initial_status : GG_STATUS_AVAIL); l.version = gg_fix32(sess->protocol_version); l.local_port = gg_fix16(gg_dcc_port); l.image_size = sess->image_size; - + if (sess->external_addr && sess->external_port > 1023) { l.external_ip = sess->external_addr; - l.external_port = sess->external_port; + l.external_port = gg_fix16(sess->external_port); } gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() sending GG_LOGIN60 packet\n"); @@ -1394,15 +1440,16 @@ if (ret == -1) { gg_debug(GG_DEBUG_TRAFFIC, "// gg_watch_fd() sending packet failed. (errno=%d, %s)\n", errno, strerror(errno)); - + errno2 = errno; close(sess->fd); + errno = errno2; sess->fd = -1; e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_WRITING; sess->state = GG_STATE_IDLE; break; } - + sess->state = GG_STATE_READING_REPLY; break; @@ -1419,11 +1466,13 @@ e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_READING; sess->state = GG_STATE_IDLE; + errno2 = errno; close(sess->fd); + errno = errno2; sess->fd = -1; break; } - + if (h->type == GG_LOGIN_OK) { gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() login succeded\n"); e->type = GG_EVENT_CONN_SUCCESS; @@ -1450,7 +1499,9 @@ e->type = GG_EVENT_CONN_FAILED; sess->state = GG_STATE_IDLE; + errno2 = errno; close(sess->fd); + errno = errno2; sess->fd = -1; free(h); @@ -1462,7 +1513,7 @@ gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() GG_STATE_CONNECTED\n"); sess->last_event = time(NULL); - + if ((res = gg_watch_fd_connected(sess, e)) == -1) { gg_debug(GG_DEBUG_MISC, "// gg_watch_fd() watch_fd_connected failed (errno=%d, %s)\n", errno, strerror(errno)); @@ -1484,10 +1535,12 @@ } return e; - + fail_connecting: if (sess->fd != -1) { + errno2 = errno; close(sess->fd); + errno = errno2; sess->fd = -1; } e->type = GG_EVENT_CONN_FAILED; Index: kopete/protocols/gadu/libgadu/pubdir.c =================================================================== --- kopete/protocols/gadu/libgadu/pubdir.c (revision 417278) +++ kopete/protocols/gadu/libgadu/pubdir.c (working copy) @@ -13,10 +13,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, + * USA. */ #include @@ -46,12 +46,12 @@ */ struct gg_http *gg_register3(const char *email, const char *password, const char *tokenid, const char *tokenval, int async) { - struct gg_http *h; + struct gg_http *h; char *__pwd, *__email, *__tokenid, *__tokenval, *form, *query; - if (!email | !password | !tokenid | !tokenval) { + if (!email || !password || !tokenid || !tokenval) { gg_debug(GG_DEBUG_MISC, "=> register, NULL parameter\n"); - errno = EINVAL; + errno = EFAULT; return NULL; } @@ -66,7 +66,6 @@ free(__email); free(__tokenid); free(__tokenval); - errno = ENOMEM; return NULL; } @@ -81,7 +80,6 @@ if (!form) { gg_debug(GG_DEBUG_MISC, "=> register, not enough memory for form query\n"); - errno = ENOMEM; return NULL; } @@ -99,10 +97,15 @@ free(form); + if (!query) { + gg_debug(GG_DEBUG_MISC, "=> register, not enough memory for query\n"); + return NULL; + } + if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/fmregister3.asp", query))) { gg_debug(GG_DEBUG_MISC, "=> register, gg_http_connect() failed mysteriously\n"); free(query); - return NULL; + return NULL; } h->type = GG_SESSION_REGISTER; @@ -111,10 +114,10 @@ h->callback = gg_pubdir_watch_fd; h->destroy = gg_pubdir_free; - + if (!async) gg_pubdir_watch_fd(h); - + return h; } @@ -139,10 +142,10 @@ if (!password || !tokenid || !tokenval) { gg_debug(GG_DEBUG_MISC, "=> unregister, NULL parameter\n"); - errno = EINVAL; + errno = EFAULT; return NULL; } - + __pwd = gg_saprintf("%ld", random()); __fmpwd = gg_urlencode(password); __tokenid = gg_urlencode(tokenid); @@ -154,7 +157,6 @@ free(__fmpwd); free(__tokenid); free(__tokenval); - errno = ENOMEM; return NULL; } @@ -167,7 +169,6 @@ if (!form) { gg_debug(GG_DEBUG_MISC, "=> unregister, not enough memory for form query\n"); - errno = ENOMEM; return NULL; } @@ -185,6 +186,11 @@ free(form); + if (!query) { + gg_debug(GG_DEBUG_MISC, "=> unregister, not enough memory for query\n"); + return NULL; + } + if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/fmregister3.asp", query))) { gg_debug(GG_DEBUG_MISC, "=> unregister, gg_http_connect() failed mysteriously\n"); free(query); @@ -197,10 +203,10 @@ h->callback = gg_pubdir_watch_fd; h->destroy = gg_pubdir_free; - + if (!async) gg_pubdir_watch_fd(h); - + return h; } @@ -228,10 +234,10 @@ if (!uin || !email || !passwd || !newpasswd || !tokenid || !tokenval) { gg_debug(GG_DEBUG_MISC, "=> change, NULL parameter\n"); - errno = EINVAL; + errno = EFAULT; return NULL; } - + __fmpwd = gg_urlencode(passwd); __pwd = gg_urlencode(newpasswd); __email = gg_urlencode(email); @@ -245,10 +251,9 @@ free(__email); free(__tokenid); free(__tokenval); - errno = ENOMEM; return NULL; } - + if (!(form = gg_saprintf("fmnumber=%d&fmpwd=%s&pwd=%s&email=%s&tokenid=%s&tokenval=%s&code=%u", uin, __fmpwd, __pwd, __email, __tokenid, __tokenval, gg_http_hash("ss", email, newpasswd)))) { gg_debug(GG_DEBUG_MISC, "=> change, not enough memory for form fields\n"); free(__fmpwd); @@ -257,33 +262,37 @@ free(__tokenid); free(__tokenval); - errno = ENOMEM; return NULL; } - + free(__fmpwd); free(__pwd); free(__email); free(__tokenid); free(__tokenval); - + gg_debug(GG_DEBUG_MISC, "=> change, %s\n", form); - query = gg_saprintf( + query = gg_saprintf( "Host: " GG_REGISTER_HOST "\r\n" - "Content-Type: application/x-www-form-urlencoded\r\n" - "User-Agent: " GG_HTTP_USERAGENT "\r\n" - "Content-Length: %d\r\n" - "Pragma: no-cache\r\n" - "\r\n" - "%s", - (int) strlen(form), form); + "Content-Type: application/x-www-form-urlencoded\r\n" + "User-Agent: " GG_HTTP_USERAGENT "\r\n" + "Content-Length: %d\r\n" + "Pragma: no-cache\r\n" + "\r\n" + "%s", + (int) strlen(form), form); free(form); + if (!query) { + gg_debug(GG_DEBUG_MISC, "=> change, not enough memory for query\n"); + return NULL; + } + if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/fmregister3.asp", query))) { gg_debug(GG_DEBUG_MISC, "=> change, gg_http_connect() failed mysteriously\n"); - free(query); + free(query); return NULL; } @@ -301,11 +310,12 @@ } /* - * gg_remind_passwd() + * gg_remind_passwd3() * * wysyła żądanie przypomnienia hasła e-mailem. * * - uin - numer + * - email - adres e-mail taki, jak ten zapisany na serwerze * - async - połączenie asynchroniczne * - tokenid - identyfikator tokenu * - tokenval - wartość tokenu @@ -313,56 +323,63 @@ * zaalokowana struct gg_http, którą poźniej należy zwolnić * funkcją gg_remind_passwd_free(), albo NULL jeśli wystąpił błąd. */ -struct gg_http *gg_remind_passwd2(uin_t uin, const char *tokenid, const char *tokenval, int async) +struct gg_http *gg_remind_passwd3(uin_t uin, const char *email, const char *tokenid, const char *tokenval, int async) { struct gg_http *h; - char *form, *query, *__tokenid, *__tokenval; + char *form, *query, *__tokenid, *__tokenval, *__email; - if (!tokenid || !tokenval) { + if (!tokenid || !tokenval || !email) { gg_debug(GG_DEBUG_MISC, "=> remind, NULL parameter\n"); - errno = EINVAL; + errno = EFAULT; return NULL; } - + __tokenid = gg_urlencode(tokenid); __tokenval = gg_urlencode(tokenval); + __email = gg_urlencode(email); - if (!__tokenid || !__tokenval) { + if (!__tokenid || !__tokenval || !__email) { gg_debug(GG_DEBUG_MISC, "=> remind, not enough memory for form fields\n"); free(__tokenid); free(__tokenval); - errno = ENOMEM; + free(__email); return NULL; } - if (!(form = gg_saprintf("userid=%d&code=%u&tokenid=%s&tokenval=%s", uin, gg_http_hash("u", uin), __tokenid, __tokenval))) { + if (!(form = gg_saprintf("userid=%d&code=%u&tokenid=%s&tokenval=%s&email=%s", uin, gg_http_hash("u", uin), __tokenid, __tokenval, __email))) { gg_debug(GG_DEBUG_MISC, "=> remind, not enough memory for form fields\n"); - errno = ENOMEM; free(__tokenid); free(__tokenval); + free(__email); return NULL; } free(__tokenid); free(__tokenval); - + free(__email); + gg_debug(GG_DEBUG_MISC, "=> remind, %s\n", form); - query = gg_saprintf( + query = gg_saprintf( "Host: " GG_REMIND_HOST "\r\n" - "Content-Type: application/x-www-form-urlencoded\r\n" - "User-Agent: " GG_HTTP_USERAGENT "\r\n" - "Content-Length: %d\r\n" - "Pragma: no-cache\r\n" - "\r\n" - "%s", - (int) strlen(form), form); + "Content-Type: application/x-www-form-urlencoded\r\n" + "User-Agent: " GG_HTTP_USERAGENT "\r\n" + "Content-Length: %d\r\n" + "Pragma: no-cache\r\n" + "\r\n" + "%s", + (int) strlen(form), form); free(form); + if (!query) { + gg_debug(GG_DEBUG_MISC, "=> remind, not enough memory for query\n"); + return NULL; + } + if (!(h = gg_http_connect(GG_REMIND_HOST, GG_REMIND_PORT, async, "POST", "/appsvc/fmsendpwd3.asp", query))) { gg_debug(GG_DEBUG_MISC, "=> remind, gg_http_connect() failed mysteriously\n"); - free(query); + free(query); return NULL; } @@ -397,36 +414,37 @@ char *tmp; if (!h) { + errno = EFAULT; + return -1; + } + + if (h->state == GG_STATE_ERROR) { + gg_debug(GG_DEBUG_MISC, "=> pubdir, watch_fd issued on failed session\n"); errno = EINVAL; return -1; } - - if (h->state == GG_STATE_ERROR) { - gg_debug(GG_DEBUG_MISC, "=> pubdir, watch_fd issued on failed session\n"); - errno = EINVAL; - return -1; - } - + if (h->state != GG_STATE_PARSING) { if (gg_http_watch_fd(h) == -1) { gg_debug(GG_DEBUG_MISC, "=> pubdir, http failure\n"); - errno = EINVAL; + errno = EINVAL; return -1; } } if (h->state != GG_STATE_PARSING) - return 0; - - h->state = GG_STATE_DONE; - + return 0; + + h->state = GG_STATE_DONE; + if (!(h->data = p = malloc(sizeof(struct gg_pubdir)))) { gg_debug(GG_DEBUG_MISC, "=> pubdir, not enough memory for results\n"); return -1; } + p->success = 0; p->uin = 0; - + gg_debug(GG_DEBUG_MISC, "=> pubdir, let's parse \"%s\"\n", h->body); if ((tmp = strstr(h->body, "success")) || (tmp = strstr(h->body, "results"))) { @@ -451,7 +469,7 @@ { if (!h) return; - + free(h->data); gg_http_free(h); } @@ -486,10 +504,10 @@ h->callback = gg_token_watch_fd; h->destroy = gg_token_free; - + if (!async) gg_token_watch_fd(h); - + return h; } @@ -508,33 +526,34 @@ int gg_token_watch_fd(struct gg_http *h) { if (!h) { + errno = EFAULT; + return -1; + } + + if (h->state == GG_STATE_ERROR) { + gg_debug(GG_DEBUG_MISC, "=> token, watch_fd issued on failed session\n"); errno = EINVAL; return -1; } - - if (h->state == GG_STATE_ERROR) { - gg_debug(GG_DEBUG_MISC, "=> token, watch_fd issued on failed session\n"); - errno = EINVAL; - return -1; - } - + if (h->state != GG_STATE_PARSING) { if (gg_http_watch_fd(h) == -1) { gg_debug(GG_DEBUG_MISC, "=> token, http failure\n"); - errno = EINVAL; + errno = EINVAL; return -1; } } if (h->state != GG_STATE_PARSING) - return 0; - + return 0; + /* jeśli h->data jest puste, to ściągaliśmy tokenid i url do niego, * ale jeśli coś tam jest, to znaczy, że mamy drugi etap polegający * na pobieraniu tokenu. */ if (!h->data) { int width, height, length; - char *url = NULL, *tokenid = NULL, *path; + char *url = NULL, *tokenid = NULL, *path, *headers; + const char *host; struct gg_http *h2; struct gg_token *t; @@ -545,34 +564,64 @@ free(url); return -1; } - + if (!h->body || sscanf(h->body, "%d %d %d\r\n%s\r\n%s", &width, &height, &length, tokenid, url) != 5) { gg_debug(GG_DEBUG_MISC, "=> token, parsing failed\n"); free(url); free(tokenid); + errno = EINVAL; return -1; } - + /* dostaliśmy tokenid i wszystkie niezbędne informacje, * więc pobierzmy obrazek z tokenem */ - if (!(path = gg_saprintf("%s?tokenid=%s", url, tokenid))) { + if (strncmp(url, "http://", 7)) { + path = gg_saprintf("%s?tokenid=%s", url, tokenid); + host = GG_REGISTER_HOST; + } else { + char *slash = strchr(url + 7, '/'); + + if (slash) { + path = gg_saprintf("%s?tokenid=%s", slash, tokenid); + *slash = 0; + host = url + 7; + } else { + gg_debug(GG_DEBUG_MISC, "=> token, url parsing failed\n"); + free(url); + free(tokenid); + errno = EINVAL; + return -1; + } + } + + if (!path) { gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for token url\n"); free(url); free(tokenid); return -1; } - free(url); + if (!(headers = gg_saprintf("Host: %s\r\nUser-Agent: " GG_HTTP_USERAGENT "\r\n\r\n", host))) { + gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for token url\n"); + free(path); + free(url); + free(tokenid); + return -1; + } - if (!(h2 = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, h->async, "GET", path, "Host: " GG_REGISTER_HOST "\r\nUser-Agent: " GG_HTTP_USERAGENT "\r\n\r\n"))) { + if (!(h2 = gg_http_connect(host, GG_REGISTER_PORT, h->async, "GET", path, headers))) { gg_debug(GG_DEBUG_MISC, "=> token, gg_http_connect() failed mysteriously\n"); + free(headers); + free(url); free(path); free(tokenid); return -1; } + free(headers); free(path); + free(url); memcpy(h, h2, sizeof(struct gg_http)); free(h2); @@ -581,7 +630,7 @@ h->callback = gg_token_watch_fd; h->destroy = gg_token_free; - + if (!h->async) gg_token_watch_fd(h); @@ -599,7 +648,7 @@ /* obrazek mamy w h->body */ h->state = GG_STATE_DONE; } - + return 0; } @@ -619,7 +668,7 @@ if ((t = h->data)) free(t->tokenid); - + free(h->data); gg_http_free(h); } Index: kopete/protocols/gadu/libgadu/libgadu.c =================================================================== --- kopete/protocols/gadu/libgadu/libgadu.c (revision 417278) +++ kopete/protocols/gadu/libgadu/libgadu.c (working copy) @@ -107,9 +107,9 @@ #else return (uint32_t) (((x & (uint32_t) 0x000000ffU) << 24) | - ((x & (uint32_t) 0x0000ff00U) << 8) | - ((x & (uint32_t) 0x00ff0000U) >> 8) | - ((x & (uint32_t) 0xff000000U) >> 24)); + ((x & (uint32_t) 0x0000ff00U) << 8) | + ((x & (uint32_t) 0x00ff0000U) >> 8) | + ((x & (uint32_t) 0xff000000U) >> 24)); #endif } @@ -131,7 +131,7 @@ #else return (uint16_t) (((x & (uint16_t) 0x00ffU) << 8) | - ((x & (uint16_t) 0xff00U) >> 8)); + ((x & (uint16_t) 0xff00U) >> 8)); #endif } @@ -187,6 +187,7 @@ { int pipes[2], res; struct in_addr a; + int errno2; gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve(%p, %p, \"%s\");\n", fd, pid, hostname); @@ -199,8 +200,10 @@ return -1; if ((res = fork()) == -1) { + errno2 = errno; close(pipes[0]); close(pipes[1]); + errno = errno2; return -1; } @@ -297,7 +300,6 @@ if (!(tmp = malloc(sizeof(pthread_t)))) { gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory for pthread id\n"); - errno = ENOMEM; return -1; } @@ -309,7 +311,7 @@ if (!(d = malloc(sizeof(*d)))) { gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory\n"); - new_errno = ENOMEM; + new_errno = errno; goto cleanup; } @@ -317,7 +319,7 @@ if (!(d->hostname = strdup(hostname))) { gg_debug(GG_DEBUG_MISC, "// gg_resolve_pthread() out of memory\n"); - new_errno = ENOMEM; + new_errno = errno; goto cleanup; } @@ -406,7 +408,7 @@ */ int gg_write(struct gg_session *sess, const char *buf, int length) { - int res; + int res = 0; #ifdef __GG_LIBGADU_HAVE_OPENSSL if (sess->ssl) { @@ -453,13 +455,16 @@ * * - sess - opis sesji * - * w przypadku błędu NULL, kod błędu w errno. + * w przypadku błędu NULL, kod błędu w errno. należy zwrócić uwagę, że gdy + * połączenie jest nieblokujące, a kod błędu wynosi EAGAIN, nie udało się + * odczytać całego pakietu i nie należy tego traktować jako błąd. */ void *gg_recv_packet(struct gg_session *sess) { struct gg_header h; char *buf = NULL; - int ret = 0, offset, size = 0; + int ret = 0; + unsigned int offset, size = 0; gg_debug(GG_DEBUG_FUNCTION, "** gg_recv_packet(%p);\n", sess); @@ -483,7 +488,7 @@ gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv(%d,%p,%d) = %d\n", sess->fd, &h + sess->header_done, sizeof(h) - sess->header_done, ret); if (!ret) { - errno = 0; + errno = ECONNRESET; gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() header recv() failed: connection broken\n"); return NULL; } @@ -522,7 +527,7 @@ memcpy(&h, sess->recv_buf, sizeof(h)); /* jakieś sensowne limity na rozmiar pakietu */ - if (h.length < 0 || h.length > 65535) { + if (h.length > 65535) { gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() invalid packet length (%d)\n", h.length); errno = ERANGE; return NULL; @@ -548,11 +553,20 @@ while (size > 0) { ret = gg_read(sess, buf + sizeof(h) + offset, size); gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv(%d,%p,%d) = %d\n", sess->fd, buf + sizeof(h) + offset, size, ret); + if (!ret) { + gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed: connection broken\n"); + errno = ECONNRESET; + return NULL; + } if (ret > -1 && ret <= size) { offset += ret; size -= ret; } else if (ret == -1) { + int errno2 = errno; + gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() body recv() failed (errno=%d, %s)\n", errno, strerror(errno)); + errno = errno2; + if (errno == EAGAIN) { gg_debug(GG_DEBUG_MISC, "// gg_recv_packet() %d bytes received, %d left\n", offset, size); sess->recv_buf = buf; @@ -603,9 +617,9 @@ { struct gg_header *h; char *tmp; - int tmp_length; + unsigned int tmp_length; void *payload; - int payload_length; + unsigned int payload_length; va_list ap; int res; @@ -625,11 +639,8 @@ while (payload) { char *tmp2; - payload_length = va_arg(ap, int); + payload_length = va_arg(ap, unsigned int); - if (payload_length < 0) - gg_debug(GG_DEBUG_MISC, "// gg_send_packet() invalid payload length (%d)\n", payload_length); - if (!(tmp2 = realloc(tmp, tmp_length + payload_length))) { gg_debug(GG_DEBUG_MISC, "// gg_send_packet() not enough memory for payload\n"); free(tmp); @@ -679,7 +690,7 @@ static int gg_session_callback(struct gg_session *s) { if (!s) { - errno = EINVAL; + errno = EFAULT; return -1; } @@ -709,7 +720,7 @@ if (!p) { gg_debug(GG_DEBUG_FUNCTION, "** gg_login(%p);\n", p); - errno = EINVAL; + errno = EFAULT; return NULL; } @@ -724,7 +735,7 @@ if (!p->password || !p->uin) { gg_debug(GG_DEBUG_MISC, "// gg_login() invalid arguments. uin and password needed\n"); - errno = EINVAL; + errno = EFAULT; goto fail; } @@ -743,7 +754,7 @@ sess->check = GG_CHECK_READ; sess->timeout = GG_DEFAULT_TIMEOUT; sess->async = p->async; - sess->type = GG_SESSION_GG; + sess->type = GG_SESSION_GG; sess->initial_status = p->status; sess->callback = gg_session_callback; sess->destroy = gg_free_session; @@ -752,6 +763,8 @@ sess->external_port = p->external_port; sess->external_addr = p->external_addr; sess->protocol_version = (p->protocol_version) ? p->protocol_version : GG_DEFAULT_PROTOCOL_VERSION; + if (p->era_omnix) + sess->protocol_version |= GG_ERA_OMNIX_MASK; if (p->has_audio) sess->protocol_version |= GG_HAS_AUDIO_MASK; sess->client_version = (p->client_version) ? strdup(p->client_version) : NULL; @@ -1092,7 +1105,7 @@ #endif if (sess->fd != -1) { - shutdown(sess->fd, 2); + shutdown(sess->fd, SHUT_RDWR); close(sess->fd); sess->fd = -1; } @@ -1129,6 +1142,11 @@ return -1; } + if (size < 0) { + errno = EINVAL; + return -1; + } + s.recipient = gg_fix32(recipient); s.seq = gg_fix32(0); s.msgclass = gg_fix32(GG_CLASS_MSG); @@ -1141,15 +1159,21 @@ if (!res) { struct gg_image_queue *q = malloc(sizeof(*q)); - char *buf = malloc(size); + char *buf; if (!q) { gg_debug(GG_DEBUG_MISC, "// gg_image_request() not enough memory for image queue\n"); - free(buf); - errno = ENOMEM; return -1; } + buf = malloc(size); + if (size && !buf) + { + gg_debug(GG_DEBUG_MISC, "// gg_image_request() not enough memory for image\n"); + free(q); + return -1; + } + memset(q, 0, sizeof(*q)); q->sender = recipient; @@ -1191,7 +1215,7 @@ struct gg_send_msg s; const char *tmp; char buf[1910]; - int res; + int res = -1; gg_debug(GG_DEBUG_FUNCTION, "** gg_image_reply(%p, %d, \"%s\", %p, %d);\n", sess, recipient, filename, image, size); @@ -1200,6 +1224,16 @@ return -1; } + if (sess->state != GG_STATE_CONNECTED) { + errno = ENOTCONN; + return -1; + } + + if (size < 0) { + errno = EINVAL; + return -1; + } + /* wytnij ścieżki, zostaw tylko nazwę pliku */ while ((tmp = strrchr(filename, '/')) || (tmp = strrchr(filename, '\\'))) filename = tmp + 1; @@ -1209,11 +1243,6 @@ return -1; } - if (sess->state != GG_STATE_CONNECTED) { - errno = ENOTCONN; - return -1; - } - s.recipient = gg_fix32(recipient); s.seq = gg_fix32(0); s.msgclass = gg_fix32(GG_CLASS_MSG); @@ -1336,12 +1365,17 @@ errno = EFAULT; return -1; } - + if (sess->state != GG_STATE_CONNECTED) { errno = ENOTCONN; return -1; } + if (!message) { + errno = EFAULT; + return -1; + } + s.recipient = gg_fix32(recipient); if (!sess->seq) sess->seq = 0x01740000 | (rand() & 0xffff); @@ -1406,12 +1440,17 @@ errno = EFAULT; return -1; } - + if (sess->state != GG_STATE_CONNECTED) { errno = ENOTCONN; return -1; } + if (!message || recipients_count <= 0 || recipients_count > 0xffff || !recipients) { + errno = EINVAL; + return -1; + } + r.flag = 0x01; r.count = gg_fix32(recipients_count - 1); @@ -1421,6 +1460,9 @@ s.msgclass = gg_fix32(msgclass); recps = malloc(sizeof(uin_t) * recipients_count); + if (!recps) + return -1; + for (i = 0; i < recipients_count; i++) { s.recipient = gg_fix32(recipients[i]); @@ -1722,10 +1764,15 @@ int len; if (!sess) { - errno = EINVAL; + errno = EFAULT; return -1; } + if (sess->state != GG_STATE_CONNECTED) { + errno = ENOTCONN; + return -1; + } + if (!request) { sess->userlist_blocks = 1; return gg_send_packet(sess, GG_USERLIST_REQUEST, &type, sizeof(type), NULL); Index: kopete/protocols/gadu/libgadu/common.c =================================================================== --- kopete/protocols/gadu/libgadu/common.c (revision 417278) +++ kopete/protocols/gadu/libgadu/common.c (working copy) @@ -13,10 +13,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, + * USA. */ #include @@ -39,7 +39,7 @@ #include "libgadu.h" -FILE *gg_debug_file; +FILE *gg_debug_file = NULL; #ifndef GG_DEBUG_DISABLE @@ -55,7 +55,7 @@ { va_list ap; int old_errno = errno; - + if (gg_debug_handler) { va_start(ap, format); (*gg_debug_handler)(level, format, ap); @@ -63,7 +63,7 @@ goto cleanup; } - + if ((gg_debug_level & level)) { va_start(ap, format); vfprintf((gg_debug_file) ? gg_debug_file : stderr, format, ap); @@ -91,10 +91,10 @@ */ char *gg_vsaprintf(const char *format, va_list ap) { - int size = 0; + int size = 0; const char *start; char *buf = NULL; - + #ifdef __GG_LIBGADU_HAVE_VA_COPY va_list aq; @@ -107,13 +107,13 @@ # endif #endif - start = format; + start = format; #ifndef __GG_LIBGADU_HAVE_C99_VSNPRINTF { int res; char *tmp; - + size = 128; do { size *= 2; @@ -128,7 +128,7 @@ #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); @@ -138,7 +138,7 @@ #endif format = start; - + #ifdef __GG_LIBGADU_HAVE_VA_COPY vsnprintf(buf, size + 1, format, aq); va_end(aq); @@ -150,7 +150,7 @@ vsnprintf(buf, size + 1, format, ap); # endif #endif - + return buf; } @@ -180,36 +180,36 @@ /* * gg_get_line() // funkcja pomocnicza - * + * * podaje kolejną linię z bufora tekstowego. niszczy go bezpowrotnie, dzieląc * na kolejne stringi. zdarza się, nie ma potrzeby pisania funkcji dublującej * bufor żeby tylko mieć nieruszone dane wejściowe, skoro i tak nie będą nam * poźniej potrzebne. obcina `\r\n'. - * + * * - ptr - wskaźnik do zmiennej, która przechowuje aktualną pozycję * w przemiatanym buforze - * + * * wskaźnik do kolejnej linii tekstu lub NULL, jeśli to już koniec bufora. */ char *gg_get_line(char **ptr) { - char *foo, *res; + char *foo, *res; - if (!ptr || !*ptr || !strcmp(*ptr, "")) - return NULL; + if (!ptr || !*ptr || !strcmp(*ptr, "")) + return NULL; - res = *ptr; + res = *ptr; - if (!(foo = strchr(*ptr, '\n'))) - *ptr += strlen(*ptr); - else { - *ptr = foo + 1; - *foo = 0; - if (strlen(res) > 1 && res[strlen(res) - 1] == '\r') - res[strlen(res) - 1] = 0; - } + if (!(foo = strchr(*ptr, '\n'))) + *ptr += strlen(*ptr); + else { + *ptr = foo + 1; + *foo = 0; + if (strlen(res) > 1 && res[strlen(res) - 1] == '\r') + res[strlen(res) - 1] = 0; + } - return res; + return res; } /* @@ -227,27 +227,27 @@ */ int gg_connect(void *addr, int port, int async) { - int sock, one = 1; + int sock, one = 1, errno2; struct sockaddr_in sin; struct in_addr *a = addr; - struct sockaddr_in myaddr; + struct sockaddr_in myaddr; gg_debug(GG_DEBUG_FUNCTION, "** gg_connect(%s, %d, %d);\n", inet_ntoa(*a), port, async); - + if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) { gg_debug(GG_DEBUG_MISC, "// gg_connect() socket() failed (errno=%d, %s)\n", errno, strerror(errno)); return -1; } - memset(&myaddr, 0, sizeof(myaddr)); - myaddr.sin_family = AF_INET; + memset(&myaddr, 0, sizeof(myaddr)); + myaddr.sin_family = AF_INET; - myaddr.sin_addr.s_addr = gg_local_ip; + myaddr.sin_addr.s_addr = gg_local_ip; - if(bind(sock, (struct sockaddr *) &myaddr, sizeof(myaddr)) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_connect() bind() failed (errno=%d, %s)\n", errno, strerror(errno)); - return -1; - } + if (bind(sock, (struct sockaddr *) &myaddr, sizeof(myaddr)) == -1) { + gg_debug(GG_DEBUG_MISC, "// gg_connect() bind() failed (errno=%d, %s)\n", errno, strerror(errno)); + return -1; + } #ifdef ASSIGN_SOCKETS_TO_THREADS gg_win32_thread_socket(0, sock); @@ -260,7 +260,9 @@ 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)); + errno2 = errno; close(sock); + errno = errno2; return -1; } } @@ -268,16 +270,18 @@ sin.sin_port = htons(port); sin.sin_family = AF_INET; sin.sin_addr.s_addr = a->s_addr; - + if (connect(sock, (struct sockaddr*) &sin, sizeof(sin)) == -1) { if (errno && (!async || errno != EINPROGRESS)) { gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() failed (errno=%d, %s)\n", errno, strerror(errno)); + errno2 = errno; close(sock); + errno = errno2; return -1; } gg_debug(GG_DEBUG_MISC, "// gg_connect() connect() in progress\n"); } - + return sock; } @@ -290,12 +294,16 @@ * - buf - wskaźnik do bufora * - length - długość bufora * - * jeśli trafi na błąd odczytu, zwraca NULL. inaczej zwraca buf. + * jeśli trafi na błąd odczytu lub podano nieprawidłowe parametry, zwraca NULL. + * inaczej zwraca buf. */ char *gg_read_line(int sock, char *buf, int length) { int ret; + if (!buf || length < 0) + return NULL; + for (; length > 1; buf++, length--) { do { if ((ret = read(sock, buf, 1)) == -1 && errno != EINTR) { @@ -328,13 +336,17 @@ */ void gg_chomp(char *line) { - if (!line || strlen(line) < 1) + int len; + + if (!line) return; - if (line[strlen(line) - 1] == '\n') - line[strlen(line) - 1] = 0; - if (line[strlen(line) - 1] == '\r') - line[strlen(line) - 1] = 0; + len = strlen(line); + + if (len > 0 && line[len - 1] == '\n') + line[--len] = 0; + if (len > 0 && line[len - 1] == '\r') + line[--len] = 0; } /* @@ -352,10 +364,10 @@ { char *q, *buf, hex[] = "0123456789abcdef"; const char *p; - int size = 0; + unsigned int size = 0; - if (!str && !(str = strdup(""))) - return NULL; + if (!str) + str = ""; for (p = str; *p; p++, size++) { if (!((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9') || *p == ' ') || (*p == '@') || (*p == '.') || (*p == '-')) @@ -404,18 +416,18 @@ va_start(ap, format); for (j = 0; j < strlen(format); j++) { - unsigned char *arg, buf[16]; + char *arg, buf[16]; if (format[j] == 'u') { snprintf(buf, sizeof(buf), "%d", va_arg(ap, uin_t)); arg = buf; } else { - if (!(arg = va_arg(ap, unsigned char*))) + if (!(arg = va_arg(ap, char*))) arg = ""; - } + } i = 0; - while ((c = (int) arg[i++]) != 0) { + while ((c = (unsigned char) arg[i++]) != 0) { a = (c ^ b) + (c << 8); b = (a >> 24) | (a << 8); } @@ -446,12 +458,12 @@ int h_errnop, ret; size_t buflen = 1024; int new_errno; - + new_errno = ENOMEM; - + if (!(addr = malloc(sizeof(struct in_addr)))) goto cleanup; - + if (!(hp = calloc(1, sizeof(*hp)))) goto cleanup; @@ -459,45 +471,44 @@ goto cleanup; tmpbuf = buf; - + while ((ret = gethostbyname_r(hostname, hp, buf, buflen, &hp2, &h_errnop)) == ERANGE) { buflen *= 2; - + if (!(tmpbuf = realloc(buf, buflen))) break; - + buf = tmpbuf; } - + if (ret) new_errno = h_errnop; if (ret || !hp2 || !tmpbuf) goto cleanup; - + memcpy(addr, hp->h_addr, sizeof(struct in_addr)); - + free(buf); free(hp); - + return addr; - + cleanup: errno = new_errno; - + if (addr) free(addr); if (hp) free(hp); if (buf) free(buf); - + return NULL; #else struct hostent *hp; if (!(addr = malloc(sizeof(struct in_addr)))) { - errno = ENOMEM; goto cleanup; } @@ -507,7 +518,7 @@ memcpy(addr, hp->h_addr, sizeof(struct in_addr)); return addr; - + cleanup: if (addr) free(addr); @@ -535,7 +546,7 @@ * jeśli na win32 przy połączeniach synchronicznych zapamiętamy w jakim * wątku uruchomiliśmy funkcję, która się z czymkolwiek łączy, to z osobnego * wątku możemy anulować połączenie poprzez gg_win32_thread_socket(watek, -1); - * + * * - thread_id - id wątku. jeśli jest równe 0, brany jest aktualny wątek, * jeśli równe -1, usuwa wpis o podanym sockecie. * - socket - deskryptor gniazda. jeśli równe 0, zwraca deskryptor gniazda @@ -552,42 +563,41 @@ if (!thread_id) thread_id = GetCurrentThreadId(); - + while (wsk) { if ((thread_id == -1 && wsk->socket == socket) || wsk->id == thread_id) { if (close) { /* socket zostaje usuniety */ - closesocket(wsk->socket); - *p_wsk = wsk->next; - free(wsk); - return 1; - } else if (!socket) { + closesocket(wsk->socket); + *p_wsk = wsk->next; + free(wsk); + return 1; + } else if (!socket) { /* socket zostaje zwrocony */ return wsk->socket; - } else { + } else { /* socket zostaje ustawiony */ wsk->socket = socket; return socket; } - } + } + p_wsk = &(wsk->next); + wsk = wsk->next; + } - p_wsk = &(wsk->next); - wsk = wsk->next; - } - - if (close && socket != -1) + if (close && socket != -1) closesocket(socket); - if (close || !socket) + if (close || !socket) return 0; + + /* Dodaje nowy element */ + wsk = malloc(sizeof(gg_win32_thread)); + wsk->id = thread_id; + wsk->socket = socket; + wsk->next = 0; + *p_wsk = wsk; - /* Dodaje nowy element */ - wsk = malloc(sizeof(gg_win32_thread)); - wsk->id = thread_id; - wsk->socket = socket; - wsk->next = 0; - *p_wsk = wsk; - - return socket; + return socket; } #endif /* ASSIGN_SOCKETS_TO_THREADS */ @@ -607,14 +617,14 @@ char *gg_base64_encode(const char *buf) { char *out, *res; - int i = 0, j = 0, k = 0, len = strlen(buf); - + unsigned int i = 0, j = 0, k = 0, len = strlen(buf); + res = out = malloc((len / 3 + 1) * 4 + 2); if (!res) return NULL; - - while (j < len) { + + while (j <= len) { switch (i % 4) { case 0: k = (buf[j] & 252) >> 2; @@ -646,9 +656,9 @@ if (i % 4) for (j = 0; j < 4 - (i % 4); j++, out++) *out = '='; - + *out = 0; - + return res; } @@ -665,11 +675,11 @@ { char *res, *save, *foo, val; const char *end; - int index = 0; + unsigned int index = 0; if (!buf) return NULL; - + save = res = calloc(1, (strlen(buf) / 4 + 1) * 3 + 2); if (!save) @@ -706,7 +716,7 @@ index %= 4; } *res = 0; - + return save; } @@ -714,7 +724,7 @@ * gg_proxy_auth() // funkcja wewnętrzna * * tworzy nagłówek autoryzacji dla proxy. - * + * * zaalokowany tekst lub NULL, jeśli proxy nie jest włączone lub nie wymaga * autoryzacji. */ @@ -722,7 +732,7 @@ { char *tmp, *enc, *out; unsigned int tmp_size; - + if (!gg_proxy_enabled || !gg_proxy_username || !gg_proxy_password) return NULL; @@ -735,14 +745,14 @@ free(tmp); return NULL; } - + free(tmp); if (!(out = malloc(strlen(enc) + 40))) { free(enc); return NULL; } - + snprintf(out, strlen(enc) + 40, "Proxy-Authorization: Basic %s\r\n", enc); free(enc); @@ -759,7 +769,7 @@ static void gg_crc32_make_table() { uint32_t h = 1; - int i, j; + unsigned int i, j; memset(gg_crc32_table, 0, sizeof(gg_crc32_table)); @@ -789,6 +799,9 @@ if (!gg_crc32_initialized) gg_crc32_make_table(); + if (!buf || len < 0) + return crc; + crc ^= 0xffffffffL; while (len--) Index: kopete/protocols/gadu/libgadu/compat.h =================================================================== --- kopete/protocols/gadu/libgadu/compat.h (revision 417278) +++ kopete/protocols/gadu/libgadu/compat.h (working copy) @@ -15,7 +15,8 @@ * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, + * USA. */ #ifndef __COMPAT_H Index: kopete/protocols/gadu/libgadu/dcc.c =================================================================== --- kopete/protocols/gadu/libgadu/dcc.c (revision 417278) +++ kopete/protocols/gadu/libgadu/dcc.c (working copy) @@ -52,9 +52,9 @@ * - buf - bufor z danymi * - size - rozmiar danych */ -static void gg_dcc_debug_data(const char *prefix, int fd, const void *buf, int size) +static void gg_dcc_debug_data(const char *prefix, int fd, const void *buf, unsigned int size) { - int i; + unsigned int i; gg_debug(GG_DEBUG_MISC, "++ gg_dcc %s (fd=%d,len=%d)", prefix, fd, size); @@ -92,7 +92,7 @@ * - unix - czas w postaci unixowej * - filetime - czas w postaci windowsowej */ -static void gg_dcc_fill_filetime(uint32_t ut, uint32_t *ft) +void gg_dcc_fill_filetime(uint32_t ut, uint32_t *ft) { #ifdef __GG_LIBGADU_HAVE_LONG_LONG unsigned long long tmp; @@ -124,31 +124,48 @@ */ int gg_dcc_fill_file_info(struct gg_dcc *d, const char *filename) { + return gg_dcc_fill_file_info2(d, filename, filename); +} + +/* + * gg_dcc_fill_file_info2() + * + * wypełnia pola struct gg_dcc niezbędne do wysłania pliku. + * + * - d - struktura opisująca połączenie DCC + * - filename - nazwa pliku + * - local_filename - nazwa na lokalnym systemie plików + * + * 0, -1. + */ +int gg_dcc_fill_file_info2(struct gg_dcc *d, const char *filename, const char *local_filename) +{ struct stat st; const char *name, *ext, *p; + unsigned char *q; int i, j; - - gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_fill_file_info(%p, \"%s\");\n", d, filename); - + + gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_fill_file_info2(%p, \"%s\", \"%s\");\n", d, filename, local_filename); + if (!d || d->type != GG_SESSION_DCC_SEND) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info() invalid arguments\n"); + gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() invalid arguments\n"); errno = EINVAL; return -1; } - - if (stat(filename, &st) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info() stat() failed (%s)\n", strerror(errno)); + + if (stat(local_filename, &st) == -1) { + gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() stat() failed (%s)\n", strerror(errno)); return -1; } if ((st.st_mode & S_IFDIR)) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info() that's a directory\n"); + gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() that's a directory\n"); errno = EINVAL; return -1; } - if ((d->file_fd = open(filename, O_RDONLY)) == -1) { - gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info() open() failed (%s)\n", strerror(errno)); + if ((d->file_fd = open(local_filename, O_RDONLY)) == -1) { + gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() open() failed (%s)\n", strerror(errno)); return -1; } @@ -160,7 +177,7 @@ gg_dcc_fill_filetime(st.st_atime, d->file_info.atime); gg_dcc_fill_filetime(st.st_mtime, d->file_info.mtime); gg_dcc_fill_filetime(st.st_ctime, d->file_info.ctime); - + d->file_info.size = gg_fix32(st.st_size); d->file_info.mode = gg_fix32(0x20); /* FILE_ATTRIBUTE_ARCHIVE */ @@ -174,14 +191,40 @@ for (i = 0, p = name; i < 8 && p < ext; i++, p++) d->file_info.short_filename[i] = toupper(name[i]); - + + if (i == 8 && p < ext) { + d->file_info.short_filename[6] = '~'; + d->file_info.short_filename[7] = '1'; + } + if (strlen(ext) > 0) { for (j = 0; *ext && j < 4; j++, p++) d->file_info.short_filename[i + j] = toupper(ext[j]); - } - gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info() short name \"%s\", dos name \"%s\"\n", name, d->file_info.short_filename); + for (q = d->file_info.short_filename; *q; q++) { + if (*q == 185) { + *q = 165; + } else if (*q == 230) { + *q = 198; + } else if (*q == 234) { + *q = 202; + } else if (*q == 179) { + *q = 163; + } else if (*q == 241) { + *q = 209; + } else if (*q == 243) { + *q = 211; + } else if (*q == 156) { + *q = 140; + } else if (*q == 159) { + *q = 143; + } else if (*q == 191) { + *q = 175; + } + } + + gg_debug(GG_DEBUG_MISC, "// gg_dcc_fill_file_info2() short name \"%s\", dos name \"%s\"\n", name, d->file_info.short_filename); strncpy(d->file_info.filename, name, sizeof(d->file_info.filename) - 1); return 0; @@ -346,7 +389,7 @@ { struct gg_dcc *c; struct sockaddr_in sin; - int sock, bound = 0; + int sock, bound = 0, errno2; gg_debug(GG_DEBUG_FUNCTION, "** gg_create_dcc_socket(%d, %d);\n", uin, port); @@ -383,7 +426,9 @@ if (listen(sock, 10)) { gg_debug(GG_DEBUG_MISC, "// gg_create_dcc_socket() unable to listen (%s)\n", strerror(errno)); + errno2 = errno; close(sock); + errno = errno2; return NULL; } @@ -431,6 +476,7 @@ gg_debug(GG_DEBUG_FUNCTION, "++ gg_dcc_voice_send(%p, %p, %d);\n", d, buf, length); if (!d || !buf || length < 0 || d->type != GG_SESSION_DCC_VOICE) { gg_debug(GG_DEBUG_MISC, "// gg_dcc_voice_send() invalid argument\n"); + errno = EINVAL; return -1; } @@ -502,7 +548,7 @@ struct gg_event *e; int foo; - gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_watch_fd(%p);\n", h); + gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_watch_fd(%p);\n", h); if (!h || (h->type != GG_SESSION_DCC && h->type != GG_SESSION_DCC_SOCKET && h->type != GG_SESSION_DCC_SEND && h->type != GG_SESSION_DCC_GET && h->type != GG_SESSION_DCC_VOICE)) { gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() invalid argument\n"); @@ -862,7 +908,6 @@ e->event.dcc_voice_data.length = h->chunk_size; h->state = GG_STATE_READING_VOICE_HEADER; h->voice_buf = NULL; - } h->check = GG_CHECK_READ; @@ -1058,6 +1103,15 @@ utmp = sizeof(buf); gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() offset=%d, size=%d\n", h->offset, h->file_info.size); + + /* koniec pliku? */ + if (h->file_info.size == 0) { + gg_debug(GG_DEBUG_MISC, "// gg_dcc_watch_fd() read() reached eof on empty file\n"); + e->type = GG_EVENT_DCC_DONE; + + return e; + } + lseek(h->file_fd, h->offset, SEEK_SET); size = read(h->file_fd, buf, utmp); @@ -1215,7 +1269,7 @@ */ void gg_dcc_free(struct gg_dcc *d) { - gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_free(%p);\n", d); + gg_debug(GG_DEBUG_FUNCTION, "** gg_dcc_free(%p);\n", d); if (!d) return; Index: kopete/protocols/gadu/libgadu/pubdir50.c =================================================================== --- kopete/protocols/gadu/libgadu/pubdir50.c (revision 417278) +++ kopete/protocols/gadu/libgadu/pubdir50.c (working copy) @@ -12,10 +12,10 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, + * USA. */ #include @@ -84,7 +84,7 @@ return 0; } - + if (!(dupfield = strdup(field))) { gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_add_n() out of memory\n"); free(dupvalue); @@ -139,7 +139,7 @@ int gg_pubdir50_seq_set(gg_pubdir50_t req, uint32_t seq) { gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_seq_set(%p, %d);\n", req, seq); - + if (!req) { gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_seq_set() invalid arguments\n"); errno = EFAULT; @@ -164,7 +164,7 @@ if (!s) return; - + for (i = 0; i < s->entries_count; i++) { free(s->entries[i].field); free(s->entries[i].value); @@ -192,7 +192,7 @@ struct gg_pubdir50_request *r; gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50(%p, %p);\n", sess, req); - + if (!sess || !req) { gg_debug(GG_DEBUG_MISC, "// gg_pubdir50() invalid arguments\n"); errno = EFAULT; @@ -209,7 +209,7 @@ /* wyszukiwanie bierze tylko pierwszy wpis */ if (req->entries[i].num) continue; - + size += strlen(req->entries[i].field) + 1; size += strlen(req->entries[i].value) + 1; } @@ -261,12 +261,12 @@ struct gg_pubdir50_reply *r = (struct gg_pubdir50_reply*) packet; gg_pubdir50_t res; int num = 0; - + gg_debug(GG_DEBUG_FUNCTION, "** gg_pubdir50_handle_reply(%p, %p, %d);\n", e, packet, length); if (!e || !packet) { gg_debug(GG_DEBUG_MISC, "// gg_pubdir50_handle_reply() invalid arguments\n"); - errno = EINVAL; + errno = EFAULT; return -1; } @@ -318,7 +318,7 @@ } value = NULL; - + for (p = field; p < end; p++) { /* jeśli mamy koniec tekstu... */ if (!*p) { @@ -333,7 +333,7 @@ break; } } - + /* sprawdźmy, czy pole nie wychodzi poza pakiet, żeby nie * mieć segfaultów, jeśli serwer przestanie zakańczać pakietów * przez \0 */ @@ -354,10 +354,10 @@ if (gg_pubdir50_add_n(res, num, field, value) == -1) goto failure; } - } + } res->count = num + 1; - + return 0; failure: