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

		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;

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


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

		/** 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;

		/** 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 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 messageReceived(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);

		/**

		**/
		void onCreateTabNetwork();

		/**

		**/
		void onApplyTabNetwork();

		/**

		**/
		void ifDefServerEnabled(bool value);

		/**

		**/
		void useTlsEnabled(bool value);

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

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

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

		virtual UserStatus *newStatus() const;
	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 msg wiadomość, którą wysyłamy - musi być podana w postaci cp1250
			@todo zmienić na sendMessage(const UinsList &, QString &) z wewnętrzną konwersją na cp1250
		**/
		int sendMessage(UserListElements users, const char *msg);

		/**
			Wysyła wiadomość z formatowaniem 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 msg wiadomość, którą wysyłamy - musi być podana w postaci cp1250
			@param myLastFormats formatowanie tekstu
			@param myLastFormatsLength ilośc znaczników formatujących

			@todo zmienić na sendMessageRichText(const UinsList &, QString &, ...)
				z wewnętrzną konwersją na cp1250 oraz z jakimś lepszym sposobem formatowania tekstu
		**/
		int sendMessageRichText(UserListElements users, const char *msg, unsigned char *myLastFormats,
		 	unsigned int myLastFormatsLength);

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

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

		/**
			 To raczej chwilowo.

			 @todo usunąć
			 @todo niech Adrian zrobi porzadek z tym dcc...
		**/
		void freeEvent(struct gg_event* e);

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

		void dccRequest(UinType);
		void dccFree(struct gg_dcc* d);
		struct gg_event* dccWatchFd(struct gg_dcc* d);
		void dccSetType(struct gg_dcc* d, int type);
		int dccFillFileInfo(struct gg_dcc* d, const QString& filename);
		void dccSocketCreate(UinType uin, uint16_t port, struct gg_dcc **out);
		void dccSendFile(uint32_t ip, uint16_t port, UinType my_uin, UinType peer_uin, struct gg_dcc **out);
		void dccGetFile(uint32_t ip, uint16_t port, UinType my_uin, UinType peer_uin, struct gg_dcc **out);
		void dccVoiceChat(uint32_t ip, uint16_t port, UinType my_uin, UinType peer_uin, struct gg_dcc **out);
		int dccVoiceSend(struct gg_dcc* d, char* buf, int length);
		void setDccIpAndPort(unsigned long dcc_ip, int dcc_port);

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

		/**
			wiadomość nie dostaczona (występuje tylko przy CTCP)
		**/
		void messageNotDelivered(int seq, UinType uin);

		/**
			wiadomość została przyjęta przez serwer
		**/
		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 messageFiltering(Protocol *protocol, UserListElements senders,
								QCString& msg, QByteArray& formats, bool& stop);
		/**
			Otrzymano wiadomość którą trzeba pokazać (klasa chat lub msg,
			nadawca nie jest ignorowany, itp)
			Treść zdeszyfrowana i zdekodowana do unicode.
			Jeśli któryś ze slotów sygnału chatMsgReceived1 ustawi zmienną
			grab na true to sygnał chatReceived2 nie zostanie wygenerowany.
			Jeśli natomiast zmienna grab zostanie ustawiona przez slot
			chatMsgReceived0, to żadna czynność związana z obsługą tego
			zdarzenia nie zostanie podjęta (tj. wyświetlanie wiadomości
			w oknie, dodanie jej do historii, etc.), poza przekonwertowaniem
			kodowania wiadomości z CP1250 na Unicode.
		**/
		void chatMsgReceived0(Protocol *protocol, UserListElements senders, const QString& msg, time_t time, bool& grab);
		void chatMsgReceived1(Protocol *protocol, UserListElements senders, const QString& msg, time_t time, bool& grab);
		void chatMsgReceived2(Protocol *protocol, UserListElements senders, const QString& msg, time_t time);

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

};

extern GaduProtocol* gadu;

#endif
