// bezporednie poczenia midzy klientami (dcc) w ekg

obsuga dcc nie jest jeszcze kompletna. brakuje wielu rzeczy. w chwili
obecnej mona odbiera pliki. by wczy dcc naley wpisa:

	set dcc 1
	set dcc_ip <adres_ip>
	reconnect

od tej chwili moemy odbiera wysyane do nas pliki. jeli kto sprbuje
co do nas wysa, pojawi si:

	->- kto/123 przesya plik zdjecie.jpg o rozmiarze 129117
	->- Wpisz dcc get #1 by go odebra, lub dcc close #1 by anulowa

dalszych instrukcji chyba nie trzeba podawa. inne opcje dcc bd
dostpne w cigu kilku najbliszych dni. prosz _nie_przesya_
informacji, e nie dziaa nie istniej opcja, ani nie pyta si,
kiedy bdzie dziaa.

// api kodu dcc

to jest pocztkowy opis pocztkowych stadiw kodu. wszystko moe si
zmieni i najprawdopodobniej spora cz ulegnie zmianie.

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)
		wykrzacz_si("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);
		wykrzacz_si("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 danym
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_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. dalej libgadu zajmie si
   transferem.

4) 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)) {
		wykrzacz_si("nie mog otworzy pliku");
		usu_z_listy_przegldanych_deskryptorw(klient);
		gg_dcc_free(klient);
	}

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

6) 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.

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)
		wykrzacz_si("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.






// $Id: dcc.txt,v 1.5 2002/04/19 20:07:01 wojtekka Exp $
