Struktura archiwum komunikatora Tlen.pl
• tech • 883 słowa • 5 minut czytania
Ta notatka jest częścią serii Tlen.pl bez tajemnic. Zapoznaj się z pozostałymi wpisami.
Znów o tlenie, nowa publikacji z serii “Tlen.pl bez tajemnic”, tym razem na temat struktury archiwum komunikatora Tlen.pl.
Tlen.pl tworzy dla każdego profilu folder DataBase
, umiejscowiony w katalogu danego profilu. W folderze tym są przechowywane pliki archiwum, a w nich zależnie od ustawień - wiadomości, rozmowy i smsy.
Pliki archiwum można podzielić na dwa rodzaje - pliki indeksowe i pliki danych. Pliki indeksowe, o rozszerzeniu .idx
, jak sama nazwa wskazuje, składają się z indeksów przechowujących zapisane informacje o wiadomościach, rozmowach, i smsach, których treść znajduje się w plikach danych, identyfikowanych rozszerzeniem .dat
.
W niniejszej publikacji postaram się omówić budowę archiwum.
Wszystkie wartości liczbowe zapisane są w formie Little-Endian, czyli zgodnie z kolejnością bajtów maszyn Intela.
Przy opisie struktur, założono, że wyrównanie do granicy rozmiaru słowa wynosi 1 bajt. Przez co należy wyłączyć w kompilatorze domyślnie włączone wyrównanie zmiennych do rozmiaru słowa danej architektury. Należy zwrócić uwagę na rozmiar typów zmiennych i kolejność bajtów.
Myślę, że nie ma potrzeby opisywania przeznaczenia poszczególnych pól zawartych w przedstawianych strukturach, ich nazwy i zawarte komentarze “mówią” same za siebie.
Pola o nieznanym lub nie do końca jasnym znaczeniu, oznaczono przedrostkiem unknown
.
Jako, iż tlen.pl tworzony jest z wykorzystaniem VCLa, wszelkie dane na temat daty i czasu zostały zapisane w Borlandowskim formacie TDateTime. Informacje o prostej konwersji na bardziej ludzki format - uniksowy znacznik czasu można znależć tutaj: Convert TDateTime to Unix TimeStamp.
Wszelkie wartości offset
, występujące w strukturach są liczone względem początku pliku.
Rozmowy
Rozmowy archiwizowane są w plikach chats.idx
i chats.dat
.
Plik indeksu zawiera listę wszystkich przeprowadzonych rozmów. Lista składa się z rekordów, które przechowują informacje o rozmowie, każdy rekord reprezentowany jest przez strukturę:
struct IDXchat {
char name[26]; // nazwa rozmowcy
char network[6]; // nazwa sieci (nieobsługiwane)
double time; // czas w TDateTime
int flags; // flagi
int offset; // pozycja pierwszej wypowiedzi
int count; // ilosc wypowiedzi
int ID; // ID rozmowy
};
Rozmiar tej struktury wynosi 56 bajtów.
Plik danych - chats.dat
składa się z rekordów tworzących listę, gdzie każdy rekord reprezentuje jedną wypowiedz z rozmowy. Każda wypowiedz zapisana jest w formie struktury:
struct DATchat {
double time; // czas wypowiedzi w TDateTime
int flags; // flagi
int size; // rozmiar wypowiedzi
int ID; // ID rozmowy
int unknown;
char msg[]; // tresc wypowiedzi
};
Struktura ta ma rozmiar równy 24 bajty + size
.
Flagi w powyższych strukturach opisują dodatkowe właściwości. Obecnie dla każdej po jednej:
#define ARCHIVE_CHAT_FLAG_SELECT 0x00001 // IDXchat / zaznaczona do usuniecia
#define ARCHIVE_CHAT_FLAG_SEND 0x00001 // DATchat / wyslana przez nas
Wzajemna relacja miedzy indeksem rozmowy a jej wypowiedziami identyfikowana jest na podstawie ID
. Przy czym wypowiedzi danej rozmowy nie są zapisane w jednym ciągu kolejnych po sobie rekordów, a “rozrzucone” po całym pliku.
Wiadomości
Wiadomości przechowywane są w plikach msgs.idx
i msgs.dat
.
Plik indeksowy wiadomości, podobnie jak w przypadku rozmów, jest listą wszystkich odebranych i wysłanych wiadomości. Każda rozmowa zapisana jest w postaci poniższej, 56-bajtowej struktury:
struct IDXmsg {
char name[26]; // nazwa nadawcy
char network[6]; // nazwa sieci (nieobsługiwane)
double time; // czas wiadomosci w TDateTime
int flags; // flagi
int offset; // pozycja wiadomosci
int size; // rozmiar wiadomosci
int unknown;
};
Flagi opisują dodatkowe właściwości wiadomości. Obecnie istnieją tylko dwie:
#define ARCHIVE_MSG_FLAG_SEND 0x00001 // wyslana przez nas
#define ARCHIVE_MSG_FLAG_SELECT 0x10000 // zaznaczona do usuniecia
Plik danych jest zwykłym plikiem tekstowym zawierającym treści wszystkich wiadomości oddzielonych od siebie spacją. Na podstawie danych zawartych w strukturach IDXmsg
- offset
i size
można w łatwy sposób przypisać daną treść do konkretnej struktury wiadomości, odwzorowując tym samym pełną, właściwą wiadomość.
SMSy
Historia wysłanych wiadomości smsowych zawarta jest w dwóch plikach - sms.idx
i sms.dat
. Ich budowa jest zbliżona do budowy plików przechowywujących archiwum wiadomości.
Tak, jak pozostałe pliki indeksowe archiwum tlena, również sms.idx
zawiera informacje dotyczące wszystkich wysłanych smsach w postaci listy odpowiednich struktur o rozmiarze 40 bajtów. Struktury te mają następującą budowę:
struct IDXsms {
char tel[12]; // nr telefonu
int unknown1;
double time; // czas wyslania w TDateTime
int flags; // flagi
int offset; // pozycja wiadomosci
short size; // rozmiar wiadomosci
short recv; // odebrany sms
int unknown2;
};
Flagi opisują dodatkowe właściwości smsa:
#define ARCHIVE_SMS_FLAG_SELECT 0x00001 // zaznaczony do usuniecia
Plik danych sms.dat
zawierający treści poszczególnych wiadomości sms, jest, tak jak w przypadku msgs.dat
, zwykłym plikiem tekstowy. Treści oddzielone są spacją, a dostęp do nich i identyfikacja następuje na podstawie danych zawartych w indeksach.
Przy usuwaniu rozmów, wiadomości czy smsów z archiwum, tlen od razu nie usuwa fizycznie danych z plików archiwum. Specjalnie oznacza usunięte rekordy w plikach indeksowych, co by nie były brane pod uwagę przy wyświetlaniu. Fizyczne usuniecie następuje dopiero w czasie wykonywania kompaktowania archiwum.
Istnieje, więc możliwość odzyskania treści usuniętych wiadomości i smsów, a w przypadku rozmów teoretycznie jest możliwość pełnego odtworzenia rozmowy.
Oznaczenie usuniętych rekordów jest rozpoznawane po wartości pól time
i size
, time
zostaje wyzerowane, a wartość size
ustawiona na -1
, pozostałe pola zawierają niezidentyfikowane dane.
Nie należy tutaj mylić “usuniętych” z polem select
, które służy do czegoś zupełnie innego - informuje ono o “zaznaczeniu do usunięcia” danej pozycji w archiwum tlena.
To byłoby wszystko na temat struktury archiwum tlena.
W wolnym czasie postaram się napisać i udostępnić kilka przykładowych programów operujących na plikach archiwum. Obecnie tylko jeden “ciekawszy” program, na jaki trafiłem całkiem przypadkiem, można znaleźć na forum ekipa.tlen.pl w temacie Dostep do archiwum tlena. Niestety napisany w Delphi :(.
Komentarze (17)
Jak tak dobrze ci idzie rozszyfrowywanie Tlena, to rozszyfruj jeszcze przesyłanie plików przez NAT’a, obrazki podczas rozmów i wideokonferencje.
Niektóre z tych problemów pewnie zostaną opisane w Nieoficjalnej dokumentacji protokołu. Nie wiem jak z NAT-em, ale gdzieś miałem jakiś kod do p2p, tyle że tej starszej wersji. Obecnie, póki co, nie mam zbytnio na to czasu ;)
W Tlen dla Miranda jest pełen protokół przesyłania plików w wersji bez NAT, jak i rozmowy głosowe, ale przydało by się jeszcze opracować tych kilka dodatków.
Ach, zanim zapomnę, gdzie można dostać tę bibliotekę lint? W sieci nigdzie jej nie ma. Czy jest dostępna tylko z tą książką?
Cześć Marcin,
czytałem dzisiaj Twój wpis na blogu sprzed 14 lat(!) i mam pytanie w jego kontekście. Kończysz wpis tak:
Napisałeś te kilka przykładowych programów? Albo masz może jeszcze gdzieś (najlepiej skompilowany) program z forum ekipa.tlen.pl?
Zebrało mi się na wspominki i chciałem poczytać swoje dawne rozmowy z Tlenu, ale poza napisaniem własnego programu (dzięki za taki szczegółowy opis - w ostateczności może coś wyrzeźbię (chociaż programistą nie jestem)), pozostaje mi instalacja tlenu i podmiana plików
chats.dat
ichats.idx
. Jednak sam komunikator nie za wiele oferuje w kontekście obsługi archiwum. Brak możliwości eksportowania rozmów z danym kontaktem, etc.Podsumowując - dzięki za ten wpis sprzed ponad dekady, a jeśli masz jakiś program do obsługi
chats.dat
i chcesz się nim podzielić, daj znać.Pozdrawiam,
Robert
Niestety na szybko nic nie udało mi się znaleźć…
Wydaje mi się, że najwygodniej archiwum poprzeglądać prosto z Tlenu (jeśli jest taka możliwość), ale tak jak piszesz, chyba nie ma tam żadnej opcji do eksportu prócz ręcznego kopiowania konwersacji.
Bazując na moim opisie bez problemu dałoby się zrobić jakiś eksporter (program, skrypt), który przemieliłby te pliki i wypluł ich zawartość w jakimś bardziej aktualnym formacie - txt, xml, json.
Dzięki za odpowiedź!
Gdybyś znalazł kiedyś przez przypadek czy to skrypt, czy cokolwiek innego - to jeśli byś mógł - podrzuć mi na maila (z góry dzięki). Nawet jakiś draft - łatwiej będzie mi samemu coś wypłodzić…
Właśnie, co do napisania czegoś własnego - Twój opis jest super, ale ja nie jestem doświadczonym programistą (właściwie w ogóle nie jestem programistą - czasem coś pokoduje hobbystycznie), więc nie wiem czy dam radę. Ale na pewno spróbuję. Mam tam połowę swojego młodzieńczego życia :)
Wczoraj czytałem te archiwum właśnie poprzez odpalenie Tlena - oj uśmiałem się z siebie (wiesz taka podróż 15 lat wstecz :) ).
Pozdrawiam,
Robert
Jakbym na coś trafił to dam znać… Po uporządkowaniu bloga i migracji może będę w wolnych chwilach porządkował projekty i kody, i jakby coś się znalazło to pewnie tutaj o tym wspomnę.
Mam podobną podroż w czasie, jak przeglądam tutaj stare wpisy ;)
A pamiętasz może jakie kodowanie było plików chats.idx/dat - bo kiedy potraktować je zwykłym cat to oprócz oczekiwanej treści wypluwa różne dziwne znaki (właśnie jakby kodowanie było nie takie). Na przykład: " Ola=-��;��@���…. "
Czy źle w ogóle do tego się zabieram i nie da się w ten sposób tego czytać?
Pewnie stringi zapisane są w jakimś windowsowym kodowaniu, spróbuj Windows-1250.
To znowu ja.
Poradziłem sobie ze zmienną wielkością struktury, ale napotkałem kolejny problem - w połowie pliku dat pojawiają się same zera (około 50 bajtów), a potem kolejne zapisy - ale jakby już z pominięciem przedstawionej przez Ciebie struktury.
Czy to możliwe, że w czasie struktura się zmieniała, czy może raczej plik jest uszkodzony (to wydaje się dziwne - bo mam dwa różne archiwa - z dwóch różnych urządzeń - i w obu występuje ten sam problem :( )?
Rozszyfrowałem
offset
z idx - nie był on do końca oczywisty (przynajmniej dla mnie). Offset to numer bajtu, na którym zaczyna się pierwszy rekordDATchat
wiadomości oID
wskazanym w rekordzieIDXchat
. Hmm - nadal nie brzmi to jasno…Te puste miejsca w pliku dat to mogą być jakieś usunięte rozmowy, ale dziwne, bo wtedy i tak struktury powinny zostać zachowane, aby dało się bezproblemowo “łazić” po rekordach w pliku.
Co do offsetu to tak jak myślisz, pozycja względem początku pliku - tutaj bajtowo. Kolejne wypowiedzi w rozmowie nie muszą być zapisane jedna za drugą. Dane rekordy porozrzucane są po pliku…
Dlatego, ogólnie w większości przypadków, cała idea zabawy z tym wymaga wczytania wszystkiego do pamięci i odpowiedniego przetworzenia/zapakowania w struktury. Na przykład jakieś listy i wektory dla wypowiedzi posegregowane po identyfikatorach rozmów, co pozwoli szybko dostać się do danej rozmowy etc… Opcji jest wiele… ;)
Być może ten
unknown
wDATchat
coś znaczy. Może to pozycja/offset do kolejnej wypowiedzi? Chyba nigdy nie wpadłem na pomysł by coś takiego sprawdzić - teraz przyszło mi to do głowy. Gdyby tak było to wtedy dałoby się sekwencyjnie “lecieć” po całej wybranej rozmowie skacząc po pliku, bez czytania całości i sortowania po czasie.Może gdybym miał trochę wolnego czasu to bym się tym pobawił. Niestety aktualnie nie mam ani czasu, ani potrzeby grzebania w tym. Chociaż potraktowanie tego jako małego i szybkiego zadanka dla zabawy nie byłoby głupim pomysłem…
Cześć!
Od dawna dawna zabierałem się za coś do czytania archiwum tlena. I w końcu udało mi się wykroić trochę czasu i zrobiłem coś na szybko: github.com/darthmaure/O2ArchiveReader. Kod nie jest jakiś optymalny, więc “feel free to fork” :)
Plusy są takie, że struktury opisane w artykule sprawdzają się i wszystko mniej więcej się wczytuje.
Minus jest taki, że mam całe góry dzinych znaków unicode, np:
podaj wlasciwyçĘ\u0003ŇŐÜâ@\u0001\u0018\u0001\v\n\n
. Sprawdzałem różne kodowania od ascii, przez utfy i inicody i najlepiej wygląda to dla ISO-8859-2 - ale i tak nie idealnie (patrz:podaj wlasciwyçĘ\u0003ŇŐÜâ@\u0001\u0018\u0001\v\n\n
). Do tego czasem wydaje się, że wiadomości zaczynają się o kilka znaków za daleko (np. “k daleko?” zamiast pewnie “Jak daleko?”) albo nawet są puste. Sprawdzałem poszczególne bajty wczytywane w takiej sytuacji i nie ma tam nic co mogło być przycięte.Tak na szybko, zmień kodowanie na
Windows-1252
, w funkcjiReadMessageText
wywalSeek
-a i powinno działać ;)Wskaźnik w strumieniu znajduje się już na poprawnej pozycji po przeczytaniu struktury (
messageCoreData
), a Ty go przesuwasz o kolejne 24 bajty i stamtąd czytasz jakieś dane myśląc, że to potencjalny tekst wypowiedzi…Dzięki za podpowiedź -
Seek
rzeczywiście psuł tutaj :)Co do
Windows-1252
- nie pomaga, wygląda na to, że naISO-8859-2
polskie znaki są lepiej wyświetlane.Posiedzę nad tym w wolnych chwilach i wrzucę poprawki - może ktoś kiedyś skorzysta :)
Pomyliłem się w ostatnim komentarzu z tym
Windows-1252
, bo powinno być oczywiścieWindows-1250
, jak już wcześniej gdzieś wyżej napisałem. Sprawdziłem na jakiś szczątkowych plikach archiwum zapis polskich znaki i odpowiadały one kodom zawartym w tablicyCP-1250
.Podmieniłem
chats.dat
ichats.idx
w moim Tlenie (v.7), ale niestety nie widzę nic w archiwum. Tlen v.6 nie mogę zainstalować, niektóre opcje są niedostępne. Jest dzisiaj dostępny jakiś sposób żeby odczytać archiwum z tych plików?Niestety taka struktura archiwum, którego dotyczy ten wpis (i wspomniane pliki) była dostępna do wersji 6 komunikatora włącznie. Tlen 7 był już przepisany w innych technologiach (Qt i inne takie), dlatego Ci nie działa.
Jedyna opcja, a przynajmniej najlepsza, to instalacja na Windows 7, na przykład na maszynie wirtualnej, jeśli nie masz fizycznie dostępu do tego sytemu, wtedy na pewno zadziała ;)