// jakitam sobie opis API libgadu
// (c) copyright 2001-2002 by wojtek kaniewski <wojtekka@irc.pl>
//			      robert j. wozny <speedy@ziew.org>

kada sesja jest opisywana przez ,,struct gg_session''. biblioteka moe
w ramach jednego procesu/wtku obsugiwa tyle sesji, na ile pozwol
zasoby. deklarujemy sobie...

	struct gg_session *blah;

nastpnie wypadaoby si poczy. przykad bdzie dotyczy socketw
nieblokujcych, bo w wikszoci aplikacji ciko sobie pozwoli na
zawieszanie programu na czas czenia.

	struct gg_login_params p;

	memset(&p, 0, sizeof(p));
	p.uin = 123456;
	p.password = "haso";
	p.async = 1;
	p.status = GG_STATUS_INVISIBLE;

	if (!(blah = gg_login(&p)))
		my_error();

jeli uda si rozpocz proces czenia, dostajemy wskanik do struktury,
inaczej NULL. wywoanie gg_login() powoduje uruchomienie drugiego procesu
w tle, ktry wywoa gethostbyname() i przez pipe'a zwrci wynik. pniej
poczy si z serwerem, wyle, odbierze, poczy si ze wskazanym adresem
IP, zaloguje si itd. jako e wszystko dziej si w tle, klient musi
sprawdza cay czas podane deskryptory. pole ,,blah->fd'' zawiera
deskryptor, a ,,blah->check'' jest bitmap i zawiera GG_CHECK_READ i/lub
GG_CHECK_WRITE jeli mamy sprawdzi czy przyszy nowe dane i/lub moemy
wysya. jeli co si wydarzy, wywoujemy ,,gg_watch_fd()'', a libgadu
sobie ju sprawdzi, co takiego si zdarzyo:

	while (1) {
		fd_set rd, wr, ex;

		FD_ZERO(&rd);
		FD_ZERO(&wr);
		FD_ZERO(&ex);

		if ((blah->check & GG_CHECK_READ))
			FD_SET(blah->fd, &rd);
		if ((blah->check & GG_CHECK_WRITE))
			FD_SET(blah->fd, &wr);
		FD_SET(blah->fd, &ex);

		if (select(blah->fd + 1, &rd, &wr, &ex, NULL) == -1)
			my_error();

		if (FD_ISSET(blah->fd, &ex))
			my_error();

		if (FD_ISSET(blah->fd, &rd) || FD_ISSET(blah->fd, &wr))
			my_handle_event();
	}

nie ma tutaj obsugi timeoutw itp. jeli komu zaley, niech sobie
sam dopisze. poza tym, jeli program sprawdza te inne deskryptory
jak np. stdin dla klientw konsolowych, dobrze byoby sprawdzi, czy
dana sesja co robi i nie sprawdza ,,blah->fd'' jeli
,,blah->state == GG_STATE_IDLE''. no i od czasu do czasu mona by
dawa zna serwerowi, e co si dzieje, za pomoc...

	gg_ping(blah);

ale to ju wymaga implementacji jakich timeoutw i liczenia czasu od
ostatniego pinga. ,,blah->last_pong'' mwi nam, kiedy serwer ostatni
raz odpowiedzia na pakiet ping, a ,,blah->last_event'' mwi, kiedy
dostalimy cokolwiek ostatnio od serwera.

wracajc do obsugi deskryptorw -- jeli klient zauway, e co si
zmienio na podanym sockecie, powinien wywoa ,,gg_watch_fd()'',
ktra wszystkim si zajmie. zwraca ona wskanik do zaalokowanej
struktury opisujcej zdarzenie. po obejrzeniu naley zwolni j za
pomoc ,,gg_event_free()''. w powyszym przykadzie jest wywoywana
funkcja ,,my_handle_event()'', ktra moe wyglda tak:

	struct gg_event *e;
	
	if (!(e = gg_watch_fd(blah)))
		my_error();

	switch (e->type) {
		case GG_EVENT_NONE:
		case GG_EVENT_PONG:
			/* olewamy */
			break;

		case GG_EVENT_CONN_SUCCESS:
			printf("poczono!\n");
			/* tutaj wysyamy userlist za pomoc gg_notify() */
			break;

		case GG_EVENT_CONN_FAILED:
			printf("nie udao si\n");
			/* powd w e->event.failure, stae GG_FAILURE_... */
			break;

		case GG_EVENT_MSG:
			printf("masz wiadomo!\n");
			printf("od: %d\n", e->event.msg.sender);
			printf("tre: %s\n", e->event.msg.message);
			/* e->event.msg.class mwi czy rozmowa czy wiad. */
			/* jeli e->event.msg.sender rwny 0, to mamy */
			/* wiadomo systemow o numerze w msg.class */
			break;

		case GG_EVENT_NOTIFY:
			printf("oto ludzie, ktrzy si pojawili: ");
			/* tutaj sprawdzanie tablicy e->event.notify */
			break;

		case GG_EVENT_STATUS:
			printf("kto %d zmieni stan\n", e->event.status.uin);
			/* nowy stan w e->event.status.status */
			break;

		case GG_EVENT_ACK:
			printf("wiadomo dotara do %d.\n",
				e->event.ack.recipient);
			/* e->event.ack.status mwi czy dotara do klienta */
			/* czy ley na serwerze, stae GG_ACK_... */
			/* e->event.ack.seq to numerek wiadomoci */
			break;

		case GG_EVENT_SEARCH50_REPLY:
			printf("znalazo kogo\n");
			/* opisane niej */
			break;
	}

	gg_event_free(e);

przy okazji wiadomo, co oznacza ktry event. cz z nich mona ignorowa,
jeli robi si okrojonego klienta, np. commandline'owego wysyajcego
jedn wiadomo.

po zalogowaniu wypadaoby wysa serwerowi list uytkownikw, ktrzy nas
interesuj. ,,gg_notify()'' przyjmuje za argument tablic zmiennych typu
,,uin_t''. w odpowiedzi dostaniemy GG_EVENT_NOTIFY i tablic struktur
,,struct gg_notify_reply'', jeli kto jest. po szczegy odsyam do
libgadu.c, libgadu.h i rde konsolowego klienta. jeli dodajemy lub
usuwamy kogo w trakcie dziaania, naley skorzysta z ,,gg_add_notify()''
lub ,,gg_remove_notify()''.

eby zmieni stan na zajty lub dostpny, uywamy ,,gg_change_status()''.

wysyanie wiadomoci za pomoc ,,gg_send_message()''. parametr ,,class''
mwi, czy ma sie pojawi w osobnym okienku (GG_CLASS_MSG) czy w okienku
rozmowy (GG_CLASS_CHAT). funkcja zwraca numer sekwencyjny wiadomoci,
ktrego moemy uy do potwierdzenia.

jedyne zalenoci libgadu w domylnej wersji to <sys/types.h> i <stdint.h>



[ Date: Sat, 11 Jan 2003 20:28:54 +0100 (CET)   ]
[ From: Wojtek Kaniewski <wojtekka@dev.null.pl> ]
[ To: ekg-devel@list.ziew.org                   ]
[ Subject: [ekg-devel] wyszukiwanie w gg 5.0    ]

skoro ju dziaa, opisz aktualne API. gwnym zaoeniem bya
maksymalna niezaleno od zmian w protokole, zmian nazw pl, dodawania
nowych itd. zastosowane podejcie moe by troch dziwne na pierwszy rzut
oka, ale podpatrzyem to w powaniejszych projektach (np. libdbi).

jeli chcemy szuka:

        gg_search50_t req = gg_search50_new();

        if (!req)
                out_of_memory();

        /* szukamy po numerku... */

        gg_search50_add(req, GG_SEARCH50_UIN, "123456");

        /* lub... */

        gg_search50_add(req, GG_SEARCH50_FIRSTNAME, "Ania");
        gg_search50_add(req, GG_SEARCH50_GENDER, GG_SEARCH50_GENDER_FEMALE);

        /* lub... */

        gg_search50_add(req, GG_SEARCH50_BIRTHYEAR, "1979 1985");
        gg_search50_add(req, GG_SEARCH50_START, "0");
        gg_search50_add(req, GG_SEARCH50_ACTIVE, GG_SEARCH50_ACTIVE_TRUE);

        /* i w kocu... */

        gg_search50(sesja, req);

        /* i zwalniamy pami, albo sobie gdzie zachowujemy. whatever */

        gg_search50_free(req);

jak wita, gg_search50_new() tworzy obiekt opisujcy wyszukiwanie,
gg_search50_add() dodaje kolejne parametry. rodzaj parametru jest w
rzeczywici sta tekstowk, np. GG_SEARCH50_UIN to "FmNumber". naley
pamita, e wszystkie argumenty s tekstami. nie trzeba si bawi w ich
alokowanie czy co takiego. biblioteka sobie sama zapamita. teksty musz
by oczywicie w CP1250. na kocu wywoujemy gg_search50() i tyle. funkcja
ta zwraca numer sekwencyjny wyszukiwania, ktry moemy sobei zachowa dla
pniejszych referencji.

eby otrzyma wynik naley obsuy zdarzenei GG_EVENT_SEARCH50_RESULT, a
nastpnie:

        gg_search50_t res = zdarzenie->event.search50;
        int count = gg_search50_count(res);

        if (count < 1) {
                wiadomo("Nie znaleziono");
                return;
        }

        for (int i = 0; i < count; i++) {
                const char *uin, *first, *nick, *born, *city, *status;

                uin = gg_search50_get(res, i, GG_SEARCH50_UIN);
                first = gg_search50_get(res, i, GG_SEARCH50_FIRSTNAME);
                nick = gg_search50_get(res, i, GG_SEARCH50_NICK);
                born = gg_search50_get(res, i, GG_SEARCH50_BIRTHYEAR);
                city = gg_search50_get(res, i, GG_SEARCH50_CITY);
                status = gg_search50_get(res, i, GG_SEARCH50_STATUS);

                printf("Numer: %s\nImi: %s\nPseudonim: %s\n"
                        "Urodzony: %s\nMiejscowo: %s\n", uin,
                        first, nick, born, city);

                switch ((status) ? atoi(status) : -1) {
                        case GG_STATUS_AVAIL:
                                printf("Dostpny\n");
                                break;
                        case GG_STATUS_BUSY:
                                printf("Zajty\n");
                                break;
                        default:
                                printf("Niedostpny\n");
                }

                printf("\n");
        }

        gg_event_free(zdarzenie);

jeli chcemy wiedzie, od jakiego numeru zaczc wyszukiwanie, eby dosta
dalsz cz, uzywamy gg_search50_next(). jeli chcemy numer sekwencyjny,
uywamy gg_search50_seq().

w adnym wypadku nie mona si odwoywa do pl gg_search50_t, poniewa
mog si zmienai midzy wersjami biblioteki. dziki odwoywaniu si przez
funkcje, mamy pewno, e bez wzgldu na zmiany API/ABI mamy to samo.
dodatkowo, jeli dojd jakies opcje wyszukiwania, nie trzeba w bibliotece
niczego zmienia -- adnych struktur, itd. po prostu odwoujemy si do
kolejnego pola przez gg_search50_add() i gg_search50_get().

w przyszoci tak samo chciabym rozwiza parametry gg_login(), ale to
inny historia.

teraz pytanie: czy druyna pierc^W Kadu ma jakie uwagi, komentarze itp?
jestem otwarty na propozycje, jeli jaka zmiana miaaby uatwi Wam ycie
(mi moe utrudni, byle w granicach rozsdku ;>)

pozdr,
w.




$Id: api.txt,v 1.11 2003/01/11 19:40:03 wojtekka Exp $
