/* * Opis formatu archiwów Gadu-Gadu (dbfile3) * * Wersja: 0.1 * Autor: wzik (wzik@wp.pl) * * Pomocy udzielili: * Ajron (ajron@wp.pl) - obliczanie sumy kontrolnej */ Na razie opisałem tylko msgarch.dat, a i to nie do końca. Czasu brak... 0. Wstęp ======== Gadu-Gadu dla każego użytkownika tworzy następujące pliki: config.dat - ustawienia klienta msgarch.dat - wiadomości outbox.dat - SMS-y oczekujące na wysłanie sent.dat - wysłane SMS-y smseab.dat - kontakty smseagrp.dat - grupy kontaktów Spośród tych plików wszystkie oprócz config.dat, którego tu nie opiszę, mają identyczną budowę ogólną. 1. Wspólne cechy ================ 1.1. Nagłówek ------------- Na początku pliku znajduje się nagłówek tekstowy: char header_txt[] = "dbfile3."; zaś po nim jest liczba rekordów zapisanych w danym archiwum: int rec_num; Po tej liczbie następuje tablica z offsetami rekordów w pliku, liczonymi od końca nagłówka. Pierwsza wartość to zawsze 0. Za tablicą offsetów są już rekordy z właściwymi danymi. 1.2. Suma kontrolna ------------------- Ostatnie 4 bajty każdego pliku, to suma kontrolna. Sposób jej obliczania opracował Ajron, a ilustrują poniższe przykłady, również jego autorstwa: - w Assemblerze: buff dd adres_bufora len dd dlugosc_bufora crc dd ? mov [crc],0 mov esi,[buff] mov edi,[len] test edi,edi jz finish next: movzx eax,byte ptr [esi] mov edx,[crc] add edx,eax mov eax,edx shr eax,18h shl edx,8 or eax,edx mov [crc],eax movzx edx,byte ptr [esi] xor edx,eax inc esi dec edi mov [crc],edx jnz next finish: mov eax,[crc] - w C: // *buff - adres bufora z wczytanym plikiem // len - długość pliku bez ostatnich 4 bajtów unsigned int checksum(unsigned char *buff, int len) { int x; unsigned int tmp, crc = 0; for (x = 0; x < len; x++) { crc += *buff; crc = (crc >> 0x18)|(crc << 8); tmp = *buff++; crc = tmp^crc; } return crc; } 2. Archiwum wiadomości (msgarch.dat) ==================================== Każdy rekord wygląda następująco: struct msgarch { unsigned int *msg_id; // identyfikator wiadomości unsigned int *conv_id; // identyfikator rozmowy unsigned int *sender; // nadawca wiadomości char *uins; // numery rozmówców int *time; // czas wysłania/przyjścia wiadomości char *msg; // treść wiadomości char *format; // formatowanie tekstu } 2.1. Identyfikator wiadomości ----------------------------- 2.2. Identyfikator rozmowy -------------------------- 2.3. Nadawca wiadomości ----------------------- Pole to może przyjąć następujące wartości: 1 - wiadomość ode mnie 2 - wiadomość do mnie Co najmniej od wersji 4.6.1 aż do wersji 4.8.6 istniała możliwość kasowania wiadomości w ten sposób, że były one nadal widoczne w kliencie w oddzielnej gałęzi drzewa. Były one oznaczane dodatkową flagą 4, czyli odpowiednio: 5 i 6. Od wersji 4.8.6 nie można już w ten sposób usuwać wiadomości i te, które są tak oznaczone nie są wyświetlane. 2.4. Numery rozmówców --------------------- W przypadku, gdy rozmowa toczy się pomiędzy dwoma osobami, zapisywany jest tekstowo numer rozmówcy. W przypadku rozmowy konferencyjnej zapisywana jest lista rozmówców, w której poszczególne numery oddzielone są średnikami. 2.5. Czas wysłania/odebrania wiadomości --------------------------------------- Czas ten liczony jest w sekundach od 00:00:00, 1 stycznia 1970, CUT, co oznacza, że można odczytać czas wysłania/odebrania dokładniej niż podaje to Gadu-Gadu. 2.6. Treść wiadomości --------------------- Przy konwersji archiwów do formatu HTML należy pamiętać o tym, że wiadomość może zawierać tagi HTML-owe i przed zapisem do pliku należy zamienić < i > odpowiednio na < i >. 2.7. Formatowanie tekstu ------------------------ W wersjach starszych niż 4.8.1 był tu zawsze pusty string, zaś od tej wersji włącznie znajdują się tu ustawienia formatowania tekstu. Postać tego stringa jest identyczna z informacją o formatowaniu doklejaną do wysyłanego przez Gadu-Gadu pakietu i jest opisana w protokole Gadu-Gadu dostępnym na stronie projektu EKG (http://dev.null.pl/ekg/docs/protocol.html). Jedyna różnica polega na tym, że każda wartość jest zamieniona tak, aby powstał ciąg liter. Algorytm zamiany jest prosty. Przykładowo napisanie pierwszych 7 liter wiadomości czcionką pogrubioną wygląda następująco: format z pakietu GG |02 12 00 01 00 01 08 00 00 --------------------+-------------------------- zapis w archiwum | ba aa ba ia aa aa Aby uzyskać z ciągu "baaabaiaaaaa" z powrotem dane binarne należy postąpić następująco: 1. pobieram pierwszy znak i traktując go jak liczbę odejmuję od niego 0x61: b: 0x62 - 0x61 = 0x1 2. pobieram drugi znak i od niego również odejmuję 0x61: a: 0x61 - 0x61 = 0x0 3. mnożę wynik drugiego działania przez 0x10 i dodaję do wyniku pierwszego 4. GOTO 1. :) /* * That's all folks! */