// szybki kurs libgadu
// (c) copyright 2001-2003 by wojtek kaniewski <wojtekka@irc.pl>
//			      robert j. wozny <speedy@ziew.org>

// tekst poprawiany ostatnio 2003-10-03

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

	struct gg_session *blah;

nastpnie bdziemy si czy. 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
lub wtku w tle, ktry wywoa gethostbyname() i potokiem 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();
	}

dla uproszczenia, nie ma tutaj obsugi timeoutw i tym podobnych dodatkw.
poza tym, jeli program sprawdza te inne deskryptory (np. stdin dla
klientw konsolowych), dobrze byoby sprawdzi, czy dana sesja co robi i
nie sprawdza ,,blah->fd'' jeli ,,blah->state == GG_STATE_IDLE''. od czasu
do czasu mona da serwerowi zna, e co si dzieje, za pomoc...

	gg_ping(blah);

ale to ju wymaga implementacji timerw i liczenia czasu od ostatniego
pinga. ,,blah->last_event'' mwi, kiedy dostalimy cokolwiek ostatnio od
serwera. wszystkie pola struktury s opisane w pliku libgadu.h.

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_NOTIFY60:
			printf("oto ludzie, ktrzy si pojawili: ");
			/* tutaj sprawdzanie tablicy e->event.notify60 */
			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_STATUS60:
			printf("kto %d zmieni stan\n", e->event.status60.uin);
			/* nowy stan w e->event.status60.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_PUBDIR50_REPLY:
			printf("znalazo kogo\n");
			/* opisane niej */
			break;

		case GG_EVENT_USERLIST:
			printf("wysano lub odebrano list z serwera\n");
			/* opisane niej */
			break;
	}

	gg_event_free(e);

przy okazji wiadomo, co oznaczaj zdarzenia. cz z nich mona ignorowa,
jeli robi si okrojonego klienta, np. wysyajcego jedn wiadomo z linii
komend.

po zalogowaniu naley wysa serwerowi list uytkownikw, ktrych mamy
w licie kontaktw. ,,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()''. jeli chcemy korzysta z listy osb blokowanych
lub takich, przed ktrymi si ukrywamy, naley korzysta z funkcji
,,gg_notify_ex()'', ,,gg_add_notify_ex()'' i ,,gg_remove_notify_ex()'',
ktre bior dodatkowy argument mwicy, jak traktowa uytkownika.
odpowiadaj za to stae GG_USER_NORMAL, GG_USER_BLOCKED i GG_USER_OFFLINE.

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

wysyanie wiadomoci za pomoc ,,gg_send_message()''. parametr ,,class''
mwi, czy ma si pojawi w osobnym okienku (GG_CLASS_MSG) czy w okienku
rozmowy (GG_CLASS_CHAT). funkcja zwraca numer sekwencyjny wiadomoci,
ktrego moemy uy do potwierdzenia. wiadomo, ktra ma by sformatowana
w odpowiedni sposb (pogrubienie, kursywa, kolory, itp.) wysyamy za pomoc
,,gg_send_message_richtext()''. wiadomoci konferencyjne wysyamy funkcjami
,,gg_send_message_confer()'' lub ,,gg_send_message_confer_richtext()''.

jeli chcemy si wylogowa, wywoujemy ,,gg_logoff()'' i potem zwalniamy
pami zwizan z sesj funkcj ,,gg_free_session()''.

jeli chcemy przypomnie swoje haso, wywoujemy funkcj
,,gg_remind_passwd2()'', a wynikow struktur ,,gg_http'' traktujemy
podobnie do ,,gg_session'':
 - sprawdzamy ->fd i ->check,
 - wywoujemy ,,gg_remind_passwd_watch_fd()'', gdy co si dzieje. funkcja
   ta zwraca -1 w przypadku bdu. jeli zwraca 0, wywoujemy j, pki
   ->state nie bdzie rwne GG_STATE_DONE lub GG_STATE_ERROR.
 - po zakoczeniu, wywoujemy ,,gg_remind_passwd_free()''.

jeli chcemy zarejestrowa konto lub zmieni haso, naley pobra token
z serwera. wywoujemy funkcj ,,gg_token()'' i traktujemy podobnie
wynikowe ,,gg_http''. po skoczonej operacji w ->data mamy struktur
,,gg_token'' zawierajc ,,tokenid'' i inne pola. w ->body mamy obrazek
z tokenem o rozmiarze ->body_size. pokazujemy go uytkownikowi, eby mg
spisa token.

majc ju token, jeli chcemy zarejestrowa konto, wywoujemy
,,gg_register3()'' z odpowiednimi parametrami, a jeli chodzi o zmian hasa,
to ,,gg_change_passwd4()''.

konto usuwane jest funkcj ,,gg_unregister3()''.

***

OBSUGA KATALOGU PUBLICZNEGO GG 5.0 (na podstawie listu na ekg-devel)

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_pubdir50_t req = gg_pubdir50_new(GG_PUBDIR50_SEARCH_REQUEST);

        if (!req)
                out_of_memory();

        /* szukamy po numerku... */

        gg_pubdir50_add(req, GG_PUBDIR50_UIN, "123456");

        /* lub... */

        gg_pubdir50_add(req, GG_PUBDIR50_FIRSTNAME, "Ania");
        gg_pubdir50_add(req, GG_PUBDIR50_GENDER, GG_PUBDIR50_GENDER_FEMALE);

        /* lub... */

        gg_pubdir50_add(req, GG_PUBDIR50_BIRTHYEAR, "1979 1985");
        gg_pubdir50_add(req, GG_PUBDIR50_START, "0");
        gg_pubdir50_add(req, GG_PUBDIR50_ACTIVE, GG_PUBDIR50_ACTIVE_TRUE);

        /* i w kocu... */

        gg_pubdir50(sesja, req);

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

        gg_pubdir50_free(req);

jak wita, gg_pubdir50_new() tworzy obiekt opisujcy operacj katalogu,
gg_pubdir50_add() dodaje kolejne parametry. rodzaj parametru jest w
rzeczywici sta tekstow, np. GG_PUBDIR50_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_pubdir50() i tyle. funkcja
ta zwraca numer sekwencyjny wyszukiwania, ktry moemy sobie zachowa dla
pniejszych referencji.

eby otrzyma wynik, naley obsuy zdarzenia GG_EVENT_PUBDIR50_SEARCH_REPLY,
GG_EVENT_PUBDIR50_WRITE i GG_EVENT_PUBDIR50_READ. dla przykadu, obsuga
wynikw wyszukiwania wyglda nastpujco:

        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_pubdir50_get(res, i, GG_PUBDIR50_UIN);
                first = gg_pubdir50_get(res, i, GG_PUBDIR50_FIRSTNAME);
                nick = gg_pubdir50_get(res, i, GG_PUBDIR50_NICK);
                born = gg_pubdir50_get(res, i, GG_PUBDIR50_BIRTHYEAR);
                city = gg_pubdir50_get(res, i, GG_PUBDIR50_CITY);
                status = gg_pubdir50_get(res, i, GG_PUBDIR50_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 zacz wyszukiwanie, eby dosta
dalsz cz, uywamy gg_pubdir50_next(). jeli chcemy numer sekwencyjny,
uywamy gg_pubdir50_seq().

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

***

OBSUGA LISTY KONTAKTW GG 6.0

od wersji 6.0 import i eksport listy kontaktw jest zawarty w sesji klienta,
nie wymaga osobnego poczenia http. aby wysa list kontaktw, wywoujemy:

	gg_userlist_request(sesja, GG_USERLIST_PUT, lista_kontaktw);

w odpowiedzi dostaniemy od serwera zdarzenie GG_EVENT_USERLIST z polem
,,type'' rwnym GG_USERLIST_PUT_REPLY.

jeli chcemy pobra list kontaktw z serwera, wywoujemy:

	gg_userlist_request(sesja, GG_USERLIST_GET, NULL);

i oczekujemy zdarzenia GG_EVENT_USERLIST z ,,type'' GG_USERLIST_GET_REPLY.
zawarto listy kontaktw znajdziemy w polu ,,reply''.

***

WIADOMOCI GRAFICZNE

informacje o obrazku s zawarte w bloku wiadomoci dotyczcym formatowania
tekstu. dla danego znaku tekstu pole ,,font'' zawiera GG_FONT_IMAGE i zaraz
potem znajduje si struktura gg_msg_richtext_image, np.

  0x00	koniec wiadomoci
  0x02	.flag = 0x02				gg_msg_richtext
  0x0d	.length = 0x000d			|
  0x00  |					|
  0x00  .position = 0x00			gg_msg_richtext_format
  0x00  |					|
  0x80  font = GG_FONT_IMAGE 			|
  0x90	.unknown1 = 0x0109			gg_msg_richtext_image
  0x01	|					|
  0x12	.size = 0x3412				|
  0x34	|					|
  0x00	|					|
  0x00	|					|
  0x56	.crc32 = 0x7856				|
  0x78	|					|
  0x00	|					|
  0x00	|					|

wiemy zatem, e obrazek ma dugo 0x3412 i sum kontroln 0x7856. jeli
nie mamy takiego obrazka zapisanego u siebie, wywoujemy funkcj:

	gg_image_request(sesja, nadawca, rozmiar, suma_kontrolna);

i czekam na zdarzenie GG_EVENT_IMAGE_REPLY, w ktrym wane s dla nas
pola .size, .crc32, .filename (nazwa obrazka), .image (tre obrazka).
rodzaj pliku graficznego nie jest okrelony przy transmisji. libgadu
ignoruje wszystkie obrazki, ktre nie byy zamwione, eby unikn
zajcia caej dostpnej pamici, gdy kto nieustannie wysya nam rne
obrazki.

jeli wysyamy wiadomo graficzn musimy obsugiwa zdarzenie
GG_EVENT_IMAGE_REQUEST. w polach .size i .crc32 s informacje o
obrazku, ktrego potrzebuje nasz rozmwca. wysyamy funkcj
gg_image_reply(sesja, odbiorca, nazwa_pliku, zawarto_pliku, dugo);

***

BEZPOREDNIE POCZENIA

gadu-gadu, w przeciwiestwie do irc, umoliwia poczenia w obie strony,
bez wzgldu na to, ktry klient nadaje, a ktry odbiera. do tego, jeli
obie strony wychodz z tego samego adresu IP, serwer informuje ich o ich
adresach wewntrznych z tego samego LANu. mamy kilka moliwych sytuacji:

a) mam publiczny lub niepubliczny adres IP i chc wysa plik do kogo
   z publicznym adresem -- cz si z jego klientem, przedstawiam si,
   mwi czego chc i jeli to zaakceptuje, zaczynam wysya plik. bardzo
   to przypomina zwyke poczenia dcc klientw irc.

b) mam publiczny adres IP i wysyam plik do kogo za maskarad -- wysyam
   do niego odpowiedni pakiet ctcp (client-to-client protocol). jest to
   pakiet klasy GG_CLASS_CTCP (0x10) o treci skadajcej si z jednego
   znaku o kodzie 0x02. druga strona, odebrawszy taki pakiet czy si
   z nami, mwi, e proszono j o poczenie i czeka na dalsze instrukcje.
   wtedy wysyamy informacj, e owszem, chcemy wysa plik, mwimy jaki
   i jeli druga strona to zaakceptuje, nadajemy.

c) mam niepubliczny adres IP, tak samo jak i druga strona -- tutaj
   nawizanie poczenia jest moliwe tylko i wycznie, gdy oba klienty
   znajduj si w tej samej sieci (tj. oba cz si z serwerem GG z tego
   samego adresu zewntrznego) i wyglda to wtedy identycznie jak w punkcie
   a).

to, czy moemy si z kim poczy wida po porcie, jaki dostajemy w
pakietach gg_notify_reply. jeli jest mniejszy ni 10, poczenie nie
jest moliwe, a wtedy wysyamy pakiet ctcp za pomoc funkcji
gg_dcc_request().

kade poczenie zwizanie z dcc opisywane jest przez struktur gg_dcc.
najwaniejsze jest GG_SESSION_DCC_SOCKET, ktre odpowiada za przychodzce
poczenia. tworzymy je przez:

	struct gg_dcc *socket = gg_dcc_socket_create(uin, port);

	if (!socket)
		bd("nie mog otworzy socketu");

	dodaj_do_listy_przegldanych_deskryptorw(socket);

port moe wynosi 0, a wtedy libgadu samo wemie pierwszy lepszy
z brzegu. w razie powodzenia zwraca zaalokowan struktur gg_dcc,
ktrej najbardziej interesujcym polem jest gg_dcc->port zawierajce
numer przyznanego portu. jeli funkcja zwrci NULL, patrzymy na errno.
EINVAL to niewaciwie parametry, ENOMEM brak pamici, a reszta
moliwych bdw to te zwizane z socketami, typu EADDRINUSE gdy nie
moe wolnego portu znale.

teraz wypadaoby ustawi zmienn ,,gg_dcc_port'' i poczy si z
serwerem GG, eby ogosi swoje namiary. ogaszany adres IP bdzie
brany z poczenia z serwerem.

	gg_dcc_port = socket->port;
	pocz_si_z_serwerem();

w kadym razie, gdy pojawi si co na deskryptorze, wywoujemy:

	struct gg_event *event = gg_dcc_watch_fd(socket);

	if (!event) {
		usu_z_listy_przegldanych_deskryptorw(socket);
		gg_dcc_free(socket);
		bd("powany bd"):
	}

bd jest zwracany tylko w naprawd krytycznych sytuacjach, gdy
brakuje pamici, lub nie powioda si operacja na socketach, ktra
nie miaa si nie powie (i przy okazji dalsza zabawa jest
kompletnie bezcelowa).

jeli bdu nie bdzie, dostajemy informacje o zdarzeniu. w przypadku
GG_SESSION_DCC_SOCKET mog to by:

1) GG_EVENT_NONE -- nic ciekawego si nie wydarzyo.

2) GG_EVENT_DCC_ERROR -- wystpi bd, ktrego kod znajduje si w
   event->event.dcc_error. w przypadku tego typu sesji moliwy jest
   tylko GG_ERROR_DCC_HANDSHAKE, ktry mwi, e nie udao si nawiza
   poczenia z klientem.

3) GG_EVENT_DCC_NEW -- nowe poczenie od klienta. w polu
   event->event.dcc_new jest struktura gg_dcc typu GG_SESSION_DCC,
   ktr dodajemy do listy przegldanych deskryptorw.

w kadym z tych wypadkw naley po sprawdzeniu zdarzenia wywoa funkcj:

	gg_event_free(socket->event);

by zwolni pami po zdarzeniu.


gdy nadejdzie poczenie i dopiszemy je do listy przegldanych deskryptorw,
musimy zwraca uwag na nastpujce zdarzenia:

1) GG_EVENT_NONE -- nic si nie zdarzyo.

2) GG_EVENT_DCC_CLIENT_ACCEPT -- klient si przedstawi i czeka na
   autoryzacj poczenia. sprawdzamy gg_dcc->uin czy jest naszym numerem
   i czy gg_dcc->peer_uin jest na naszej licie kontaktw i czy chcemy z
   nim nawizywa poczenie. jeli nie, to po prostu usuwamy poczenie:

   	if (!akceptujemy_poczenie(klient->uin, klient->peer_uin)) {
		usu_z_listy_przegldanych_deskryptorw(client);
		gg_dcc_free(klient);
	}

3) GG_EVENT_DCC_CALLBACK -- poprosilimy klienta, eby si z nami poczy
   za pomoc gg_dcc_request() i on teraz pyta si, czego chcemy. zaraz po
   tym zdarzeniu naley wywoa funkcj:

	gg_dcc_set_type(klient, rodzaj_poczenia);

   gdzie rodzaj to GG_SESSION_DCC_SEND albo GG_SESSION_DCC_VOICE. jeli
   wysyamy plik, mona od razu wywoa gg_dcc_fill_file_info(), ale nie
   jest to wymagane. kiedy przyjdzie pora, libgadu sama nas o to poprosi.

4) GG_EVENT_DCC_NEED_FILE_ACK -- klient chce wysa nam plik. w strukturze
   gg_dcc->file_info znajduj si wszystkie informacje na temat pliku, jak
   jego nazwa, rozmiar, atrybuty, data i czas utworzenia itp. jeli nie
   chcemy pliku, zamykamy poczenie w podobny sposb jak przy braku
   autoryzacji. libgadu jeszcze nie potrafi odpowiada negatywnie na proby
   pocze dcc. jeli chcemy plik, otwieramy plik do zapisu i numer jego
   deskryptora zapisujemy do gg_dcc->file_fd. jeli chcemy wznowi przerwany
   transfer, otwieramy plik w trybie dopisywania i do gg_dcc->offset
   wpisujemy ile bajtw ju mamy i od ktrego offsetu odbieramy. dalej
   libgadu zajmie si transferem.

5) GG_EVENT_DCC_NEED_FILE_INFO -- wczeniej poprosilimy drug stron by
   si z nami poczya, bo jest za maskarad, a my chcemy wysa plik.
   w tym wypadku moemy albo sami wypeni struktur gg_dcc->file_info,
   ktr biblioteka wyle drugiej stronie, albo skorzysta z funkcji
   gg_dcc_fill_file_info().

   	if (gg_dcc_fill_file_info(klient, nazwa_pliku)) {
		bd("nie mog otworzy pliku");
		usu_z_listy_przegldanych_deskryptorw(klient);
		gg_dcc_free(klient);
	}

6) GG_EVENT_DCC_DONE -- zakoczono transfer, mona ju nie patrze na
   deskryptor i zwolni pami po poczeniu.

7) GG_EVENT_DCC_ERROR -- bd. moliwy kod bdu to GG_ERROR_DCC_HANDSHAKE
   gdy nie powiodo si ustanowienie poczenia z klientem, GG_ERROR_DCC_NET
   kiedy nie udao si wysa lub odczyta czego z socketa, GG_ERROR_DCC_FILE
   gdy nie mona byo odczyta albo zapisa do pliku, GG_ERROR_DCC_EOF gdy
   plik lub poczenie zbyt wczenie si skoczy, GG_ERROR_DCC_REFUSED gdy
   uytkownik po drugiej stronie odmwi poczenia.

tutaj rwnie naley pamita o wywoywaniu gg_event_free().


jeli chcemy sami wysa plik, sprawdzamy najpierw, czy druga strona
moe przyj poczenie, patrzc na jej port. jeli powyej 10, moemy
miao wywoa funkcj:

	struct gg_dcc *klient = gg_dcc_send_file(adres_ip, port, nasz_uin, jego_uin);

	if (!klient)
		bd("nie mona ustanowi poczenia");

zaraz potem moemy wywoa funkcj gg_dcc_fill_file_info() by uzupeni
informacj o pliku...

	gg_dcc_fill_file_info(klient, nazwa_pliku);

...ale jeli tego nie zrobimy teraz, biblioteka poprosi nas o to
w odpowiedniej za pomoc zdarzenia GG_EVENT_DCC_NEED_FILE_INFO.

jeli port jest podejrzanie niski, znaczy e poczenie jest niemoliwe
i wtedy wywoujemy funkcj:

	gg_dcc_request(sesja_gg, jego_uin);

gdzie sesja_gg to nasza sesja GG (jako musimy wysa wiadomo),
a jego_uin to numer drugiej strony. spowoduje ona, e druga strona
sprbuje si z nami poczy, jeli ma tak moliwo.


gdy otrzymamy wiadomo klasy GG_CLASS_CTCP o treci 0x02 znaczy,
e kto chce nam co przesa i mamy si z nim poczy. wywoujemy
wtedy:

	struct gg_dcc *klient = gg_dcc_get_file(adres_ip, port, nasz_uin, jego_uin);

	if (!klient)
		bd("nie mona ustanowi poczenia");

dalej tak samo, jak przy zwykym odbieraniu pliku.

$Id: api.txt,v 1.27 2006-08-09 06:39:56 embe Exp $
