Пример #1
0
/**
 * Rozpoczyna połączenie HTTP.
 *
 * Funkcja przeprowadza połączenie HTTP przy połączeniu synchronicznym,
 * zwracając wynik w polach struktury \c gg_http, lub błąd, gdy sesja się
 * nie powiedzie.
 *
 * Przy połączeniu asynchronicznym, funkcja rozpoczyna połączenie, a dalsze
 * etapy będą przeprowadzane po wykryciu zmian (\c watch) na obserwowanym
 * deskryptorze (\c fd) i wywołaniu funkcji \c gg_http_watch_fd().
 *
 * Po zakończeniu, należy zwolnić strukturę za pomocą funkcji
 * \c gg_http_free(). Połączenie asynchroniczne można zatrzymać w każdej
 * chwili za pomocą \c gg_http_stop().
 *
 * \param hostname Adres serwera
 * \param port Port serwera
 * \param async Flaga asynchronicznego połączenia
 * \param method Metoda HTTP
 * \param path Ścieżka do zasobu (musi być poprzedzona znakiem '/')
 * \param header Nagłówek zapytania plus ewentualne dane dla POST
 *
 * \return Zaalokowana struktura \c gg_http lub NULL, jeśli wystąpił błąd.
 *
 * \ingroup http
 */
struct gg_http *gg_http_connect(const char *hostname, int port, int async, const char *method, const char *path, const char *header)
{
	struct gg_http *h;

	if (!hostname || !port || !method || !path || !header) {
		gg_debug(GG_DEBUG_MISC, "// gg_http_connect() invalid arguments\n");
		errno = EFAULT;
		return NULL;
	}

	if (!(h = malloc(sizeof(*h))))
		return NULL;
	memset(h, 0, sizeof(*h));

	h->async = async;
	h->port = port;
	h->fd = -1;
	h->type = GG_SESSION_HTTP;

	gg_http_set_resolver(h, GG_RESOLVER_DEFAULT);

	if (gg_proxy_enabled) {
		char *auth = gg_proxy_auth();

		h->query = gg_saprintf("%s http://%s:%d%s HTTP/1.0\r\n%s%s",
				method, hostname, port, path, (auth) ? auth :
				"", header);
		hostname = gg_proxy_host;
		h->port = port = gg_proxy_port;
		free(auth);

	} else {
		h->query = gg_saprintf("%s %s HTTP/1.0\r\n%s",
				method, path, header);
	}

	if (!h->query) {
		gg_debug(GG_DEBUG_MISC, "// gg_http_connect() not enough memory for query\n");
		free(h);
		errno = ENOMEM;
		return NULL;
	}

	gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", h->query);

	if (async) {
		if (h->resolver_start(&h->fd, &h->resolver, hostname) == -1) {
			gg_debug(GG_DEBUG_MISC, "// gg_http_connect() resolver failed\n");
			gg_http_free(h);
			errno = ENOENT;
			return NULL;
		}

		gg_debug(GG_DEBUG_MISC, "// gg_http_connect() resolver = %p\n", h->resolver);

		h->state = GG_STATE_RESOLVING;
		h->check = GG_CHECK_READ;
		h->timeout = GG_DEFAULT_TIMEOUT;
	} else {
		struct in_addr addr;

		if (gg_gethostbyname(hostname, &addr, 0) == -1) {
			gg_debug(GG_DEBUG_MISC, "// gg_http_connect() host not found\n");
			gg_http_free(h);
			errno = ENOENT;
			return NULL;
		}

		if (!(h->fd = gg_connect(&addr, port, 0)) == -1) {
			gg_debug(GG_DEBUG_MISC, "// gg_http_connect() connection failed (errno=%d, %s)\n", errno, strerror(errno));
			gg_http_free(h);
			return NULL;
		}

		h->state = GG_STATE_CONNECTING;

		while (h->state != GG_STATE_ERROR && h->state != GG_STATE_PARSING) {
			if (gg_http_watch_fd(h) == -1)
				break;
		}

		if (h->state != GG_STATE_PARSING) {
			gg_debug(GG_DEBUG_MISC, "// gg_http_connect() some strange error\n");
			gg_http_free(h);
			return NULL;
		}
	}

	h->callback = gg_http_watch_fd;
	h->destroy = gg_http_free;

	return h;
}
Пример #2
0
/**
 * Rejestruje nowego użytkownika.
 *
 * Wymaga wcześniejszego pobrania tokenu za pomocą \c gg_token().
 *
 * \param email Adres e-mail
 * \param password Hasło
 * \param tokenid Identyfikator tokenu
 * \param tokenval Zawartość tokenu
 * \param async Flaga połączenia asynchronicznego
 *
 * \return Struktura \c gg_http lub \c NULL w przypadku błędu
 *
 * \ingroup register
 */
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;
}
Пример #3
0
/**
 * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia.
 *
 * Operacja będzie zakończona, gdy pole \c state będzie równe \c GG_STATE_DONE.
 * Jeśli wystąpi błąd, \c state będzie równe \c GG_STATE_ERROR, a kod błędu
 * znajdzie się w polu \c error.
 *
 * \param h Struktura połączenia
 *
 * \return 0 jeśli się powiodło, -1 w przypadku błędu
 *
 * \ingroup token
 */
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śli h->data jest puste, to ściągaliśmy tokenid i url do niego,
	 * ale jeśli coś tam jest, to znaczy, że mamy drugi etap polegający
	 * na pobieraniu tokenu. */
	if (!h->data) {
		int width, height, length;
		char *url = NULL, *tokenid = NULL, *path, *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 = (char*)malloc(strlen(h->body) + 1)) || !(tokenid = (char*)malloc(strlen(h->body) + 1)))) {
			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śmy tokenid i wszystkie niezbędne informacje,
		 * wię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 = 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);

		gg_http_free_fields(h);

		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 = (struct gg_token*)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;
}
Пример #4
0
/**
 * Wysyła hasło użytkownika na e-mail.
 *
 * Wymaga wcześniejszego pobrania tokenu za pomocą \c gg_token().
 *
 * \param uin Numer Gadu-Gadu
 * \param email Adres e-mail (podany przy rejestracji)
 * \param tokenid Identyfikator tokenu
 * \param tokenval Zawartość tokenu
 * \param async Flaga połączenia asynchronicznego
 *
 * \return Struktura \c gg_http lub \c NULL w przypadku błędu
 *
 * \ingroup remind
 */
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;
}
Пример #5
0
/*
 * gg_http_connect() // funkcja pomocnicza
 *
 * rozpoczyna po³±czenie po http.
 *
 *  - hostname - adres serwera
 *  - port - port serwera
 *  - async - asynchroniczne po³±czenie
 *  - method - metoda http (GET, POST, cokolwiek)
 *  - path - ¶cie¿ka do zasobu (musi byæ poprzedzona ,,/'')
 *  - header - nag³ówek zapytania plus ewentualne dane dla POST
 *
 * zaalokowana struct gg_http, któr± po¼niej nale¿y
 * zwolniæ funkcj± gg_http_free(), albo NULL je¶li wyst±pi³ b³±d.
 */
struct gg_http *gg_http_connect(const char *hostname, int port, int async, const char *method, const char *path, const char *header)
{
	struct gg_http *h;

	if (!hostname || !port || !method || !path || !header) {
		gg_debug(GG_DEBUG_MISC, "// gg_http_connect() invalid arguments\n");
		errno = EFAULT;
		return NULL;
	}
	
	if (!(h = malloc(sizeof(*h))))
		return NULL;
	memset(h, 0, sizeof(*h));

	h->async = async;
	h->port = port;
	h->fd = -1;
	h->type = GG_SESSION_HTTP;

	if (gg_proxy_enabled) {
		char *auth = gg_proxy_auth();

		h->query = gg_saprintf("%s http://%s:%d%s HTTP/1.0\r\n%s%s",
				method, hostname, port, path, (auth) ? auth :
				"", header);
		hostname = gg_proxy_host;
		h->port = port = gg_proxy_port;

		if (auth)
			free(auth);
	} else {
		h->query = gg_saprintf("%s %s HTTP/1.0\r\n%s",
				method, path, header);
	}

	if (!h->query) {
		gg_debug(GG_DEBUG_MISC, "// gg_http_connect() not enough memory for query\n");
		free(h);
		errno = ENOMEM;
		return NULL;
	}
	
	gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-QUERY-----\n%s\n=> -----END-HTTP-QUERY-----\n", h->query);

	if (async) {
#ifndef __GG_LIBGADU_HAVE_PTHREAD
		if (gg_resolve(&h->fd, &h->pid, hostname)) {
#else
		if (gg_resolve_pthread(&h->fd, &h->resolver, hostname)) {
#endif
			gg_debug(GG_DEBUG_MISC, "// gg_http_connect() resolver failed\n");
			gg_http_free(h);
			errno = ENOENT;
			return NULL;
		}

		gg_debug(GG_DEBUG_MISC, "// gg_http_connect() resolver = %p\n", h->resolver);

		h->state = GG_STATE_RESOLVING;
		h->check = GG_CHECK_READ;
		h->timeout = GG_DEFAULT_TIMEOUT;
	} else {
		struct in_addr *hn, a;

		if (!(hn = gg_gethostbyname(hostname))) {
			gg_debug(GG_DEBUG_MISC, "// gg_http_connect() host not found\n");
			gg_http_free(h);
			errno = ENOENT;
			return NULL;
		} else {
			a.s_addr = hn->s_addr;
			free(hn);
		}

		if (!(h->fd = gg_connect(&a, port, 0)) == -1) {
			gg_debug(GG_DEBUG_MISC, "// gg_http_connect() connection failed (errno=%d, %s)\n", errno, strerror(errno));
			gg_http_free(h);
			return NULL;
		}

		h->state = GG_STATE_CONNECTING;

		while (h->state != GG_STATE_ERROR && h->state != GG_STATE_PARSING) {
			if (gg_http_watch_fd(h) == -1)
				break;
		}

		if (h->state != GG_STATE_PARSING) {
			gg_debug(GG_DEBUG_MISC, "// gg_http_connect() some strange error\n");
			gg_http_free(h);
			return NULL;
		}
	}

	h->callback = gg_http_watch_fd;
	h->destroy = gg_http_free;
	
	return h;
}

#define gg_http_error(x) \
	close(h->fd); \
	h->fd = -1; \
	h->state = GG_STATE_ERROR; \
	h->error = x; \
	return 0;

/*
 * gg_http_watch_fd()
 *
 * przy asynchronicznej obs³udze HTTP funkcjê t± nale¿y wywo³aæ, je¶li
 * zmieni³o siê co¶ na obserwowanym deskryptorze.
 *
 *  - h - struktura opisuj±ca po³±czenie
 *
 * je¶li wszystko posz³o dobrze to 0, inaczej -1. po³±czenie bêdzie
 * zakoñczone, je¶li h->state == GG_STATE_PARSING. je¶li wyst±pi jaki¶
 * b³±d, to bêdzie tam GG_STATE_ERROR i odpowiedni kod b³êdu w h->error.
 */
int gg_http_watch_fd(struct gg_http *h)
{
	gg_debug(GG_DEBUG_FUNCTION, "** gg_http_watch_fd(%p);\n", h);

	if (!h) {
		gg_debug(GG_DEBUG_MISC, "// gg_http_watch_fd() invalid arguments\n");
		errno = EFAULT;
		return -1;
	}

	if (h->state == GG_STATE_RESOLVING) {
		struct in_addr a;

		gg_debug(GG_DEBUG_MISC, "=> http, resolving done\n");

		if (read(h->fd, &a, sizeof(a)) < (signed)sizeof(a) || a.s_addr == INADDR_NONE) {
			gg_debug(GG_DEBUG_MISC, "=> http, resolver thread failed\n");
			gg_http_error(GG_ERROR_RESOLVING);
		}

		close(h->fd);
		h->fd = -1;

#ifndef __GG_LIBGADU_HAVE_PTHREAD
		waitpid(h->pid, NULL, 0);
#else
		if (h->resolver) {
			gg_resolve_pthread_cleanup(h->resolver, 0);
			h->resolver = NULL;
		}
#endif

		gg_debug(GG_DEBUG_MISC, "=> http, connecting to %s:%d\n", inet_ntoa(a), h->port);

		if ((h->fd = gg_connect(&a, h->port, h->async)) == -1) {
			gg_debug(GG_DEBUG_MISC, "=> http, connection failed (errno=%d, %s)\n", errno, strerror(errno));
			gg_http_error(GG_ERROR_CONNECTING);
		}

		h->state = GG_STATE_CONNECTING;
		h->check = GG_CHECK_WRITE;
		h->timeout = GG_DEFAULT_TIMEOUT;

		return 0;
	}

	if (h->state == GG_STATE_CONNECTING) {
		int res = 0;
		unsigned int res_size = sizeof(res);

		if (h->async && (getsockopt(h->fd, SOL_SOCKET, SO_ERROR, &res, &res_size) || res)) {
			gg_debug(GG_DEBUG_MISC, "=> http, async connection failed (errno=%d, %s)\n", (res) ? res : errno , strerror((res) ? res : errno));
			close(h->fd);
			h->fd = -1;
			h->state = GG_STATE_ERROR;
			h->error = GG_ERROR_CONNECTING;
			if (res)
				errno = res;
			return 0;
		}

		gg_debug(GG_DEBUG_MISC, "=> http, connected, sending request\n");

		h->state = GG_STATE_SENDING_QUERY;
	}

	if (h->state == GG_STATE_SENDING_QUERY) {
		int res;

		if ((res = write(h->fd, h->query, strlen(h->query))) < 1) {
			gg_debug(GG_DEBUG_MISC, "=> http, write() failed (len=%d, res=%d, errno=%d)\n", strlen(h->query), res, errno);
			gg_http_error(GG_ERROR_WRITING);
		}

		if (res < strlen(h->query)) {
			gg_debug(GG_DEBUG_MISC, "=> http, partial header sent (led=%d, sent=%d)\n", strlen(h->query), res);

			memmove(h->query, h->query + res, strlen(h->query) - res + 1);
			h->state = GG_STATE_SENDING_QUERY;
			h->check = GG_CHECK_WRITE;
			h->timeout = GG_DEFAULT_TIMEOUT;
		} else {
			gg_debug(GG_DEBUG_MISC, "=> http, request sent (len=%d)\n", strlen(h->query));
			free(h->query);
			h->query = NULL;

			h->state = GG_STATE_READING_HEADER;
			h->check = GG_CHECK_READ;
			h->timeout = GG_DEFAULT_TIMEOUT;
		}

		return 0;
	}

	if (h->state == GG_STATE_READING_HEADER) {
		char buf[1024], *tmp;
		int res;

		if ((res = read(h->fd, buf, sizeof(buf))) == -1) {
			gg_debug(GG_DEBUG_MISC, "=> http, reading header failed (errno=%d)\n", errno);
			if (h->header) {
				free(h->header);
				h->header = NULL;
			}
			gg_http_error(GG_ERROR_READING);
		}

		if (!res) {
			gg_debug(GG_DEBUG_MISC, "=> http, connection reset by peer\n");
			if (h->header) {
				free(h->header);
				h->header = NULL;
			}
			gg_http_error(GG_ERROR_READING);
		}

		gg_debug(GG_DEBUG_MISC, "=> http, read %d bytes of header\n", res);

		if (!(tmp = realloc(h->header, h->header_size + res + 1))) {
			gg_debug(GG_DEBUG_MISC, "=> http, not enough memory for header\n");
			free(h->header);
			h->header = NULL;
			gg_http_error(GG_ERROR_READING);
		}

		h->header = tmp;

		memcpy(h->header + h->header_size, buf, res);
		h->header_size += res;

		gg_debug(GG_DEBUG_MISC, "=> http, header_buf=%p, header_size=%d\n", h->header, h->header_size);

		h->header[h->header_size] = 0;

		if ((tmp = strstr(h->header, "\r\n\r\n")) || (tmp = strstr(h->header, "\n\n"))) {
			int sep_len = (*tmp == '\r') ? 4 : 2;
			unsigned int left;
			char *line;

			left = h->header_size - ((long)(tmp) - (long)(h->header) + sep_len);

			gg_debug(GG_DEBUG_MISC, "=> http, got all header (%d bytes, %d left)\n", h->header_size - left, left);

			/* HTTP/1.1 200 OK */
			if (strlen(h->header) < 16 || strncmp(h->header + 9, "200", 3)) {
				gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-HEADER-----\n%s\n=> -----END-HTTP-HEADER-----\n", h->header);

				gg_debug(GG_DEBUG_MISC, "=> http, didn't get 200 OK -- no results\n");
				free(h->header);
				h->header = NULL;
				gg_http_error(GG_ERROR_CONNECTING);
			}

			h->body_size = 0;
			line = h->header;
			*tmp = 0;
                        
			gg_debug(GG_DEBUG_MISC, "=> -----BEGIN-HTTP-HEADER-----\n%s\n=> -----END-HTTP-HEADER-----\n", h->header);

			while (line) {
				if (!strncasecmp(line, "Content-length: ", 16)) {
					h->body_size = atoi(line + 16);
				}
				line = strchr(line, '\n');
				if (line)
					line++;
			}

			if (h->body_size <= 0) {
				gg_debug(GG_DEBUG_MISC, "=> http, content-length not found\n");
				h->body_size = left;
			}

			if (left > h->body_size) {
				gg_debug(GG_DEBUG_MISC, "=> http, oversized reply (%d bytes needed, %d bytes left)\n", h->body_size, left);
				h->body_size = left;
			}

			gg_debug(GG_DEBUG_MISC, "=> http, body_size=%d\n", h->body_size);

			if (!(h->body = malloc(h->body_size + 1))) {
				gg_debug(GG_DEBUG_MISC, "=> http, not enough memory (%d bytes for body_buf)\n", h->body_size + 1);
				free(h->header);
				h->header = NULL;
				gg_http_error(GG_ERROR_READING);
			}

			if (left) {
				memcpy(h->body, tmp + sep_len, left);
				h->body_done = left;
			}

			h->body[left] = 0;

			h->state = GG_STATE_READING_DATA;
			h->check = GG_CHECK_READ;
			h->timeout = GG_DEFAULT_TIMEOUT;
		}

		return 0;
	}

	if (h->state == GG_STATE_READING_DATA) {
		char buf[1024];
		int res;

		if ((res = read(h->fd, buf, sizeof(buf))) == -1) {
			gg_debug(GG_DEBUG_MISC, "=> http, reading body failed (errno=%d)\n", errno);
			if (h->body) {
				free(h->body);
				h->body = NULL;
			}
			gg_http_error(GG_ERROR_READING);
		}

		if (!res) {
			if (h->body_done >= h->body_size) {
				gg_debug(GG_DEBUG_MISC, "=> http, we're done, closing socket\n");
				h->state = GG_STATE_PARSING;
				close(h->fd);
				h->fd = -1;
			} else {
				gg_debug(GG_DEBUG_MISC, "=> http, connection closed while reading (have %d, need %d)\n", h->body_done, h->body_size);
				if (h->body) {
					free(h->body);
					h->body = NULL;
				}
				gg_http_error(GG_ERROR_READING);
			}

			return 0;
		}

		gg_debug(GG_DEBUG_MISC, "=> http, read %d bytes of body\n", res);

		if (h->body_done + res > h->body_size) {
			char *tmp;

			gg_debug(GG_DEBUG_MISC, "=> http, too much data (%d bytes, %d needed), enlarging buffer\n", h->body_done + res, h->body_size);

			if (!(tmp = realloc(h->body, h->body_done + res + 1))) {
				gg_debug(GG_DEBUG_MISC, "=> http, not enough memory for data (%d needed)\n", h->body_done + res + 1);
				free(h->body);
				h->body = NULL;
				gg_http_error(GG_ERROR_READING);
			}

			h->body = tmp;
			h->body_size = h->body_done + res;
		}

		h->body[h->body_done + res] = 0;
		memcpy(h->body + h->body_done, buf, res);
		h->body_done += res;

		gg_debug(GG_DEBUG_MISC, "=> body_done=%d, body_size=%d\n", h->body_done, h->body_size);

		return 0;
	}
	
	if (h->fd != -1)
		close(h->fd);

	h->fd = -1;
	h->state = GG_STATE_ERROR;
	h->error = 0;

	return -1;
}
Пример #6
0
/*
 * gg_token_watch_fd()
 *
 * przy asynchronicznych operacjach zwi±zanych z tokenem nale¿y wywo³ywaæ
 * tê funkcjê przy zmianach na obserwowanym deskryptorze.
 *
 *  - h - struktura opisuj±ca po³±czenie
 *
 * je¶li wszystko posz³o dobrze to 0, inaczej -1. operacja bêdzie
 * zakoñczona, je¶li h->state == GG_STATE_DONE. je¶li wyst±pi jaki¶
 * b³±d, to bêdzie tam GG_STATE_ERROR i odpowiedni kod b³êdu w h->error.
 */
int gg_token_watch_fd(struct gg_http *h)
{
	if (!h) {
		errno = EINVAL;
		return -1;
	}

        if (h->state == GG_STATE_ERROR) {
                gg_debug(GG_DEBUG_MISC, "=> token, watch_fd issued on failed session\n");
                errno = EINVAL;
                return -1;
        }
	
	if (h->state != GG_STATE_PARSING) {
		if (gg_http_watch_fd(h) == -1) {
			gg_debug(GG_DEBUG_MISC, "=> token, http failure\n");
                        errno = EINVAL;
			return -1;
		}
	}

	if (h->state != GG_STATE_PARSING)
                return 0;
	
	/* je¶li h->data jest puste, to ¶ci±gali¶my tokenid i url do niego,
	 * ale je¶li co¶ tam jest, to znaczy, ¿e mamy drugi etap polegaj±cy
	 * na pobieraniu tokenu. */
	if (!h->data) {
		int width, height, length;
		char *url = NULL, *tokenid = NULL, *path;
		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);
			return -1;
		}
		
		/* dostali¶my tokenid i wszystkie niezbêdne informacje,
		 * wiêc pobierzmy obrazek z tokenem */

		if (!(path = gg_saprintf("%s?tokenid=%s", url, tokenid))) {
			gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for token url\n");
			free(url);
			free(tokenid);
			return -1;
		}

		free(url);
	
		if (!(h2 = gg_http_connect(GG_APPMSG_HOST, GG_APPMSG_PORT, h->async, "GET", path, "Host: " GG_APPMSG_HOST "\r\nUser-Agent: " GG_HTTP_USERAGENT "\r\n\r\n"))) {
			gg_debug(GG_DEBUG_MISC, "=> token, gg_http_connect() failed mysteriously\n");
			free(path);
			free(tokenid);
			return -1;
		}

		free(path);

		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;
}
Пример #7
0
/*
 * gg_change_passwd4()
 *
 * wysy³a ¿±danie zmiany has³a zgodnie z protoko³em GG 6.0. wymaga
 * wcze¶niejszego pobrania tokenu za pomoc± funkcji gg_token().
 *
 *  - uin - numer
 *  - email - adres e-mail
 *  - passwd - stare has³o
 *  - newpasswd - nowe has³o
 *  - tokenid - identyfikator tokenu
 *  - tokenval - warto¶æ tokenu
 *  - async - po³±czenie asynchroniczne
 *
 * zaalokowana struct gg_http, któr± po¼niej nale¿y zwolniæ
 * funkcj± gg_change_passwd_free(), albo NULL je¶li wyst±pi³ b³±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 = EINVAL;
		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);
		errno = ENOMEM;
		return NULL;
	}
	
	if (!(form = gg_saprintf("fmnumber=%d&fmpwd=%s&pwd=%s&email=%s&tokenid=%s&tokenval=%s&code=%u", uin, __fmpwd, __pwd, __email, __tokenid, __tokenval, gg_http_hash("ss", email, newpasswd)))) {
		gg_debug(GG_DEBUG_MISC, "=> change, not enough memory for form fields\n");
		free(__fmpwd);
		free(__pwd);
		free(__email);
		free(__tokenid);
		free(__tokenval);

		errno = ENOMEM;
		return NULL;
	}
	
	free(__fmpwd);
	free(__pwd);
	free(__email);
	free(__tokenid);
	free(__tokenval);
	
	gg_debug(GG_DEBUG_MISC, "=> change, %s\n", form);

        query = gg_saprintf(
		"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 (!(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;
}
Пример #8
0
/*
 * gg_unregister3()
 *
 * usuwa konto u¿ytkownika z serwera protoko³em GG 6.0
 *
 *  - uin - numerek GG
 *  - password - has³o klienta
 *  - tokenid - identyfikator tokenu
 *  - tokenval - warto¶æ tokenu
 *  - async - po³±czenie asynchroniczne
 *
 * zaalokowana struct gg_http, któr± po¼niej nale¿y zwolniæ
 * funkcj± gg_unregister_free(), albo NULL je¶li wyst±pi³ b³±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 = EINVAL;
		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);
                errno = ENOMEM;
		return NULL;
	}

	form = gg_saprintf("fmnumber=%d&fmpwd=%s&delete=1&pwd=%s&[email protected]&tokenid=%s&tokenval=%s&code=%u", uin, __fmpwd, __pwd, __tokenid, __tokenval, gg_http_hash("ss", "*****@*****.**", __pwd));

	free(__fmpwd);
	free(__pwd);
	free(__tokenid);
	free(__tokenval);

	if (!form) {
		gg_debug(GG_DEBUG_MISC, "=> unregister, not enough memory for form query\n");
		errno = ENOMEM;
		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 (!(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;
}