File: protocol.html

package info (click to toggle)
libgadu 1:1.9.0-2+squeeze2
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 2,828 kB
  • ctags: 735
  • sloc: ansic: 10,507; sh: 10,195; perl: 320; makefile: 161
file content (2165 lines) | stat: -rw-r--r-- 79,393 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html>
<head>
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<style type="text/css">
body { font-family: tahoma, verdana, arial, helvetica, sans-serif; }
.tab { background-color: #a0a0a0; }
.tabh { background-color: #d0d0d0; }
.tabf { background-color: white; }
.tabf2 { background-color: white; color: silver; }
.check { background-color: white; color: silver; font-size: 0.7em; }
.warn { font-family: monospace; padding: 0.7em; background-color: red; border: 1px solid #80a0a0; }
.c { font-family: monospace; padding: 0.7em; background-color: #e0e0e0; border: 1px solid #a0a0a0; }
.http { font-family: monospace; padding: 0.7em; background-color: #c0f0c0; border: 1px solid #80a080; }
.example { font-family: monospace; padding: 0.7em; background-color: #c0f0f0; border: 1px solid #80a0a0; }
pre { margin: 0px; }
</style>
<title>Protokół Gadu-Gadu</title>
</head>

<body bgcolor="white" text="black">

<center>
<table width="600" border="0"><tr><td>

<center>
<h1>Protokół Gadu-Gadu</h1>
<h3>&copy; Copyright 2001-2009 <a href="#ch4">Autorzy</a></h3>
</center>

<hr />

<a name="index"></a>

<h2>Spis treści</h2>

<ol>
	<li><a href="#ch1">Protokół Gadu-Gadu</a><br />
		1.1.&nbsp;&nbsp;<a href="#ch1.1">Format pakietów i konwencje</a><br />
		1.2.&nbsp;&nbsp;<a href="#ch1.2">Zanim się połączymy</a><br />
		1.3.&nbsp;&nbsp;<a href="#ch1.3">Logowanie się</a><br />
		1.4.&nbsp;&nbsp;<a href="#ch1.4">Zmiana stanu</a><br />
		1.5.&nbsp;&nbsp;<a href="#ch1.5">Ludzie przychodzą, ludzie odchodzą</a><br />
		1.6.&nbsp;&nbsp;<a href="#ch1.6">Wysyłanie wiadomości</a><br />
		1.7.&nbsp;&nbsp;<a href="#ch1.7">Otrzymywanie wiadomości</a><br />
		1.8.&nbsp;&nbsp;<a href="#ch1.8">Ping, pong</a><br />
		1.9.&nbsp;&nbsp;<a href="#ch1.9">Rozłączenie</a><br />
		1.10.&nbsp;&nbsp;<a href="#ch1.10">Wiadomości systemowe</a><br />
		1.11.&nbsp;&nbsp;<a href="#ch1.11">Wiadomości GG_XML_ACTION</a><br />
		1.12.&nbsp;&nbsp;<a href="#ch1.12">Katalog publiczny</a><br />
		1.13.&nbsp;&nbsp;<a href="#ch1.13">Lista kontaktów</a><br />
		1.14.&nbsp;&nbsp;<a href="#ch1.14">Indeks pakietów</a><br />
	</li>
	<li><a href="#ch2">Usługi HTTP</a><br />
		2.1.&nbsp;&nbsp;<a href="#ch2.1">Format danych</a><br />
		2.2.&nbsp;&nbsp;<a href="#ch2.2">Tokeny</a><br />
		2.3.&nbsp;&nbsp;<a href="#ch2.3">Rejestracja konta</a><br />
		2.4.&nbsp;&nbsp;<a href="#ch2.4">Usunięcie konta</a><br />
		2.5.&nbsp;&nbsp;<a href="#ch2.5">Zmiana hasła</a><br />
		2.6.&nbsp;&nbsp;<a href="#ch2.6">Przypomnienie hasła pocztą</a><br />
	</li>
	<li><a href="#ch3">Połączenia bezpośrednie</a><br />
		3.1.&nbsp;&nbsp;<a href="#ch3.1">Nawiązanie połączenia</a><br />
		3.2.&nbsp;&nbsp;<a href="#ch3.2">Przesyłanie plików</a><br />
		3.3.&nbsp;&nbsp;<a href="#ch3.3">Rozmowy głosowe</a><br />
	</li>
	<li><a href="#ch4">Autorzy</a></li>
</ol>

<hr />

<a name="ch0"></a>
<h2>Informacje wstępne</h2>

<p>
Opis protokołu używanego przez Gadu-Gadu bazuje na doświadczeniach
przeprowadzonych przez autorów oraz informacjach nadsyłanych przez 
użytkowników. Żaden klient Gadu-Gadu nie został skrzywdzony podczas
badań. Reverse-engineering opierał się głównie na analizie pakietów
przesyłanych między klientem a serwerem.
</p>

<p>
Najnowsza wersja opisu protokołu znajduje się pod adresem
<a href="http://toxygen.net/libgadu/protocol/">http://toxygen.net/libgadu/protocol/</a>.
</p>

<hr />

<a name="ch1"></a>
<h2>1. Protokół Gadu-Gadu</h2>

<a name="ch1.1"></a>
<h3>1.1. Format pakietów i konwencje</h3>

<p>
Podobnie jak coraz większa ilość komunikatorów, Gadu-Gadu korzysta z
protokołu TCP/IP. Każdy pakiet zawiera na początku dwa stałe pola:
</p>

<div class="c">
<pre>struct gg_header {
	int type;	<i>/* typ pakietu */</i>
	int length;	<i>/* długość reszty pakietu */</i>
};</pre>
</div>

<p>
Wszystkie zmienne liczbowe są zgodne z kolejnością bajtów maszyn Intela,
czyli Little-Endian. Wszystkie teksty są kodowane przy użyciu zestawu
znaków UTF-8, chyba że zaznaczono inaczej. Linie kończą się znakami
<tt>\r\n</tt>.
</p>

<p>
Przy opisie struktur, założono, że <tt>char</tt> ma rozmiar 1 bajtu,
<tt>short</tt> 2 bajtów, <tt>int</tt> 4 bajtów, <tt>long long</tt> 8 bajtów,
wszystkie bez znaku. Używając architektur innych niż i386, należy zwrócić
szczególną uwagę na rozmiar typów zmiennych i kolejność bajtów. Poza tym,
większość dostępnych obecnie kompilatorów domyślnie wyrównuje zmienne do
rozmiaru słowa danej architektury, więc należy wyłączyć tą funkcję. W przypadku
gcc będzie to <tt>__attribute__ ((packed))</tt> zaraz za deklaracją każdej
struktury, a dla Microsoft Visual C++ powinno pomóc: </p>

<div class="c">
<pre>#pragma pack(push, 1)

<i>/* deklaracje */</i>

#pragma pack(pop)</pre>
</div>

<p>
Pola, których znaczenie jest nieznane, lub nie do końca jasne, oznaczono
przedrostkiem <tt>unknown</tt>.
</p>

<hr />

<a name="ch1.2"></a>
<h3>1.2. Zanim się połączymy</h3>

<p>
Żeby wiedzieć, z jakim serwerem mamy się połączyć, należy za pomocą HTTP
połączyć się z <tt>appmsg.gadu-gadu.pl</tt> i wysłać:
</p>

<div class="http">
<pre>GET /appsvc/appmsg_ver8.asp?fmnumber=<b>NUMER</b>&amp;fmt=<b>FORMAT</b>&amp;lastmsg=<b>WIADOMOŚĆ</b>&amp;version=<b>WERSJA</b> HTTP/1.1
Connection: Keep-Alive
Host: appmsg.gadu-gadu.pl</pre>
</div>

<p>
Gdzie:
</p>

<ul>
<li><b>NUMER</b> jest numerem Gadu-Gadu.</li>
<li><b>WERSJA</b> jest wersją klienta w postaci &bdquo;<tt>A.B.C.D</tt>&rdquo;
(na przykład &bdquo;<tt>8.0.0.7669</tt>&rdquo;).</li>
<li><b>FORMAT</b> określa czy wiadomość systemowa będzie przesyłana czystym
tekstem (brak zmiennej &bdquo;fmt&rdquo;) czy w HTMLu (wartość &bdquo;<tt>2</tt>&rdquo;).</li>
<li><b>WIADOMOŚĆ</b> jest numerem ostatnio otrzymanej wiadomości systemowej.</li>
</ul>

<p>
Na postawione w ten sposób zapytanie, serwer może odpowiedzieć w następujący
sposób:
</p>

<div class="example">
<pre>HTTP/1.0 200 OK
Connection: close

0 0 91.197.13.78:8074 91.197.13.78</pre>
</div>

<p>
Pierwsze pole jest numerem wiadomości systemowej, a trzecie i czwarte
podają nam namiary na właściwy serwer. Jeśli serwer jest niedostępny,
zamiast adresu IP jest zwracany tekst &bdquo;<tt>notoperating</tt>&rdquo;.
Jeżeli połączenie z portem 8074 nie powiedzie się z jakichś powodów,
można się łączyć na port 443. 
</p>

<p>
Jeśli pierwsza liczba jest różna od zera, zaraz po nagłówku znajduje się
wiadomość systemowa w wybranym formacie, lub jeśli linia zaczyna się od znaku
&bdquo;<tt>@</tt>&rdquo;, adres strony, którą należy otworzyć w przeglądarce.
</p>

<div class="http">
<pre>GET /appsvc/appmsg3.asp?fmnumber=<b>NUMER</b>&amp;version=<b>WERSJA</b>&amp;fmt=<b>FORMAT</b>&amp;lastmsg=<b>WIADOMOŚĆ</b>
Host: appmsg.gadu-gadu.pl
User-Agent: <b>PRZEGLĄDARKA</b>
Pragma: no-cache</pre>
</div>

<hr />

<a name="ch1.3"></a>
<h3>1.3. Logowanie się</h3>

<p>
Po połączeniu się portem 8074 lub 443 serwera Gadu-Gadu, otrzymujemy pakiet
typu <tt>0x0001</tt>, który na potrzeby tego dokumentu nazwiemy:
</p>

<div class="c">
<pre>#define GG_WELCOME 0x0001</pre>
</div>

<p>
Reszta pakietu zawiera ziarno &mdash; wartość, którą razem z hasłem przekazuje
się do funkcji skrótu:
</p>

<div class="c">
<pre>struct gg_welcome {
	int seed;	<i>/* ziarno */</i>
};</pre>
</div>

<p>
Kiedy mamy już tą wartość możemy odesłać pakiet logowania:
</p>

<div class="c">
<pre>#define GG_LOGIN80 0x0031

struct gg_login80 {
        int uin;              <i>/* numer Gadu-Gadu */</i>
        char language[2];     <i>/* język: "pl" */</i>
        char hash_type;       <i>/* rodzaj funkcji skrótu hasła */</i>
        char hash[64];        <i>/* skrót hasła dopełniony \0 */</i>
        int status;           <i>/* początkowy status połączenia */</i>
        int flags;            <i>/* flagi (przeznaczenie nieznane) */</i>
        int features;         <i>/* opcje protokołu (0x00000007)*/</i>
        int local_ip;         <i>/* lokalny adres połączeń bezpośrednich (nieużywany) */</i>
        short local_port;     <i>/* lokalny port połączeń bezpośrednich (nieużywany) */</i>
        int external_ip;      <i>/* zewnętrzny adres (nieużywany) */</i>
        short external_port;  <i>/* zewnętrzny port (nieużywany) */</i>
        char image_size;      <i>/* maksymalny rozmiar grafiki w KB */</i>
        char unknown2;        <i>/* 0x64 */</i>
        int version_len;      <i>/* długość ciągu z wersją (0x21) */</i>
        char version[];       <i>/* "Gadu-Gadu Client build 8.0.0.7669" (bez \0) */</i>
        int description_size; <i>/* rozmiar opisu */</i>
        char description[];   <i>/* opis (nie musi wystąpić, bez \0) */</i>
};</pre>

</div>

<p>
Pola określające adresy i port są pozostałościami po poprzednich wersjach
protokołów i w obecnej wersji zawierają zera.</p>
<p>Pole z flagami jest przekazywane innym kontaktom, ale jego znaczenie nie jest jeszcze znane.
Ustalono jedynie, że wartość <tt>0x00100000</tt> powoduje wyświetlenie ikony telefonu komórkowego
na liście kontaktów, a bitmaska <tt>0x00800000</tt> wyłącza "cenzurowanie" linków</p>
<p>Pole opcji protokołu zawsze zawiera wartość <tt>0x00000007</tt> i jest mapą bitową:</p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td><b>Bit</b></td><td><b>Wartość</b></td><td><b>Znaczenie</b></td></tr>
<tr class="tabf"><td>0</td><td><tt>0x00000001</tt></td><td>Rodzaj pakietu informującego o zmianie stanu kontaktów (patrz bit 2)<br /><tt>0</tt> &mdash; <tt>GG_STATUS77</tt>, <tt>GG_NOTIFY_REPLY77</tt><br /><tt>1</tt> &mdash; <tt>GG_STATUS80BETA</tt>, <tt>GG_NOTIFY_REPLY80BETA</tt></td></tr>
<tr class="tabf"><td>1</td><td><tt>0x00000002</tt></td><td>Rodzaj pakietu z otrzymają wiadomością<br /><tt>0</tt> &mdash; <tt>GG_RECV_MSG</tt><br /><tt>1</tt> &mdash; <tt>GG_RECV_MSG80</tt></td></tr>
<tr class="tabf"><td>2</td><td><tt>0x00000004</tt></td><td>Rodzaj pakietu informującego o zmianie stanu kontaktów (patrz bit 0)<br /><tt>0</tt> &mdash; wybrany przez bit 0<br /><tt>1</tt> &mdash; <tt>GG_STATUS80</tt>, <tt>GG_NOTIFY_REPLY80</tt></td></tr>
</table>

<p>
Skrót hasła można liczyć na dwa sposoby:
</p>

<div class="c">
<pre>#define GG_LOGIN_HASH_GG32 0x01
#define GG_LOGIN_HASH_SHA1 0x02</pre>
</div>

<p>
Pierwszy algorytm (<tt>GG_LOGIN_HASH_GG32</tt>) został wymyślony na potrzeby
Gadu-Gadu i zwraca 32-bitową wartość dla danego ziarna i hasła. Jego
implementacja w języku C wygląda następująco:
</p>

<div class="c">
<pre>int gg_login_hash(unsigned char *password, unsigned int seed)
{
	unsigned int x, y, z;

	y = seed;

	for (x = 0; *password; password++) {
		x = (x &amp; 0xffffff00) | *password;
		y ^= x;
		y += x;
		x &lt;&lt;= 8;
		y ^= x;
		x &lt;&lt;= 8;
		y -= x;
		x &lt;&lt;= 8;
		y ^= x;

		z = y &amp; 0x1f;
		y = (y &lt;&lt; z) | (y &gt;&gt; (32 - z));
	}

	return y;
}</pre>
</div>

<p>
Ze względu na niewielki zakres wartości wyjściowych, istnieje
prawdopodobieństwo, że inne hasło przy odpowiednim ziarnie da taki sam wynik.
Z tego powodu zalecane jest używane algorytmu
<a href="http://pl.wikipedia.org/wiki/SHA-1">SHA-1</a>, którego implementacje
są dostępne dla większości współczesnych systemów operacyjnych. Skrót SHA-1
należy obliczyć z połączenia hasła (bez <tt>\0</tt>) i binarnej reprezentacji
ziarna. Przykładowy kod może wyglądać w następujący sposób:
</p>

<div class="c">
<pre>char *gg_sha_hash(char *password, unsigned int seed)
{
	SHA1_CTX ctx;
	static char result[20];
	  
	SHA1_Init(&amp;ctx);  
	SHA1_Update(&amp;ctx, password, strlen(password));
	SHA1_Update(&amp;ctx, &amp;seed, sizeof(seed));
	SHA1_Final(result, &amp;ctx);

	return result;
}</pre>
</div>

<p>
Jeśli autoryzacja się powiedzie, dostaniemy w odpowiedzi pakiet:
</p>

<div class="c">
<pre>#define GG_LOGIN80_OK 0x0035

struct gg_login80_ok {
	int unknown1;	<i>/* 01 00 00 00 */</i>
};</pre>
</div>

<p>
W przypadku błędu autoryzacji otrzymamy pusty pakiet:
</p>

<div class="c">
<pre>#define GG_LOGIN_FAILED 0x0009</pre>
</div>

<hr />

<a name="ch1.4"></a>
<h3>1.4. Zmiana stanu</h3>

<p>
Gadu-Gadu przewiduje kilka stanów klienta, które zmieniamy pakietem typu:
</p>

<div class="c">
<pre>#define GG_NEW_STATUS80 0x0038

struct gg_new_status80 {
	int status;		<i>/* na jaki zmienić? */</i>
	int flags;              <i>/* flagi (nieznane przeznaczenie) */</i>
	int description_size;   <i>/* rozmiar opisu */</i>
	char description[];	<i>/* opis (nie musi wystąpić, bez \0) */</i>
};</pre>
</div>

<p>
Możliwe stany to:
</p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td><b>Etykieta</b></td><td><b>Wartość</b></td><td><b>Znaczenie</b></td></tr>
<tr class="tabf"><td><tt>GG_STATUS_NOT_AVAIL</tt></td><td><tt>0x0001</tt></td><td>Niedostępny</td></tr>
<tr class="tabf"><td><tt>GG_STATUS_NOT_AVAIL_DESCR</tt></td><td><tt>0x0015</tt></td><td>Niedostępny (z opisem)</td></tr>
<tr class="tabf"><td><tt>GG_STATUS_FFC</tt></td><td><tt>0x0017</tt></td><td>PoGGadaj ze mną</td></tr>
<tr class="tabf"><td><tt>GG_STATUS_FFC_DESCR</tt></td><td><tt>0x0018</tt></td><td>PoGGadaj ze mną (z opisem)</td></tr>
<tr class="tabf"><td><tt>GG_STATUS_AVAIL</tt></td><td><tt>0x0002</tt></td><td>Dostępny</td></tr>
<tr class="tabf"><td><tt>GG_STATUS_AVAIL_DESCR</tt></td><td><tt>0x0004</tt></td><td>Dostępny (z opisem)</td></tr>
<tr class="tabf"><td><tt>GG_STATUS_BUSY</tt></td><td><tt>0x0003</tt></td><td>Zajęty</td></tr>
<tr class="tabf"><td><tt>GG_STATUS_BUSY_DESCR</tt></td><td><tt>0x0005</tt></td><td>Zajęty (z opisem)</td></tr>
<tr class="tabf"><td><tt>GG_STATUS_DND</tt></td><td><tt>0x0021</tt></td><td>Nie przeszkadzać</td></tr>
<tr class="tabf"><td><tt>GG_STATUS_DND_DESCR</tt></td><td><tt>0x0022</tt></td><td>Nie przeszkadzać (z opisem)</td></tr>
<tr class="tabf"><td><tt>GG_STATUS_INVISIBLE</tt></td><td><tt>0x0014</tt></td><td>Niewidoczny</td></tr>
<tr class="tabf"><td><tt>GG_STATUS_INVISIBLE_DESCR</tt></td><td><tt>0x0016</tt></td><td>Niewidoczny (z opisem)</td></tr>
<tr class="tabf"><td><tt>GG_STATUS_BLOCKED</tt></td><td><tt>0x0006</tt></td><td>Zablokowany</td></tr>
<tr class="tabf"><td><tt>GG_STATUS80_DESCR_MASK</tt></td><td><tt>0x0100</tt></td><td>Maska bitowa oznaczająca ustawiony opis graficzny</td></tr>
<tr class="tabf"><td><tt>GG_STATUS80_DESCR_MASK</tt></td><td><tt>0x4000</tt></td><td>Maska bitowa oznaczająca ustawiony opis</td></tr>
<tr class="tabf"><td><tt>GG_STATUS_FRIENDS_MASK</tt></td><td><tt>0x8000</tt></td><td>Maska bitowa oznaczająca tryb tylko dla przyjaciół</td></tr>
</table>

<p>
Należy pamiętać, żeby przed rozłączeniem się z serwerem należy zmienić
stan na <tt>GG_STATUS_NOT_AVAIL</tt> lub <tt>GG_STATUS_NOT_AVAIL_DESCR</tt>.
Jeśli ma być widoczny tylko dla przyjaciół, należy dodać
<tt>GG_STATUS_FRIENDS_MASK</tt> do normalnej wartości stanu.
</p>

<p>
Maksymalna długość opisu wynosi 255 bajtów, jednak należy pamiętać że znak w UTF-8
czasami zajmuje więcej niż 1 bajt.
</p>

<hr />

<a name="ch1.5"></a>
<h3>1.5. Ludzie przychodzą, ludzie odchodzą</h3>

<p>
Zaraz po zalogowaniu możemy wysłać serwerowi naszą listę kontaktów, żeby
dowiedzieć się, czy są w danej chwili dostępni. Lista kontaktów jest dzielona
na pakiety po 400 wpisów. Pierwsze wpisy są typu <tt>GG_NOTIFY_FIRST</tt>,
a ostatni typu <tt>GG_NOTIFY_LAST</tt>, żeby serwer wiedział, kiedy kończymy.
Jeśli lista kontaktów jest mniejsza niż 400 wpisów, wysyłamy oczywiście tylko
<tt>GG_NOTIFY_LAST</tt>. Pakiety te zawierają struktury <tt>gg_notify</tt>:
</p>

<div class="c">
<pre>#define GG_NOTIFY_FIRST 0x000f
#define GG_NOTIFY_LAST 0x0010
	
struct gg_notify {
	int uin;	<i>/* numer Gadu-Gadu kontaktu */</i>
	char type;	<i>/* rodzaj użytkownika */</i>
};</pre>	
</div>

<p>
Gdzie pole <tt>type</tt> jest mapą bitową następujących wartości:
</p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td><b>Etykieta</b></td><td><b>Wartość</b></td><td><b>Znaczenie</b></td></tr>
<tr class="tabf"><td><tt>GG_USER_BUDDY</tt></td><td><tt>0x01</tt></td><td>Każdy użytkownik dodany do listy kontaktów</td></tr>
<tr class="tabf"><td><tt>GG_USER_FRIEND</tt></td><td><tt>0x02</tt></td><td>Użytkownik, dla którego jesteśmy widoczni w trybie &bdquo;tylko dla przyjaciół&rdquo;</td></tr>
<tr class="tabf"><td><tt>GG_USER_BLOCKED</tt></td><td><tt>0x04</tt></td><td>Użytkownik, którego wiadomości nie chcemy otrzymywać</td></tr>
</table>

<p>
Jednak dla zachowania starego nazewnictwa stałych można używać najczęściej spotykane wartości to:
</p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td><b>Etykieta</b></td><td><b>Wartość</b></td><td><b>Znaczenie</b></td></tr>
<tr class="tabf"><td><tt>GG_USER_OFFLINE</tt></td><td><tt>0x01</tt></td><td>Użytkownik, dla którego będziemy niedostępni, ale mamy go w liście kontaktów</td></tr>
<tr class="tabf"><td><tt>GG_USER_NORMAL</tt></td><td><tt>0x03</tt></td><td>Zwykły użytkownik dodany do listy kontaktów</td></tr>
<tr class="tabf"><td><tt>GG_USER_BLOCKED</tt></td><td><tt>0x04</tt></td><td>Użytkownik, którego wiadomości nie chcemy otrzymywać</td></tr>
</table>

<p>
Jeśli nie mamy nikogo na liście wysyłamy następujący pakiet o zerowej długości:
</p>

<div class="c">
<pre>#define GG_LIST_EMPTY 0x0012</pre>
</div>

<p>
Jeśli ktoś jest, serwer odpowie pakietem <tt>GG_NOTIFY_REPLY80</tt>
zawierającym jedną lub więcej struktur <tt>gg_notify_reply80</tt>:
</p>

<div class="c">
<pre>#define GG_NOTIFY_REPLY80 0x37
	
struct gg_notify_reply80 {
	int uin;		<i>/* numer Gadu-Gadu kontaktu */</i>
	int status;		<i>/* status */</i>
	int flags;		<i>/* flagi (nieznane przeznaczenie) */</i>
	int remote_ip;		<i>/* adres IP bezpośrednich połączeń (nieużywane) */</i>
	short remote_port;	<i>/* port bezpośrednich połączeń (nieużywane) */</i>
	char image_size;	<i>/* maksymalny rozmiar obrazków w KB */</i>
	char unknown2;		<i>/* 0x00 */</i>
	int unknown3;		<i>/* 0x00000000 */</i>
	int description_size;	<i>/* rozmiar opisu */</i>
	char description[];	<i>/* opis (nie musi wystąpić, bez \0) */</i>
};</pre>
</div>

<p>
Zdarzają się też inne &bdquo;nietypowe&rdquo; wartości, ale ich znaczenie nie
jest jeszcze do końca znane.
</p>

<p>
Aby dodać do listy kontaktów numer w trakcie połączenia, należy wysłać niżej
opisany pakiet. Jego format jest identyczny jak <tt>GG_NOTIFY_*</tt>, z tą
różnicą, że zawiera jeden numer.
</p>

<div class="c">
<pre>#define GG_ADD_NOTIFY 0x000d
	
struct gg_add_notify {
	int uin;	<i>/* numerek */</i>
	char type;	<i>/* rodzaj użytkownika */</i>
};</pre>
</div>

<p>
Poniższy pakiet usuwa z listy kontaktów:
</p>

<div class="c">
<pre>#define GG_REMOVE_NOTIFY 0x000e
	
struct gg_remove_notify {
	int uin;	<i>/* numerek */</i>
	char type;	<i>/* rodzaj użytkownika */</i>
};</pre>
</div>

<p>
Należy zwrócić uwagę, że pakiety <tt>GG_ADD_NOTIFY</tt>
i <tt>GG_REMOVE_NOTIFY</tt> dodają i usuwają flagi będące mapą bitową. Aby
zmienić status użytkownika z normalnego na blokowanego, należy najpierw
usunąć rodzaj <tt>GG_USER_NORMAL</tt>, a następnie dodać rodzaj 
<tt>GG_USER_BLOCKED</tt>.
</p>

<p>
Jeśli ktoś opuści Gadu-Gadu lub zmieni stan, otrzymamy poniższy pakiet,
którego struktura jest identyczna z <tt>GG_NOTIFY_REPLY80</tt>.
</p>

<div class="c">
<pre>#define GG_STATUS80 0x0036</pre>
</div>

<hr />

<a name="ch1.6"></a>
<h3>1.6. Wysyłanie wiadomości</h3>

<p>
Wiadomości wysyła się następującym typem pakietu:
</p>

<div class="c">
<pre>#define GG_SEND_MSG80 0x002d

struct gg_send_msg80 {
	int recipient;		<i>/* numer odbiorcy */</i>
	int seq;		<i>/* numer sekwencyjny */</i>
	int class;		<i>/* klasa wiadomości */</i>
	int offset_plain;	<i>/* położenie treści czystym tekstem */</i>
	int offset_attributes;	<i>/* położenie atrybutów */</i>
	char html_message[];	<i>/* treść w formacie HTML (zakończona \0) */</i>
	char plain_message[];	<i>/* treść czystym tekstem (zakończona \0) */</i>
	char attributes[];	<i>/* atrybuty wiadomości */</i>
};</pre>

</div>

<p>
Numer sekwencyjny w poprzednich wersjach protokołu był losową liczbą
pozwalającą przypisać potwierdzenie do wiadomości. Obecnie jest znacznikiem
czasu w postaci uniksowej (liczba sekund od 1 stycznia 1970r. UTC).
</p>

<p>
Klasa wiadomości jest mapą bitową (domyślna wartość to <tt>0x08</tt>):
</p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td><b>Etykieta</b></td><td><b>Wartość</b></td><td><b>Znaczenie</b></td></tr>
<tr class="tabf"><td><tt>GG_CLASS_QUEUED</tt></td><td><tt>0x0001</tt></td><td>Bit ustawiany wyłącznie przy odbiorze wiadomości, gdy wiadomość została wcześniej zakolejkowania z powodu nieobecności</td></tr>
<tr class="tabf"><td><tt>GG_CLASS_MSG</tt></td><td><tt>0x0004</tt></td><td>Wiadomość ma się pojawić w osobnym okienku (nieużywane)</td></tr>
<tr class="tabf"><td><tt>GG_CLASS_CHAT</tt></td><td><tt>0x0008</tt></td><td>Wiadomość jest częścią toczącej się rozmowy i zostanie wyświetlona w istniejącym okienku</td></tr>
<tr class="tabf"><td><tt>GG_CLASS_CTCP</tt></td><td><tt>0x0010</tt></td><td>Wiadomość jest przeznaczona dla klienta Gadu-Gadu i nie powinna być wyświetlona użytkownikowi (nieużywane)</td></tr>
<tr class="tabf"><td><tt>GG_CLASS_ACK</tt></td><td><tt>0x0020</tt></td><td>Klient nie życzy sobie potwierdzenia wiadomości</td></tr>
</table>

<p>
Długość treści wiadomości nie powinna przekraczać 2000 znaków. Oryginalny
klient zezwala na wysłanie do 1989 znaków. Treść w formacie HTML jest kodowana
UTF-8. Treść zapisana czystym tekstem jest kodowana zestawem znaków CP1250.
W obu przypadkach, mimo domyślnych atrybutów tekstu, oryginalny klient dodaje
informacje o formatowaniu tekstu. Dla HTML wygląda to następująco:
</p>

<div class="http">
<pre>&lt;span style="color:#000000; font-family:'MS Shell Dlg 2'; font-size:9pt; "&gt;Treść&lt;/span&gt;</pre>
</div>

<p>
Dla czystego tekstu dodawane są informacje o tym, że tekst ma kolor czarny:
</p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td><b>Bajty</b></td><td><b>Opis</b></td></tr>
<tr class="tabf"><td><tt>0x02</tt></td><td>Flaga formatowania tekstu</td></tr>
<tr class="tabf"><td><tt>0x06 0x00</tt></td><td>Długość bloku formatowania wynosi 6 bajtów</td></tr>
<tr class="tabf"><td><tt>0x00 0x00</tt></td><td>Atrybut tekstu od pozycji 0</td></tr>
<tr class="tabf"><td><tt>0x08</tt></td><td>Tekst kolorowy</td></tr>
<tr class="tabf"><td><tt>0x00 0x00 0x00</tt></td><td>Kolor czarny</td></tr>
</table>

<a name="ch1.6.1"></a>
<h4>1.6.1. Konferencje</h4>

<p>
Podczas konferencji ta sama wiadomość jest wysyłana do wszystkich odbiorców,
a do sekcji atrybutów dołączana jest lista pozostałych uczestników konferencji.
Dla przykładu, jeśli w konferencji biorą udział Ala, Bartek, Celina i Darek,
to osoba Ala wysyła wysyła do Bartka wiadomość z listą zawierającą numery
Celiny i Darka, do Celiny z numerami Bartka i Darka, a do Darka z numerami
Bartka i Celiny. Lista pozostałych uczestników konferencji jest przekazywana
za pomocą struktury:
</p>

<div class="c">
<pre>struct gg_msg_recipients {
	char flag;		<i>/* 0x01 */</i>
	int count;		<i>/* liczba odbiorców */</i>
	int recipients[];	<i>/* lista odbiorców */</i>
};</pre>
</div>

<p>
Na przykład, by wysłać wysłać do do dwóch osób, należy wysłać pakiet z
wiadomością o treści:
</p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td><b>Bajty</b></td><td><b>Opis</b></td></tr>
<tr class="tabf"><td><tt>0x01</tt></td><td>Flaga wiadomości konferencyjnej</td></tr>
<tr class="tabf"><td><tt>0x02 0x00 0x00 0x00</tt></td><td>Liczba pozostałych uczestników</td></tr>
<tr class="tabf"><td><tt>0xXX 0xXX 0xXX 0xXX</tt></td><td>Numer uczestnika #2</td></tr>
<tr class="tabf"><td><tt>0xYY 0xYY 0xYY 0xYY</tt></td><td>Numer uczestnika #3</td></tr>
</table>

<a name="ch1.6.2"></a>
<h4>1.6.2. Formatowanie tekstu</h4>

<p>
Możliwe jest również dodawanie do wiadomości różnych atrybutów tekstu, jak
pogrubienie czy kolory. Niezbędne jest dołączenie następującej struktury:
</p>

<div class="c">
<pre>struct gg_msg_richtext {
	char flag;	<i>/* 0x02 */</i>
	short length;	<i>/* długość dalszej części */</i>
};</pre>
</div>

<p>
Dalsza część pakietu zawiera odpowiednią ilość struktur o łącznej długości
określonej polem <tt>length</tt>:
</p>

<div class="c">
<pre>struct gg_msg_richtext_format {
	short position;	<i>/* pozycja atrybutu w tekście */</i>
	char font;	<i>/* atrybuty czcionki */</i>
	char rgb[3];	<i>/* kolor czcionki (nie musi wystąpić) */</i>
	struct gg_msg_richtext_image image; <i>/* obrazek (nie musi wystąpić) */</i>
};</pre>
</div>

<p>
Każda z tych struktur określa kawałek tekstu począwszy od znaku określonego
przez pole <tt>position</tt> (liczone od zera) aż do następnego wpisu lub
końca tekstu. Pole <tt>font</tt> jest mapą bitową i kolejne bity mają
następujące znaczenie:
</p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td><b>Etykieta</b></td><td><b>Wartość</b></td><td><b>Znaczenie</b></td></tr>
<tr class="tabf"><td><tt>GG_FONT_BOLD</tt></td><td><tt>0x01</tt></td><td>Pogrubiony tekst</td></tr>
<tr class="tabf"><td><tt>GG_FONT_ITALIC</tt></td><td><tt>0x02</tt></td><td>Kursywa</td></tr>
<tr class="tabf"><td><tt>GG_FONT_UNDERLINE</tt></td><td><tt>0x04</tt></td><td>Podkreślenie</td></tr>
<tr class="tabf"><td><tt>GG_FONT_COLOR</tt></td><td><tt>0x08</tt></td><td>Kolorowy tekst. Tylko w tym wypadku struktura <tt>gg_msg_richtext_format</tt> zawiera pole <tt>rgb[]</tt> będące opisem trzech składowych koloru, kolejno czerwonej, zielonej i niebieskiej.</td></tr>
<tr class="tabf"><td><tt>GG_FONT_IMAGE</tt></td><td><tt>0x80</tt></td><td>Obrazek. Tylko w tym wypadku struktura <tt>gg_msg_richtext_format</tt> zawiera pole <tt>image</tt>.</td></tr>
</table>

<p>
Jeśli wiadomość zawiera obrazek, przesyłana jest jego suma kontrolna CRC32
i rozmiar. Dzięki temu nie trzeba za każdym razem wysyłać każdego obrazka
&mdash; klienty je zachowują. Struktura <tt>gg_msg_richtext_image</tt> opisująca
obrazek umieszczony w wiadomości wygląda następująco:
</p>

<div class="c">
<pre>struct gg_msg_richtext_image {
	short unknown1;	<i>/* 0x0109 */</i>
	int size;	<i>/* rozmiar obrazka */</i>
	int crc32;	<i>/* suma kontrolna obrazka */</i>
};</pre>
</div>

<p>
Przykładowo, by przesłać tekst &bdquo;ala <b>ma</b> kota&rdquo;, należy
dołączyć do wiadomości następującą sekwencję bajtów:
</p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td><b>Bajty</b></td><td><b>Opis</b></td></tr>
<tr class="tabf"><td><tt>0x02</tt></td><td>Flaga formatowania tekstu</td></tr>
<tr class="tabf"><td><tt>0x06 0x00</tt></td><td>Długość bloku formatowania wynosi 6 bajtów</td></tr>
<tr class="tabf"><td><tt>0x04 0x00</tt></td><td>Atrybut tekstu od pozycji 4</td></tr>
<tr class="tabf"><td><tt>0x01</tt></td><td>Tekst pogrubiony</td></tr>
<tr class="tabf"><td><tt>0x06 0x00</tt></td><td>Atrybut tekstu od pozycji 6</td></tr>
<tr class="tabf"><td><tt>0x00</tt></td><td>Tekst normalny</td></tr>
</table>

<p>
W przypadku gdy wiadomość zawiera zarówno informacje o uczestnikach konferencji,
jaki i o formatowaniu, najpierw informacje o konferencji powinny znajdować się
przed formatowaniem.
</p>

<p>
Jeśli obrazek jest przesyłany w wiadomości bez tekstu, jej treść powinna
zawierać znak niełamliwej spacji (kod 160 w kodowaniu CP1250). W innym
przypadku nowsze klienty (np. Nowe Gadu-Gadu) nie wyświetlą obrazka.
</p>

<a name="ch1.6.3"></a>
<h4>1.6.3. Przesyłanie obrazków</h4>

<p>
Gdy klient nie posiada w pamięci podręcznej obrazka o podanych parametrach,
wysyła pustą wiadomość o klasie <tt>GG_CLASS_MSG</tt> z dołączoną strukturą
<tt>gg_msg_image_request</tt>:
</p>

<div class="c">
<pre>struct gg_msg_image_request {
	char flag;	<i>/* 0x04 */</i>
	int size;	<i>/* rozmiar */</i>
	int crc32;	<i>/* suma kontrolna */</i>
};</pre>
</div>

<p>
Przykładowa treść wiadomości z prośbą o wysłanie obrazka o długości 10000
bajtów i sumie kontrolnej 0x12345678 to:
</p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td><b>Bajty</b></td><td><b>Opis</b></td></tr>
<tr class="tabf"><td><tt>0x04</tt></td><td>Flaga pobrania obrazka</td></tr>
<tr class="tabf"><td><tt>0x10 0x27 0x00 0x00</tt></td><td>Rozmiar obrazka w bajtach</td></tr>
<tr class="tabf"><td><tt>0x78 0x56 0x34 0x12</tt></td><td>Suma kontrolna</td></tr>
</table>

<p>
W odpowiedzi, drugi klient wysyła obrazek za pomocą wiadomości o zerowej
długości (należy pamiętać o kończącym bajcie o wartości <tt>0x00</tt>)
z dołączoną strukturą <tt>gg_msg_image_reply</tt>:
</p>

<div class="c">
<pre>struct gg_msg_image_reply {
	char flag;      	<i>/* 0x05 lub 0x06 */</i>
	int size;       	<i>/* rozmiar */</i>
	int crc32;      	<i>/* suma kontrolna */</i>
	char filename[];	<i>/* nazwa pliku (nie musi wystąpić) */</i>
	char image[];		<i>/* zawartość obrazka (nie musi wystąpić) */</i>
};</pre>
</div>

<p>
Jeśli długość struktury <tt>gg_msg_image_reply</tt> jest dłuższa niż 1909
bajtów, treść obrazka jest dzielona na kilka pakietów nie przekraczających
1909 bajtów. Pierwszy pakiet ma pole <tt>flag</tt> równe <tt>0x05</tt> i ma
wypełnione pole <tt>filename</tt>, a w kolejnych pole <tt>flag</tt> jest równe
<tt>0x06</tt> i pole <tt>filename</tt> w ogóle nie występuje (nawet bajt
zakończenia ciągu znaków).
</p>

<p>
Jeśli otrzymamy pakiet bez pola <tt>filename</tt> oraz <tt>image</tt>, oznacza
to, że klient nie posiada żądanego obrazka.
</p>

<a name="ch1.6.4"></a>
<h4>1.6.4. Potwierdzenie</h4>

<p>
Serwer po otrzymaniu wiadomości odsyła potwierdzenie, które przy okazji
mówi nam, czy wiadomość dotarła do odbiorcy czy została zakolejkowana
z powodu nieobecności. Otrzymujemy je w postaci pakietu:
</p>

<div class="c">
<pre>#define GG_SEND_MSG_ACK 0x0005
	
struct gg_send_msg_ack {
	int status;	<i>/* stan wiadomości */</i>
	int recipient;	<i>/* numer odbiorcy */</i>
	int seq;	<i>/* numer sekwencyjny */</i>
};</pre>
</div>

<p>
Numer sekwencyjny i numer adresata są takie same jak podczas wysyłania,
a stan wiadomości może być jednym z następujących:
</p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td><b>Etykieta</b></td><td><b>Wartość</b></td><td><b>Znaczenie</b></td></tr>
<tr class="tabf"><td><tt>GG_ACK_BLOCKED</tt></td><td><tt>0x0001</tt></td><td>Wiadomości nie przesłano (zdarza się przy wiadomościach zawierających adresy internetowe blokowanych przez serwer GG gdy odbiorca nie ma nas na liście)</td></tr>
<tr class="tabf"><td><tt>GG_ACK_DELIVERED</tt></td><td><tt>0x0002</tt></td><td>Wiadomość dostarczono</td></tr>
<tr class="tabf"><td><tt>GG_ACK_QUEUED</tt></td><td><tt>0x0003</tt></td><td>Wiadomość zakolejkowano</td></tr>
<tr class="tabf"><td><tt>GG_ACK_MBOXFULL</tt></td><td><tt>0x0004</tt></td><td>Wiadomości nie dostarczono. Skrzynka odbiorcza na serwerze jest pełna (20 wiadomości maks). Występuje tylko w trybie offline</td></tr>
<tr class="tabf"><td><tt>GG_ACK_NOT_DELIVERED</tt></td><td><tt>0x0006</tt></td><td>Wiadomości nie dostarczono. Odpowiedź ta występuje tylko w przypadku wiadomości klasy <tt>GG_CLASS_CTCP</tt></td></tr>
</table>

<hr />

<a name="ch1.7"></a>
<h3>1.7. Otrzymywanie wiadomości</h3>

<p>
Wiadomości serwer przysyła za pomocą pakietu:
</p>

<div class="c">
<pre>#define GG_RECV_MSG80 0x002e

struct gg_recv_msg80 {
	int sender;		<i>/* numer nadawcy */</i>
	int seq;		<i>/* numer sekwencyjny */</i>
	int time;		<i>/* czas nadania */</i>
	int class;		<i>/* klasa wiadomości */</i>
	int offset_plain;	<i>/* położenie treści czystym tekstem */</i>
	int offset_attributes;	<i>/* położenie atrybutów */</i>
	char html_message[];	<i>/* treść w formacie HTML (zakończona \0) */</i>
	char plain_message[];	<i>/* treść czystym tekstem (zakończona \0) */</i>
	char attributes[];	<i>/* atrybuty wiadomości */</i>
};</pre>

</div>

<p>
Czas nadania jest zapisany w postaci UTC, jako ilości sekund od 1 stycznia
1970r.
</p>

<p>
W przypadku pakietów &bdquo;konferencyjnych&rdquo; na końcu pakietu doklejona
jest struktura identyczna z <tt>gg_msg_recipients</tt> zawierająca pozostałych
rozmówców.
</p>

<hr />

<a name="ch1.8"></a>
<h3>1.8. Ping, pong</h3>

<p>
Od czasu do czasu klient wysyła pakiet do serwera, by oznajmić, że połączenie
jeszcze jest utrzymywane. Jeśli serwer nie dostanie takiego pakietu w
przeciągu 5 minut, zrywa połączenie. To, czy klient dostaje odpowiedź
zmienia się z wersji na wersję, więc najlepiej nie polegać na tym.
</p>

<div class="c">
<pre>#define GG_PING 0x0008

#define GG_PONG 0x0007</pre>
</div>

<hr />

<a name="ch1.9"></a>
<h3>1.9. Rozłączenie</h3>

<p>
Jeśli serwer zechce nas rozłączyć, wyśle wcześniej pusty pakiet:
</p>

<div class="c">
<pre>#define GG_DISCONNECTING 0x000b</pre>
</div>

<p>
Ma to miejsce, gdy próbowano zbyt wiele razy połączyć się z nieprawidłowym
hasłem (wtedy pakiet zostanie wysłany w odpowiedzi na GG_LOGIN70), lub gdy 
równocześnie połączy się drugi klient z tym samym numerem (nowe połączenie 
ma wyższy priorytet).
</p>

<p>
W nowych wersjach protokołu (prawdopodobnie od <tt>0x29</tt>), po wysłaniu
pakietu zmieniającego status na niedostępny, serwer przysyła pakiet:
</p>

<div class="c">
<pre>#define GG_DISCONNECT_ACK 0x000d</pre>
</div>

<p>
Jest to potwierdzenie, że serwer odebrał pakiet zmiany stanu i klient może
zakończyć połączenie mając pewność, że zostanie ustawiony żądany opis.
</p>

<hr />

<a name="ch1.10"></a>
<h3>1.10. Wiadomości systemowe</h3>

<p>
Od wersji 7.7 serwer może wysyłać nam wiadomości systemowe przy pomocy pakietu:
</p>

<div class="c">
<pre>#define GG_XML_EVENT 0x0027</pre>
</div>

<p>
Wiadomość systemowa zawiera kod XML zakodowany w UTF-8 z informacjami dotyczącymi 
np. przedłużenia konta w mobilnym GG, czy nowej wiadomości na poczcie głosowej. 
Przykładowy kod:
</p>

<div class="example">
<pre>&lt;?xml version="1.0" encoding="utf-8"?&gt;
&lt;event xmlns:ev="www.gadu-gadu.pl/Event/1.0" id ="" type="realtime" creation_time="1194732873" ttl="60"&gt;
  &lt;ev:actions&gt;
    &lt;ev:showMessage&gt;
      &lt;ev:text&gt;Wejdź na stronę EKG&lt;/ev:text&gt;

      &lt;ev:executeHtml url="ekg.chmurka.net" /&gt;
   &lt;/ev:showMessage&gt;
  &lt;/ev:actions&gt;
&lt;/event&gt;</pre>
</div>

<hr />

<a name="ch1.11"></a>
<h3>1.11. Wiadomości GG_XML_ACTION</h3>

<div class="c">
<pre>#define GG_XML_ACTION 0x002c</pre>
</div>

<a name="ch1.11.1"></a>
<h4>1.11.1 Wiadomości GGLive</h4>

<div class="check">
<p>Opisać usługi http://life.gadu-gadu.pl/<br/>
Logowanie OAuth: /login?oauth_consumer_key=UIN&amp;oauth_nonce=....&amp;oauth_signature=...&amp;oauth_signature_method=HMAC-SHA1&amp;oauth_timestamp=...&amp;oauth_token=....&amp;oauth_version=1.0<br/>
Wysyłanie: POST /send/message/?USER_IS_AUTHENTICATED=1&amp;uin=UIN&amp;token=TOKEN<br/>
message=Testowa+wiadomo%C5%9B%C4%87&amp;send=Wy%C5%9Blij<br/>
</p>
</div>

<p>
Przykładowa otrzymana wiadomość:
</p>
<div class="example">
<pre>
&lt;events&gt;
  &lt;event id="13106118792229117994"&gt;
  &lt;type&gt;1&lt;/type&gt;
  &lt;sender&gt;7496195&lt;/sender&gt;
  &lt;time&gt;1243461221&lt;/time&gt;
  &lt;bodyXML&gt;
    &lt;serviceID&gt;lifestreaming&lt;/serviceID&gt;
    &lt;msg&gt;&lt;![CDATA[Testowa wiadomość]]&gt;&lt;/msg&gt;
    &lt;link isLogin="0"&gt;&lt;/link&gt;
    &lt;creationTime&gt;1243461221&lt;/creationTime&gt;
  &lt;/bodyXML&gt;
 &lt;/event&gt;
&lt;/events&gt;
</pre>
</div>

<a name="ch1.11.2"></a>
<h4>1.11.2 Zmiana avatara przez znajomego</h4>

<p>Przykładowa informacja:</p>
<div class="example">
<pre>
&lt;events&gt;
  &lt;event id="13095886332244853765"&gt;
    &lt;type&gt;28&lt;/type&gt;
    &lt;sender&gt;3732&lt;/sender&gt;
    &lt;time&gt;1245843651&lt;/time&gt;
    &lt;body&gt;&lt;/body&gt;
    &lt;bodyXML&gt;
      &lt;smallAvatar&gt;http://media6.mojageneracja.pl/oiytwyurtp/avatar/ueuivsp.jpg&lt;/smallAvatar&gt;
    &lt;/bodyXML&gt;
  &lt;/event&gt;
&lt;/events&gt;
</pre>
</div>

<a name="ch1.11.3"></a>
<h4>1.11.3 Nowy wpis na blogu znajomego</h4>

<p>Przykładowa informacja:</p>
<div class="example">
<pre>
&lt;events&gt;
  &lt;event id="13095868082578904423"&gt;
    &lt;type&gt;7&lt;/type&gt;
    &lt;sender&gt;3732&lt;/sender&gt;
    &lt;time&gt;1245847900&lt;/time&gt;
    &lt;bodyXML&gt;
      &lt;serviceID&gt;MG&lt;/serviceID&gt;
      &lt;msg&gt;&lt;![CDATA[Doda\u0139, wpis do bloga]]&gt;&lt;/msg&gt;
      &lt;link isLogin="1"&gt;http://www.mojageneracja.pl/7233258/blog/4877775414a42215b91fd7/0&lt;/link&gt;
      &lt;creationTime&gt;1245847900&lt;/creationTime&gt;
    &lt;/bodyXML&gt;
 &lt;/event&gt;
&lt;/events&gt;
</pre>
</div>

<a name="ch1.11.4"></a>
<h4>1.11.4 Opisy graficzne</h4>
<div class="check">
<p>Osobny rozdział XXX?</p>
</div>

<p>
Serwer Gadu-Gadu po kupnie opisu graficznego na stronie <a href="http://gadudodatki.pl/opisygraficzne">GaduDodatki</a>
przesyła nam pakiet GG_XML_EVENT
</p>

<p>Przykładowy opis graficzny: Krol Popu</p>
<div class="example">
<pre>
&lt;?xml version="1.0" encoding="utf-8" ?&gt;
&lt;activeUserbarEventList&gt;
  &lt;activeUserbarEvent&gt;
     &lt;userbarId&gt;Krol Popu&lt;/userbarId&gt;
     &lt;beginTime&gt;2009-07-06T12:30:43+02:00&lt;/beginTime&gt;
     &lt;expireTime&gt;2009-08-05T12:30:43+02:00&lt;/expireTime&gt;
     &lt;userbarOwner&gt;7496195&lt;/userbarOwner&gt;
     &lt;userbarBuyer&gt;7496195&lt;/userbarBuyer&gt;
   &lt;/activeUserbarEvent&gt;
&lt;/activeUserbarEventList&gt;
</pre>
</div>

<p>
Użytkownik powinien zostać zapytany czy chce ustawić ten opis i jeśli tak, to wysyłany jest pakiet GG_NEW_STATUS80
</p>
<p>Przykładowe ustawienie opisu graficznego: Krol Popu</p>
<div class="example">
<pre>
struct gg_new_status80 krol_popu = { 
	.status           = GG_STATUS80_DESCR_MASK | GG_STATUS80_GRAPH_MASK | docelowy_opisowy_status; <i>/* 0x4100 | opis */</i>
	.flags            = 0x03;
	.description_size = 9;
	.description      = "Krol Popu"
};</pre>
</div>

<p>
Gdy użytkownik ma ustawiony opis graficzny (.status &amp; GG_STATUS80_GRAPH_MASK)
możemy pobrać ZIP-paczkę z http://www.gadudodatki.pl/userbar/get/id/
</p>
<p>Dla przykładowego Króla Popu jest to adres: <span class="example">http://www.gadudodatki.pl/userbar/get/id/Krol%20Popu</span></p>

<hr />

<a name="ch1.12"></a>
<h3>1.12. Katalog publiczny</h3>

<div class="check">
<p>Nowe Gadu-Gadu korzysta z OAutha do odczytu oraz zmian danych w katalogu, API opisane jest na:
<a href="http://dev.gadu-gadu.pl/api/pages/gaduapi.html">http://dev.gadu-gadu.pl/api/pages/gaduapi.html</a>
</p>
<p>Nowe Gadu-Gadu korzysta z wyszukiwarki dostępnej na:
<a href="http://ipubdir.gadu-gadu.pl">http://ipubdir.gadu-gadu.pl</a>
</p>
</div>

<p>
Od wersji 5.0.2 zmieniono sposób dostępu do katalogu publicznego &mdash; stał
się częścią sesji, zamiast osobnej sesji HTTP. Aby obsługiwać wyszukiwanie
osób, odczytywanie własnych informacji lub ich modyfikację należy użyć
następującego typu pakietu:
</p>

<div class="c">
<pre>#define GG_PUBDIR50_REQUEST 0x0014
	
struct gg_pubdir50 {
	char type;
	int seq;
	char request[];
};</pre>
</div>

<p>
Pole <tt>type</tt> oznacza rodzaj zapytania:
</p>

<div class="c">
<pre>#define GG_PUBDIR50_WRITE 0x01
#define GG_PUBDIR50_READ 0x02
#define GG_PUBDIR50_SEARCH 0x03</pre>
</div>

<p>
Pole <tt>seq</tt> jest numerem sekwencyjnym zapytania, różnym od zera,
zwracanym również
w wyniku. Oryginalny klient tworzy go na podstawie aktualnego czasu.
<tt>request</tt> zawiera parametry zapytania. Ilość jest dowolna. Każdy
parametr jest postaci <tt>"<b>nazwa</b>\0<b>wartość</b>\0"</tt>, tzn.
nazwa od wartości są oddzielone znakiem o kodzie 0, podobnie jak kolejne
parametry od siebie. Możliwe parametry zapytania to:
</p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td><b>Etykieta</b></td><td><b>Wartość</b></td><td><b>Znaczenie</b></td></tr>
<tr class="tabf"><td><tt>GG_PUBDIR50_UIN</tt></td><td><tt>FmNumber</tt></td><td>Numer szukanej osoby</td></tr>
<tr class="tabf"><td><tt>GG_PUBDIR50_FIRSTNAME</tt></td><td><tt>firstname</tt></td><td>Imię</td></tr>
<tr class="tabf"><td><tt>GG_PUBDIR50_LASTNAME</tt></td><td><tt>lastname</tt></td><td>Nazwisko</td></tr>
<tr class="tabf"><td><tt>GG_PUBDIR50_NICKNAME</tt></td><td><tt>nickname</tt></td><td>Pseudonim</td></tr>
<tr class="tabf"><td><tt>GG_PUBDIR50_BIRTHYEAR</tt></td><td><tt>birthyear</tt></td><td>Rok urodzenia. Jeśli chcemy szukać osób z danego przedziału, podajemy rok początkowy i końcowy, oddzielone spacją. Na przykład &bdquo;<tt>1980 1985</tt>&rdquo;.</td></tr>
<tr class="tabf"><td><tt>GG_PUBDIR50_CITY</tt></td><td><tt>city</tt></td><td>Miejscowość</td></tr>
<tr class="tabf"><td><tt>GG_PUBDIR50_GENDER</tt></td><td><tt>gender</tt></td><td>Płeć. Jeśli szukamy kobiet, ma wartość &bdquo;<tt>1</tt>&rdquo; (stała <tt>GG_PUBDIR50_GENDER_FEMALE</tt>). Jeśli mężczyzn, ma wartość &bdquo;<tt>2</tt>&rdquo; (stała <tt>GG_PUBDIR50_GENDER_MALE</tt>). W przypadku pobierania lub ustawiania informacji o sobie stałe mają odwrócone znaczenia (stałe <tt>GG_PUBDIR50_GENDER_SET_FEMALE</tt> i <tt>GG_PUBDIR50_GENDER_SET_MALE</tt>)</td></tr>
<tr class="tabf"><td><tt>GG_PUBDIR50_ACTIVE</tt></td><td><tt>ActiveOnly</tt></td><td>Jeśli szukamy tylko dostępnych osób, ma mieć wartość &bdquo;<tt>1</tt>&rdquo; (stała <tt>GG_PUBDIR50_ACTIVE_TRUE</tt>).</td></tr>
<tr class="tabf"><td><tt>GG_PUBDIR50_FAMILYNAME</tt></td><td><tt>familyname</tt></td><td>Nazwisko panieńskie. Ma znaczenie tylko przy ustawianiu własnych danych.</td></tr>
<tr class="tabf"><td><tt>GG_PUBDIR50_FAMILYCITY</tt></td><td><tt>familycity</tt></td><td>Miejscowość pochodzenia. Ma znaczenie tylko przy ustawianiu własnych danych.</td></tr>
<tr class="tabf"><td><tt>GG_PUBDIR50_START</tt></td><td><tt>fmstart</tt></td><td>Numer, od którego rozpocząć wyszukiwanie. Ma znaczenie, gdy kontynuujemy wyszukiwanie.</td></tr>
</table>

<p>
Treść przykładowego zapytania (pomijając pola <tt>type</tt> i <tt>seq</tt>) znajduje się poniżej. Szukano dostępnych kobiet o imieniu Ewa z Warszawy. Znaki o kodzie 0 zastąpiono kropkami.
</p>

<div class="example">
<pre>firstname.Ewa.city.Warszawa.gender.1.ActiveOnly.1.</pre>
</div>

<p>
Wynik zapytania zostanie zwrócony za pomocą pakietu:
</p>

<div class="c">
<pre>#define GG_PUBDIR50_REPLY 0x000e
	
struct gg_pubdir50_reply {
	char type;
	int seq;
	char reply[];
};</pre>
</div>

<p>
Pole <tt>type</tt> poza wartościami takimi jak przy pakiecie typu
<tt>GG_PUBDIR50_REQUEST</tt> może przyjąć jeszcze wartość oznaczającą
odpowiedź wyszukiwania:
</p>

<div class="c">
<pre>#define GG_PUBDIR50_SEARCH_REPLY 0x05</pre>
</div>

<p>
Wyniki są zbudowane identycznie jak w przypadku zapytań, z tą różnicą, że
kolejne osoby oddzielane pustym polem: <tt>"<b>parametr</b>\0<b>wartość</b>\0\0<b>parametr</b>\0<b>wartość</b>\0"</tt>.
</p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td><b>Etykieta</b></td><td><b>Wartość</b></td><td><b>Znaczenie</b></td></tr>
<tr class="tabf"><td><tt>GG_PUBDIR50_STATUS</tt></td><td><tt>FmStatus</tt></td><td>Stan szukanej osoby</td></tr>
<tr class="tabf"><td>&nbsp;</td><td><tt>nextstart</tt></td><td>Pole występujące w ostatnim wyniku, określające, od jakiego numeru należy rozpocząć wyszukiwanie, by otrzymać kolejną porcję danych. Podaje się go w zapytaniu jako parametr &bdquo;<tt>start</tt>&rdquo;.</td></tr>
</table>

<p>
Przykładowy wynik zawierający dwie znalezione osoby:
</p>

<div class="example">
<pre>FmNumber.12345.FmStatus.1.firstname.Adam.nickname.Janek.birthyear.1979.city.Wzdów
..FmNumber.3141592.FmStatus.5.firstname.Ewa.nickname.Ewcia.birthyear.1982.city.Gd
dańsk..nextstart.0.</pre>
</div>

<p>
Wyszukiwanie <b>nie zwraca</b> nazwisk i płci znalezionych osób.
</p>

<hr />

<a name="ch1.13"></a>
<h3>1.13. Lista kontaktów</h3>

<div class="check">
<pre>Sprawdzić czy wszystkie #define dalej są potrzebne</pre>
</div>

<p>
Od wersji 6.0 lista kontaktów na serwerze stała częścią sesji, zamiast
osobnej sesji HTTP. Aby wysłać lub pobrać listę kontaktów z serwera należy
użyć pakietu:
</p>

<div class="c">
<pre>#define GG_USERLIST_REQUEST80 0x002f
	
struct gg_userlist_request {
	char type;		<i>/* rodzaj zapytania */</i>
	char request[];		<i>/* treść (nie musi wystąpić) */</i>
};</pre>
</div>

<p>
Pole <tt>type</tt> oznacza rodzaj zapytania:
</p>

<div class="c">
<pre>#define GG_USERLIST_PUT 0x00            <i>/* początek eksportu listy */</i>
#define GG_USERLIST_PUT_MORE 0x01       <i>/* dalsza część eksportu listy */</i>
#define GG_USERLIST_GET 0x02            <i>/* import listy */</i></pre>
</div>

<p>
W przypadku eksportu listy kontaktów, pole <tt>request</tt> zawiera dokument
XML opisany na stronie
<a href="http://dev.gadu-gadu.pl/api/pages/formaty_plikow.html">http://dev.gadu-gadu.pl/api/pages/formaty_plikow.html</a> skompresowany algorytmem 
<a href="http://pl.wikipedia.org/wiki/Deflate">Deflate</a>. Wolnodostępna
implementacja algorytmu, używana również przez oryginalnego klienta, znajduje
się w biblotece <a href="http://www.zlib.net/">zlib</a>. 
</p>

<p>
Podczas przesyłania lista kontaktów jest dzielona na pakiety po 2048 bajtów.
Pierwszy jest wysyłany pakietem typu <tt>GG_USERLIST_PUT</tt>, żeby uaktualnić
plik na serwerze, pozostałe typu <tt>GG_USERLIST_PUT_MORE</tt>, żeby dopisać
do pliku.
</p>

<p>
Na zapytania dotyczące listy kontaktów serwer odpowiada pakietem:
</p>

<div class="c">
<pre>#define GG_USERLIST_REPLY80 0x0030
	
struct gg_userlist_reply {
	char type;		<i>/* rodzaj zapytania */</i>
	char reply[];		<i>/* treść (nie musi wystąpić) */</i>
};</pre>
</div>

<p>
Pole <tt>type</tt> oznacza rodzaj odpowiedzi:
</p>

<div class="c">
<pre>#define GG_USERLIST_PUT_REPLY 0x00         <i>/* początek eksportu listy */</i>
#define GG_USERLIST_PUT_MORE_REPLY 0x02    <i>/* kontynuacja */</i>
#define GG_USERLIST_GET_MORE_REPLY 0x04    <i>/* początek importu listy */</i>
#define GG_USERLIST_GET_REPLY 0x06         <i>/* ostatnia część importu */</i></pre>
</div>

<p>
W przypadku importu w polu <tt>request</tt> znajdzie się lista kontaktów
w takiej samej postaci, w jakiej ją umieszczono. Serwer nie ingeruje w jej
treść. Podobnie jak przy wysyłaniu, przychodzi podzielona na mniejsze pakiety.
Pobieranie krótkiej listy kontaktów zwykle powoduje wysłanie pojedynczego
pakietu <tt>GG_USERLIST_GET_REPLY</tt>, a gdy lista jest długa, serwer może
przysłać dowolną ilość pakietów <tt>GG_USERLIST_GET_MORE_REPLY</tt> przed
pakietem <tt>GG_USERLIST_GET_REPLY</tt>.
</p>

<p>
Aby usunąć listę kontaktów z serwera oryginalny klient wysyła spację jako
listę kontaktów czego wynikiem jest pole <tt>request</tt> o zawartości:
</p>

<div class="example">
<pre>78 da 53 00 00 00 21 00 21</pre>
</div>

<hr />

<a name="ch1.14"></a>
<h3>1.14. Indeks pakietów</h3>

<p>
Pakiety wysyłane:
</p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td><b>Wartość</b></td><td><b>Etykieta</b></td><td><b>Znaczenie</b></td></tr>
<tr class="tabf2"><td><tt>0x0002</tt></td><td><tt>GG_NEW_STATUS</tt></td><td>Zmiana stanu przed GG 8.0</td></tr>
<tr class="tabf2"><td><tt>0x0007</tt></td><td><tt>GG_PONG</tt></td><td>Pong</td></tr>
<tr class="tabf"><td><tt>0x0008</tt></td><td><tt>GG_PING</tt></td><td>Ping</td></tr>
<tr class="tabf2"><td><tt>0x000b</tt></td><td><tt>GG_SEND_MSG</tt></td><td>Wysłanie wiadomości przed GG 8.0</td></tr>
<tr class="tabf2"><td><tt>0x000c</tt></td><td><tt>GG_LOGIN</tt></td><td>Logowanie przed GG 6.0</td></tr>
<tr class="tabf"><td><tt>0x000d</tt></td><td><tt>GG_ADD_NOTIFY</tt></td><td>Dodanie do listy kontaktów</td></tr>
<tr class="tabf"><td><tt>0x000e</tt></td><td><tt>GG_REMOVE_NOTIFY</tt></td><td>Usunięcie z listy kontaktów</td></tr>
<tr class="tabf"><td><tt>0x000f</tt></td><td><tt>GG_NOTIFY_FIRST</tt></td><td>Początkowy fragment listy kontaktów większej niż 400 wpisów</td></tr>
<tr class="tabf"><td><tt>0x0010</tt></td><td><tt>GG_NOTIFY_LAST</tt></td><td>Ostatni fragment listy kontaktów</td></tr>
<tr class="tabf"><td><tt>0x0012</tt></td><td><tt>GG_LIST_EMPTY</tt></td><td>Lista kontaktów jest pusta</td></tr>
<tr class="tabf2"><td><tt>0x0013</tt></td><td><tt>GG_LOGIN_EXT</tt></td><td>Logowanie przed GG 6.0</td></tr>
<tr class="tabf"><td><tt>0x0014</tt></td><td><tt>GG_PUBDIR50_REQUEST</tt></td><td>Zapytanie katalogu publicznego</td></tr>
<tr class="tabf2"><td><tt>0x0015</tt></td><td><tt>GG_LOGIN60</tt></td><td>Logowanie przed GG 7.7</td></tr>
<tr class="tabf2"><td><tt>0x0016</tt></td><td><tt>GG_USERLIST_REQUEST</tt></td><td>Zapytanie listy kontaktów na serwerze przed Nowym Gadu-Gadu</td></tr>
<tr class="tabf2"><td><tt>0x0019</tt></td><td><tt>GG_LOGIN70</tt></td><td>Logowanie przed GG 8.0</td></tr>
<tr class="tabf"><td><tt>0x001f</tt></td><td><tt>GG_DCC7_INFO</tt></td><td></td></tr>
<tr class="tabf"><td><tt>0x0020</tt></td><td><tt>GG_DCC7_NEW</tt></td><td>Informacje o chęci nawiązania połączenia DCC</td></tr>
<tr class="tabf"><td><tt>0x0021</tt></td><td><tt>GG_DCC7_ACCEPT</tt></td><td>Zaakceptowanie połączenia DCC</td></tr>
<tr class="tabf"><td><tt>0x0022</tt></td><td><tt>GG_DCC7_REJECT</tt></td><td>Odrzucenie połączenia DCC</td></tr>
<tr class="tabf"><td><tt>0x0023</tt></td><td><tt>GG_DCC7_ID_REQUEST</tt></td><td></td></tr>
<tr class="tabf2"><td><tt>0x0024</tt></td><td><tt>GG_DCC7_DUNNO1</tt></td><td></td></tr>
<tr class="tabf"><td><tt>0x0025</tt></td><td><tt>GG_DCC7_ABORT</tt></td><td></td></tr>
<tr class="tabf2"><td><tt>0x0028</tt></td><td><tt>GG_NEW_STATUS80BETA</tt></td><td>Zmiana stanu przed Nowym Gadu-Gadu</td></tr>
<tr class="tabf2"><td><tt>0x0029</tt></td><td><tt>GG_LOGIN80BETA</tt></td><td>Logowanie przed Nowym Gadu-Gadu</td></tr>
<tr class="tabf"><td><tt>0x002d</tt></td><td><tt>GG_SEND_MSG80</tt></td><td>Wysłanie wiadomości</td></tr>
<tr class="tabf"><td><tt>0x002f</tt></td><td><tt>GG_USERLIST_REQUEST80</tt></td><td>Zapytanie listy kontaktów na serwerze</td></tr>
<tr class="tabf"><td><tt>0x0031</tt></td><td><tt>GG_LOGIN80</tt></td><td>Logowanie</td></tr>
<tr class="tabf"><td><tt>0x0038</tt></td><td><tt>GG_NEW_STATUS80</tt></td><td>Zmiana stanu</td></tr>
</table>

<p>
Pakiety odbierane:
</p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td><b>Wartość</b></td><td><b>Etykieta</b></td><td><b>Znaczenie</b></td></tr>
<tr class="tabf"><td><tt>0x0001</tt></td><td><tt>GG_WELCOME</tt></td><td>Liczba do wyznaczenie hashu hasła</td></tr>
<tr class="tabf2"><td><tt>0x0002</tt></td><td><tt>GG_STATUS</tt></td><td>Zmiana stanu przed GG 6.0</td></tr>
<tr class="tabf2"><td><tt>0x0003</tt></td><td><tt>GG_LOGIN_OK</tt></td><td>Logowanie powiodło się przed Nowym Gadu-Gadu</td></tr>
<tr class="tabf"><td><tt>0x0005</tt></td><td><tt>GG_SEND_MSG_ACK</tt></td><td>Potwierdzenie wiadomości</td></tr>
<tr class="tabf2"><td><tt>0x0007</tt></td><td><tt>GG_PONG</tt></td><td>Pong</td></tr>
<tr class="tabf2"><td><tt>0x0008</tt></td><td><tt>GG_PING</tt></td><td>Ping</td></tr>
<tr class="tabf"><td><tt>0x0009</tt></td><td><tt>GG_LOGIN_FAILED</tt></td><td>Logowanie nie powiodło się</td></tr>
<tr class="tabf2"><td><tt>0x000a</tt></td><td><tt>GG_RECV_MSG</tt></td><td>Przychodząca wiadomość przed GG 8.0</td></tr>
<tr class="tabf"><td><tt>0x000b</tt></td><td><tt>GG_DISCONNECTING</tt></td><td>Zerwanie połączenia</td></tr>
<tr class="tabf2"><td><tt>0x000c</tt></td><td><tt>GG_NOTIFY_REPLY</tt></td><td>Stan listy kontaktów przed GG 6.0</td></tr>
<tr class="tabf"><td><tt>0x000d</tt></td><td><tt>GG_DISCONNECT_ACK</tt></td><td>Zerwanie połączenia po zmianie stanu na niedostępny</td></tr>
<tr class="tabf"><td><tt>0x000e</tt></td><td><tt>GG_PUBDIR50_REPLY</tt></td><td>Odpowiedź katalogu publicznego</td></tr>
<tr class="tabf2"><td><tt>0x000f</tt></td><td><tt>GG_STATUS60</tt></td><td>Zmiana stanu przed GG 7.7</td></tr>
<tr class="tabf2"><td><tt>0x0010</tt></td><td><tt>GG_USERLIST_REPLY</tt></td><td>Odpowiedź listy kontaktów na serwerze przed nowym Gadu-Gadu</td></tr>
<tr class="tabf2"><td><tt>0x0011</tt></td><td><tt>GG_NOTIFY_REPLY60</tt></td><td>Stan listy kontaktów przed GG 7.7</td></tr>
<tr class="tabf"><td><tt>0x0014</tt></td><td><tt>GG_NEED_EMAIL</tt></td><td>Logowanie powiodło się, ale powinniśmy uzupełnić adres e-mail w katalogu publicznym</td></tr>
<tr class="tabf2"><td><tt>0x0016</tt></td><td><tt>GG_LOGIN_HASH_TYPE_INVALID</tt></td><td>Dany rodzaj hashowania hasła jest nieobsługiwany przez serwer</td></tr>
<tr class="tabf2"><td><tt>0x0017</tt></td><td><tt>GG_STATUS77</tt></td><td>Zmiana stanu przed GG 8.0</td></tr>
<tr class="tabf2"><td><tt>0x0018</tt></td><td><tt>GG_NOTIFY_REPLY77</tt></td><td>Stan listy kontaktów przed GG 8.0</td></tr>
<tr class="tabf"><td><tt>0x001f</tt></td><td><tt>GG_DCC7_INFO</tt></td><td></td></tr>
<tr class="tabf"><td><tt>0x0020</tt></td><td><tt>GG_DCC7_NEW</tt></td><td>Informacje o chęci nawiązania połączenia DCC</td></tr>
<tr class="tabf"><td><tt>0x0021</tt></td><td><tt>GG_DCC7_ACCEPT</tt></td><td>Zaakceptowanie połączenia DCC</td></tr>
<tr class="tabf"><td><tt>0x0022</tt></td><td><tt>GG_DCC7_REJECT</tt></td><td>Odrzucenie połączenia DCC</td></tr>
<tr class="tabf"><td><tt>0x0023</tt></td><td><tt>GG_DCC7_ID_REPLY</tt></td><td></td></tr>
<tr class="tabf"><td><tt>0x0025</tt></td><td><tt>GG_DCC7_ABORTED</tt></td><td></td></tr>
<tr class="tabf"><td><tt>0x0027</tt></td><td><tt>GG_XML_EVENT</tt></td><td>Odebrano wiadomość systemową</td></tr>
<tr class="tabf2"><td><tt>0x002a</tt></td><td><tt>GG_STATUS80BETA</tt></td><td>Zmiana stanu przed Nowym Gadu-Gadu</td></tr>
<tr class="tabf"><td><tt>0x002b</tt></td><td><tt>GG_NOTIFY_REPLY80BETA</tt></td><td>Stan listy kontaktów przed Nowym Gadu-Gadu</td></tr>
<tr class="tabf"><td><tt>0x002c</tt></td><td><tt>GG_XML_ACTION</tt></td><td></td></tr>
<tr class="tabf"><td><tt>0x002e</tt></td><td><tt>GG_RECV_MSG80</tt></td><td>Przychodząca wiadomość</td></tr>
<tr class="tabf"><td><tt>0x0030</tt></td><td><tt>GG_USERLIST_REPLY80</tt></td><td>Odpowiedź listy kontaktów na serwerze</td></tr>
<tr class="tabf"><td><tt>0x0035</tt></td><td><tt>GG_LOGIN_OK80</tt></td><td>Logowanie powiodło się</td></tr>
<tr class="tabf"><td><tt>0x0036</tt></td><td><tt>GG_STATUS80</tt></td><td>Zmiana stanu</td></tr>
<tr class="tabf"><td><tt>0x0037</tt></td><td><tt>GG_NOTIFY_REPLY80</tt></td><td>Stan listy kontaktów</td></tr>
</table>

<hr />

<a name="ch2"></a>
<h2>2. Usługi HTTP</h2>

<a name="ch2.1"></a>
<h3>2.1. Format danych</h3>

<p>
Komunikacja z <tt>appmsg.gadu-gadu.pl</tt> metodą <tt>GET</tt> HTTP/1.0
została opisana w poprzednim rozdziale, pozostałe pakiety używają 
<tt>POST</tt> dla HTTP/1.0, a w odpowiedzi 1.1. Mają one postać:
</p>

<div class="http">
<pre>POST <b>ŚCIEŻKA</b> HTTP/1.0
Host: <b>HOST</b>
Content-Type: application/x-www-form-urlencoded
User-Agent: <b>AGENT</b>
Content-Length: <b>DŁUGOŚĆ</b>
Pragma: no-cache

<b>DANE</b></pre>
</div>

<p>
Gdzie <tt><b>AGENT</b></tt> to nazwa przeglądarki (na przykład <tt>Mozilla/4.0
(compatible; MSIE 5.0; Windows 98)</tt> lub inne, wymienione w rozdziale
<a href="#ch1.2">1.2</a>), <tt><b>DŁUGOŚĆ</b></tt> to długość bloku
<tt><b>DANE</b></tt> w znakach.
</p>

<p>
Jeśli będzie mowa o wysyłaniu danych do serwera, to chodzi o cały powyższy
pakiet, opisane zostaną tylko: <tt><b>HOST</b></tt>, <tt><b>ŚCIEŻKA</b></tt>
i <tt><b>DANE</b></tt>. Pakiet jest wysyłany na port 80. Gdy mowa o wysyłaniu
pól zapytania, mowa o <tt><b>DANE</b></tt> o wartości:
</p>

<div class="http">
<pre>pole1=wartość1&amp;pole2=wartość2&amp;...</pre>
</div>

<p>
Pamiętaj o zmianie kodowania na CP1250 i zakodowaniu danych do postaci URL
(na przykład funkcją typu <tt>urlencode</tt>).
</p>

<p>
Odpowiedzi serwera na powyższe zapytania mają mniej więcej postać:
</p>

<div class="http">
<pre>HTTP/1.1 200 OK
Server: Microsoft-IIS/5.0
Date: Mon, 01 Jul 2002 22:30:31 GMT
Connection: Keep-Alive
Content-Length: <b>DŁUGOŚĆ</b>
Content-Type: text/html
Set-Cookie: <b>COOKIE</b>
Cache-control: private

<b>ODPOWIEDŹ</b></pre>
</div>

<p>
Nagłówki nie są dla nas ważne. Można zauważyć tylko to, że czasami serwer
ustawia <tt><b>COOKIE</b></tt> np. &bdquo;<tt>ASPSESSIONIDQQGGGLJC=CAEKMBGDJCFBEOKCELEFCNKH; path=/</tt>&rdquo;. Pisząc dalej, że serwer &bdquo;odpowie wartością&rdquo; mowa
tylko o polu <b>ODPOWIEDŹ</b>. Kodowanie znaków w odpowiedzi to CP1250.
</p>

<hr />

<a name="ch2.2"></a>

<h3>2.2. Tokeny</h3> 

<p>
Prawdopodobnie ze względu na nadużycia i wykorzystywanie automatów
rejestrujących do polowań na &bdquo;złote numery GG&rdquo;, wprowadzono konieczność
autoryzacji za pomocą tokenu. Każda operacja zaczyna się od pobrania tokenu
z serwera, wyświetlenia użytkownikowi, odczytaniu jego wartości i wysłania
zapytania z identyfikatorem i wartością tokenu. Pobranie tokenu wygląda 
następująco:
</p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td width="20%"><b>Pole nagłówka</b></td><td width="80%"><b>Wartość</b></td></tr>
<tr class="tabf"><td><tt>HOST</tt></td><td><tt>register.gadu-gadu.pl</tt></td></tr>
<tr class="tabf"><td><tt>ŚCIEŻKA</tt></td><td><tt>/appsvc/regtoken.asp</tt></td></tr>
</table>

<p>
Nie są wysyłane żadne parametry. Przykład:
</p>

<div class="http">
<pre>POST /appsvc/regtoken.asp HTTP/1.0
Host: register.gadu-gadu.pl
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows 98)
Content-Length: 0
Pragma: no-cache
</pre>
</div>

<p>
Serwer w odpowiedzi odeśle:
</p>

<div class="http">
<pre><b>SZEROKOŚĆ WYSOKOŚĆ DŁUGOŚĆ
IDENTYFIKATOR
ŚCIEŻKA</b></pre></div>

<p>
Gdzie <tt><b>SZEROKOŚĆ</b></tt> i <tt><b>WYSOKOŚĆ</b></tt> opisują wymiary
obrazka z wartością tokenu, <tt><b>DŁUGOŚĆ</b></tt> mówi ile znaków zawiera
token, <tt><b>IDENTYFIKATOR</b></tt> jest identyfikatorem tokenu (tylko do
niego pasuje wartość tokenu), a <tt><b>ŚCIEŻKA</b></tt> to ścieżka do skryptu
zwracającego obrazek z wartością tokenu. Przykładowa odpowiedź:
</p>

<div class="http">
<pre>60 24 6
06C05A44
http://register.gadu-gadu.pl/appsvc/tokenpic.asp</pre></div>

<p>
Możemy teraz pobrać metodą GET z podanej ścieżki obrazek z tokenem, doklejając
do ścieżki parametr <tt><b>tokenid</b></tt> o wartości będącej identyfikatorem
uzyskanym przed chwilą. Adres obrazka z wartością tokenu dla powyższego
przykładu to:
</p>

<div class="example">
<pre>http://register.gadu-gadu.pl/appsvc/tokenpic.asp?tokenid=06C05A44</pre>
</div>

<p>
Pobrany obrazek (w tej chwili jest w formacie JPEG, ale prawdopodobnie może
się to zmienić na dowolny format obsługiwany domyślnie przez system Windows)
najlepiej wyświetlić użytkownikowi, prosząc o podanie wartości na nim
przedstawionej. Będzie ona niezbędna do przeprowadzenia kolejnych operacji.
</p>

<hr />

<a name="ch2.3"></a>

<h3>2.3. Rejestracja konta</h3>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td width="20%"><b>Pole nagłówka</b></td><td width="80%"><b>Wartość</b></td></tr>
<tr class="tabf"><td><tt>HOST</tt></td><td><tt>register.gadu-gadu.pl</tt></td></tr>
<tr class="tabf"><td><tt>ŚCIEŻKA</tt></td><td><tt>/appsvc/fmregister3.asp</tt></td></tr>
</table>

<p></p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td width="20%"><b>Wysyłamy pole</b></td><td width="80%"><b>Znaczenie</b></td></tr>
<tr class="tabf"><td><tt>pwd</tt></td><td>hasło dla nowego numeru</td></tr>
<tr class="tabf"><td><tt>email</tt></td><td>e-mail na który będzie przesyłane przypomnienie hasła</td></tr>
<tr class="tabf"><td><tt>tokenid</tt></td><td>identyfikator tokenu</td></tr>
<tr class="tabf"><td><tt>tokenval</tt></td><td>wartość tokenu</td></tr>
<tr class="tabf"><td><tt>code</tt></td><td>hash liczony z pól <tt>email</tt> i <tt>pwd</tt>. Algorytmu szukaj w źródłach libgadu w <tt>lib/common.c</tt></td></tr>
</table>

<p>
Przykład:
</p>

<div class="http">
<pre>POST /appsvc/fmregister3.asp HTTP/1.0
Host: register.gadu-gadu.pl
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows 98)
Content-Length: 76
Pragma: no-cache
		
pwd=sekret&amp;email=abc&#64;xyz.pl<!-- &amp;qa=5~Maria -->&amp;tokenid=06C05A44&amp;tokenval=e94d56&amp;code=1104465363</pre>
</div>

<p>
Jeśli wszystko przebiegło poprawnie, serwer odpowie:
</p>

<div class="http">
<pre>Tokens okregisterreply_packet.reg.dwUserId=<b>UIN</b></pre>
</div>

<p>
Gdzie <tt><b>UIN</b></tt> to nowy numer, który właśnie otrzymaliśmy.
</p>

<p>
Jeśli został podany nieprawidłowy token, serwer odpowie:
</p>

<div class="http">
<pre>bad_tokenval</pre>
</div>

<hr />

<a name="ch2.4"></a>
<h3>2.4. Usunięcie konta</h3>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td width="20%"><b>Pole nagłówka</b></td><td width="80%"><b>Wartość</b></td></tr>
<tr class="tabf"><td><tt>HOST</tt></td><td><tt>register.gadu-gadu.pl</tt></td></tr>
<tr class="tabf"><td><tt>ŚCIEŻKA</tt></td><td><tt>/appsvc/fmregister3.asp</tt></td></tr>
</table>

<p></p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td width="20%"><b>Wysyłamy pole</b></td><td width="80%"><b>Znaczenie</b></td></tr>
<tr class="tabf"><td><tt>fmnumber</tt></td><td>usuwany numer</td></tr>
<tr class="tabf"><td><tt>fmpwd</tt></td><td>hasło</td></tr>
<tr class="tabf"><td><tt>delete</tt></td><td>wartość &bdquo;<tt>1</tt>&rdquo;</td></tr>
<tr class="tabf"><td><tt>pwd</tt></td><td>losowa liczba</td></tr>
<tr class="tabf"><td><tt>email</tt></td><td>wartość &bdquo;<tt>deletedaccount@gadu-gadu.pl</tt>&rdquo;</td></tr>
<tr class="tabf"><td><tt>tokenid</tt></td><td>identyfikator tokenu</td></tr>
<tr class="tabf"><td><tt>tokenval</tt></td><td>wartość tokenu</td></tr>
<tr class="tabf"><td><tt>code</tt></td><td>hash liczony z pól <tt>pwd</tt> i <tt>email</tt></td></tr>
</table>

<p>
Przykład:
</p>

<div class="http">
<pre>POST /appsvc/fmregister2.asp HTTP/1.0
Host: register.gadu-gadu.pl
Content-Type: application/x-www-form-urlencoded
User-Agent: Mozilla/4.0 (compatible; MSIE 5.0; Windows 98)
Content-Length: 137
Pragma: no-cache
		
fmnumber=4969256&amp;fmpwd=haslo&amp;delete=1&amp;email=deletedaccount@gadu-gadu.pl&amp;pwd=%2D38
8046464&amp;tokenid=06C05A44&amp;tokenval=e94d56&amp;code=1483497094</pre>
</div>

<p>
Jeśli wszystko przebiegło poprawnie, serwer odpowie:
</p>

<div class="http">
<pre>reg_success:<b>UIN</b></pre>
</div>

<p>
Gdzie <tt><b>UIN</b></tt> to numer, który skasowaliśmy.
</p>

<hr />

<a name="ch2.5"></a>
<h3>2.5. Zmiana hasła</h3>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td width="20%"><b>Pole nagłówka</b></td><td width="80%"><b>Wartość</b></td></tr>
<tr class="tabf"><td><tt>HOST</tt></td><td><tt>register.gadu-gadu.pl</tt></td></tr>
<tr class="tabf"><td><tt>ŚCIEŻKA</tt></td><td><tt>/appsvc/fmregister3.asp</tt></td></tr>
</table>

<p></p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td width="20%"><b>Wysyłamy pole</b></td><td width="80%"><b>Znaczenie</b></td></tr>
<tr class="tabf"><td><tt>fmnumber</tt></td><td>numer</td></tr>
<tr class="tabf"><td><tt>fmpwd</tt></td><td>stare hasło</td></tr>
<tr class="tabf"><td><tt>pwd</tt></td><td>nowe hasło</td></tr>
<tr class="tabf"><td><tt>email</tt></td><td>nowe adres e-email</td></tr>
<tr class="tabf"><td><tt>tokenid</tt></td><td>identyfikator tokenu</td></tr>
<tr class="tabf"><td><tt>tokenval</tt></td><td>wartość tokenu</td></tr>
<tr class="tabf"><td><tt>code</tt></td><td>hash liczony z pól <tt>pwd</tt> i <tt>email</tt></td></tr>
</table>

<p>
Jeśli wszystko przebiegło poprawnie, serwer odpowie:
</p>

<div class="http">
<pre>reg_success:<b>UIN</b></pre>
</div>

<hr />

<a name="ch2.6"></a>
<h3>2.6. Przypomnienie hasła pocztą</h3>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td width="20%"><b>Pole nagłówka</b></td><td width="80%"><b>Wartość</b></td></tr>
<tr class="tabf"><td><tt>HOST</tt></td><td><tt>retr.gadu-gadu.pl</tt></td></tr>
<tr class="tabf"><td><tt>ŚCIEŻKA</tt></td><td><tt>/appsvc/fmsendpwd3.asp</tt></td></tr>
</table>

<p></p>

<table class="tab" border="0" cellspacing="1" cellpadding="2" width="100%">
<tr class="tabh"><td width="20%"><b>Wysyłamy pole</b></td><td width="80%"><b>Znaczenie</b></td></tr>
<tr class="tabf"><td><tt>userid</tt></td><td>numer</td></tr>
<tr class="tabf"><td><tt>tokenid</tt></td><td>identyfikator tokenu</td></tr>
<tr class="tabf"><td><tt>tokenval</tt></td><td>wartość tokenu</td></tr>
<tr class="tabf"><td><tt>code</tt></td><td>hash liczony z pola <tt>userid</tt></td></tr>
</table>

<p>
Jeśli się udało, serwer odpowie:
</p>

<div class="http">
<pre>pwdsend_success</pre>
</div>

<hr />

<a name="ch3"></a>
<h2>3. Połączenia bezpośrednie</h2>

<a name="ch3.1"></a>
<h3>3.1. Nawiązanie połączenia</h3>

<p>
Połączenia bezpośrednie pozwalają przesyłać pliki lub prowadzić rozmowy
głosowe bez pośrednictwa serwera. Początkowe wersje Gadu-Gadu potrafiły
przesyłać bezpośrednio również wiadomości tekstowe, ale funkcjonalność
ta została zarzucona.
</p>

<p>
Dla każdego połączenia musimy zdobyć od serwera 8 bajtowy identyfikator.
Aby pobrać identyfikator należy użyć pakietu:
</p>

<div class="c">
<pre>#define GG_DCC7_ID_REQUEST 0x0023

struct gg_dcc7_id_request {
	int type;		<i>/* rodzaj transmisji */</i>
};</pre>
</div>

<p>
Pole <tt>type</tt> oznacza rodzaj transmisji:
</p>

<div class="c">
<pre>#define GG_DCC7_TYPE_VOICE 0x00000001	<i>/* Rozmowa głosowa (już nieużywane) */</i>
#define GG_DCC7_TYPE_FILE 0x00000004	<i>/* Przesyłanie plików */</i>
</pre>
</div>

<p>
Na co serwer odpowie:
</p>

<div class="c">
<pre>#define GG_DCC7_ID_REPLY 0x0023

struct gg_dcc7_id_reply {
	int type;	<i>/* Rodzaj transmisji */</i>
	long long id;	<i>/* przyznany identyfikator */</i>
};</pre>
</div>

<hr />

<a name="ch3.2"></a>
<h3>3.2. Przesyłanie plików</h3>

<div class="check">W rodzaju transmisji (type) GG_DCC7_TYPE_FILE</div>

<h4>3.2.1 GG_DCC7_TYPE_FILE - Jak powiadamiać, jak akceptować oraz jak odrzucać</h4>

<p>
Aby powiadomić o chęci przesłania pliku, należy wysłać następujący pakiet.
</p>

<div class="c">
<pre>#define GG_DCC7_NEW 0x0020

struct gg_dcc7_new {
	long long id;		<i>/* identyfikator połączenia */</i>
	int uin_from;		<i>/* numer nadawcy */</i>
	int uin_to;		<i>/* numer odbiorcy */</i>
	int type;		<i>/* rodzaj transmisji */</i>
	char filename[255];	<i>/* nazwa pliku */</i>
	long long size;		<i>/* rozmiar pliku */</i>
	char hash[20];		<i>/* hash SHA1 (już nieużywane 00 00 00) */</i>
};</pre>
</div>

<p>
Strona wywoływana po otrzymaniu pakietu GG_DCC7_NEW, może zaakceptować pobieranie pliku,
wysyła pakiet:
</p>

<div class="c">
<pre>#define GG_DCC7_ACCEPT 0x0021

struct gg_dcc7_accept {
	int uin;	<i>/* numer przyjmującego połączenie */</i>
	long long id;	<i>/* identyfikator połączenia */</i>
	int offset;	<i>/* offset przy wznawianiu transmisji */</i>
	int dunno1;	<i>/* 0x00000000 (na 99% kontynuacja offsetu) */</i>
};</pre>
</div>

<p>
Jeśli plik został już częściowo odebrany i chcemy wznowić przesyłanie,
w polu <tt>offset</tt> wystarczy podać ile bajtów już mamy, a odebrane
dane dopisać na końcu pliku.
</p>

<p>
Jeśli strona wywołana chce odrzucić plik wysyła pakiet:
</p>

<div class="c">
<pre>#define GG_DCC7_REJECT 0x0022

struct gg_dcc7_reject {
	int uin;	<i>/* Numer odrzucającego połączenie */</i>
	long long id;	<i>/* Identyfikator połączenia */</i>
	int reason;	<i>/* Powód rozłączenia */</i>
};</pre>
</div>

<p>
Dla pola <tt>reason</tt> znane są wartości:
</p>

<div class="c">
<pre>#define GG_DCC7_REJECT_BUSY	0x00000001	<i>/* Połączenie bezpośrednie już trwa, nie umiem obsłużyć więcej */</i>
#define GG_DCC7_REJECT_USER	0x00000002	<i>/* Użytkownik odrzucił połączenie */</i>
#define GG_DCC7_REJECT_VERSION	0x00000006	<i>/* Druga strona ma wersję klienta nieobsługującą połączeń bezpośrednich tego typu */</i>
</pre>
</div>

<p>
Przed akceptacją pliku przez stronę wywoływaną, użytkownik może przerwać
żądanie wysyłając pakiet:
</p>

<div class="c">
<pre>#define GG_DCC7_ABORT 0x0025
struct gg_dcc7_abort {
	long long id;		<i>/* identyfikator połączenia */</i>
	int uin_from;		<i>/* numer nadawcy */</i>
	int uin_to;		<i>/* numer odbiorcy */</i>
};</pre>
</div>

<p>
Strona wywoływana w takim przypadku powinna otrzymać pakiet:
</p>

<div class="c">
<pre>#define GG_DCC7_ABORTED 0x0025
struct gg_dcc7_aborted {
	long long id;		<i>/* identyfikator połączenia */</i>
};</pre>
</div>


<p>
Po zaakceptowaniu pliku, obie strony zaczynają nasłuchiwać na losowo wybranym porcie i
wysyłają pakiet GG_DCC7_INFO z informacjami potrzebnymi do połączenia.
</p>

<h4>3.2.2 relay.gadu-gadu.pl - 91.197.13.102 albo tajemniczy host w podsieci 91.197.12.0/22</h4>

<p>
Oba hosty łączą się również z relay.gadu-gadu.pl:80 aby uzyskać listę serwerów które mogą pośredniczyć
w wymianie plików.
</p>

<div class="c">
<pre>#define GG_DCC7_RELAY_REQUEST 0x0a
struct gg_dcc7_relay_req {
	int magic;	<i>/* 0x0a */</i>
	int len;	<i>/* długość całego pakietu */</i>
	long long id;	<i>/* identyfikator połączenia */</i>
	short dunno1;	<i>/* 0x01 0x00 */</i>
	short dunno2;	<i>/* 0x02 0x00 */</i>
};</pre>
</div>

<div class="check">
Czy wysyła zapytania DNS o relay.gadu-gadu.pl U mnie łączy się z 91.197.13.102, zapytań nie widziałem (cache?)
</div>

<div class="check">
Tak naprawdę z relay.gadu-gadu.pl łączą się dwa razy.
Za pierwszym razem łączą się wysyłając w dunno1: 08 00.
Odpowiada też dwoma rekordami, ale w port jest 00 00
</div>

<p>
Przykładowe pytanie o serwery dla połączenia 0x160600000bd4
</p>

<div class="example">
<pre>
0000  0a 00 00 00 14 00 00 00 d4 0b 00 00 06 16 00 00
0010  01 00 02 00
</pre>
</div>

<p>
Serwer odpowiada:
</p>

<div class="c">
<pre>#define GG_DCC7_RELAY_REPLY 0x0b
struct gg_dcc7_relay_reply {
	int magic;	<i>/* 0x0b */</i>
	int len;	<i>/* długość całego pakietu */</i>
	int rcount;	<i>/* prawdopodobnie ilość pośredniczących serwerów */</i>
	struct {
		int ip;		<i>/* adres ip serwera */</i>
		short port;	<i>/* port serwera */</i>
		char family;	<i>/* rodzina adresów (na końcu?!) AF_INET=2 */</i>
	} proxies[rcount];
};</pre>

</div>

<p>Przykładowa odpowiedź serwera zawierająca 2 rekordy:</p>
<ol>
  <li>91.197.13.104:80</li>
  <li>91.197.13.104:443</li>
</ol>

<div class="example">
<pre>
0000  0b 00 00 00 1a 00 00 00 02 00 00 00 5b c5 0d 68
0010  50 00 02 5b c5 0d 68 bb 01 02
</pre>
</div>

<p></p>

<h4>3.2.3 GG_DCC7_INFO - Jak się odnaleźć w mroku</h4>

<div class="c">
<pre>#define GG_DCC7_INFO 0x001f

struct gg_dcc7_info {
	int uin;	<i>/* numer nadawcy */</i>
	int type;	<i>/* sposób połączenia */</i>
	long long id;	<i>/* identyfikator połączenia */</i>
	char info[64];	<i>/* informacje o połączeniu */</i>
};</pre>
</div>

<div class="check">Rodzielić info na info1, info2</div>

<p>
W polu <tt>type</tt> sposób połączenia:
</p>

<div class="c">
<pre>#define GG_DCC7_TYPE_P2P 0x00000001	<i>/* Połączenie bezpośrednie */</i>
#define GG_DCC7_TYPE_SERVER 0x00000002	<i>/* Połączenie przez serwer */</i>
</pre>
</div>

<p>Dla połączeń bezpośrednich:</p>
<ul>
 <li>pierwsze 32bajty pola <tt>info</tt> to <i>IP &lt;SPACJA&gt; PORT</i></li>
 <li>drugie 32bajty pola <tt>info</tt> to ip oraz port w innej postaci, niestety nie mamy informacji o algorytmie :)</li>
</ul>

<p>
Przykładowa zawartość pola <tt>info</tt> dla 10.0.0.2:22563
</p>

<div class="example">
<pre>
0000   31 30 2e 30 2e 30 2e 32 20 32 32 35 36 33 00 00  10.0.0.2 22563..
0010   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0020   31 37 36 34 36 38 34 38 34 00 00 00 00 00 00 00  176468484.......
0030   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
</pre>
</div>

<p>
Po udanym połączeniu na podany adres w GG_DCC7_INFO wysyłamy pakiet powitalny:
</p>

<div class="c">
<pre>struct gg_dcc7_welcome_p2p {
	long long id;	<i>/* identyfikator połączenia */</i>
};</pre>
</div>

<p>
Druga strona powinna odpowiedzieć tym samym. Teraz już możemy albo wysyłać albo odbierać plik.
</p>
<div class="check">
Z powodu tego że obie strony łączą się w tym samym momencie możliwy jest wyścig.
Z tego co zauważyłem gdy jednak ze stron zorientuje się że na innym połączeniu dostaliśmy już ten id,
to połączenie jest zrywane - ale czy taki sposób rozwiązywania nie powoduje możliwych wyścigów?
</div>

<p>Dla połączeń przez serwer:<br/>
- pierwsze 32bajty pola <tt>info</tt> to GG<i>id</i>CH<i>numerek</i><br/><br/>
Gdzie: <br/>
<tt>id</tt> to identyfikator połączenia zapisany w cyferkach ASCII<br/>
<tt>numerek</tt> TBD
</p>

<div class="warn">
<pre>
GG7.7 wysyła: GG<i>id</i><b>SH</b><i>numerek</i>
Protokół jest inny, i raczej nie będzie działać.
</pre>
</div>

<p>
Przykładowa zawartość pola <tt>info</tt> dla połączenia 0x00000a0600000b27<br/>
<br/>
$ echo 'ibase=16; 00000A0600000B27' | bc <br/>
11020886084391
</p>

<div class="example">
<pre>
0000   47 47 31 31 30 32 30 38 38 36 30 38 34 33 39 31  GG11020886084391
0010   43 48 36 39 36 32 00 00 00 00 00 00 00 00 00 00  CH6962..........
0020   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
0030   00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
</pre>
</div>

<p>
Po połączeniu do serwera pośredniczącego wysyłamy pakiet powitalny:
</p>

<div class="c">
<pre>struct gg_dcc7_welcome_server {
	int dunno1;	<i>/* 0xc0debabe */</i>
	long long id;	<i>/* identyfikator połączenia */</i>
};</pre>
</div>

<p>
Serwer powinien odpowiedzieć tym samym. Teraz już możemy albo wysyłać albo odbierać plik.
</p>

<hr />

<a name="ch3.3"></a>
<h3>3.3. Rozmowy głosowe</h3>

<div class="check">
ZTCP to leci po SIP
</div>

<div class="check">
<p>
Aby powiadomić o chęci rozmowy głosowej należy wysłać pakiet:
</p>

<div class="c">
<pre>#define GG_DCC_REQUEST_VOICE 0x0002

struct gg_dcc_request {
	int type;	<i>/* GG_DCC_REQUEST_VOICE */</i>
};</pre>
</div>

<p>
Strona wywołana może potwierdzić chęć przeprowadzenia rozmowy za pomocą
pakietu:
</p>

<div class="c">
<pre>#define GG_DCC_VOICE_ACK 0x01

struct gg_dcc_voice_ack {
	char type;	<i>/* GG_DCC_VOICE_ACK */</i>
};</pre>
</div>

<p>
Jeśli strona wywołana chce odrzucić rozmowę głosową, zrywa połączenie.
Mimo tego, strona wywołująca nie powinna ignorować wartości potwierdzenia.
</p>

<p>
Następnie przesyłane są próbki dźwiękowe kodowane microsoftowym wariantem
GSM. Pod systemem Windows wystarczy użyć standardowego kodeka, pod innymi
można skorzystać z biblioteki
<a href="http://kbs.cs.tu-berlin.de/~jutta/toast.html">libgsm</a> z opcją
WAV49. Pakiet danych wygląda następująco:
</p>

<div class="c">
<pre>#define GG_DCC_VOICE_DATA 0x03

struct gg_dcc_voice_data {
	char type;	<i>/* GG_DCC_VOICE_DATA */</i>
	int length;	<i>/* długość pakietu */</i>
	char data[];	<i>/* dane */</i>
};</pre>
</div>

<p>
W celu zakończenia rozmowy głosowej, zamiast powyższej ramki wysyła się:
</p>

<div class="c">
<pre>#define GG_DCC_VOICE_TERMINATE 0x04

struct gg_dcc_voice_terminate {
	char type;	<i>/* GG_DCC_VOICE_TERMINATE */</i>
};</pre>
</div>

<p>
Do wersji 5.0.5 w jednym pakiecie było umieszczone 6 ramek GSM (<i>6 * 32,5 =
195 bajtów</i>), a począwszy od tej wersji przesyła się po 10 ramek GSM,
poprzedzając je bajtem zerowym (<i>1 + 10 * 32,5 = 326 bajtów</i>).
</p>
</div>

<hr />

<a name="ch4"></a>
<h2>4. Autorzy</h2>

<p>
Lista autorów tego tekstu znajduje się poniżej. Ich adresy e-mail <b>nie
służą</b> do zadawania pytań o podstawy programowania albo jak się
połączyć z serwerem i co zrobić dalej. Jeśli masz pytania dotyczące protokołu,
napisz na listę dyskusyjną
<a href="http://lists.ziew.org/mailman/listinfo/libgadu-devel">libgadu-devel</a>.
</p>

<ul>
	<li><b>Wojtek Kaniewski</b> (wojtekka%irc.pl): pierwsza wersja opisu,
	poprawki, utrzymanie wszystkiego w porządku.</li>
	<li><b>Robert J. Woźny</b> (speedy%atman.pl): opis nowości w protokole
	GG 4.6, poprawki.</li>
	<li><b>Tomasz Jarzynka</b> (tomee%cpi.pl): badanie timeoutów.</li>
	<li><b>Adam Ludwikowski</b> (adam.ludwikowski%wp.pl): wiele poprawek,
	wersje klientów, rozszerzone wiadomości, powody nieobecności.</li>
	<li><b>Marek Kozina</b> (klith%hybrid.art.pl): czas otrzymania
	wiadomości.</li>
	<li><b>Rafał Florek</b> (raf%regionet.regionet.pl): opis połączeń
	konferencyjnych.</li>
	<li><b>Igor Popik</b> (igipop%wsfiz.edu.pl): klasy wiadomości przy
	odbieraniu zakolejkowanej.</li>
	<li><b>Rafał Cyran</b> (ajron%wp.pl): informacje o remote_port,
	rodzaje potwierdzeń przy ctcp, GG_LOGIN_EXT.</li>
	<li><b>Piotr Mach</b> (pm%gadu-gadu.com): ilość kontaktów, pełna
	skrzynka, pusta lista, maska audio, usługi HTTP, GG_LOGIN_EXT.</li>
	<li><b>Adam Czyściak</b> (acc%interia.pl): potwierdzenie wiadomości
	GG_CLASS_ACK.</li>
	<li><b>Kamil Dębski</b> (kdebski%kki.net.pl): czas w stanach
	opisowych.</li>
	<li><b>Paweł Piwowar</b> (alfapawel%go2.pl): format czasu.</li>
	<li><b>Tomasz Chiliński</b> (chilek%chilan.com): nowości w 5.0.2.</li>
	<li><b>Radosław Nowak</b> (rano%ranosoft.net): uzupełnienie statusu
	opisowego, wersja 5.0.3.</li>
	<li><b>Walerian Sokołowski</b>: pierwsza wersja opisu protokołu
	bezpośrednich połączeń.</li>
	<li><b>Nikodem</b> (n-d%tlen.pl): flagi rodzaju użytkownika.</li>
	<li><b>Adam Wysocki</b> (gophi%ekg.chmurka.net): poprawki, utrzymanie 
	wszystkiego w porządku, GG_XML_EVENT.</li>
	<li><b>Marcin Krupowicz</b> (marcin.krupowicz%gmail.com): informacja na 
	temat tego, że pakiet GG_LOGIN_OK nie zawsze jest zerowej długości.</li>
	<li><b>Jakub Zawadzki</b> (darkjames%darkjames.ath.cx): nowości w
	7.x i 8.x.</li>
	<li><b>Krystian Kołodziej</b> (krystiankolodziej%gmail.com): znaczenie
	GG_DISCONNECT_ACK.</li>
	<li><b>Adrian Warecki</b> (bok%kokosoftware.pl): Przykładowe pakiety GG_XML_ACTION</li>
</ul>

<hr />

<font color="silver">
$Id$
</font>

</td></tr></table>
</center>

</body>
</html>