You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdenetwork/kopete/protocols/gadu/libgadu/pubdir.c

690 lines
17 KiB

/* $Id$ */
/*
* (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka@irc.pl>
* Dawid Jarosz <dawjar@poczta.onet.pl>
* Adam Wysocki <gophi@ekg.chmurka.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License Version
* 2.1 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
* USA.
*/
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "libgadu.h"
/*
* gg_register3()
*
* rozpoczyna rejestracj<63> u<>ytkownika protoko<6B>em GG 6.0. wymaga wcze<7A>niejszego
* pobrania tokenu za pomoc<6F> funkcji gg_token().
*
* - email - adres e-mail klienta
* - password - has<61>o klienta
* - tokenid - identyfikator tokenu
* - tokenval - warto<74><6F> tokenu
* - async - po<70><6F>czenie asynchroniczne
*
* zaalokowana struct gg_http, kt<6B>r<EFBFBD> po<70>niej nale<6C>y zwolni<6E>
* funkcj<63> gg_register_free(), albo NULL je<6A>li wyst<73>pi<70> b<><62>d.
*/
struct gg_http *gg_register3(const char *email, const char *password, const char *tokenid, const char *tokenval, int async)
{
struct gg_http *h;
char *__pwd, *__email, *__tokenid, *__tokenval, *form, *query;
if (!email || !password || !tokenid || !tokenval) {
gg_debug(GG_DEBUG_MISC, "=> register, NULL parameter\n");
errno = EFAULT;
return NULL;
}
__pwd = gg_urlencode(password);
__email = gg_urlencode(email);
__tokenid = gg_urlencode(tokenid);
__tokenval = gg_urlencode(tokenval);
if (!__pwd || !__email || !__tokenid || !__tokenval) {
gg_debug(GG_DEBUG_MISC, "=> register, not enough memory for form fields\n");
free(__pwd);
free(__email);
free(__tokenid);
free(__tokenval);
return NULL;
}
form = gg_saprintf("pwd=%s&email=%s&tokenid=%s&tokenval=%s&code=%u",
__pwd, __email, __tokenid, __tokenval,
gg_http_hash("ss", email, password));
free(__pwd);
free(__email);
free(__tokenid);
free(__tokenval);
if (!form) {
gg_debug(GG_DEBUG_MISC, "=> register, not enough memory for form query\n");
return NULL;
}
gg_debug(GG_DEBUG_MISC, "=> register, %s\n", form);
query = gg_saprintf(
"Host: " GG_REGISTER_HOST "\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"User-Agent: " GG_HTTP_USERAGENT "\r\n"
"Content-Length: %d\r\n"
"Pragma: no-cache\r\n"
"\r\n"
"%s",
(int) strlen(form), form);
free(form);
if (!query) {
gg_debug(GG_DEBUG_MISC, "=> register, not enough memory for query\n");
return NULL;
}
if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/fmregister3.asp", query))) {
gg_debug(GG_DEBUG_MISC, "=> register, gg_http_connect() failed mysteriously\n");
free(query);
return NULL;
}
h->type = GG_SESSION_REGISTER;
free(query);
h->callback = gg_pubdir_watch_fd;
h->destroy = gg_pubdir_free;
if (!async)
gg_pubdir_watch_fd(h);
return h;
}
/*
* gg_unregister3()
*
* usuwa konto u<>ytkownika z serwera protoko<6B>em GG 6.0
*
* - uin - numerek GG
* - password - has<61>o klienta
* - tokenid - identyfikator tokenu
* - tokenval - warto<74><6F> tokenu
* - async - po<70><6F>czenie asynchroniczne
*
* zaalokowana struct gg_http, kt<6B>r<EFBFBD> po<70>niej nale<6C>y zwolni<6E>
* funkcj<63> gg_unregister_free(), albo NULL je<6A>li wyst<73>pi<70> b<><62>d.
*/
struct gg_http *gg_unregister3(uin_t uin, const char *password, const char *tokenid, const char *tokenval, int async)
{
struct gg_http *h;
char *__fmpwd, *__pwd, *__tokenid, *__tokenval, *form, *query;
if (!password || !tokenid || !tokenval) {
gg_debug(GG_DEBUG_MISC, "=> unregister, NULL parameter\n");
errno = EFAULT;
return NULL;
}
__pwd = gg_saprintf("%ld", random());
__fmpwd = gg_urlencode(password);
__tokenid = gg_urlencode(tokenid);
__tokenval = gg_urlencode(tokenval);
if (!__fmpwd || !__pwd || !__tokenid || !__tokenval) {
gg_debug(GG_DEBUG_MISC, "=> unregister, not enough memory for form fields\n");
free(__pwd);
free(__fmpwd);
free(__tokenid);
free(__tokenval);
return NULL;
}
form = gg_saprintf("fmnumber=%d&fmpwd=%s&delete=1&pwd=%s&email=deletedaccount@gadu-gadu.pl&tokenid=%s&tokenval=%s&code=%u", uin, __fmpwd, __pwd, __tokenid, __tokenval, gg_http_hash("ss", "deletedaccount@gadu-gadu.pl", __pwd));
free(__fmpwd);
free(__pwd);
free(__tokenid);
free(__tokenval);
if (!form) {
gg_debug(GG_DEBUG_MISC, "=> unregister, not enough memory for form query\n");
return NULL;
}
gg_debug(GG_DEBUG_MISC, "=> unregister, %s\n", form);
query = gg_saprintf(
"Host: " GG_REGISTER_HOST "\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"User-Agent: " GG_HTTP_USERAGENT "\r\n"
"Content-Length: %d\r\n"
"Pragma: no-cache\r\n"
"\r\n"
"%s",
(int) strlen(form), form);
free(form);
if (!query) {
gg_debug(GG_DEBUG_MISC, "=> unregister, not enough memory for query\n");
return NULL;
}
if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/fmregister3.asp", query))) {
gg_debug(GG_DEBUG_MISC, "=> unregister, gg_http_connect() failed mysteriously\n");
free(query);
return NULL;
}
h->type = GG_SESSION_UNREGISTER;
free(query);
h->callback = gg_pubdir_watch_fd;
h->destroy = gg_pubdir_free;
if (!async)
gg_pubdir_watch_fd(h);
return h;
}
/*
* gg_change_passwd4()
*
* wysy<73>a <20><>danie zmiany has<61>a zgodnie z protoko<6B>em GG 6.0. wymaga
* wcze<7A>niejszego pobrania tokenu za pomoc<6F> funkcji gg_token().
*
* - uin - numer
* - email - adres e-mail
* - passwd - stare has<61>o
* - newpasswd - nowe has<61>o
* - tokenid - identyfikator tokenu
* - tokenval - warto<74><6F> tokenu
* - async - po<70><6F>czenie asynchroniczne
*
* zaalokowana struct gg_http, kt<6B>r<EFBFBD> po<70>niej nale<6C>y zwolni<6E>
* funkcj<63> gg_change_passwd_free(), albo NULL je<6A>li wyst<73>pi<70> b<><62>d.
*/
struct gg_http *gg_change_passwd4(uin_t uin, const char *email, const char *passwd, const char *newpasswd, const char *tokenid, const char *tokenval, int async)
{
struct gg_http *h;
char *form, *query, *__email, *__fmpwd, *__pwd, *__tokenid, *__tokenval;
if (!uin || !email || !passwd || !newpasswd || !tokenid || !tokenval) {
gg_debug(GG_DEBUG_MISC, "=> change, NULL parameter\n");
errno = EFAULT;
return NULL;
}
__fmpwd = gg_urlencode(passwd);
__pwd = gg_urlencode(newpasswd);
__email = gg_urlencode(email);
__tokenid = gg_urlencode(tokenid);
__tokenval = gg_urlencode(tokenval);
if (!__fmpwd || !__pwd || !__email || !__tokenid || !__tokenval) {
gg_debug(GG_DEBUG_MISC, "=> change, not enough memory for form fields\n");
free(__fmpwd);
free(__pwd);
free(__email);
free(__tokenid);
free(__tokenval);
return NULL;
}
if (!(form = gg_saprintf("fmnumber=%d&fmpwd=%s&pwd=%s&email=%s&tokenid=%s&tokenval=%s&code=%u", uin, __fmpwd, __pwd, __email, __tokenid, __tokenval, gg_http_hash("ss", email, newpasswd)))) {
gg_debug(GG_DEBUG_MISC, "=> change, not enough memory for form fields\n");
free(__fmpwd);
free(__pwd);
free(__email);
free(__tokenid);
free(__tokenval);
return NULL;
}
free(__fmpwd);
free(__pwd);
free(__email);
free(__tokenid);
free(__tokenval);
gg_debug(GG_DEBUG_MISC, "=> change, %s\n", form);
query = gg_saprintf(
"Host: " GG_REGISTER_HOST "\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"User-Agent: " GG_HTTP_USERAGENT "\r\n"
"Content-Length: %d\r\n"
"Pragma: no-cache\r\n"
"\r\n"
"%s",
(int) strlen(form), form);
free(form);
if (!query) {
gg_debug(GG_DEBUG_MISC, "=> change, not enough memory for query\n");
return NULL;
}
if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/fmregister3.asp", query))) {
gg_debug(GG_DEBUG_MISC, "=> change, gg_http_connect() failed mysteriously\n");
free(query);
return NULL;
}
h->type = GG_SESSION_PASSWD;
free(query);
h->callback = gg_pubdir_watch_fd;
h->destroy = gg_pubdir_free;
if (!async)
gg_pubdir_watch_fd(h);
return h;
}
/*
* gg_remind_passwd3()
*
* wysy<73>a <20><>danie przypomnienia has<61>a e-mailem.
*
* - uin - numer
* - email - adres e-mail taki, jak ten zapisany na serwerze
* - async - po<70><6F>czenie asynchroniczne
* - tokenid - identyfikator tokenu
* - tokenval - warto<74><6F> tokenu
*
* zaalokowana struct gg_http, kt<6B>r<EFBFBD> po<70>niej nale<6C>y zwolni<6E>
* funkcj<63> gg_remind_passwd_free(), albo NULL je<6A>li wyst<73>pi<70> b<><62>d.
*/
struct gg_http *gg_remind_passwd3(uin_t uin, const char *email, const char *tokenid, const char *tokenval, int async)
{
struct gg_http *h;
char *form, *query, *__tokenid, *__tokenval, *__email;
if (!tokenid || !tokenval || !email) {
gg_debug(GG_DEBUG_MISC, "=> remind, NULL parameter\n");
errno = EFAULT;
return NULL;
}
__tokenid = gg_urlencode(tokenid);
__tokenval = gg_urlencode(tokenval);
__email = gg_urlencode(email);
if (!__tokenid || !__tokenval || !__email) {
gg_debug(GG_DEBUG_MISC, "=> remind, not enough memory for form fields\n");
free(__tokenid);
free(__tokenval);
free(__email);
return NULL;
}
if (!(form = gg_saprintf("userid=%d&code=%u&tokenid=%s&tokenval=%s&email=%s", uin, gg_http_hash("u", uin), __tokenid, __tokenval, __email))) {
gg_debug(GG_DEBUG_MISC, "=> remind, not enough memory for form fields\n");
free(__tokenid);
free(__tokenval);
free(__email);
return NULL;
}
free(__tokenid);
free(__tokenval);
free(__email);
gg_debug(GG_DEBUG_MISC, "=> remind, %s\n", form);
query = gg_saprintf(
"Host: " GG_REMIND_HOST "\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"User-Agent: " GG_HTTP_USERAGENT "\r\n"
"Content-Length: %d\r\n"
"Pragma: no-cache\r\n"
"\r\n"
"%s",
(int) strlen(form), form);
free(form);
if (!query) {
gg_debug(GG_DEBUG_MISC, "=> remind, not enough memory for query\n");
return NULL;
}
if (!(h = gg_http_connect(GG_REMIND_HOST, GG_REMIND_PORT, async, "POST", "/appsvc/fmsendpwd3.asp", query))) {
gg_debug(GG_DEBUG_MISC, "=> remind, gg_http_connect() failed mysteriously\n");
free(query);
return NULL;
}
h->type = GG_SESSION_REMIND;
free(query);
h->callback = gg_pubdir_watch_fd;
h->destroy = gg_pubdir_free;
if (!async)
gg_pubdir_watch_fd(h);
return h;
}
/*
* gg_pubdir_watch_fd()
*
* przy asynchronicznych operacjach na katalogu publicznym nale<6C>y wywo<77>ywa<77>
* t<> funkcj<63> przy zmianach na obserwowanym deskryptorze.
*
* - h - struktura opisuj<75>ca po<70><6F>czenie
*
* je<6A>li wszystko posz<73>o dobrze to 0, inaczej -1. operacja b<>dzie
* zako<6B>czona, je<6A>li h->state == GG_STATE_DONE. je<6A>li wyst<73>pi jaki<6B>
* b<><62>d, to b<>dzie tam GG_STATE_ERROR i odpowiedni kod b<><62>du w h->error.
*/
int gg_pubdir_watch_fd(struct gg_http *h)
{
struct gg_pubdir *p;
char *tmp;
if (!h) {
errno = EFAULT;
return -1;
}
if (h->state == GG_STATE_ERROR) {
gg_debug(GG_DEBUG_MISC, "=> pubdir, watch_fd issued on failed session\n");
errno = EINVAL;
return -1;
}
if (h->state != GG_STATE_PARSING) {
if (gg_http_watch_fd(h) == -1) {
gg_debug(GG_DEBUG_MISC, "=> pubdir, http failure\n");
errno = EINVAL;
return -1;
}
}
if (h->state != GG_STATE_PARSING)
return 0;
h->state = GG_STATE_DONE;
if (!(h->data = p = malloc(sizeof(struct gg_pubdir)))) {
gg_debug(GG_DEBUG_MISC, "=> pubdir, not enough memory for results\n");
return -1;
}
p->success = 0;
p->uin = 0;
gg_debug(GG_DEBUG_MISC, "=> pubdir, let's parse \"%s\"\n", h->body);
if ((tmp = strstr(h->body, "Tokens okregisterreply_packet.reg.dwUserId="))) {
p->success = 1;
p->uin = strtol(tmp + sizeof("Tokens okregisterreply_packet.reg.dwUserId=") - 1, NULL, 0);
gg_debug(GG_DEBUG_MISC, "=> pubdir, success (okregisterreply, uin=%d)\n", p->uin);
} else if ((tmp = strstr(h->body, "success")) || (tmp = strstr(h->body, "results"))) {
p->success = 1;
if (tmp[7] == ':')
p->uin = strtol(tmp + 8, NULL, 0);
gg_debug(GG_DEBUG_MISC, "=> pubdir, success (uin=%d)\n", p->uin);
} else
gg_debug(GG_DEBUG_MISC, "=> pubdir, error.\n");
return 0;
}
/*
* gg_pubdir_free()
*
* zwalnia pami<6D><69> po efektach operacji na katalogu publicznym.
*
* - h - zwalniana struktura
*/
void gg_pubdir_free(struct gg_http *h)
{
if (!h)
return;
free(h->data);
gg_http_free(h);
}
/*
* gg_token()
*
* pobiera z serwera token do autoryzacji zak<61>adania konta, usuwania
* konta i zmiany has<61>a.
*
* zaalokowana struct gg_http, kt<6B>r<EFBFBD> po<70>niej nale<6C>y zwolni<6E>
* funkcj<63> gg_token_free(), albo NULL je<6A>li wyst<73>pi<70> b<><62>d.
*/
struct gg_http *gg_token(int async)
{
struct gg_http *h;
const char *query;
query = "Host: " GG_REGISTER_HOST "\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"User-Agent: " GG_HTTP_USERAGENT "\r\n"
"Content-Length: 0\r\n"
"Pragma: no-cache\r\n"
"\r\n";
if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/regtoken.asp", query))) {
gg_debug(GG_DEBUG_MISC, "=> token, gg_http_connect() failed mysteriously\n");
return NULL;
}
h->type = GG_SESSION_TOKEN;
h->callback = gg_token_watch_fd;
h->destroy = gg_token_free;
if (!async)
gg_token_watch_fd(h);
return h;
}
/*
* gg_token_watch_fd()
*
* przy asynchronicznych operacjach zwi<77>zanych z tokenem nale<6C>y wywo<77>ywa<77>
* t<> funkcj<63> przy zmianach na obserwowanym deskryptorze.
*
* - h - struktura opisuj<75>ca po<70><6F>czenie
*
* je<6A>li wszystko posz<73>o dobrze to 0, inaczej -1. operacja b<>dzie
* zako<6B>czona, je<6A>li h->state == GG_STATE_DONE. je<6A>li wyst<73>pi jaki<6B>
* b<><62>d, to b<>dzie tam GG_STATE_ERROR i odpowiedni kod b<><62>du w h->error.
*/
int gg_token_watch_fd(struct gg_http *h)
{
if (!h) {
errno = EFAULT;
return -1;
}
if (h->state == GG_STATE_ERROR) {
gg_debug(GG_DEBUG_MISC, "=> token, watch_fd issued on failed session\n");
errno = EINVAL;
return -1;
}
if (h->state != GG_STATE_PARSING) {
if (gg_http_watch_fd(h) == -1) {
gg_debug(GG_DEBUG_MISC, "=> token, http failure\n");
errno = EINVAL;
return -1;
}
}
if (h->state != GG_STATE_PARSING)
return 0;
/* je<6A>li h->data jest puste, to <20>ci<63>gali<6C>my tokenid i url do niego,
* ale je<6A>li co<63> tam jest, to znaczy, <20>e mamy drugi etap polegaj<61>cy
* na pobieraniu tokenu. */
if (!h->data) {
int width, height, length;
char *url = NULL, *tokenid = NULL, *path, *headers;
const char *host;
struct gg_http *h2;
struct gg_token *t;
gg_debug(GG_DEBUG_MISC, "=> token body \"%s\"\n", h->body);
if (h->body && (!(url = malloc(strlen(h->body))) || !(tokenid = malloc(strlen(h->body))))) {
gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for results\n");
free(url);
return -1;
}
if (!h->body || sscanf(h->body, "%d %d %d\r\n%s\r\n%s", &width, &height, &length, tokenid, url) != 5) {
gg_debug(GG_DEBUG_MISC, "=> token, parsing failed\n");
free(url);
free(tokenid);
errno = EINVAL;
return -1;
}
/* dostali<6C>my tokenid i wszystkie niezb<7A>dne informacje,
* wi<77>c pobierzmy obrazek z tokenem */
if (strncmp(url, "http://", 7)) {
path = gg_saprintf("%s?tokenid=%s", url, tokenid);
host = GG_REGISTER_HOST;
} else {
char *slash = (char*)strchr(url + 7, '/');
if (slash) {
path = gg_saprintf("%s?tokenid=%s", slash, tokenid);
*slash = 0;
host = url + 7;
} else {
gg_debug(GG_DEBUG_MISC, "=> token, url parsing failed\n");
free(url);
free(tokenid);
errno = EINVAL;
return -1;
}
}
if (!path) {
gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for token url\n");
free(url);
free(tokenid);
return -1;
}
if (!(headers = gg_saprintf("Host: %s\r\nUser-Agent: " GG_HTTP_USERAGENT "\r\n\r\n", host))) {
gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for token url\n");
free(path);
free(url);
free(tokenid);
return -1;
}
if (!(h2 = gg_http_connect(host, GG_REGISTER_PORT, h->async, "GET", path, headers))) {
gg_debug(GG_DEBUG_MISC, "=> token, gg_http_connect() failed mysteriously\n");
free(headers);
free(url);
free(path);
free(tokenid);
return -1;
}
free(headers);
free(path);
free(url);
memcpy(h, h2, sizeof(struct gg_http));
free(h2);
h->type = GG_SESSION_TOKEN;
h->callback = gg_token_watch_fd;
h->destroy = gg_token_free;
if (!h->async)
gg_token_watch_fd(h);
if (!(h->data = t = malloc(sizeof(struct gg_token)))) {
gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for token data\n");
free(tokenid);
return -1;
}
t->width = width;
t->height = height;
t->length = length;
t->tokenid = tokenid;
} else {
/* obrazek mamy w h->body */
h->state = GG_STATE_DONE;
}
return 0;
}
/*
* gg_token_free()
*
* zwalnia pami<6D><69> po efektach pobierania tokenu.
*
* - h - zwalniana struktura
*/
void gg_token_free(struct gg_http *h)
{
struct gg_token *t;
if (!h)
return;
if ((t = h->data))
free(t->tokenid);
free(h->data);
gg_http_free(h);
}
/*
* Local variables:
* c-indentation-style: k&r
* c-basic-offset: 8
* indent-tabs-mode: notnil
* End:
*
* vim: shiftwidth=8:
*/