comparison libpurple/protocols/gg/lib/pubdir.c @ 15374:5fe8042783c1

Rename gtk/ and libgaim/ to pidgin/ and libpurple/
author Sean Egan <seanegan@gmail.com>
date Sat, 20 Jan 2007 02:32:10 +0000
parents
children 44b4e8bd759b
comparison
equal deleted inserted replaced
15373:f79e0f4df793 15374:5fe8042783c1
1 /* $Id: pubdir.c 16856 2006-08-19 01:13:25Z evands $ */
2
3 /*
4 * (C) Copyright 2001-2002 Wojtek Kaniewski <wojtekka@irc.pl>
5 * Dawid Jarosz <dawjar@poczta.onet.pl>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License Version
9 * 2.1 as published by the Free Software Foundation.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307,
19 * USA.
20 */
21
22 #include <ctype.h>
23 #include <errno.h>
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29
30 #include "libgadu.h"
31
32 /*
33 * gg_register3()
34 *
35 * rozpoczyna rejestrację użytkownika protokołem GG 6.0. wymaga wcześniejszego
36 * pobrania tokenu za pomocą funkcji gg_token().
37 *
38 * - email - adres e-mail klienta
39 * - password - hasło klienta
40 * - tokenid - identyfikator tokenu
41 * - tokenval - wartość tokenu
42 * - async - połączenie asynchroniczne
43 *
44 * zaalokowana struct gg_http, którą poźniej należy zwolnić
45 * funkcją gg_register_free(), albo NULL jeśli wystąpił błąd.
46 */
47 struct gg_http *gg_register3(const char *email, const char *password, const char *tokenid, const char *tokenval, int async)
48 {
49 struct gg_http *h;
50 char *__pwd, *__email, *__tokenid, *__tokenval, *form, *query;
51
52 if (!email || !password || !tokenid || !tokenval) {
53 gg_debug(GG_DEBUG_MISC, "=> register, NULL parameter\n");
54 errno = EFAULT;
55 return NULL;
56 }
57
58 __pwd = gg_urlencode(password);
59 __email = gg_urlencode(email);
60 __tokenid = gg_urlencode(tokenid);
61 __tokenval = gg_urlencode(tokenval);
62
63 if (!__pwd || !__email || !__tokenid || !__tokenval) {
64 gg_debug(GG_DEBUG_MISC, "=> register, not enough memory for form fields\n");
65 free(__pwd);
66 free(__email);
67 free(__tokenid);
68 free(__tokenval);
69 return NULL;
70 }
71
72 form = gg_saprintf("pwd=%s&email=%s&tokenid=%s&tokenval=%s&code=%u",
73 __pwd, __email, __tokenid, __tokenval,
74 gg_http_hash("ss", email, password));
75
76 free(__pwd);
77 free(__email);
78 free(__tokenid);
79 free(__tokenval);
80
81 if (!form) {
82 gg_debug(GG_DEBUG_MISC, "=> register, not enough memory for form query\n");
83 return NULL;
84 }
85
86 gg_debug(GG_DEBUG_MISC, "=> register, %s\n", form);
87
88 query = gg_saprintf(
89 "Host: " GG_REGISTER_HOST "\r\n"
90 "Content-Type: application/x-www-form-urlencoded\r\n"
91 "User-Agent: " GG_HTTP_USERAGENT "\r\n"
92 "Content-Length: %d\r\n"
93 "Pragma: no-cache\r\n"
94 "\r\n"
95 "%s",
96 (int) strlen(form), form);
97
98 free(form);
99
100 if (!query) {
101 gg_debug(GG_DEBUG_MISC, "=> register, not enough memory for query\n");
102 return NULL;
103 }
104
105 if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/fmregister3.asp", query))) {
106 gg_debug(GG_DEBUG_MISC, "=> register, gg_http_connect() failed mysteriously\n");
107 free(query);
108 return NULL;
109 }
110
111 h->type = GG_SESSION_REGISTER;
112
113 free(query);
114
115 h->callback = gg_pubdir_watch_fd;
116 h->destroy = gg_pubdir_free;
117
118 if (!async)
119 gg_pubdir_watch_fd(h);
120
121 return h;
122 }
123
124 /*
125 * gg_unregister3()
126 *
127 * usuwa konto użytkownika z serwera protokołem GG 6.0
128 *
129 * - uin - numerek GG
130 * - password - hasło klienta
131 * - tokenid - identyfikator tokenu
132 * - tokenval - wartość tokenu
133 * - async - połączenie asynchroniczne
134 *
135 * zaalokowana struct gg_http, którą poźniej należy zwolnić
136 * funkcją gg_unregister_free(), albo NULL jeśli wystąpił błąd.
137 */
138 struct gg_http *gg_unregister3(uin_t uin, const char *password, const char *tokenid, const char *tokenval, int async)
139 {
140 struct gg_http *h;
141 char *__fmpwd, *__pwd, *__tokenid, *__tokenval, *form, *query;
142
143 if (!password || !tokenid || !tokenval) {
144 gg_debug(GG_DEBUG_MISC, "=> unregister, NULL parameter\n");
145 errno = EFAULT;
146 return NULL;
147 }
148
149 __pwd = gg_saprintf("%ld", random());
150 __fmpwd = gg_urlencode(password);
151 __tokenid = gg_urlencode(tokenid);
152 __tokenval = gg_urlencode(tokenval);
153
154 if (!__fmpwd || !__pwd || !__tokenid || !__tokenval) {
155 gg_debug(GG_DEBUG_MISC, "=> unregister, not enough memory for form fields\n");
156 free(__pwd);
157 free(__fmpwd);
158 free(__tokenid);
159 free(__tokenval);
160 return NULL;
161 }
162
163 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));
164
165 free(__fmpwd);
166 free(__pwd);
167 free(__tokenid);
168 free(__tokenval);
169
170 if (!form) {
171 gg_debug(GG_DEBUG_MISC, "=> unregister, not enough memory for form query\n");
172 return NULL;
173 }
174
175 gg_debug(GG_DEBUG_MISC, "=> unregister, %s\n", form);
176
177 query = gg_saprintf(
178 "Host: " GG_REGISTER_HOST "\r\n"
179 "Content-Type: application/x-www-form-urlencoded\r\n"
180 "User-Agent: " GG_HTTP_USERAGENT "\r\n"
181 "Content-Length: %d\r\n"
182 "Pragma: no-cache\r\n"
183 "\r\n"
184 "%s",
185 (int) strlen(form), form);
186
187 free(form);
188
189 if (!query) {
190 gg_debug(GG_DEBUG_MISC, "=> unregister, not enough memory for query\n");
191 return NULL;
192 }
193
194 if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/fmregister3.asp", query))) {
195 gg_debug(GG_DEBUG_MISC, "=> unregister, gg_http_connect() failed mysteriously\n");
196 free(query);
197 return NULL;
198 }
199
200 h->type = GG_SESSION_UNREGISTER;
201
202 free(query);
203
204 h->callback = gg_pubdir_watch_fd;
205 h->destroy = gg_pubdir_free;
206
207 if (!async)
208 gg_pubdir_watch_fd(h);
209
210 return h;
211 }
212
213 /*
214 * gg_change_passwd4()
215 *
216 * wysyła żądanie zmiany hasła zgodnie z protokołem GG 6.0. wymaga
217 * wcześniejszego pobrania tokenu za pomocą funkcji gg_token().
218 *
219 * - uin - numer
220 * - email - adres e-mail
221 * - passwd - stare hasło
222 * - newpasswd - nowe hasło
223 * - tokenid - identyfikator tokenu
224 * - tokenval - wartość tokenu
225 * - async - połączenie asynchroniczne
226 *
227 * zaalokowana struct gg_http, którą poźniej należy zwolnić
228 * funkcją gg_change_passwd_free(), albo NULL jeśli wystąpił błąd.
229 */
230 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)
231 {
232 struct gg_http *h;
233 char *form, *query, *__email, *__fmpwd, *__pwd, *__tokenid, *__tokenval;
234
235 if (!uin || !email || !passwd || !newpasswd || !tokenid || !tokenval) {
236 gg_debug(GG_DEBUG_MISC, "=> change, NULL parameter\n");
237 errno = EFAULT;
238 return NULL;
239 }
240
241 __fmpwd = gg_urlencode(passwd);
242 __pwd = gg_urlencode(newpasswd);
243 __email = gg_urlencode(email);
244 __tokenid = gg_urlencode(tokenid);
245 __tokenval = gg_urlencode(tokenval);
246
247 if (!__fmpwd || !__pwd || !__email || !__tokenid || !__tokenval) {
248 gg_debug(GG_DEBUG_MISC, "=> change, not enough memory for form fields\n");
249 free(__fmpwd);
250 free(__pwd);
251 free(__email);
252 free(__tokenid);
253 free(__tokenval);
254 return NULL;
255 }
256
257 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)))) {
258 gg_debug(GG_DEBUG_MISC, "=> change, not enough memory for form fields\n");
259 free(__fmpwd);
260 free(__pwd);
261 free(__email);
262 free(__tokenid);
263 free(__tokenval);
264
265 return NULL;
266 }
267
268 free(__fmpwd);
269 free(__pwd);
270 free(__email);
271 free(__tokenid);
272 free(__tokenval);
273
274 gg_debug(GG_DEBUG_MISC, "=> change, %s\n", form);
275
276 query = gg_saprintf(
277 "Host: " GG_REGISTER_HOST "\r\n"
278 "Content-Type: application/x-www-form-urlencoded\r\n"
279 "User-Agent: " GG_HTTP_USERAGENT "\r\n"
280 "Content-Length: %d\r\n"
281 "Pragma: no-cache\r\n"
282 "\r\n"
283 "%s",
284 (int) strlen(form), form);
285
286 free(form);
287
288 if (!query) {
289 gg_debug(GG_DEBUG_MISC, "=> change, not enough memory for query\n");
290 return NULL;
291 }
292
293 if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/fmregister3.asp", query))) {
294 gg_debug(GG_DEBUG_MISC, "=> change, gg_http_connect() failed mysteriously\n");
295 free(query);
296 return NULL;
297 }
298
299 h->type = GG_SESSION_PASSWD;
300
301 free(query);
302
303 h->callback = gg_pubdir_watch_fd;
304 h->destroy = gg_pubdir_free;
305
306 if (!async)
307 gg_pubdir_watch_fd(h);
308
309 return h;
310 }
311
312 /*
313 * gg_remind_passwd3()
314 *
315 * wysyła żądanie przypomnienia hasła e-mailem.
316 *
317 * - uin - numer
318 * - email - adres e-mail taki, jak ten zapisany na serwerze
319 * - async - połączenie asynchroniczne
320 * - tokenid - identyfikator tokenu
321 * - tokenval - wartość tokenu
322 *
323 * zaalokowana struct gg_http, którą poźniej należy zwolnić
324 * funkcją gg_remind_passwd_free(), albo NULL jeśli wystąpił błąd.
325 */
326 struct gg_http *gg_remind_passwd3(uin_t uin, const char *email, const char *tokenid, const char *tokenval, int async)
327 {
328 struct gg_http *h;
329 char *form, *query, *__tokenid, *__tokenval, *__email;
330
331 if (!tokenid || !tokenval || !email) {
332 gg_debug(GG_DEBUG_MISC, "=> remind, NULL parameter\n");
333 errno = EFAULT;
334 return NULL;
335 }
336
337 __tokenid = gg_urlencode(tokenid);
338 __tokenval = gg_urlencode(tokenval);
339 __email = gg_urlencode(email);
340
341 if (!__tokenid || !__tokenval || !__email) {
342 gg_debug(GG_DEBUG_MISC, "=> remind, not enough memory for form fields\n");
343 free(__tokenid);
344 free(__tokenval);
345 free(__email);
346 return NULL;
347 }
348
349 if (!(form = gg_saprintf("userid=%d&code=%u&tokenid=%s&tokenval=%s&email=%s", uin, gg_http_hash("u", uin), __tokenid, __tokenval, __email))) {
350 gg_debug(GG_DEBUG_MISC, "=> remind, not enough memory for form fields\n");
351 free(__tokenid);
352 free(__tokenval);
353 free(__email);
354 return NULL;
355 }
356
357 free(__tokenid);
358 free(__tokenval);
359 free(__email);
360
361 gg_debug(GG_DEBUG_MISC, "=> remind, %s\n", form);
362
363 query = gg_saprintf(
364 "Host: " GG_REMIND_HOST "\r\n"
365 "Content-Type: application/x-www-form-urlencoded\r\n"
366 "User-Agent: " GG_HTTP_USERAGENT "\r\n"
367 "Content-Length: %d\r\n"
368 "Pragma: no-cache\r\n"
369 "\r\n"
370 "%s",
371 (int) strlen(form), form);
372
373 free(form);
374
375 if (!query) {
376 gg_debug(GG_DEBUG_MISC, "=> remind, not enough memory for query\n");
377 return NULL;
378 }
379
380 if (!(h = gg_http_connect(GG_REMIND_HOST, GG_REMIND_PORT, async, "POST", "/appsvc/fmsendpwd3.asp", query))) {
381 gg_debug(GG_DEBUG_MISC, "=> remind, gg_http_connect() failed mysteriously\n");
382 free(query);
383 return NULL;
384 }
385
386 h->type = GG_SESSION_REMIND;
387
388 free(query);
389
390 h->callback = gg_pubdir_watch_fd;
391 h->destroy = gg_pubdir_free;
392
393 if (!async)
394 gg_pubdir_watch_fd(h);
395
396 return h;
397 }
398
399 /*
400 * gg_pubdir_watch_fd()
401 *
402 * przy asynchronicznych operacjach na katalogu publicznym należy wywoływać
403 * tę funkcję przy zmianach na obserwowanym deskryptorze.
404 *
405 * - h - struktura opisująca połączenie
406 *
407 * jeśli wszystko poszło dobrze to 0, inaczej -1. operacja będzie
408 * zakończona, jeśli h->state == GG_STATE_DONE. jeśli wystąpi jakiś
409 * błąd, to będzie tam GG_STATE_ERROR i odpowiedni kod błędu w h->error.
410 */
411 int gg_pubdir_watch_fd(struct gg_http *h)
412 {
413 struct gg_pubdir *p;
414 char *tmp;
415
416 if (!h) {
417 errno = EFAULT;
418 return -1;
419 }
420
421 if (h->state == GG_STATE_ERROR) {
422 gg_debug(GG_DEBUG_MISC, "=> pubdir, watch_fd issued on failed session\n");
423 errno = EINVAL;
424 return -1;
425 }
426
427 if (h->state != GG_STATE_PARSING) {
428 if (gg_http_watch_fd(h) == -1) {
429 gg_debug(GG_DEBUG_MISC, "=> pubdir, http failure\n");
430 errno = EINVAL;
431 return -1;
432 }
433 }
434
435 if (h->state != GG_STATE_PARSING)
436 return 0;
437
438 h->state = GG_STATE_DONE;
439
440 if (!(h->data = p = malloc(sizeof(struct gg_pubdir)))) {
441 gg_debug(GG_DEBUG_MISC, "=> pubdir, not enough memory for results\n");
442 return -1;
443 }
444
445 p->success = 0;
446 p->uin = 0;
447
448 gg_debug(GG_DEBUG_MISC, "=> pubdir, let's parse \"%s\"\n", h->body);
449
450 if ((tmp = strstr(h->body, "success")) || (tmp = strstr(h->body, "results"))) {
451 p->success = 1;
452 if (tmp[7] == ':')
453 p->uin = strtol(tmp + 8, NULL, 0);
454 gg_debug(GG_DEBUG_MISC, "=> pubdir, success (uin=%d)\n", p->uin);
455 } else
456 gg_debug(GG_DEBUG_MISC, "=> pubdir, error.\n");
457
458 return 0;
459 }
460
461 /*
462 * gg_pubdir_free()
463 *
464 * zwalnia pamięć po efektach operacji na katalogu publicznym.
465 *
466 * - h - zwalniana struktura
467 */
468 void gg_pubdir_free(struct gg_http *h)
469 {
470 if (!h)
471 return;
472
473 free(h->data);
474 gg_http_free(h);
475 }
476
477 /*
478 * gg_token()
479 *
480 * pobiera z serwera token do autoryzacji zakładania konta, usuwania
481 * konta i zmiany hasła.
482 *
483 * zaalokowana struct gg_http, którą poźniej należy zwolnić
484 * funkcją gg_token_free(), albo NULL jeśli wystąpił błąd.
485 */
486 struct gg_http *gg_token(int async)
487 {
488 struct gg_http *h;
489 const char *query;
490
491 query = "Host: " GG_REGISTER_HOST "\r\n"
492 "Content-Type: application/x-www-form-urlencoded\r\n"
493 "User-Agent: " GG_HTTP_USERAGENT "\r\n"
494 "Content-Length: 0\r\n"
495 "Pragma: no-cache\r\n"
496 "\r\n";
497
498 if (!(h = gg_http_connect(GG_REGISTER_HOST, GG_REGISTER_PORT, async, "POST", "/appsvc/regtoken.asp", query))) {
499 gg_debug(GG_DEBUG_MISC, "=> token, gg_http_connect() failed mysteriously\n");
500 return NULL;
501 }
502
503 h->type = GG_SESSION_TOKEN;
504
505 h->callback = gg_token_watch_fd;
506 h->destroy = gg_token_free;
507
508 if (!async)
509 gg_token_watch_fd(h);
510
511 return h;
512 }
513
514 /*
515 * gg_token_watch_fd()
516 *
517 * przy asynchronicznych operacjach związanych z tokenem należy wywoływać
518 * tę funkcję przy zmianach na obserwowanym deskryptorze.
519 *
520 * - h - struktura opisująca połączenie
521 *
522 * jeśli wszystko poszło dobrze to 0, inaczej -1. operacja będzie
523 * zakończona, jeśli h->state == GG_STATE_DONE. jeśli wystąpi jakiś
524 * błąd, to będzie tam GG_STATE_ERROR i odpowiedni kod błędu w h->error.
525 */
526 int gg_token_watch_fd(struct gg_http *h)
527 {
528 if (!h) {
529 errno = EFAULT;
530 return -1;
531 }
532
533 if (h->state == GG_STATE_ERROR) {
534 gg_debug(GG_DEBUG_MISC, "=> token, watch_fd issued on failed session\n");
535 errno = EINVAL;
536 return -1;
537 }
538
539 if (h->state != GG_STATE_PARSING) {
540 if (gg_http_watch_fd(h) == -1) {
541 gg_debug(GG_DEBUG_MISC, "=> token, http failure\n");
542 errno = EINVAL;
543 return -1;
544 }
545 }
546
547 if (h->state != GG_STATE_PARSING)
548 return 0;
549
550 /* jeśli h->data jest puste, to ściągaliśmy tokenid i url do niego,
551 * ale jeśli coś tam jest, to znaczy, że mamy drugi etap polegający
552 * na pobieraniu tokenu. */
553 if (!h->data) {
554 int width, height, length;
555 char *url = NULL, *tokenid = NULL, *path, *headers;
556 const char *host;
557 struct gg_http *h2;
558 struct gg_token *t;
559
560 gg_debug(GG_DEBUG_MISC, "=> token body \"%s\"\n", h->body);
561
562 if (h->body && (!(url = malloc(strlen(h->body))) || !(tokenid = malloc(strlen(h->body))))) {
563 gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for results\n");
564 free(url);
565 return -1;
566 }
567
568 if (!h->body || sscanf(h->body, "%d %d %d\r\n%s\r\n%s", &width, &height, &length, tokenid, url) != 5) {
569 gg_debug(GG_DEBUG_MISC, "=> token, parsing failed\n");
570 free(url);
571 free(tokenid);
572 errno = EINVAL;
573 return -1;
574 }
575
576 /* dostaliśmy tokenid i wszystkie niezbędne informacje,
577 * więc pobierzmy obrazek z tokenem */
578
579 if (strncmp(url, "http://", 7)) {
580 path = gg_saprintf("%s?tokenid=%s", url, tokenid);
581 host = GG_REGISTER_HOST;
582 } else {
583 char *slash = strchr(url + 7, '/');
584
585 if (slash) {
586 path = gg_saprintf("%s?tokenid=%s", slash, tokenid);
587 *slash = 0;
588 host = url + 7;
589 } else {
590 gg_debug(GG_DEBUG_MISC, "=> token, url parsing failed\n");
591 free(url);
592 free(tokenid);
593 errno = EINVAL;
594 return -1;
595 }
596 }
597
598 if (!path) {
599 gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for token url\n");
600 free(url);
601 free(tokenid);
602 return -1;
603 }
604
605 if (!(headers = gg_saprintf("Host: %s\r\nUser-Agent: " GG_HTTP_USERAGENT "\r\n\r\n", host))) {
606 gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for token url\n");
607 free(path);
608 free(url);
609 free(tokenid);
610 return -1;
611 }
612
613 if (!(h2 = gg_http_connect(host, GG_REGISTER_PORT, h->async, "GET", path, headers))) {
614 gg_debug(GG_DEBUG_MISC, "=> token, gg_http_connect() failed mysteriously\n");
615 free(headers);
616 free(url);
617 free(path);
618 free(tokenid);
619 return -1;
620 }
621
622 free(headers);
623 free(path);
624 free(url);
625
626 memcpy(h, h2, sizeof(struct gg_http));
627 free(h2);
628
629 h->type = GG_SESSION_TOKEN;
630
631 h->callback = gg_token_watch_fd;
632 h->destroy = gg_token_free;
633
634 if (!h->async)
635 gg_token_watch_fd(h);
636
637 if (!(h->data = t = malloc(sizeof(struct gg_token)))) {
638 gg_debug(GG_DEBUG_MISC, "=> token, not enough memory for token data\n");
639 free(tokenid);
640 return -1;
641 }
642
643 t->width = width;
644 t->height = height;
645 t->length = length;
646 t->tokenid = tokenid;
647 } else {
648 /* obrazek mamy w h->body */
649 h->state = GG_STATE_DONE;
650 }
651
652 return 0;
653 }
654
655 /*
656 * gg_token_free()
657 *
658 * zwalnia pamięć po efektach pobierania tokenu.
659 *
660 * - h - zwalniana struktura
661 */
662 void gg_token_free(struct gg_http *h)
663 {
664 struct gg_token *t;
665
666 if (!h)
667 return;
668
669 if ((t = h->data))
670 free(t->tokenid);
671
672 free(h->data);
673 gg_http_free(h);
674 }
675
676 /*
677 * Local variables:
678 * c-indentation-style: k&r
679 * c-basic-offset: 8
680 * indent-tabs-mode: notnil
681 * End:
682 *
683 * vim: shiftwidth=8:
684 */