/***************************************************************************
 *   Copyright (C) 2004 by Johnny Mast                                     *
 *   rave@linux                                                            *
 *                                                                         *
 *   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.             *
 ***************************************************************************/

#include "../global.h"


struct _n
{
	char *nick;
	char *why;
	char *name;
};



int irc_do_user(void);
int irc_do_nick(void);
int irc_do_users(void);
int irc_do_list(void); 
int irc_do_join(void); 
int irc_do_part(void); 
int irc_do_topic(void); 
int irc_do_version(void);
int irc_do_invite(void);
int irc_do_kick(void); 
int irc_do_names(char *room,int fd);
int irc_do_whois(void); 
int irc_do_who(void); 
int irc_do_away(void);
int irc_do_mode(void);
int irc_do_nmode(void);
int irc_do_privmsg(void);
int irc_do_notice(void);
int irc_do_quit(void);
int irc_names(void);
int irc_do_time(void);
int irc_do_info(void);	
int irc_do_vhost(void);	
int irc_do_ircop(void);
int irc_do_admin(void); 	
int irc_do_ping(struct __user *user,char *server);
int irc_do_pong(struct __user *user,char *server,char *what);
int irc_do_links(void);
int irc_do_ison(void);
int irc_do_knock(void);




extern void core_do_version(struct __user *_usr);
extern int core_motd(struct __user *_usr, int type);
extern int core_welcome(struct __user *_usr);
extern int i_who_line(struct __room *rm, struct __user *usr,int isroom,char *modes,char *line);
extern int i_int_modes(char *modes,int type);
extern struct _invites *i_invitelist(struct _invites *inv,char *room,char *line);
extern struct _bans *i_banlist(struct _bans *ban,char *room,char *line);
extern char *i_createident(struct __user *usr); // NA KIJKEN
extern int i_msgtarget ( char *target );
extern char * i_usertypeExtent(struct __user *_usr);
extern char * i_usertype(int mode);
extern char *i_charmode(int mode, int type); 
extern int i_userprefix(int mode);
extern char *i_globcharmodes(int modes, int type);
extern int i_uspref(char modes);
extern char ** s_splitcmd(char *string);
extern char *s_upercommand(char *string);
extern int msg_room (char *thisuser, char *room,const char *fmt, ...);
extern int msg_build ( int sock, int flags, const char *fmt, ... );
extern int msg_user_rooms (char *nick,char *thisuser,const char *fmt, ...);
extern int msg_user (char *user, char *fmt, ... );
extern int msg_raw ( int sock, int flags, const char *fmt, ...);
extern int s_findchars ( char *thisc, char *inhere );
extern int s_countargc(char **argv);
extern struct __user *usdb_getstart ( void );
extern int s_strnlen(char *string, size_t max);
extern struct __room * rmdb_getstart (void);
extern int rmdb_room_has_user( char *room, char *user);
extern char *i_createident(struct __user *usr);
extern char * rmdb_user_show ( char *room);
extern struct _kline *kdb_find_kline(struct __user *user);
extern struct __user  * usdb_find_user (char *Nick );
extern struct _rdb_usrs *rmdb_room_find_user(char *room,char *user);
extern int i_uspref(char modes);
extern struct __room * rmdb_find_room ( char *room );
extern struct _invites *rmdb_add_invite(char *invite_by, char *invited,char *to_room);
extern int i_who_line(struct __room *rm, struct __user *usr,int isroom,char *modes,char *line);
extern int ircSprintf(char *dest, char *fmt, ...);
extern int i_int_modes(char *modes,int type);
extern struct _bans *i_banlist(struct _bans *ban,char *room,char *line);
extern int rmdb_clean_room_key(char *room);
extern int rmdb_set_room_key( char *room, char *key);
extern int rmdb_room_setban(char *room, char *setby, char *banmode);
extern int rmdb_free_ban(char *room, char *user);
extern int rmdb_user_leave ( char *room , char *user );
extern int rmdb_user_leaves_all(char *user);
extern int rmdb_user_join ( char * room , char *User,int modes);
extern int rmdb_room_has_modes ( char *room, int modes);
extern struct __room *rmdb_new_room (char *name, char *user );
extern struct _invites *rmdb_find_invite(char *room,char *user);
extern struct _bans *rmdb_find_ban ( char *room, struct __user *usr);
extern struct _invites *rmdb_find_invite(char *room,char *user);
extern int rmdb_free_invite(char *user,char *room);
extern int rmdb_change_topic ( char *room, char *user, char *topic );
extern int i_msgtarget ( char *target );
extern int usdb_free_user ( char *user  );
extern int rmdb_count_rooms (void);
extern int sdb_count(void);
extern char * i_usertype(int mode);
extern char * i_usertypeExtent(struct __user *_usr);
extern void usdb_count_users(int *globop,int *locop,int *globadm,int *locadm);
extern struct _vhost *vhost_find(char *user);
extern char *s_upperstring(char *string);
extern FILE *f_open ( char *file, char *mode );
extern char *f_read ( FILE *fd, char *dst, size_t max);
extern int f_close (FILE *fd);
extern int msg_privilaged_notice(const char *fmt, ... );
extern char *s_timestr (time_t timevar);
extern int new_who(char *nick, char *user, char *host, char *serv,char *rname,time_t j_time);
extern int irc_command ( char * message, struct __user *us );
extern int err_send(int sock, char *fmt, ... );
extern char *sdb_finddisc(char *server);


extern int TS5_USERMESG ( const char *fmt, ...);
extern int TS5_gosend(char *to,char *msg);
extern int TS5_tellnick(struct __user *usr);
extern int TS5_telljoin(struct __room *room, char *user);
extern int TS5_tellsethost(char *user, char *host);
extern int TS5_tellversion( char *user );
extern int TS5_tellnewnick ( char *user, char *msg );


extern struct __user *_usr ; 
extern char *msg;

int irc_do_pass ( void )
{
char **argv;
int argc;


if (!(argv = ALLOCATE(char **)))
	return -1; // close connection,

if (!(argv=s_splitcmd(msg)))
	return err_send(_usr->fd,"ERROR :Closing Link: %s (PASS Command incomplete)",_usr->IP);

if ((argc = s_countargc(argv)) < 1)
	return err_send(_usr->fd,"ERROR :Closing Link: %s (PASS Command incomplete)",_usr->IP);
 

_usr ->serv_p = strdup(argv[2]);



return 0;
}
int irc_do_nick ( void )
{
struct __user *usrdb;
struct __room *rm;
char *name;

/*
TODO:             
                          
		   ERR_NICKCOLLISION
           ERR_UNAVAILRESOURCE             
		   ERR_RESTRICTED
		   ERR_NICKTOLONG

TO Fix:
		   RETURN -1 if user db is empty
		  
*/   

	/* Was the NICK command used correctly 
	** if there is no nick given return error
	** NO NICK NAME GIVEN
	*/
	if ( strlen ( msg ) < 6)
		return msg_build(_usr ->fd,0,IRC_NO_NICK);



	/* Here we check for chars that are not allowed 
	** in a nick name.
	** If it contains a forbidden char 
	** ERRONEUS NICKNAME
	*/
	if ( s_findchars ("@&%!$*()/<>.,?'",msg) == 0 )
		return msg_build(_usr->fd,0,IRC_INVALID_NICK," ");
	

	/* We have to know if the username isnt already registered 
	** if it is return error NICKNAME IN USE
	*/
	// moet dit wel ?? als de db leeg is faalt het altijd
	usrdb = usdb_getstart();
	if (!usrdb)
	{
		printf("usdb error\n");
		return -1;
	}


	name = msg +5;

	if ( name[0] == ':' )
		name ++;


	WALKDB(usrdb)
	{
	  if (usrdb->Nick != NULL)
		if ( (strcmp ( name, usrdb->Nick)) == 0)
			return msg_build(_usr->fd,0,IRC_INUSE_NICK);
	
	}



	/* Check if the Nickname isnt to long */
	if ( s_strnlen(name,MR) > config->n_len )
		 return msg_build(_usr->fd,0,IRC_INVALID_NICK, " ");
	

	

	
	/* if the user is registered he wants to change its nick */
	if ( _usr ->registered == YES)
	{
	  if (!(rm = rmdb_getstart()))
			return -1;
	
	if ( _usr ->n_change >= config->m_nc )
			return -1;

	WALKDB(rm)
	{
	 if (rmdb_room_has_user(rm->name,_usr->Nick))
		 msg_room(_usr->Nick,rm->name,IRC_NICK,_usr->ident,msg);
	}

	 msg_raw(_usr->fd,0,IRC_NICK,_usr->ident,msg);

	TS5_tellnewnick(_usr ->Nick,msg);

	 new_who(_usr->Nick, _usr->username, _usr->Host, _usr->conn_to,_usr->Real_Name,_usr->Join_time);


	_usr ->Nick = strdup(name);
	_usr ->ident = i_createident(_usr);
	_usr ->n_change ++;
	return 0;
	}

	/* Else if the user is logged in, add the nickname to 
	** user database
	*/
	_usr ->Nick = strdup ( name );

	
	if ( _usr->Real_Name && strlen(_usr ->Real_Name) > 0 )
	{ 
	
		_usr ->registered  =  YES;
		core_welcome(_usr);
	}

	return 0;
}

int irc_do_names(char *room,int fd)
{
char **a,*users,*rm;
int ret;


if ( fd == 0 )
	fd = _usr->fd;

if ( !room)
{

	
	if (!(a = ALLOCATE(char **)))
		return printf("error");

	a = s_splitcmd(msg);
	ret = s_countargc(a);
	
	if ( ret < 1 )
		return msg_build(fd,DEBUG_NONE,IRC_ENDOF_NLIST,
												_usr->Nick,
												"");
;

		users = rmdb_user_show (a[1]);
		if ( !users) users = "";
		rm = a[1];
		;
} else 
{ 
	users = rmdb_user_show (room);
	if ( !users) users = "";
	rm = room;
}
	if (!rmdb_room_has_user(rm,_usr->Nick) && HIGH_PRIVS(_usr->globmode))
	msg_build(fd,DEBUG_NONE,IRC_JOIN_NLIST,
												_usr->Nick,
												rm,
												users);
	
	
	if (rmdb_room_has_user(rm,_usr->Nick))
		msg_build(fd,DEBUG_NONE,IRC_JOIN_NLIST,
												_usr->Nick,
												rm,
												users);
	
	return msg_build(fd,DEBUG_NONE,IRC_ENDOF_NLIST,
												_usr->Nick,
												rm);
;
}


int irc_do_user ( void ) 
{
struct _kline *kline;
char **a, tmp [128],*ptr = NULL; 
int y,x=y=0;
int len,argc;

/*
TODO:             
                          
		   

TO Fix:
	Bij 1 user cmd crashed the daemon HEAP related
	  ... ...

*/   



	len = strlen (msg);
	clean(tmp);

		if ( len <= 5)
	     return msg_build(_usr->fd,0,IRC_USER_NEED_MORE);
	

	if ( (a = ALLOCATE ( char **)) == NULL )
		return msg_build(_usr->fd,0,IRC_USER_NEED_MORE);


	do
	{


	 if ( *msg  == 0x20 )
	  {
		  tmp [strlen(tmp)] = '\0';
		  a[y] = strdup ( tmp );
		  memset ( tmp, '\0', sizeof (tmp));
		  x=0;
		  ++y;
	  }



	   tmp[x] = *msg;
	   ++x;
	   msg ++;


	} while ( ((*msg != '\0') && ( x < len -1 ) && ( y < 4) ));

	
	if (msg [0] == ':' )
		++msg;

	a[5] = NULL;
	a[4] = strdup (msg);
    argc = s_countargc(a); 
	if ( argc < 4)
	  return msg_build(_usr->fd,0,IRC_USER_NEED_MORE);

	/* It might be possible that a user is already logged in
	** and he try`s to use the USER command again.
	** We dont want the user to change its info when it is already
	** set this is not allow acording to the rfc papers.
	** If the user is logged in error ALREAD REGISTERED will be 
	** returned.
	*/
	if ( _usr ->registered == YES )
		return msg_build(_usr->fd,0,IRC_USER_ALREADYREG);;
	
	/***********************************
	 *
	 * a[0] == The command "USER"
	 * a[1] == Username
	 * a[2] == User mode 
	 * a[3] == Unused ..
	 * a[4] == Real name;
	 ***********************************/
	 
	if ( !_usr)
		return msg_build(_usr->fd,0,IRC_USER_NEED_MORE);


	if ( s_findchars ("@&%!$*().,?'",a[1]) == 0 )
		return msg_build(_usr->fd,0,IRC_USER_NEED_MORE);

	

	_usr ->Real_Name =  strdup(a[4]); 
	
	a[1] ++;
	_usr ->username  =  strdup(a[1]);
	

	if ( _usr ->Nick)
	{
		_usr ->registered = YES;
	
	if ( (kline = kdb_find_kline(_usr)))
	{
	
		if ( (strstr(_usr->Host,kline->host)) && (strstr(_usr->Nick,kline->user) || strstr(_usr->username,kline->user)))
		{
		msg_raw(_usr->fd,0,IRC_AUTH_KLINE,kline->message);
		return irc_do_kill(_usr->Nick,kline->message);

		} else if ( (kline ->host[0] == '*') && (strstr(_usr->Nick,kline->user) || strstr(_usr->username,kline->user))) 
			return core_welcome(_usr);
		
		
		else if ( !(strstr(_usr->Host,kline->host)) && (strstr(_usr->Nick,kline->user) || strstr(_usr->username,kline->user)))
			return core_welcome(_usr);
		
		else if ( !(strstr(_usr->Host,kline->host)) && (strstr(_usr->Nick,kline->user) || strstr(_usr->username,kline->user)) )  
		{
		
			msg_raw(_usr->fd,0,IRC_AUTH_KLINE,kline->message);
			return irc_do_kill(_usr->Nick,kline->message);
	
		} else if ( (strstr(_usr->Host, kline ->host)) && kline->user[0] == ':') {
			msg_raw(_usr->fd,0,IRC_AUTH_KLINE,kline->message);
			return irc_do_kill(_usr->Nick,kline->message);
	
		} 
		else if ( kline ->host[0] == '*' ) {
		
			msg_raw(_usr->fd,0,IRC_AUTH_KLINE,kline->message);
			return irc_do_kill(_usr->Nick,kline->message);
	
			
		}
		
	}

	
	TS5_USERMESG(TS5_GCONNECT,netw->net_addr,_usr ->Nick,_usr->username,_usr->Host,_usr->IP,_usr->Real_Name);
	
	TS5_tellnick(_usr);
	
	core_welcome(_usr);
	
	TS5_tellsethost(_usr->Nick,_usr->Vhost);
	new_who(_usr->Nick, _usr->username, _usr->Host, _usr->conn_to,_usr->Real_Name,_usr->Join_time);

	}

	return 0;
}


int irc_do_away(void)
{
char *message=NULL;



	if (s_strnlen(msg,MR) >=5 )
		  message = msg+5;

	if (message){
	if (message[0] == ':') message++;
        _usr->away_msg = strdup(message);
	} else 
		 _usr ->away_msg = strdup ("+Away+");



	if (ISUSED(_usr->globmode,USER_NORMAL_HERE)) {
		printf("zetten away\n");
		
		_usr ->globmode -= USER_NORMAL_HERE;
		_usr ->globmode |= USER_NORMAL_AWAY;

		msg_build(_usr->fd,0,IRC_AWAY_MARK, _usr->Nick);
	

	} else 
	if (ISUSED(_usr->globmode,USER_NORMAL_AWAY)) { 
		_usr ->globmode -= USER_NORMAL_AWAY;
		_usr ->globmode |= USER_NORMAL_HERE;

		free(_usr->away_msg);
		_usr->away_msg=NULL;
		msg_build(_usr->fd,0,IRC_AWAY_NOMARK, _usr->Nick);
	}
	
	TS5_USERMESG(TS5_AWAY,_usr->Nick,msg);
	return 0;

}



// whois <server> <nickname>
int irc_do_whois(void)
{
struct __user *usr;
struct __room *rm;
struct _rdb_usrs *db;

char *user, modeline[MR],mod,mode[MR],*disc;
int rooms,higher;

/* If we dont have a name to whois 
** return the NO SUCH user error string.
*/
if ( s_strnlen(msg,MR) >= 7)
	user = msg + 6;
		else return msg_build(_usr->fd,0,IRC_WHOIS_NOSUCH,_usr->Nick,"*");


/* Checking if our user exists 
** it is doesnt return the NO SUCH user error string.
*/
usr = usdb_find_user(user);
if (!usr)
	return msg_build(_usr->fd,0,IRC_WHOIS_NOSUCH,_usr->Nick,user);

/* Check if the user has some kind of higher privilages */
higher = HIGH_PRIVS(_usr->globmode);

/* Ok the user we are about to whois has been found.
** Lets collect some info 
*/
msg_build(_usr->fd,0,IRC_WHOIS_IDENT,_usr->Nick,usr->Nick,usr->username,usr->Vhost,usr->Real_Name);


if ( higher ) {


  
msg_build(_usr->fd,0,IRC_WHOIS_MODES,_usr->Nick,usr->Nick, 
		  i_globcharmodes ( usr->globmode, IRC_USER_GLOBAL),
		  i_globcharmodes ( usr->globmode, IRC_HUSER_FLAGS)
		  
		  );

msg_build(_usr->fd,0,IRC_WHOIS_HOST,_usr->Nick,usr->Nick, 
		  usr->Host,usr->IP);


}


/* Building a list of rooms this user is in and his/hers modes
*/
rooms = usr->rooms;
rm = rmdb_getstart();
clean(modeline);
clean(mode);
WALKDB(rm)
{

	if ( (strlen(rm->name)+1) + strlen(modeline) >= MR) 
		break;


	if (!ISUSED(rm->modes, ROOM_SECRET) || HIGH_PRIVS(_usr->globmode)){

	db = rmdb_room_find_user(rm->name, usr->Nick);
	if ( db != NULL)
	{
		clean (modeline);
		mod=i_userprefix( db->modes );
			  if (mod !=0 ) 
				modeline[0]= mod;
		
		if ( (strlen (rm->name) +2) >= sizeof(mode))
			 break;

		strcat (modeline,rm->name);
		strcat (modeline, " ");
		strcat (mode, modeline);
		
	
	

	}

	}
}

if ( usr ->rooms > 0 )	
msg_build(_usr->fd,0,IRC_WHOIS_RMODES,_usr->Nick,usr->Nick,mode);

if (!(disc = sdb_finddisc(_usr->conn_to)))
	disc = _usr->conn_to;


msg_build(_usr->fd,0,IRC_WHOIS_CONECTEDTO,_usr->Nick,usr->Nick,usr->conn_to,disc);

  if (ISUSED(usr->globmode,LOCAL_OPER))	            
  msg_build(_usr->fd,0,IRC_USER_TYPE,_usr->Nick,usr->Nick,"Local Operator");

  if (ISUSED(usr->globmode,NET_OPER))	            
  msg_build(_usr->fd,0,IRC_USER_TYPE,_usr->Nick,usr->Nick,"Global Operator");


  if (ISUSED(usr->globmode,GUEST_ADMIN))	        
  msg_build(_usr->fd,0,IRC_USER_TYPE,_usr->Nick,usr->Nick,"Guest Administrator");

  if (ISUSED(usr->globmode,SERV_CO_ADMIN))	    
  msg_build(_usr->fd,0,IRC_USER_TYPE,_usr->Nick,usr->Nick,"Server CO Administrator");

  if (ISUSED(usr->globmode,SERV_ADMIN))	
  msg_build(_usr->fd,0,IRC_USER_TYPE,_usr->Nick,usr->Nick,"Server Administrator");

  if (ISUSED(usr->globmode,NET_CO_ADMIN))	
  msg_build(_usr->fd,0,IRC_USER_TYPE,_usr->Nick,usr->Nick,"Global CO Administrator");

 if (ISUSED(usr->globmode,NET_ADMIN))	
  msg_build(_usr->fd,0,IRC_USER_TYPE,_usr->Nick,usr->Nick,"Global Administrator");

  if (ISUSED(usr->globmode,USER_SSL))	
  msg_build(_usr->fd,0,IRC_USER_TYPE,_usr->Nick,usr->Nick,"User connected to with ssl");

  if (ISUSED(usr->globmode,USER_NORMAL))	
  msg_build(_usr->fd,0,IRC_USER_TYPE,_usr->Nick,usr->Nick,"Normal");


msg_build(_usr->fd,0,IRC_WHOIS_TIMES,_usr->Nick,usr->Nick,time(NULL) - usr->IDLE,usr->Join_time);


if (ISUSED(usr->globmode,USER_NORMAL_AWAY)) 	
msg_build(_usr->fd,0,IRC_WHOIS_AWAY,_usr->Nick,usr->Nick,usr->away_msg);


msg_build(_usr->fd,0,IRC_WHOIS_END,_usr->Nick,usr->Nick);


if (CAN_PROTOPER(usr->candomode))
	msg_build(usr->fd,0, IRC_WHOIS_ONYOU,usr->Nick,_usr->Nick,_usr->ident);


return 0;
}



// TS5 invite
int irc_do_invite (void)
{
struct __room *rm;
struct __user *usr;
char **a;
int ret;

	a = ALLOCATE(char **);

	if (!a)
		printf("malloc failed\n");

	clean(a);
	a = s_splitcmd(msg);

	ret = s_countargc (a);
	if ( ret != 2)
		return printf("no enough parameters\n");

	/****************************
	** a[1] user to invite
	** a[1] room to invite him to 
	*/

	if ( (usr = usdb_find_user(a[1])) == NULL)
			return msg_build(_usr->fd,0,IRC_INVITE_ALREADY_IR,_usr->Nick,a[1]);

	if ( ( rm = rmdb_find_room(a[2])) == NULL)
			return msg_build(_usr->fd,0,IRC_INV_NOSUTCH_ROOM,_usr->Nick,a[2]);

	if ( rmdb_room_has_user(rm->name,usr->Nick))
			return msg_build(_usr->fd,0,IRC_WHOIS_NOSUCH,_usr->Nick,a[2]);
	


	/* sending status message to the invitor */
	msg_build(_usr->fd,0,IRC_INVITE_INVITOR,_usr->Nick,usr->Nick,rm->name);

	/* sending message to invited */
	msg_raw (usr->fd,0,IRC_INVITE_INVITED,_usr->ident,msg);
	printf("invite %s to %s %d\n",a[1],a[2],ret);
	
	/* Add user to the invited list on the channel */
	rmdb_add_invite(_usr->Nick,usr->Nick,rm->name);
	
	/* Get rid of the allocated memory */
	FREE_AREA(a,ret);

return 0;
}

int irc_do_who(void)
{
struct __room *rm;
struct __user *usr;
struct _rdb_usrs *db;

char *wildcard;
char line [MR],modes[MR];
char *query;

int higher,hopcount=1,len,isroom;

higher = HIGH_PRIVS(_usr->globmode);


query = wildcard = msg + 4;
len = s_strnlen(msg,MR);


if ( len > 5 && query[0] != '*' )
{

	isroom = (rm = rmdb_find_room(query)) ? WHO_ROOM : \
			 (usr = usdb_find_user(query)) ? WHO_USER : 0; 


	if ( isroom == WHO_ROOM && rm == NULL)
	goto _end;
	else if ( isroom == WHO_USER && usr == NULL)
	goto _end;

	if ( isroom == WHO_ROOM )
	{
		db = (struct _rdb_usrs *)rm ->preset->_rdbs;
	WALKDB(db)
	{
		clean(line);
		clean(modes);
		usr = db->_usr;
	
		if ( !ISUSED(usr->globmode,USER_NORMAL_AWAY) && !ISUSED(usr->globmode,USER_NORMAL_HERE))
					 usr ->globmode |= USER_NORMAL_HERE;

		strcat ( modes, i_charmode(db->modes,isroom));
		strcat ( modes, i_charmode(usr->globmode,0));

		i_who_line(rm,usr,isroom,modes,line);
		msg_build(_usr->fd,0,IRC_WHO_LINE,_usr->Nick,line);
	}


	}  else if ( isroom == WHO_USER ) {

		if ( usr ->u_type == USER_LINKED || usr ->u_type == USER_BRIDGE)
			  goto not_this_user;

		clean(modes);

		if ( !ISUSED(usr->globmode,USER_NORMAL_AWAY) && !ISUSED(usr->globmode,USER_NORMAL_HERE))
					 usr ->globmode |= USER_NORMAL_HERE;

		strcat ( modes, i_charmode(usr->globmode,isroom));

		i_who_line(NULL,usr,isroom,modes,line);
		msg_build(_usr->fd,0,IRC_WHO_LINE,_usr->Nick,line);
	
not_this_user:;
	} 

	}



if ( higher )
{
	wildcard ++;
	


	
	usr = usdb_getstart();
	if (!usr) 
		goto _end;

	WALKDB(usr)
	{
	clean(modes);
	clean(line);

	if ( strstr(usr->ident,wildcard) ) {
	clean(modes);
	strcat ( modes, i_charmode(usr->globmode,WHO_USER));
	i_who_line(rm,usr,isroom,modes,line);
	
	} else if ( len == 4 ) {
	clean(modes);
	clean(line);
	strcat ( modes, i_charmode(usr->globmode,WHO_USER));
	i_who_line(rm,usr,isroom,modes,line);
	}

	if (usr ->u_type == USER_LOCAL || usr ->u_type == USER_LINKED)
	msg_build(_usr->fd,0,IRC_WHO_LINE,_usr->Nick,line);
	}

}

_end:
msg_build(_usr->fd,0,IRC_WHO_END,_usr->Nick, (len ==3 ) ? "" : query);
 /* Show the whole users list if this user if oper*/
//i_charmode

return 0;
}







static void irc_room_mode ( struct __room *rm )
{
char *mode;
char tmp[MR];

if ( !rm )
	return ;

if ( rm ->name <= 0 )
	  mode = strdup (" ");
	else 
	  mode = strdup( i_globcharmodes ( rm->modes, IRC_ROOM_MODES) );
		
if ( rmdb_room_has_user(rm->name,_usr->Nick) ){


		if ( ISUSED(rm->modes, ROOM_KEY_PROT )) {
		clean(tmp);
		ircSprintf(tmp," %s",rm->key); 
		strcat ( mode, tmp); }


	

	if ( ISUSED(rm->modes, ROOM_LIMIT )) {
		clean(tmp);
		ircSprintf(tmp," %d",rm->limit); 
		strcat ( mode, tmp); }
}
	
	msg_build(_usr->fd,DEBUG_LOG,
		  IRC_MODE_ROOM_QUERY,_usr->Nick,rm->name,mode);

	msg_build(_usr->fd,DEBUG_LOG,
		  IRC_MODE_ROOM_QUERY2,_usr->Nick,rm->name,rm->C_Time);




}


/*
** Mode query nog fixen
** Room mode change nog fixen
** Error messages
*/
// voice werkt niet
// als er in een room een nieuwe mode word gezet moet de oude worden gewist !!

int irc_do_mode (void)
{
struct __room *rm;
struct __user *usr;
struct _bans  *bn;
struct _invites *inv;
struct _rdb_usrs *rusr;

char **a,mode[MR],line[MR];


int ret,argc,limit;
int mnotice,muser;


	if (!(a = ALLOCATE(char **)))
	 return -1; 


	a = s_splitcmd ( msg );
	
	
	argc = s_countargc (a); 
	if ( argc < 1)
		return msg_build(_usr->fd,0,IRC_MODE_NEED_MORE,_usr->Nick);

	/*
	** Check if requested user is around 
	*/
	if ( (usr=usdb_find_user(a[1])) != NULL)
	{
		
			if (argc == 1)
			{
				ircSprintf(mode , "%s",
					i_globcharmodes ( _usr->globmode, IRC_USER_GLOBAL)
				);
				
				
				return msg_build(_usr->fd,0,IRC_MODE_USER_QUERY,_usr->Nick,mode);
			}

	
		/*
		** check if user has the right to change the mode of an other user 
		*/
		if ( ((strcmp(a[1], _usr->Nick)) ==0) && ( argc == 2 ) )
		  {
				

		if ((HIGH_PRIVS(_usr->globmode)))
		{
			
			switch (a[2][1]){
			
			case 'o':
				printf("-o\n");
			break;

			case 'O':
				printf("-O\n");
			break;

			case 'A':
				printf("-A\n");
			break;

			case 'S':
				printf("-A\n");
			break;

			default:
			break;

			}
			
			

		}
		 
	   /* -= O:Line operator Modes =-
		*--- +c Can see connect notices
		*--- +C Can see /CHATOPS notices
		*--- +d Can see debug notices
		*--- +f Can see exess flood notices
		*--- +F Can see global connect notices
		*--- +n Can see /NETINFO and routing notices
		*--- +p Protected irc operator
		*--- +W Can see /WHOIS notices
		*/
			
			ret = s_findchars("cCdfFnpWw",a[2]+1);
			if ( (ret != -1) && HIGH_PRIVS(_usr->globmode))
			{
				mnotice = muser = 0;

				muser = i_int_modes(a[2],IRC_USER_GLOBAL);

				if ( HIGH_PRIVS(_usr->globmode))
				mnotice = i_int_modes(a[2],IRC_NOTICE_FLAGS);


				if (a[2][0] == '+' ) {
				usr ->globmode |=ret;
				usr ->noticeflags |= mnotice;

				} else if (a[2][0] == '-') {
				usr ->globmode -=ret;
				usr ->noticeflags -= mnotice;

				}
				
				printf("user did mode as opper");
			

			} 
			 /*
			  ** Mode Doesnt return any errors
			  */

		   /* -= mode available for all users =- 
			* --- +i  Invisible (Hidden in /WHO)
			* --- +k  Can see server originating kill notices
			* --- +s  Can see server notices
			* --- +w  Can see /WALLOPS notices
			*/
			ret = s_findchars("iksw",a[2]);
			if ( ret != -1)
			{
				ret = i_int_modes(a[2],IRC_USER_GLOBAL);
				
				if (a[2][0] == '+' )
				usr ->globmode |=ret;
				else 
				usr ->globmode -=ret;
				
				printf("chaning user mode to %d\n",ret);

			} 
			
			/*
			** Mode Doesnt return any errors
			*/




			printf("change own mode\n");
			return 0;

		} else if ( ((strcmp(a[1], _usr->Nick)) ==0) && ( argc == 3 ) ){
			
			printf("change own mode in a room\n");
			return 0;

		} 		else if ( ((strcmp(a[1], usr ->Nick)) == 0) && ( argc == 3) )
		  {
			ret = HIGH_PRIVS(_usr->globmode);
				 
			/*
			** if ret == 1 the is TRUE
			*/
			if ( ret == 1 )
				printf("user can change other users mode\n");
			else 
				printf("user can NOT change other users mode\n");
		  
			/* Lets check if whe want to change our own mode */
		  } 
		  
	} else if ( ((rm = rmdb_find_room(a[1])) !=NULL) && argc == 1) {
			irc_room_mode(rm);
	} else if ( ((rm = rmdb_find_room(a[1])) !=NULL) && argc == 2 )
	{
		ret = i_int_modes(a[2]+1,IRC_ROOM_MODES);
		
		// in rmdb toevoegen rmdb_add_usr_ban
		// error messages
		
		/* The user is asking us to return the 
		** banned user list to him so lets do it 
		*/

		if (a[2][1] == 'b')
		{
			
			bn = rm ->preset->ban_start;
			while (bn=i_banlist(bn,a[1],line)) {


			msg_build(_usr->fd,0,IRC_BAN_LIST,_usr->Nick,line);
			clean(line);
			bn = bn->Next;
			}

		/* Sending Message end of user ban list */
		return msg_build(_usr->fd,0,IRC_BAN_END,_usr->Nick,rm->name);	
		}


		if (rmdb_room_has_user(rm->name,_usr->Nick) )
		{
			
		   rusr = rmdb_room_find_user(rm->name,_usr->Nick);
		   if (!HIGH_ROOM(rusr->modes) )
				 return msg_build(_usr->fd,0,IRC_MODE_NOPRIVS,usr->Nick,rm->name,_usr->Nick);
     
		} 

		/* The user is asking us to return the 
		** invited user list to him so lets do it 
		*/
		if (a[2][1] == 'I')
		{
			inv = rm->preset->invite_start;
	
			clean(line);
			while (inv=i_invitelist(inv,a[1],line)) {


			msg_build(_usr->fd,0,IRC_INVITE_LIST,_usr->Nick,line);
		
			clean(line);
			inv = inv->Next;
			}

		/* Sending Message end of user ban list */
		return msg_build(_usr->fd,0,IRC_INVITE_END,_usr->Nick,rm->name);	
		}

		if ( ret == 0 )
			return msg_build(_usr ->fd,0,IRC_MODE_ERRMODE,_usr->Nick,rm->name,a[2]+1);

		if (a[2][0] == '+' )
				rm ->modes |=ret;

		else if (a[2][0] == '-')
				rm ->modes -=ret;
		
	
		if (TS5_LOCAL(_usr ->u_type) )
		  TS5_USERMESG(IRC_MODE,_usr ->Nick,msg);
		msg_room(NULL,a[1],IRC_MODE,_usr ->ident,msg);
		printf("room mode change %s\n",a[2]);

	} else if ( ((rm = rmdb_find_room(a[1])) !=NULL) && argc == 3 )
	{
		usr = _usr;
		if ( rmdb_room_has_user(rm->name,usr->Nick) ){
		rusr = rmdb_room_find_user(rm->name,usr->Nick);
		
		/* We can only set channel modes when we are right
		** So gues what we need to check :D
		**/

		if ( HIGH_ROOM(rusr->modes) || HIGH_PRIVS(_usr->globmode)) 
		/* If oper == 1 switch for channel mode */
		switch (a[2][1])
		{
		/* Set room key */
		case 'k':
			if ( a[2][0] == '-' )
			{	 rmdb_clean_room_key(rm->name);
				 rm ->modes -= ROOM_KEY_PROT;
			
			} else {
			  rm ->modes |= ROOM_KEY_PROT;
			  rmdb_set_room_key(rm->name,a[3]);
			  
			if (TS5_LOCAL(_usr ->u_type) )
			 TS5_USERMESG(IRC_MODE,_usr ->Nick,msg);
		
			msg_room(NULL,a[1],IRC_MODE,_usr ->ident,msg);
		
			}
		
		break;

		/* Set room limit for the room */
		case 'l':
			limit = atoi ( a[3]);
			if ( a[2][0] == '-' )
			{	 rm ->limit = 0;
				 rm ->modes -= ROOM_LIMIT;
			} else {
			  rm ->limit = limit;
			  rm ->modes |= ROOM_LIMIT;
			}
		
				if (TS5_LOCAL(_usr ->u_type) )
			     TS5_USERMESG(IRC_MODE,_usr ->Nick,msg);
				msg_room(NULL,a[1],IRC_MODE,_usr ->ident,msg);
	
		break;
		case 'f':
			/* Reserved */
			break;

		/* Add a banned user */
		case 'b':
		if (a[2][0] == '+' )
		rmdb_room_setban(rm->name,_usr->Nick,a[3]);
		else if ( a[2][0] == '-')
		rmdb_free_ban(rm->name,_usr->Nick);

		
		if (TS5_LOCAL(_usr ->u_type) )
		  TS5_USERMESG(IRC_MODE,_usr ->Nick,msg);
		msg_room(NULL,a[1],IRC_MODE,_usr ->ident,msg);

		break;

		default:
		
			if ( rmdb_room_has_user ( rm->name, a[3]) ){
				  rusr = rmdb_room_find_user(rm->name, a[3]);

				if ( a[2][0] == '-' ) {
				ret = i_int_modes(a[2] +1, IRC_ROOM_USER);
				
				rusr ->modes -= ret;
				} else if (a[2][0] == '+'){
					ret = i_int_modes(a[2] +1, IRC_ROOM_USER);
				    rusr ->modes |= ret;
			
					printf("user in room change mode %s with mode %s\n",a[3],a[2]);
				}
			
				
			//	if ( ret == 0 )
			//		return ERR_MODE_ROOM_MODE_UNKNOWN(_usr,0,a[2]+1);

				if (TS5_LOCAL(_usr ->u_type) )
				 TS5_USERMESG(TS5_MODE,_usr ->Nick,msg);


				msg_room(NULL,a[1],IRC_MODE,_usr->ident,msg);
			
			
			} else {

			// nog wat restanten room modes;

			}
			break;
		}
		else 
		return msg_build(_usr->fd,0,IRC_MODE_NOPRIVS,usr->Nick,rm->name,_usr->Nick);
     

		


	}
	}

//	FREE_AREA(a, argc);
return 0;
}

int irc_do_nmode (void)
{
char **argv;
char *modes;



	if (!(argv = ALLOCATE(char **)))
	 return -1;

	if (!(modes = i_globcharmodes(_usr ->candomode, IRC_OPER_CANDO)))
		 modes = "";

	msg_build(_usr ->fd, 0, IRC_NMODE, _usr ->Nick, modes);

	
return 0;
}
int irc_do_kick(void)
{
struct __room *rm;
struct __user *usr;
struct _rdb_usrs *rusr;

char **a;
int higher,count,go,oper;



	if (!(a = ALLOCATE(char **)))
	 return msg_build(_usr->fd,0,IRC_UNKNOW_COMMAND,_usr->Nick,msg);


	a = s_splitcmd(msg);
	if ( (count = s_countargc(a)) < 2)
		return msg_build(_usr->fd,0,IRC_KICK_NMORE_PARS,_usr->Nick);


	
go	   = 0;
higher = HIGH_PRIVS(_usr->globmode);


	/* Overview
	** a[0]	-> "Kick"
	** a[1] -> room
	** a[2] -> nick to kick
	** a[3] -> reason
	*/

	/* Lets see if the room the kicker has requested realy exitsts */
rm = rmdb_find_room(a[1]);

	if (!rm)
		return msg_build(_usr->fd,0,IRC_KICK_NOSUCH_CHAN,_usr->Nick,a[1]);

	/* Check if the calling user is not in the room 
	** But has higher rights, If so this ircd allows the kick
	** 
	*/
	oper = ( !rmdb_room_has_user(rm->name,_usr->Nick) && higher );

	if (!oper && rmdb_room_has_user(rm->name,_usr->Nick)) 
			 go =1;

		
	if ( rmdb_room_has_user(rm->name, a[2])) {
			
	/* NOTICE
	** If this fails for some reason ( i dont see why ) return no sutch user 
	*/
	rusr = rmdb_room_find_user(rm->name,a[2]);
	if (!rusr) return msg_build(_usr->fd,0,IRC_KICK_NOSUCH_CHAN,_usr->Nick,a[2]);
	
	/* NOTICE
	** If this fails for some reason ( i dont see why ) return no sutch user 
	*/
	usr = usdb_find_user(a[2]);
	if (!usr) return msg_build(_usr->fd,0,IRC_KICK_NOSUCH_USER,_usr->Nick,a[2]);
	
	/* IMPORTANT (!)
	** See if the target user is not protected 
	*/

	if ( CAN_PROTOPER(usr->candomode) && !HIGHER_ADMIN(_usr->globmode))
	  return msg_build(_usr->fd,0,IRC_KICK_PROT_OPER,rm->name,rm->name,_usr->Nick,a[2],rm->name);

	/* Now, if we are not a global op but we are in the room
	** Can we kick it ?
	*/
	if (!oper && rmdb_room_has_user(rm->name,_usr->Nick)) 
		 if (!(rusr = rmdb_room_find_user(rm->name,_usr->Nick)))
				return msg_build(_usr->fd,0,IRC_KICK_NOPRIVS ,_usr->Nick,rm->name,_usr->Nick);	
		 
	/* Do we have rights to kick this person ? */
		 higher = HIGH_ROOM(rusr->modes);
	if ( higher && !oper)
		go =1;
	else 
		return msg_build(_usr->fd,0,IRC_KICK_NOPRIVS ,_usr->Nick,rm->name,_usr->Nick);		
		 
	} else 
		return msg_build(_usr->fd,0,IRC_KICK_NOSUCH_USER,_usr->Nick,a[2]);


	if ( go ) {

	msg_room(NULL,rm->name,IRC_KICK,_usr->ident,msg);
	rmdb_user_leave(rm->name,a[2]);
	} 

	FREE_AREA(a,count);
return 0;
}

int irc_do_list (void)
{
struct __room *rm;
int higher;
int ret;

msg_build(_usr->fd,DEBUG_LOG,
		  IRC_LIST_START,_usr->Nick);


rm = rmdb_getstart();

	if (!rm) 
	  printf("list error for user %s\n",_usr->Nick);

	higher = HIGH_PRIVS(_usr->globmode);

	
	WALKDB(rm)
	{
		if ( _usr ->u_type == USER_BRIDGE && rm ->name[0] == config ->rpref[P_LOCAL])
			goto do_not_show_local_rooms;

		ret = rmdb_room_has_modes(rm->name,ROOM_SECRET|ROOM_PRIVATE); 	
	
		
		if (ret && higher ) 	
		  msg_build(_usr->fd,DEBUG_LOG,
			  IRC_LIST_LINE,_usr->Nick,rm->name,rm->users,
			  (rm->Topic == NULL) ? "" : rm->Topic
			  );
		

	if (!ret)
		msg_build(_usr->fd,DEBUG_LOG,
			  IRC_LIST_LINE,_usr->Nick,rm->name,rm->users,
			  (rm->Topic == NULL) ? "" : rm->Topic
			  );

do_not_show_local_rooms:;

	}

	msg_build(_usr->fd,DEBUG_LOG,
		  IRC_LIST_END,_usr->Nick);

	

return 0;
}

/*
**
** Only if no users are in the room has been taken care of  
** User Limit hasnt been taken care of yet 
** room->users++; must be tuned the right  way
** Banned ?
*/ 
// :hippolytushoef.nl 474 a #rosiello :Cannot join channel, you are banned from channel (+b)
// ISBANNED moet ook ff checken op hosts en moet de ident (vol) als parameter krijgen

// Kan maar 1 room per keer joinen ik wil, join #rosiello,#tkn

// alle nicks moeten in lower case
int irc_do_join (void)
{
struct __room *room;
struct _invites *inv ;
struct _bans *ban;
char **a,*users;
int flags,argc;



	if ( (a = ALLOCATE ( char **)) == NULL )
	return msg_build(_usr->fd,0,IRC_NOSUCH_ROOM,_usr->Nick," ");

	///////////////////////////////////////////////////
	/// We need to know if the room already exists ///
	///
	///
	///
	///

	a = s_splitcmd ( msg );
	if ( (argc = s_countargc(a)) < 1)
		return msg_build(_usr ->fd,0,IRC_NO_NICK);


	
	// ROOM KEY ??
	room = rmdb_find_room ( a[1] );
	
	if (!room)
	{ 
		flags = ROOM_USER_CHAN_OP;
		if ( (s_findchars ("@#&%!$*().,?'`;[]|_+/?;",a[1]+1) == 0) || (s_strnlen(a[1],MR) <= 1))
				return msg_build(_usr->fd,0,IRC_NO_SUTCH_ROOM,_usr->Nick,a[1]);

		if ( a[1][0] != config ->rpref[P_LOCAL] && a[1][0] != config ->rpref[P_GLOBAL] )
				return msg_build(_usr->fd,0,IRC_NOSUCH_ROOM,_usr->Nick,a[1]);

		room = rmdb_new_room(a[1],_usr->Nick);
	}


		

	// USER limit ONLY ??
	if (ISUSED(room->modes,ROOM_LIMIT))
	{
		if (  room->limit < (room->users +1) )
			return msg_build(_usr->fd,0, IRC_JOIN_ROOM_FULL,_usr->Nick,room->name,_usr->Nick);
	}


		inv = rmdb_find_invite(room->name,_usr->Nick);
	// INVITE ONLY ??
		if (ISUSED(room->modes,ROOM_INVITE_ONLY) && !inv)
			return msg_build(_usr->fd,DEBUG_LOG,IRC_JOIN_INVITE_ON,_usr->Nick,a[1]);
			
	// PRIVATE CHANNEL ??
		if (ISUSED(room->modes,ROOM_PRIVATE) && !inv)
			return msg_build(_usr->fd,DEBUG_LOG,IRC_JOIN_PRIVATE_ON,_usr->Nick,a[1]);
	
	if ( ISUSED(room->modes,ROOM_KEY_PROT) )
		if (s_countargc(a) < 2) 
			return msg_build(_usr->fd,DEBUG_LOG,IRC_JOIN_NO_KEY,_usr->Nick,a[1]);

	// OPER ONLY CHAN ?
	if ( !HIGH_PRIVS(_usr->globmode) && rmdb_room_has_modes(room->name,ROOM_OOPER_FLAG) && !inv)
			return msg_build(_usr->fd,0,IRC_JOIN_OPER_ONLY,_usr->Nick,_usr->Nick);

	// Admin ONLY CHAN ?
	if ( !HIGH_PRIVS(_usr->globmode) && rmdb_room_has_modes(room->name,ROOM_ADMIN_ONLY) && !inv)
			return msg_build(_usr->fd,0,IRC_JOIN_ADMIN_ONLY,_usr->Nick,_usr->Nick);

	

	// Created by server ??
	if (ISUSED(room->modes,ROOM_CREATE_BY_SERV))
			flags = ROOM_USER_NORIGHTS;


	if ( (ISUSED(room->modes, ROOM_KEY_PROT )) && a[2] != NULL)
	
	if ( (strcmp (room->key,a[2])) ==-1)
		return msg_build(_usr->fd,DEBUG_LOG,IRC_JOIN_NO_KEY,_usr->Nick,a[1]);;
	
	
	// Banned ?
	ban = rmdb_find_ban(room->name,_usr);
	if ( ban )
		return msg_build(_usr->fd,0,IRC_JOIN_BANNED,_usr->Nick,room->name);

	if ( room ->users > 0)
			flags = ROOM_USER_NORIGHTS;




	if ( rmdb_room_has_user(room->name,_usr->Nick))
			return 0;

	
		rmdb_user_join(room->name,_usr->Nick,flags);
		msg_room(NULL,a[1],IRC_JOIN_SUCCESS, _usr->ident,a[1]);

		
	if ( room ->name[0] == config->rpref[P_GLOBAL] )
		TS5_asktopic(_usr ->Nick, room->name);


		if (room->Topic) { 
		msg_build(_usr->fd,DEBUG_NONE,
			IRC_JOIN_R_ANDTOPIC,
			_usr->Nick,
			room->name,
			room ->Topic
			);
		
			msg_build(_usr->fd,DEBUG_NONE,
			IRC_JOIN_C_BY,
			_usr->Nick,
			room->name,
			room->Tby,
			room->C_Time
			);

		}
		else 
			msg_build(_usr->fd,DEBUG_NONE,
			IRC_JOIN_NO_TOPIC,
			room->name
			);


		
		

		users = rmdb_user_show (room ->name);
		if ( users == NULL)
			 users = _usr ->Nick;

		if ( flags != USER_ROOM_OP)
		irc_do_names(room->name,0);

	
		if ( room ->name [0] != config ->rpref[P_LOCAL])
			TS5_telljoin(room,_usr ->Nick);
	



		if (inv)
			rmdb_free_invite(inv->user,room->name);



			_usr->rooms++;		
		
		
		if ( argc )
		  FREE_AREA(a,argc);
				
return 0;
}


int irc_do_part(void)
{
struct __room *rm;
char *room,**a;
int argc;


if ( strlen(msg) < 6) 
	return msg_build(_usr->fd,0,IRC_PART_PARAMS,_usr->Nick);

  	if ( (a = ALLOCATE( char **)) == NULL )
	{
		printf ("Malloc failed\n");
		return -1;
	}

	if (!(a = s_splitcmd ( msg )))
		 return -1;

	argc = s_countargc(a);

	if ( argc < 1  )
		  return -1;
	
room = a[1];


if (!(rm = rmdb_find_room(room)))
 return msg_build(_usr->fd,0,IRC_PART_NOSUCH_CHAN,_usr->Nick,msg);


msg_room(NULL,room,IRC_PART,_usr->ident,msg);


if ( _usr ->u_type == USER_LOCAL)
	TS5_USERMESG(TS5_PART,_usr->Nick,msg);


rmdb_user_leave(room,_usr->Nick);



_usr->rooms--;

		if (argc)
		  FREE_AREA(a,argc);

return 0;
}

 
int irc_do_topic(void)
{
char **a,*topic;
struct __room *rm;
struct _rdb_usrs *rusr;

int inroom = 0;
int canoutside = 0;
int go = 0;
int ret;
int higher;

  	if ( (a = malloc ( sizeof ( char **))) == NULL )
	{
		printf ("Malloc failed\n");
		return -1;
	}

	a = s_splitcmd ( msg );
	ret = s_countargc(a); 

	if (  ret < 1)
		return msg_build(_usr->fd,0,IRC_TOPIC_NOTENOUGH);

	if ( ret == 1 )
	{

		if (!(rm = rmdb_find_room(a[1])))
				return msg_build(_usr->fd,0,IRC_TOPIC_NOTENOUGH);

		 
	
			if (rm->Topic) { 
		msg_build(_usr->fd,DEBUG_NONE,
			IRC_JOIN_R_ANDTOPIC,
			_usr->Nick,
			rm->name,
			rm ->Topic
			);
		
			msg_build(_usr->fd,DEBUG_NONE,
			IRC_JOIN_C_BY,
			_usr->Nick,
			rm->name,
			rm->Tby,
			rm->C_Time
			);

		}
		else 
			msg_build(_usr->fd,DEBUG_NONE,
			IRC_JOIN_NO_TOPIC,
			rm->name
			);

		return 0;
	}

	/* This is ugly im aware */
	topic = msg + ( strlen(a[0]) + strlen(a[1]) + 3);

	/* We need to know if the room is protected with the +t mode
	** This disallows normal users to change the topic so the question is.
	**
	** A. Do we deal with a +t mode and does the user has higher rights in this 
	** room to change the topic. 
	** 
	** If thats the case go will be set to 1
	*/
	if ( rmdb_room_has_user ( a[1], _usr->Nick)) {
	  
		rusr = rmdb_room_find_user(a[1],_usr->Nick);
		
		
		/* Finding out users mode in this channel */
		higher = ISUSED(rusr->modes, ROOM_USER_CHAN_OP) ? 1 :
				 ISUSED(rusr->modes, ROOM_USER_CHAN_HOP) ? 1 : 0;

		
		if ( rmdb_room_has_modes( a[1], ROOM_PROT_TOPIC) && higher)
				go =1;


	}
	/*
	** Now suppose that the topic isnt protected with the +t mode
	** then we can allow users without higher rights to set the topic
	*/
	if ( !rmdb_room_has_modes( a[1], ROOM_PROT_TOPIC))
				go =1;


	/* Are we inside this room ? returns 0 or 1 */
	inroom = rmdb_room_has_user(a[1],_usr->Nick);
	

	
	
	if ( go == 1)
	{

	ret = rmdb_change_topic(a[1],_usr->Nick,topic);
	if ( ret < 0 )
		printf("changing the topic failed\n");

	if ( _usr ->u_type == USER_LOCAL)
	  TS5_tellnewtopic(_usr ->Nick, a[1], topic);

	 msg_room(NULL,a[1],IRC_TOPIC,
		  _usr->ident,
		  msg
		 );
	

	}


	if ( ret )
		FREE_AREA(a,ret);

	return 0;
}




int irc_do_privmsg(void)
{
struct _rdb_usrs *rusr;
char tmp[MR];

char *target, *message;
int i,ret;


	if (strlen(msg) < 9)
		return msg_build(_usr->fd,0,IRC_PRIVMSG_PARAMS,_usr->Nick);


	clean(tmp);
	target = msg + 8;

	if ( strlen(target ) <= 1)
		return msg_build(_usr->fd,0,IRC_PRIVMSG_PARAMS,_usr->Nick);
	

	i=0;
	while ( i <= (int)strlen(target) && i <= MR)
	{

		if (target[i] == ' ')
			break;

		tmp[i]=target[i];
		i++;

	} 

	
	message = (target + (i +1));
	if ( message[0] == ':' )
			message++;

	target = tmp;

	ret = i_msgtarget(target);
	
	_usr ->IDLE = time(NULL);
	
	if ( ret == TARGET_ROOM)
	{

		/* QUESTION:
		** What is the room is modurated ? ( mode flag +m ), Then only users with a legal voice 
		** thats mode +v can talk in that channel.
		*/
		if ( rmdb_room_has_user(target,_usr->Nick))
				rusr=rmdb_room_find_user(target,_usr->Nick);

		if ( rmdb_room_has_modes(target, ROOM_MODERATED)) {

		
			if (!rusr)
				printf("oops\n");

			ret = ISUSED(rusr->modes,
				ROOM_USER_VOICE|ROOM_USER_CREATOR|ROOM_USER_CHAN_OP|ROOM_USER_CHAN_HOP|ROOM_USER_ADMIN);


			if (!ret)
				 return msg_build(_usr->fd,0,IRC_JOIN_ROOM_MODUR,_usr->Nick,target,_usr->Nick);

		}

		


		/* QUESTION: 
		** Can we send messages from outside the channel to the channel ?. If we cant its 
		** protected by the +t flag.
		**/
		if ( rmdb_room_has_modes(target, ROOM_NO_OUTSIDE) && !rmdb_room_has_user(target,_usr->Nick))
		     return msg_build(_usr->fd,0,IRC_PRIVMSG_NOOUTSIDE,_usr->Nick,target);

		/* Yes we can send messages to the channel from the outside */
		else { 
			msg_room(_usr->Nick,target,IRC_PRIVMSG,_usr->ident,msg);
			
			if ( _usr ->u_type == USER_LOCAL)
			TS5_tellmessage(_usr ->Nick,  msg);
		}



		} else if ( ret == TARGET_USER) {
			msg_user(target,IRC_PRIVMSG,_usr->ident,msg);
		
			if ( _usr ->u_type == USER_LOCAL)
			TS5_tellmessage(_usr ->Nick,  msg);
		}
			

		return 0;
}


int irc_do_notice(void)
{
struct _rdb_usrs *rusr;
char tmp[MR];

char *target, *message;
int i,ret;


	if (strlen(msg) < 8)
	 return msg_build(_usr->fd,0,IRC_NOTICE_PARAMS,_usr->Nick);

	clean(tmp);
	target = msg + 7;

	if ( strlen(target ) <= 1)
		return msg_build(_usr->fd,0,IRC_NOTICE_PARAMS,_usr->Nick);

	i=0;
	while ( i <= (int)strlen(target) && i <= MR)
	{

		if (target[i] == ' ')
			break;

		tmp[i]=target[i];
		i++;

	} 

	
	message = (target + (i +1));
	if ( message[0] == ':' )
			message++;

	target = tmp;

	ret = i_msgtarget(target);
	
	_usr ->IDLE = time(NULL);
	
	if ( ret == TARGET_ROOM)
	{

		/* QUESTION:
		** What is the room is modurated ? ( mode flag +m ), Then only users with a legal voice 
		** thats mode +v can talk in that channel.
		*/
		if ( rmdb_room_has_user(target,_usr->Nick))
				rusr=rmdb_room_find_user(target,_usr->Nick);

		if ( rmdb_room_has_modes(target, ROOM_MODERATED)) {

		
			if (!rusr)
				printf("oops\n");

			ret = ISUSED(rusr->modes,
				ROOM_USER_VOICE|ROOM_USER_CREATOR|ROOM_USER_CHAN_OP|ROOM_USER_CHAN_HOP|ROOM_USER_ADMIN);


			if (!ret)
				 return msg_build(_usr->fd,0,IRC_JOIN_ROOM_MODUR,_usr->Nick,target,_usr->Nick);

		}

		


		/* QUESTION: 
		** Can we send messages from outside the channel to the channel ?. If we cant its 
		** protected by the +t flag.
		**/
		if ( rmdb_room_has_modes(target, ROOM_NO_OUTSIDE) && !rmdb_room_has_user(target,_usr->Nick))
		     return msg_build(_usr->fd,0,IRC_NOTICE_NOOUTSIDE,_usr->Nick,target);

		/* Yes we can send messages to the channel from the outside */
		else { 
			msg_room(NULL,target,IRC_NOTICE,_usr->ident,msg);
			
			if ( _usr ->u_type == USER_LOCAL)
			TS5_tellmessage(_usr ->Nick,  msg);
		}



		} else if ( ret == TARGET_USER) {
			msg_user(target,IRC_NOTICE,_usr->ident,msg);
		
			if ( _usr ->u_type == USER_LOCAL)
			TS5_tellmessage(_usr ->Nick,  msg);
		}
			

	return 0;
}


int irc_do_quit(void)
{
struct __room *rm;

rm = rmdb_getstart();

WALKDB(rm)
{
	if (rmdb_room_has_user(rm->name,_usr->Nick)) {
	msg_room(_usr->Nick,rm->name,":%s %s",_usr->ident,msg);

	
	
	
	TS5_USERMESG(TS5_QUIT, _usr ->Nick, msg);
	}

}

if ( _usr ->u_type == USER_LINKED) {
	usdb_free_user(_usr ->Nick);

		 return 3;
}

	_usr ->did_quit = YES;


	return CLOSE_CON;
}









int irc_do_users (void)
{
struct __user *tmp;
char **argv;
int argc;
int operators,rooms,gu;
int servers;
int go = 0;






if (!(argv=ALLOCATE(char **)))
		return -1;

if (!(argv=s_splitcmd(msg)))
		return -1;

argc = s_countargc(argv);

if ( (strncmp ( msg, "USERS",5))==0)
	go =1;

	if ( argc > 0 && _usr ->u_type == USER_LOCAL && go)
		return TS5_USERMESG(TS5_USERS_Q,_usr->Nick,argv[1]);


operators = 0;
rooms = rmdb_count_rooms();
servers = sdb_count();
gu = 0;

/* Our local server is also included so add one */
++ servers;

tmp = usdb_getstart();
WALKDB(tmp)
{

    if ( HIGH_PRIVS(tmp->globmode) && tmp ->u_type != USER_BRIDGE)
		operators ++;

	if ( tmp ->u_type == USER_LINKED)
		gu ++;
}


gu += netw ->users;

msg_build(_usr->fd,DEBUG_LOG,IRC_STAT_USERS,_usr->Nick,gu,gu,servers);
msg_build(_usr->fd,DEBUG_LOG,IRC_STAT_OPS,_usr->Nick,operators);


msg_build(_usr->fd,DEBUG_LOG,IRC_STAT_ROOMS,_usr->Nick,rooms);


msg_build(_usr->fd,DEBUG_LOG,IRC_STAT_LUSERS,_usr->Nick,netw->users,netw->max);



msg_build(_usr->fd,DEBUG_LOG,IRC_STAT_GUSERS,_usr->Nick,gu ,gu);


	if ( argc )
		FREE_AREA(argv, argc);


return 0;
}


int irc_do_ping(struct __user *user,char *server)
{
char **a;
int ret;


if ( _usr ->u_type == USER_LINKED || _usr ->u_type == USER_BRIDGE)
	return 0;

if (!user) {	
	if (!(a = ALLOCATE(char **)))
		return -1;

	
a = s_splitcmd(msg);
ret = s_countargc(a);
if ( ret < 1 )
	return msg_build(_usr->fd,0,IRC_PING_NO_ORGINE);

	 
	return irc_do_pong(_usr,NULL,a[1]);

} else {

	printf("sending a ping to %s\n",user->Nick);
	return msg_raw(user->fd,0, IRC_PING_SEND, netw->net_addr);
}
  return  irc_do_pong(user,NULL,NULL);
}


int irc_do_pong(struct __user *user,char *server,char *what)
{
char **a;
int ret;

if (!user) {	
	if (!(a = ALLOCATE(char **)))
		return -1;

	
a = s_splitcmd(msg);
ret = s_countargc(a);
if ( ret < 1 )
	return msg_build(_usr->fd,0,IRC_PONG_NO_ORGINE);

		_usr->ping->last = time(NULL);


} else {

	printf("sending a pong to %s\n",user->Nick);
	user->ping->last = time(NULL);

if (!what)
  return msg_build(_usr->fd,0, IRC_P0NG_SEND, netw->net_addr, _usr->Nick);
	else
  return msg_build(_usr->fd,0, IRC_P0NG_SEND, netw->net_addr, what);

}





return 0;
}
// --- Total: 11 IRCOps online - 10 Globals, 1 Local <-- die line nog
int irc_do_ircop(void)
{
struct __user *usr;
int higher;
int lop,gob,lad,gad;

usr = usdb_getstart();
if (!usr)
 return msg_build(_usr->fd,0,IRC_COP_END,_usr->Nick);

WALKDB(usr){

higher = HIGH_PRIVS(usr->globmode);

if ( usr ->u_type == USER_LOCAL || usr ->u_type == USER_LINKED )
if (higher)
msg_build(_usr->fd,0,IRC_COP_LINE,_usr->Nick,usr->Nick,i_usertype(usr->globmode),
		  usr ->conn_to,i_usertypeExtent(usr));

}

gob=lop=gad=lad=0;
usdb_count_users(&gob,&lop,&gad,&lad);
printf("local opers: %d\n",lop);
printf("Glob opers: %d\n",gob);
printf("Local Admins: %d\n",lad);
printf("Global Admins: %d\n",gad);


return msg_build(_usr->fd,0,IRC_COP_END,_usr->Nick);
}


int irc_do_vhost (void)
{
struct _vhost *vhost;
char **argv;
int argc;


if ( config ->E_VHOST != ENABLED)
	return -1;


argv = s_splitcmd(msg);
argc = s_countargc(argv);

if ( argc > 2 || argc < 2)
	    return msg_build(_usr->fd,0,IRC_VHOST_FAIL,_usr->Nick);

if (!(vhost = vhost_find(argv[1])))
		return msg_build(_usr->fd,0,IRC_VHOST_NOLINE,_usr->Nick,argv[1]);


if ( (strcmp (vhost->pass,argv[2])) !=0 ) 
 return msg_build(_usr->fd,0,IRC_VHOST_WRONGPASS,_usr->Nick);


 irc_do_sethost(_usr->Nick,vhost->vhost);
 msg_user(_usr->Nick,IRC_VHOST_USER,_usr->Nick,vhost->vhost);


 
if ( _usr ->u_type == USER_LOCAL)
	TS5_USERMESG(TS5_VHOST,netw->net_addr,_usr->Nick,_usr->username,_usr->Host,_usr->Nick,
			 vhost->vhost);


  TS5_tellsethost ( _usr ->Nick, vhost ->vhost);


	if ( argc )
		FREE_AREA(argv, argc);

return 0;
}


int irc_do_admin(void)
{
char **argv;
int argc;


if (!(argv=ALLOCATE(char **)))
		return -1;

if (!(argv=s_splitcmd(msg)))
		return -1;

argc = s_countargc(argv);

	if ( argc > 0 && _usr ->u_type == USER_LOCAL)
	{
		TS5_USERMESG(TS5_ADMIN_Q,_usr->Nick,argv[1]);
		//return 0;//FREE_AREA(argv,argc);
	}


msg_build(_usr->fd,0,IRC_ADMIN_INFO_SERV,_usr->Nick,netw->net_addr);
msg_build(_usr->fd,0,IRC_ADMIN_INFO_TYPE,_usr->Nick);
msg_build(_usr->fd,0,IRC_ADMIN_INFO_NAME,_usr->Nick,netw->Admin_name);
msg_build(_usr->fd,0,IRC_ADMIN_INFO_EMAIL,_usr->Nick,netw->Admin_Email);
return 0;
}



int irc_names(void)
{
struct _n *names;
FILE *fd;
char **argv;
int argc;


argv = s_splitcmd(msg);
argc = s_countargc(argv);

if ( argc < 1  )
	return msg_build(_usr->fd,0,IRC_IRCNAME_FAIL,_usr->Nick);

argv [1] = s_upperstring(argv[1]);

if ( (strncmp ( argv[1], "ADD",3))==0)
{
	if ( argc < 3  )
	return msg_build(_usr->fd,0,IRC_IRCNAME_FAIL,_usr->Nick);

	if (!(fd=f_open("names.txt","a")))
		return -1;


	names = ALLOCATE_STRUCT(_n);
	names->name = argv[2];
	names->nick = _usr->Nick;
	names->why = msg + strlen(argv[1]) + 1 + strlen(argv[2])+1+strlen("IRCDNAME")+1;


	fprintf(fd,"%s wants \"%s\" because: %s\n",names->nick,names->name,names->why);
	
	f_close(fd);

	msg_user(_usr->Nick,IRC_IRCNAME_TANKZ,_usr->Nick);
	msg_privilaged_notice(IRC_NAME_OPERS,_usr->Nick,_usr->Nick,names->name);
} else if ((strncmp(argv[1], "SHOW",4))==0) 
{
	core_motd(_usr,NAMES_FILE);
}

	if ( argc )
		FREE_AREA(argv, argc);

	return 0;
}





int irc_do_version(void)
{
char **argv;
int argc;


if (!(argv=ALLOCATE(char **)))
		return -1;

if (!(argv=s_splitcmd(msg)))
		return -1;

argc = s_countargc(argv);

	if ( argc > 0 && _usr ->u_type == USER_LOCAL)
	{
		TS5_USERMESG(TS5_VERSION_Q,_usr->Nick,argv[1]);
		return 0;//FREE_AREA(argv,argc);
	}


core_do_version(_usr);
	
	if ( argc )
	 FREE_AREA( argv, argc);


	return 0;
}


int irc_do_time(void)
{
char *tstr;
char **argv;
int argc;
time_t ltime;


if (!(argv=ALLOCATE(char **)))
		return -1;

if (!(argv=s_splitcmd(msg)))
		return -1;

argc = s_countargc(argv);

	if ( argc > 0 && _usr ->u_type == USER_LOCAL)
	{
		TS5_USERMESG(TS5_TIME_Q,_usr->Nick,argv[1]);
		return 0;//FREE_AREA(argv,argc);
	}


ltime = time (NULL);
     
tstr =  s_timestr(ltime);

msg_build(_usr ->fd,0,IRC_TIME,_usr->Nick,netw->net_addr, tstr);


return 0;
}



int irc_do_info(void)
{
char **argv;
int argc;


if (!(argv=ALLOCATE(char **)))
		return -1;

if (!(argv=s_splitcmd(msg)))
		return -1;

argc = s_countargc(argv);

	if ( argc > 0 && _usr ->u_type == USER_LOCAL)
	{
		TS5_USERMESG(TS5_INFO_Q,_usr->Nick,argv[1]);
		return 0;//FREE_AREA(argv,argc);
	}



		

		msg_build(_usr->fd,0,IRC_INFO_CURL,_usr->Nick,3,"7\tanIRCD Server information !!");
		msg_build(_usr->fd,0,IRC_INFO_NETADRR,_usr->Nick,netw->net_addr);
		msg_build(_usr->fd,0,IRC_INFO_ADMIN,_usr->Nick, netw->Admin_name,netw->Admin_Email);
		msg_build(_usr->fd,0,IRC_INFO_LOC,_usr->Nick, netw->net_loc);

		if ( HIGH_PRIVS(_usr->globmode))
		{
		
			msg_build(_usr->fd,0,IRC_INFO_LINE,_usr->Nick,"\n", "\n");

			msg_build(_usr->fd,0,IRC_INFO_LINE,_usr->Nick,"Nick Flood protection : ", (config->N_prot == ENABLED) ? "enabled": "disabled");
			msg_build(_usr->fd,0,IRC_INFO_LINE,_usr->Nick,"/RULES is : ", (config->E_RULES == ENABLED) ? "enabled": "disabled");
			msg_build(_usr->fd,0,IRC_INFO_LINE,_usr->Nick,"/MOTD is  : ", (config->E_MOTD == ENABLED) ? "enabled": "disabled");
			msg_build(_usr->fd,0,IRC_INFO_LINE,_usr->Nick,"/VHOST is : ", (config->E_VHOST == ENABLED) ? "enabled": "disabled");



			



		}

		msg_build(_usr->fd,0,IRC_INFO_END,_usr->Nick);

		if ( argc )
			FREE_AREA(argv, argc);

		return 0;
}


int irc_do_ison(void)
{
struct __user *usr;
char **argv;
int argc;



if (!(argv = s_splitcmd(msg)))
		return -1;

if ( ((argc = s_countargc) >= 1) && 
	(usr = usdb_find_user(argv[1])))

	return msg_build(_usr ->fd,0,IRC_ISON_REPLY,_usr->Nick,usr->Nick);
else
	return -1;

}


int irc_do_knock(void)
{
struct __room *rm;
char **argv;
int argc;


if (!(ALLOCATE(char **)))
	return -1;

if (!(argv = s_splitcmd(msg)))
	return -1;

if ((argc = s_countargc(argv)) < 1)
	return msg_build(_usr ->fd, 0, IRC_KNOCK_NEEDMORE, _usr->Nick);

if (!(rm = rmdb_find_room(argv[1])))
	return msg_build(_usr ->fd,0,IRC_KNOCK_NOSUCH_ROOM,_usr->Nick,argv[1]);


if (rmdb_room_has_user(rm ->name, _usr->Nick))
	 return msg_build(_usr ->fd,0, IRC_KNOCK_ALRI, _usr->Nick, rm ->name);


if ( !rmdb_room_has_modes(rm ->name, ROOM_INVITE_ONLY|ROOM_SECRET|ROOM_ONLYREG_NICKS|ROOM_OOPER_FLAG|ROOM_ADMIN_ONLY))
		return msg_build(_usr ->fd,0,IRC_KNOCK_WHY,_usr->Nick);


msg_room(NULL,rm ->name,IRC_KNOCK_KNOCK, rm->name, _usr->Nick,rm ->name);

msg_build(_usr ->fd,0, IRC_KNOCK_CONFIRM, _usr->Nick, rm ->name);

return 0;
}