4 * (C) Copyright 2001-2006 Wojtek Kaniewski <wojtekka@irc.pl>
5 * Dawid Jarosz <dawjar@poczta.onet.pl>
6 * Adam Wysocki <gophi@ekg.chmurka.net>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU Lesser General Public License Version
10 * 2.1 as published by the Free Software Foundation.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
26 * \brief Obsługa katalogu publicznego
38 * Rejestruje nowego użytkownika.
40 * Wymaga wcześniejszego pobrania tokenu za pomocą \c gg_token().
42 * \param email Adres e-mail
43 * \param password Hasło
44 * \param tokenid Identyfikator tokenu
45 * \param tokenval Zawartość tokenu
46 * \param async Flaga połączenia asynchronicznego
48 * \return Struktura \c gg_http lub \c NULL w przypadku błędu
52 struct gg_http
*gg_register3(const char *email
, const char *password
,
53 const char *tokenid
, const char *tokenval
, int async
)
56 char *__pwd
, *__email
, *__tokenid
, *__tokenval
, *form
, *query
;
58 if (!email
|| !password
|| !tokenid
|| !tokenval
) {
59 gg_debug(GG_DEBUG_MISC
, "=> register, NULL parameter\n");
64 __pwd
= gg_urlencode(password
);
65 __email
= gg_urlencode(email
);
66 __tokenid
= gg_urlencode(tokenid
);
67 __tokenval
= gg_urlencode(tokenval
);
69 if (!__pwd
|| !__email
|| !__tokenid
|| !__tokenval
) {
70 gg_debug(GG_DEBUG_MISC
, "=> register, not enough memory for form fields\n");
78 form
= gg_saprintf("pwd=%s&email=%s&tokenid=%s&tokenval=%s&code=%u",
79 __pwd
, __email
, __tokenid
, __tokenval
,
80 gg_http_hash("ss", email
, password
));
88 gg_debug(GG_DEBUG_MISC
, "=> register, not enough memory for form query\n");
92 gg_debug(GG_DEBUG_MISC
, "=> register, %s\n", form
);
95 "Host: " GG_REGISTER_HOST
"\r\n"
96 "Content-Type: application/x-www-form-urlencoded\r\n"
97 "User-Agent: " GG_HTTP_USERAGENT
"\r\n"
98 "Content-Length: %d\r\n"
99 "Pragma: no-cache\r\n"
102 (int) strlen(form
), form
);
107 gg_debug(GG_DEBUG_MISC
, "=> register, not enough memory for query\n");
111 if (!(h
= gg_http_connect(GG_REGISTER_HOST
, GG_REGISTER_PORT
, async
,
112 "POST", "/appsvc/fmregister3.asp", query
)))
114 gg_debug(GG_DEBUG_MISC
, "=> register, gg_http_connect() failed mysteriously\n");
119 h
->type
= GG_SESSION_REGISTER
;
123 h
->callback
= gg_pubdir_watch_fd
;
124 h
->destroy
= gg_pubdir_free
;
127 gg_pubdir_watch_fd(h
);
135 * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia.
137 * Operacja będzie zakończona, gdy pole \c state będzie równe \c GG_STATE_DONE.
138 * Jeśli wystąpi błąd, \c state będzie równe \c GG_STATE_ERROR, a kod błędu
139 * znajdzie się w polu \c error.
141 * \note W rzeczywistości funkcja jest makrem rozwijanym do
142 * \c gg_pubdir_watch_fd().
144 * \param h Struktura połączenia
146 * \return 0 jeśli się powiodło, -1 w przypadku błędu
150 int gg_register_watch_fd(struct gg_httpd
*h
)
152 return gg_pubdir_watch_fd(h
);
156 * Zwalnia zasoby po operacji.
158 * \note W rzeczywistości funkcja jest makrem rozwijanym do \c gg_pubdir_free().
160 * \param h Struktura połączenia
164 void gg_register_free(struct gg_http
*h
)
166 return gg_pubdir_free(h
);
174 * Wymaga wcześniejszego pobrania tokenu za pomocą \c gg_token().
176 * \param uin Numer Gadu-Gadu
177 * \param password Hasło
178 * \param tokenid Identyfikator tokenu
179 * \param tokenval Zawartość tokenu
180 * \param async Flaga połączenia asynchronicznego
182 * \return Struktura \c gg_http lub \c NULL w przypadku błędu
184 * \ingroup unregister
186 struct gg_http
*gg_unregister3(uin_t uin
, const char *password
, const char *tokenid
, const char *tokenval
, int async
)
189 char *__fmpwd
, *__pwd
, *__tokenid
, *__tokenval
, *form
, *query
;
191 if (!password
|| !tokenid
|| !tokenval
) {
192 gg_debug(GG_DEBUG_MISC
, "=> unregister, NULL parameter\n");
197 __pwd
= gg_saprintf("%d", rand());
198 __fmpwd
= gg_urlencode(password
);
199 __tokenid
= gg_urlencode(tokenid
);
200 __tokenval
= gg_urlencode(tokenval
);
202 if (!__fmpwd
|| !__pwd
|| !__tokenid
|| !__tokenval
) {
203 gg_debug(GG_DEBUG_MISC
, "=> unregister, not enough memory for form fields\n");
211 form
= gg_saprintf("fmnumber=%d&fmpwd=%s&delete=1&pwd=%s&"
212 "email=deletedaccount@gadu-gadu.pl&tokenid=%s&tokenval=%s&"
213 "code=%u", uin
, __fmpwd
, __pwd
, __tokenid
, __tokenval
,
214 gg_http_hash("ss", "deletedaccount@gadu-gadu.pl", __pwd
));
222 gg_debug(GG_DEBUG_MISC
, "=> unregister, not enough memory for form query\n");
226 gg_debug(GG_DEBUG_MISC
, "=> unregister, %s\n", form
);
229 "Host: " GG_REGISTER_HOST
"\r\n"
230 "Content-Type: application/x-www-form-urlencoded\r\n"
231 "User-Agent: " GG_HTTP_USERAGENT
"\r\n"
232 "Content-Length: %d\r\n"
233 "Pragma: no-cache\r\n"
236 (int) strlen(form
), form
);
241 gg_debug(GG_DEBUG_MISC
, "=> unregister, not enough memory for query\n");
245 if (!(h
= gg_http_connect(GG_REGISTER_HOST
, GG_REGISTER_PORT
, async
,
246 "POST", "/appsvc/fmregister3.asp", query
)))
248 gg_debug(GG_DEBUG_MISC
, "=> unregister, gg_http_connect() failed mysteriously\n");
253 h
->type
= GG_SESSION_UNREGISTER
;
257 h
->callback
= gg_pubdir_watch_fd
;
258 h
->destroy
= gg_pubdir_free
;
261 gg_pubdir_watch_fd(h
);
269 * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia.
271 * Operacja będzie zakończona, gdy pole \c state będzie równe \c GG_STATE_DONE.
272 * Jeśli wystąpi błąd, \c state będzie równe \c GG_STATE_ERROR, a kod błędu
273 * znajdzie się w polu \c error.
275 * \note W rzeczywistości funkcja jest makrem rozwijanym do
276 * \c gg_pubdir_watch_fd().
278 * \param h Struktura połączenia
280 * \return 0 jeśli się powiodło, -1 w przypadku błędu
282 * \ingroup unregister
284 int gg_unregister_watch_fd(struct gg_httpd
*h
)
286 return gg_pubdir_watch_fd(h
);
290 * Zwalnia zasoby po operacji.
292 * \note W rzeczywistości funkcja jest makrem rozwijanym do \c gg_pubdir_free().
294 * \param h Struktura połączenia
296 * \ingroup unregister
298 void gg_unregister_free(struct gg_http
*h
)
300 return gg_pubdir_free(h
);
306 * Zmienia hasło użytkownika.
308 * Wymaga wcześniejszego pobrania tokenu za pomocą \c gg_token().
310 * \param uin Numer Gadu-Gadu
311 * \param email Adres e-mail
312 * \param passwd Obecne hasło
313 * \param newpasswd Nowe hasło
314 * \param tokenid Identyfikator tokenu
315 * \param tokenval Zawartość tokenu
316 * \param async Flaga połączenia asynchronicznego
318 * \return Struktura \c gg_http lub \c NULL w przypadku błędu
322 struct gg_http
*gg_change_passwd4(uin_t uin
, const char *email
,
323 const char *passwd
, const char *newpasswd
, const char *tokenid
,
324 const char *tokenval
, int async
)
327 char *form
, *query
, *__email
, *__fmpwd
, *__pwd
, *__tokenid
, *__tokenval
;
329 if (!uin
|| !email
|| !passwd
|| !newpasswd
|| !tokenid
|| !tokenval
) {
330 gg_debug(GG_DEBUG_MISC
, "=> change, NULL parameter\n");
335 __fmpwd
= gg_urlencode(passwd
);
336 __pwd
= gg_urlencode(newpasswd
);
337 __email
= gg_urlencode(email
);
338 __tokenid
= gg_urlencode(tokenid
);
339 __tokenval
= gg_urlencode(tokenval
);
341 if (!__fmpwd
|| !__pwd
|| !__email
|| !__tokenid
|| !__tokenval
) {
342 gg_debug(GG_DEBUG_MISC
, "=> change, not enough memory for form fields\n");
351 if (!(form
= gg_saprintf("fmnumber=%d&fmpwd=%s&pwd=%s&email=%s&"
352 "tokenid=%s&tokenval=%s&code=%u", uin
, __fmpwd
, __pwd
, __email
,
353 __tokenid
, __tokenval
, gg_http_hash("ss", email
, newpasswd
))))
355 gg_debug(GG_DEBUG_MISC
, "=> change, not enough memory for form fields\n");
371 gg_debug(GG_DEBUG_MISC
, "=> change, %s\n", form
);
374 "Host: " GG_REGISTER_HOST
"\r\n"
375 "Content-Type: application/x-www-form-urlencoded\r\n"
376 "User-Agent: " GG_HTTP_USERAGENT
"\r\n"
377 "Content-Length: %d\r\n"
378 "Pragma: no-cache\r\n"
381 (int) strlen(form
), form
);
386 gg_debug(GG_DEBUG_MISC
, "=> change, not enough memory for query\n");
390 if (!(h
= gg_http_connect(GG_REGISTER_HOST
, GG_REGISTER_PORT
, async
,
391 "POST", "/appsvc/fmregister3.asp", query
)))
393 gg_debug(GG_DEBUG_MISC
, "=> change, gg_http_connect() failed mysteriously\n");
398 h
->type
= GG_SESSION_PASSWD
;
402 h
->callback
= gg_pubdir_watch_fd
;
403 h
->destroy
= gg_pubdir_free
;
406 gg_pubdir_watch_fd(h
);
414 * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia.
416 * Operacja będzie zakończona, gdy pole \c state będzie równe \c GG_STATE_DONE.
417 * Jeśli wystąpi błąd, \c state będzie równe \c GG_STATE_ERROR, a kod błędu
418 * znajdzie się w polu \c error.
420 * \note W rzeczywistości funkcja jest makrem rozwijanym do
421 * \c gg_pubdir_watch_fd().
423 * \param h Struktura połączenia
425 * \return 0 jeśli się powiodło, -1 w przypadku błędu
429 int gg_change_passwd_watch_fd(struct gg_httpd
*h
)
431 return gg_pubdir_watch_fd(h
);
435 * Zwalnia zasoby po operacji.
437 * \note W rzeczywistości funkcja jest makrem rozwijanym do \c gg_pubdir_free().
439 * \param h Struktura połączenia
443 void gg_change_passwd_free(struct gg_http
*h
)
445 return gg_pubdir_free(h
);
451 * Wysyła hasło użytkownika na e-mail.
453 * Wymaga wcześniejszego pobrania tokenu za pomocą \c gg_token().
455 * \param uin Numer Gadu-Gadu
456 * \param email Adres e-mail (podany przy rejestracji)
457 * \param tokenid Identyfikator tokenu
458 * \param tokenval Zawartość tokenu
459 * \param async Flaga połączenia asynchronicznego
461 * \return Struktura \c gg_http lub \c NULL w przypadku błędu
465 struct gg_http
*gg_remind_passwd3(uin_t uin
, const char *email
, const char *tokenid
, const char *tokenval
, int async
)
468 char *form
, *query
, *__tokenid
, *__tokenval
, *__email
;
470 if (!tokenid
|| !tokenval
|| !email
) {
471 gg_debug(GG_DEBUG_MISC
, "=> remind, NULL parameter\n");
476 __tokenid
= gg_urlencode(tokenid
);
477 __tokenval
= gg_urlencode(tokenval
);
478 __email
= gg_urlencode(email
);
480 if (!__tokenid
|| !__tokenval
|| !__email
) {
481 gg_debug(GG_DEBUG_MISC
, "=> remind, not enough memory for form fields\n");
488 if (!(form
= gg_saprintf("userid=%d&code=%u&tokenid=%s&tokenval=%s&"
489 "email=%s", uin
, gg_http_hash("u", uin
), __tokenid
, __tokenval
,
492 gg_debug(GG_DEBUG_MISC
, "=> remind, not enough memory for form fields\n");
503 gg_debug(GG_DEBUG_MISC
, "=> remind, %s\n", form
);
506 "Host: " GG_REMIND_HOST
"\r\n"
507 "Content-Type: application/x-www-form-urlencoded\r\n"
508 "User-Agent: " GG_HTTP_USERAGENT
"\r\n"
509 "Content-Length: %d\r\n"
510 "Pragma: no-cache\r\n"
513 (int) strlen(form
), form
);
518 gg_debug(GG_DEBUG_MISC
, "=> remind, not enough memory for query\n");
522 if (!(h
= gg_http_connect(GG_REMIND_HOST
, GG_REMIND_PORT
, async
, "POST", "/appsvc/fmsendpwd3.asp", query
))) {
523 gg_debug(GG_DEBUG_MISC
, "=> remind, gg_http_connect() failed mysteriously\n");
528 h
->type
= GG_SESSION_REMIND
;
532 h
->callback
= gg_pubdir_watch_fd
;
533 h
->destroy
= gg_pubdir_free
;
536 gg_pubdir_watch_fd(h
);
544 * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia.
546 * Operacja będzie zakończona, gdy pole \c state będzie równe \c GG_STATE_DONE.
547 * Jeśli wystąpi błąd, \c state będzie równe \c GG_STATE_ERROR, a kod błędu
548 * znajdzie się w polu \c error.
550 * \note W rzeczywistości funkcja jest makrem rozwijanym do
551 * \c gg_pubdir_watch_fd().
553 * \param h Struktura połączenia
555 * \return 0 jeśli się powiodło, -1 w przypadku błędu
559 int gg_remind_watch_fd(struct gg_httpd
*h
)
561 return gg_pubdir_watch_fd(h
);
565 * Zwalnia zasoby po operacji.
567 * \note W rzeczywistości funkcja jest makrem rozwijanym do \c gg_pubdir_free().
569 * \param h Struktura połączenia
573 void gg_remind_free(struct gg_http
*h
)
575 return gg_pubdir_free(h
);
581 * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia.
583 * Operacja będzie zakończona, gdy pole \c state będzie równe \c GG_STATE_DONE.
584 * Jeśli wystąpi błąd, \c state będzie równe \c GG_STATE_ERROR, a kod błędu
585 * znajdzie się w polu \c error.
587 * \param h Struktura połączenia
589 * \return 0 jeśli się powiodło, -1 w przypadku błędu
591 int gg_pubdir_watch_fd(struct gg_http
*h
)
601 if (h
->state
== GG_STATE_ERROR
) {
602 gg_debug(GG_DEBUG_MISC
, "=> pubdir, watch_fd issued on failed session\n");
607 if (h
->state
!= GG_STATE_PARSING
) {
608 if (gg_http_watch_fd(h
) == -1) {
609 gg_debug(GG_DEBUG_MISC
, "=> pubdir, http failure\n");
615 if (h
->state
!= GG_STATE_PARSING
)
618 h
->state
= GG_STATE_DONE
;
620 if (!(h
->data
= p
= malloc(sizeof(struct gg_pubdir
)))) {
621 gg_debug(GG_DEBUG_MISC
, "=> pubdir, not enough memory for results\n");
628 gg_debug(GG_DEBUG_MISC
, "=> pubdir, let's parse \"%s\"\n", h
->body
);
630 if ((tmp
= strstr(h
->body
, "Tokens okregisterreply_packet.reg.dwUserId="))) {
632 p
->uin
= strtol(tmp
+ sizeof("Tokens okregisterreply_packet.reg.dwUserId=") - 1, NULL
, 0);
633 p
->error
= GG_PUBDIR_ERROR_NONE
;
634 gg_debug(GG_DEBUG_MISC
, "=> pubdir, success (okregisterreply, uin=%d)\n", p
->uin
);
635 } else if ((tmp
= strstr(h
->body
, "success")) || (tmp
= strstr(h
->body
, "results"))) {
638 p
->uin
= strtol(tmp
+ 8, NULL
, 0);
639 p
->error
= GG_PUBDIR_ERROR_NONE
;
640 gg_debug(GG_DEBUG_MISC
, "=> pubdir, success (uin=%d)\n", p
->uin
);
641 } else if (strncmp(h
->body
, "error1", 6) == 0 || strncmp(h
->body
, "error3", 6) == 0) {
642 p
->error
= GG_PUBDIR_ERROR_NEW_PASSWORD
;
643 gg_debug(GG_DEBUG_MISC
, "=> pubdir, invalid new password\n");
644 } else if (strncmp(h
->body
, "not authenticated", 17) == 0) {
645 p
->error
= GG_PUBDIR_ERROR_OLD_PASSWORD
;
646 gg_debug(GG_DEBUG_MISC
, "=> pubdir, invalid old password\n");
647 } else if (strncmp(h
->body
, "bad_tokenval", 12) == 0) {
648 p
->error
= GG_PUBDIR_ERROR_TOKEN
;
649 gg_debug(GG_DEBUG_MISC
, "=> pubdir, invalid token\n");
651 p
->error
= GG_PUBDIR_ERROR_OTHER
;
652 gg_debug(GG_DEBUG_MISC
, "=> pubdir, unknown error\n");
659 * Zwalnia zasoby po operacji na katalogu publicznym.
661 * \param h Struktura połączenia
663 void gg_pubdir_free(struct gg_http
*h
)
673 * Pobiera token do autoryzacji operacji na katalogu publicznym.
675 * Token jest niezbędny do tworzenia nowego i usuwania użytkownika,
678 * \param async Flaga połączenia asynchronicznego
680 * \return Struktura \c gg_http lub \c NULL w przypadku błędu
684 struct gg_http
*gg_token(int async
)
689 query
= "Host: " GG_REGISTER_HOST
"\r\n"
690 "Content-Type: application/x-www-form-urlencoded\r\n"
691 "User-Agent: " GG_HTTP_USERAGENT
"\r\n"
692 "Content-Length: 0\r\n"
693 "Pragma: no-cache\r\n"
696 if (!(h
= gg_http_connect(GG_REGISTER_HOST
, GG_REGISTER_PORT
, async
, "POST", "/appsvc/regtoken.asp", query
))) {
697 gg_debug(GG_DEBUG_MISC
, "=> token, gg_http_connect() failed mysteriously\n");
701 h
->type
= GG_SESSION_TOKEN
;
703 h
->callback
= gg_token_watch_fd
;
704 h
->destroy
= gg_token_free
;
707 gg_token_watch_fd(h
);
713 * Funkcja wywoływana po zaobserwowaniu zmian na deskryptorze połączenia.
715 * Operacja będzie zakończona, gdy pole \c state będzie równe \c GG_STATE_DONE.
716 * Jeśli wystąpi błąd, \c state będzie równe \c GG_STATE_ERROR, a kod błędu
717 * znajdzie się w polu \c error.
719 * \param h Struktura połączenia
721 * \return 0 jeśli się powiodło, -1 w przypadku błędu
725 int gg_token_watch_fd(struct gg_http
*h
)
732 if (h
->state
== GG_STATE_ERROR
) {
733 gg_debug(GG_DEBUG_MISC
, "=> token, watch_fd issued on failed session\n");
738 if (h
->state
!= GG_STATE_PARSING
) {
739 if (gg_http_watch_fd(h
) == -1) {
740 gg_debug(GG_DEBUG_MISC
, "=> token, http failure\n");
746 if (h
->state
!= GG_STATE_PARSING
)
749 /* jeśli h->data jest puste, to ściągaliśmy tokenid i url do niego,
750 * ale jeśli coś tam jest, to znaczy, że mamy drugi etap polegający
751 * na pobieraniu tokenu. */
753 int width
, height
, length
;
754 char *url
= NULL
, *tokenid
= NULL
, *path
, *headers
;
760 gg_debug(GG_DEBUG_MISC
, "=> token body \"%s\"\n", h
->body
);
762 results_len
= h
->body
? strlen(h
->body
) : 0;
764 if (h
->body
&& (!(url
= malloc(results_len
)) || !(tokenid
= malloc(results_len
)))) {
765 gg_debug(GG_DEBUG_MISC
, "=> token, not enough memory for results\n");
770 if (!h
->body
|| sscanf(h
->body
, "%d %d %d\r\n%s\r\n%s", &width
, &height
, &length
, tokenid
, url
) != 5) {
771 gg_debug(GG_DEBUG_MISC
, "=> token, parsing failed\n");
778 /* dostaliśmy tokenid i wszystkie niezbędne informacje,
779 * więc pobierzmy obrazek z tokenem */
781 if (strncmp(url
, "http://", 7)) {
782 path
= gg_saprintf("%s?tokenid=%s", url
, tokenid
);
783 host
= GG_REGISTER_HOST
;
785 char *slash
= strchr(url
+ 7, '/');
788 path
= gg_saprintf("%s?tokenid=%s", slash
, tokenid
);
792 gg_debug(GG_DEBUG_MISC
, "=> token, url parsing failed\n");
801 gg_debug(GG_DEBUG_MISC
, "=> token, not enough memory for token url\n");
807 if (!(headers
= gg_saprintf("Host: %s\r\nUser-Agent: " GG_HTTP_USERAGENT
"\r\n\r\n", host
))) {
808 gg_debug(GG_DEBUG_MISC
, "=> token, not enough memory for token url\n");
815 if (!(h2
= gg_http_connect(host
, GG_REGISTER_PORT
, h
->async
, "GET", path
, headers
))) {
816 gg_debug(GG_DEBUG_MISC
, "=> token, gg_http_connect() failed mysteriously\n");
828 gg_http_free_fields(h
);
830 memcpy(h
, h2
, sizeof(struct gg_http
));
833 h
->type
= GG_SESSION_TOKEN
;
835 h
->callback
= gg_token_watch_fd
;
836 h
->destroy
= gg_token_free
;
839 gg_token_watch_fd(h
);
841 if (!(h
->data
= t
= malloc(sizeof(struct gg_token
)))) {
842 gg_debug(GG_DEBUG_MISC
, "=> token, not enough memory for token data\n");
850 t
->tokenid
= tokenid
;
852 /* obrazek mamy w h->body */
853 h
->state
= GG_STATE_DONE
;
860 * Zwalnia zasoby po operacji pobierania tokenu.
862 * \param h Struktura połączenia
866 void gg_token_free(struct gg_http
*h
)
882 * c-indentation-style: k&r
884 * indent-tabs-mode: notnil