 #
 # Copyright (c) 2001 Uiewera Ruirarchzatrea.  All rights reserved.
 # 
 #  The EPTSL Library is now covered under the BSD Licence, please see
 #  the EPTSL-LICENCE file included for this licence.


#!/usr/bin/perl -w
	 # use strict;
	 use Socket;
	 use IO::Select;
	 use IO;
         use IO::Socket;
         use Net::hostent;              # for OO version of gethostbyaddr
	require 'misc.pl';
	require 'toc_unroast.pl';
	my %userdb;
	my %userdb1;
	my %listeningtolist;
	my %listenerslist;
	my %chatdb;
	my %chatdb1;
	my %chatdb2;
	my %usersubscribedto;
	my %flap_seq;
	my %connectionmode;
	my %signonmode;
	my %signedon;
        my %pre_userdb;
        my %pre_userdb1;
         my ($port) = (9000);                  # pick something not in use

         my $socket = IO::Socket::INET->new( Proto     => 'tcp',
                                          LocalPort => $port,
                                          Listen    => 5,
                                          Reuse     => 1);

         die "can't setup server" unless $socket;
         print "[Server $0 accepting clients]\n";
	 my $readable = IO::Select->new;
	 $readable->add($socket);
#         while ($fd = $server->accept()) {


	while(1) { # 1
          # $client->autoflush(1);
 	my ($ready) = IO::Select->select($readable, undef, undef, undef);
 	foreach my $s (@$ready)
 	{ # 2
          # $hostinfo = gethostbyaddr($client->peeraddr);
 	# printf "[Connect from %s]\n", $hostinfo->name || $client->peerhost;                                                      

	if($s == $socket) { # 3
	my $new_sock = $socket->accept;
	$readable->add($new_sock) if $new_sock;
	# recieve_flapon($new_sock);
	$connectionmode{$new_sock} = 1;
	$signonmode{$new_sock} = 1;
	$signedon{$new_sock} = 0;
	} # e 3
	
	else
	{ # 3
my $buf = "blah";
my $fd = $s;
	if($s)
	{ # 4

if ($connectionmode{"$s"} == 1) { # 5
if ($signonmode{"$s"} == 1) { # 6 
print "0\n"; 
# $signonmsg = "SIGN_ON:1";
my @statres = stat($s);
print @statres[7];
recieve_flapon($s);
print "1\n";
send_flap_signon($s, 1, 1, 4, 1);
print "2\n"; 
$signonmode{"$s"} = 2;
# ++$signonmode{"$s"};
} # e 6

elsif ($signonmode{"$s"} == 2) { # 6
recieve_flap_signon($s);
print "3\n";
++$signonmode{"$s"};
} # e 6

elsif ($signonmode{"$s"} == 3) { # 6
my $toc_signon_str = serv_recieve($fd);
@parse_toc_signon_str = MISC::parse_tocclientmsg($toc_signon_str);


if ($parse_toc_signon_str[1] eq "toc_signon") {
   my $toc_passwd = TOCUNRST::toc_unroast($parse_toc_signon_str[5]);
   $pre_userdb{"$parse_toc_signon_str[4]"} = $s;
   $pre_userdb1{"$s"} = $parse_toc_signon_str[4];
   # toc_useronline($parse_toc_signon_str[4]);
}
else {
   close_connection($s);
}

print "4\n";
$signonmsg = "SIGN_ON:1";
$len = length($signonmsg);
# $seq = 1
# $ftype = 1
serv_send($signonmsg, $len, $fd, 2, 2);
print "5\n";
++$signonmode{"$s"};

$signonmsg2 = "CONFIG:";
$len2 = length($signonmsg2);
serv_send($signonmsg2, $len2, $fd, 3, 2);
$flap_seq{"$s"} = 4;
$connectionmode{"$s"} = 2;
} # e 6

else {
	print "hmmmm";
}

} #  e 5

else { # 5

my $chatid = 0;
my $myusername = $userdb1{"$s"};

$recvbuffer = serv_recieve($fd);
# require 'misc.pl';
@parsedtoc = MISC::parse_tocclientmsg($recvbuffer);

if ($parsedtoc[1] eq "toc_send_im") {
$recvbuffer2 ="IM_IN:System\@mydomain.com:F:{$parsedtoc[1]}{$parsedtoc[2]}message:{$parsedtoc[3]}";
$fromuser = $userdb1{"$s"};
$tofd = $userdb{"$parsedtoc[2]"};
$tosend1="IM_IN:$fromuser:$parsedtoc[3]:$parsedtoc[4]";
# dstuser message T/F
$len14 = length($tosend1);
print($tosend1);
++$flap_seq{"$tofd"} if serv_send($tosend1, $len14. $tofd, $flap_seq{"$tofd"}, 2);
# ++$seq11;
$len11 = length($recvbuffer2);
++$flap_seq{"$s"} if serv_send($recvbuffer2, $len11, $fd, $flap_seq{"$s"}, 2);
# ++$seq11;
 }

elsif ($parsedtoc[1] eq "toc_init_done") {
	$userdb{$myusername} = $pre_userdb1{$myusername};
	delete $pre_userdb{$myusername};
	$userdb1{$s} = $pre_userdb1{$s};
	delete $pre_userdb1{$s};
	if (@listenerslist{$myusername}) {
	foreach (@listenerslist{$myusername}) {
		# my $incoming;
		$incoming = $_;
		my ($tofd) = $pre_userdb{"$myusername"};
		$signedon{$fd} = 1;
		my ($sendstring) = "UPDATE_BUDDY:$myusername:T:0%:$unixepoc:0: O ";
		sflap_send($tofd, $sendstring);
	}
	}	
}
	
elsif ($parsedtoc[1] eq "keepalive_frame") {
	print ("We recieved a keepalive frame\n");
}

elsif ($parsedtoc[1] eq "toc_add_buddy") {
	my $arraylen = scalar(@parsedtoc);
	my $lastelement = $arraylen - 1;
	my @userlist = @parsedtoc[1..$lastelement];
	foreach (@userlist) {
	$buddy = $_;
	@array43[0] = $myusername;
	
	push(@{$listenerslist{$buddy}}, @array43);
	push(@{$listeningtolist{$myusername}}, $buddy);
	if ($userdb{$buddy}) {
	
	my $sendstring = "UPDATE_BUDDY:$buddy:T:0%:$unixepoc:0: O ";
	sflap_send($fd, $sendstring);
	}
	}
}

elsif ($parsedtoc[1] eq "toc_remove_buddy") { # 1
	my @userlist = @parsedtoc;
	my $tocommand = shift(@userlist);
	
	$arraycount = 0;
	foreach (@userlist) { # 2
	$incominguser = $_;
	foreach (@listeningtolist{"$myusername"}) { # 3
	$incoming = $_;
	if ($incoming eq $incominguser) { # 4
		 
		@newarray = splice(@{$listeningtolist{"$myusername"}}, $arraycount, 1);
		@listeningtolist{$myusername} = @newarray;
		last;
		} # e 4
	else { # 4
		++$arraycount;
	} # e 4
	foreach (@listenerslist{"$incominguser"}) { # 4
	$incoming = $_;
	if ($incoming eq $myusername) { # 5
		 
		@newarray = splice(@{$listenerslist{"$incominguser"}}, $arraycount, 1);
		@listeningto{$myusername} = @newarray;
		last;
		} # e 5
	else { # 5
		++$arraycount;
	} # e 5
	
	if ($userdb{"$incominguser"}) { # 5
	
	$sendstring = "UPDATE_BUDDY:$incominguser:F:0%:$unixepoc:0: O ";
	sflap_send($fd, $sendstring);
	} # e 5
	}
	}
	}
}



elsif ($parsedtoc[1] eq "toc_set_config") {
	@configarray1 = split("\n", $parsedtoc[2]);
	foreach(@configarray1) {
		$incoming = $_;
		my($type, $value) = split(" ", $incoming);
		if ($type eq "b") {
			# add_user_db($
		print("fdfd");
			}
		elsif ($type eq "p") {
			}
		elsif ($type eq "d") {
			}
		elsif ($type eq "m") {
			}
		elsif ($type eq "g") {
			}
		else {
			print("hmmmm");
		}
	}
	$config_string = $parsedtoc[2];
	$lenval = length($config_string);
	# serv_send();
}


elsif ($parsedtoc[1] eq "toc_evil") {
print "hmmm";	
}

elsif ($parsedtoc[1] eq "toc_add_permit") {
print "hhmmm";	
}

elsif ($parsedtoc[1] eq "toc_add_deny") {
	
}

elsif ($parsedtoc[1] eq "toc_chat_join") {
	#exchange roomname
	if (exists($chatdb1{"$parsedtoc[2]"}{"$parsedtoc[3]"})) {
	}	
	else {
	$chatdb1{$parsedtoc[2]}{$parsedtoc[3]} = $chatid;
	push(@{$chatdb2{$chatid}}, $parsedtoc[2], $parsedtoc[3]); 
	$chatroomid = $chatid;
	++$chatid;
	$chatdb{"$chatroomid"}[0] = 0;
	
	}
	$roomname = $parsedtoc[3];
	$sendstring = "CHAT_JOIN:$chatroomid:$roomname";
	push(@{$chatdb{"$chatroomid"}}, $myusername);
	# push(@usersubscribedto{"$myusername"}, $chatroomid);
	# ++$chatdb{"$chatroomid"}[0];
	@temparray = @chatdb{$chatroomid};
	push(@{$chatdb{"$chatroomid"}}, $myusername);
	shift(@temparray);
	$usernamelist = join(":", @temparray);
	$chatupdatestr = "CHAT_UPDATE:$chatroomid:T:$usernamelist";
	sflap_send($fd, $sendstring);
	
	foreach(@temparray) {
		
	$username = $_;
		$tofd = $userdb{$username};
		$chatupdate = "CHAT_UPDATE:$chatroomid:T:$myusername";
		sflap_send($tofd, $chatupdate);
		
	}
	sflap_send($fd, $chatupdatestr);
}

elsif ($parsedtoc[1] eq "toc_chat_send") { # 1
$bgcnt = 0;
$message = $parsedtoc[2];
$auto = $parsedtoc[3];
$chatid = $parsedtoc[2];
@userlist = @chatdb{$chatid};
shift(@userdb);
	
my($split1, $split2) = split(" ", $message, 2);
$split1 = 0;
		if ($split1 eq "//roll") { # 2
			#//roll -sides2 -dice2 arguments not need order
			@rollarray = split(" ". $split2);
			$rollsize = scalar(@rollarray);
			
			if ($rollsize < 2) {
				$dice = 2;
				$sides = 6;
			}
			else {
				
				$rollarg1len = length($rollarray[1]);
				$rolltestchar = substr($rollarray[1], 0, 1);
				if ($rolltestchar eq "d") {
				}
				elsif ($rolltestchar eq "s") {
				}
				$message = "$myusename rolled $dice ($sides)-sided dice: 1 2 3";	
			}
			for ($i=0;$i<$dice;$i++) {
			$diceval = rand $sides;
			$dicestring = $dicestring . $diceval;
			}
			
	foreach(@userlist) {
		
		$username = $_;
		$tofd = $userdb{$username};
		
		$chatupdate = "CHAT_IN:$chatroomid:$myusername:F:$message";
		
		sflap_send($tofd, $chatupdate);
		}
	}
}

elsif ($parsedtoc[1] eq "toc_chat_whisper") {
	$chatid = $parsedtoc[2];
	$dstuser = $parsedtoc[3];
	$message = $parsedtoc[4];
	
	$tofd = $userdb1{$dstusr};
	$sendstring = "CHAT_IN:$chatid:$myusername:T:$message";
	sflap_send($tofd, $sendstring);
	
}

elsif ($parsedtoc[1] eq "toc_chat_evil") {
	
}

elsif ($parsedtoc[1] eq "toc_chat_invite") {
	# chatrid invitemsg listofbuddies ....
	my @temparray = @parsedtoc;
	shift(@temparray);
	$message = shift(@temparray);
	$roomid = shift(@temparray);
	$roomname = $chatdb2{$roomid}[1];
	my $roomname = $chatdb{$roomid};
	foreach(@temparray) {
		$username = $_;
		$tofd = $userdb{$username};
		
		$sendstring = "CHAT_INVITE:$roomname:$roomid:$myusername:$message";
		sflap_send($tofd, $sendstring);
	}
}

elsif ($parsedtoc[1] eq "toc_chat_leave") {
	$arraycount = 0;
	foreach(@chatarray) {
		$incoming = $_;
		if ($myusername eq $incoming) {
			splice (@chatarray, $arraycount, 1);	
		}
		else {
			++$arraycount;
		}
	} 

	$chat_left = "CHAT_LEFT:$chatroomid";
	foreach(@chatarray) {
		$incoming = $_;
			if ($bgcnt = 0) {
			++$bgcnt;
		}
		else {
		$username = $_;
		$tofd = $userdb{$username};
		$chatupdate = "CHAT_UPDATE:$chatroomid:F:$myusername";
		sflap_send($fd, $chatupdate);
		}
	}	 
}

elsif ($parsedtoc[1] eq "toc_chat_accept") {
	$chatroomid = $parsedtoc[2];
	$sendstring = "CHAT_JOIN:$chatroomid:$chatroomname";
	join_chat($parsedtoc[2]); 
}

elsif ($parsedtoc[1] eq "toc_get_info") {
$infolisting = $userinfodb{"$username"};
	
}


elsif ($parsedtoc[1] eq "toc_set_info") {

$userinfodb{$myusername} = $parsedtoc[2];
	
}

elsif ($parsedtoc[1] eq "toc_set_away") {
# $tocustatusdb{"$myusername"}[8] = " OA"
# $sendstring = "UPDATE_BUDDY:$username

}

elsif ($parsedtoc[1] eq "toc_get_dir") {
	
}

elsif ($parsedtoc[1] eq "toc_set_dir") {
	
}

elsif ($parsedtoc[1] eq "toc_dir_search") { 
	
}

elsif ($parsedtoc[1] eq "toc_set_idle") {
	# $tocustatusdb{"$myusername"}[10] = $awaytime;
	# $sendstring = "UPDATE_BUDDY:";
	# broadcast_msg("$myusername, $sendstring");
}

elsif ($parsedtoc[1] eq "toc_set_caps") {
	
}

elsif ($parsedtoc[1] eq "toc_format_nickname") {
	
}

elsif ($parsedtoc[1] eq "toc_change_passwd") {
	
}
print "recieve\n";
$len12 = length($recvbuffer);
$recvbuffer1 = "IM_IN:System\@mydomain.com:F:We recieved a message";
$len11 =  length($recvbuffer1);
my $seq11 = $flap_seq{"$s"};
serv_send($recvbuffer1, $len11, $fd, $seq11, 2);
++$flap_seq{"$s"};
# }
} # e 5
} # e 4

else { # 4
close_connection($s);
# $readable->$remove($s);
# $s->close;


} # e 4
} # e 3
} # e 2
} # e 1

sub broadcast_msg {
	$sendstring = pop(@incomingarray);
	
	foreach(@userlist) {
		$incoming = $_;
		$tofd = $userdb1{"$incoming"};
		sflap_send($tofd, $sendstring);
	}
}	

sub add_user_db {
	# add a user to the user databases
}

sub toc_useronline {
	print("hmmm");
}

sub tocuseroffline {
	print("hmmm");
	
}

sub create_chat {
# exchange roomname
	($exchange, $roomname) = @_;
	if ($chatdb1{$exchange}{$roomname}) {
	return("");
	}	
	else {
	$chatdb1{"$parsedtoc[2]"}{"$parsedtoc[3]"} = $chatid;
	$chatroomid = $chatid;
	++$chatid;
	$chatdb{"$chatroomid"}[0] = 0;
	push(@{$chatdb2{$chatroomid}}, $parsedtoc[2], $parsedtoc[3]);
	return $chatroomid;
	}
}

sub join_chat {
	my($chatroomid) = @_[0];
	if (exists($chatdb2{$chatroomid})) {
	my($fd) = @_[2];
	my $myusername = $userdb{$fd};
	unless (@_[1]) {
		my $roomname = $chatdb2{$chatid}[1];
	}
	else {
		my $roomname = @_[1];
	}
	my $resultval = grep (/^($chatid)$/, @usersubsribedto{$myusername});
	unless ($resultval > 0) {
	$sendstring = "CHAT_JOIN:$chatroomid:$roomname";
	push(@{$chatdb{"$chatroomid"}}, $myusername);

	# push(@usersubscribedto{"$myusername"}, $chatroomid);
	# ++$chatdb{"$chatroomid"}[0];
	@temparray = @chatdb{"$chatroomid"};
	push(@{$chatdb{"$chatroomid"}}, $myusername);
	shift(@temparray);
	$usernamelist = join(":", @temparray);
	$chatupdatestr = "CHAT_UPDATE_BUDDY:$chatroomid:T:$usernamelist";
	serv_send($fd, $sendstring);
	
	foreach(@temparray) {
		
	$username = $_;
		$tofd = $userdb{$username};
		$chatupdate = "CHAT_UPDATE_BUDDY:$chatroomid:T:$myusername";
		send_sflap($tofd, $chatupdate);
		
	}
	send_sflap($fd, $chatupdatestr);
 	return 1;
	}
	else {
		return 0;
	}
	}
	else {
		return 2;
	}
		
		
	
}



sub sflap_send {
	my ($fd, $sendstring) = @_;
	my $len = length($sendstring);
	my $seq = $flap_seq{$fd};
	my $ftype = 2;
	$returnstr = serv_send($sendstring, $len, $fd, $seq, $ftype);
	++$flap_seq{$fd};
	return($returnstr);
}
sub serv_send {
	my ($buffer) = '';
	my ($format) = "cCnna*";
	my ($data, $len, $fd, $seq, $ftype) = @_;
	$buffer = pack($format, 42, $ftype, $seq, $len, $data);
	close_connection($fd) unless ($foo = syswrite($fd, $buffer, $len + 6));
	if ($foo <= 0) {
		close_connection($fd);
	}
	
}	

sub serv_recieve {
	my ($fd) = @_;
	my ($buffer, $len, $type) = '';
	my ($payloadsuccess) = 0;
	close_connection($fd) unless ($foo = sysread($fd, $buffer, 6));
	if ($foo <= 0) {
		close_connection($fd);
	}
	($type, $ast, $seq, $len) = unpack("aCnn", $buffer);
	if ($len > 0) {
	close_connection($fd) unless ($foo = sysread($fd, $buffer, $len));
	$payloadsuc = 1;
	if ($foo <= 0) {
		close_connection($fd);
	}
	}
	if ($type == 5) {
	 serv_send("", 0, $fd, $flap_seq{$fd}, 5);
	 ++$flap_seq{$fd};
	 return("keepalive_frame");
	}
	else {
	if ($payloadsuccess = 1) {
	print $buffer;
	return($buffer);
	}
	else {
	print ("hmmmm");
	}
	}
}

sub recieve_flapon {
	
	my ($fd) = @_;
	my $foo = sysread($fd, $buffer, 10);
	if ($foo <= 0) {
		close_connection($fd);
	}
	print $buffer;
}

sub send_flap_signon {

	my ($fd, $ftype, $seqnum, $datlen1, $flapver) = @_;
	my ($datlen) = 4;
	my ($buffer) = pack(cCnnN, 54, $ftype, $seqnum, $datlen, $flapver);
# another way, use flap_send here
#	$buffer = pack(a, $flapver);
#	my ($datlen2) = $datlen1
#	serv_send($buffer, $datlen2, $fd, $seqnum, $ftype)
	my ($foo) = syswrite($fd, $buffer, 10);
	if ($foo <= 0) {
		close_connection($fd);
	}
}	

sub close_connection { # 1
	my ($fha) = @_;
	my $myusername = $userdb{$fha};
	if ($signedon{"$fha"} = 1) { # 2
		# Send logoff update to all chat and im buddies, 
		# and remove db entries
		# chatdb
		# @userlist = 
		foreach(@listenerslist{$myusername}) { # 3
			$thierusername = $_;
			my $tofd = $userdb{$thierusername};
			my $sendstring = "UPDATE_BUDDY:$myusername:F:0%:$unixepoc:0: O ";
			sflap_send($tofd, $sendstring);
			foreach(@listenerslist{$thierusername}) { # 4
				$incoming = $_;
				if ($incoming eq $myusername) { # 5
				  @listenerslist{$thierusername} = splice(@{$listenerslist{$thierusername}}, $offset, 1);
				}
				else {
					++$arraycount;
				} # e 5
			} # e 4
		} # e 3
		# broadcast_msg(@userlist)
		foreach(@usersubscribedto{$myusername}) { # 3
		   $inchatid = $_;
		   foreach($chatdb{$inchatid}) { # 4
		   my $offsetcnt = 0; 
		   my $incoming = $_;
		   if ($myusername eq $incoming) { # 5
		   	@chatdb{$inchatid} = splice(@{$chatdb1{$inchatid}}, $offsetcnt, 1);
		   }
		   else {
		   	++$offsetcnt;
		   } # e 5
		   } # e 4
		   foreach($chatdb{$inchatid}) { # 4
 		   	my $incoming = $_;
		   	my $sendstring = "CHAT_UPDATE_BUDDY:$inchatid:F:$myusername";
		   	$tofd = $userdb1{$incoming};
		   	send_sflap($tofd, $sendstring);
	
	
	
		   } # e 4
	delete @usersubscribedto{$myusername};
	delete @listenerslist{$myusername};
	delete @listeningtolist{$myusername};
	
	} # e 3
	
	
	
	
	$readable->remove($fha);
	$fha->close;
	my $username = $userdb{"$fha"};
	toc_useroffline($username);
	delete $userdb1{"$username"};
	delete $userdb{"$fha"};
	delete $signonstatus{"$fha"};
	delete $connectionstatus{"$fha"};
	delete $signedon{"$fha"};
	
	
} # e 2
}

sub recieve_flap_signon {

	my ($fd) = @_;
	my ($buffer) = '';
	my ($foo) = sysread($fd, $buffer, 6);
	if ($foo <= 0) {
		close_connection($fd);
	}
	print $buffer;
	my ($aster, $ftype, $seqnum, $datlen) = unpack("aCnn", $buffer);
	$foo = sysread($fd, $buffer, $datlen);
	if ($foo <= 0) {
		close_connection($fd);
	}
	($flapver, $tlv, $snlen, $snnom) = unpack("Nnna*", $buffer);
	print $snnom;
#	$len = length($buffer);
#	$foo = CORE::sysread($fd, $buffer, $len + 1);
#	($1, $2) = unpack("*aC", $buffer);
}
