/*--------------------------------------*/
#include <sys/time.h> //select
#include <unistd.h> //select,alarm
#include <fcntl.h>
#include <openssl/des.h>
#include <openssl/sha.h>
#include <math.h>
#include <arpa/inet.h>
#include "signals.h"
#include "sockets.h"
#include <sys/ipc.h> 
#include <sys/shm.h>
/*--------------------------------------*/
//#define ADMIN_IP "lyre.ctr.columbia.edu"
#ifndef ADMIN_IP
#define ADMIN_IP "128.59.67.27"
#endif

#define ADMIN_PORT 60000
#define GRP_LEN 3
#define CHAT_PORT 60001
#define IPC_PORT 60002
#define MAX_USERS 128
//#define DEPTH (int)(log(MAX_USERS)/log(2))+1
#define DEPTH 7
#define KEY_LEN 8
#define BLK_LEN 8
#define MSG_LEN 1024
#define ADDR_LEN 15
/*--------------------------------------*/
/*------------------------*/
/** CHAT MESSAGE STRUCTS **/
/*------------------------*/

typedef enum chat_msgs {
  JOIN_REQ=0x10,
  VER_UPDATE=0x01,
  REV_UPDATE=0x02,
  CHAT_DATA=0x03,
  JOIN_KEYS=0x04,
  JOIN_MEMS=0x05,
  COMPLAINT=0x06,
  LEAVE=0x07,
  DESTROY=0x08
} chat_msg;

/* key descriptor format */
typedef struct keydesc {
  unsigned char kid;
  unsigned char ver;
  unsigned char rev;
} kd;

/* keys struct  */
typedef struct {
  struct keydesc desc;
  unsigned char key[KEY_LEN];
} node;

/* member list */
typedef struct list {
  unsigned char addr[ADDR_LEN];
  unsigned char kid;
  struct list *lnk;
} members;

/* join request message */
typedef struct {
  unsigned char type;
  unsigned char key[8];
} join_req_msg;

/* member list message */
typedef struct {
  unsigned char type;//msg type
  unsigned char entries;//users in this msg (max=67)
  unsigned char num_users;//tot. users
  unsigned char num_msgs;
  /* user IPs: unsigned char[ADDR_LEN] */
} mem_list_msg;

/* key list message */
typedef struct {
  unsigned char type;//msg type
  unsigned char kid;
  unsigned char num_keys;//keys in this msg (W-1)
  /* node keys: <struct kd,unsigned char[KEY_LEN]> */
} key_list_msg;

/* key version change message */
typedef struct {
  unsigned char type;
  unsigned char lmem[ADDR_LEN];
  unsigned char num_keys;//(2*W-1)
  /* node keys */
} key_ver_msg;

/* key revision change message */
typedef struct {
  unsigned char type;
  struct keydesc desc;
  unsigned char jmem[ADDR_LEN];
} key_rev_msg;

/* chat data message */
typedef struct {
  unsigned char type;
  struct keydesc desc;
  unsigned char data[980];
} data_msg;

/* complaint message */
typedef struct {
  unsigned char type;
  struct keydesc desc;
  unsigned char mem[15];
} complaint_msg;
/*------------------------*/
/** ADMIN MESSAGE STRUCTS */
/*------------------------*/

typedef enum admin_msgs {
  GRP_QUERY=0x01,
  GRP_REPLY=0x02,
  REG_QUERY=0x03,
  REG_REPLY=0x04,
  GM_RESIGN=0x05
} admin_msg;

typedef struct grp_query {
  unsigned char type;
  unsigned char grp[3];
} grp_query_msg;

typedef struct grp_reply {
  unsigned char type;
  unsigned char grp[3];
  unsigned char addr[15];
} grp_reply_msg;

typedef struct reg_query {
  unsigned char type;
  unsigned char grp[3];
  unsigned char addr[15];
} reg_query_msg;

typedef struct reg_reply {
  unsigned char type;
  unsigned char flag;
  unsigned char grp[3];
  unsigned char addr[15];
} reg_reply_msg;

typedef struct gm_resign {
  unsigned char type;
  unsigned char grp[3];
} gm_resign_msg;

    
/*--------------------------------------*/
int add_fail_flag=0,gm_flag=0;
int mem_ctr=0,n_s_ipc;
members *active=NULL;
//node keys[DEPTH+1];//(non-GM)
node *keys;//(non-GM)
//node keys[8];//(non-GM)
//node *tree[DEPTH+1];//(GM)
//node **tree;//(GM)
node *tree[8];//(GM)
unsigned char my_ip[16];
pid_t pid=0;
unsigned char gm[ADDR_LEN+1],skey[KEY_LEN];
/*--------------------------------------*/
void StartUp(unsigned char*);
void Join_Group();
void Chat(unsigned char*);
void Who_Is_GM(int*,unsigned char*);
void Add_Active_Member(unsigned char*,unsigned char);
void GM_Initialize_Key_Tree();
void Generate_Key(unsigned char*);
void Handle_Msg(unsigned char*,unsigned char*,int,unsigned char*);
void Send_Join_Keys(unsigned char*,unsigned char,int);
void Send_Join_Mems(unsigned char*,unsigned char,int);
void Send_Key_Rev_Update(unsigned char*);
void Handle_Complaint(unsigned char*,unsigned char*,int);
void Send_Key_Ver_Update(int,unsigned char*);
unsigned char GM_Add_Key(unsigned char*);
void GM_Remove_Key(int);
int Is_Valid_Member(unsigned char*,unsigned char*);
void Update_Keys(unsigned char*);
void Encrypt(unsigned char,unsigned char*,int);
void Decrypt(unsigned char,unsigned char*,int);
int Remove_Member(unsigned char*);
void Destroy_Group(unsigned char*);
void Display(unsigned char*,unsigned char*);
void Send_To_Group(unsigned char*,int,int);
void Send_Complaint(unsigned char*);
void Hash_Keys();
void Send_Leave(unsigned char*);
void Debug_Msg(unsigned char*,int);
void charncpy(unsigned char*,unsigned char*,int);
/*--------------------------------------*/
