/*
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 *
 *  Jabber
 *  Copyright (C) 1998-1999 The Jabber Team http://jabber.org/
 */

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

#include "libxode.h"

#ifndef __JAB_H
#define __JAB_H

/*
** core jabber types/utils
*/

typedef struct jid_struct
{ /* type=user/resource@server */
    pool p;
    char *resource;
    char *user;
    char *server;
    char *full;
    struct jid_struct *next; /* for lists of jids */
} *jid;
 
#define JID_RESOURCE 1
#define JID_USER 2
#define JID_SERVER 4
 
jid jid_new(pool p, char *idstr); /* Creates a jabber id from the idstr */
void jid_set(jid id, char *str, int item); /* allows you to individually set jid components */
char *jid_full(jid id); /* builds a string type=user/resource@server from the jid data */
int jid_cmp(jid a, jid b); /* compares two jid's, returns 0 for perfect match */
int jid_cmpx(jid a, jid b, int parts); /* compares just the parts specified as JID_|JID_ */
jid jid_append(jid a, jid b); /* appending b to a (list), no dups */
xmlnode jid_xres(jid id); /* returns xmlnode representation of the resource?query=string */
xmlnode jid_nodescan(jid id, xmlnode x); /* scans the children of the node for a matching jid attribute */

#define JPACKET_UNKNOWN 0x00
#define JPACKET_MESSAGE 0x01
#define JPACKET_PRESENCE 0x02
#define JPACKET_IQ 0x04
#define JPACKET_S10N 0x08

#define JPACKET__UNKNOWN 0
#define JPACKET__NONE 1
#define JPACKET__ERROR 2
#define JPACKET__CHAT 3
#define JPACKET__GROUPCHAT 4
#define JPACKET__GET 5
#define JPACKET__SET 6
#define JPACKET__RESULT 7
#define JPACKET__SUBSCRIBE 8
#define JPACKET__SUBSCRIBED 9
#define JPACKET__UNSUBSCRIBE 10
#define JPACKET__UNSUBSCRIBED 11
#define JPACKET__AVAILABLE 12
#define JPACKET__UNAVAILABLE 13
#define JPACKET__PROBE 14
#define JPACKET__HEADLINE 15

typedef struct jpacket_struct
{
    unsigned char type;
    int subtype;
    int flag;
    void *aux1;
    xmlnode x;
    jid to;
    jid from;
    char *iqns;
    xmlnode iq;
    pool p;
} *jpacket, _jpacket;
 
jpacket jpacket_new(xmlnode x); /* Creates a jabber packet from the xmlnode */
jpacket jpacket_reset(jpacket p); /* Resets the jpacket values based on the xmlnode */
int jpacket_subtype(jpacket p); /* Returns the subtype value (looks at xmlnode for it) */


typedef struct ppdb_struct
{
    /* entry data */
    jid id;
    int pri;
    xmlnode x;

    /* linked list for user@server */
    struct ppdb_struct *user;

    /* db-level data */
    pool p;
    struct ppdb_struct *next;
} _ppdb, *ppdb;

ppdb ppdb_insert(ppdb db, jid id, xmlnode x); /* inserts presence into the proxy */
xmlnode ppdb_primary(ppdb db, jid id); /* fetches the matching primary presence for the id */
xmlnode ppdb_get(ppdb db, jid id); /* called successively to return each presence xmlnode for the id and children, returns NULL at the end */
void ppdb_free(ppdb db); /* frees the db and all entries */


/* jabber errors */
typedef struct terror_struct
{
    int code;
    char msg[64];
} terror;

#define TERROR_BAD (terror){400,"Bad Request"}
#define TERROR_AUTH (terror){401,"Unauthorized"}
#define TERROR_PAY (terror){402,"Payment Required"}
#define TERROR_FORBIDDEN (terror){403,"Forbidden"}
#define TERROR_NOTFOUND (terror){404,"Not Found"}
#define TERROR_NOTALLOWED (terror){405,"Not Allowed"}
#define TERROR_NOTACCEPTABLE (terror){406,"Not Acceptable"}
#define TERROR_REGISTER (terror){407,"Registration Required"}
#define TERROR_REQTIMEOUT (terror){408,"Request Timeout"}
#define TERROR_CONFLICT (terror){409,"Conflict"}

#define TERROR_INTERNAL (terror){500,"Internal Server Error"}
#define TERROR_NOTIMPL (terror){501,"Not Implemented"}
#define TERROR_EXTERNAL (terror){502,"Remote Server Error"}
#define TERROR_UNAVAIL (terror){503,"Service Unavailable"}
#define TERROR_EXTTIMEOUT (terror){504,"Remote Server Timeout"}

/* some namespace handy constants */

#define NSCHECK(x,n) (j_strcmp(xmlnode_get_attrib(x,"xmlns"),n) == 0)

#define NS_CLIENT "jabber:client"
#define NS_SERVER "jabber:server"
#define NS_AUTH "jabber:iq:auth"
#define NS_REGISTER "jabber:iq:register"
#define NS_ROSTER "jabber:iq:roster"
#define NS_OFFLINE "jabber:x:offline"
#define NS_AGENT "jabber:iq:agent"
#define NS_AGENTS "jabber:iq:agents"
#define NS_DELAY "jabber:x:delay"
#define NS_VERSION "jabber:iq:version"
#define NS_TIME "jabber:iq:time"
#define NS_VCARD "vcard-temp"
#define NS_PRIVATE "jabber:iq:private"
#define NS_SEARCH "jabber:iq:search"
#define NS_OOB "jabber:iq:oob"
#define NS_XOOB "jabber:x:oob"
#define NS_ADMIN "jabber:iq:admin"
#define NS_FILTER "jabber:iq:filter"


/* some stuff added for comfort */
xmlnode jutil_presnew(int type, char *to, char *status);
xmlnode jutil_iqnew(int type, char *ns);
int jutil_priority(xmlnode x);
void jutil_tofrom(xmlnode x);
xmlnode jutil_iqresult(xmlnode x);
char *jutil_timestamp(void);
void jutil_error(xmlnode x, terror E);
void jutil_delay(xmlnode msg, char *reason);
char *jutil_regkey(char *key, char *seed); /* pass a seed to generate a key, pass the key again to validate (returns it) */

/*
** General
*/

typedef void (*jabEvent)(void);

void jab_setcb(int cb, jabEvent func);
#define JABCB_ONLINE 0
#define JABCB_OFFLINE 1
#define JABCB_MESSAGE 2
#define JABCB_PRESENCE 3
#define JABCB_IQ 4
#define JABCB_ROSTER 5
#define JABCB_AUTH 6
#define JABCB_PROFILE 7



/*
** Connection Stuff
*/

typedef struct jabc_struct
{
    pool p;
    int state;
    int fd;
    int currentid;
    /* user */
    jid user;
    char *pass;
    int flags;
    struct jabpf_struct *profile;
    /* jabstream */
    XML_Parser xparser;
    xmlnode xnode;
    int xflag;
} *jabc, _jabc;

jabc jab_connect(char *user, char *pass, int flags);
#define JABC_DIRECT 1
#define JABC_FASTIO 2
#define JABC_NEWUSER 4
#define JABC_ROSTER 8
#define JABC_PROFILE 16
void jab_disconnect(jabc j);
void jab_poll(jabc j);
int jab_fd(jabc j);
int jab_isonline(jabc j);

/* auth callback */
#define JAB_REG_OK 0
#define JAB_REG_FAIL 1
#define JAB_AUTH_OK 2
#define JAB_AUTH_FAIL 3

/* offline callback error numbers */
#define JAB_OFF_BYE 1
#define JAB_OFF_XML 2
#define JAB_OFF_SOCK 3




/*
** Node Stuff
*/

#define JABNSTRUCT pool p; int node; char *id; jid from; jid to; int type;

union jabn_union
{
	struct jabn_struct
	{
		JABNSTRUCT
	} jn;
	struct jabm_struct
	{
		JABNSTRUCT
		int priority;
		char *thread;
		char *subject;
		char *body;
		xmlnode x;
	} jm;
	struct jabp_struct
	{
		JABNSTRUCT
		int priority;
		char *status;
	} jp;
	struct jabq_struct
	{
		JABNSTRUCT
		char *xmlns;
		xmlnode query;
	} jq;
};

typedef union jabn_union *jabn;
typedef struct jabm_struct *jabm, _jabm;
typedef struct jabp_struct *jabp, _jabp;
typedef struct jabq_struct *jabq, _jabq;

jabn jab_newnode(int type, ...);
void jab_editnode(jabn node, ...);
/*jabn jab_replynode(jabn node, ...);*/
jabn jab_parsenode(xmlnode xml);
void jab_sendnode(jabc j, jabn node);
void jab_freenode(jabn node);

/* nodes */
#define JABN_MSG 0
#define JABN_PRS 1
#define JABN_IQ 2

/* common args and their synonyms */
#define JABN_DONE 0
#define JABM_DONE 0
#define JABP_DONE 0
#define JABQ_DONE 0
#define JABN_ID 1
#define JABM_ID 1
#define JABP_ID 1
#define JABQ_ID 1
#define JABN_FROM 2
#define JABM_FROM 2
#define JABP_FROM 2
#define JABQ_FROM 2
#define JABN_TO 3
#define JABM_TO 3
#define JABP_TO 3
#define JABQ_TO 3
#define JABN_TYPE 4
#define JABM_TYPE 4
#define JABP_TYPE 4
#define JABQ_TYPE 4

/* message args */
#define JABM_BODY 21
#define JABM_SUBJECT 22
#define JABM_THREAD 23
#define JABM_PRIORITY 24
#define JABM_X 25

/* message types */
#define JABM_TYPE_NORMAL 0	/* default */
#define JABM_TYPE_ERROR 1
#define JABM_TYPE_CHAT 2
#define JABM_TYPE_GROUPCHAT 3

/* presence args */
#define JABP_STATUS 41
#define JABP_PRIORITY 42

/* presence types */
#define JABP_TYPE_AVAILABLE 0	/* default */
#define JABP_TYPE_UNAVAILABLE 1
#define JABP_TYPE_SUBSCRIBE 2
#define JABP_TYPE_SUBSCRIBED 3
#define JABP_TYPE_UNSUBSCRIBE 4
#define JABP_TYPE_UNSUBSCRIBED 5
#define JABP_TYPE_PROBE 6

/* query args */
#define JABQ_QUERY 61

/* query types */
#define JABQ_TYPE_GET 0	/* default */
#define JABQ_TYPE_SET 1
#define JABQ_TYPE_RESULT 2
#define JABQ_TYPE_ERROR 3




/*
** Roster Stuff
*/

#define JABR_ROSTER 1
#define JABR_PUSH 2

typedef struct jabr_struct
{
    pool p;
    struct jabri_struct *items;
    struct jabri_struct *lastitem;
} *jabr, _jabr;

typedef enum
{
    JABR_SUB_NDEF,
    JABR_SUB_NONE,
    JABR_SUB_TO,
    JABR_SUB_FROM,
    JABR_SUB_BOTH,
    JABR_SUB_REMOVE
} jabri_sub_enum;

typedef enum
{
    JABR_ASK_NDEF,
    JABR_ASK_SUB,
    JABR_ASK_UNSUB
} jabri_ask_enum;

typedef struct jabri_struct
{
    struct jabri_struct *next;
    char *user;
    char *name;
    jabri_sub_enum sub;
    jabri_ask_enum ask;
    struct jabrg_struct *groups;
    struct jabrg_struct *lastgroup;
} *jabri, _jabri;

typedef struct jabrg_struct
{
    struct jabrg_struct *next;
    char *name;
} *jabrg, _jabrg;

void jabr_request(jabc j);
void jabr_additem(jabc j, char *group, char *user, char *name);
void jabr_removeitem(jabc j, char *user);
jabri jabr_updateitem(char *user, char *name);
void jabr_updategroup(jabri item, char *group);
void jabr_sendupdate(jabc j, jabri item);
void jabr_free(jabr r);




/*
** Profile Stuff
*/

typedef struct jabpf_struct
{
    pool p;
    char *from;
    char *type;
    char *name;
    char *description;
    char *email;
    char *url;
} *jabpf, _jabpf;

#define JABPF_TYPE 1
#define JABPF_NAME 2
#define JABPF_DESCRIPTION 3
#define JABPF_EMAIL 4
#define JABPF_URL 5

void jabpf_set(jabc j, int element, char *value);
void jabpf_ask(jabc j, char *user);
void jabpf_free(jabpf pf);


#endif	/* __JAB_H */
