/**

\defgroup events Obsługa zdarzeń
\ingroup session

\details

Funkcje biblioteki (za wyjątkiem \ref dcc "połączeń bezpośrednich") zostały
przygotowane w taki sposób, by móc z nich korzystać zarówno w trybie
synchronicznym (działanie programu jest blokowane do zakończeniu operacji), jak
i asynchroniczym (operacja jest rozpoczynana, a do czasu jej zakończenia
program może robić inne rzeczy).

W trybie synchronicznym, po udanym zakończeniu funkcji \c gg_login(), należy
w pętli wywoływać funkcję \c gg_watch_fd(), która po odebraniu informacji od
serwera zwróci informację o zdarzeniu w strukturze \c gg_event lub \c NULL 
w przypadku błędu. Lista zdarzeń znajduje się poniżej.

Tryb asynchroniczny wymaga od programu obserwowania zmian na określonych
deskryptorach za pomocą funkcji systemowych \c select() czy \c poll(), lub za 
pomocą mechanizmów pętli zdarzeń wbudowanych w wykorzystaną bibliotekę
interfejsu użytkownika. Struktura połączenia asynchronicznego zawiera
pole \c fd określające obserwowany deskryptor, pole \c watch będące maską
bitową mówiącą czy obserwowana ma być możliwość odczytu i/lub zapisu,
\c timeout określające maksymalny czas wykonywania operacji. Gdy zaobserwuje
się zmianę na deskryptorze należy wywołać funkcję \c gg_watch_fd() i postępować
podobnie jak w trybie synchronicznym.

\section sync-example Przykład połączenia synchronicznego

\code
struct gg_session *sesja;
struct gg_login_params parametry;
struct gg_event *zdarzenie;

memset(&parametry, 0, sizeof(parametry));
parametry.uin = 12345;
parametry.password = "hasło";

sesja = gg_login(&parametry);

if (!sesja) {
    błąd("Nie można się połączyć");
    exit(1);
}

informacja("Połączono");

gg_send_message(sesja, 23456, "Cześć!");

while ((zdarzenie = gg_watch_fd(sesja))) {
    switch (zdarzenie->type) {
        // ...
    }

    gg_event_free(zdarzenie);
}

gg_logoff(sesja);
gg_free_session(sesja);
\endcode

\note Przykład jest niekompletny, ponieważ powinien wysłać listę kontaktów
i co minutę wywoływać funkcję \c gg_ping().

\section sync-example Przykład połączenia asynchronicznego

\code
struct gg_session *sesja;
struct gg_login_params parametry;
struct timeval tv;
fd_set rd, wd;
int wynik;

memset(&parametry, 0, sizeof(parametry));
parametry.uin = 12345;
parametry.password = "hasło";
parametry.async = 1;

sesja = gg_login(&parametry);

if (!sesja) {
    błąd("Nie można się połączyć");
    exit(1);
}

for (;;) {
    FD_ZERO(&rd);
    FD_ZERO(&wd);

    if ((sesja->check & GG_CHECK_READ))
        FD_SET(sesja->fd, &rd);

    if ((sesja->check & GG_CHECK_WRITE))
        FD_SET(sesja->fd, &wd);

    if (sesja->timeout) {
        tv.tv_sec = sesja->timeout;
        tv.tv_usec = 0;
    }

    wynik = select(sesja->fd + 1, &rd, &wd, NULL, (sesja->timeout) ? &tv : NULL);

    if (!wynik) {
        błąd("Przekroczono czas operacji");
	gg_free_session(sesja);
	exit(1);
    }

    if (wynik == -1) {
        if (errno != EINTR) {
	    błąd("Błąd funkcji select()");
	    gg_free_session(sesja);
	    exit(1);
	}
    }

    if (FD_ISSET(sesja->fd, &rd) || FD_ISSET(sesja->fd, &wd)) {
        struct gg_event *zdarzenie;

	zdarzenie = gg_watch_fd(sesja);

	if (!zdarzenie) {
	    błąd("Połączenie przerwane");
	    gg_free_session(sesja);
	    exit(1);
	}

	switch (zdarzenie->type) {
	    case GG_EVENT_CONN_SUCCESS:
	        informacja("Połączono");
		break;
	    case GG_EVENT_CONN_FAILED:
	        błąd("Nie można się połączyć");
		gg_event_free(zdarzenie);
		gg_free_session(sesja);
		exit(1);
	    // ...
	}

	gg_event_free(zdarzenie);
    }
}
\endcode

\note Przykład jest niekompletny, ponieważ powinien wysłać listę kontaktów
i co minutę wywoływać funkcję \c gg_ping().

\section Zdarzenia

 - \c GG_EVENT_NONE
 - \c GG_EVENT_CONN_FAILED
 - \c GG_EVENT_CONN_SUCCESS

 - \c GG_EVENT_MSG

 - \c GG_EVENT_NOTIFY_DESCR
 - \c GG_EVENT_NOTIFY
 - \c GG_EVENT_STATUS
 - \c GG_EVENT_NOTIFY60
 - \c GG_EVENT_STATUS60
 - \c GG_EVENT_ACK
 - \c GG_EVENT_MSG_ACK
 - \c GG_EVENT_PONG
 - \c GG_EVENT_DISCONNECT
 - \c GG_EVENT_XML_EVENT
 - \c GG_EVENT_USERLIST
 - \c GG_EVENT_IMAGE_REPLY
 - \c GG_EVENT_IMAGE_REQUEST


 - \c GG_EVENT_

*/
