Mercurial > pidgin.yaz
view src/protocols/gg/protocol.txt @ 2529:44b56faccb22
[gaim-migrate @ 2542]
Drugs are bad, mmmkay.
committer: Tailor Script <tailor@pidgin.im>
author | Rob Flynn <gaim@robflynn.com> |
---|---|
date | Thu, 18 Oct 2001 00:29:05 +0000 |
parents | a7ecfd3f7714 |
children | 1ffac7cf4e94 |
line wrap: on
line source
--------------------------------------------------------------------------- protokół g*du-g*du 4.x (c) copyright 2001 by wojtek kaniewski <wojtekka@irc.pl> --- 0) disclaimer --------------------------------------------------------- wszystkie informacje bazują na doświadczeniach przeprowadzonych na moim domowym komputerze. żaden klient g*du-g*du nie został skrzywdzony podczas przeprowadzania badań, blabla. --- 1) transmisja, format wszystkich pakietów ----------------------------- w przeciwieństwie do zabawek typu icq, g*du-g*du korzysta z protokołu tcp. każdy pakiet zawiera dwa stałe pola: struct gg_header { int type; /* typ pakietu */ int length; /* długość reszty pakietu */ }; dla ułatwienia przyjmuję następujące długości zmiennych: sizeof(char) = 1, sizeof(short) = 2, sizeof(int) = 4. oczywiście wszystkie liczby są zgodnie z intelowym endianem. zakładam też, że wszystkie zmienne są bez znaku. nie chce mi się wszędzie pisać `unsigned'. pola, co do których znaczenia nie mam pewności, lub w ogóle nie mam pojęcia, skąd się tam wzięły, oznaczam `dunno'. --- 2) zanim się połączymy ------------------------------------------------- żeby wiedzieć, z jakim serwerem mamy się połączyć, należy poudawać przez chwilę Internet Explorera, połączyć się z hostem `appmsg.gadu-gadu.pl'. GET /appsvc/appmsg.asp?fmnumber=<tutaj_numerek_gg> HTTP/1.0 Host: appmsg.gadu-gadu.pl User-Agent: Mozilla/4.7 [en] (Win98; I) Pragma: no-cache na co powinniśmy dostać odpowiedź w stylu: HTTP/1.0 200 OK 0 1 0 217.17.33.21:8074 217.17.33.21 217.17.33.21 co to oznacza? nie mam pojęcia ;) wygląda na to, że cały g*du-g*du jest przemyślany i w przyszłości będzie można używać różnych serwerów do różnych rzeczy, typu szukanie, obsługa klientów itd. póki co, łączyć się trzeba na pierwszy adres (tak, ten z portem). --- 3) logowanie się ------------------------------------------------------- po połączeniu się portem 8074 serwera g*du-g*du, dostajemy pakiet typu 0x0001, który na potrzeby tego dokumentu nazwiemy: #define GG_WELCOME 0x0001 reszta pakietu zawiera liczbę, na podstawie której liczony jest hash z hasła klienta: struct gg_welcome { int key; /* klucz szyfrowania hasła */ }; kiedy mamy już tą wartość możemy odesłać pakiet logowania #define GG_LOGIN 0x000c musimy podać kilka informacji: struct gg_login { int uin; /* twój numerek */ int hash; /* hash hasła */ int status; /* status na dzień dobry */ int dunno1; /* == 0x0b */ int local_ip; /* mój adres ip */ short local_port; /* port, na którym słucham */ }; jak obliczyć hash hasła? hmm... nic prostszego. do każdej literki hasła dodaje się jedynkę, mnoży wszystko razem, a potem przez liczbę podaną przez serwer. for (hash = 1; *passwd; passwd++) hash *= (*passwd) + 1; zrozumiałe, racja? jeśli wszystko się powiedzie, dostaniemy w odpowiedzi pakiet typu #define GG_LOGIN_OK 0x0003 z polem header->length = 0, lub pakiet #define GG_LOGIN_FAILED 0x0009 --- 4) zmiana statusu ----------------------------------------------------- g*du-g*du przewiduje trzy stany klienta, które zmieniamy pakietem #define GG_NEW_STATUS 0x0002 #define GG_STATUS_NOT_AVAIL 0x0001 /* rozłączony */ #define GG_STATUS_AVAIL 0x0002 /* dostępny */ #define GG_STATUS_BUSY 0x0003 /* zajęty */ #define GG_STATUS_INVISIBLE 0x0014 /* niewidoczny */ #define GG_STATUS_FRIENDS_MASK 0x8000 /* tylko dla przyjaciół */ struct gg_new_status { int status; /* na jaki zmienić? */ } należy pamiętać, żeby przed rozłączeniem się z serwerem należy zmienić stan na GG_STATUS_NOT_AVAIL. jeśli ma być widoczny tylko dla przyjaciół, należy dodać GG_STATUS_FRIENDS do normalnej wartości stanu. --- 5) ludzie przychodzą, ludzie odchodzą --------------------------------- zaraz po zalogowaniu możemy wysłać serwerowi listę ludzików w naszej liście kontaktów, żeby dowiedzieć się, czy są w tej chwili dostępni. pakiet zawiera dowolną ilość struktur gg_notify: #define GG_NOTIFY 0x0010 struct gg_notify { int uin; /* numerek danej osoby */ char dunno1; /* == 3 */ }; jeśli ktoś jest, serwer odpowie pakietem zawierającym jedną lub więcej struktur gg_notify_reply: #define GG_NOTIFY_REPLY 0x000c /* tak, to samo co GG_LOGIN */ struct gg_notify_reply { int uin; /* numerek */ int status; /* status danej osoby */ int remote_ip; /* adres ip delikwenta */ short remote_port; /* port, na którym słucha klient */ int dunno1; /* == 0x0b */ short dunno2; /* znowu port? */ }; jeśli klient nie obsługuje połączeń między klientami (np. g*du-g*du 3.x) zamiast adresu ip jest 0, zamiast portu jest 2. nieważne ;) w każdym razie, jeśli ktoś się pojawi w trakcie pracy, również zostanie przysłany ten pakiet. proste? proste :) żeby dodać kogoś do listy w trakcie pracy, trzeba wysłać niżej opisany pakiet. jego format jest identyczny jak przy GG_NOTIFY. #define GG_ADD 0x000d struct gg_add { int uin; /* numerek */ char dunno1; /* == 3 */ }; jeśli ktoś opuści g*du-g*du lub zmieni stan, otrzymamy pakiet #define GG_STATUS 0x0002 struct gg_status { int uin; /* numerek */ int status; /* nowy stan */ }; --- 6) wysyłanie wiadomości ------------------------------------------------ przejdźmy do sedna sprawy ;) #define GG_SEND_MSG 0x000b #define GG_CLASS_MSG 0x0004 #define GG_CLASS_CHAT 0x0008 struct gg_send_msg { int recipient; int seq; int class; char message[]; }; wiadomo, odbiorca. numer sekwencyjny, który wykorzystujemy potem do potwierdzenia. nie wykluczone, że w jakis sposób odróżnia się różne rozmowy za pomocą części bajtów, ale raczej nie ma znaczenia. klasa wiadomości pozwala odróżnić, czy wiadomość ma się pokazać w osobym okienku czy jako kolejna linijka w okienku rozmowy. wygląda na to, że to jakaś bitmapa, więc najlepiej olać inne bity niż 0x0f. (czasem klienty wysyłają 0x04, czasem 0x24) serwer po otrzymaniu wiadomości odsyła informację o tym. przy okazji mówi, czy wiadomość dotarła do odbiorcy (status == GG_ACK_DELIVERED), czy może jest offline i została zakolejkowana (GG_ACK_QUEUED): #define GG_SEND_MSG_ACK 0x0005 #define GG_ACK_DELIVERED 0x0002 #define GG_ACK_QUEUED 0x0003 struct gg_send_msg_ack { int status; int recipient; int seq; }; numer sekwencyjny i adresat ten sam, co przy wysyłaniu. --- 7) otrzymywanie wiadomości --------------------------------------------- zbyt wiele wyjaśnień chyba nie trzeba. wiadomo od kogo. nieznane pola to coś a'la numer sekwencyjny albo identyfikator okienka z rozmową albo nowe dane dla setiathome. klasa wiadomości taka sama jak przy wysyłaniu: #define GG_RECV_MSG 0x000a struct gg_recv_msg { int sender; int dunno1; int dunno2; int class; char message[]; }; --- 8) otrzymywanie wiadomości --------------------------------------------- od czasu do czasu klient wysyła pakiet a'la ping do serwera i dostaje pustą odpowiedź. ciężko stwierdzić, czy serwer wywala, jeśli nie dostanie pinga przez jakiś czas, czy klient się rozłącza, jeśli serwer mu nie odpowie. jakoś nie chce mi się sprawdzać ;) #define GG_PING 0x0008 /* nie ma niczego */ #define GG_PONG 0x0007 /* nie ma niczego */ --- 9) podziękowania ------------------------------------------------------- swój wkład w poznanie protokołu miał Robert Woźny, który opisał nowości w GG 4.6. ---------------------------------------------------------------------------- $Id: protocol.txt 2406 2001-09-29 23:06:30Z warmenhoven $