#ifndef GADU_H
#define GADU_H

#include <qhostaddress.h>
#include <qvaluelist.h>

#include "libgadu.h"
#include "protocol.h"
#include "status.h"
#include "usergroup.h"
#include "userlist.h"

typedef uin_t UinType;

class QTimer;
class GaduSocketNotifiers;

// ------------------------------------
//            UinsList
// ------------------------------------

class UinsList : public QValueList<UinType>
{
	public:
		/**
			konstruuje obiekt UinsList
		**/
		UinsList();

		/**
			konstruuje obiekt UinsList, inicjując go uinem
		**/
		UinsList(UinType uin);

		/**
			konstruuje obiekt UinsList na podstawie łańcucha "uins" składającego
			się z oddzielonych przecinkami Uinów
		**/
		UinsList(const QString &uins);

		/**
			konstruuje obiekt UinsList na podstawie "list"
			przekształacając każdy element do typy UinType
		**/
		UinsList(const QStringList &list);

		bool equals(const UinsList &uins) const;
		void sort();
		QStringList toStringList() const;
};

// ------------------------------------
//             UserStatus
// ------------------------------------

class GaduStatus : public UserStatus
{
//	Q_OBJECT

	public:
		GaduStatus();
		virtual ~GaduStatus();

		GaduStatus &operator = (const UserStatus &copyMe);

		virtual QPixmap pixmap(eUserStatus status, bool has_desc, bool mobile) const;
		virtual QString pixmapName(eUserStatus status, bool has_desc, bool mobile) const;

		int toStatusNumber() const;
		static int toStatusNumber(eUserStatus status, bool has_desc);

		void fromStatusNumber(int statusNumber, const QString &description);

		virtual UserStatus *copy() const;
		virtual QString protocolName() const;
};

// ------------------------------------
//              Search
// ------------------------------------

struct SearchResult
{
	QString Uin;
	QString First;
	QString Last;
	QString Nick;
	QString Born;
	QString City;
	QString FamilyName;
	QString FamilyCity;
	int Gender;
	GaduStatus Stat;

	SearchResult();
	SearchResult(const SearchResult &);
	void setData(const char *uin, const char *first, const char *last, const char *nick, const char *born,
		const char *city, const char *familyName, const char *familyCity, const char *gender, const char *status);
};

typedef QValueList<SearchResult> SearchResults;

struct SearchRecord
{
	int Seq;
	int FromUin;
	QString Uin;
	QString FirstName;
	QString LastName;
	QString NickName;
	QString City;
	QString BirthYearFrom;
	QString BirthYearTo;
	int Gender;
	bool Active;
	bool IgnoreResults;

	SearchRecord();
	virtual ~SearchRecord();

	void reqUin(const QString& uin);
	void reqFirstName(const QString& firstName);
	void reqLastName(const QString& lastName);
	void reqNickName(const QString& nickName);
	void reqCity(const QString& city);
	void reqBirthYear(const QString& birthYearFrom, const QString& birthYearTo);
	void reqGender(bool female);
	void reqActive();

	void clearData();
};


enum GaduError
{
	ConnectionServerNotFound,
	ConnectionCannotConnect,
	ConnectionNeedEmail,
	ConnectionInvalidData,
	ConnectionCannotRead,
	ConnectionCannotWrite,
	ConnectionIncorrectPassword,
	ConnectionTlsError,
	ConnectionIntruderError,
	ConnectionUnavailableError,
	ConnectionUnknow,
	ConnectionTimeout,
	Disconnected
};

// ------------------------------------
//			GaduFormater
// ------------------------------------
class GaduFormater
{
	private:
		struct attrib_formant
		{
			QString name;
			QString value;
			attrib_formant() : name(), value() {}
		};

		struct richtext_formant
		{
			struct gg_msg_richtext_format format;
			struct gg_msg_richtext_color color;
			struct gg_msg_richtext_image image;
		};

		static QString stripHTMLFromGGMessage(const QString &msg);

		/**
		 * Translates QValueList with formants into flat buffer on heap
		 *
		 * Precondition - formats_length must contain valid length of result buffer
		 */
		static unsigned char *allocFormantBuffer(const QValueList<struct richtext_formant> &formants, unsigned int &formats_length);

	public:
		static QString formatGGMessage(const QString &msg, unsigned int formats_length, void *formats, UinType sender);
		static QString unformatGGMessage(const QString &msg, unsigned int &formats_length, unsigned char *&formats);
};

// ------------------------------------
//            GaduProtocol
// ------------------------------------

/**
	Klasa do obsługi protokołu Gadu-Gadu
**/
class GaduProtocol : public Protocol
{
	Q_OBJECT

	private:

		/**
			@enum Mode
			@short Tryb pracy obiektu
			@see TokenSocketNotifiers
			@see gotToken
			@see needTokenValue
			@see register
			@see doRegister
			@see unregister
			@see doUnregister
			@see remindPassword
			@see doRemindPassword
			@see changePassword
			@see doChangePassword

			Kilka operacji w protokole Gadu-Gadu wymaga od klienta wysłania do serwera, oprócz
			standardowych pakietów, tak zwanego 'tokena'. Najpierw pobierany jest z serwera identyfikator
			tokena oraz obrazek. Następnie z obrazka odczytywana jest wartośc tokena (w założeniach
			miało to zapobiegać rejestrowaniu nowych użytkowników przez automaty.

			Sloty register, unregister, remindPassword i changePassword inicjują pobieranie tokena
			i ustalają wartość pola Mode. Pobieranie obrazka realizowane jest przez klasę
			TokenSocketNotifiers. Po pobraniu wywoływany jest slot gotToken, który na podstawie wartości
			pola Mode wywołuje jedną z funkcji doRegister, doUnregister, doRemindPassword i doChangePassword.
		**/
		enum
		{
			/** Rejestrowanie nowego użytkownika **/
			Register,
			/** Wyrejestrowywanie istniejącego użytkownika **/
			Unregister,
			/** Przypominanie hasła **/
			RemindPassword,
			/** Zmienianie hasła **/
			ChangePassword
		} Mode;

		/** Identyfikator użytkownika **/
		UinType DataUin;
		/** e-mail użytkownika **/
		QString DataEmail;
		/** stare hasło użytkownika **/
		QString DataPassword;
		/** nowe hasło użytkownika **/
		QString DataNewPassword;
		/** identyfikator tokena **/
		QString TokenId;
		/** wartość tokena **/
		QString TokenValue;

		/** Serwery, z którymi łaczy się obiekt. **/
		static QValueList<QHostAddress> ConfigServers;
		/** Numer serwera, do którego obiekt ostatnio próbował się podłączyć. **/
		unsigned int ServerNr;
		/** Adres serwera, do którego obiekt jest podłączony. **/
		QHostAddress ActiveServer;

		/** IP serwera, do którego udało się podłączyć ostatnim razem **/
		QHostAddress lastServerIP;

		/** port serwera, do którego udało się podłączyć ostatnim razem **/
		int lastServerPort;

		/** czy w procedurze łączenia mamy korzystać z informacji o IP/portu ostatniego serwera? **/
		bool useLastServer;

		int lastTriedServerPort;

		/** Parametry logowania - wymagane przez bibliotekę libgadu **/
		struct gg_login_params LoginParams;

		/** Sesja połączenia - wymagane przez bibliotekę libgadu **/
		gg_session* Sess;

		/** liczba żądań obrazków wysłanych w ciągu ostatniej minuty**/
		unsigned int sendImageRequests;

		/** numer sekwencyjny ostatnio wysłanej wiadomości **/
		int seqNumber;

		/** czy jesteśmy w trakcie łączenia się z serwerem **/
		bool whileConnecting;

		QHostAddress DccExternalIP;

		/**
			Klasa gniazdek łącząca się z serwerem. Wysyła sygnały po wystąpieniu zdarzenia protokołu
			(połączenie, zerwanie połączenia, nowa wiadomość).

			@see GaduSocketNotifiers
		**/
		GaduSocketNotifiers *SocketNotifiers;

		/**
			Zegar pingujący serwer.
		**/
		QTimer* PingTimer;

		QTimer* SendUserListTimer;

		/**
			Zmienna ustawiana w zależności od tego, czy wysyłamy listę kontaktów na serwer
			czy też usuwamy ją z tego serwera. Zakończenie obydwu tych czynności wywołuje
			sygnał podpięty do slotu userListReplyReceived, który w zależności od wartości
			tego pola wywołuje userListCleared albo userListExported.

			@see userListReplyReceived
			@see userListCleared
			@see userListExported
		**/
		bool UserListClear;

		/**
			Lista użytkowników pobrana z serwera w postaci łańcucha. Wartość ustalana w slocie
			userListReplyReceived.

			@see userListReplyReceived
		**/
		QString ImportReply;

		/**
			Ustawianie parametrów połączenia proxy. Metoda wywoływana podczas logowania.

			@see login
		**/
		void setupProxy();

		/**
			Za pomocą klasy TokenSocketNotifiers metoda pobiera z serwera GaduGadu token wraz
			z identyfikatorem. Pobrany token jest obsługiwany za pomocą slota gotToken,
			który pobiera wartość tokena emitując sygnał needTokenValue i następnie wywołując
			jedną z metod  doRegisterAccount, doUnregisterAccount(), doRemindPassword(),
			doChangePassword() na podstawie wartości pola Mode.

			@see TokenSocketNotifiers
			@see gotToken
			@see doRegisterAccount
			@see doUnregisterAccount
			@see doRemindPassword
			@see doChangePassword
			@see Mode
		**/
		void getToken();

		/**
			Rejestruje nowe konto. Wywoływane przez gotToken (które jest wywołane pośrednio przez
			registerAccount). Korzysta z pomocy PubdirSocketNotifiers oraz slotu registerDone,
			który emituje sygnał registered.

			@see registerAccount
			@see registered
			@see registerDone
			@see gotToken
		**/
		void doRegisterAccount();

		/**
			Wyrejestrowuje konto. Wywoływane przez gotToken (które jest wywołane pośrednio przez
			unregisterAccount). Korzysta z pomocy PubdirSocketNotifiers oraz slotu unregisterDone,
			który emituje sygnał unregistered.

			@see unregisterAccount
			@see unregistered
			@see unregisterDone
			@see gotToken
		**/
		void doUnregisterAccount();

		/**
			Przypomina hasło. Wywoływane przez gotToken (które jest wywołane pośrednio przez
			remindPassword). Korzysta z pomocy PubdirSocketNotifiers oraz slotu remindDone,
			który emituje sygnał reminded.

			@see remindPassword
			@see reminded
			@see remindDone
			@see gotToken
		**/
		void doRemindPassword();

		/**
			Zmienia hasło. Wywoływane przez gotToken (które jest wywołane pośrednio przez
			changePassword). Korzysta z pomocy PubdirSocketNotifiers oraz slotu changePasswordDone,
			który emituje sygnał passwordChanged.

			@see changePassword
			@see passwordChanged
			@see changePasswordDone
			@see gotToken
		**/
		void doChangePassword();

		GaduProtocol(const GaduProtocol &) : Protocol(QString::null, QString::null) {}
		GaduProtocol &operator=(const GaduProtocol &){return *this;}

	private slots:

		/**
			Loguje się do serwera Gadu-Gadu. Po uruchomieniu emituje sygnał connecting. Parametry
			logowania odczytuje z konfiguracji, status logowania pobiera z pola NextStatus.
			Łącząc się, wybiera kolejne serwery (w przypadku nieudanego połączenia) wykorzystując
			pola ConfigServers i i ServerNr.

			Po poprawnym zalogowaniu wywoływany jest slot connectedSlot, który emituje sygnał
			GaduProtocol::connected

			Metodę można uruchomić pośrednio poprzez wywołanie typu gadu->status().setOnline(),
			które wywoła slot iWantToGoOnline, który z kolei (gdy stwierdzi, że nie jesteśmy zalogowani)
			wywoła procedurę.

			@see connecting
			@see connected
			@see connectedSlot
			@see NextStatus
			@see ConfigServers
			@see ServerNr
		**/
		void login();

		/**
			Wywoływany po zarejestrowaniu konta. Emituje registered/

			@see registerAccount
			@see doRegisterAccount
			@see registered
		**/
		void registerDone(bool ok, struct gg_http *);

		/**
			Wywoływany po wyrejestrowaniu konta. Emituje unregistered.

			@see unregisterAccount
			@see doUnregisterAccount
			@see unregistered
		**/
		void unregisterDone(bool ok, struct gg_http *);

		/**
			Wywoływany po przypomnieniu hasła. Emituje reminded.

			@see remindPassword
			@see doRemindPassword
			@see reminded
		**/
		void remindDone(bool ok, struct gg_http *);

		/**
			Wywoływany po zmianie hasła. Emituje passwordChanged.

			@see changePassword
			@see doChangePassword
			@see passwordChanged
		**/
		void changePasswordDone(bool ok, struct gg_http *);

		/**
			Slot wywoływany, gdy pobieranie tokena się nie udało.

			@see getToken
		**/
		void tokenError();
		/**
			Slot wywoływany, gdy pobieranie tokena się powiodło. Emituje needTokenValue

			@see getToken
			@see needTokenValue
		**/
		void gotToken(QString, QPixmap);

		/**
			Slot wywoływany po połączeniu z serwerem. Emituje connected i włącza pingowanie
			serwera.

			@see connected
		**/
		void connectedSlot();

		/**
			Slot wywoływany po rozłączeniu z serwerem. Emituje disconnected i wyłącza pingowanie
			serwera.

			@see disconnected
		**/
		void disconnectedSlot();

		/**
			Slot wywoływany po zerwaniu połączenia przez serwer. Wywołuje disconnectedSlot(),
			oraz dodatkowo zmienia NextStatus.
		**/
		void socketDisconnectedSlot();


		/**
			Slot wywoływany po przekroczeniu czasu połączenia. Próbuje połaczyć ponownie.
		**/
		void connectionTimeoutTimerSlot();

		/**
			Slot wywoływane po wystąpieniu błędu połączenia. Emituje disconnected i error.

			@see error
			@see disconnected
		**/
		void errorSlot(GaduError);

		/**
			Slot wywoływany po otrzymaniu obrazka od serwera. Emituje imageReceivedAndSaved

			@see imageReceivedAndSaved
		**/
		void imageReceived(UinType sender, uint32_t size, uint32_t crc32,
			const QString &filename, const char *data);

		/**
			Slot wywoływany po otrzymaniu prośby o obrazek od serwera. Wysyła obrazek.
		**/
		void imageRequestReceivedSlot(UinType, uint32_t, uint32_t);

		/**
			Slot wywoływany po otrzymaniu wiadomości od serwera.
		**/
		void messageReceivedSlot(int, UserListElements, QCString& msg, time_t, QByteArray &formats);

		/**
			Wykonuje zadania co minutę - pinguje sieć i zeruje licznik
			odebranych obrazków (jeśli jesteśmy połączeni).
		**/
		void everyMinuteActions();

		/**
			Obsługuje otrzymanie nowych wyników wyszukiwania z serwera. Emituje newSearchResults.

			@see newSearchResults
		**/
		void newResults(gg_pubdir50_t res);

		/**
			Nowa wiadomość od serwera. Emituje systemMessageReceived

			@see systemMessageReceived
		**/
		void systemMessageReceived(QString &, QDateTime &, int, void *);

		/**
			Pobrano listę użytkowników z serwera. Emituje userStatusChanged dla każdego
			otrzymanego kontaktu oraz userListChanged przed zakończeniem działania.

			@see userStatusChanged
			@see userListChanged
		**/
		void userListReceived(const struct gg_event *);

		/**
			Odpowiedź od serwera na temat operacji na liście użytkowników. Emituje, w zależności
			od trybu działania: userListCleared, userListExported, userListImported.

			@see userListCleared
			@see userListExported
			@see userListImported
		**/
		void userListReplyReceived(char, char *);

		/**
			Informacja o zmianie statusu kontaktu. Emituje userStatusChanged oraz userListChanged.

			@see userStatusChanged
			@see userListChanged
		**/
		void userStatusChanged(const struct gg_event *);

		/**
			Ktoś wykonał gadu.status().setOnline(). Łączymy z serwerem, jeżeli jeszcze tego nie
			zrobiliśmy, i zmieniamy status.

			@see CurrentStatus
			@see NextStatus
			@see login
		**/
		void iWantGoOnline(const QString &);

		/**
			Ktoś wykonał gadu.status().setBusy(). Łączymy z serwerem, jeżeli jeszcze tego nie
			zrobiliśmy, i zmieniamy status.

			@see CurrentStatus
			@see NextStatus
			@see login
		**/
		void iWantGoBusy(const QString &);

		/**
			Ktoś wykonał gadu.status().setInvisible(). Łączymy z serwerem, jeżeli jeszcze tego nie
			zrobiliśmy, i zmieniamy status.

			@see CurrentStatus
			@see NextStatus
			@see login
		**/
		void iWantGoInvisible(const QString &);

		/**
			Ktoś wykonał gadu.status().setOffline(). Rozłączamy się z serwerem i ustawiamy opis (jeżeli
			byliśmy połączeni).

			@see CurrentStatus
			@see NextStatus
			@see logout
		**/
		void iWantGoOffline(const QString &);

		/**
			Przyszła informacja o dostarczeniu (lub nie) wiadomości.
			Na podstawie statusu emituje odpowiednie sygnały message*

			@see messageBlocked
			@see messageDelivered
			@see messageQueued
			@see messageBoxFull
			@see messageNotDelivered
			@see messageAccepted
			@see messageRejected
		**/
		void ackReceived(int seq, uin_t uin, int status);

		void currentStatusChanged(const UserStatus &status, const UserStatus &oldStatus);

	public:
		static void initModule();
		static void closeModule();

		GaduProtocol(const QString &id, QObject *parent = NULL, const char *name = NULL);
		virtual ~GaduProtocol();

		gg_session * session() { return Sess; }

		void changeID(const QString &id);
		/**
			Zwraca serwer z którym jesteśmy połączeni lub do którego się właśnie łączymy.
			isNull() = hub.
		**/
		QHostAddress activeServer();

		/**
			Konwertuje listę użytkowników do postaci łańcucha.

			Łańcuch wynikowy ma postać:
			<code>
				opis_użytkownika<CR><LF>
				opis_użytkownika<CR><LF>
				...
				opis_użytkownika<CR><LF>
			</code>

			opis_użytkownika ma postać:
			<code>
				firstName;lastName;nickName;altNick;mobile;grupy;uin;email;0;;0;
			</code>

			grupy mają postać:
			<code>
				grupa_1;grupa_2;grupa_3
			</code>

			@param userList lista użytkowników, która zostanie skonwertowana
			@return łańcuch reprezentujący listę użytkowników
			@see stringToUserList
			@see streamToUserList
		**/
		QString userListToString(const UserList &userList) const;

		/**
			Konwertuję łańcuch do listy użytkowników.

			Format łańcucha jest anologiczny do tego z funkcji userListToString.

			@param source łańuch, będący reprezentacją listy użytkowników
			@see userListToString
			@see streamToUserList
		**/
		QValueList<UserListElement> stringToUserList(const QString &source) const;

		/**
			Odczytuje ze strumienia łańcuch reprezentujący listę użytkowników i konwertuje
			go go postaci obiektu UserList.

			Format łańcucha jest anologiczny do tego z funkcji userListToString.

			@param source strumień, z którego odczytane zostaną dane
			@see userListToString
			@see stringToUserList
		**/
		QValueList<UserListElement> streamToUserList(QTextStream &source) const;

		/**
			Po jedno sekundowym opóźnieniu wykonuje próbę połączenia.
		**/
		void connectAfterOneSecond();

		/**
			Ustawia adres IP który ma być przekazany do serwera GG
			jako adres komputera, który przekierowuje do nas port DCC.
			Zmiana jest uwzględniana dopiero przy ponownym połączeniu
			z serwerem.
		**/
		void setDccExternalIP(const QHostAddress& ip);
		int seqNum() { return seqNumber; }
		bool validateUserID(QString& uid);

		virtual UserStatus *newStatus() const;

		// --------------------
		//  DCC
		// --------------------

		void dccRequest(UinType);
		void setDccIpAndPort(unsigned long dcc_ip, int dcc_port);

	public slots:
		/**
			Wysyła wiadomość bez formatowania tekstu. Jeśli adresatów jest więcej niż jeden, to wysyłana
			jest wiadomość konferencyjna. Zwracany jest numer sekwencyjny wiadomości, jeśli
			przypadkiem byśmy chcieli śledzić jej potwierdzenie.
			@param users lista użytkowników, do których wysyłamy wiadomość
			@param mesg wiadomość, którą wysyłamy - kodowanie zmieniane wewnątrz
		**/
		QString sendMessage(UserListElements users, const QString &mesg);
		/**
			Wysyła prośbę o przysłanie obrazka z danymi parametrami.

			@param user użytkownik, od którego chcemy obrazek
			@param size rozmiar obrazka w bajtach
			@param crc32 crc32 pliku
			@todo powinno być sendImageRequest(uniqId uint32_t) - info o obrazku zapisywać gdzieś w środku
		**/
		bool sendImageRequest(UserListElement user, int size, uint32_t crc32);

		/**
			Wywyła obrazek o podanych parametrach.

			@param user użytkownik, któremu wysyłamy obrazek
			@param file_name nazwa pliku obrazka
			@param size rozmiar obrazka w bajtach
			@param data zawartość pliku
			@todo usunąć parametry size i data - możemy to chyba sami wyznaczyć
		**/
		bool sendImage(UserListElement user, const QString &file_name, uint32_t size, const char *data);

		/**
			Rejetrujemy nowe konto. Odpowiedź przychodzi poprzez sygnał registered. Może
			zostać także wywołany sygnał needTokenValue.

			@param mail nasz email, pole nieobowiązkowe
			@param password nasze hasło, pole obowiązkowe
			@see registered
			@see needTokenValue
			@see unregisterAccount
		**/
		void registerAccount(const QString &mail, const QString &password);

		/**
			Wyrejestrowujemy stare konto. Odpowiedź przychodzi poprzez sygnał unregistered. Może
			zostać także wywołany sygnał needTokenValue.

			@param uin nasz uin
			@param password nasze hasło
			@todo parametr uin naprawdę potrzebny?
		**/
		void unregisterAccount(UinType uin, const QString &password);

		/**
			Wysyła hasło na email. Odpowiedź przychodzi poprzez sygnał reminded. Może
			zostać także wywołany sygnał needTokenValue.

			@param uin nasz uin
			@param email nasz email (musi być taki sam jak podczas rejestracji)
			@todo parametr uin naprawdę potrzebny?
		**/
		void remindPassword(UinType uin, const QString& mail);

		/**
			Zmienia nasze hasło. Odpowiedź przychodzi poprzez sygnał passwordChanged. Może
			zostać także wywołany sygnał needTokenValue.

			@param uin nasz uin
			@param mail nasz email, jaki podaliśmy przy rejestracji
			@param password stare hasło
			@param newPassword nowe hasło
			@todo parametr uin naprawdę potrzebny?
		**/
		void changePassword(UinType uin, const QString &mail, const QString &password,
			const QString &newPassword);

		/**
			Wysyła listę użytkowników na serwer. Odpowiedź przychodzi przez sygnał userListExported.

			@return false, jeżli operacja się nie powiodła
			@param userList lista do wysłania
			@see userListExported
			@todo usunąć wartość zwracaną
		**/
		bool doExportUserList(const UserList &userList);

		/**
			Usuwa listę użytkowników z serwera. Odpowiedź przychodzi przez sygnał userListCleared.

			@return false, jeżli operacja się nie powiodła
			@see userListCleared
			@todo usunąć wartość zwracaną
		**/
		bool doClearUserList();

		/**
			Importuje listę użytkowników z serwera. Odpowiedź przychodzi przez sygnał userListImported.

			@return false, jeżli operacja się nie powiodła
			@see userListImported
			@todo usunąć wartość zwracaną
		**/
		bool doImportUserList();

		/**
			Wysyła naszą listę użytkowników na serwer. Uwaga: nie ma to nic wspólnego z importem/eksportem.
		**/
		void sendUserList();

		void sendUserListLater();

		/**
			Szuka ludzi w katalogu publicznym. Wyniki przychodzą za pomoca sygnału newSearchResults.

			@param searchRecord dane do szukania
			@see newSearchResults
			@see searchNextInPubdir
		**/
		void searchInPubdir(SearchRecord& searchRecord);

		/**
			Szuka ludzi w katalogu publicznym. Wyniki przychodzą za pomoca sygnału newSearchResults.

			@param searchRecord dane do szukania
			@see newSearchResults
			@see searchInPubdir
		**/
		void searchNextInPubdir(SearchRecord& searchRecord);

		/**
			Zatrzymuje wyszukiwanie.

			@param searchRecord dane użyte w wyszukiwaniu
			@see searchInPubdir
		**/
		void stopSearchInPubdir(SearchRecord& searchRecord);

		/**
			Pobiera informacje o danych osobowych z katalogu publicznego.

			@todo jak to w ogóle działa, bo zapomniałem??
		**/
		void getPersonalInfo(SearchRecord& searchRecord);

		/**
			Ustawia informacje o danych osobowych w katalogu publicznym.

			@todo jak to w ogóle działa, bo zapomniałem??
		**/
		void setPersonalInfo(SearchRecord& searchRecord, SearchResult& newData);


	protected slots:
		/* sloty podłączane do sygnałów z klasy UserList */
		void protocolUserDataChanged(QString protocolName, UserListElement elem,
							QString name, QVariant oldValue, QVariant currentValue,
							bool massively, bool last);
		void userDataChanged(UserListElement elem, QString name, QVariant oldValue,
							QVariant currentValue, bool massively, bool last);
		void userAdded(UserListElement elem, bool massively, bool last);

		void removingUser(UserListElement elem, bool massively, bool last);

		void protocolAdded(UserListElement elem, QString protocolName, bool massively, bool last);

		void removingProtocol(UserListElement elem, QString protocolName, bool massively, bool last);

	signals:
		/**
			wiadomość została zablokowana przez serwer
		**/
		//void messageBlocked(int seq, UinType uin);

		/**
			wiadomość dostarczono
		**/
		void messageDelivered(int seq, UinType uin);

		/**
			wiadomość zakolejkowano
		**/
		void messageQueued(int seq, UinType uin);

		/**
			skrzynka odbiorcza na serwerze jest pełna
		**/
		//void messageBoxFull(int seq, UinType uin);


		//void messageNotDelivered(int seq, UinType uin);


		//void messageAccepted(int seq, UinType uin);
		/**
			wiadomość została odrzucona przez serwer
		**/
		void messageRejected(int seq, UinType uin);

		/**
			wystąpił błąd połączenia
			@param err przyczyna
			@see connectionError
		**/
		void error(GaduError err);

		/**
			dostaliśmy prośbę o przysłanie obrazka
			@param sender od kogo
			@param size rozmiar pliku
			@param crc32 jego suma kontrolna obliczana przy pomocy crc32
		**/
		void imageRequestReceived(UinType sender, uint32_t size, uint32_t crc32);

		/**
			Otrzymano dane obrazka i zapisano go do pliku.
			@param sender od kogo
			@param size rozmiar pliku
			@param crc32 jego suma kontrolna obliczana przy pomocy crc32
			@param path ścieżka do zapisanego pliku
		**/
		void imageReceivedAndSaved(UinType sender, uint32_t size, uint32_t crc32, const QString &path);

		/**
			dostaliśmy od serwera informację o zmianie statusu dla kontaktu,
			którego nie mamy na liście
		**/
		void userStatusChangeIgnored(UinType uin);

		/**
			otrzymana wiadomość systemową
			@param message treść wiadomości wraz z datą
		**/
		void systemMessageReceived(const QString &message);

		/**
			Otrzymano wiadomość CTCP.
			Ktoś nas prosi o połączenie dcc, ponieważ
			jesteśmy za NAT-em
			@param user wywołujący
			@todo zmienić nazwę
		**/
		void dccConnectionReceived(const UserListElement &user);

		/**
			otrzymano nowe wyniki wyszukiwania w katalogu publicznym
			@param searchResults wyniki
			@param seq numer sekwencyjny
			@param lastUin ?
		**/
		void newSearchResults(SearchResults& searchResults, int seq, int lastUin);

		/**
			operacja rejestracji nowego konta została zakończona
			@param ok powodzenie operacji
			@param uin nowy numer
			@see doRegisterAccount
		**/
		void registered(bool ok, UinType uin);

		/**
			operacja wyrejestrowania konta została zakończona
			@param ok powodzenie operacji
			@see doUnregisterAccount
		**/
		void unregistered(bool ok);

		/**
			operacja przypomnienia hasła została zakończona
			@param ok powodzenie operacji
			@see doRemindPassword
		**/
		void reminded(bool ok);

		/**
			operacja zmiany hasła została zakończona
			@param ok powodzenie operacji
			@see doChangePassword
		**/
		void passwordChanged(bool ok);

		/**
			operacja eksportu listy kontaktów na serwer została zakończona
			@param ok powodzenie operacji
			@see doExportUserList
		**/
		void userListExported(bool ok);

		/**
			operacja usunięcia listy kontaktów z serwera została zakończona
			@param ok powodzenie operacji
			@see doClearUserList
		**/
		void userListCleared(bool ok);

		/**
			operacja importu listy kontaktów z serwera została zakończona
			@param ok powodzenie operacji
			@param list jeżeli operacja się powiodła, to zaimportowana lista
			@see doImportUserList
		**/
		void userListImported(bool ok, QValueList<UserListElement> list);

		/**
			Sygnał daje mozliwość operowania na wiadomości
			która przyszła z serwera jeszcze w jej oryginalnej
			formie przed konwersją na unicode i innymi zabiegami.
			Treść wiadomości można zmienić grzebiąc w buforze msg,
			ale uwaga: można zepsuć formatowanie tekstu zapisane
			w formats. Oczywiście je również można zmieniać według
			opisu protokołu GG ;)
			Można też przerwać dalszą obróbkę wiadomości ustawiając
			stop na true.
		**/
		void rawGaduReceivedMessageFilter(Protocol *protocol, UserListElements senders, QCString &msg, QByteArray &formats, bool &ignore);

		/**
			Wywoływane, gdy chcemy odczytać token z obrazka
		**/
		void needTokenValue(QPixmap in, QString &out);

		void dcc7New(struct gg_dcc7 *);
		void dcc7Accepted(struct gg_dcc7 *);
		void dcc7Rejected(struct gg_dcc7 *);

};

extern GaduProtocol* gadu;

#endif
