# HG changeset patch # User Eric Warmenhoven # Date 1007545736 0 # Node ID 4b3f17ca66bf889e04d52e509fedd6d431a85f6d # Parent 0c10058610a0e3b61dc72d0178556e10c03c7341 [gaim-migrate @ 2859] so here it comes - some bugs fixed, new ones introduced: - password changing (was in part 1) - update to latest libgg (fixes password change on alpha) - auto away on idle (remembers GG_STATE_FRIENDS_MASK) - handle_errcode() can now use hide_login_progress() - remove encode_postdata() and use gg_urlencode() from libgg + encode only fields (not whole url) - fixed status related ugly bug in GG_EVENT_NOTIFY (!!!) - remove linefeed from messages Thanks, Arkadiusz Miskiewicz committer: Tailor Script diff -r 0c10058610a0 -r 4b3f17ca66bf src/protocols/gg/.cvsignore --- a/src/protocols/gg/.cvsignore Tue Dec 04 19:51:27 2001 +0000 +++ b/src/protocols/gg/.cvsignore Wed Dec 05 09:48:56 2001 +0000 @@ -6,3 +6,4 @@ libgg.la libgg.lo iconv_string.lo +common.lo diff -r 0c10058610a0 -r 4b3f17ca66bf src/protocols/gg/Makefile.am --- a/src/protocols/gg/Makefile.am Tue Dec 04 19:51:27 2001 +0000 +++ b/src/protocols/gg/Makefile.am Wed Dec 05 09:48:56 2001 +0000 @@ -13,6 +13,7 @@ libgg_a_SOURCES = libgg.c \ libgg.h \ + common.c \ iconv_string.c \ iconv_string.h \ gg.c @@ -25,6 +26,7 @@ libgg_la_SOURCES = libgg.c \ libgg.h \ + common.c \ iconv_string.c \ iconv_string.h \ gg.c diff -r 0c10058610a0 -r 4b3f17ca66bf src/protocols/gg/common.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/protocols/gg/common.c Wed Dec 05 09:48:56 2001 +0000 @@ -0,0 +1,330 @@ +/* $Id: common.c 2859 2001-12-05 09:48:56Z warmenhoven $ */ + +/* + * (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 + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef _AIX +# include +#endif +#include +#include +#include +#ifdef sun + #include +#endif +#include "libgg.h" +#include "config.h" + +/* + * gg_debug() + * + * wyrzuca komunikat o danym poziomie, o ile użytkownik sobie tego życzy. + * + * - level - poziom wiadomości, + * - format... - treść wiadomości (printf-alike.) + * + * niczego nie zwraca. + */ +void gg_debug(int level, char *format, ...) +{ + va_list ap; + + if ((gg_debug_level & level)) { + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + } +} + +/* + * gg_alloc_sprintf() + * + * robi dokładnie to samo, co sprintf(), tyle że alokuje sobie wcześniej + * 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() + * + * zwraca zaalokowany buforek, który wypadałoby później zwolnić, lub NULL + * jeśli nie udało się wykonać zadania. + */ +char *gg_alloc_sprintf(char *format, ...) +{ + va_list ap; + char *buf = NULL, *tmp; + int size = 0, res; + + va_start(ap, format); + + 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); + + va_end(ap); + + return buf; +} + +/* + * gg_get_line() + * + * 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_connect() + * + * łączy się z serwerem. pierwszy argument jest typu (void *), żeby nie + * musieć niczego inkludować w libgg.h i nie psuć jakiś głupich zależności + * na dziwnych systemach. + * + * - addr - adres serwera (struct in_addr *), + * - port - port serwera, + * - async - ma być asynchroniczne połączenie? + * + * zwraca połączonego socketa lub -1 w przypadku błędu. zobacz errno. + */ +int gg_connect(void *addr, int port, int async) +{ + int sock, one = 1; + struct sockaddr_in sin; + 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) { + if (ioctl(sock, FIONBIO, &one) == -1) { + gg_debug(GG_DEBUG_MISC, "-- ioctl() failed. errno = %d (%s)\n", errno, strerror(errno)); + return -1; + } + } + + 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, "-- connect() failed. errno = %d (%s)\n", errno, strerror(errno)); + return -1; + } + gg_debug(GG_DEBUG_MISC, "-- connect() in progress\n"); + } + + return sock; +} + +/* + * gg_read_line() + * + * czyta jedną linię tekstu z socketa. + * + * - sock - socket, + * - buf - wskaźnik bufora, + * - length - długość bufora. + * + * olewa błędy. jeśli na jakiś trafi, potraktuje go jako koniec linii. + */ +void gg_read_line(int sock, char *buf, int length) +{ + 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) { + *buf = 0; + return; + } + } while (ret == -1 && errno == EINTR); + + if (*buf == '\n') { + buf++; + break; + } + } + + *buf = 0; + return; +} + +/* + * gg_chomp() + * + * ucina "\r\n" lub "\n" z końca linii. + * + * - line - ofiara operacji plastycznej. + * + * niczego nie zwraca. + */ +void gg_chomp(char *line) +{ + if (!line || strlen(line) < 1) + return; + + if (line[strlen(line) - 1] == '\n') + line[strlen(line) - 1] = 0; + if (line[strlen(line) - 1] == '\r') + line[strlen(line) - 1] = 0; +} + + +/* + * gg_urlencode() // funkcja wewnętrzna + * + * zamienia podany tekst na ciąg znaków do formularza http. przydaje się + * przy szukaniu userów z dziwnymi znaczkami. + * + * - str - ciąg znaków do poprawki. + * + * zwraca zaalokowany bufor, który wypadałoby kiedyś zwolnić albo NULL + * w przypadku błędu. + */ +char *gg_urlencode(char *str) +{ + char *p, *q, *buf, hex[] = "0123456789abcdef"; + int size = 0; + + if (!str) + str = strdup(""); + + for (p = str; *p; p++, size++) { + if (!((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9'))) + size += 2; + } + + if (!(buf = malloc(size + 1))) + return NULL; + + for (p = str, q = buf; *p; p++, q++) { + if ((*p >= 'a' && *p <= 'z') || (*p >= 'A' && *p <= 'Z') || (*p >= '0' && *p <= '9')) + *q = *p; + else { + *q++ = '%'; + *q++ = hex[*p >> 4 & 15]; + *q = hex[*p & 15]; + } + } + + *q = 0; + + return buf; +} + +/* + * gg_http_hash() + * + * funkcja, która liczy hash dla adresu e-mail i hasła. + * + * - email - adres email, + * - password - hasło. + * + * zwraca hash wykorzystywany przy rejestracji i wszelkich + * manipulacjach własnego wpisu w katalogu publicznym. + */ + +int gg_http_hash(unsigned char *email, unsigned char *password) +{ + unsigned int a, c; + int b, i; + b = (-1); + + i = 0; + while ((c = (int) email[i++]) != 0) { + a = (c ^ b) + (c << 8); + b = (a >> 24) | (a << 8); + } + + i = 0; + while ((c = (int) password[i++]) != 0) { + a = (c ^ b) + (c << 8); + b = (a >> 24) | (a << 8); + } + + return (b < 0 ? -b : b); +} + +/* + * Local variables: + * c-indentation-style: k&r + * c-basic-offset: 8 + * indent-tabs-mode: notnil + * End: + * + * vim: shiftwidth=8: + */ diff -r 0c10058610a0 -r 4b3f17ca66bf src/protocols/gg/gg.c --- a/src/protocols/gg/gg.c Tue Dec 04 19:51:27 2001 +0000 +++ b/src/protocols/gg/gg.c Wed Dec 05 09:48:56 2001 +0000 @@ -1,6 +1,6 @@ /* * gaim - Gadu-Gadu Protocol Plugin - * $Id: gg.c 2848 2001-12-02 20:42:30Z warmenhoven $ + * $Id: gg.c 2859 2001-12-05 09:48:56Z warmenhoven $ * * Copyright (C) 2001 Arkadiusz Miśkiewicz * @@ -65,6 +65,7 @@ #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_REGISTER_DATA_FORM "/appsvc/fmregister.asp" #define AGG_PUBDIR_MAX_ENTRIES 200 #define AGG_STATUS_AVAIL _("Available") @@ -80,11 +81,13 @@ #define AGG_HTTP_USERLIST_IMPORT 2 #define AGG_HTTP_USERLIST_EXPORT 3 #define AGG_HTTP_USERLIST_DELETE 4 +#define AGG_HTTP_PASSWORD_CHANGE 5 #define UC_NORMAL 2 struct agg_data { struct gg_session *sess; + int own_status; }; struct agg_http { @@ -170,7 +173,7 @@ return gg_localenc; } -static char *handle_errcode(int errcode, gboolean show) +static char *handle_errcode(struct gaim_connection *gc, int errcode) { static char msg[AGG_BUF_LEN]; @@ -198,73 +201,51 @@ break; } - if (show) - do_error_dialog(msg, _("Gadu-Gadu Error")); + hide_login_progress(gc, msg); return msg; } -static gchar *encode_postdata(const gchar *data) -{ - gchar *p = NULL; - int i, j = 0; - for (i = 0; i < strlen(data); i++) { - /* locale insensitive, doesn't reflect RFC (1738 section 2.2, 1866 section 8.2.1) */ - if ((data[i] >= 'a' && data[i] <= 'z') - || (data[i] >= 'A' && data[i] <= 'Z') - || (data[i] >= '0' && data[i] <= '9') - || data[i] == '=' || data[i] == '&') { - p = g_realloc(p, j + 1); - p[j] = data[i]; - j++; - } else { - p = g_realloc(p, j + 4); /* remember, sprintf appends a '\0' */ - sprintf(p + j, "%%%02x", (unsigned char)data[i]); - j += 3; - } - } - p = g_realloc(p, j + 1); - p[j] = '\0'; - - if (p && strlen(p)) - return p; - else - return g_strdup(data); -} - static void agg_set_away(struct gaim_connection *gc, char *state, char *msg) { struct agg_data *gd = (struct agg_data *)gc->proto_data; + int status = gd->own_status; if (gc->away) gc->away = NULL; if (!g_strcasecmp(state, AGG_STATUS_AVAIL)) - gg_change_status(gd->sess, GG_STATUS_AVAIL); + status = GG_STATUS_AVAIL; else if (!g_strcasecmp(state, AGG_STATUS_AVAIL_FRIENDS)) - gg_change_status(gd->sess, GG_STATUS_AVAIL | GG_STATUS_FRIENDS_MASK); + status = GG_STATUS_AVAIL | GG_STATUS_FRIENDS_MASK; else if (!g_strcasecmp(state, AGG_STATUS_BUSY)) { - gg_change_status(gd->sess, GG_STATUS_BUSY); + status = GG_STATUS_BUSY; gc->away = ""; } else if (!g_strcasecmp(state, AGG_STATUS_BUSY_FRIENDS)) { - gg_change_status(gd->sess, GG_STATUS_BUSY | GG_STATUS_FRIENDS_MASK); + status = GG_STATUS_BUSY | GG_STATUS_FRIENDS_MASK; gc->away = ""; } else if (!g_strcasecmp(state, AGG_STATUS_INVISIBLE)) { - gg_change_status(gd->sess, GG_STATUS_INVISIBLE); + status = GG_STATUS_INVISIBLE; gc->away = ""; } else if (!g_strcasecmp(state, AGG_STATUS_INVISIBLE_FRIENDS)) { - gg_change_status(gd->sess, GG_STATUS_INVISIBLE | GG_STATUS_FRIENDS_MASK); + status = GG_STATUS_INVISIBLE | GG_STATUS_FRIENDS_MASK; gc->away = ""; } else if (!g_strcasecmp(state, AGG_STATUS_NOT_AVAIL)) { - gg_change_status(gd->sess, GG_STATUS_NOT_AVAIL); + status = GG_STATUS_NOT_AVAIL; gc->away = ""; } else if (!g_strcasecmp(state, GAIM_AWAY_CUSTOM)) { if (msg) { - gg_change_status(gd->sess, GG_STATUS_BUSY); + status = GG_STATUS_BUSY; gc->away = ""; } else - gg_change_status(gd->sess, GG_STATUS_AVAIL); + status = GG_STATUS_AVAIL; + + if (gd->own_status & GG_STATUS_FRIENDS_MASK) + status |= GG_STATUS_FRIENDS_MASK; } + + gd->own_status = status; + gg_change_status(gd->sess, status); } static gchar *get_away_text(int uc) @@ -359,6 +340,7 @@ if (!(e = gg_watch_fd(gd->sess))) { debug_printf("main_callback: gg_watch_fd failed - CRITICAL!\n"); + hide_login_progress(gc, _("Unable to read socket")); signoff(gc); return; } @@ -373,7 +355,7 @@ case GG_EVENT_CONN_FAILED: if (gc->inpa) gaim_input_remove(gc->inpa); - handle_errcode(e->event.failure, TRUE); + handle_errcode(gc, e->event.failure); signoff(gc); break; case GG_EVENT_MSG: @@ -385,6 +367,7 @@ if (!allowed_uin(gc, user)) break; imsg = charset_convert(e->event.msg.message, "CP1250", find_local_charset()); + strip_linefeed(imsg); /* 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); @@ -404,8 +387,7 @@ case GG_STATUS_AVAIL: case GG_STATUS_BUSY: case GG_STATUS_INVISIBLE: - case GG_STATUS_FRIENDS_MASK: - status = UC_NORMAL | (e->event.status.status << 5); + status = UC_NORMAL | (n->status << 5); break; default: status = UC_NORMAL; @@ -431,7 +413,6 @@ case GG_STATUS_AVAIL: case GG_STATUS_BUSY: case GG_STATUS_INVISIBLE: - case GG_STATUS_FRIENDS_MASK: status = UC_NORMAL | (e->event.status.status << 5); break; default: @@ -440,8 +421,8 @@ } 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); + serv_got_update(gc, user, (status == UC_UNAVAILABLE) ? 0 : 1, 0, 0, 0, + status, 0); } break; case GG_EVENT_ACK: @@ -479,18 +460,17 @@ gc->inpa = gaim_input_add(gd->sess->fd, GAIM_INPUT_READ, login_callback, gc); switch (gd->sess->state) { - case GG_STATE_CONNECTING_HTTP: - case GG_STATE_WRITING_HTTP: - set_login_progress(gc, 2, _("Handshake")); + case GG_STATE_READING_DATA: + set_login_progress(gc, 2, _("Reading data")); break; case GG_STATE_CONNECTING_GG: - set_login_progress(gc, 3, _("Connecting to GG server")); + set_login_progress(gc, 3, _("Balancer handshake")); break; - case GG_STATE_WAITING_FOR_KEY: - set_login_progress(gc, 4, _("Waiting for server key")); + case GG_STATE_READING_KEY: + set_login_progress(gc, 4, _("Reading server key")); break; - case GG_STATE_SENDING_KEY: - set_login_progress(gc, 5, _("Sending key")); + case GG_STATE_READING_REPLY: + set_login_progress(gc, 5, _("Exchanging key hash")); break; default: break; @@ -498,6 +478,7 @@ if (!(e = gg_watch_fd(gd->sess))) { debug_printf("login_callback: gg_watch_fd failed - CRITICAL!\n"); + hide_login_progress(gc, _("Critical error in GG library\n")); signoff(gc); return; } @@ -522,7 +503,7 @@ case GG_EVENT_CONN_FAILED: gaim_input_remove(gc->inpa); gc->inpa = 0; - handle_errcode(e->event.failure, TRUE); + handle_errcode(gc, e->event.failure); signoff(gc); break; default: @@ -536,6 +517,7 @@ { struct agg_data *gd = (struct agg_data *)gc->proto_data; if (gg_ping(gd->sess) < 0) { + hide_login_progress(gc, _("Unable to ping server")); signoff(gc); return; } @@ -578,7 +560,7 @@ gd->sess->uin = (uin_t) strtol(user->username, (char **)NULL, 10); gd->sess->password = g_strdup(user->password); - gd->sess->state = GG_STATE_CONNECTING_HTTP; + gd->sess->state = GG_STATE_CONNECTING; gd->sess->check = GG_CHECK_WRITE; gd->sess->async = 1; gd->sess->fd = proxy_connect(GG_APPMSG_HOST, GG_APPMSG_PORT, login_callback, gc); @@ -599,6 +581,7 @@ gg_logoff(gd->sess); gg_free_session(gd->sess); g_free(gc->proto_data); + gd->own_status = GG_STATUS_NOT_AVAIL; } static int agg_send_im(struct gaim_connection *gc, char *who, char *msg, int flags) @@ -614,7 +597,8 @@ if (strlen(msg) > 0) { imsg = charset_convert(msg, find_local_charset(), "CP1250"); - if (gg_send_message(gd->sess, (flags & IM_FLAG_CHECKBOX) ? GG_CLASS_MSG : GG_CLASS_CHAT, + if (gg_send_message(gd->sess, (flags & IM_FLAG_CHECKBOX) + ? GG_CLASS_MSG : GG_CLASS_CHAT, strtol(who, (char **)NULL, 10), imsg) < 0) return -1; g_free(imsg); @@ -848,6 +832,18 @@ do_error_dialog(_("Couldn't delete Buddies List from Server"), _("Gadu-Gadu Error")); } +static void password_change_server_results(struct gaim_connection *gc, gchar *webdata) +{ + if (strstr(webdata, "reg_success:")) { + do_error_dialog(_("Password changed sucessfully"), + _("Gadu-Gadu Information")); + return; + } + + debug_printf("delete_buddies_server_results: webdata [%s]\n", webdata); + do_error_dialog(_("Password couldn't be changed"), _("Gadu-Gadu Error")); +} + static void http_results(gpointer data, gint source, GaimInputCondition cond) { struct agg_http *hdata = data; @@ -904,6 +900,9 @@ case AGG_HTTP_USERLIST_DELETE: delete_buddies_server_results(gc, webdata); break; + case AGG_HTTP_PASSWORD_CHANGE: + password_change_server_results(gc, webdata); + break; case AGG_HTTP_NONE: default: debug_printf("http_results: unsupported type %d\n", hdata->type); @@ -920,7 +919,6 @@ struct gaim_connection *gc = hdata->gc; gchar *request = hdata->request; gchar *buf; - char *ptr; debug_printf("http_req_callback: begin\n"); @@ -938,10 +936,7 @@ return; } - ptr = encode_postdata(request); - g_free(request); - - debug_printf("http_req_callback: http request [%s]\n", ptr); + debug_printf("http_req_callback: http request [%s]\n", request); buf = g_strdup_printf("POST %s HTTP/1.0\r\n" "Host: %s\r\n" @@ -949,9 +944,9 @@ "User-Agent: " GG_HTTP_USERAGENT "\r\n" "Content-Length: %d\r\n" "Pragma: no-cache\r\n" "\r\n" "%s\r\n", - hdata->form, hdata->host, strlen(ptr), ptr); + hdata->form, hdata->host, strlen(request), request); - g_free(ptr); + g_free(request); if (write(source, buf, strlen(buf)) < strlen(buf)) { g_free(buf); @@ -970,12 +965,17 @@ { struct agg_http *hi = g_new0(struct agg_http, 1); static char msg[AGG_BUF_LEN]; + gchar *u = gg_urlencode(gc->username); + gchar *p = gg_urlencode(gc->password); 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); + hi->request = g_strdup_printf("FmNum=%s&Pass=%s", u, p); + + g_free(u); + g_free(p); 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)"), @@ -992,13 +992,19 @@ struct agg_http *he = g_new0(struct agg_http, 1); static char msg[AGG_BUF_LEN]; gchar *ptr; + gchar *u = gg_urlencode(gc->username); + gchar *p = gg_urlencode(gc->password); + 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); + he->request = g_strdup_printf("FmNum=%s&Pass=%s&Contacts=", u, p); + + g_free(u); + g_free(p); while (gr) { struct group *g = gr->data; @@ -1007,17 +1013,24 @@ struct buddy *b = m->data; gchar *newdata; /* GG Number */ - gchar *name = b->name; + gchar *name = gg_urlencode(b->name); /* GG Pseudo */ - gchar *show = strlen(b->show) ? b->show : b->name; + gchar *show = gg_urlencode(strlen(b->show) ? b->show : b->name); + /* Group Name */ + gchar *gname = gg_urlencode(g->name); ptr = he->request; newdata = g_strdup_printf("%s;%s;%s;%s;%s;%s;%s\r\n", - show, show, show, show, "", g->name, name); + show, show, show, show, "", gname, name); he->request = g_strconcat(ptr, newdata, NULL); + g_free(newdata); g_free(ptr); + g_free(gname); + g_free(show); + g_free(name); + m = g_slist_next(m); } gr = g_slist_next(gr); @@ -1037,12 +1050,14 @@ { struct agg_http *he = g_new0(struct agg_http, 1); static char msg[AGG_BUF_LEN]; + gchar *u = gg_urlencode(gc->username); + gchar *p = gg_urlencode(gc->password); he->gc = gc; he->type = AGG_HTTP_USERLIST_DELETE; he->form = AGG_PUBDIR_USERLIST_EXPORT_FORM; he->host = GG_PUBDIR_HOST; - he->request = g_strdup_printf("FmNum=%s&Pass=%s&Delete=1", gc->username, gc->password); + he->request = g_strdup_printf("FmNum=%s&Pass=%s&Delete=1", u, p); if (proxy_connect(GG_PUBDIR_HOST, GG_PUBDIR_PORT, http_req_callback, he) < 0) { g_snprintf(msg, sizeof(msg), _("Deletion of Buddies List from Server failed (%s)"), @@ -1055,7 +1070,8 @@ } 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) + char *last, char *maiden, char *city, char *state, + char *country, char *email) { struct agg_http *srch = g_new0(struct agg_http, 1); static char msg[AGG_BUF_LEN]; @@ -1066,25 +1082,36 @@ srch->host = GG_PUBDIR_HOST; if (email && strlen(email)) { - srch->request = g_strdup_printf("Mode=1&Email=%s", email); + gchar *eemail = gg_urlencode(email); + srch->request = g_strdup_printf("Mode=1&Email=%s", eemail); + g_free(eemail); } 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->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); + gchar *enew_first = gg_urlencode(new_first); + gchar *enew_last = gg_urlencode(new_last); + gchar *enew_city = gg_urlencode(new_city); g_free(new_first); g_free(new_last); g_free(new_city); + + /* For active only add &ActiveOnly= */ + srch->request = g_strdup_printf("Mode=0&FirstName=%s&LastName=%s&Gender=%d" + "&NickName=%s&City=%s&MinBirth=%d&MaxBirth=%d", + enew_first, enew_last, AGG_GENDER_NONE, + "", enew_city, 0, 0); + + g_free(enew_first); + g_free(enew_last); + g_free(enew_city); } 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); + g_snprintf(msg, sizeof(msg), _("Connect to search service failed (%s)"), + GG_PUBDIR_HOST); do_error_dialog(msg, _("Gadu-Gadu Error")); g_free(srch->request); g_free(srch); @@ -1092,10 +1119,45 @@ } } +static void agg_change_passwd(struct gaim_connection *gc, char *old, char *new) +{ + struct agg_http *hpass = g_new0(struct agg_http, 1); + static char msg[AGG_BUF_LEN]; + gchar *u = gg_urlencode(gc->username); + gchar *p = gg_urlencode(gc->password); + gchar *enew = gg_urlencode(new); + gchar *eold = gg_urlencode(old); + + hpass->gc = gc; + hpass->type = AGG_HTTP_PASSWORD_CHANGE; + hpass->form = AGG_REGISTER_DATA_FORM; + hpass->host = GG_REGISTER_HOST; + + /* We are using old password as place for email - it's ugly */ + hpass->request = g_strdup_printf("fmnumber=%s&fmpwd=%s&pwd=%s&email=%s&code=%u", + u, p, enew, eold, gg_http_hash(old, new)); + + g_free(u); + g_free(p); + g_free(enew); + g_free(eold); + + if (proxy_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, http_req_callback, hpass) < 0) { + g_snprintf(msg, sizeof(msg), _("Changing Password failed (%s)"), + GG_REGISTER_HOST); + do_error_dialog(msg, _("Gadu-Gadu Error")); + g_free(hpass->request); + g_free(hpass); + return; + } +} + static void agg_do_action(struct gaim_connection *gc, char *action) { if (!strcmp(action, _("Directory Search"))) { show_find_info(gc); + } else if (!strcmp(action, _("Change Password"))) { + show_change_passwd(gc); } else if (!strcmp(action, _("Import Buddies List from Server"))) { import_buddies_server(gc); } else if (!strcmp(action, _("Export Buddies List to Server"))) { @@ -1110,6 +1172,9 @@ GList *m = NULL; m = g_list_append(m, _("Directory Search")); + m = g_list_append(m, NULL); + m = g_list_append(m, _("Change Password")); + m = g_list_append(m, NULL); m = g_list_append(m, _("Import Buddies List from Server")); m = g_list_append(m, _("Export Buddies List to Server")); m = g_list_append(m, _("Delete Buddies List from Server")); @@ -1130,17 +1195,21 @@ /* If it's invalid uin then maybe it's nickname? */ if (invalid_uin(who)) { gchar *new_who = charset_convert(who, find_local_charset(), "CP1250"); + gchar *enew_who = gg_urlencode(new_who); + + g_free(new_who); 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); + "", "", AGG_GENDER_NONE, enew_who, "", 0, 0); - g_free(new_who); + g_free(enew_who); } else srch->request = g_strdup_printf("Mode=3&UserId=%s", who); 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); + g_snprintf(msg, sizeof(msg), _("Connect to search service failed (%s)"), + GG_PUBDIR_HOST); do_error_dialog(msg, _("Gadu-Gadu Error")); g_free(srch->request); g_free(srch); @@ -1199,7 +1268,7 @@ ret->get_dir = agg_get_info; ret->dir_search = agg_dir_search; ret->set_idle = NULL; - ret->change_passwd = NULL; + ret->change_passwd = agg_change_passwd; ret->add_buddy = agg_add_buddy; ret->add_buddies = agg_add_buddies; ret->remove_buddy = agg_rem_buddy; @@ -1245,3 +1314,13 @@ } #endif + +/* + * Local variables: + * c-indentation-style: k&r + * c-basic-offset: 8 + * indent-tabs-mode: notnil + * End: + * + * vim: shiftwidth=8: + */ diff -r 0c10058610a0 -r 4b3f17ca66bf src/protocols/gg/libgg.c --- a/src/protocols/gg/libgg.c Tue Dec 04 19:51:27 2001 +0000 +++ b/src/protocols/gg/libgg.c Wed Dec 05 09:48:56 2001 +0000 @@ -1,8 +1,8 @@ -/* $Id: libgg.c 2805 2001-11-26 21:22:56Z warmenhoven $ */ +/* $Id: libgg.c 2859 2001-12-05 09:48:56Z warmenhoven $ */ /* * (C) Copyright 2001 Wojtek Kaniewski , - * Robert J. Woźny + * 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 @@ -37,7 +37,7 @@ #include #include #ifdef sun -#include + #include #endif #include #if G_BYTE_ORDER == G_BIG_ENDIAN @@ -47,37 +47,19 @@ #include "config.h" int gg_debug_level = 0; +int gg_http_use_proxy = 0; +int gg_http_proxy_port = 0; +char *gg_http_proxy_host = NULL; -#ifndef lint +#ifndef lint static char rcsid[] #ifdef __GNUC__ - __attribute__ ((unused)) +__attribute__ ((unused)) #endif - = "$Id: libgg.c 2805 2001-11-26 21:22:56Z warmenhoven $"; - -#endif += "$Id: libgg.c 2859 2001-12-05 09:48:56Z warmenhoven $"; -/* - * gg_debug() - * - * wyrzuca komunikat o danym poziomie, o ile użytkownik sobie tego życzy. - * - * - level - poziom wiadomości, - * - format... - treść wiadomości (printf-alike.) - * - * niczego nie zwraca. - */ -void gg_debug(int level, char *format, ...) -{ - va_list ap; - - if ((gg_debug_level & level)) { - va_start(ap, format); - vprintf(format, ap); - va_end(ap); - } -} +#endif /* * fix32() // funkcja wewnętrzna @@ -90,10 +72,11 @@ 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 } /* @@ -107,88 +90,12 @@ 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 } /* - * gg_alloc_sprintf() // funkcja wewnętrzna - * - * robi dokładnie to samo, co sprintf(), tyle że alokuje sobie wcześniej - * 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() - * - * zwraca zaalokowany buforek, który wypadałoby później zwolnić, lub NULL - * jeśli nie udało się wykonać zadania. - */ -char *gg_alloc_sprintf(char *format, ...) -{ - va_list ap; - char *buf = NULL, *tmp; - int size = 0, res; - - va_start(ap, format); - - 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); - - va_end(ap); - - return buf; -} - -/* - * 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ć @@ -208,7 +115,7 @@ struct in_addr a; gg_debug(GG_DEBUG_FUNCTION, "** gg_resolve(..., \"%s\");\n", hostname); - + if (!fd | !pid) { errno = EFAULT; return -1; @@ -223,11 +130,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)); @@ -244,91 +151,6 @@ } /* - * gg_connect() // funkcja wewnętrzna - * - * łączy się z serwerem. pierwszy argument jest typu (void *), żeby nie - * musieć niczego inkludować w libgg.h i nie psuć jakiś głupich zależności - * na dziwnych systemach. - * - * - addr - adres serwera (struct in_addr *), - * - port - port serwera, - * - async - ma być asynchroniczne połączenie? - * - * zwraca połączonego socketa lub -1 w przypadku błędu. zobacz errno. - */ -int gg_connect(void *addr, int port, int async) -{ - int sock, one = 1; - struct sockaddr_in sin; - 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) { - if (ioctl(sock, FIONBIO, &one) == -1) { - gg_debug(GG_DEBUG_MISC, "-- ioctl() failed. errno = %d (%s)\n", errno, - strerror(errno)); - return -1; - } - } - - 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, "-- connect() failed. errno = %d (%s)\n", errno, - strerror(errno)); - return -1; - } - gg_debug(GG_DEBUG_MISC, "-- connect() in progress\n"); - } - - return sock; -} - -/* - * gg_read_line() // funkcja wewnętrzna - * - * czyta jedną linię tekstu z socketa. - * - * - sock - socket, - * - buf - wskaźnik bufora, - * - length - długość bufora. - * - * olewa błędy. jeśli na jakiś trafi, potraktuje go jako koniec linii. - */ -static void gg_read_line(int sock, char *buf, int length) -{ - 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) { - *buf = 0; - return; - } - } while (ret == -1 && errno == EINTR); - - if (*buf == '\n') { - buf++; - break; - } - } - - *buf = 0; - return; -} - -/* * gg_recv_packet() // funkcja wewnętrzna * * odbiera jeden pakiet gg i zwraca wskaźnik do niego. pamięć po nim @@ -345,7 +167,7 @@ int ret = 0, offset, size = 0; gg_debug(GG_DEBUG_FUNCTION, "** gg_recv_packet(...);\n"); - + if (!sess) { errno = EFAULT; return NULL; @@ -357,8 +179,7 @@ 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; } } @@ -400,7 +221,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); @@ -410,7 +231,7 @@ return NULL; } if (errno != EINTR) { -// errno = EINVAL; +// errno = EINVAL; free(buf); return NULL; } @@ -423,8 +244,8 @@ 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"); } @@ -447,16 +268,14 @@ * 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; @@ -468,7 +287,7 @@ return -1; } - h = (struct gg_header *)tmp; + h = (struct gg_header*) tmp; h->type = fix32(type); h->length = fix32(length + payload_length); @@ -482,20 +301,19 @@ 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"); } 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; } @@ -519,6 +337,8 @@ struct gg_session *gg_login(uin_t uin, char *password, int async) { struct gg_session *sess; + char *hostname; + int port; gg_debug(GG_DEBUG_FUNCTION, "** gg_login(%u, \"...\", %d);\n", uin, async); @@ -538,9 +358,18 @@ sess->last_pong = 0; sess->server_ip = 0; sess->initial_status = 0; + sess->type = GG_SESSION_GG; + + if (gg_http_use_proxy) { + hostname = gg_http_proxy_host; + port = gg_http_proxy_port; + } else { + hostname = GG_APPMSG_HOST; + port = GG_APPMSG_PORT; + }; if (async) { - if (gg_resolve(&sess->fd, &sess->pid, GG_APPMSG_HOST)) { + if (gg_resolve(&sess->fd, &sess->pid, hostname)) { gg_debug(GG_DEBUG_MISC, "-- resolving failed\n"); free(sess); return NULL; @@ -548,24 +377,24 @@ } else { struct in_addr a; - if ((a.s_addr = inet_addr(GG_APPMSG_HOST)) == INADDR_NONE) { + if ((a.s_addr = inet_addr(hostname)) == INADDR_NONE) { struct hostent *he; - - if (!(he = gethostbyname(GG_APPMSG_HOST))) { - gg_debug(GG_DEBUG_MISC, "-- host %s not found\n", GG_APPMSG_HOST); + + if (!(he = gethostbyname(hostname))) { + gg_debug(GG_DEBUG_MISC, "-- host %s not found\n", hostname); 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) { + if (!(sess->fd = gg_connect(&a, port, 0)) == -1) { gg_debug(GG_DEBUG_MISC, "-- connection failed\n"); free(sess); return NULL; } - sess->state = GG_STATE_CONNECTING_HTTP; + sess->state = GG_STATE_CONNECTING; while (sess->state != GG_STATE_CONNECTED) { struct gg_event *e; @@ -658,7 +487,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); @@ -686,7 +515,7 @@ errno = EFAULT; return -1; } - + if (sess->state != GG_STATE_CONNECTED) { errno = ENOTCONN; return -1; @@ -700,7 +529,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; @@ -764,7 +593,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; @@ -774,25 +603,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; @@ -824,12 +653,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); } @@ -858,10 +687,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); } @@ -887,13 +716,12 @@ 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; @@ -903,7 +731,7 @@ 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); } } @@ -913,9 +741,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; @@ -967,26 +795,6 @@ } /* - * gg_chomp() // funkcja wewnętrzna - * - * ucina "\r\n" lub "\n" z końca linii. - * - * - line - ofiara operacji plastycznej. - * - * niczego nie zwraca. - */ -static void gg_chomp(char *line) -{ - if (!line || strlen(line) < 1) - return; - - if (line[strlen(line) - 1] == '\n') - line[strlen(line) - 1] = 0; - if (line[strlen(line) - 1] == '\r') - line[strlen(line) - 1] = 0; -} - -/* * gg_watch_fd() * * funkcja wywoływana, gdy coś się stanie na obserwowanym deskryptorze. @@ -1004,6 +812,7 @@ { struct gg_event *e; int res = 0; + int port; if (!sess) { errno = EFAULT; @@ -1012,7 +821,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; } @@ -1020,14 +829,14 @@ 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; @@ -1038,7 +847,7 @@ break; } - + sess->server_ip = a.s_addr; close(sess->fd); @@ -1046,81 +855,87 @@ waitpid(sess->pid, NULL, 0); gg_debug(GG_DEBUG_MISC, "-- resolved, now connecting\n"); + + if (gg_http_use_proxy) { + port = gg_http_proxy_port; + } else { + port = GG_APPMSG_PORT; + }; - if ((sess->fd = gg_connect(&a, GG_APPMSG_PORT, sess->async)) == -1) { - struct in_addr *addr = (struct in_addr *)&sess->server_ip; - - gg_debug(GG_DEBUG_MISC, - "-- connection failed, trying direct connection\n"); + if ((sess->fd = gg_connect(&a, port, sess->async)) == -1) { + struct in_addr *addr = (struct in_addr*) &sess->server_ip; + + gg_debug(GG_DEBUG_MISC, "-- connection failed, trying direct connection\n"); 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)); + 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; - } + 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->state = GG_STATE_CONNECTING; sess->check = GG_CHECK_WRITE; } - + break; } - case GG_STATE_CONNECTING_HTTP: + case GG_STATE_CONNECTING: { char buf[1024]; int res, res_size = sizeof(res); - gg_debug(GG_DEBUG_MISC, "== GG_STATE_CONNECTING_HTTP\n"); + gg_debug(GG_DEBUG_MISC, "== GG_STATE_CONNECTING\n"); - 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)); + 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)); 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)); + 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; - } + 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=%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 (gg_http_use_proxy) { + snprintf(buf, sizeof(buf) - 1, + "GET http://" GG_APPMSG_HOST "/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); + } else { + snprintf(buf, sizeof(buf) - 1, + "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); + }; + gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", buf); + if (write(sess->fd, buf, strlen(buf)) < strlen(buf)) { gg_debug(GG_DEBUG_MISC, "-- sending query failed\n"); @@ -1131,25 +946,24 @@ break; } - sess->state = GG_STATE_WRITING_HTTP; + sess->state = GG_STATE_READING_DATA; sess->check = GG_CHECK_READ; break; } - case GG_STATE_WRITING_HTTP: + case GG_STATE_READING_DATA: { char buf[1024], *tmp, *host; int port = GG_DEFAULT_PORT; struct in_addr a; - gg_debug(GG_DEBUG_MISC, "== GG_STATE_WRITING_HTTP\n"); + gg_debug(GG_DEBUG_MISC, "== GG_STATE_READING_DATA\n"); 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"); @@ -1159,18 +973,19 @@ 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; + while (*tmp && *tmp != ' ') tmp++; while (*tmp && *tmp == ' ') @@ -1190,78 +1005,70 @@ 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, - "-- connection failed, trying https connection\n"); + 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)); + 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)) { - struct in_addr *addr = (struct in_addr *)&sess->server_ip; + 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, - "-- connection failed, trying https connection\n"); + 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, "-- 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->state = GG_STATE_READING_KEY; sess->check = GG_CHECK_READ; break; } - case GG_STATE_WAITING_FOR_KEY: + case GG_STATE_READING_KEY: { - struct gg_header *h; + struct gg_header *h; struct gg_welcome *w; struct gg_login l; unsigned int hash; char *password = sess->password; - gg_debug(GG_DEBUG_MISC, "== GG_STATE_WAITING_FOR_KEY\n"); + gg_debug(GG_DEBUG_MISC, "== GG_STATE_READING_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; @@ -1269,7 +1076,7 @@ close(sess->fd); break; } - + if (h->type != GG_WELCOME) { gg_debug(GG_DEBUG_MISC, "-- invalid packet received\n"); @@ -1281,34 +1088,32 @@ 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(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; @@ -1316,17 +1121,17 @@ sess->state = GG_STATE_IDLE; break; } - - sess->state = GG_STATE_SENDING_KEY; + + sess->state = GG_STATE_READING_REPLY; break; } - case GG_STATE_SENDING_KEY: + case GG_STATE_READING_REPLY: { struct gg_header *h; - gg_debug(GG_DEBUG_MISC, "== GG_STATE_SENDING_KEY\n"); + gg_debug(GG_DEBUG_MISC, "== GG_STATE_READING_REPLY\n"); if (!(h = gg_recv_packet(sess))) { gg_debug(GG_DEBUG_MISC, "-- recv_packet failed\n"); @@ -1336,7 +1141,7 @@ close(sess->fd); break; } - + if (h->type == GG_LOGIN_OK) { gg_debug(GG_DEBUG_MISC, "-- login succeded\n"); e->type = GG_EVENT_CONN_SUCCESS; @@ -1363,17 +1168,15 @@ 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 @@ -1390,3 +1193,13 @@ return e; } + +/* + * Local variables: + * c-indentation-style: k&r + * c-basic-offset: 8 + * indent-tabs-mode: notnil + * End: + * + * vim: shiftwidth=8: + */ diff -r 0c10058610a0 -r 4b3f17ca66bf src/protocols/gg/libgg.h --- a/src/protocols/gg/libgg.h Tue Dec 04 19:51:27 2001 +0000 +++ b/src/protocols/gg/libgg.h Wed Dec 05 09:48:56 2001 +0000 @@ -1,8 +1,8 @@ -/* $Id: libgg.h 2805 2001-11-26 21:22:56Z warmenhoven $ */ +/* $Id: libgg.h 2859 2001-12-05 09:48:56Z warmenhoven $ */ /* * (C) Copyright 2001 Wojtek Kaniewski , - * Robert J. Woźny + * 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 @@ -18,15 +18,15 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#ifndef __LIBGG_H -#define __LIBGG_H +#ifndef __GG_LIBGG_H +#define __GG_LIBGG_H #ifdef __cplusplus extern "C" { #endif #if defined(sun) && !defined(INADDR_NONE) -#define INADDR_NONE 0xffffffff + #define INADDR_NONE 0xffffffff #endif #include @@ -34,176 +34,297 @@ /* * typ zmiennej określającej numerek danej osoby. */ - typedef unsigned long uin_t; +typedef unsigned long uin_t; + +/* + * struktura opisująca daną sesję. tworzona przez gg_login(). + */ +struct gg_session { + 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. == GG_SESSION_GG */ + + int async; /* czy połączenie jest asynchroniczne */ + int pid; /* pid procesu resolvera */ + int port; /* port, z którym się łączymy */ + int seq; /* numer sekwencyjny ostatniej wiadomości */ + int last_pong; /* czas otrzymania ostatniego ping/pong */ + + unsigned int server_ip; /* adres serwera */ + unsigned int client_ip; /* adres klienta */ + int client_port; /* port, na którym klient słucha */ + + uin_t uin; /* numerek klienta */ + char *password; /* i jego hasło. zwalniane automagicznie */ + + int initial_status; /* początkowy stan klienta */ + + char *recv_buf; /* bufor na otrzymywane pakiety */ + int recv_done; /* ile już wczytano do bufora */ + int recv_left; /* i ile jeszcze trzeba wczytać */ +}; /* - * cośtam. + * ogólna struktura opisująca stan wszystkich operacji http. */ - struct gg_session { - int state, check; - int fd, pid; - int port; - int seq, async; - int last_pong; +struct gg_http { + 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. == GG_SESSION_HTTP */ + + 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 */ + int body_size; /* ilość informacji */ - /* powinno być ,,in_addr'', ale nie chcę inkludować sieci tutaj */ - unsigned long server_ip; + void *data; /* dane danej operacji http */ +}; - uin_t uin; - char *password; - int initial_status; +/* + * ogólna struktura opisująca różne sesje. przydatna w klientach. + */ +struct gg_common { + 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 */ +}; - char *recv_buf; - int recv_done, recv_left; - }; +/* + * rodzaje sesji. + */ +enum { + GG_SESSION_GG = 1, /* połączenie z serwerem gg */ + GG_SESSION_HTTP, /* ogólna sesja http */ + GG_SESSION_SEARCH, /* szukanie */ + GG_SESSION_REGISTER, /* rejestrowanie */ +}; /* * różne stany asynchronicznej maszynki. */ - enum { - GG_STATE_IDLE = 0, /* wspólne */ - GG_STATE_RESOLVING, - GG_STATE_CONNECTING_HTTP, +enum { + /* 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_STATE_CONNECTING_GG, /* wywołał connect() */ + GG_STATE_READING_KEY, /* czeka na klucz */ + GG_STATE_READING_REPLY, /* czeka na odpowiedź */ + GG_STATE_CONNECTED, /* połączył się */ - GG_STATE_WRITING_HTTP, /* gg_login */ - GG_STATE_CONNECTING_GG, - GG_STATE_WAITING_FOR_KEY, - GG_STATE_SENDING_KEY, - GG_STATE_CONNECTED, + /* gg_http */ + GG_STATE_READING_HEADER, /* czeka na nagłówek http */ + GG_STATE_PARSING, /* przetwarza dane */ + GG_STATE_DONE, /* skończył */ +}; - GG_STATE_READING_HEADER, /* gg_search */ - GG_STATE_READING_DATA, - GG_STATE_PARSING, - GG_STATE_FINISHED, - }; +/* + * dla zachowania kompatybilności wstecz. w wersji 1.0 będzie usunięte. oby. + */ +#define GG_STATE_WRITING_HTTP GG_STATE_READING_DATA +#define GG_STATE_WAITING_FOR_KEY GG_STATE_READING_KEY +#define GG_STATE_SENDING_KEY GG_STATE_READING_REPLY +#define GG_STATE_FINISHED GG_STATE_DONE /* * 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, /* nic. nie powinno wystąpić */ + GG_CHECK_WRITE = 1, /* sprawdzamy możliwość zapisu */ + GG_CHECK_READ = 2, /* sprawdzamy możliwość odczytu */ +}; - 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 */ - 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_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 version; /* == 0x0b */ + unsigned short dunno2; /* znowu port? */ +} __attribute__ ((packed)); - struct gg_status { - uin_t uin; /* numerek */ - unsigned long 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_FAILURE_RESOLVING = 1, - GG_FAILURE_CONNECTING, - GG_FAILURE_INVALID, - GG_FAILURE_READING, - GG_FAILURE_WRITING, - GG_FAILURE_PASSWORD, - }; +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, +}; - 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; - }; +/* + * niedługo się tego pozbędę na rzecz sensownej obsługi błędów. --w + */ +enum { + GG_FAILURE_RESOLVING = 1, + GG_FAILURE_CONNECTING, + GG_FAILURE_INVALID, + GG_FAILURE_READING, + GG_FAILURE_WRITING, + GG_FAILURE_PASSWORD, + GG_FAILURE_404, +}; - 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); +/* + * rodzaje błędów, na razie używane przez http. bez rozczulania się nad + * powodami. klient powie, że albo nie znalazł hosta, albo nie mógł się + * połączyć, albo nie mógł wysłać, albo nie mógł odebrac. i tyle. jak + * ktoś będzie chciał, to będzie mógł sprawdzić errno. ale po co? + */ +enum { + GG_ERROR_RESOLVING = 1, + GG_ERROR_CONNECTING, + GG_ERROR_READING, + GG_ERROR_WRITING, +}; /* - * jakieśtam bzdurki dotyczące szukania userów. + * struktura opisująca rodzaj zdarzenia. wychodzi z gg_watch_fd() + */ +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); + +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); + + +/* + * OBSŁUGA HTTP + */ + +struct gg_http *gg_http_connect(char *hostname, int port, int async, char *method, char *path, char *header); +int gg_http_watch_fd(struct gg_http *h); +void gg_http_stop(struct gg_http *h); +void gg_free_http(struct gg_http *h); + +/* + * SZUKANIE UŻYTKOWNIKÓW */ - struct gg_search_result { - uin_t uin; - char *first_name; - char *last_name; - char *nickname; - int born; - int gender; - char *city; - int active; - }; +/* + * struktura opisująca kryteria wyszukiwania. argument gg_search(). + */ +struct gg_search_request { + int active; /* czy ma szukać tylko aktywnych? */ + + /* mode 0 */ + char *nickname; /* pseudonim */ + char *first_name; /* imię */ + char *last_name; /* nazwisko */ + char *city; /* miasto */ + int gender; /* płeć */ + int min_birth; /* urodzony od roku... */ + int max_birth; /* urodzony do roku... */ + + /* mode 1 */ + char *email; /* adres e-mail */ + + /* mode 2 */ + char *phone; /* numer telefonu */ + + /* mode 3 */ + uin_t uin; /* numerek */ +}; + +/* + * struktura opisująca rezultat wyszukiwania. pole gg_http. + */ +struct gg_search { + int count; /* ilość znalezionych */ + struct gg_search_result *results; /* tabelka z nimi */ +}; - 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; - }; +/* + * pojedynczy rezultat wyszukiwania. + */ +struct gg_search_result { + uin_t uin; /* numerek */ + char *first_name; /* imię */ + char *last_name; /* nazwisko */ + char *nickname; /* pseudonim */ + int born; /* rok urodzenia */ + int gender; /* płeć */ + char *city; /* miasto */ + int active; /* czy jest aktywny */ +}; - struct gg_search { - struct gg_search_request request; +#define GG_GENDER_NONE 0 /* nie podano lub bez znaczenia */ +#define GG_GENDER_FEMALE 1 /* kobieta */ +#define GG_GENDER_MALE 2 /* mężczyzna */ - /* bzdurki */ - int mode, fd, async, state, check, error, pid; - char *header_buf, *data_buf; - int header_size, data_size; +struct gg_http *gg_search(struct gg_search_request *r, int async); +int gg_search_watch_fd(struct gg_http *f); +void gg_free_search(struct gg_http *f); + +struct gg_search_request *gg_search_request_mode_0(char *nickname, char *first_name, char *last_name, char *city, int gender, int min_birth, int max_birth, int active); +struct gg_search_request *gg_search_request_mode_1(char *email, int active); +struct gg_search_request *gg_search_request_mode_2(char *phone, int active); +struct gg_search_request *gg_search_request_mode_3(uin_t uin, int active); - /* wyniki */ - int count; - struct gg_search_result *results; - }; +/* + * OPERACJE NA KATALOGU PUBLICZNYM + */ -#define GG_GENDER_NONE 0 -#define GG_GENDER_FEMALE 1 -#define GG_GENDER_MALE 2 +struct gg_pubdir { + int success; /* czy się udało */ + uin_t uin; /* otrzymany numerek. 0 jeśli błąd */ +}; - 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_http *gg_register(char *email, char *password, int async); +void gg_free_register(struct gg_http *f); + +int gg_pubdir_watch_fd(struct gg_http *f); +#define gg_register_watch_fd gg_pubdir_watch_fd /* * jeśli chcemy sobie podebugować, wystarczy ustawić `gg_debug_level'. @@ -211,7 +332,7 @@ * się ustawiać odpowiednich leveli, więc większość szła do _MISC. */ - extern int gg_debug_level; +extern int gg_debug_level; #define GG_DEBUG_NET 1 #define GG_DEBUG_TRAFFIC 2 @@ -219,7 +340,16 @@ #define GG_DEBUG_FUNCTION 8 #define GG_DEBUG_MISC 16 - void gg_debug(int level, char *format, ...); +void gg_debug(int level, char *format, ...); + +/* + * Pare małych zmiennych do obsługi "http proxy" + * + */ + +extern int gg_http_use_proxy; +extern char *gg_http_proxy_host; +extern int gg_http_proxy_port; /* * ------------------------------------------------------------------------- @@ -230,41 +360,47 @@ * ------------------------------------------------------------------------- */ - 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); +int gg_resolve(int *fd, int *pid, char *hostname); +void gg_debug(int level, char *format, ...); +char *gg_alloc_sprintf(char *format, ...); +char *gg_get_line(char **ptr); +int gg_connect(void *addr, int port, int async); +void gg_read_line(int sock, char *buf, int length); +void gg_chomp(char *line); +char *gg_urlencode(char *str); +int gg_http_hash(unsigned char *email, unsigned char *password); #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_REGISTER_HOST "register.gadu-gadu.pl" +#define GG_REGISTER_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 { - unsigned long type; /* typ pakietu */ - unsigned long 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 { - unsigned long 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 */ - 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)); +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 @@ -273,39 +409,39 @@ #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 { - unsigned long 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 @@ -313,37 +449,48 @@ #define GG_CLASS_MSG 0x0004 #define GG_CLASS_CHAT 0x0008 - struct gg_send_msg { - unsigned long recipient; - unsigned long seq; - unsigned long 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 { - unsigned long status; - unsigned long recipient; - unsigned long 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 { - unsigned long sender; - unsigned long seq; - unsigned long time; - unsigned long 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 + +#endif /* __GG_LIBGG_H */ + +/* + * Local variables: + * c-indentation-style: k&r + * c-basic-offset: 8 + * indent-tabs-mode: notnil + * End: + * + * vim: shiftwidth=8: + */