/*
 * Ostatnia aktualizacja:
 * 
 * - $Id: libtlen.h,v 1.69 2003/10/18 08:56:08 mati Exp $
 *
 */

// Deklaracja naglowka
#ifndef __LIBTLEN_H
#define __LIBTLEN_H

// Inkludy
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <setjmp.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <syslog.h>
#include <string.h>
#include <unistd.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/time.h>
#include <stdarg.h>
#include <ctype.h>
#include <time.h>
#include "xmlparse.h"
#include "str.h"

#ifndef INET_ADDRSTRLEN
#define INET_ADDRSTRLEN 16
#endif

// Coby sie g++ kompilowalo
#ifdef __cplusplus
extern "C"
{
#endif

// Deklaracje hostow
#define TLEN_HUB "idi.tlen.pl"
#define TLEN_FALLBACK_SERVER "s1.tlen.pl"
#define TLEN_FALLBACK_PORT 443

// Deklaracje bledow
#define TLEN_ERROR_UNAUTHORIZED 1
#define TLEN_ERROR_BADRESPONSE 2
#define TLEN_ERROR_MALLOC 3
#define TLEN_ERROR_OTHER 4
#define TLEN_ERROR_NETWORK 5

// Deklaracje statusów

#define TLEN_STATUS_AVAILABLE 2
#define TLEN_STATUS_EXT_AWAY 3
#define TLEN_STATUS_AWAY 4
#define TLEN_STATUS_DND 5
#define TLEN_STATUS_CHATTY 6
#define TLEN_STATUS_INVISIBLE 7
#define TLEN_STATUS_UNAVAILABLE 8

// Deklaracje stanów

#define TLEN_STATE_CONNECTING_HUB 1
#define TLEN_STATE_CONNECTING 2
#define TLEN_STATE_CONNECTED 3

// Deklaracje checkow

#define TLEN_CHECK_READ 1
#define TLEN_CHECK_WRITE 2

struct tlen_writebuffer_item
{
        void *data_mem;
        void *data_ptr;
        size_t data_len;
        struct tlen_writebuffer_item *next;
};

// tlen_session
// --
// struktura sesji tlen.pl, tutaj przechowywane sa informacje o kontaktach,
// ktore "subskrybuje" user, oraz wszelkie info o userze, ktory jest
// zalogowany. Struktura wypelniana przez funkcje tlen_login.

struct tlen_session
{
	int fd;		// socket
	int error;	// kod bledu
	int state;	// stan
	int check;	// typ sprawdzania
	XML_Parser parser;	// parser strumienia XML
	struct tlen_event *event;
	spool buffer; // bufor na XML
	pool bufferpool;
	int buffering; // czy zbieramy do bufora
	char *sid;	// ID sesji
	char *username;	// nazwa uzytkownika przed @tlen.pl
	char *password;	// haselko
	int status;	// stan
	int hub_blocking; // blokowanie huba
	char *description;	// opis
	int nestlevel; // poziom zagnieżdzenia w parsowanym XML-u
        int resolv_pid; // PID resolvera
	int proxy_enabled; // czy uzywamy proxy?
	char *proxy_addr; // adres proxy
	int proxy_port; // port proxy
	struct tlen_writebuffer_item *writebuffer; // bufor danych do wysłania przez socket
        struct tlen_writebuffer_item *writebuffer_last_item; // ostatni element bufora
};

// tlen_user
// --
// struktura danych o użytkowniku - zawiera nazwę, identyfikator @tlen.pl,
// grupę w której użytkownik "siedzi", oraz poziom autoryzacji.

struct tlen_user
{
	char *name;
	char *jid;
	char *group;
	char *subscription;
	char *ask;//jesli ask zawiera 'subscribe' to znaczy ze czekamy na
        //autoryzacje u tej osoby
};


// tlen_message
// --
// tutaj znajdziesz wiadomość - struktura wypełniana przez
// tlen_watch_fd.

#define TLEN_MESSAGE 0
#define TLEN_CHAT 1

struct tlen_message
{
	char *from;	// od kogo
	char *body;	// treść już zdekodowana urldecodem
        char *stamp;    // data wyslania wiadomosci, jesli byla przechowywana
	int type;	// typ wiadomości
};

// tlen_presence
// --
// tutaj znajdziesz presence - struktura wypełniana przez
// tlen_watch_fd.

struct tlen_presence
{
	char *from;	// od kogo
	int status; // status w postaci liczbowej
	char *description;	// opis do statusu
};

// tlen_subscription
// --
// tutaj znajdziesz informacje o subskrybcji - struktura
// wypelniana przez tlen_watch_fd

struct tlen_subscription
{
	char *jid;
};

// tlen_newmail
// --
// informacje o nowym mailu na skrzynce, od kogo i jaki tytul

struct tlen_newmail
{
    char *from;
    char *subject;
};

// tlen_grouchat
// --
// struktura opisująca konferencję, identyfikatory, hashe, etc.

struct tlen_groupchat
{
    char *conf; // Identyfikator w formie idSEKUNDA@conf
    char *secret; // Haslo, wysylanie jako totalny random przy twożeniu konferencji
};

// tlen_webmsg
// --
// wiadomosc wyslana ze strony ludzie.tlen.pl/login_name

struct tlen_webmsg
{
    char *from;
    char *email;
    char *site;
    char *body;
};

// tlen_notify
// --
// powiadomienia - pisze, przestal pisac, wiadomosc dzwiekowa

#define TLEN_NOTIFY_TYPING 1
#define TLEN_NOTIFY_NOTTYPING 2
#define TLEN_NOTIFY_SOUNDALERT 3

struct tlen_notify
{
    char *from; // od kogo
    char *to; // do kogo
    int type; // typ powiadomienia
};

// tlen_advert
// --
// reklama wyskaująca
struct tlen_advert
{
    char *url; // adres reklamy
    char *name; // nazwa rekalmodawcy
    int width; // szerokosc okienka wyskakujacego
    int height; // wysokosc okienka wyskakujacego
};

// **********************************************************
// KATALOG PUBLICZNY

// zawody - sorry za polskie, ale bez sensu bylo to angielszczyc
#define TLEN_PUBDIR_JOB_NONE 0
#define TLEN_PUBDIR_JOB_UCZEN 1
#define TLEN_PUBDIR_JOB_STUDENT 2
#define TLEN_PUBDIR_JOB_ROLNIK 3
#define TLEN_PUBDIR_JOB_MENEDZER 4
    // specjalista, wolny zawod
#define TLEN_PUBDIR_JOB_SPEC_WOL 5
    // urzednik, uslugi, administracja
#define TLEN_PUBDIR_JOB_UUA 6
#define TLEN_PUBDIR_JOB_BEZROBOTNY 7
    // emeryt, rencista
#define TLEN_PUBDIR_JOB_EMERYT 8
#define TLEN_PUBDIR_JOB_GOSPODYNI 9
#define TLEN_PUBDIR_JOB_NAUCZYCIEL 10
#define TLEN_PUBDIR_JOB_LEKARZ 11
#define TLEN_PUBDIR_JOB_INNY 12

// płcie

#define TLEN_PUBDIR_GENDER_NONE 0
#define TLEN_PUBDIR_GENDER_MALE 1
#define TLEN_PUBDIR_GENDER_FEMALE 2

// plany

#define TLEN_PUBDIR_WANT_NONE 0
#define TLEN_PUBDIR_WANT_CINEMA 1
//...trzeba dopisac

// szukam...

#define TLEN_PUBDIR_LOOK_NONE 0
#define TLEN_PUBDIR_LOOK_TALK 1
#define TLEN_PUBDIR_LOOK_FRIEND 2
#define TLEN_PUBDIR_LOOK_FLIRT 3
#define TLEN_PUBDIR_LOOK_LOVE 4 

// Glos

#define TLEN_PUBDIR_VOICE_DISABLED 0
#define TLEN_PUBDIR_VOICE_ENABLED 1

// Widocznosc

#define TLEN_PUBDIR_VISIBLE_NO 0
#define TLEN_PUBDIR_VISIBLE_YES 1

// Status

#define TLEN_PUBDIR_STATUS_AVAILABLE 2
#define TLEN_PUBDIR_STATUS_CHATTY 3

// Oznaczenia:
// *PS* - katalog i szukanie
// *S* - samo szukanie
// *SR* - szukanie i tylko wartosc zwracana

struct tlen_pubdir
{
    char *firstname; // *PS* Imię
    char *lastname; // *PS* Nazwisko
    char *nick; // *PS* Nick
    int gender; // *PS* Płeć
    char *city; // *PS* Miasto
    char *email; // *PS* Email
    int age; // *SR* ZWRACANY wiek
    int age_min; // *S* min. wiek
    int age_max; // *S* max. wiek
    int look_for; // *PS* poszukuję...
    char *school; // *PS* szkoła
    int job; // *PS* zawód
    int status; // *S* stan
    int voice; // *PS* z możliwością rozmowy głosowej
    char *id; // *S* identyfikator
    int plans; // *PS* plany
    int birthyear; // *P* rok urodzenia
    int visible; // *P* czy moj status ma byc widoczny? 
};


// **********************************************************


#define TLEN_EVENT_UNKNOWN -1
#define TLEN_EVENT_AUTHORIZED 3
#define TLEN_EVENT_GOTROSTERITEM 5
#define TLEN_EVENT_MESSAGE 6
#define TLEN_EVENT_SUBSCRIBE 7
#define TLEN_EVENT_PRESENCE 8
#define TLEN_EVENT_UNSUBSCRIBE 9
#define TLEN_EVENT_ENDROSTER 10
#define TLEN_EVENT_SUBSCRIBED 11
#define TLEN_EVENT_UNSUBSCRIBED 12
#define TLEN_EVENT_NEWMAIL 14
#define TLEN_EVENT_GOTSEARCHITEM 15
#define TLEN_EVENT_ENDSEARCH 16
#define TLEN_EVENT_PUBDIR_GOTDATA 17
#define TLEN_EVENT_PUBDIR_GOTUPDATEOK 18
#define TLEN_EVENT_WEBMSG 19
#define TLEN_EVENT_NOTIFY 20
#define TLEN_EVENT_ADVERT 21

// tlen_event
// --
// struktura wypełniana przez tlen_watch_fd, type wskazuje na typ
// zdarzenia (typy powyrzej), jeżeli message to od razu wypełnione
// jest pole message, jeżeli presence to presence - tak więc
// łatwo się do wszystkiego dobrać.

struct tlen_event
{
	int type;	// typ zdarzenia - definicje wyzej
	struct tlen_presence *presence;	// jezeli zdarzenie to status, tutaj sa jego dane
	struct tlen_message *message;	// jezeli zdarzenie to wiadomosc, tutaj znajdziesz jej wlasciwosci
	struct tlen_subscription *subscribe;	// jezeli zdarzenie to subskrybcja, tutaj znajdziesz jej dane
	struct tlen_user *roster;	// jezeli zdarzenie to ksiazka adresowa, tutaj jest tablica uzytkownikow
        struct tlen_newmail *newmail; //dla zdarzenia newmail
        struct tlen_webmsg *webmsg; //dla zdarzenia webmsg
	struct tlen_pubdir *pubdir; //do pubdira (search i katalog)
	struct tlen_notify *notify; //do powiadomien - pisze, przestal pisac, sygnal dzwiekowy
	struct tlen_advert *advert; //reklama wyskakujaca
	struct tlen_event *next_event;
};

// funkcje obslugi sesji
struct tlen_session *tlen_init(void);
void tlen_set_hub_blocking(struct tlen_session *sess, int blocking);
void tlen_set_auth(struct tlen_session *sess, char *username, char *password);
void tlen_set_proxy(struct tlen_session *sess, char *addr, int port);
void tlen_login (struct tlen_session *sess);
int tlen_freesession (struct tlen_session *sesja);

// funkcje obslugi gniazd
int tlen_socket_create (const char *address, int port);
int tlen_socket_write_string (struct tlen_session *sess, const void *string);
int tlen_socket_write (struct tlen_session *sess, const void *data, size_t len);
int tlen_socket_destroy (struct tlen_session *sess);

// funkcje obslugi autoryzacji
char *tlen_hash (const char *pass, const char *id);
int tlen_getid (struct tlen_session *sesja);
int tlen_authorize (struct tlen_session *sesja);

// funkcje obslugi ksiazki adresowej
int tlen_getroster (struct tlen_session *sesja);
int tlen_addcontact (struct tlen_session *sesja, const char *name,
		     const char *jid, const char *group);
int tlen_removecontact (struct tlen_session *sesja, const char *jid);
int tlen_request_subscribe (struct tlen_session *sesja, const char *jid);
int tlen_request_unsubscribe (struct tlen_session *sesja, const char *jid);
int tlen_accept_subscribe (struct tlen_session *sesja, const char *jid);
int tlen_accept_unsubscribe (struct tlen_session *sesja, const char *jid);


// funkcje obslugi statusów 
int tlen_presence (struct tlen_session *sesja, int status,
		   const char *description);
int tlen_presence_disconnect (struct tlen_session *sesja);
int tlen_presence_invisible (struct tlen_session *sesja);

// funkcje obslugi zdarzeń
void tlen_watch_fd (struct tlen_session *sesja);

// funkcje obslugi messagow
int tlen_sendmsg (struct tlen_session *sesja,
		  const char *destination, const char *message, int type);
int tlen_sendnotify (struct tlen_session *sesja,
		  const char *destination, int type);

// funkcje obsługi konferencji
int tlen_get_second();
int tlen_groupchat_create(struct tlen_session *sesja);

// funkcje obslugi wyszukiwania
int tlen_search (struct tlen_session *sesja, struct tlen_pubdir *search);
struct tlen_pubdir *tlen_new_pubdir ();
int tlen_free_pubdir (struct tlen_pubdir *pubdir);
int tlen_get_pubdir (struct tlen_session *sesja);
int tlen_change_pubdir (struct tlen_session *sesja, struct tlen_pubdir *pubdir);

// utilsy :-D
void tlen_ping (struct tlen_session *);
char *tlen_encode (const char *);
char *tlen_decode (const char *);

void tlen_debug_raw (const char *name, char *format, ...);
#define tlen_debug(...) tlen_debug_raw(__func__,__VA_ARGS__)

void tlen_parsebuffer(struct tlen_session *sesja);
int tlen_stripresource(char *jid);
int tlen_setdebug (int dbg);
char *tlen_base64_encode(const char *buf);
char *tlen_base64_decode(const char *buf);

// events
struct tlen_event* tlen_newevent(int type);
void tlen_freeevent (struct tlen_event* e);
void tlen_addevent(struct tlen_session *sesja, struct tlen_event *e);
struct tlen_event* tlen_getevent(struct tlen_session *sesja);

// handlery

void tlen_starttag_handler(void *userData, const XML_Char *name, const XML_Char **atts);
void tlen_endtag_handler (void *userData, const XML_Char *name);
void tlen_char_handler (void *userData, const XML_Char *s, int len);

// hub

int tlen_connect_hub (struct tlen_session *sess, int blocking);

// *********************************************
// *********************************************
// NIE MOJE, WZIĘTE Z INNYCH PROGRAMÓW, ITP.:
// gaim, ekg, expat, itd. itp.
// *********************************************
// *********************************************

// Obsluga stringow

#ifndef HAVE_SNPRINTF
	extern int ap_snprintf (char *, size_t, const char *, ...);
#define snprintf ap_snprintf
#endif

#ifndef HAVE_VSNPRINTF
	extern int ap_vsnprintf (char *, size_t, const char *, va_list ap);
#define vsnprintf ap_vsnprintf
#endif

#define ZONE zonestr(__FILE__,__LINE__)
	char *zonestr (char *file, int line);

// prostee metody ograniczania pasma jabbera (wziete z gaim)

	typedef struct jlimit_struct
	{
		char *key;
		int start;
		int points;
		int maxt, maxp;
		pool p;
	}
	 *jlimit, _jlimit;

	jlimit jlimit_new (int maxt, int maxp);
	void jlimit_free (jlimit r);
	int jlimit_check (jlimit r, char *key, int points);

// Hashtable (z expat)

	typedef struct xhn_struct
	{
		struct xhn_struct *next;
		const char *key;
		void *val;
	}
	 *xhn, _xhn;

	typedef struct xht_struct
	{
		pool p;
		int prime;
		struct xhn_struct *zen;
	}
	 *xht, _xht;

	xht xhash_new (int prime);
	void xhash_put (xht h, const char *key, void *val);
	void *xhash_get (xht h, const char *key);
	void xhash_zap (xht h, const char *key);
	void xhash_free (xht h);
	typedef void (*xhash_walker) (xht h, const char *key, void *val,
				      void *arg);
	void xhash_walk (xht h, xhash_walker w, void *arg);

// "Staromodne" hashtable (z expat)

	typedef int (*KEYHASHFUNC) (const void *key);
	typedef int (*KEYCOMPAREFUNC) (const void *key1, const void *key2);
	typedef int (*TABLEWALKFUNC) (void *user_data, const void *key,
				      void *data);

	typedef void *HASHTABLE;

	HASHTABLE ghash_create (int buckets, KEYHASHFUNC hash,
				KEYCOMPAREFUNC cmp);
	HASHTABLE ghash_create_pool (pool p, int buckets, KEYHASHFUNC hash,
				     KEYCOMPAREFUNC cmp);
	void ghash_destroy (HASHTABLE tbl);
	void *ghash_get (HASHTABLE tbl, const void *key);
	int ghash_put (HASHTABLE tbl, const void *key, void *value);
	int ghash_remove (HASHTABLE tbl, const void *key);
	int ghash_walk (HASHTABLE tbl, TABLEWALKFUNC func, void *user_data);
	int str_hash_code (const char *s);

// Wezly xml (xmlnodes) (z expat)

#define NTYPE_TAG    0
#define NTYPE_ATTRIB 1
#define NTYPE_CDATA  2

#define NTYPE_LAST   2
#define NTYPE_UNDEF  -1

/* -------------------------------------------------------------------------- 
   Node structure. Do not use directly! Always use accessor macros 
   and methods!
   -------------------------------------------------------------------------- */
	typedef struct xmlnode_t
	{
		char *name;
		unsigned short type;
		char *data;
		int data_sz;
		int complete;
		pool p;
		struct xmlnode_t *parent;
		struct xmlnode_t *firstchild;
		struct xmlnode_t *lastchild;
		struct xmlnode_t *prev;
		struct xmlnode_t *next;
		struct xmlnode_t *firstattrib;
		struct xmlnode_t *lastattrib;
	}
	_xmlnode, *xmlnode;

/* Node creation routines */
	xmlnode xmlnode_wrap (xmlnode x, const char *wrapper);
	xmlnode xmlnode_new_tag (const char *name);
	xmlnode xmlnode_new_tag_pool (pool p, const char *name);
	xmlnode xmlnode_insert_tag (xmlnode parent, const char *name);
	xmlnode xmlnode_insert_cdata (xmlnode parent, const char *CDATA,
				      unsigned int size);
	xmlnode xmlnode_insert_tag_node (xmlnode parent, xmlnode node);
	void xmlnode_insert_node (xmlnode parent, xmlnode node);
	xmlnode xmlnode_str (char *str, int len);
	xmlnode xmlnode_file (char *file);
	char *xmlnode_file_borked (char *file);	/* same as _file but returns the parsing error */
	xmlnode xmlnode_dup (xmlnode x);	/* duplicate x */
	xmlnode xmlnode_dup_pool (pool p, xmlnode x);

/* Node Memory Pool */
	pool xmlnode_pool (xmlnode node);
	xmlnode _xmlnode_new (pool p, const char *name, unsigned int type);

/* Node editing */
	void xmlnode_hide (xmlnode child);
	void xmlnode_hide_attrib (xmlnode parent, const char *name);

/* Node deletion routine, also frees the node pool! */
	void xmlnode_free (xmlnode node);

/* Locates a child tag by name and returns it */
	xmlnode xmlnode_get_tag (xmlnode parent, const char *name);
	char *xmlnode_get_tag_data (xmlnode parent, const char *name);

/* Attribute accessors */
	void xmlnode_put_attrib (xmlnode owner, const char *name,
				 const char *value);
	char *xmlnode_get_attrib (xmlnode owner, const char *name);
	void xmlnode_put_expat_attribs (xmlnode owner, const char **atts);

/* Bastard am I, but these are fun for internal use ;-) */
	void xmlnode_put_vattrib (xmlnode owner, const char *name,
				  void *value);
	void *xmlnode_get_vattrib (xmlnode owner, const char *name);

/* Node traversal routines */
	xmlnode xmlnode_get_firstattrib (xmlnode parent);
	xmlnode xmlnode_get_firstchild (xmlnode parent);
	xmlnode xmlnode_get_lastchild (xmlnode parent);
	xmlnode xmlnode_get_nextsibling (xmlnode sibling);
	xmlnode xmlnode_get_prevsibling (xmlnode sibling);
	xmlnode xmlnode_get_parent (xmlnode node);

/* Node information routines */
	char *xmlnode_get_name (xmlnode node);
	char *xmlnode_get_data (xmlnode node);
	int xmlnode_get_datasz (xmlnode node);
	int xmlnode_get_type (xmlnode node);

	int xmlnode_has_children (xmlnode node);
	int xmlnode_has_attribs (xmlnode node);

/* Node-to-string translation */
	char *xmlnode2str (xmlnode node);

/* Node-to-terminated-string translation 
   -- useful for interfacing w/ scripting langs */
	char *xmlnode2tstr (xmlnode node);

	int xmlnode_cmp (xmlnode a, xmlnode b);	/* compares a and b for equality */

	int xmlnode2file (char *file, xmlnode node);	/* writes node to file */

/* Expat callbacks */
	void expat_startElement (void *userdata, const char *name,
				 const char **atts);
	void expat_endElement (void *userdata, const char *name);
	void expat_charData (void *userdata, const char *s, int len);

/***********************
 * XSTREAM Section
 ***********************/

#define XSTREAM_MAXNODE 1000000
#define XSTREAM_MAXDEPTH 100

#define XSTREAM_ROOT        0	/* root element */
#define XSTREAM_NODE        1	/* normal node */
#define XSTREAM_CLOSE       2	/* closed </stream:stream> */
#define XSTREAM_ERR         4	/* parser error */

	typedef void (*xstream_onNode) (int type, xmlnode x, void *arg);	/* xstream event handler */

	typedef struct xstream_struct
	{
		XML_Parser parser;
		xmlnode node;
		char *cdata;
		int cdata_len;
		pool p;
		xstream_onNode f;
		void *arg;
		int status;
		int depth;
	}
	 *xstream, _xstream;

	xstream xstream_new (pool p, xstream_onNode f, void *arg);	/* create a new xstream */
	int xstream_eat (xstream xs, char *buff, int len);	/* parse new data for this xstream, returns last XSTREAM_* status */

/* convience functions */
	xmlnode xstream_header (char *namespace, char *to, char *from);
	char *xstream_header_char (xmlnode x);

	typedef struct
	{
		XML_Parser parser;
		xmlnode current;
	}
	 *xmlstr2xmlnode_parser, xmlstr2xmlnode_parser_struct;

	void xmlstr2xmlnode_charData (void *userdata, const char *s,
				      int slen);
	void xmlstr2xmlnode_startElement (void *userdata, const char *name,
					  const char **attribs);
	void xmlstr2xmlnode_endElement (void *userdata, const char *name);
	xmlnode xmlstr2xmlnode (char *xmlstring);

	typedef struct
	{
		unsigned long H[5];
		unsigned long W[80];
		int lenW;
		unsigned long sizeHi, sizeLo;
	}
	j_SHA_CTX;


	void shaInit (j_SHA_CTX * ctx);
	void shaUpdate (j_SHA_CTX * ctx, unsigned char *dataIn, int len);
	void shaFinal (j_SHA_CTX * ctx, unsigned char hashout[20]);
	void shaBlock (unsigned char *dataIn, int len,
		       unsigned char hashout[20]);

// zamkniecie kilku definicji

#ifdef __cplusplus
}
#endif

#endif	/* __LIBTLEN_H typedef struct */
