libtlen

Dokumentacja biblioteki libtlen

Mateusz Papiernik

Hubert Sokołowski

Piotr Pawłow


Spis treści
1. API biblioteki.
1.1. Zaczynamy.
1.2. Zdarzenia.
1.2.1. Zdarzenia obsługiwane jeden raz na początku sesji.
1.2.2. Pozostałe zdarzenia.
1.2.3. Zawartość struktury tlen_event
1.3. Połączmy się.
1.3.1. Funkcje.
2. Specyfikacja katalogu publicznego
2.1. Tagi z parametrami katalogu publicznego
2.2. Odczyt danych z katalogu publicznego
2.3. Zmiana naszych danych w katalogu publicznym
2.4. Wyszukiwanie
2.4.1. Zapytanie
2.4.2. Odpowiedź od serwera
3. Dokumentacja funkcji biblioteki
3.1. auth.c
3.1.1. tlen_hash()
3.1.2. tlen_getid()
3.1.3. tlen_authorize()
3.2. events.c
3.2.1. tlen_starttag_handler()
3.2.2. tlen_endtag_handler()
3.2.3. tlen_char_handler()
3.2.4. tlen_parsebuffer()
3.2.5. tlen_addevent()
3.2.6. tlen_getevent()
3.2.7. tlen_newevent()
3.2.8. tlen_freeevent()
3.2.9. tlen_watch_fd()
3.3. expat.c
3.4. groupchat.c
3.4.1. tlen_groupchat_init()
3.4.2. tlen_get_second()
3.5. hashtable.c
3.6. hub.c
3.6.1. tlen_connect_server()
3.6.2. tlen_hub_query()
3.6.3. tlen_find_server()
3.6.4. tlen_connect_hub_process()
3.6.5. tlen_connect_hub()
3.7. libtlen.c
3.7.1. tlen_init()
3.7.2. tlen_set_hub_blocking()
3.7.3. tlen_set_auth()
3.7.4. tlen_set_proxy()
3.7.5. tlen_login()
3.7.6. tlen_freesession()
3.8. message.c
3.8.1. tlen_sendmsg()
3.9. pool.c
3.10. pubdir.c
3.10.1. tlen_search()
3.10.2. tlen_get_pubdir()
3.10.3. tlen_change_pubdir()
3.10.4. tlen_new_pubdir()
3.10.5. tlen_free_pubdir()
3.11. rate.c
3.12. roster.c
3.12.1. tlen_presence()
3.12.2. tlen_presence_disconnect()
3.12.3. tlen_getroster()
3.12.4. tlen_addcontact()
3.12.5. tlen_removecontact()
3.13. snprintf.c
3.14. sockets.c
3.14.1. tlen_socket_create()
3.14.2. tlen_socket_write()
3.14.3. tlen_socket_write_string()
3.14.4. tlen_socket_destroy()
3.15. str.c
3.16. testclient.c
3.17. utils.c
3.17.1. tlen_ping()
3.17.2. tlen_encode()
3.17.3. tlen_decode()
3.17.4. tlen_debug_raw()
3.17.5. tlen_stripresource()
3.17.6. tlen_base64_encode()
3.17.7. tlen_base64_decode()
3.18. xmlnode.c
3.19. xmlparse.c
3.20. xmlrole.c
3.21. xmltok.c
3.22. xmltok_impl.c
3.23. xmltok_ns.c
4. Omówienie programów przykładowych
4.1. examples/sendmsg.c
4.2. lib/testclient.c

Rozdział 1. API biblioteki.

1.1. Zaczynamy.

Bibliotekę libtlen można wykorzystać w programach pisanych w C oraz C++. Należy tylko dołączać plik nagłówkowy biblioteki jak na przykładzie poniżej

    #include <libtlen/libtlen.h>
    

oraz linkować z biblioteką tlen, np:

    gcc -g -Wall -O2 -ltlen main.c -o main
    

Wszystkie funkcje oraz nazwy struktur z biblioteki dostępne dla programisty mają przedrostek tlen_, natomiast stałe zdefiniowane przedrostek TLEN_. Przed połączeniem z serwerem należy zadeklarować wskaźnik na strukturę tlen_session. W tej strukturze przechowywane są informacje o danej sesji. Jeśli chcemy, aby biblioteka wypisywała informacje o wykonywanych operacjach (np. łączenie z serwerem, autoryzacja) uruchamiamy funkcję

    tlen_setdebug(1);
    

Teraz można przejść do logowania. Dostępne są dwie funkcje: tlen_login oraz tlen_login_nb. Obie wymagają podania dwóch parametrów, odpowiednio loginu i hasła w postaci 'const char *'. Różnią się tym, że pierwsza z nich blokuje program zanim połączy się z serwerem, druga natomiast łączy się z serwerem w oddzielnym procesie, dzięki czemu program nie jest blokowany i przechodzi do obsługi zdarzeń (o tym później). Obie funkcję zwracają wskaźnik na strukturę tlen_session, który należy zachować (będzie potrzebny we wszystkich dalej opisanych funkcjach), lub NULL jeśli logowanie nie powiodło się. Po wywołaniu jednej z tych funkcji przechodzimy do obsługi zdarzeń.


1.2. Zdarzenia.

O wszystkich zdarzeniach (nowa wiadomość, zmiana statusu kogoś z listy użytkowników, itp) program jest powiadamiany za pomocą eventów, których nazwy mają przedrostek TLEN_EVENT_. Poniżej opiszę poszczególne eventy, a potem pokażę przykładową pętlę obsługującą je.


1.2.1. Zdarzenia obsługiwane jeden raz na początku sesji.

Pierwszym zdarzeniem jest TLEN_EVENT_NOWGETID. Mówi nam ono o gotowości serwera, teraz można wysłać żądanie o identyfikator sesji. Służy do tego funkcja tlen_getid, której jako jedyny parametr przekazujemy wskaźnik do sesji. W rezultacie otrzymujemy event TLEN_EVENT_GOTID, a więc mamy już id sesji, czas na autoryzację. W tym celu wywołujemy funkcję tlen_authorize z tym samym parametrem co poprzednio. Jeśli ta operacja się powiedzie program otrzyma zdarzenie TLEN_EVENT_AUTHORIZED, w którego obsłudze można wysłać żądanie o książkę adresową, tlen_getroster (wywołanie również z jednym parametrem). O niepowodzeniu autoryzacji jesteśmy informowani zdarzeniem TLEN_EVENT_UNAUTHORIZED, w tym przypadku należy zakończyć działanie programu lub spróbować zalogować sie ponownie. Zdarzenie TLEN_EVENT_GOTROSTERITEM to pojedynczy wpis w naszej książce adresowej. Aby dostać się do tych informacji odwołujemy się do pola roster w strukturze tlen_event (o niej poźniej w opisie pętli). Pole te jest strukturą o nazwie tlen_user, zawiera nazwę osoby (name), identyfikator (jid) w postaci login@tlen.pl, nazwę grupy (group), rodzaj subskrypcji (subscription) oraz pole ask, które jeśli zawiera napis "subscribe", to znaczy, że czekamy na pozwolenie o subskrypcję u danej osoby. W przeciwnym razie pole ask zawiera NULL. Jeśli chcemy dodać kogoś do naszej listy, to musimy ją poprosić o subskrypcję, inaczej dana osoba nie będzie widoczna. Pole subscription natomiast określa poziom subskrypcji, jeśli zawiera napis "none" to oznacza brak subskrypcji u obu stron, "from" oznacza subskrypcję danej osoby w naszej książce (np. gdy czekamy na pozwolenie na subskrypcję), "to" oznacza, że jesteśmy zapisani u danej osoby ale ta osoba nie jest zapisana u nas (np. gdy zrezygnowaliśmy z kontaktu). Najwyższy poziom subskrypcji to "both", oznacza, że obie strony są zapisane w książce partnera. O końcu książki adresowej jesteśmy powiadamiani zdarzeniem TLEN_EVENT_ENDROSTER. Na tym kończy się obsługa tej części zdarzeń, teraz wywołujemy funkcję tlen_presence jak na przykładzie:

    tlen_presence(sesja,TLEN_STATUS_AVAILABLE,"Dostępny");
    

gdzie pierwszy parametr jest wskaźnikiem na sesję, drugi oznacza status (w tym przypadku dostępny), w trzecim zaś podajemy własny opis.


1.2.2. Pozostałe zdarzenia.

Gdy ktoś dodaje nas do swojej listy kontaktów, jego program wysyła do nas prośbę o subskrypcję, wtedy otrzymujemy event SUBSCRIBE (dokładnie TLEN_EVENT_SUBSCRIBE). Aby subskrypcja przebiegła prawidłowo, należy najpierw zaakceptować nowy kontakt, nawet jeśli chcemy odrzucić prośbę. Inaczej druga strona nie dowie się o naszej decyzji. Jeśli dodatkowo nie mamy tej osoby na liście kontaktów, to należy ją dodać. Służą do tego funkcje odpowiednio "tlen_accept_subscribe" oraz "tlen_addcontact". Teraz należy zapytać użytkownika czy chce subskrybować daną osobę. Jeśli nie, to wywołujemy funkcje "tlen_removecontact" oraz "tlen_accept_unsubscribe".

Event SUBSCRIBED powiadamia nas o tym, że otrzymaliśmy pozwolenie na subskrypcję u danej osoby. Teraz możemy odświeżyć listę kontaktów.

Event UNSUBSCRIBE otrzymujemy, gdy ktoś usunie nas ze swojej listy kontaktów. Nie mamy wyboru, musimy ten fakt zaakceptować, wywołując funkcję "tlen_accept_unsubscribe". Zmieniamy pole "subscribe" na "none", odświeżamy listę i żądamy tego samego, czyli "tlen_request_unsubscribe". W rezultacie powinniśmy otrzymać event UNSUBSCRIBED.

Przechodzimy do ciekawszych rzeczy, czyli wiadomości. MESSAGE powiadamia nas o nowej wiadomości, która może być w postaci rozmowy (TLEN_CHAT) lub pojedynczej wiadomości.

Kiedy osoba zapisana na naszej liście zmienia swój status lub opis otrzymujemy event PRESENCE.

Event NEWMAIL to powiadomienie o nowej poczcie na skrzynce tlen.pl

Event GOTPUBDIRDATA informuje nas o nadejściu naszych danych z katalogu publicznego. Jest rezultatem wywołania funkcji "tlen_get_pubdir".

Aby zmienić nasze dane publiczne wywołujemy funkcję "tlen_change_pubdir". Jeśli ta operacja się powiedzie otrzymujemy event GOTPUBDIRUPDATEOK.

Funkcja "tlen_search" służy do przeszukiwania katalogu publicznego. O znalezionych pozycjach informuje nas event GOTSEARCHITEM. Event ENDSEARCH oznacza koniec znalezionych rekordów.

Każde zdarzenie uzupełnia odpowiednio strukturę tlen_event. Np. event MESSAGE musi gdzieś zapisywać informacje od kogo jest wiadomość i jaką ma treść. O tym mówi następna sekcja.


1.2.3. Zawartość struktury tlen_event

Ponieważ mamy kilka rodzaji zdarzeń, struktura musi zawierać pole określające typ, jest nim "type", które przyjmuje wartości TLEN_EVENT_* (dokładny opis znajduje się w pliku nagłówkowym biblioteki). Poza tym, znajdziemy wskaźniki do struktur odpowiednich typów. Dla danego zdarzenia alokowana jest pamieć dla struktury odpowiadającej temu zdarzeniu, na którą wskazuje odpowiedni wskaźnik. Dokladny opis tej struktury, jak i innych dla konkretnych zdarzeń, znajduje się w samym pliku nagłówkowym.


1.3. Połączmy się.

Załóżmy, że mamy już zadeklarowany w programie wskaźnik na strukturę tlen_session, czyli "struct tlen_session *sesja". Aby pobrać z kolejki zdarzenie potrzebujemy następujących zmiennych:

  fd_set rd, wr;            // obserwowane deskryptory socketów
  struct tlen_event *event; // wskaźnik na zdarzenie
  struct timeval tv;        // czas blokowania programu przez select
  

Inicjalizujemy te zmienne:

  tv.tv_sec = 0;
  tv.tv_usec = 1; // jeśli brak danych to funkcja select nie blokuje programu
  FD_ZERO (&rd);
  FD_ZERO (&wr);
  if ((sesja->check & TLEN_CHECK_READ)) // jeśli czytamy dane
    FD_SET (sesja->fd, &rd);
  if ((sesja->check & TLEN_CHECK_WRITE)) // jeśli wysyłamy dane
    FD_SET (sesja->fd, &wr);
  

Sprawdzamy obecność danych:

  if (select (sesja->fd + 1, &rd, &wr, NULL, &tv) == -1)
  {
    perror("select"); // błąd z deskryptorem?
    exit(1); //wychodzimy z programu
  }
  

Pobieramy zdarzenie:

  if (sesja && (FD_ISSET (sesja->fd, &rd) || FD_ISSET (sesja->fd,
  &wr)))
  {
    tlen_watch_fd (sesja);
    while ((event=tlen_getevent(sesja))!=NULL)
    {
      switch (event->type)
      {
        case TLEN_EVENT_NOWGETID:
        //...
      }
      tlen_freeevent(event); //zwalniamy pamięć
    }
  

Tu zaczyna się obsługa zdarzeń, o której była mowa wcześniej. Powyższy kod należy umieścic w funkcji, którą wywołujemy np. co sekundę. Ponadto aby serwer nie zerwał połączenia należy co jedną minutę wywoływać funkcję "tlen_ping(sesja)". Podczas działania programu sprawdzamy pole "error" w strukturze tlen_session, jeśli jest różne od zera, ponownie łączymy się z serwerem.


1.3.1. Funkcje.

  • tlen_addcontact - dodanie osoby do ksiązki adresowej lub aktualizacja danych, oprócz loginu możemy podać nazwę dla danej osoby i nazwę grupy, do której chcemy ją zapisać.

  • tlen_removecontact - usuwanie osoby z książki.

  • tlen_request_subscribe - prośba o autoryzację u danej osoby.

  • tlen_request_unsubscribe - prośba o wypisanie się z książki danej osoby.

  • tlen_accept_subscribe - autoryzowanie danej osoby w naszej książce.

  • tlen_accept_unsubscribe - zatwierdzenie wypisania z naszej książki danej osoby.

  • tlen_presence - zmiana statusu, podajemy TLEN_STATUS_* oraz opis, jeśli podamy TLEN_STATUS_UNAVAILABLE to zerwiemy połączenie z serwerem.

  • tlen_sendmsg - wysłanie komunikatu, musimy określić typ (TLEN_CHAT dla rozmowy lub TLEN_MESSAGE dla wiadomości).

  • tlen_search - wyszukiwanie w katalogu publicznym.

  • tlen_new_pubdir - inicjalizacja struktury tlen_pubdir.

  • tlen_free_pubdir - zwolnienie pamięci zajmowanem przez strukturę tlen_pubdir.

  • tlen_get_pubdir - pobranie z serwera naszych danych.

  • tlen_change_pubdir - zmiana naszych danych w katalogu publicznym.


Rozdział 2. Specyfikacja katalogu publicznego

2.1. Tagi z parametrami katalogu publicznego

Parametry wyszukiwania:

  • <first> imię </first>

  • <last> nazwisko </last>

  • <nick> nick </nick>

  • <email> email </email>

  • <c> miasto </c>

  • <s> płeć </s> (TLEN_PUBDIR_GENDER_)

  • <d> minimalny wiek </d>

  • <u> maksymalny wiek </u>

  • <r> poszukuję </r> (TLEN_PUBDIR_LOOK_)

  • <g> rozmowa głosowa </g> (TLEN_PUBDIR_VOICE_)

  • <j> zawód </j> (TLEN_PUBDIR_JOB_)

  • <m> stan </m> (TLEN_STATUS_)

  • <p> plany </p> (TLEN_PUBDIR_PLANS_)

  • <e> szkoła </e>

  • <i> identyfikator </i>

Parametry naszych danych z katalogu publicznego są takie same jak wyszkiwaniu z róznicami:

  • <v> widoczność naszego stanu </v>

  • <d>, <u> zastąpione przez <b> - rok urodzenia

W naszych danych nie ma pola <i> !


2.2. Odczyt danych z katalogu publicznego

Aby odczytać nasze dane z katalogu publicznego, wysyłamy zapytanie:

    <iq type="get" id="tr" to="tuba"><query xmlns="jabber:iq:register"></query></iq>
    

Serwer zwróci nam:

    <iq type="result" id="tr" to="id@tlen.pl/t" from="tuba"><query xmlns="jabber:iq:register"><item>parametry</item></query></iq>
    

parametry to tagi, które musimy parsować


2.3. Zmiana naszych danych w katalogu publicznym

Aby zmienić nasze dane w katalogu publicznym, wysyłamy zapytanie:

    <iq type="set" id="tr" to="tuba"><query xmlns="jabber:iq:register">parametry</query></iq>
    

gdzie parametry to tagi (takie samej jak przy odbiorze danych). Jeżeli wszystko poszło prawidłowo i nasze dane zostały uaktualnione, serwer zwróci potwierdzenie w postaci

    <iq type="result" id="tw" to="id@tlen.pl/t" from="tuba"><query xmlns="jabber:iq:register"></query></iq>
    

2.4. Wyszukiwanie

2.4.1. Zapytanie

Aby przeszukać katalog publiczny wysyłamy do serwera zapytanie:

    <iq type="get" id="src" to="tuba"><query xmlns="jabber:iq:search">tutaj to czego szukamy</query></iq>
    

to czego szukamy to lista tagów z wybranymi przez nas właściwościami.

Jeżeli przy wyszukiwaniu nie szukamy wg. któregoś z tych parametrów, to po prostu nie umieszczamy go w zapytaniu. Większość parametrów liczbowych opisywana jest przez #define'y TLEN_PUBDIR_, które ułatwiają nam rozumienie zapytań. Nie dotyczy to parametrów wieku - gdzie po prostu podajemy odpowiednią liczbę. Po złożeniu zapytania wysyłamy je do serwera po czym czekamy na odpowiedź z wynikami.


2.4.2. Odpowiedź od serwera

Po wysłaniu zapytania serwer odpowie nam takim tagiem:

    <iq type="result" id="src" to="id/@tlen.pl/t" from="tuba" n="1"><query xmlns="jabber:iq:search">
	<item jid="jakistamid@tlen.pl">parametry</item>
	<item jid="jakistamid@tlen.pl">parametry</item>	
    </query></iq>
    

Zwrócona parametry są takie same jak te, które wysyłamy w zapytaniu z kilkoma wyjątkami:

  • Zamiast <d> i <u> zwracany jest tag <b> - wiek

  • Zamiast <m> stan zwracany jest w tagu <a>

  • Id użytkownika zwracany jest w głównym tagu <item> w parametrze jid, zamiast w <i>

Otrzymany wynik parsujemy. Każdy tag <item> odpowiada jednemu użytkownikowi. Ze względu na ograniczenia spamu serwer zwraca maksymalnie 20 wyników. Jeżeli nie ma w nich poszukwianej przez nas osoby, dokładniej sprecyzujmy parametry przeszukiwania.


Rozdział 3. Dokumentacja funkcji biblioteki

Opis wszystkich funkcji biblioteki wraz z ich parametrami i dodatkowymi komentarzami.


3.1. auth.c

Opis funkcji zawartych w pliku auth.c


3.1.1. tlen_hash()

Generuje hash potrzebny do zalogowania się

- pass - hasło
- id - identyfikator sesji

Funkcja wewnętrzna na potrzeby tlen_authorize

Deklaracja: char *tlen_hash (const char *pass, const char *id)


3.1.2. tlen_getid()

Wysyła prośbę o ID do serwera

- sesja - nasza sesja

Wywoływane zaraz po połączeniu

Deklaracja: int tlen_getid (struct tlen_session *sesja)


3.1.3. tlen_authorize()

Wysyła zapytanie logujące do serwera

- sesja - nasza sesja

Wywoływane po otrzymaniu ID

Deklaracja: int tlen_authorize (struct tlen_session *sesja)


3.2. events.c

Opis funkcji zawartych w pliku events.c


3.2.1. tlen_starttag_handler()

Handler wykonywany przy rozpoczęciu tagu

- userData - dane parsera
- name - nazwa obsługiwanego tagu
- atts - parametry w tagu

Funkcja wewnętrzna parsera zdarzeń

Deklaracja: void tlen_starttag_handler(void *userData, const XML_Char *name, const XML_Char **atts)


3.2.2. tlen_endtag_handler()

Handler wykonywany przy zakończeniu tagu

- userData - dane parsera
- name - nazwa obsługiwanego tagu

Funkcja wewnętrzna parsera zdarzeń

Deklaracja: void tlen_endtag_handler (void *userData, const XML_Char *name)


3.2.3. tlen_char_handler()

Buforuje otrzymywany tekst w celu otrzymania kompletnego tagu

- userData - dane parsera
- s - tekst dodawany do bufora
- len - długość tekstu

Funkcja wewnętrzna parsera zdarzeń

Deklaracja: void tlen_char_handler (void *userData, const XML_Char *s, int len)


3.2.4. tlen_parsebuffer()

Parsuje jeden kompletny tag XML otrzymany od serwera

- sesja - sesja, w której obsługujemy ewentualne zdarzenia

Funkcja wewnętrzna parsera zdarzeń

Deklaracja: void tlen_parsebuffer(struct tlen_session *sesja) {


3.2.5. tlen_addevent()

Dodaje zdarzenie do kolejki zdarzeń

- sesja - sesja, do której kolejki dodajemy
- e - zdarzenie

Funkcja wewnętrzna parsera zdarzeń

Deklaracja: void tlen_addevent(struct tlen_session *sesja, struct tlen_event *e)


3.2.6. tlen_getevent()

Pobiera kolejne (jeżeli istnieje) zdarzenie z kolejki

- sesja - sesja, której zdarzenia obsługujemy

Zwraca zdarzenie, lub NULL jeżeli nie ma więcej

Deklaracja: struct tlen_event* tlen_getevent(struct tlen_session *sesja)


3.2.7. tlen_newevent()

Tworzy nowe zdarzenie

- type - typ zdarzenia

Zwraca zaalokowaną strukturę zdarzenia

Deklaracja: struct tlen_event* tlen_newevent(int type)


3.2.8. tlen_freeevent()

Zwalnia pamięć po zdarzeniu

- e - zdarzenie

Wewnętrzna funkcja parsowania zdarzeń

Deklaracja: void tlen_freeevent(struct tlen_event *e)


3.2.9. tlen_watch_fd()

funkcja sprawdzająca socket w poszukiwaniu jakiegoś zdarzenia

- sesja - nasza sesja

Podczas błędów ustawia sesja->error i potrafi nawet rozłączyć gniazdo!

Deklaracja: void tlen_watch_fd (struct tlen_session *sesja)


3.3. expat.c

Opis funkcji zawartych w pliku expat.c


3.4. groupchat.c

Opis funkcji zawartych w pliku groupchat.c


3.4.1. tlen_groupchat_init()

Inicjuje konferencję

- sesja - nasza sesja
- to - użytkownik z którym chcemy konferować

Niezaimplementowana obsługa konferencji, funkcja testowa!

Deklaracja: int tlen_groupchat_init(struct tlen_session *sesja, char *to)


3.4.2. tlen_get_second()

Zwraca sekundę danego dnia

- brak parametrów

Potrzebna przy zapytaniach konferencyjnych

Deklaracja: int tlen_get_second()


3.5. hashtable.c

Opis funkcji zawartych w pliku hashtable.c


3.6. hub.c

Opis funkcji zawartych w pliku hub.c


3.6.1. tlen_connect_server()

Łączy się z serwerem

- host - adres
- port - port

Wewnętrzna funkcja dla resolvera huba

Deklaracja: int tlen_connect_server(const char* host, int port)


3.6.2. tlen_hub_query()

Tworzy i wysyła zapytanie do huba

- user - nazwa użytkownika

Funkcja wewnętrzna resolvera huba

Deklaracja: xmlnode tlen_hub_query (const char* user)


3.6.3. tlen_find_server()

Znajduje adres i port serwera z którym można się połączyć

- username - nazwa użytkownika
- port - port (wskaźnik!)

Funkcja wewnętrzna do resolvera huba

Deklaracja: char* tlen_find_server (const char* username, int* port)


3.6.4. tlen_connect_hub_process()

Tworzy i obsługuje proces łączenia z hubem

- user - nazwa użytkownika
- pipe - rórka

Funkcja wewnętrzna resolvera huba

Deklaracja: void tlen_connect_hub_process (const char* user, int pipe)


3.6.5. tlen_connect_hub()

Łączy się z hubem

- sess - sesja
- blocking - blokowalne, lub nie

jeśli blocking=0 uruchamia proces łączący się w tle z hubem

Deklaracja: int tlen_connect_hub (struct tlen_session *sess, int blocking)


3.7. libtlen.c

Opis funkcji zawartych w pliku libtlen.c


3.7.1. tlen_init()

Wywoływana na początku, w celu zainicjowania struktury sesji

- brak parametrów

Przed wykonaniem tej funkcji nie wolno nic robić z sesją!

Deklaracja: struct tlen_session *tlen_init (void)


3.7.2. tlen_set_hub_blocking()

Ustawia, czy proces resolvovania huba ma być synchroniczny, czy asynchroniczny

- sess - sesja dla której ustawiamy parametr
- blocking - 0 lub 1

Nie ustawiamy tego ręcznie, poprzez edycję struktury, a jedynie

Deklaracja: void tlen_set_hub_blocking(struct tlen_session *sess, int blocking)


3.7.3. tlen_set_auth()

Ustawia nazwę użytkownika i hasło w sesji

- sess - sesja dla której ustawiamy parametr
- username - nazwa użytkownika
- password - hasło

Nie ustawiamy tego ręcznie, poprzez edycję struktury, a jedynie

Deklaracja: void tlen_set_auth(struct tlen_session *sess, char *username, char *password)


3.7.4. tlen_set_proxy()

Ustawia adres i port serwera proxy dla transmisji

- sess - sesja dla której ustawiamy parametr
- addr - adres serwera
- port - port

NIEZAIMPLEMENTOWANE

Deklaracja: void tlen_set_proxy(struct tlen_session *sess, char *addr, int port)


3.7.5. tlen_login()

Podstawowa funkcja rozpoczynająca połączenie z serwerem

- sess - sesja opisująca połączenie

Funkcja wypełnia różne pola w sesji, jako jej parametr podajemy

Deklaracja: void tlen_login (struct tlen_session *sess)


3.7.6. tlen_freesession()

Wywoływane w celu zwolnienia pamięci po sesji

- sess - sesja, którą zwalniamy

Najpierw nalezy się rozłączyć z serwerem wysyłając status

Deklaracja: int tlen_freesession (struct tlen_session *sess)


3.8. message.c

Opis funkcji zawartych w pliku message.c


3.8.1. tlen_sendmsg()

Wysyła wiadomość

- sesja - nasza sesja
- destination - osoba, do której wysyłamy wiadomość
- message - treść wiadomości
- type - typ wiadomości, TLEN_CHAT lub TLEN_MESSAGE

Trzeba określić w parametrze type rodzaj wysyłanej wiadomości

Deklaracja: int tlen_sendmsg(struct tlen_session *sesja, const char *destination, const char *message, int type)


3.9. pool.c

Opis funkcji zawartych w pliku pool.c


3.10. pubdir.c

Opis funkcji zawartych w pliku pubdir.c


3.10.1. tlen_search()

Inicjuje wyszukiwanie w katalogu publicznym

- sesja - nasza sesja
- search - struktura opisujaca wyszukiwanie

Uwagi do poniższego kodu:

Deklaracja: int tlen_search(struct tlen_session *sesja, struct tlen_pubdir *search)


3.10.2. tlen_get_pubdir()

Wysyła prośbę o nasze dane z katalogu publicznego

- sesja - nasza sesja

Wraca zaraz po wysłaniu zapytania

Deklaracja: int tlen_get_pubdir (struct tlen_session *sesja)


3.10.3. tlen_change_pubdir()

Wysyła żądanie o zmianę danych w katalogu publicznym

- sesja - nasza sesja
- pubdir - struktura zawierająca nowe dane

Wraca zaraz po wysłaniu zapytania

Deklaracja: int tlen_change_pubdir(struct tlen_session *sesja, struct tlen_pubdir *pubdir)


3.10.4. tlen_new_pubdir()

Inicjuje strukturę zawierającą dane typu katalog publiczny (wyszukiwanie, itp.)

- brak parametrów

Zwraca nową strukturę tlen_pubdir

Deklaracja: struct tlen_pubdir *tlen_new_pubdir ()


3.10.5. tlen_free_pubdir()

Zwalnia pamięć po strukturze tlen_pubdir

- pubdir - struktura, którą chcemy zwolnić

Brak uwag dodatkowych

Deklaracja: int tlen_free_pubdir (struct tlen_pubdir *pubdir)


3.11. rate.c

Opis funkcji zawartych w pliku rate.c


3.12. roster.c

Opis funkcji zawartych w pliku roster.c


3.12.1. tlen_presence()

Pozwala na ustawienie swojego stanu dostępności

- sesja - nasza sesja
- status - stan w postaci TLEN_STATUS_*
- description - opcjonalny status opisowy, jeżeli NULL to ""

Brak uwag dodatkowych

Deklaracja: int tlen_presence (struct tlen_session *sesja, int status, const char *description)


3.12.2. tlen_presence_disconnect()

Funkcja wewnętrzna zamykająca połączenie z serwerem, wywoływana przez wysłanie statusu TLEN_STATUS_UNAVAILABLE

- sesja - nasza sesja

Nie używać w swoich programach, od tego jest tlen_presence()

Deklaracja: int tlen_presence_disconnect (struct tlen_session *sesja)


3.12.3. tlen_getroster()

Wysyła prośbę o ksiażkę adresową

- sesja - nasza sesja

brak uwag

Deklaracja: int tlen_getroster (struct tlen_session *sesja)


3.12.4. tlen_addcontact()

Dodaje użytkownika do książki adresowej

- sesja - nasza sesja
- name - nazwa użytkownika 
- jid - identyfikator użytkownika w @tlen.pl
- group - grupa dla użytkownika

Po dodaniu wypadałoby poprosić o subskrypcję przez

Deklaracja: int tlen_addcontact (struct tlen_session *sesja, const char *name,


3.12.5. tlen_removecontact()

Usuwa użytkownika z książki adresowej

- sesja - nasza sesja
- jid - identyfikator w @tlen.pl

Przed należy poprosić o desubskrypcję przez tlen_request_unsubscribe()

Deklaracja: int tlen_removecontact (struct tlen_session *sesja, const char *jid)


3.13. snprintf.c

Opis funkcji zawartych w pliku snprintf.c


3.14. sockets.c

Opis funkcji zawartych w pliku sockets.c


3.14.1. tlen_socket_create()

tworzy socket i laczy sie z serwerem

- address - adres IP serwera
- port - port na który się łączymy

zwraca gniazdo

Deklaracja: int tlen_socket_create (const char *address, int port)


3.14.2. tlen_socket_write()

pisze do gniazda

- sess - sesja, w której jest nasze gniazdo
- data - to co chcemy wysłać
- len - długość tego co chcemy wysłać

zwraca 0 w przypadku błędu lub 1 jak się powiedzie

Deklaracja: int tlen_socket_write (struct tlen_session *sess, const void *data, size_t len)


3.14.3. tlen_socket_write_string()

Pisze tekst do gniazda

- sess - sesja z gniazdem
- string - tekst do wyslania

Zwraca 0 w przypadku bledu, lub 1 jak operacja się powiodła

Deklaracja: int tlen_socket_write_string (struct tlen_session *sess, const void *string)


3.14.4. tlen_socket_destroy()

niszczy gniazdo

- sess - sesja w której jest gniazdo

Zwraca 1 jak się powiedzie, lub 0 w przypadku błędu

Deklaracja: int tlen_socket_destroy (struct tlen_session *sess)


3.15. str.c

Opis funkcji zawartych w pliku str.c


3.16. testclient.c

Opis funkcji zawartych w pliku testclient.c


3.17. utils.c

Opis funkcji zawartych w pliku utils.c


3.17.1. tlen_ping()

Wysyła pakiet kontrolny keep-alive do serwera

- sesja - identyfikator sesji

Ping powinien być wysyłany co około 60 sekund

Deklaracja: void tlen_ping(struct tlen_session *sesja)


3.17.2. tlen_encode()

Koduje tekst przy pomocy urlencode

- what - tekst który chcemy zakodować

Dla zwracanego tekstu alokowana jest pamięć, trzeba go

Deklaracja: char *tlen_encode (const char *what)


3.17.3. tlen_decode()

Dekoduje tekst przy pomocy urldecode

- what - tekst który chcemy rozkodować

Dla zwracanego tekstu alokowana jest pamięć, trzeba go

Deklaracja: char *tlen_decode(const char *what)


3.17.4. tlen_debug_raw()

Wyświetla na stderr tekst pomocniczy przy debugowaniu

- name - nazwa funkcji z której debug został wywołany
- format - format tekstu do wyświetlenia
- ... - wyświetlany tekst(y)

Funkcja wewnętrzna, należy używać wrappera tlen_debug(),

Deklaracja: void tlen_debug_raw(const char *name, char *format, ...) {


3.17.5. tlen_stripresource()

Usuwa z podanego tekstu wszystko co po znaku /

- jid - tekst z którego ma zostać usuniety "resource"

Używane dla identyfikatorów jabbera dla przychodzących

Deklaracja: int tlen_stripresource (char *jid)


3.17.6. tlen_base64_encode()

Funkcja kodująca tekst przy użyciu base64

- buf - tekst do zakodowania

Wartość zwracana jest alokowana, należy zwolnić przez free()

Deklaracja: char *tlen_base64_encode(const char *buf)


3.17.7. tlen_base64_decode()

Funkcja dekodująca tekst przy użyciu base64

- buf - tekst do zdekodowania

Wartość zwracana jest alokowana, należy zwolnić przez free()

Deklaracja: char *tlen_base64_decode(const char *buf)


3.18. xmlnode.c

Opis funkcji zawartych w pliku xmlnode.c


3.19. xmlparse.c

Opis funkcji zawartych w pliku xmlparse.c


3.20. xmlrole.c

Opis funkcji zawartych w pliku xmlrole.c


3.21. xmltok.c

Opis funkcji zawartych w pliku xmltok.c


3.22. xmltok_impl.c

Opis funkcji zawartych w pliku xmltok_impl.c


3.23. xmltok_ns.c

Opis funkcji zawartych w pliku xmltok_ns.c


Rozdział 4. Omówienie programów przykładowych

Automatycznie wygenerowane na podstawie kodu źródłowego omówienie programów przykładowych libtlen


4.1. examples/sendmsg.c

Omówienie programu examples/sendmsg.c

Po więcej informacji zajżyj do rozdziału o lib/testclient.c, gdyż podstawa dokumentacji na nim się opiera.

 
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <signal.h>

Inkludujemy nagłówek libtlen


#include "libtlen.h"

int main (int argc, char **argv)
{

Deklarujemy strukturę sesji

 
struct tlen_session *sesja;
struct tlen_event *event;
struct timeval tv;

tlen_setdebug(0);

if (argc==5) { 

Inicjujemy sesję

    sesja = tlen_init();

Ustawiamy użytkownika i hasło z parametru programu

    tlen_set_auth(sesja,argv[1],argv[2]);

Łączenie z hubem ma przebiegać jako nieblokowalne

    tlen_set_hub_blocking(sesja,0);

Okej, łączymy

    tlen_login(sesja);
} else {
            printf("Usage: %s login password user message\n",argv[0]);
            return 1;
        }

// tutaj jest obserwowany socket
while ((!sesja->error))
{
fd_set rd, wr;
int retval;

tv.tv_sec = 60;
tv.tv_usec = 0;

FD_ZERO (&rd);
FD_ZERO (&wr);

Ustawiamy opcje monitorowania deskryptorów


if ((sesja->check & TLEN_CHECK_READ))
FD_SET (sesja->fd, &rd);
if ((sesja->check & TLEN_CHECK_WRITE))
FD_SET (sesja->fd, &wr);

if ((retval = select (sesja->fd + 1, &rd, &wr, NULL, &tv) == -1))
{
perror ("select");
}
else if (sesja && (FD_ISSET (sesja->fd, &rd) || FD_ISSET (sesja->fd, &wr)))
{

Sprawdzamy co się zmieniło na gnieździe

tlen_watch_fd (sesja);

Pętla obsługi zdarzeń

while ((event=tlen_getevent(sesja))!=NULL) {
switch (event->type)
{

Połączony! Pobieramy id.

case TLEN_EVENT_NOWGETID:
{
tlen_getid(sesja);
break;
}

Logujemy się

case TLEN_EVENT_GOTID:
{
tlen_authorize(sesja);
break;
}

Udało się - pobieramy książkę adresową

case TLEN_EVENT_AUTHORIZED:
{
tlen_getroster(sesja);
break;
}

Ups - coś nie wyszło. Wychodzimy

case TLEN_EVENT_UNAUTHORIZED:
{
exit(0);
break;
}

Książka adresowa się odebrała (nie obsługujemy poszczególnych elementów, bo nie ma po co. Możemy więc wysłać wiadomość (TLEN_MESSAGE, nie TLEN_CHAT), a następnie się rozłączyć

case TLEN_EVENT_ENDROSTER:
{
tlen_sendmsg(sesja,argv[3],argv[4],TLEN_MESSAGE);
tlen_presence_disconnect (sesja);
tlen_freesession (sesja);
break;
}

}

Zwalniamy zdarzenie

tlen_freeevent(event);
}
}
return 0;
}


4.2. lib/testclient.c

Omówienie programu lib/testclient.c

Ostatnia aktualizacja: - $Id: libtlen.html,v 1.25 2003/04/04 19:14:19 mati Exp $


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <signal.h>

Dołączamy nagłówek libtlen.h w którym zawarte są wszystkie informacje o zdarzeniach, funkcjach, strukturach itp. Bez tego ani rusz!


#include "libtlen.h"

Zmienna służąca do zamknięcia klienta - obsługiwana w handlerze dla wciśnięcia CTRL+C


int terminate=0;

Zmienna klienta informująca kiedy był ostatni ping do serwera - w tym przypadku potrzebna, żeby pingać tylko co 60 sekund.


int last_ping_time;

Wewnętrzny handler klienta ustawiający zmienną na 1 - wywoływany podczas CTRL+C


void termhandler(int sig)
{
    terminate=1;
}

Głowna funkcja programu - tutaj będzie miąchanie z tlenem


int main (int argc, char **argv)
{

Definiujemy strukturę typu tlen_session opisującą wszystko co z naszym tlenowym połączeniem związane. Przechowuje ona gniazda, zdarzenia i inne potrzebne rzeczy


struct tlen_session *sesja;

Struktura typu tlen_event służy do przechowywania informacji o zdarzeniach - do niej będą pobierane zdarzenia w głównej pętli tlenowej.


struct tlen_event *event;

Struktura nie związana z libtlen - potrzebna przy takim a nie innym rozwiązaniu monitorowania gniazda - określa timeout.


struct timeval tv;

Łączymy SIGINT (Ctrl+C) z naszym handlerem (termhandler), pozwoli to na poprawne zamknięcie połączenia - tzn. jego obsłużenie, zamiast twardego wyjścia z programu


signal(SIGINT,termhandler);

Funkcja biblioteki, pozwalająca na sterowanie informacjami dodatkowymi (debug). Ustawiając jej parametr 1 włączamy debugowanie, od tej pory biblioteka będzie wypluwała na stderr wszystkie informacje pomocnicze.


tlen_setdebug(1);

Sprawdzamy, czy liczba parametrów przekazanych do programu jest równa 2 - użytkownik i hasło (+1, gdyż pierwszym z nich jest sama nazwa programu, której my nie przekazujemy).


if (argc==3) { 

Inicjujemy sesję przy użyciu funkcji tlen_init()


sesja = tlen_init();

Przy użyciu funkcji tlen_set_auth() przekazujemy do biblioteki nazwę użytkownika i hasło


tlen_set_auth(sesja,argv[1],argv[2]);

Funkcja tlen_set_hub_blocking() ustawia, czy proces łączenia z HUBem ma być synchroniczny, czy asynchroniczny (blokowalny/nieblokowalny) - ustawiamy asynchroniczność.


tlen_set_hub_blocking(sesja,0);

tlen_login() inicjuje połączenie z serwerem Tlenu. Najpierw łączy się z hubem, następnie pobiera adres serwera i się z nim łączy. Pobranie ID oraz autoryzacja następują automagicznie.


tlen_login(sesja);
} else {
printf("Usage: %s login password\n",argv[0]);
return 1;
        }

Punkt kulminacyjny klienta - główna pętla obsługi zdarzeń


while ((!terminate)&&(!sesja->error))
{

zmienne potrzebne do poprawnego sterowania obserwacją gniazda


fd_set rd, wr;
int retval;

Ustawiamy timeout dla serwera na 60 sekund


tv.tv_sec = 60;
tv.tv_usec = 0;

Zerujemy deskryptory


FD_ZERO (&rd);
FD_ZERO (&wr);

Wchodzi kawałek obsługi biblioteki - jeżeli libtlen prosi nas o monitorowanie kanału przychodzącego, to ustawiamy RD, zaś jeżeli kanału wychodzącego to WR. Kanał wychodzący przede wszystkim sprawdza, czy gniazdo nadaje się już do zapisy, czyli czy jesteśmy już połączeni


if ((sesja->check & TLEN_CHECK_READ))
FD_SET (sesja->fd, &rd);
if ((sesja->check & TLEN_CHECK_WRITE))
FD_SET (sesja->fd, &wr);

Funkcja select - systemowa, nie związana z biblioteką, obserwuje deskryptor połączenia z serwerem - gniazdo znajduje się w strukturze sesji - jako sesja->fd


if ((retval = select (sesja->fd + 1, &rd, &wr, NULL, &tv) == -1))
{
perror ("select");
terminate = 1;
}

Znaleziono coś w gnieździe! Obsługujemy zdarzenia.


else if (sesja && (FD_ISSET (sesja->fd, &rd) || FD_ISSET (sesja->fd, &wr)))
{

Funkcja biblioteki - tlen_watch_fd() - sprawdza, co się zmieniło na gnieździe, odczytuje dane, a następnie uzupełnia zdarzenia, które dalej będziemy obsługiwać.


tlen_watch_fd (sesja);

W pętli pobieramy zdarzenia poprzez tlen_getevent do struktury typu tlen_event (którą zadeklarowaliśmy na początku programu). Pętla obsługi zdarzeń wykonuje się tak długo, aż wszystkie czekające zdarzenia zostaną obsłużone


while ((event=tlen_getevent(sesja))!=NULL) {

Przełącznikiem switch sprawdzamy typ zdarzenia


switch (event->type)
{

Dostaliśmy informację, że logowanie się powiodło, możemy więc pobrać z serwera książkę adresową - funkcja tlen_getroster()

case TLEN_EVENT_AUTHORIZED:
{
tlen_getroster(sesja);
break;
}

Po wywołaniu tlen_getroster będziemy po kolei dostawać zdarzenia typu TLEN_EVENT_GOTROSTERITEM informujące o pobraniu danych jednego użytkownika. W tym programie wypisujemy je jedynie na ekran. Dane użytkownika zawarte są w strukturze typu tlen_user. Przy każdym zdarzeniu, w którym otrzymujemy jakieś dane, do struktury tlen_event dodawana jest struktura danego zdarzenia - w tym wypadku książki adresowej.

case TLEN_EVENT_GOTROSTERITEM:
{
printf("Got user: %s\n",event->roster->jid);
break;
}

Otrzymaliśmy całą książkę adresową - informuje o tym zdarzenie ENDROSTER. Skoro tak, to powinnismy wysłać informację o swojej dostępności. Służy do tego funkcja tlen_presence pobierająca informacje o stanie - TLEN_STATUS_* oraz nasz status opisowy - jeżeli żaden wstawiamy "" lub NULL.

case TLEN_EVENT_ENDROSTER:
{
printf("Roster received\n");
tlen_presence(sesja,TLEN_STATUS_AVAILABLE,"Dostępny");
break;
}

Jednym z najtrudniejszych elementów protokołu tlenu/jabbera są subskrybcje. Jest to system pozwalający na kontrolę naszej znajomości. Generalnie - nikt nie będzie widział naszego stanu, jeżeli nie wyrazimy na to zgody, tak samo nikt nie doda nas do książki adresowej jeżeli nie wyrazimy na to zgody. Zdarzenie TLEN_EVENT_SUBSCRIBE mówi nam, że ktoś prosi o zgodę na autoryzację. Identyfikator danej osoby znajduje się w polu event->subscribe->jid. Jeżeli zgadzamy się - tutaj zawsze się zgadzamy, nie jest zaimplementowana obsługa niezgadzania sie ;) - to akceptujemy prośbę funkcją tlen_accept_subscribe, no i żeby być fair prosimy użytkownika o subskrybcję, żeby też mieć go w książce - tlen_request_subscribe.

case TLEN_EVENT_SUBSCRIBE:
{
tlen_accept_subscribe(sesja,event->subscribe->jid);
tlen_request_subscribe(sesja,event->subscribe->jid);
break;
}

"Ktoś" zgodził się abyśmy go dodali do swojej książki - a więc to robimy, funkcja tlen_addcontact.

case TLEN_EVENT_SUBSCRIBED:
{
tlen_addcontact(sesja,"nazwa",event->subscribe->jid,"grupa");
break;
}

BUU - ktoś chce nas usunąć ze swojej książki - więć prosi abyśmy my również go usuęli - zgadzamy się na to poprzez tlen_accept_unsubscribe, i żeby dobić wszystkich formalności prosimy o to samo - tlen_request_unsubscribe.

case TLEN_EVENT_UNSUBSCRIBE:
{
tlen_accept_unsubscribe(sesja,event->subscribe->jid);
tlen_request_unsubscribe(sesja,event->subscribe->jid);
break;
}

"Ktoś" nas właśnie pomyślnie usunął, więc my też usuwamy - tlen_removecontact

case TLEN_EVENT_UNSUBSCRIBED:
{
tlen_removecontact(sesja,event->subscribe->jid);
break;
}

Oho - przyszła wiadomość! Dane wiadomości są w strukturze event->message, podstawowymi są body - treść, oraz from - od kogo, a na szarym końcu type - typ (TLEN_CHAT albo TLEN_MESSAGE). Nasz prosty klient obsługuje wiadomości w sposób bardzo prowizoryczny, np. zmienia stan, odpowiada pingiem, i inne takie pierdoły. Generalnie nie pojawia się tu na razie nic ważnego - do czasu...

case TLEN_EVENT_MESSAGE:
{
                                                if (strcmp(event->message->body,"exit")==0) 
{ 
    terminate=1;
    tlen_sendmsg(sesja,event->message->from,"exiting...",TLEN_CHAT);
}
if (strcmp(event->message->body,"available")==0) { tlen_presence(sesja,TLEN_STATUS_AVAILABLE,"available"); tlen_sendmsg(sesja,event->message->from,"status changed to available", TLEN_CHAT); }
if (strcmp(event->message->body,"away")==0) { tlen_presence(sesja,TLEN_STATUS_AWAY,"away"); tlen_sendmsg(sesja,event->message->from,"status changed to away", TLEN_CHAT); }
if (strcmp(event->message->body,"chatty")==0) { tlen_presence(sesja,TLEN_STATUS_CHATTY,"away"); tlen_sendmsg(sesja,event->message->from,"status changed to chatty", TLEN_CHAT); }
if (strcmp(event->message->body,"xa")==0) { tlen_presence(sesja,TLEN_STATUS_EXT_AWAY,"away"); tlen_sendmsg(sesja,event->message->from,"status changed to xa", TLEN_CHAT); }
if (strcmp(event->message->body,"dnd")==0) { tlen_presence(sesja,TLEN_STATUS_DND,"away"); tlen_sendmsg(sesja,event->message->from,"status changed to dnd", TLEN_CHAT); }
if (strcmp(event->message->body,"invisible")==0) { tlen_presence(sesja,TLEN_STATUS_INVISIBLE,"away"); tlen_sendmsg(sesja,event->message->from,"status changed to invisible", TLEN_CHAT); }
if (strcmp(event->message->body,"ping")==0) { tlen_sendmsg(sesja,event->message->from,"pong", TLEN_CHAT); }

Jeżeli wyślemy klientowi wiadomość pubdir, wyśle on prośbę o swoje dane z katalogu publicznego - tlen_get_pubdir()

if (strcmp(event->message->body,"pubdir")==0) { tlen_get_pubdir(sesja); }
if (strcmp(event->message->body,"groupchat")==0) { tlen_groupchat_init(sesja,event->message->from); }

Jeżeli wyślemy do testclienta wiadomość o treści search, klient rozpocznie proces wyszukiwania w katalogu publicznym. W tym celu inicjowana jest struktura tlen_pubdir, przy użyciu funkcji tlen_new_pubdir(), a następnie wypełniane są jej pola. Tutaj akutat wykonujemy odpowiednik windowsowej "wizytówki" - tzn. wyszukujemy po identyfikatorze tlenu. Gdy wyślemy zamówienie poprzez tlen_search, zwalniamy strukturę funkcją tlen_free_pubdir().

if (strcmp(event->message->body,"search")==0)
{
    struct tlen_pubdir *sercz = tlen_new_pubdir();
    sercz->id = "matijozef"; // tutaj sobie wpiszcie jaki wam sie podoba
    tlen_search(sesja,sercz);
    tlen_free_pubdir(sercz);
}

Analogicznie - tutaj obsługiwana jest prośba o zmianę naszych danych w katalogu. Również inicjujemy strukturę tlen_pubdir, uzupełniamy jej pola, a następnie funkcją tlen_change_pubdir wysyłamy do serwera nowe dane. Na koniec zwalniamy strukturę poprzez tlen_free_pubdir()

if (strcmp(event->message->body,"pubdir_change")==0)
{
    struct tlen_pubdir *pub = tlen_new_pubdir();
    pub->firstname = "matijozef"; // tutaj sobie wpiszcie jaki wam sie podoba
    pub->lastname = "krzysztoffelix"; 
    tlen_change_pubdir(sesja,pub);
    tlen_free_pubdir(pub);
}
    
break;
}

Ktoś zmienił stan - np. na niedostępny, zajęty, lub zmienił stan opisowy Aktualnie nie jest to u nas obsługiwane :) Dane oczywiście zawarte są w event->presence.

case TLEN_EVENT_PRESENCE:
{

break;
}

Zintegrowany system kont na o2.pl / tlen.pl jest połączony z serwerem tlenu. Tak więc możemy otrzymać informację o nowej poczcie - tutaj właśnie tak się dzieje. Informacje o tym są wysyłane na ekran - dane zaś znajdziemy w polu event->newmail

case TLEN_EVENT_NEWMAIL:
{
printf("Masz nową pocztę od %s o temacie %s!\n",event->newmail->from, event->newmail->subject);
break;
}

Na razie jeszcze nie mamy w testcliencie obsługi wyszukiwania, więć program poinformuje nas jedynie o tym, że wyszukiwanie skończył. Obsługa jednak jest analogiczna do książki adresowej - GOTSEARCHITEM a na końcu ENDSEARCH.

case TLEN_EVENT_ENDSEARCH:
{
printf("Wyszukiwanie zakończone!\n");
break;
}

Serwer tlenu pomyślnie zwrócił nam swoje dane, znajdziemy je w event->pubdir.

case TLEN_EVENT_PUBDIR_GOTDATA:
{
printf("Odebralem swoje dane!\n");
break;
}

"Pusty" event. Dostajemy informacje o tym, że nasze dane się ładnie zmieniły.

case TLEN_EVENT_PUBDIR_GOTUPDATEOK:
{
printf("Zmienilem swoje dane!\n");
break;
}

}
tlen_freeevent(event);
}

Co 60 sekund musimy pingać, zapewnia nam to prosty trick z funkcją time.

if (time(NULL)-last_ping_time>60) { tlen_ping (sesja); last_ping_time = time(NULL); }
}

obsluga m.in bledu autoryzacji

        if(sesja->error)
        {
                printf("Error occured while talking to server!\n");
                exit(1);
        }

Jeżeli dostaliśmy CTRL+C to wychodzimy i zamykamy połączenie z serwerem.

if (terminate) printf("SIGINT received, exiting...\n");

Wysyłamy zamknięcie połączenia poprzez stan TLEN_STATUS_UNAVAILABLE.

tlen_presence(sesja, TLEN_STATUS_UNAVAILABLE, "");

A na koniec zwalniamy pamięć po sesji.

tlen_freesession (sesja);
return 0;
}