2393
|
1 ---------------------------------------------------------------------------
|
|
2
|
|
3 protokół g*du-g*du 4.x
|
|
4 (c) copyright 2001 by wojtek kaniewski <wojtekka@irc.pl>
|
|
5
|
|
6 --- 0) disclaimer ---------------------------------------------------------
|
|
7
|
|
8 wszystkie informacje bazują na doświadczeniach przeprowadzonych na moim
|
|
9 domowym komputerze. żaden klient g*du-g*du nie został skrzywdzony podczas
|
|
10 przeprowadzania badań, blabla.
|
|
11
|
|
12 --- 1) transmisja, format wszystkich pakietów -----------------------------
|
|
13
|
|
14 w przeciwieństwie do zabawek typu icq, g*du-g*du korzysta z protokołu tcp.
|
|
15 każdy pakiet zawiera dwa stałe pola:
|
|
16
|
|
17 struct gg_header {
|
|
18 int type; /* typ pakietu */
|
|
19 int length; /* długość reszty pakietu */
|
|
20 };
|
|
21
|
|
22 dla ułatwienia przyjmuję następujące długości zmiennych: sizeof(char) = 1,
|
|
23 sizeof(short) = 2, sizeof(int) = 4. oczywiście wszystkie liczby są zgodnie
|
|
24 z intelowym endianem. zakładam też, że wszystkie zmienne są bez znaku. nie
|
|
25 chce mi się wszędzie pisać `unsigned'.
|
|
26
|
|
27 pola, co do których znaczenia nie mam pewności, lub w ogóle nie mam pojęcia,
|
|
28 skąd się tam wzięły, oznaczam `dunno'.
|
|
29
|
|
30 --- 2) zanim się połączymy -------------------------------------------------
|
|
31
|
|
32 żeby wiedzieć, z jakim serwerem mamy się połączyć, należy poudawać przez
|
|
33 chwilę Internet Explorera, połączyć się z hostem `appmsg.gadu-gadu.pl'.
|
|
34
|
|
35 GET /appsvc/appmsg.asp?fmnumber=<tutaj_numerek_gg> HTTP/1.0
|
|
36 Host: appmsg.gadu-gadu.pl
|
|
37 User-Agent: Mozilla/4.7 [en] (Win98; I)
|
|
38 Pragma: no-cache
|
|
39
|
|
40 na co powinniśmy dostać odpowiedź w stylu:
|
|
41
|
|
42 HTTP/1.0 200 OK
|
|
43
|
|
44 0 1 0 217.17.33.21:8074 217.17.33.21 217.17.33.21
|
|
45
|
|
46 co to oznacza? nie mam pojęcia ;) wygląda na to, że cały g*du-g*du jest
|
|
47 przemyślany i w przyszłości będzie można używać różnych serwerów do różnych
|
|
48 rzeczy, typu szukanie, obsługa klientów itd. póki co, łączyć się trzeba na
|
|
49 pierwszy adres (tak, ten z portem).
|
|
50
|
|
51 --- 3) logowanie się -------------------------------------------------------
|
|
52
|
|
53 po połączeniu się portem 8074 serwera g*du-g*du, dostajemy pakiet typu 0x0001,
|
|
54 który na potrzeby tego dokumentu nazwiemy:
|
|
55
|
|
56 #define GG_WELCOME 0x0001
|
|
57
|
|
58 reszta pakietu zawiera liczbę, na podstawie której liczony jest hash z hasła
|
|
59 klienta:
|
|
60
|
|
61 struct gg_welcome {
|
|
62 int key; /* klucz szyfrowania hasła */
|
|
63 };
|
|
64
|
|
65 kiedy mamy już tą wartość możemy odesłać pakiet logowania
|
|
66
|
|
67 #define GG_LOGIN 0x000c
|
|
68
|
|
69 musimy podać kilka informacji:
|
|
70
|
|
71 struct gg_login {
|
|
72 int uin; /* twój numerek */
|
|
73 int hash; /* hash hasła */
|
|
74 int status; /* status na dzień dobry */
|
|
75 int dunno1; /* == 0x0b */
|
|
76 int local_ip; /* mój adres ip */
|
|
77 short local_port; /* port, na którym słucham */
|
|
78 };
|
|
79
|
|
80 jak obliczyć hash hasła? hmm... nic prostszego. do każdej literki hasła
|
|
81 dodaje się jedynkę, mnoży wszystko razem, a potem przez liczbę podaną przez
|
|
82 serwer.
|
|
83
|
|
84 for (hash = 1; *passwd; passwd++)
|
|
85 hash *= (*passwd) + 1;
|
|
86
|
|
87 zrozumiałe, racja? jeśli wszystko się powiedzie, dostaniemy w odpowiedzi
|
|
88 pakiet typu
|
|
89
|
|
90 #define GG_LOGIN_OK 0x0003
|
|
91
|
|
92 z polem header->length = 0, lub pakiet
|
|
93
|
|
94 #define GG_LOGIN_FAILED 0x0009
|
|
95
|
|
96 --- 4) zmiana statusu -----------------------------------------------------
|
|
97
|
|
98 g*du-g*du przewiduje trzy stany klienta, które zmieniamy pakietem
|
|
99
|
|
100 #define GG_NEW_STATUS 0x0002
|
|
101
|
|
102 #define GG_STATUS_NOT_AVAIL 0x0001 /* rozłączony */
|
|
103 #define GG_STATUS_AVAIL 0x0002 /* dostępny */
|
|
104 #define GG_STATUS_BUSY 0x0003 /* zajęty */
|
|
105 #define GG_STATUS_INVISIBLE 0x0014 /* niewidoczny */
|
|
106
|
|
107 #define GG_STATUS_FRIENDS_MASK 0x8000 /* tylko dla przyjaciół */
|
|
108
|
|
109 struct gg_new_status {
|
|
110 int status; /* na jaki zmienić? */
|
|
111 }
|
|
112
|
|
113 należy pamiętać, żeby przed rozłączeniem się z serwerem należy zmienić
|
|
114 stan na GG_STATUS_NOT_AVAIL. jeśli ma być widoczny tylko dla przyjaciół,
|
|
115 należy dodać GG_STATUS_FRIENDS do normalnej wartości stanu.
|
|
116
|
|
117 --- 5) ludzie przychodzą, ludzie odchodzą ---------------------------------
|
|
118
|
|
119 zaraz po zalogowaniu możemy wysłać serwerowi listę ludzików w naszej liście
|
|
120 kontaktów, żeby dowiedzieć się, czy są w tej chwili dostępni. pakiet zawiera
|
|
121 dowolną ilość struktur gg_notify:
|
|
122
|
|
123 #define GG_NOTIFY 0x0010
|
|
124
|
|
125 struct gg_notify {
|
|
126 int uin; /* numerek danej osoby */
|
|
127 char dunno1; /* == 3 */
|
|
128 };
|
|
129
|
|
130 jeśli ktoś jest, serwer odpowie pakietem zawierającym jedną lub więcej
|
|
131 struktur gg_notify_reply:
|
|
132
|
|
133 #define GG_NOTIFY_REPLY 0x000c /* tak, to samo co GG_LOGIN */
|
|
134
|
|
135 struct gg_notify_reply {
|
|
136 int uin; /* numerek */
|
|
137 int status; /* status danej osoby */
|
|
138 int remote_ip; /* adres ip delikwenta */
|
|
139 short remote_port; /* port, na którym słucha klient */
|
|
140 int dunno1; /* == 0x0b */
|
|
141 short dunno2; /* znowu port? */
|
|
142 };
|
|
143
|
|
144 jeśli klient nie obsługuje połączeń między klientami (np. g*du-g*du 3.x)
|
|
145 zamiast adresu ip jest 0, zamiast portu jest 2. nieważne ;) w każdym razie,
|
|
146 jeśli ktoś się pojawi w trakcie pracy, również zostanie przysłany ten
|
|
147 pakiet. proste? proste :)
|
|
148
|
|
149 żeby dodać kogoś do listy w trakcie pracy, trzeba wysłać niżej opisany
|
|
150 pakiet. jego format jest identyczny jak przy GG_NOTIFY.
|
|
151
|
|
152 #define GG_ADD 0x000d
|
|
153
|
|
154 struct gg_add {
|
|
155 int uin; /* numerek */
|
|
156 char dunno1; /* == 3 */
|
|
157 };
|
|
158
|
|
159 jeśli ktoś opuści g*du-g*du lub zmieni stan, otrzymamy pakiet
|
|
160
|
|
161 #define GG_STATUS 0x0002
|
|
162
|
|
163 struct gg_status {
|
|
164 int uin; /* numerek */
|
|
165 int status; /* nowy stan */
|
|
166 };
|
|
167
|
|
168 --- 6) wysyłanie wiadomości ------------------------------------------------
|
|
169
|
|
170 przejdźmy do sedna sprawy ;)
|
|
171
|
|
172 #define GG_SEND_MSG 0x000b
|
|
173
|
|
174 #define GG_CLASS_MSG 0x0004
|
|
175 #define GG_CLASS_CHAT 0x0008
|
|
176
|
|
177 struct gg_send_msg {
|
|
178 int recipient;
|
|
179 int seq;
|
|
180 int class;
|
|
181 char message[];
|
|
182 };
|
|
183
|
|
184 wiadomo, odbiorca. numer sekwencyjny, który wykorzystujemy potem do
|
|
185 potwierdzenia. nie wykluczone, że w jakis sposób odróżnia się różne
|
|
186 rozmowy za pomocą części bajtów, ale raczej nie ma znaczenia. klasa
|
|
187 wiadomości pozwala odróżnić, czy wiadomość ma się pokazać w osobym
|
|
188 okienku czy jako kolejna linijka w okienku rozmowy. wygląda na to,
|
|
189 że to jakaś bitmapa, więc najlepiej olać inne bity niż 0x0f. (czasem
|
|
190 klienty wysyłają 0x04, czasem 0x24)
|
|
191
|
|
192 serwer po otrzymaniu wiadomości odsyła informację o tym. przy okazji
|
|
193 mówi, czy wiadomość dotarła do odbiorcy (status == GG_ACK_DELIVERED),
|
|
194 czy może jest offline i została zakolejkowana (GG_ACK_QUEUED):
|
|
195
|
|
196 #define GG_SEND_MSG_ACK 0x0005
|
|
197
|
|
198 #define GG_ACK_DELIVERED 0x0002
|
|
199 #define GG_ACK_QUEUED 0x0003
|
|
200
|
|
201 struct gg_send_msg_ack {
|
|
202 int status;
|
|
203 int recipient;
|
|
204 int seq;
|
|
205 };
|
|
206
|
|
207 numer sekwencyjny i adresat ten sam, co przy wysyłaniu.
|
|
208
|
|
209 --- 7) otrzymywanie wiadomości ---------------------------------------------
|
|
210
|
|
211 zbyt wiele wyjaśnień chyba nie trzeba. wiadomo od kogo. nieznane pola to
|
|
212 coś a'la numer sekwencyjny albo identyfikator okienka z rozmową albo nowe
|
|
213 dane dla setiathome. klasa wiadomości taka sama jak przy wysyłaniu:
|
|
214
|
|
215 #define GG_RECV_MSG 0x000a
|
|
216
|
|
217 struct gg_recv_msg {
|
|
218 int sender;
|
|
219 int dunno1;
|
|
220 int dunno2;
|
|
221 int class;
|
|
222 char message[];
|
|
223 };
|
|
224
|
|
225 --- 8) otrzymywanie wiadomości ---------------------------------------------
|
|
226
|
|
227 od czasu do czasu klient wysyła pakiet a'la ping do serwera i dostaje pustą
|
|
228 odpowiedź. ciężko stwierdzić, czy serwer wywala, jeśli nie dostanie pinga
|
|
229 przez jakiś czas, czy klient się rozłącza, jeśli serwer mu nie odpowie.
|
|
230 jakoś nie chce mi się sprawdzać ;)
|
|
231
|
|
232 #define GG_PING 0x0008
|
|
233
|
|
234 /* nie ma niczego */
|
|
235
|
|
236 #define GG_PONG 0x0007
|
|
237
|
|
238 /* nie ma niczego */
|
|
239
|
|
240 --- 9) podziękowania -------------------------------------------------------
|
|
241
|
|
242 swój wkład w poznanie protokołu miał Robert Woźny, który opisał nowości
|
|
243 w GG 4.6.
|
|
244
|
|
245 ----------------------------------------------------------------------------
|
|
246
|
|
247 $Id: protocol.txt 2406 2001-09-29 23:06:30Z warmenhoven $
|
|
248
|