// bezporednie poczenia midzy klientami (dcc) w ekg

aby umoliwi przesyanie plikw naley wykona nastpujce komendy:

	set dcc 1
	set dcc_ip <adres_ip>
	reconnect

jeli jestemy za maskarad lub chcemy przesya pliki do ludzi z tej
samej sieci lokalnej, podajemy adres komputera widoczny od strony sieci.
w przeciwnym wypadku podajemy adres zewntrzny. jeli mamy tylko jeden
interfejs sieciowy, problemu nie ma, bo adres jest tylko jeden.

po ponownym poczeniu moemy korzysta z dobrodziejstw bezporednich
poczeni. 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

wystarczy zastosowa si do podanych wskazwek. jeli chcemy wysa
komu plik, wpisujemy:

	dcc send <pseudonim/numer> <nazwa_pliku>

naley pamita, e do przesyania plikw obie strony musz mie
dopisane siebie do list kontaktw. jeli ustawimy niewaciwy adres,
oryginalne klienty Gadu-Gadu bd odrzuca poczenia. dzieje si tak,
gdy adres z ktrego przychodzi poczenie jest inny ni ten, ktry
zosta przesany przez serwer. ma to wpyw gwnie na sytuacje typu:

			        ,-----------.
				| Gadu-Gadu | workstacja
				`-----+-----'
           |      |          |        | 10.0.0.5
           `------+---+------+--------'
		      |                 (sie lokalna)
	              | 10.0.0.1
		 ,----+----.
		 |   ekg   | router z NAT
		 `----+----'
		      | 1.2.3.4
                      |
		  (internet)

jeli ekg na routerze bdzie miao ustawiony adres 1.2.3.4, taki adres
zobaczy te serwer. ten sam adres dostanie klient Gadu-Gadu w sieci
lokalnej. tyle e kiedy ekg bdzie chciao wysa plik do Gadu-Gadu,
poczy si z adresu 10.0.0.1, bo taki ma przypisany do sieci lokalnej.
w takim wypadku Gadu-Gadu odrzuci poczenie ze wzgldu na niezgodno
adresw. dlatego mona albo ustawi adres sieci lokalnej, albo uy
do wysyania:

	dcc send <pseudonim/numer> <nazwa_pliku> --reverse

ktre wyle do Gadu-Gadu danie poczenia za porednictwem serwera
Gadu-Gadu i windowsowy klient sam si z nami poczy. ekg nie jest a
tak restrykcyjne, ale moe si to zmieni. najprawdopodobniej parametry
komendy dcc rwnie ulegn zmianom w przyszoci. pki co, kod jest
w fazie rozwoju.


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


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)
		wykrzacz_si("nie mona ustanowi poczenia");

dalej tak samo, jak przy zwykym odbieraniu pliku.



$Id: dcc.txt,v 1.1.1.1 2002/07/09 22:22:02 chilek Exp $
