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 (15)

zwierzak avatar
zwierzak
20070730-175504-zwierzak

Jak tak dobrze ci idzie rozszyfrowywanie Tlena, to rozszyfruj jeszcze przesyłanie plików przez NAT’a, obrazki podczas rozmów i wideokonferencje.

MalCom avatar
MalCom
20070730-213748-malcom

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 ;)

zwierzak avatar
zwierzak
20070731-202945-zwierzak

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ą?

Robert avatar
Robert
20210123-223411-robert

Cześć Marcin,

czytałem dzisiaj Twój wpis na blogu sprzed 14 lat(!) i mam pytanie w jego kontekście. Kończysz wpis tak:

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 :(.

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 i chats.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

Malcom avatar
Malcom
20210124-120326-malcom

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.

Robert avatar
Robert
20210124-130036-robert

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

Malcom avatar
Malcom
20210124-142055-malcom

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 ;)

Robert avatar
Robert
20210124-195020-robert

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ć?

Malcom avatar
Malcom
20210124-224638-malcom

Pewnie stringi zapisane są w jakimś windowsowym kodowaniu, spróbuj Windows-1250.

Robert avatar
Robert
20210131-120936-robert

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 rekord DATchat wiadomości o ID wskazanym w rekordzie IDXchat. Hmm - nadal nie brzmi to jasno…

Malcom avatar
Malcom
20210131-184505-malcom

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 pod identyfikatorach rozmów, co pozwoli szybko dostać się do danej rozmowy etc… Opcji jest wiele… ;)

Być może ten unknown w DATchat 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…

Maure avatar
Maure
20210305-154818-maure

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.

Malcom avatar
Malcom
20210305-224752-malcom

Tak na szybko, zmień kodowanie na Windows-1252, w funkcji ReadMessageText wywal Seek-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…

Maure avatar
Maure
20210309-120116-maure

Dzięki za podpowiedź - Seek rzeczywiście psuł tutaj :)
Co do Windows-1252 - nie pomaga, wygląda na to, że na ISO-8859-2 polskie znaki są lepiej wyświetlane.

Posiedzę nad tym w wolnych chwilach i wrzucę poprawki - może ktoś kiedyś skorzysta :)

Malcom avatar
Malcom
20210309-211555-malcom

Pomyliłem się w ostatnim komentarzu z tym Windows-1252, bo powinno być oczywiście Windows-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 tablicy CP-1250.

Dodaj komentarz

/dozwolony markdown/

/nie zostanie opublikowany/