# HG changeset patch # User Eric Warmenhoven # Date 1006809776 0 # Node ID 9123abd0db9282606b2ba4b8c691251c3aefdbbf # Parent 8f6365332a05c2da1a9402b290f4379637c805e8 [gaim-migrate @ 2805] Arkadiusz Miskiewicz's updates to Gadu-Gadu committer: Tailor Script diff -r 8f6365332a05 -r 9123abd0db92 src/protocols/gg/gg.c --- a/src/protocols/gg/gg.c Mon Nov 26 20:39:54 2001 +0000 +++ b/src/protocols/gg/gg.c Mon Nov 26 21:22:56 2001 +0000 @@ -1,8 +1,8 @@ /* * gaim - Gadu-Gadu Protocol Plugin - * $Id: gg.c 2804 2001-11-26 20:39:54Z warmenhoven $ + * $Id: gg.c 2805 2001-11-26 21:22:56Z warmenhoven $ * - * Copyright (C) 2001, Arkadiusz Miśkiewicz + * Copyright (C) 2001 Arkadiusz Miśkiewicz * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -62,7 +62,9 @@ #define AGG_GENDER_NONE -1 -#define AGG_PUBDIR_FORM "/appsvc/fmpubquery2.asp" +#define AGG_PUBDIR_USERLIST_EXPORT_FORM "/appsvc/fmcontactsput.asp" +#define AGG_PUBDIR_USERLIST_IMPORT_FORM "/appsvc/fmcontactsget.asp" +#define AGG_PUBDIR_SEARCH_FORM "/appsvc/fmpubquery2.asp" #define AGG_PUBDIR_MAX_ENTRIES 200 #define AGG_STATUS_AVAIL _("Available") @@ -73,16 +75,24 @@ #define AGG_STATUS_INVISIBLE_FRIENDS _("Invisible for friends only") #define AGG_STATUS_NOT_AVAIL _("Unavailable") +#define AGG_HTTP_NONE 0 +#define AGG_HTTP_SEARCH 1 +#define AGG_HTTP_USERLIST_IMPORT 2 +#define AGG_HTTP_USERLIST_EXPORT 3 + #define UC_NORMAL 2 struct agg_data { struct gg_session *sess; }; -struct agg_search { +struct agg_http { struct gaim_connection *gc; - gchar *search_data; + gchar *request; + gchar *form; + gchar *host; int inpa; + int type; }; static char *agg_name() @@ -94,7 +104,7 @@ { #ifdef HAVE_ICONV gchar *result = NULL; - if (iconv_string(encdst, encsrc, locstr, locstr+strlen(locstr)+1, &result, NULL) >= 0) + if (iconv_string(encdst, encsrc, locstr, locstr + strlen(locstr) + 1, &result, NULL) >= 0) return result; #endif return g_strdup(locstr); @@ -202,8 +212,7 @@ if ((data[i] >= 'a' && data[i] <= 'z') || (data[i] >= 'A' && data[i] <= 'Z') || (data[i] >= '0' && data[i] <= '9') - || data[i] == '=' || data[i] == '&' - || data[i] == '\n' || data[i] == '\r' || data[i] == '\t' || data[i] == '\014') { + || data[i] == '=' || data[i] == '&') { p = g_realloc(p, j + 1); p[j] = data[i]; j++; @@ -371,10 +380,11 @@ gchar *imsg; gchar user[20]; - g_snprintf(user, sizeof(user), "%u", e->event.msg.sender); + g_snprintf(user, sizeof(user), "%lu", e->event.msg.sender); if (!allowed_uin(gc, user)) break; imsg = charset_convert(e->event.msg.message, "CP1250", find_local_charset()); + /* e->event.msg.time - we don't know what this time is for */ serv_got_im(gc, user, imsg, 0, time((time_t) NULL)); g_free(imsg); } @@ -401,7 +411,7 @@ break; } - g_snprintf(user, sizeof(user), "%u", n->uin); + g_snprintf(user, sizeof(user), "%lu", n->uin); serv_got_update(gc, user, (status == UC_UNAVAILABLE) ? 0 : 1, 0, 0, 0, status, 0); n++; @@ -428,7 +438,7 @@ break; } - g_snprintf(user, sizeof(user), "%u", e->event.status.uin); + g_snprintf(user, sizeof(user), "%lu", e->event.status.uin); serv_got_update(gc, user, (status == UC_UNAVAILABLE) ? 0 : 1, 0, 0, 0, status, 0); } @@ -648,50 +658,13 @@ } } -static void search_results(gpointer data, gint source, GaimInputCondition cond) +static void search_results(struct gaim_connection *gc, gchar *webdata) { - struct agg_search *srch = data; - struct gaim_connection *gc = srch->gc; + gchar **webdata_tbl; gchar *buf; char *ptr; - char *webdata; - int len; - char read_data; - gchar **webdata_tbl; int i, j; - if (!g_slist_find(connections, gc)) { - debug_printf("search_callback: g_slist_find error\n"); - gaim_input_remove(srch->inpa); - g_free(srch); - close(source); - return; - } - - webdata = NULL; - len = 0; - - while (read(source, &read_data, 1) > 0 || errno == EWOULDBLOCK) { - if (errno == EWOULDBLOCK) { - errno = 0; - continue; - } - - if (!read_data) - continue; - - len++; - webdata = g_realloc(webdata, len); - webdata[len - 1] = read_data; - } - - webdata = g_realloc(webdata, len + 1); - webdata[len] = 0; - - gaim_input_remove(srch->inpa); - g_free(srch); - close(source); - if ((ptr = strstr(webdata, "query_results:")) == NULL || (ptr = strchr(ptr, '\n')) == NULL) { debug_printf("search_callback: pubdir result [%s]\n", webdata); g_free(webdata); @@ -795,87 +768,294 @@ g_free(buf); } -static void search_callback(gpointer data, gint source, GaimInputCondition cond) +static void agg_import_buddies_results(struct gaim_connection *gc, gchar *webdata) +{ + gchar *ptr; + gchar **users_tbl; + int i; + if (strstr(webdata, "no_data:")) { + g_free(webdata); + do_error_dialog(_("There is no Buddy List stored on server. Sorry!"), + _("Gadu-Gadu Error")); + return; + } + + if ((ptr = strstr(webdata, "get_results:")) == NULL || (ptr = strchr(ptr, ':')) == NULL) { + debug_printf("agg_import_buddies_list: import buddies result [%s]\n", webdata); + g_free(webdata); + do_error_dialog(_("Couldn't Import Buddies List from Server"), _("Gadu-Gadu Error")); + return; + } + ptr++; + + users_tbl = g_strsplit(ptr, "\n", AGG_PUBDIR_MAX_ENTRIES); + g_free(webdata); + + /* Parse array of Buddies List */ + for (i = 0; users_tbl[i] != NULL; i++) { + gchar **data_tbl; + gchar *name, *show; + + g_strdelimit(users_tbl[i], "\r\t\n\015", ' '); + data_tbl = g_strsplit(users_tbl[i], ";", 8); + + show = data_tbl[3]; + name = data_tbl[6]; + + if (invalid_uin(name)) { + continue; + } + + debug_printf("uin: %s\n", name); + if (!find_buddy(gc, name)) { + /* Default group if none specified on server */ + gchar *group = g_strdup("Gadu-Gadu"); + if (strlen(data_tbl[5])) { + gchar **group_tbl = g_strsplit(data_tbl[5], ",", 2); + if (strlen(group_tbl[0])) { + g_free(group); + group = g_strdup(group_tbl[0]); + } + g_strfreev(group_tbl); + } + /* Add Buddy to our userlist */ + add_buddy(gc, group, name, strlen(show) ? show : name); + do_export(gc); + g_free(group); + } + g_strfreev(data_tbl); + } + g_strfreev(users_tbl); +} + +static void agg_export_buddies_results(struct gaim_connection *gc, gchar *webdata) { - struct agg_search *srch = data; - struct gaim_connection *gc = srch->gc; - gchar *search_data = srch->search_data; + if (strstr(webdata, "put_success:")) { + g_free(webdata); + do_error_dialog(_("Buddies List sucessfully transfered into Server"), + _("Gadu-Gadu Information")); + return; + } + + debug_printf("agg_export_buddies_results: webdata [%s]\n", webdata); + g_free(webdata); + do_error_dialog(_("Couldn't transfer Buddies List into Server"), _("Gadu-Gadu Error")); +} + +static void http_results(gpointer data, gint source, GaimInputCondition cond) +{ + struct agg_http *hdata = data; + struct gaim_connection *gc = hdata->gc; + char *webdata; + int len; + char read_data; + + debug_printf("http_results: begin\n"); + + if (!g_slist_find(connections, gc)) { + debug_printf("search_callback: g_slist_find error\n"); + gaim_input_remove(hdata->inpa); + g_free(hdata); + close(source); + return; + } + + webdata = NULL; + len = 0; + + while (read(source, &read_data, 1) > 0 || errno == EWOULDBLOCK) { + if (errno == EWOULDBLOCK) { + errno = 0; + continue; + } + + if (!read_data) + continue; + + len++; + webdata = g_realloc(webdata, len); + webdata[len - 1] = read_data; + } + + webdata = g_realloc(webdata, len + 1); + webdata[len] = 0; + + gaim_input_remove(hdata->inpa); + close(source); + + debug_printf("http_results: type %d, webdata [%s]\n", hdata->type, webdata); + + switch (hdata->type) { + case AGG_HTTP_SEARCH: + search_results(gc, webdata); + break; + case AGG_HTTP_USERLIST_IMPORT: + agg_import_buddies_results(gc, webdata); + break; + case AGG_HTTP_USERLIST_EXPORT: + agg_export_buddies_results(gc, webdata); + break; + case AGG_HTTP_NONE: + default: + debug_printf("http_results: unsupported type %d\n", hdata->type); + break; + } + + g_free(hdata); +} + +static void http_req_callback(gpointer data, gint source, GaimInputCondition cond) +{ + struct agg_http *hdata = data; + struct gaim_connection *gc = hdata->gc; + gchar *request = hdata->request; gchar *buf; char *ptr; - debug_printf("search_callback enter: begin\n"); + debug_printf("http_req_callback: begin\n"); if (!g_slist_find(connections, gc)) { - debug_printf("search_callback: g_slist_find error\n"); - g_free(search_data); - g_free(srch); + debug_printf("http_req_callback: g_slist_find error\n"); + g_free(request); + g_free(hdata); close(source); return; } if (source == -1) { - g_free(search_data); - g_free(srch); + g_free(request); + g_free(hdata); return; } - ptr = encode_postdata(search_data); - g_free(search_data); + ptr = encode_postdata(request); + g_free(request); - debug_printf("search_callback: pubdir request [%s]\n", ptr); + debug_printf("http_req_callback: http request [%s]\n", ptr); - buf = g_strdup_printf("POST " AGG_PUBDIR_FORM " HTTP/1.0\r\n" - "Host: " GG_PUBDIR_HOST "\r\n" + buf = g_strdup_printf("POST %s HTTP/1.0\r\n" + "Host: %s\r\n" "Content-Type: application/x-www-form-urlencoded\r\n" - "User-Agent: Mozilla/4.7 [en] (Win98; I)\r\n" + "User-Agent: " GG_HTTP_USERAGENT "\r\n" "Content-Length: %d\r\n" - "Pragma: no-cache\r\n" "\r\n" "%s\r\n", strlen(ptr), ptr); + "Pragma: no-cache\r\n" "\r\n" "%s\r\n", + hdata->form, hdata->host, strlen(ptr), ptr); g_free(ptr); if (write(source, buf, strlen(buf)) < strlen(buf)) { g_free(buf); - g_free(srch); + g_free(hdata); close(source); - do_error_dialog(_("Couldn't send search request"), _("Gadu-Gadu Error")); + do_error_dialog(_("Couldn't send http request"), _("Gadu-Gadu Error")); return; } g_free(buf); - srch->inpa = gaim_input_add(source, GAIM_INPUT_READ, search_results, srch); + hdata->inpa = gaim_input_add(source, GAIM_INPUT_READ, http_results, hdata); +} + +static void agg_import_buddies(struct gaim_connection *gc) +{ + struct agg_http *hi = g_new0(struct agg_http, 1); + static char msg[AGG_BUF_LEN]; + + hi->gc = gc; + hi->type = AGG_HTTP_USERLIST_IMPORT; + hi->form = AGG_PUBDIR_USERLIST_IMPORT_FORM; + hi->host = GG_PUBDIR_HOST; + hi->request = g_strdup_printf("FmNum=%s&Pass=%s", gc->username, gc->password); + + if (proxy_connect(GG_PUBDIR_HOST, GG_PUBDIR_PORT, http_req_callback, hi) < 0) { + g_snprintf(msg, sizeof(msg), _("Buddies List import from Server failed (%s)"), + GG_PUBDIR_HOST); + do_error_dialog(msg, _("Gadu-Gadu Error")); + g_free(hi->request); + g_free(hi); + return; + } +} + +static void agg_export_buddies(struct gaim_connection *gc) +{ + struct agg_http *he = g_new0(struct agg_http, 1); + static char msg[AGG_BUF_LEN]; + gchar *ptr; + GSList *gr = gc->groups; + + he->gc = gc; + he->type = AGG_HTTP_USERLIST_EXPORT; + he->form = AGG_PUBDIR_USERLIST_EXPORT_FORM; + he->host = GG_PUBDIR_HOST; + he->request = g_strdup_printf("FmNum=%s&Pass=%s&Contacts=", gc->username, gc->password); + + while (gr) { + struct group *g = gr->data; + GSList *m = g->members; + while (m) { + struct buddy *b = m->data; + gchar *newdata; + /* GG Number */ + gchar *name = b->name; + /* GG Pseudo */ + gchar *show = strlen(b->show) ? b->show : b->name; + + ptr = he->request; + newdata = g_strdup_printf("%s;%s;%s;%s;%s;%s;%s\r\n", + show, show, show, show, "", g->name, name); + he->request = g_strconcat(ptr, newdata, NULL); + g_free(newdata); + g_free(ptr); + + m = g_slist_next(m); + } + gr = g_slist_next(gr); + } + + if (proxy_connect(GG_PUBDIR_HOST, GG_PUBDIR_PORT, http_req_callback, he) < 0) { + g_snprintf(msg, sizeof(msg), _("Buddies List export to Server failed (%s)"), + GG_PUBDIR_HOST); + do_error_dialog(msg, _("Gadu-Gadu Error")); + g_free(he->request); + g_free(he); + return; + } } static void agg_dir_search(struct gaim_connection *gc, char *first, char *middle, char *last, char *maiden, char *city, char *state, char *country, char *email) { - struct agg_search *srch = g_new0(struct agg_search, 1); + struct agg_http *srch = g_new0(struct agg_http, 1); static char msg[AGG_BUF_LEN]; srch->gc = gc; + srch->type = AGG_HTTP_SEARCH; + srch->form = AGG_PUBDIR_SEARCH_FORM; + srch->host = GG_PUBDIR_HOST; if (email && strlen(email)) { - srch->search_data = g_strdup_printf("Mode=1&Email=%s", email); + srch->request = g_strdup_printf("Mode=1&Email=%s", email); } else { gchar *new_first = charset_convert(first, find_local_charset(), "CP1250"); gchar *new_last = charset_convert(last, find_local_charset(), "CP1250"); gchar *new_city = charset_convert(city, find_local_charset(), "CP1250"); /* For active only add &ActiveOnly= */ - srch->search_data = g_strdup_printf("Mode=0&FirstName=%s&LastName=%s&Gender=%d" - "&NickName=%s&City=%s&MinBirth=%d&MaxBirth=%d", - new_first, new_last, AGG_GENDER_NONE, - "", new_city, 0, 0); + srch->request = g_strdup_printf("Mode=0&FirstName=%s&LastName=%s&Gender=%d" + "&NickName=%s&City=%s&MinBirth=%d&MaxBirth=%d", + new_first, new_last, AGG_GENDER_NONE, + "", new_city, 0, 0); g_free(new_first); g_free(new_last); g_free(new_city); } - if (proxy_connect(GG_PUBDIR_HOST, GG_PUBDIR_PORT, search_callback, srch) < 0) { + if (proxy_connect(GG_PUBDIR_HOST, GG_PUBDIR_PORT, http_req_callback, srch) < 0) { g_snprintf(msg, sizeof(msg), _("Connect to search service failed (%s)"), GG_PUBDIR_HOST); do_error_dialog(msg, _("Gadu-Gadu Error")); - g_free(srch->search_data); + g_free(srch->request); g_free(srch); return; } @@ -885,6 +1065,10 @@ { if (!strcmp(action, _("Directory Search"))) { show_find_info(gc); + } else if (!strcmp(action, _("Import Buddies List from Server"))) { + agg_import_buddies(gc); + } else if (!strcmp(action, _("Export Buddies List to Server"))) { + agg_export_buddies(gc); } } @@ -893,33 +1077,38 @@ GList *m = NULL; m = g_list_append(m, _("Directory Search")); + m = g_list_append(m, _("Import Buddies List from Server")); + m = g_list_append(m, _("Export Buddies List to Server")); return m; } static void agg_get_info(struct gaim_connection *gc, char *who) { - struct agg_search *srch = g_new0(struct agg_search, 1); + struct agg_http *srch = g_new0(struct agg_http, 1); static char msg[AGG_BUF_LEN]; srch->gc = gc; + srch->type = AGG_HTTP_SEARCH; + srch->form = AGG_PUBDIR_SEARCH_FORM; + srch->host = GG_PUBDIR_HOST; /* If it's invalid uin then maybe it's nickname? */ if (invalid_uin(who)) { gchar *new_who = charset_convert(who, find_local_charset(), "CP1250"); - srch->search_data = g_strdup_printf("Mode=0&FirstName=%s&LastName=%s&Gender=%d" - "&NickName=%s&City=%s&MinBirth=%d&MaxBirth=%d", - "", "", AGG_GENDER_NONE, new_who, "", 0, 0); + srch->request = g_strdup_printf("Mode=0&FirstName=%s&LastName=%s&Gender=%d" + "&NickName=%s&City=%s&MinBirth=%d&MaxBirth=%d", + "", "", AGG_GENDER_NONE, new_who, "", 0, 0); g_free(new_who); } else - srch->search_data = g_strdup_printf("Mode=3&UserId=%s", who); + srch->request = g_strdup_printf("Mode=3&UserId=%s", who); - if (proxy_connect(GG_PUBDIR_HOST, GG_PUBDIR_PORT, search_callback, srch) < 0) { + if (proxy_connect(GG_PUBDIR_HOST, GG_PUBDIR_PORT, http_req_callback, srch) < 0) { g_snprintf(msg, sizeof(msg), _("Connect to search service failed (%s)"), GG_PUBDIR_HOST); do_error_dialog(msg, _("Gadu-Gadu Error")); - g_free(srch->search_data); + g_free(srch->request); g_free(srch); return; } diff -r 8f6365332a05 -r 9123abd0db92 src/protocols/gg/libgg.c --- a/src/protocols/gg/libgg.c Mon Nov 26 20:39:54 2001 +0000 +++ b/src/protocols/gg/libgg.c Mon Nov 26 21:22:56 2001 +0000 @@ -1,7 +1,8 @@ -/* $Id: libgg.c 2608 2001-10-24 08:35:55Z warmenhoven $ */ +/* $Id: libgg.c 2805 2001-11-26 21:22:56Z warmenhoven $ */ /* - * (C) Copyright 2001 Wojtek Kaniewski + * (C) Copyright 2001 Wojtek Kaniewski , + * Robert J. Woźny * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as @@ -26,22 +27,39 @@ #include #include #include -#include -#include +#include #include #include -#include +#ifndef _AIX +# include +#endif #include #include +#include +#ifdef sun +#include +#endif #include +#if G_BYTE_ORDER == G_BIG_ENDIAN +# define WORDS_BIGENDIAN 1 +#endif #include "libgg.h" +#include "config.h" int gg_debug_level = 0; -#ifdef GG_DEBUG +#ifndef lint + +static char rcsid[] +#ifdef __GNUC__ + __attribute__ ((unused)) +#endif + = "$Id: libgg.c 2805 2001-11-26 21:22:56Z warmenhoven $"; + +#endif /* - * gg_debug_real() + * gg_debug() * * wyrzuca komunikat o danym poziomie, o ile użytkownik sobie tego życzy. * @@ -50,10 +68,10 @@ * * niczego nie zwraca. */ -void gg_debug_real(int level, char *format, ...) +void gg_debug(int level, char *format, ...) { va_list ap; - + if ((gg_debug_level & level)) { va_start(ap, format); vprintf(format, ap); @@ -61,8 +79,6 @@ } } -#endif /* GG_DEBUG */ - /* * fix32() // funkcja wewnętrzna * @@ -70,15 +86,14 @@ */ static inline unsigned long fix32(unsigned long x) { -#if G_BYTE_ORDER == G_LITTLE_ENDIAN +#ifndef WORDS_BIGENDIAN return x; #else return (unsigned long) - (((x & (unsigned long) 0x000000ffU) << 24) | - ((x & (unsigned long) 0x0000ff00U) << 8) | - ((x & (unsigned long) 0x00ff0000U) >> 8) | - ((x & (unsigned long) 0xff000000U) >> 24)); -#endif + (((x & (unsigned long)0x000000ffU) << 24) | + ((x & (unsigned long)0x0000ff00U) << 8) | + ((x & (unsigned long)0x00ff0000U) >> 8) | ((x & (unsigned long)0xff000000U) >> 24)); +#endif } /* @@ -88,12 +103,11 @@ */ static inline unsigned short fix16(unsigned short x) { -#if G_BYTE_ORDER == G_LITTLE_ENDIAN +#ifndef WORDS_BIGENDIAN return x; #else return (unsigned short) - (((x & (unsigned short) 0x00ffU) << 8) | - ((x & (unsigned short) 0xff00U) >> 8)); + (((x & (unsigned short)0x00ffU) << 8) | ((x & (unsigned short)0xff00U) >> 8)); #endif } @@ -101,8 +115,8 @@ * gg_alloc_sprintf() // funkcja wewnętrzna * * robi dokładnie to samo, co sprintf(), tyle że alokuje sobie wcześniej - * miejsce na dane. jak znam życie, ze względu na różnice między funkcjami - * vsnprintf() na różnych platformach, nie będzie działało ;) + * miejsce na dane. powinno działać na tych maszynach, które mają funkcję + * vsnprintf() zgodną z C99, jak i na wcześniejszych. * * - format, ... - parametry takie same jak w innych funkcjach *printf() * @@ -112,16 +126,26 @@ char *gg_alloc_sprintf(char *format, ...) { va_list ap; - char *buf = NULL; - int size; + char *buf = NULL, *tmp; + int size = 0, res; va_start(ap, format); - if ((size = vsnprintf(buf, 0, format, ap)) < 0) - return NULL; - - if (!(buf = malloc(size + 1))) - return NULL; + if ((size = vsnprintf(buf, 0, format, ap)) < 1) { + size = 128; + do { + size *= 2; + if (!(tmp = realloc(buf, size))) { + free(buf); + return NULL; + } + buf = tmp; + res = vsnprintf(buf, size, format, ap); + } while (res == size - 1); + } else { + if (!(buf = malloc(size + 1))) + return NULL; + } vsnprintf(buf, size + 1, format, ap); @@ -131,6 +155,40 @@ } /* + * gg_get_line() // funkcja wewnętrzna + * + * podaje kolejną linię z bufora tekstowego. psuje co 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; + + if (!ptr || !*ptr || !strcmp(*ptr, "")) + return NULL; + + res = *ptr; + + if (!(foo = strchr(*ptr, '\n'))) + *ptr += strlen(*ptr); + else { + *ptr = foo + 1; + *foo = 0; + if (res[strlen(res) - 1] == '\r') + res[strlen(res) - 1] = 0; + } + + return res; +} + +/* * gg_resolve() // funkcja wewnętrzna * * tworzy pipe'y, forkuje się i w drugim procesie zaczyna resolvować @@ -150,7 +208,7 @@ struct in_addr a; gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve(..., \"%s\");\n", hostname); - + if (!fd | !pid) { errno = EFAULT; return -1; @@ -165,11 +223,11 @@ if (!res) { if ((a.s_addr = inet_addr(hostname)) == INADDR_NONE) { struct hostent *he; - + if (!(he = gethostbyname(hostname))) a.s_addr = INADDR_NONE; else - memcpy((char*) &a, he->h_addr, sizeof(a)); + memcpy((char *)&a, he->h_addr, sizeof(a)); } write(pipes[1], &a, sizeof(a)); @@ -205,21 +263,16 @@ struct in_addr *a = addr; 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, "-- socket() failed. errno = %d (%s)\n", errno, strerror(errno)); return -1; } if (async) { -#ifdef FIONBIO if (ioctl(sock, FIONBIO, &one) == -1) { -#else - int flags = fcntl (sock, F_GETFL); - if (flags < 0 || - fcntl (sock, F_SETFL, flags | O_NONBLOCK) < 0) { -#endif - gg_debug(GG_DEBUG_MISC, "-- ioctl() failed. errno = %d (%s)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, "-- ioctl() failed. errno = %d (%s)\n", errno, + strerror(errno)); return -1; } } @@ -227,13 +280,16 @@ 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) { - gg_debug(GG_DEBUG_MISC, "-- connect() failed. errno = %d (%s)\n", errno, strerror(errno)); - if (errno && (!async || errno != EINPROGRESS)) + + if (connect(sock, (struct sockaddr *)&sin, sizeof(sin)) == -1) { + if (errno && (!async || errno != EINPROGRESS)) { + gg_debug(GG_DEBUG_MISC, "-- connect() failed. errno = %d (%s)\n", errno, + strerror(errno)); return -1; + } + gg_debug(GG_DEBUG_MISC, "-- connect() in progress\n"); } - + return sock; } @@ -253,7 +309,7 @@ int ret; gg_debug(GG_DEBUG_FUNCTION, "** gg_read_line(...);\n"); - + for (; length > 1; buf++, length--) { do { if ((ret = read(sock, buf, 1)) == -1 && errno != EINTR) { @@ -289,7 +345,7 @@ int ret = 0, offset, size = 0; gg_debug(GG_DEBUG_FUNCTION, "** gg_recv_packet(...);\n"); - + if (!sess) { errno = EFAULT; return NULL; @@ -301,7 +357,8 @@ gg_debug(GG_DEBUG_MISC, "-- header recv(..., %d) = %d\n", sizeof(h), ret); if (ret < sizeof(h)) { if (errno != EINTR) { - gg_debug(GG_DEBUG_MISC, "-- errno = %d (%s)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, "-- errno = %d (%s)\n", errno, + strerror(errno)); return NULL; } } @@ -343,7 +400,7 @@ if (ret > -1 && ret <= size) { offset += ret; size -= ret; - } else if (ret == -1) { + } else if (ret == -1) { gg_debug(GG_DEBUG_MISC, "-- errno = %d (%s)\n", errno, strerror(errno)); if (errno == EAGAIN) { gg_debug(GG_DEBUG_MISC, "-- %d bytes received, %d left\n", offset, size); @@ -353,7 +410,7 @@ return NULL; } if (errno != EINTR) { - /* errno = EINVAL; */ +// errno = EINVAL; free(buf); return NULL; } @@ -362,16 +419,14 @@ sess->recv_left = 0; -#ifdef GG_DEBUG if ((gg_debug_level & GG_DEBUG_DUMP)) { int i; gg_debug(GG_DEBUG_DUMP, ">> received packet (type=%.2x):", h.type); - for (i = 0; i < sizeof(h) + h.length; i++) - gg_debug(GG_DEBUG_DUMP, " %.2x", (unsigned char) buf[i]); + for (i = 0; i < sizeof(h) + h.length; i++) + gg_debug(GG_DEBUG_DUMP, " %.2x", (unsigned char)buf[i]); gg_debug(GG_DEBUG_DUMP, "\n"); } -#endif return buf; } @@ -392,14 +447,16 @@ * zabrakło pamięci. inaczej był błąd przy wysyłaniu pakietu. dla errno=0 * nie wysłano całego pakietu. */ -static int gg_send_packet(int sock, int type, void *packet, int length, void *payload, int payload_length) +static int gg_send_packet(int sock, int type, void *packet, int length, void *payload, + int payload_length) { struct gg_header *h; int res, plen; char *tmp; - gg_debug(GG_DEBUG_FUNCTION, "** gg_send_packet(0x%.2x, %d, %d);\n", type, length, payload_length); - + gg_debug(GG_DEBUG_FUNCTION, "** gg_send_packet(0x%.2x, %d, %d);\n", type, length, + payload_length); + if (length < 0 || payload_length < 0) { gg_debug(GG_DEBUG_MISC, "-- invalid packet/payload length\n"); errno = ERANGE; @@ -411,7 +468,7 @@ return -1; } - h = (struct gg_header*) tmp; + h = (struct gg_header *)tmp; h->type = fix32(type); h->length = fix32(length + payload_length); @@ -420,26 +477,25 @@ if (payload) memcpy(tmp + sizeof(struct gg_header) + length, payload, payload_length); -#ifdef GG_DEBUG if ((gg_debug_level & GG_DEBUG_DUMP)) { int i; gg_debug(GG_DEBUG_DUMP, "%%%% sending packet (type=%.2x):", fix32(h->type)); for (i = 0; i < sizeof(struct gg_header) + fix32(h->length); i++) - gg_debug(GG_DEBUG_DUMP, " %.2x", (unsigned char) tmp[i]); + gg_debug(GG_DEBUG_DUMP, " %.2x", (unsigned char)tmp[i]); gg_debug(GG_DEBUG_DUMP, "\n"); } -#endif plen = sizeof(struct gg_header) + length + payload_length; - + if ((res = write(sock, tmp, plen)) < plen) { - gg_debug(GG_DEBUG_MISC, "-- write() failed. res = %d, errno = %d (%s)\n", res, errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, "-- write() failed. res = %d, errno = %d (%s)\n", res, errno, + strerror(errno)); free(tmp); return -1; } - free(tmp); + free(tmp); return 0; } @@ -479,6 +535,9 @@ sess->async = async; sess->seq = 0; sess->recv_left = 0; + sess->last_pong = 0; + sess->server_ip = 0; + sess->initial_status = 0; if (async) { if (gg_resolve(&sess->fd, &sess->pid, GG_APPMSG_HOST)) { @@ -491,13 +550,13 @@ if ((a.s_addr = inet_addr(GG_APPMSG_HOST)) == INADDR_NONE) { struct hostent *he; - + if (!(he = gethostbyname(GG_APPMSG_HOST))) { gg_debug(GG_DEBUG_MISC, "-- host %s not found\n", GG_APPMSG_HOST); free(sess); return NULL; } else - memcpy((char*) &a, he->h_addr, sizeof(a)); + memcpy((char *)&a, he->h_addr, sizeof(a)); } if (!(sess->fd = gg_connect(&a, GG_APPMSG_PORT, 0)) == -1) { @@ -518,6 +577,7 @@ } if (e->type == GG_EVENT_CONN_FAILED) { + errno = EACCES; gg_debug(GG_DEBUG_MISC, "-- could not login\n"); gg_free_event(e); free(sess); @@ -598,7 +658,7 @@ if (sess->state == GG_STATE_CONNECTED) gg_change_status(sess, GG_STATUS_NOT_AVAIL); - + if (sess->fd) { shutdown(sess->fd, 2); close(sess->fd); @@ -626,7 +686,7 @@ errno = EFAULT; return -1; } - + if (sess->state != GG_STATE_CONNECTED) { errno = ENOTCONN; return -1; @@ -640,7 +700,7 @@ s.seq = fix32(sess->seq); s.msgclass = fix32(msgclass); sess->seq += (rand() % 0x300) + 0x300; - + if (gg_send_packet(sess->fd, GG_SEND_MSG, &s, sizeof(s), message, strlen(message) + 1) == -1) return -1; @@ -704,7 +764,7 @@ * * jeśli udało się, zwraca 0. jeśli błąd, dostajemy -1. */ -int gg_notify(struct gg_session *sess, uin_t *userlist, int count) +int gg_notify(struct gg_session *sess, uin_t * userlist, int count) { struct gg_notify *n; uin_t *u; @@ -714,25 +774,25 @@ errno = EFAULT; return -1; } - + if (sess->state != GG_STATE_CONNECTED) { errno = ENOTCONN; return -1; } gg_debug(GG_DEBUG_FUNCTION, "** gg_notify(..., %d);\n", count); - + if (!userlist || !count) return 0; - - if (!(n = (struct gg_notify*) malloc(sizeof(*n) * count))) + + if (!(n = (struct gg_notify *)malloc(sizeof(*n) * count))) return -1; - - for (u = userlist, i = 0; i < count; u++, i++) { + + for (u = userlist, i = 0; i < count; u++, i++) { n[i].uin = fix32(*u); n[i].dunno1 = 3; } - + if (gg_send_packet(sess->fd, GG_NOTIFY, n, sizeof(*n) * count, NULL, 0) == -1) res = -1; @@ -764,12 +824,12 @@ errno = ENOTCONN; return -1; } - + gg_debug(GG_DEBUG_FUNCTION, "** gg_add_notify(..., %u);\n", uin); - + a.uin = fix32(uin); a.dunno1 = 3; - + return gg_send_packet(sess->fd, GG_ADD_NOTIFY, &a, sizeof(a), NULL, 0); } @@ -798,10 +858,10 @@ } gg_debug(GG_DEBUG_FUNCTION, "** gg_remove_notify(..., %u);\n", uin); - + a.uin = fix32(uin); a.dunno1 = 3; - + return gg_send_packet(sess->fd, GG_REMOVE_NOTIFY, &a, sizeof(a), NULL, 0); } @@ -827,12 +887,13 @@ gg_debug(GG_DEBUG_FUNCTION, "** gg_watch_fd_connected(...);\n"); if (!(h = gg_recv_packet(sess))) { - gg_debug(GG_DEBUG_MISC, "-- gg_recv_packet failed. errno = %d (%d)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, "-- gg_recv_packet failed. errno = %d (%d)\n", errno, + strerror(errno)); return -1; } - p = (void*) h + sizeof(struct gg_header); - + p = (void *)h + sizeof(struct gg_header); + if (h->type == GG_RECV_MSG) { struct gg_recv_msg *r = p; @@ -842,7 +903,8 @@ e->type = GG_EVENT_MSG; e->event.msg.msgclass = fix32(r->msgclass); e->event.msg.sender = fix32(r->sender); - e->event.msg.message = strdup((char*) r + sizeof(*r)); + e->event.msg.message = strdup((char *)r + sizeof(*r)); + e->event.msg.time = fix32(r->time); } } @@ -851,9 +913,9 @@ int count, i; gg_debug(GG_DEBUG_MISC, "-- received a notify reply\n"); - + e->type = GG_EVENT_NOTIFY; - if (!(e->event.notify = (void*) malloc(h->length + 2 * sizeof(*n)))) { + if (!(e->event.notify = (void *)malloc(h->length + 2 * sizeof(*n)))) { gg_debug(GG_DEBUG_MISC, "-- not enough memory\n"); free(h); return -1; @@ -893,6 +955,12 @@ } } + if (h->type == GG_PONG) { + gg_debug(GG_DEBUG_MISC, "-- received a pong\n"); + + sess->last_pong = time(NULL); + } + free(h); return 0; @@ -944,7 +1012,7 @@ gg_debug(GG_DEBUG_FUNCTION, "** gg_watch_fd(...);\n"); - if (!(e = (void*) malloc(sizeof(*e)))) { + if (!(e = (void *)malloc(sizeof(*e)))) { gg_debug(GG_DEBUG_MISC, "-- not enough memory\n"); return NULL; } @@ -952,15 +1020,16 @@ e->type = GG_EVENT_NONE; switch (sess->state) { - case GG_STATE_RESOLVING: + case GG_STATE_RESOLVING: { struct in_addr a; gg_debug(GG_DEBUG_MISC, "== GG_STATE_RESOLVING\n"); if (read(sess->fd, &a, sizeof(a)) < sizeof(a) || a.s_addr == INADDR_NONE) { - gg_debug(GG_DEBUG_MISC, "-- resolving failed\n"); + gg_debug(GG_DEBUG_MISC, "-- resolving failed\n"); + errno = ENOENT; e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_RESOLVING; sess->state = GG_STATE_IDLE; @@ -970,6 +1039,8 @@ break; } + sess->server_ip = a.s_addr; + close(sess->fd); waitpid(sess->pid, NULL, 0); @@ -977,50 +1048,83 @@ gg_debug(GG_DEBUG_MISC, "-- resolved, now connecting\n"); if ((sess->fd = gg_connect(&a, GG_APPMSG_PORT, sess->async)) == -1) { - gg_debug(GG_DEBUG_MISC, "-- connection failed\n"); + struct in_addr *addr = (struct in_addr *)&sess->server_ip; + + gg_debug(GG_DEBUG_MISC, + "-- connection failed, trying direct connection\n"); - e->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_CONNECTING; - sess->state = GG_STATE_IDLE; - break; + if ((sess->fd = gg_connect(addr, GG_DEFAULT_PORT, sess->async)) == -1) { + gg_debug(GG_DEBUG_MISC, + "-- connection failed, trying https connection\n"); + if ((sess->fd = + gg_connect(&a, GG_HTTPS_PORT, sess->async)) == -1) { + gg_debug(GG_DEBUG_MISC, + "-- connect() failed. errno = %d (%s)\n", errno, + strerror(errno)); + + e->type = GG_EVENT_CONN_FAILED; + e->event.failure = GG_FAILURE_CONNECTING; + sess->state = GG_STATE_IDLE; + break; + } + } + sess->state = GG_STATE_CONNECTING_GG; + sess->check = GG_CHECK_WRITE; + } else { + sess->state = GG_STATE_CONNECTING_HTTP; + sess->check = GG_CHECK_WRITE; } - sess->state = GG_STATE_CONNECTING_HTTP; - sess->check = GG_CHECK_WRITE; - break; } - case GG_STATE_CONNECTING_HTTP: + case GG_STATE_CONNECTING_HTTP: { char buf[1024]; int res, res_size = sizeof(res); gg_debug(GG_DEBUG_MISC, "== GG_STATE_CONNECTING_HTTP\n"); - if (sess->async && (getsockopt(sess->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) { - gg_debug(GG_DEBUG_MISC, "-- http connection failed, errno = %d (%s)\n", res, strerror(res)); + if (sess->async + && (getsockopt(sess->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) { + struct in_addr *addr = (struct in_addr *)&sess->server_ip; + gg_debug(GG_DEBUG_MISC, + "-- http connection failed, errno = %d (%s), trying direct connection\n", + res, strerror(res)); - errno = res; - e->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_CONNECTING; - sess->state = GG_STATE_IDLE; + if ((sess->fd = gg_connect(addr, GG_DEFAULT_PORT, sess->async)) == -1) { + gg_debug(GG_DEBUG_MISC, + "-- connection failed, trying https connection\n"); + if ((sess->fd = + gg_connect(addr, GG_HTTPS_PORT, sess->async)) == -1) { + gg_debug(GG_DEBUG_MISC, + "-- connect() failed. errno = %d (%s)\n", errno, + strerror(errno)); + + e->type = GG_EVENT_CONN_FAILED; + e->event.failure = GG_FAILURE_CONNECTING; + sess->state = GG_STATE_IDLE; + break; + } + } + + sess->state = GG_STATE_CONNECTING_GG; + sess->check = GG_CHECK_WRITE; break; } gg_debug(GG_DEBUG_MISC, "-- http connection succeded, sending query\n"); - snprintf(buf, sizeof(buf) - 1, - "GET /appsvc/appmsg.asp?fmnumber=%u HTTP/1.0\r\n" - "Host: " GG_APPMSG_HOST "\r\n" - "User-Agent: Mozilla/4.7 [en] (Win98; I)\r\n" - "Pragma: no-cache\r\n" - "\r\n", sess->uin); + "GET /appsvc/appmsg.asp?fmnumber=%lu HTTP/1.0\r\n" + "Host: " GG_APPMSG_HOST "\r\n" + "User-Agent: " GG_HTTP_USERAGENT "\r\n" + "Pragma: no-cache\r\n" "\r\n", sess->uin); if (write(sess->fd, buf, strlen(buf)) < strlen(buf)) { gg_debug(GG_DEBUG_MISC, "-- sending query failed\n"); + errno = EIO; e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_WRITING; sess->state = GG_STATE_IDLE; @@ -1033,7 +1137,7 @@ break; } - case GG_STATE_WRITING_HTTP: + case GG_STATE_WRITING_HTTP: { char buf[1024], *tmp, *host; int port = GG_DEFAULT_PORT; @@ -1043,26 +1147,27 @@ gg_read_line(sess->fd, buf, sizeof(buf) - 1); gg_chomp(buf); - + gg_debug(GG_DEBUG_TRAFFIC, "-- got http response (%s)\n", buf); - + if (strncmp(buf, "HTTP/1.", 7) || strncmp(buf + 9, "200", 3)) { gg_debug(GG_DEBUG_MISC, "-- but that's not what we've expected\n"); + errno = EINVAL; e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_INVALID; sess->state = GG_STATE_IDLE; break; } - + while (strcmp(buf, "\r\n") && strcmp(buf, "")) gg_read_line(sess->fd, buf, sizeof(buf) - 1); gg_read_line(sess->fd, buf, sizeof(buf) - 1); gg_chomp(buf); - + close(sess->fd); - + gg_debug(GG_DEBUG_TRAFFIC, "-- received http data (%s)\n", buf); tmp = buf; @@ -1085,53 +1190,68 @@ if ((tmp = strchr(host, ':'))) { *tmp = 0; - port = atoi(tmp+1); + port = atoi(tmp + 1); } a.s_addr = inet_addr(host); + sess->server_ip = a.s_addr; if ((sess->fd = gg_connect(&a, port, sess->async)) == -1) { - gg_debug(GG_DEBUG_MISC, "-- connect() failed. errno = %d (%s)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, + "-- connection failed, trying https connection\n"); + if ((sess->fd = gg_connect(&a, GG_HTTPS_PORT, sess->async)) == -1) { + gg_debug(GG_DEBUG_MISC, + "-- connection failed, errno = %d (%s)\n", errno, + strerror(errno)); - e->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_CONNECTING; - sess->state = GG_STATE_IDLE; - break; + e->type = GG_EVENT_CONN_FAILED; + e->event.failure = GG_FAILURE_CONNECTING; + sess->state = GG_STATE_IDLE; + break; + } } sess->state = GG_STATE_CONNECTING_GG; sess->check = GG_CHECK_WRITE; - + break; } - case GG_STATE_CONNECTING_GG: + case GG_STATE_CONNECTING_GG: { int res, res_size = sizeof(res); gg_debug(GG_DEBUG_MISC, "== GG_STATE_CONNECTING_GG\n"); - if (sess->async && (getsockopt(sess->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) { - gg_debug(GG_DEBUG_MISC, "-- connection failed, errno = %d (%s)\n", errno, strerror(errno)); + if (sess->async + && (getsockopt(sess->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) { + struct in_addr *addr = (struct in_addr *)&sess->server_ip; - errno = res; - e->type = GG_EVENT_CONN_FAILED; - e->event.failure = GG_FAILURE_CONNECTING; - sess->state = GG_STATE_IDLE; - break; + gg_debug(GG_DEBUG_MISC, + "-- connection failed, trying https connection\n"); + if ((sess->fd = gg_connect(addr, GG_HTTPS_PORT, sess->async)) == -1) { + gg_debug(GG_DEBUG_MISC, + "-- connection failed, errno = %d (%s)\n", errno, + strerror(errno)); + + e->type = GG_EVENT_CONN_FAILED; + e->event.failure = GG_FAILURE_CONNECTING; + sess->state = GG_STATE_IDLE; + break; + } } gg_debug(GG_DEBUG_MISC, "-- connected\n"); - + sess->state = GG_STATE_WAITING_FOR_KEY; sess->check = GG_CHECK_READ; break; } - case GG_STATE_WAITING_FOR_KEY: + case GG_STATE_WAITING_FOR_KEY: { - struct gg_header *h; + struct gg_header *h; struct gg_welcome *w; struct gg_login l; unsigned int hash; @@ -1140,7 +1260,8 @@ gg_debug(GG_DEBUG_MISC, "== GG_STATE_WAITING_FOR_KEY\n"); if (!(h = gg_recv_packet(sess))) { - gg_debug(GG_DEBUG_MISC, "-- gg_recv_packet() failed. errno = %d (%s)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, "-- gg_recv_packet() failed. errno = %d (%s)\n", + errno, strerror(errno)); e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_READING; @@ -1148,43 +1269,46 @@ close(sess->fd); break; } - + if (h->type != GG_WELCOME) { gg_debug(GG_DEBUG_MISC, "-- invalid packet received\n"); free(h); close(sess->fd); + errno = EINVAL; e->type = GG_EVENT_CONN_FAILED; e->event.failure = GG_FAILURE_INVALID; sess->state = GG_STATE_IDLE; break; } - - w = (void*) h + sizeof(struct gg_header); + + w = (void *)h + sizeof(struct gg_header); w->key = fix32(w->key); for (hash = 1; *password; password++) hash *= (*password) + 1; hash *= w->key; - - gg_debug(GG_DEBUG_DUMP, "%%%% klucz serwera %.4x, hash hasła %.8x\n", w->key, hash); - + + gg_debug(GG_DEBUG_DUMP, "%%%% klucz serwera %.4x, hash hasła %.8x\n", w->key, + hash); + free(h); free(sess->password); sess->password = NULL; - + l.uin = fix32(sess->uin); l.hash = fix32(hash); - l.status = fix32(GG_STATUS_AVAIL); + l.status = fix32(sess->initial_status ? sess->initial_status : GG_STATUS_AVAIL); l.dunno = fix32(0x0b); l.local_ip = 0; l.local_port = 0; - + gg_debug(GG_DEBUG_TRAFFIC, "-- sending GG_LOGIN packet\n"); if (gg_send_packet(sess->fd, GG_LOGIN, &l, sizeof(l), NULL, 0) == -1) { - gg_debug(GG_DEBUG_TRAFFIC, "-- oops, failed. errno = %d (%s)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_TRAFFIC, "-- oops, failed. errno = %d (%s)\n", errno, + strerror(errno)); close(sess->fd); e->type = GG_EVENT_CONN_FAILED; @@ -1192,13 +1316,13 @@ sess->state = GG_STATE_IDLE; break; } - + sess->state = GG_STATE_SENDING_KEY; break; } - case GG_STATE_SENDING_KEY: + case GG_STATE_SENDING_KEY: { struct gg_header *h; @@ -1212,11 +1336,12 @@ close(sess->fd); break; } - + if (h->type == GG_LOGIN_OK) { gg_debug(GG_DEBUG_MISC, "-- login succeded\n"); e->type = GG_EVENT_CONN_SUCCESS; sess->state = GG_STATE_CONNECTED; + free(h); break; } @@ -1227,24 +1352,28 @@ } else { gg_debug(GG_DEBUG_MISC, "-- invalid packet\n"); e->event.failure = GG_FAILURE_INVALID; + errno = EINVAL; } e->type = GG_EVENT_CONN_FAILED; sess->state = GG_STATE_IDLE; close(sess->fd); + free(h); break; } - case GG_STATE_CONNECTED: + case GG_STATE_CONNECTED: { gg_debug(GG_DEBUG_MISC, "== GG_STATE_CONNECTED\n"); if ((res = gg_watch_fd_connected(sess, e)) == -1) { - gg_debug(GG_DEBUG_MISC, "-- watch_fd_connected failed. errno = %d (%s)\n", errno, strerror(errno)); + gg_debug(GG_DEBUG_MISC, + "-- watch_fd_connected failed. errno = %d (%s)\n", errno, + strerror(errno)); - if (errno == EAGAIN) { + if (errno == EAGAIN) { e->type = GG_EVENT_NONE; res = 0; } else @@ -1261,5 +1390,3 @@ return e; } - - diff -r 8f6365332a05 -r 9123abd0db92 src/protocols/gg/libgg.h --- a/src/protocols/gg/libgg.h Mon Nov 26 20:39:54 2001 +0000 +++ b/src/protocols/gg/libgg.h Mon Nov 26 21:22:56 2001 +0000 @@ -1,7 +1,8 @@ -/* $Id: libgg.h 2523 2001-10-15 19:18:19Z warmenhoven $ */ +/* $Id: libgg.h 2805 2001-11-26 21:22:56Z warmenhoven $ */ /* - * (C) Copyright 2001 Wojtek Kaniewski + * (C) Copyright 2001 Wojtek Kaniewski , + * Robert J. Woźny * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License Version 2 as @@ -24,201 +25,201 @@ extern "C" { #endif -#define GG_DEBUG 1 - -#ifndef INADDR_NONE +#if defined(sun) && !defined(INADDR_NONE) #define INADDR_NONE 0xffffffff #endif +#include + /* * typ zmiennej określającej numerek danej osoby. */ -typedef unsigned int uin_t; + typedef unsigned long uin_t; /* * cośtam. */ -struct gg_session { - int state, check; - int fd, pid; - int port; - int seq, async; + struct gg_session { + int state, check; + int fd, pid; + int port; + int seq, async; + int last_pong; - uin_t uin; - char *password; + /* powinno być ,,in_addr'', ale nie chcę inkludować sieci tutaj */ + unsigned long server_ip; - char *recv_buf; - int recv_done, recv_left; -}; + uin_t uin; + char *password; + int initial_status; + + char *recv_buf; + int recv_done, recv_left; + }; /* * różne stany asynchronicznej maszynki. */ -enum { - GG_STATE_IDLE = 0, /* wspólne */ - GG_STATE_RESOLVING, - GG_STATE_CONNECTING_HTTP, + enum { + GG_STATE_IDLE = 0, /* wspólne */ + GG_STATE_RESOLVING, + GG_STATE_CONNECTING_HTTP, - GG_STATE_WRITING_HTTP, /* gg_login */ - GG_STATE_CONNECTING_GG, - GG_STATE_WAITING_FOR_KEY, - GG_STATE_SENDING_KEY, - GG_STATE_CONNECTED, + GG_STATE_WRITING_HTTP, /* gg_login */ + GG_STATE_CONNECTING_GG, + GG_STATE_WAITING_FOR_KEY, + GG_STATE_SENDING_KEY, + GG_STATE_CONNECTED, - GG_STATE_READING_HEADER, /* gg_search */ - GG_STATE_READING_DATA, - GG_STATE_PARSING, - GG_STATE_FINISHED, -}; + GG_STATE_READING_HEADER, /* gg_search */ + GG_STATE_READING_DATA, + GG_STATE_PARSING, + GG_STATE_FINISHED, + }; /* * co proces klienta powinien sprawdzać w deskryptorach? */ -enum { - GG_CHECK_NONE = 0, - GG_CHECK_WRITE = 1, - GG_CHECK_READ = 2, -}; + enum { + GG_CHECK_NONE = 0, + GG_CHECK_WRITE = 1, + GG_CHECK_READ = 2, + }; -struct gg_session *gg_login(uin_t uin, char *password, int async); -void gg_free_session(struct gg_session *sess); -void gg_logoff(struct gg_session *sess); -int gg_change_status(struct gg_session *sess, int status); -int gg_send_message(struct gg_session *sess, int msgclass, uin_t recipient, unsigned char *message); -int gg_ping(struct gg_session *sess); + struct gg_session *gg_login(uin_t uin, char *password, int async); + void gg_free_session(struct gg_session *sess); + void gg_logoff(struct gg_session *sess); + int gg_change_status(struct gg_session *sess, int status); + int gg_send_message(struct gg_session *sess, int msgclass, uin_t recipient, + unsigned char *message); + int gg_ping(struct gg_session *sess); -struct gg_notify_reply { - uin_t uin; /* numerek */ - int status; /* status danej osoby */ - int remote_ip; /* adres ip delikwenta */ - short remote_port; /* port, na którym słucha klient */ - int dunno1; /* == 0x0b */ - short dunno2; /* znowu port? */ -} __attribute__ ((packed)); + struct gg_notify_reply { + uin_t uin; /* numerek */ + unsigned long status; /* status danej osoby */ + unsigned long remote_ip; /* adres ip delikwenta */ + unsigned short remote_port; /* port, na którym słucha klient */ + unsigned long dunno1; /* == 0x0b */ + unsigned short dunno2; /* znowu port? */ + } __attribute__ ((packed)); -struct gg_status { - uin_t uin; /* numerek */ - int status; /* nowy stan */ -} __attribute__ ((packed)); + struct gg_status { + uin_t uin; /* numerek */ + unsigned long status; /* nowy stan */ + } __attribute__ ((packed)); -enum { - GG_EVENT_NONE = 0, - GG_EVENT_MSG, - GG_EVENT_NOTIFY, - GG_EVENT_STATUS, - GG_EVENT_ACK, - GG_EVENT_CONN_FAILED, - GG_EVENT_CONN_SUCCESS, -}; + enum { + GG_EVENT_NONE = 0, + GG_EVENT_MSG, + GG_EVENT_NOTIFY, + GG_EVENT_STATUS, + GG_EVENT_ACK, + GG_EVENT_CONN_FAILED, + GG_EVENT_CONN_SUCCESS, + }; -enum { - GG_FAILURE_RESOLVING = 1, - GG_FAILURE_CONNECTING, - GG_FAILURE_INVALID, - GG_FAILURE_READING, - GG_FAILURE_WRITING, - GG_FAILURE_PASSWORD, -}; + enum { + GG_FAILURE_RESOLVING = 1, + GG_FAILURE_CONNECTING, + GG_FAILURE_INVALID, + GG_FAILURE_READING, + GG_FAILURE_WRITING, + GG_FAILURE_PASSWORD, + }; -struct gg_event { - int type; - union { - struct { - uin_t sender; - int msgclass; - unsigned char *message; - } msg; - struct gg_notify_reply *notify; - struct gg_status status; - struct { - uin_t recipient; - int status; - int seq; - } ack; - int failure; - } event; -}; + struct gg_event { + int type; + union { + struct { + uin_t sender; + int msgclass; + time_t time; + unsigned char *message; + } msg; + struct gg_notify_reply *notify; + struct gg_status status; + struct { + uin_t recipient; + int status; + int seq; + } ack; + int failure; + } event; + }; -struct gg_event *gg_watch_fd(struct gg_session *sess); -void gg_free_event(struct gg_event *e); + struct gg_event *gg_watch_fd(struct gg_session *sess); + void gg_free_event(struct gg_event *e); -int gg_notify(struct gg_session *sess, uin_t *userlist, int count); -int gg_add_notify(struct gg_session *sess, uin_t uin); -int gg_remove_notify(struct gg_session *sess, uin_t uin); + int gg_notify(struct gg_session *sess, uin_t * userlist, int count); + int gg_add_notify(struct gg_session *sess, uin_t uin); + int gg_remove_notify(struct gg_session *sess, uin_t uin); /* * jakieśtam bzdurki dotyczące szukania userów. */ -struct gg_search_result { - uin_t uin; - char *first_name; - char *last_name; - char *nickname; - int born; - int gender; - char *city; - int active; -}; + struct gg_search_result { + uin_t uin; + char *first_name; + char *last_name; + char *nickname; + int born; + int gender; + char *city; + int active; + }; -struct gg_search_request { - /* czy ma szukać tylko aktywnych? */ - int active; - /* mode 0 */ - char *nickname, *first_name, *last_name, *city; - int gender, min_birth, max_birth; - /* mode 1 */ - char *email; - /* mode 2 */ - char *phone; - /* mode 3 */ - uin_t uin; -}; + struct gg_search_request { + /* czy ma szukać tylko aktywnych? */ + int active; + /* mode 0 */ + char *nickname, *first_name, *last_name, *city; + int gender, min_birth, max_birth; + /* mode 1 */ + char *email; + /* mode 2 */ + char *phone; + /* mode 3 */ + uin_t uin; + }; -struct gg_search { - struct gg_search_request request; + struct gg_search { + struct gg_search_request request; - /* bzdurki */ - int mode, fd, async, state, check, error, pid; - char *header_buf, *data_buf; - int header_size, data_size; + /* bzdurki */ + int mode, fd, async, state, check, error, pid; + char *header_buf, *data_buf; + int header_size, data_size; - /* wyniki */ - int count; - struct gg_search_result *results; -}; + /* wyniki */ + int count; + struct gg_search_result *results; + }; #define GG_GENDER_NONE 0 #define GG_GENDER_FEMALE 1 #define GG_GENDER_MALE 2 -struct gg_search *gg_search(struct gg_search_request *r, int async); -int gg_search_watch_fd(struct gg_search *f); -void gg_free_search(struct gg_search *f); -void gg_search_cancel(struct gg_search *f); + struct gg_search *gg_search(struct gg_search_request *r, int async); + int gg_search_watch_fd(struct gg_search *f); + void gg_free_search(struct gg_search *f); + void gg_search_cancel(struct gg_search *f); /* - * jeśli chcemy sobie podebugować, wystarczy zdefiniować GG_DEBUG. + * jeśli chcemy sobie podebugować, wystarczy ustawić `gg_debug_level'. + * niestety w miarę przybywania wpisów `gg_debug(...)' nie chciało mi + * się ustawiać odpowiednich leveli, więc większość szła do _MISC. */ -extern int gg_debug_level; - -#ifdef GG_DEBUG + extern int gg_debug_level; -# define GG_DEBUG_NET 1 -# define GG_DEBUG_TRAFFIC 2 -# define GG_DEBUG_DUMP 4 -# define GG_DEBUG_FUNCTION 8 -# define GG_DEBUG_MISC 16 +#define GG_DEBUG_NET 1 +#define GG_DEBUG_TRAFFIC 2 +#define GG_DEBUG_DUMP 4 +#define GG_DEBUG_FUNCTION 8 +#define GG_DEBUG_MISC 16 - void gg_debug_real(int level, char *format, ...); -# define gg_debug(x, y...) gg_debug_real(x, y) - -#else - -# define gg_debug(x, y...) while(0) { }; - -#endif /* GG_DEBUG */ + void gg_debug(int level, char *format, ...); /* * ------------------------------------------------------------------------- @@ -229,37 +230,41 @@ * ------------------------------------------------------------------------- */ -int gg_resolve(int *fd, int *pid, char *hostname); -int gg_connect(void *addr, int port, int async); -char *gg_alloc_sprintf(char *format, ...); + int gg_resolve(int *fd, int *pid, char *hostname); + int gg_connect(void *addr, int port, int async); + char *gg_alloc_sprintf(char *format, ...); + char *gg_get_line(char **ptr); + char *gg_urlencode(char *str); #define GG_APPMSG_HOST "appmsg.gadu-gadu.pl" #define GG_APPMSG_PORT 80 #define GG_PUBDIR_HOST "pubdir.gadu-gadu.pl" #define GG_PUBDIR_PORT 80 #define GG_DEFAULT_PORT 8074 +#define GG_HTTPS_PORT 443 +#define GG_HTTP_USERAGENT "Mozilla/4.7 [en] (Win98; I)" -struct gg_header { - int type; /* typ pakietu */ - int length; /* długość reszty pakietu */ -} __attribute__ ((packed)); + struct gg_header { + unsigned long type; /* typ pakietu */ + unsigned long length; /* długość reszty pakietu */ + } __attribute__ ((packed)); #define GG_WELCOME 0x0001 -struct gg_welcome { - int key; /* klucz szyfrowania hasła */ -} __attribute__ ((packed)); - + struct gg_welcome { + unsigned long key; /* klucz szyfrowania hasła */ + } __attribute__ ((packed)); + #define GG_LOGIN 0x000c -struct gg_login { - uin_t uin; /* twój numerek */ - int hash; /* hash hasła */ - int status; /* status na dzień dobry */ - int dunno; /* == 0x0b */ - int local_ip; /* mój adres ip */ - short local_port; /* port, na którym słucham */ -} __attribute__ ((packed)); + struct gg_login { + uin_t uin; /* twój numerek */ + unsigned long hash; /* hash hasła */ + unsigned long status; /* status na dzień dobry */ + unsigned long dunno; /* == 0x0b */ + unsigned long local_ip; /* mój adres ip */ + unsigned short local_port; /* port, na którym słucham */ + } __attribute__ ((packed)); #define GG_LOGIN_OK 0x0003 @@ -268,76 +273,77 @@ #define GG_NEW_STATUS 0x0002 #define GG_STATUS_NOT_AVAIL 0x0001 /* rozłączony */ -#define GG_STATUS_AVAIL 0x0002 /* dostępny */ -#define GG_STATUS_BUSY 0x0003 /* zajęty */ +#define GG_STATUS_AVAIL 0x0002 /* dostępny */ +#define GG_STATUS_BUSY 0x0003 /* zajęty */ #define GG_STATUS_INVISIBLE 0x0014 /* niewidoczny (GG 4.6) */ #define GG_STATUS_FRIENDS_MASK 0x8000 /* tylko dla znajomych (GG 4.6) */ -struct gg_new_status { - int status; /* na jaki zmienić? */ -} __attribute__ ((packed)); + struct gg_new_status { + unsigned long status; /* na jaki zmienić? */ + } __attribute__ ((packed)); #define GG_NOTIFY 0x0010 - -struct gg_notify { - uin_t uin; /* numerek danej osoby */ - char dunno1; /* == 3 */ -} __attribute__ ((packed)); - + + struct gg_notify { + uin_t uin; /* numerek danej osoby */ + char dunno1; /* == 3 */ + } __attribute__ ((packed)); + #define GG_NOTIFY_REPLY 0x000c /* tak, to samo co GG_LOGIN */ - + /* struct gg_notify_reply zadeklarowane wyżej */ #define GG_ADD_NOTIFY 0x000d #define GG_REMOVE_NOTIFY 0x000e - -struct gg_add_remove { - uin_t uin; /* numerek */ - char dunno1; /* == 3 */ -} __attribute__ ((packed)); + + struct gg_add_remove { + uin_t uin; /* numerek */ + char dunno1; /* == 3 */ + } __attribute__ ((packed)); #define GG_STATUS 0x0002 /* struct gg_status zadeklarowane wcześniej */ - + #define GG_SEND_MSG 0x000b +#define GG_CLASS_QUEUED 0x0001 +#define GG_CLASS_OFFLINE GG_CLASS_QUEUED #define GG_CLASS_MSG 0x0004 #define GG_CLASS_CHAT 0x0008 -struct gg_send_msg { - int recipient; - int seq; - int msgclass; -} __attribute__ ((packed)); + struct gg_send_msg { + unsigned long recipient; + unsigned long seq; + unsigned long msgclass; + } __attribute__ ((packed)); #define GG_SEND_MSG_ACK 0x0005 #define GG_ACK_DELIVERED 0x0002 #define GG_ACK_QUEUED 0x0003 - -struct gg_send_msg_ack { - int status; - int recipient; - int seq; -} __attribute__ ((packed)); + + struct gg_send_msg_ack { + unsigned long status; + unsigned long recipient; + unsigned long seq; + } __attribute__ ((packed)); #define GG_RECV_MSG 0x000a - -struct gg_recv_msg { - int sender; - int dunno1; - int dunno2; - int msgclass; -} __attribute__ ((packed)); + + struct gg_recv_msg { + unsigned long sender; + unsigned long seq; + unsigned long time; + unsigned long msgclass; + } __attribute__ ((packed)); #define GG_PING 0x0008 - + #define GG_PONG 0x0007 #ifdef __cplusplus } #endif - #endif