#!/usr/bin/perl
#
# $Id: Nateon,v 1.2 2008/06/08 06:52:25 bando Exp $
#
# NateOnPbot By YoungJoo-Kim <bando@bando.org>
#
# NateOn clients
#   http://nateon.kldp.net
#   http://nateon.haz3.com
#
#
# Packet dump tools
#   [tcpdump]
#          tcpdump -s 1024 -X port 5004 and tcp
#   [ngrep]
#          ngrep port 5004 and tcp
#   [Wireshark]
#          tcp.port == 5004
#
#
# *  ȯ
#   Perl 5.8.8 ~
#   Windows / Linux
# 
# * 
#   perl Nateon
#   perl Nateon [ID] [PASSWORD]
#
# * ⺻ 
#   *  ׳ ø files 丮 ؿ ϵ ε ȴ.
#   * Windows / Linux  ׽Ʈ ߴ.
#   * / cdic(http://cdic.kldp.net)  ġ ؾ ϸ Windows ȯ濡  Ұϴ.
#
#   1.  ۼ/
#     1.1 ø
#         ε  Ʈ ش.
#
#     1.2  [ϸ]
#         ε  Ʈ ٿε Ѵ.
#
#     1.3  [ϸ]
#         ε  Ʈ Ѵ.
#
#   2. ϵ ڿ  ߼ 
#      addnick@nate.com ?
#
#   3.  
#      []
#
#   4.  ѿ /(http://cdic.kldp.net)
#     korea
#     ѱ
#     I hate you.
#
#
# *   
#   Event  ޼ҵ:
#     messengerEvent()
#   Message  ޼ҵ:
#     messengerMesg()
#
#
# * 
#   ɽؼ 2Ʋ  4ϰ ô װ  ҽϴ...
#   յ  ϰ ϴ ưԸ ϴ...
#     ư и  ȵư ȯ  ̶ ˴ϴ...
#   ׳ ɽǮ̷   ٰ ֽø ϰڽϴ... 
#

#------------------------------------------------------------------#
# NateOnPbot Start

my $id = $ARGV[0];
my $pw = $ARGV[1];

if (!$id) {print "NateOn ID       : "; $id = <STDIN>;}
if (!$pw) {print "NateOn PASSWORD : "; $pw = <STDIN>;}
chomp($id, $pw);

# ư 帧  ʹٸ 1 Ǵ 2 ü ڿ ־ָ ȴ.
# EX) my $NATEON = Nateon::new(2);
my $NATEON = Nateon::new();
$NATEON->messengerConnect($id, $pw);

# NateOnPbot End 
#------------------------------------------------------------------#


####################################################################
# Nateon Package Start
####################################################################

package Nateon;

use strict;
use Socket;
use Fcntl;
use Switch;
use IO::Select;
use IO::Handle;
use File::stat;
use Sys::Hostname;
use Digest::MD5;

local $|    = 1; # autoflush
$SIG{CHLD} = 'IGNORE'; # Avoiding zombie process

sub new {
	my $self = {};
	$self->{debug} = shift if defined($_[0]);
	$self->{timeout} = 2;
	$self->{flag} = 0;
	$self->{retval} = 0;
	$self->{cver} = "3.1337";
	$self->{sver} = "3.0";
	$self->{lang} = "KO";
	$self->{os} = "LINUX";
	$self->{hostname} = undef;
	$self->{ip} = undef;
	$self->{sock} = undef;
	$self->{nssock} = undef;
	$self->{sbsock} = undef;
	$self->{fifo} = undef;
	$self->{pwtype} = undef;
	$self->{loginid} = undef;
	$self->{loginpw} = undef;
	$self->{loginserver} = {"SERVER" => "203.226.253.91", "PORT" => 5004};
	$self->{notifyserver} = {"SERVER" => undef, "PORT" => undef};
	$self->{switchserver} = {"SERVER" => undef, "PORT" => undef};
	$self->{p2pserver} = {"SERVER" => undef, "PORT" => undef};

	# transaction id
	$self->{tid} = 0;
	# my Unique id
	$self->{uniq} = undef;
	# my name
	$self->{name} = undef;
	# my nick
	$self->{nick} = undef;
	# my phone
	$self->{phone} = undef;
	# my email
	$self->{email} = undef;
	# my sms ticket
	$self->{ticket} = undef;
	# group list
	$self->{glst} = undef;
	# friend list (status/uniq/name/nick/phone/birthday)
	$self->{list} = undef;
	# friend id
	$self->{fid} = undef;
	# fileinfo
	$self->{fileinfo} = undef;
	# p2pcookie
	$self->{p2pcookie} = undef;
	# frcookie
	$self->{frcookie} = undef;
	# file save directory
	$self->{filedir} = "files";	
	# order processor
	$self->{processor} = undef;

	return bless $self;
}

sub socketConnect {
	my $self = shift if ref ($_[0]);
	my $host = $_[0];
	my $port = $_[1];
	my $sock = ($_[2]) ? $_[2] : *SOCK;
	my $inet_addr = inet_aton($host);
	my $paddr = sockaddr_in($port, $inet_addr);

	socket($sock, PF_INET, SOCK_STREAM, getprotobyname('tcp'));

	eval {
		local $SIG{ALRM} = sub { die "timeout\n" };
		alarm($self->{timeout});
		connect($sock, $paddr);
		alarm(0);
	};

	if ($@) {
		if ($@ =~ /timeout/i) {
			print "::: ERROR : socketConnect : Timeout!\n";
		}
		else {
			print "::: ERROR : socketConnect : $@\n";
		}
		return undef;
	}
	return ($self->{sock} = $sock);
}

sub socketColse {
	my $self = shift if ref ($_[0]);
	$self->{tid} = 0;
	shutdown($self->{sock}, 0); # ڷ Է 
	shutdown($self->{sock}, 1); # ڷ  
	shutdown($self->{sock}, 2); # ڷ ̿ 
}

sub socketNonblock {
	# 0 = Nonblocking
	# 1 = blocking
	my $self = shift if ref ($_[0]);
	my $block = ($_[0]) ? $_[0] : 0;
	my $flag = undef;

	$flag = fcntl($self->{sock}, F_GETFL, 0) or die "Can't get flags for the socket: $!\n";

	if (!$block) {
		$flag = fcntl($self->{sock}, F_SETFL, $flag | O_NONBLOCK) or die "Can't set flags for the socket: $!\n";
	} else {
		# C fcntl() ó ߴµ ³ ??
		$flag = fcntl($self->{sock}, F_SETFL, $flag & ~O_NONBLOCK) or die "Can't set flags for the socket: $!\n";
	}
}

sub fifoReadlines {
	my $self = shift if ref ($_[0]);
	my $ret = undef;
	my @lines = undef;
	$ret = sysopen(FH, $self->{fifo}, O_RDONLY);
	@lines = FH->getlines() if ($ret);
	close(FH);
	return ($ret) ? @lines : $ret;
}

sub fifoPop {
	my $self = shift if ref ($_[0]);
	my $datap = $_[0];
	my $fifodata = undef;
	my @fifor = undef;
	my @fifow = undef;

	@fifor = $self->fifoReadlines();

	foreach(@fifor) {
		if ($_ =~ /$datap/i) {
			$fifodata = $_;
		} else {
			push(@fifow, $_);
		}
	}
	$self->fifoClear();
	foreach(@fifow) {
		$self->fifoWrite($_);
	}
	return $fifodata;
}

sub fifoWrite {
	my $self = shift if ref ($_[0]);
	my $writebuf = $_[0];
	my $ret = undef;
	$ret = sysopen(FH, $self->{fifo}, O_WRONLY|O_APPEND|O_CREAT, 0600);
	if ($ret) {
		$ret = FH->syswrite($writebuf);
	}
	close(FH);
	return $ret;
}

sub fifoClear {
	my $self = shift if ref ($_[0]);
	my $ret = undef;
	$ret = sysopen(FH, $self->{fifo}, O_TRUNC);
	close(FH);
	return $ret;
}

sub fileReadlines {
	my $self = shift if ref ($_[0]);
	my $path = $_[0];
	my $ret = undef;
	my @lines = undef;
	$ret = sysopen(FH, $path, O_RDONLY);
	@lines = FH->getlines() if ($ret);
	close(FH);
	return ($ret) ? @lines : $ret;
}

sub fileWrite {
	my $self = shift if ref ($_[0]);
	my $filename = $_[0];
	my $writebuf = $_[1];
	my $ret = undef;
	$ret = sysopen(FH, $filename, O_WRONLY|O_APPEND|O_CREAT, 0755);
	if ($ret) {
		$ret = FH->syswrite($writebuf);
	}
	close(FH);
	return $ret;
}

sub trim {
	my $self = shift if ref ($_[0]);
	my $str = $_[0];
	$str =~ s/^\s+//;
	$str =~ s/\s+$//;
	return $str;
}

sub recvByte {
	my $self = shift if ref ($_[0]);
	my $byte = $_[0];
	my $sock = ($_[1]) ? $_[1] : $self->{sock};
	my $bufsize = ($_[2]) ? $_[2] : 1024;
	my $c = 0;
	my $ret = undef;
	my $recvbyte = undef;
	my $recv = undef;
	my $recvbuf = undef;
	my $err = undef;
	my $len = undef;
	my $select = undef;
	my @ready = undef;

	$select = IO::Select->new();
	$select->add(\*{$sock});
	@ready = $select->can_read($self->{timeout});

	if ($ready[0] == \*{$sock}) {
	
		if ($bufsize > $byte) {

			while(1) {
				$recv = undef;
				if (sysread($sock, $recv, 1) > 0) {
					$recvbuf .= $recv;
					$err = undef;
					$ret++;
					last if ($ret == $byte);
				} else {
					# Connection colsed or error loop exit.
					if ($err > 1024) {
						print "::: ERROR : recvByte connection closed!\n";
						$self->{retval} = 0;
						last;
					}
					$err++
				}
			}

		} else {
			#  ӵ  ϱ ...
			while(1) {
				$recv = undef;
				if (($ret = sysread($sock, $recv, $bufsize)) > 0) {
					$recvbuf .= $recv;
					$err = undef;
					$recvbyte += $ret;
					if (($recvbyte+$bufsize) > $byte) {
						$bufsize = $byte - $recvbyte;
					}
					last if ($recvbyte == $byte);
				} else {
					# Connection colsed or error loop exit.
					if ($err > 1024) {
						print "::: ERROR : recvByte connection closed!\n";
						$self->{retval} = 0;
						last;
					}
					$err++
				}
			}

		}


	} else {
		print "::: ERROR : recv timeout : $self->{timeout} sec\n";
		$self->{retval} = 0;
	}

	$select->remove(\*{$sock});

	if ($self->{debug}) {
		if ($recvbuf) {
			print "<<< ";
			if ($self->{debug} == 1) {
				$len = length($recvbuf) - 1;
				foreach(0 .. $len) {
					$c = substr($recvbuf, $_, 1);
					if (ord("$c") < 128) {
						print $c;
					} else {
						print ".";
					}
				}
			} else {
				print "$recvbuf";
			}
			print "\n";
		}
	}
	return $recvbuf;
}

sub recvLine {
	my $self = shift if ref ($_[0]);
	my $sock = ($_[0]) ? $_[0] : $self->{sock};
	my $c = undef;
	my $ret = undef;
	my $err = undef;
	my $len = undef;
	my $recv = undef;
	my $recvbuf = undef;
	my $select = undef;
	my @ready = undef;

	$select = IO::Select->new();
	$select->add(\*{$sock});
	@ready = $select->can_read($self->{timeout});

	# sysread Return Value
	# undef on error
	# 0 at end of file
	# Integer, number of bytes read
	if ($ready[0] == \*{$sock}) {
		while(1) {
			$recv = undef;
			$ret = sysread($sock, $recv, 1);
			if ($ret > 0) {
				$recvbuf .= $recv;
				$err = undef;
				last if ($recv eq "\n");
			} else {
					# Connection colsed or error loop exit.
					if ($err > 1024) {
						print "::: ERROR : Connection colsed or error!\n";
						$self->{retval} = 0;
						last;
					}
					$err++
			}
		}

	} else {
		print "::: ERROR : recv timeout : $self->{timeout} sec\n";
		$self->{retval} = 0;
	}

	$select->remove(\*{$sock});

	if ($self->{debug}) {
		if (length($recvbuf)) {
			print "<<< ";
			if ($self->{debug} == 1) {
				$len = length($recvbuf) - 1;
				foreach(0 .. $len) {
					$c = substr($recvbuf, $_, 1);
					if (ord("$c") < 128) {
						print $c;
					} else {
						print ".";
					}
				}
			} else {
				print "$recvbuf";
			}
		}
	}
	return $recvbuf;
} 

sub sendLine {
	my $self = shift if ref ($_[0]);
	my $sendbuf = $_[0];
	my $sock = ($_[1]) ? $_[1] : $self->{sock};
	my $c = undef;
	my $len = undef;
	my $ret = undef;

	$ret = send($sock, $sendbuf, 0);

	if ($self->{debug}) {
		if (length($sendbuf)) {
			print ">>> ";
			if ($self->{debug} == 1) {
				$len = length($sendbuf) - 1;
				foreach(0 .. $len) {
					$c = substr($sendbuf, $_, 1);
					if (ord("$c") < 128) {
						print $c;
					} else {
						print ".";
					}
				}
			} else {
				print "$sendbuf";
			}
		}
	}

	return $ret;
}

sub lsDir {
	my $self = shift if ref ($_[0]);
	my $dir = $_[0];
	my $file = undef;
	my @files = undef;

	if (!opendir(DH, $dir)) {
		return undef;
	}
	while ( defined ($file = readdir(DH)) ) {
		if ($file ne "." && $file ne "..") {
			push(@files, $file);
		}
	}
	closedir(DH);
	return @files;
}

sub dirPrint {
	my $self = shift if ref ($_[0]);
	my $dir =$_[0];
	my $file = undef;
	my @files = undef;
	my $info = undef;
	my $tfile = undef;
	my $tsize = undef;
	my $print = undef;

	@files = $self->lsDir($dir);

	$print  = "+--------------------------------------------------------+\n";
	$print .= "|̸                                   |      |\n";
	$print .= "+--------------------------------------------------------+\n";
	foreach(@files) {
		if($_) {
			$info = stat("$dir/$_");
			$tfile++;
			$tsize += $info->size;
			$print .= sprintf("|%-42s | %-11d|\n", $_, $info->size);	
		}
	}
	$print .= "+--------------------------------------------------------+\n";
	$print .= sprintf("| üϼ : %-28d | %-11d|\n", $tfile, $tsize);
	$print .= "+--------------------------------------------------------+\n";
	return $print;
}

# ڰ  ޽ ǺϿ  ƾ ϴ ޼ҵ̴.
#  ޽Ͽ   ൿ ⼭  ָ ȴ.
sub messengerMesg {
	my $self = shift if ref ($_[0]);
	my $recvbuf = $_[0];
	my @recva = split(/%09/, $recvbuf);
	my $rmesg = messengerString($recva[3], "NR");
	my $smesg = undef;
	my $file = undef;
	my @files = undef;
	my @motd = undef;
	my $processor = undef;

	$rmesg = $self->trim($rmesg);

	# $rmesg ⿡ ڰ  ޽  ִ.

	print "<<< $self->{fid} -> $self->{loginid} : $rmesg\n";

	switch ($rmesg) {
		case /^ø/ {
			$smesg = $self->dirPrint("$self->{filedir}/$self->{fid}");
			$self->messengerMesgsend($self->{fid}, $smesg);	
		}
		case /^/ {
			$rmesg =~ s/[\r\n]//g;
			$rmesg =~ /^[ ]+(.*)/i;
			$file = "$self->{filedir}/$self->{fid}/$1";
			if (-e "$file" && ! -d "$file") {
				$self->messengerFilesendrequest($self->{fid}, $file);
			}
		}
		case /^/ {
			$rmesg =~ s/[\r\n]//g;
			$rmesg =~ /^[ ]+(.*)/i;
			$file = "$self->{filedir}/$self->{fid}/$1";
			if (-e "$file") {
				if(unlink($file)) {
					$self->messengerMesgsend($self->{fid}, "$1 :  Ϸ");
				}
			}
		}
		case /^/ {
			$rmesg =~ /^[ ]+([^ ]*)[ ]+(.*)/s;
			$self->messengerMemosend($1, $2);
		}
		case /^/ {
			@motd = fileReadlines("./welcome.txt");
			$self->messengerMesgsend($self->{fid}, " @motd");
		}
		case /^/ {
			$rmesg =~ s/[\r\n]//g;
			$rmesg =~ /^[ ]+(.*)/i;
			$self->messengerNick($1, $self->{nssock});
		}
		# ̿ ޽ ó ƾ
		#  ̿ ޽ ش  ó ý  ڷ  .
		else {
			# processor [args]
			# http://cdic.kldp.net
			$processor = '/usr/bin/cdic';

			if (-e $processor) {
				$rmesg =~ s/[\r\n]/ /g;
				$rmesg = quotemeta($rmesg);
				$smesg = `$processor $rmesg`;
			} else {
				$smesg = "[ ó ] : $rmesg";
			}
			$self->messengerMesgsend($self->{fid}, $smesg);	
		}
	}

}

sub messengerEvent {
	my $self = shift if ref ($_[0]);
	my $event = $_[0];
	my $recvbuf = $_[1];
	my @motd = undef;
	
	switch ($event) {
		#  ȭ û
		case "INVT" {
			@motd = fileReadlines("./welcome.txt");
			$self->messengerMesgsend($self->{fid}, " @motd");
		}
		#  ȭ ޽
		case "MESG" {
			$self->messengerMesg($recvbuf);
		}
		#   ޽
		case "IMSG" {
			#$self->messengerMesgsend($self->{fid}, " ̱~");
			#$self->messengerMemosend($self->{fid}, " ̱~");
		}
		#  ȭ 
		case "QUIT" {
			#$self->messengerMemosend($self->{fid}, "߰~");
		}
		#   ģ ߰
		case "ADDB" {
		}
		#   
		case "RMVB" {
		}
		#   
		case "NTFY" {
		}
		# ׿ ǵ  ̺Ʈ
		else {
			print ">>> $event : Not defined!\n";
		}

	}

}

sub messengerLoop {
	my $self = shift if ref ($_[0]);
	my $recvbuf = undef;
	my @recva = undef;

	$self->{timeout} = 300;

	while(1) {
		while (($recvbuf = $self->recvLine())) {
			@recva = split(/\s/, $recvbuf);

			R_SWITCH:
			{
				switch ($recva[0]) {	
					#  
					case "PING" {
						$self->messengerPing($recvbuf);
					}
					#    
					case "ONST" {
						print ">>> Login status change : ¶\n" if($recva[2] eq "O");
						print ">>> Login status change : ڸ\n" if($recva[2] eq "A");
						print ">>> Login status change : ٸ빫\n" if($recva[2] eq "B");
						print ">>> Login status change : ȭ\n" if($recva[2] eq "P");
						print ">>> Login status change : ȸ\n" if($recva[2] eq "M");
						print ">>> Login status change :  ǥ\n" if($recva[2] eq "F");
					}
					# ¶  Ʈ
					case "INFY" {
						$self->messengerBuddystatus($recvbuf);
					}
					# ģ  
					case "NTFY" {
						$self->messengerEvent("NTFY", $recvbuf);
						print ">>> Friend status changed : $recva[2] $recva[3]\n";
						$self->messengerBuddystatus($recvbuf);
						
					}
					# NICK  Ϸ
					case "CNIK" {
					}
					# ģ NICK 
					case "NNIK" {
					}
					# ģ  
					case "NPRF" {
					}
					# ģ ߰ ˸ RL ((BL|1011)/(AL|1101))
					case "ADDB" {
						#
						# ù ģ ߰ û
						# <<< ADDB 0 RL 5706413 addnick@nate.com ȳϼ.迵Դϴ. KR

						# 1101   
						# 1011    
						# 1100  ߰ Ŀ  ߰ų / ϰ  ߰ų / ׻ ģ  ź
						# 0001 ģ ߰ û
						# 0010   ߰
						# 0011  ϰ  ߰...

						# ģ  (C->S)
						# >>> ADDB [TID] BL [UNIQ] [UID]\r\n
						# >>> ADDB 8 BL 10014907669 addnick@nate.com\r\n

						#   (C->S)
						# >>> ADDB [TID] AL [UNIQ] addnick@nate.com\r\n
						# >>> ADDB 8 AL 10014907669 addnick@nate.com\r\n
	
						# ģ ߰ (C->S)
						# >>> ADSB [TID] REQST %00 [UID] [GROUPID] [ADDMSG]\r\n
						# >>> ADSB 18 REQST %00 addnick@nate.com 0 ߰شٿ!\r\n
						# <<< ADSB 18 REQST 10014907669 迵 298 KR\r\n
						# <<< NNIK 0 addnick@nate.com %00\r\n

						# ģ ߰ ˸ (S->C)
						# <<< ADDB 0 RL 10002735296 addnick@nate.com ߰شٿ! KR\r\n

						# ģ  (C->S)
						# >>> ADSB [TID] ACCPT [UNIQ] [UID] [GROUPID] %00\r\n
						# >>> ADSB 18 ACCPT 10002735296 addnick@nate.com 0 %00\r\n

						# ģ ź (C->S)
						# >>> ADSB [TID] REJCT [UNIQ] [UID] 0 %00\r\n
						$self->messengerEvent("ADDB", $recvbuf);
						print ">>> $recva[4] $recva[3] ģ \n";
						$self->messengerBuddyaccept($recva[3], $recva[4]);

					}
					# ģ   ϸ ˸
					case "RMVB" {
						# <<< RMVB 0 RL [UNIQ] [UID]
						# <<< RMVB 0 RL 10002735296 addnick@nate.com
						$self->messengerEvent("RMVB", $recvbuf);
					}
					# ģ   . (ȭû/...)
					case "CTOC" {
						# CTOC 0 [] [ɻ]\r\n[]
						$self->{fid} = $recva[2];
						$recvbuf = $self->recvByte($recva[3]);
						@recva = split(/\s/, $recvbuf);
						redo R_SWITCH;
					}
					#  
					case "IMSG" {
						$self->messengerEvent("IMSG", $recvbuf);
					}
					# ȭ û 
					case "INVT" {
						$self->messengerSwitch($recvbuf);
					}
					#  ۼ    
					case "PNAK" {
					}
					#  ۼ   
					case "REQC" {
						# REQC NEW -   
						# REQC RES -  ޱ 
						# REQC FR  - ޴ʿ ޱ ҰҶ FR   û  NS  (  P2P   Ұ  )
		
						#  ޱ 
						$self->messengerP2p($recvbuf) if ($recva[1] eq "RES");
						#   信  
						$self->messengerFilesendreply($recvbuf) if ($recva[1] eq "NEW");
						#   信 FR   û
						$self->messengerP2pfilesendfr($recvbuf) if ($recva[1] eq "FR");
					}
					# FR   ڷ 
					case "REFR" {
						$self->messengerP2p($recvbuf, "FR");
					}
					# SB  
					case "RESS" {
						$self->fifoWrite($recvbuf);
					}
					# TICK 
					case "TICK" {
						$self->messengerTicket($recvbuf);
					}
					# ٸ 
					case "KILL" {
						unlink($self->{fifo});
						$self->messengerQuit('>>> QUIT : Access someone!');
					}
					# ׿ ɵ
					else {
						print ">>> $recva[0] : Not defined at notify! : $recvbuf\n";	
					}
				}

			}
			$self->messengerQuit('>>> QUIT : MAIN') if ($self->{retval} == 0);
		}
		$self->messengerQuit('>>> QUIT : MAIN') if ($self->{retval} == 0);
	}
}

sub messengerSwitchloop {
	my $self = shift if ref ($_[0]);
	my $fid = $_[0];
	my $content = $_[1];
	my $recvbuf = undef;
	my $sendbuf = undef;
	my @recva = undef;
	$self->{fid} = ($fid) ? $fid : $self->{fid};

	# ð ȭ   
	$self->{timeout} = 300;

	if ($fid) {
		# >>> CTOC 24 mynick@nate.com N [CMD BYTE]
		#     INVT addnick@nate.com 211.234.239.202 5004 012BF1F0FC000976AF
		#  \r\n ִ   ! ׳ .
		$sendbuf = "INVT $self->{loginid} $self->{switchserver}->{SERVER} $self->{switchserver}{PORT} $self->{ticket}";
		$sendbuf = "CTOC 0 $fid N " . length($sendbuf) . "\r\n" . $sendbuf;
		$self->sendLine($sendbuf, $self->{nssock});
	}	

	while(1) {
		while (($recvbuf = $self->recvLine())) {
			@recva = split(/\s/, $recvbuf);

			switch ($recva[0]) {	
				# SB  
				case "ENTR" {
					print ">>> Nateon Switchboard login : $self->{fid}\n";
					$self->messengerEvent("INVT", $recvbuf);
				}
				# ڵ  
				case "USER" {
					# <<< USER 0 [IDX] [COUNT] [Sender ID] [NICK] [NAME]\r\n
					# <<< USER 0 1 1 addnick@nate.com 迵 迵
				}
				# SB  ɵ (  û/ ȭ û...)
				case "WHSP" {
					# WHSP [TID] [ID] [TYPE] [MESSAGE]\r\n
					switch ($recva[3]) {
						case "FILE" {
							# WHSP 0 [Sender ID] FILE REQUEST%09[FILE COUNT]%09[FILE NAME]|[FILE SIZE]|[FILE Cookie]\r\n
							if ($recvbuf =~ /FILE REQUEST/i) {
								$self->messengerFilerecvreply($recvbuf);
							}
							if ($recvbuf =~ /FILE CANCEL/i) {
								print ">>> FILE  \n";
							}
							if ($recvbuf =~ /FILE NACK/i) {
								@recva = split(/\|/,$recvbuf);
								print ">>> FILE   : $recva[2]\n";
								$self->fifoPop("WHSP 0 FILE SEND.*$recva[2]");
							}
						}
						else {

						}
					}
				}
				# ޽  (Ÿ/޽...)
				case "MESG" {
					if ($recva[3] =~ /MSG/i) {
						$self->messengerEvent("MESG", $recvbuf);
					}
				}
				# SB   ˸
				case "JOIN" {
					print ">>> Friend Switchboard joined!\n";
					#   ɶ...
					if ($content) {
						if ($content =~ /^WHSP 0.*FILE REQUEST/i) {
							$self->sendLine($content, $self->{sbsock});
						} else {
							$self->messengerMesgsend($self->{fid}, $content);
						}
						$content = undef;
					}
				}
				# SB 
				case "QUIT" {
					$self->messengerEvent("QUIT", $recvbuf);
					$self->messengerQuit(">>> QUIT : From switchboard : $self->{fid}");
				}
				else {
					print ">>> $recva[0] : Not defined at switchboard!\n";	
				}
			}

			$self->messengerQuit(">>> QUIT : $self->{fid} from switchboard") if ($self->{retval} == 0);
		}

		$self->messengerQuit(">>> QUIT : $self->{fid} from switchboard") if ($self->{retval} == 0);
	}
}

#   䱸
sub messengerFilesendrequest {
	my $self = shift if ref ($_[0]);
	my $fid = $_[0];
	my $path = $_[1];
	my $recvbuf = undef;
	my $sendbuf = undef;
	my %fi = {};
	my $info = stat($path);
	srand(time() ^ ($$ + ($$ << 15)));
	my $matrix = int(rand(2**10));
	my $p2pcookie = $self->{uniq} . ':' . $matrix;

	if (!$info) {
		exit(1);
	}

	$path = $self->messengerString($path, "NS");
	$fi{name} = $path;
	$fi{name} =~ s/.*\///g;
	$fi{size} = $info->size;
	$fi{cookie} = $self->{tid} . ':' . $p2pcookie;

	$sendbuf = "WHSP 0 $fid FILE REQUEST%091%09$fi{name}|$fi{size}|$fi{cookie}\r\n";

	if (!$self->{sbsock}) {
		# SB   ʾ ƾ̴.
		# RESS  źδ  mainLoop  óؾ Ѵ.
		print ">>> Filerequest sbsock create!\n";
		$self->sendLine("RESS $self->{tid}\r\n", $self->{nssock});
		$recvbuf = $self->recvLine($self->{nssock});
		$self->messengerSwitch($recvbuf, $fid, $sendbuf);

	} else {
		$self->sendLine($sendbuf, $self->{sbsock});
	}

	$self->{tid}++;

	# P2P Server Open
	my $pid = fork();
	if ($pid > 0) {
		$self->messengerP2plisten($fid, $path, \%fi);
	}
}

sub messengerP2plisten {
	my $self = shift if ref ($_[0]);
	my $fid = $_[0];
	my $path = $_[1];
	my $fi = $_[2];
	my $recvbuf = undef;
	my $ret = undef;
	my $c_addr = undef;
	my $c_addr_ip = undef;
	my $c_addr_port = undef;
	my $c_ip = undef;
	my $c_host = undef;
	my $port = 5004;
	my $opentime = 60;
	
    $self->fifoWrite("WHSP 0 FILE SEND $fid|$path|$fi->{name}|$fi->{size}|$fi->{cookie}\r\n");

	# socket() -> bind() -> listen() -> accept() -> send() / recv()
	socket(SERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp')) or die "socket: $!";
	setsockopt(SERVER, SOL_SOCKET, SO_REUSEADDR, 1) or die "setsockopt: $!";
	my $paddr = sockaddr_in($port, INADDR_ANY);
	$ret = bind(SERVER, $paddr);
	if (!$ret) {
		print ">>> Already P2plisten Opened : $port!\n";
		exit(0);
	}
	listen(SERVER, SOMAXCONN) or die "listen: $!";

	#  ð P2P    Ǹ ó 
	#  ð     ð پ... FR  ϰ...
	eval {
		R_ACCEPT:
		{
			$SIG{ALRM} = sub { die ">>> P2P Listen Closed!\n" };
			alarm($opentime);

			if ($c_addr = accept(CLIENT, SERVER)) {
				my $pid = fork();
				if ($pid > 0) {
					close(SERVER);
					$self->messengerP2pfilesend($c_addr, *CLIENT);
					exit(0);
				}
				print ">>> ACCEPT : $c_ip:$c_addr_port ACCEPT OK\n";
				close(CLIENT);
			}
			alarm(0);
			redo R_ACCEPT;
		}
	};
	print ">>> P2plisten Closed : PORT:$port / LISTEN TIME:$opentime\n";
	close(SERVER);
	exit(0);
}

sub messengerP2pfilesendfr {
	my $self = shift if ref ($_[0]);
	my $recvbuf = $_[0];;
	my $ret = undef;
	my $pid = undef;
	my @recva = split(/\s/, $recvbuf);
	my @sia = split(/:/, $recva[2]);

	# FR  ..
	$pid = fork();
	if ($pid > 0) {
		$self->{p2pcookie} = $recva[3];
		$self->{frcookie} = $recva[4];
		exit(1) if !$self->socketConnect($sia[0], $sia[1], *FR_SOCK);
		$self->messengerP2pfilesend(undef, *FR_SOCK, "FR");
	}

}

sub messengerP2pfilesend {
	my $self = shift if ref ($_[0]);
	my $c_addr = $_[0];;
	my $sock = $_[1];;
	my $fr = $_[2];;
	my $debug = $self->{debug};
	my $c_addr_ip = undef;;
	my $c_addr_port = undef;;
	my $c_ip = undef;;
	my $c_host = undef;;
	my $recvbuf = undef;
	my $sendbuf = undef;
	my $path = undef;
	my @fifor = undef;
	my @fifow = undef;
	my @recva = undef;
	my @recvaa = undef;
	my @fileinfo = undef;
	my $sendbyte = undef;
	my $ret = undef;
	my $c = undef;
	$self->{sock} = $sock;

	if ($c_addr) {
		($c_addr_port, $c_addr_ip) = sockaddr_in($c_addr);
		$c_ip = inet_ntoa($c_addr_ip);
		$c_host = gethostbyaddr($c_addr_ip, AF_INET);
	}

	# FR  
	if ($fr) {
		$self->sendLine("ATHC 0 $self->{loginid} $self->{fid} $self->{p2pcookie} $self->{frcookie} 6004 0\r\n");
		$recvbuf = $self->recvLine();
	} else {
		# <<< ATHC 0 [YOUR ID] [MY ID] 10002735296:14746 6004 0
		$recvbuf = $self->recvLine();
		@recva = split(/\s/, $recvbuf);
		$self->{p2pcookie} = $recva[4];
	}
	$recvbuf = $self->fifoPop("^REQC NEW.*$self->{p2pcookie}");
	if ($recvbuf) {
		# FR   ƴ϶
		if (!$fr) {
			$self->sendLine("ATHC 0 100 0\r\n");
		}
		$recvbuf = $self->recvLine();
		@recva = split(/\s/, $recvbuf);
		# <<< FILE 0 ACCEPT 1:10014907669:220 0
		$recvbuf = $self->fifoPop("^WHSP 0 FILE SEND.*$recva[3]");
		if ($recvbuf) {
			chomp $recvbuf;
			@recva = split(/\s/, $recvbuf);
			@recvaa = split(/\|/, $recva[4]);
			# >>> FILE 0 INFO FILENAME [FILE SIZE] CHAT 0\r\n
			$self->sendLine("FILE 0 INFO FILENAME $recvaa[3] CHAT 0\r\n");
			$recvbuf = $self->recvLine();
			if ($recvbuf =~ /START/i) {
				# >>> FILE [COUNT] DATA [DATA LEN]\r\n
				#     [DATA DUMP]
				# >>> FILE [TID] END N 0\r\n
				# ݺ : recvaa[1]  
				# 8191 send
				$path = $self->messengerString($recvaa[1], "NR");
				$ret = sysopen(FH, $path, O_RDONLY);

				if ($ret) {
					$self->{debug} = 0;
					while (($ret = sysread(FH, $sendbuf, 8191)) > 0) {
						$c++;
						$sendbyte += $ret;
						if (!$self->sendLine("FILE $c DATA $ret\r\n$sendbuf")) {
							print "::: FILE TRANSFER ERROR!\n";
							last;
						}
					}
					$self->{debug} = $debug;
					print "<<< [BINARY $sendbyte byte sent]\n" if($self->{debug});
					$recvbuf = $self->recvLine();
					
					if ($recvbuf =~ /FILE.*END/i) {
						print ">>> [$path] -> $self->{fid} : SUCCESS\n";
					} else {
						print ">>> [$path] -> $self->{fid} : FAILURE\n";
					}
				}

			}

		}
	}
	close($sock);
	exit(0);
}

#   信  
sub messengerFilesendreply {
	my $self = shift if ref ($_[0]);
	my $recvbuf = $_[0];
	my $sendbuf = undef;
	my @recva = split(/\s/, $recvbuf);

	$sendbuf = "REQC RES $self->{ip}:5004 $recva[3]\r\n";
	$sendbuf = "CTOC 0 $self->{fid} N " . length($sendbuf) . "\r\n" . $sendbuf;
	$self->sendLine($sendbuf, $self->{nssock});

	# REQC NEW 10.20.7.19:5004 10002735296:14718\r\n
	$self->fifoWrite($recvbuf);

}

#  ޱ⿡  
sub messengerFilerecvreply {
	my $self = shift if ref ($_[0]);
	my $recvbuf = $_[0];
	my $sendbuf = undef;
	srand(time() ^ ($$ + ($$ << 15)));
	my $matrix = int(rand(2**10));
	my $p2pcookie = $self->{uniq} . ':' . $matrix;
	my @recva = split(/\s/, $recvbuf);
	my @recvaa = split(/%09/, $recva[4]);

	$self->fifoWrite($recvbuf);

	# CTOC 0 [޴»] [ɻ]\r\n[]
	# CTOC [TID] [] N [ɻ]\r\n
	# >>> REQC NEW [My P2P IP]:[My P2P Port] [My P2P Cookie]\r\n
	# >>> CTOC 10 sendnick@nate.com N [CMD BYTE]
	#     REQC NEW 192.168.0.2:5004 902126197:192441888
	$sendbuf = "REQC NEW $self->{ip}:5004 $p2pcookie\r\n";
	$sendbuf = "CTOC 0 $recva[2] N " . length($sendbuf) . "\r\n" . $sendbuf;
	$self->sendLine($sendbuf, $self->{nssock});
}

sub messengerSwitchauth {
	my $self = shift if ref ($_[0]);
	my $ret = undef;
	my $recvbuf = undef;

	$self->{tid}++;
	$self->sendLine("ENTR $self->{tid} $self->{loginid} $self->{nick} $self->{name} $self->{ticket}\r\n");
	$recvbuf = $self->recvLine();	
	if ($recvbuf =~ /^(USER|ENTR)/i) {
		$self->{retval}++;
		$ret = 1;
	}

	if(!$ret) {
		$self->{retval} = 0;
		print "::: ERROR : SwitchAuth : $recvbuf\n";
		exit(1);

	}
}
sub messengerSwitchdetach {
	my $self = shift if ref ($_[0]);
	my $recvbuf = $_[0];
	my $fid = $_[1];
	my $content = $_[2];
	my @recva = split(/\s/, $recvbuf);

	$self->{nssock} = $self->{sock};
	$self->{fid} = $recva[1];
	$self->{ticket} = $recva[4];
	$self->{switchserver}->{SERVER} = $recva[2];
	$self->{switchserver}->{PORT} = $recva[3];
	exit(1) if !$self->socketConnect($self->{switchserver}->{SERVER}, $self->{switchserver}->{PORT}, *SB_SOCK);
	$self->{sbsock} = $self->{sock};
	$self->messengerSwitchauth();
	$self->socketNonblock();
	$self->messengerSwitchloop($fid, $content);
}

sub messengerSwitch {
	my $self = shift if ref ($_[0]);
	my $recvbuf = $_[0];
	my $fid = $_[1];
	my $content = $_[2];

	my $pid = fork();
	if ($pid > 0) {
		$self->messengerSwitchdetach($recvbuf, $fid, $content);
	}
}

sub messengerP2pdetach {
	my $self = shift if ref ($_[0]);
	my $recvbuf = $_[0];
	my $fr = $_[1];
	my $sendbuf = undef;
	my @recva = split(/\s/, $recvbuf);
	my @sia = (!$fr) ? split(/:/, $recva[2]) : ($recva[2], $recva[3]);
	my $p2pcookie = $recva[3];
	my $ret = undef;

	$self->{timeout} = 5;
	$self->{nssock} = $self->{sock};
	$self->{p2pcookie} = (!$fr) ? $p2pcookie : $self->{p2pcookie};
	$self->{p2pserver}->{SERVER} = $sia[0];
	$self->{p2pserver}->{PORT} = $sia[1];

	## Ÿ ƿ Ͼ FR    FR   û
	$ret = $self->socketConnect($self->{p2pserver}->{SERVER}, $self->{p2pserver}->{PORT}, *P2P_SOCK);

	# P2P    н FR  û
	# http://www.faqs.org/rfcs/rfc1918.html
	if ((!$ret && !$fr) || $self->{p2pserver}->{SERVER} =~ /(192\.168|172\.16|10\.)/) {
		$self->sendLine("REFR $self->{tid} $self->{fid}\r\n", $self->{nssock});
		exit(0);
	}
	# NS  FR  ޾ FR    NS  
	if ($fr) {
		# >>> FRIN 0 mynick@nate.com 52398074\r\n
		$self->sendLine("FRIN 0 $self->{fid} $recva[4]\r\n");
		$recvbuf = $self->recvLine();
		if ($recvbuf =~ /FRIN/i) {
			# >>> CTOC [TID] mynick@nate.com N [CMD BYTE]\r\n
			#     REQC FR 211.234.239.180:5004 10014907669:101 377222509\r\n
			$sendbuf = "REQC FR $self->{p2pserver}->{SERVER}:$self->{p2pserver}->{PORT} $self->{p2pcookie} $self->{frcookie}\r\n";
			$sendbuf = "CTOC $self->{tid} $self->{fid} N " . length($sendbuf) . "\r\n" . $sendbuf;
			$self->sendLine($sendbuf, $self->{nssock});
		} else {
			print "::: ERROR : messengerP2pdetach : $recvbuf : " . __LINE__ . "\n";
			exit(1);
		}
	}
	$self->messengerP2pfilerecv($fr);
}

sub messengerP2pfilerecv {
	my $self = shift if ref ($_[0]);
	my $fr = $_[0];
	my %fi = ($self->{fileinfo}) ? %{$self->{fileinfo}} : ();;
	my %si = %{$self->{p2pserver}};
	my $recvbyte = 0;
	my $recvbuf = undef;
	my @recva = undef;
	my $ret = undef;
	my $debug = $self->{debug};
	my $filename = $self->messengerString($fi{name}, "NR");
	my $path = ($self->{filedir}) ? $self->{filedir} . '/' . $self->{fid} . '/' . $filename : $filename;

	unless (-d $self->{filedir}) {
		mkdir($self->{filedir}, 0755) or die "can't mkdir $self->{filedir}: $!";
	}
	unless (-d "$self->{filedir}/$self->{fid}") {
		mkdir("$self->{filedir}/$self->{fid}", 0755) or die "can't mkdir $self->{filedir}/$self->{fid}: $!";
	}

	# >>> ATHC 0 [MY ID] [YOUR ID] [P2P COOKIE] 6004 0\r\n
	# <<< ATHC 0 100 6004 0\r\n
	# >>> FILE 0 ACCEPT [FILE COOKIE] 0\r\n
	# <<< FILE 0 INFO FILENAME [FILE SIZE] CHAT 0\r\n
	# >>> FILE 0 START [FILE OPSET] 0\r\n
	# <<< FILE [COUNT] DATA [DATA LEN]\r\n
	# <<< [DATA DUMP]

	if ($self->{debug}) {
		print "---------------------------------------------------------\n";
		print "P2P COOKIE : $self->{p2pcookie}\n";
		print "P2P SERVER : $si{SERVER}:$si{PORT}\n";
		print "MY ID      : $self->{loginid}\n";
		print "YOUR ID    : $self->{fid}\n";
		print "FILE INFO  : $fi{name}|$fi{size}|$fi{cookie}\n";
		print "---------------------------------------------------------\n";
	}

	$self->{timeout} = 5;

	# FR  
	if ($fr) {
		$recvbuf = $self->recvLine();
	} else {
		$self->sendLine("ATHC 0 $self->{loginid} $self->{fid} $self->{p2pcookie} 6004 0\r\n");
		$recvbuf = $self->recvLine();
	}
	if ($recvbuf =~ /ATHC/i) {
		# FR  
		if ($fr) {
			$self->sendLine("ATHC 0 100 6004 0\r\n");
		}
		$self->sendLine("FILE 0 ACCEPT $fi{'cookie'} 0\r\n");
		$recvbuf = $self->recvLine();
		if ($recvbuf =~ /INFO/i) {
			$self->sendLine("FILE 0 START 0 0\r\n");
			unlink($path);
			while($recvbuf = $self->recvLine()) {
				@recva = split(/\s/, $recvbuf);
				if ($recva[2] =~ /DATA/i) {
					$self->{debug} = 0;
					$recvbuf = $self->recvByte($recva[3]);
					$self->fileWrite($path, $recvbuf);
					$recvbyte += $recva[3];
					if ($fi{size} == $recvbyte) {
						$self->{debug} = $debug;
						print "<<< [BINARY $fi{'size'} byte received]\n" if ($self->{debug});
						$self->sendLine("FILE $self->{tid} END N 0\r\n");
						$self->{retval}++;
						$ret = 1;
						last;
					}
				}		
			}
		}	
	}
	if(!$ret) {
		$self->{retval} = 0;
		print "::: ERROR : p2pfilerecv : $recvbuf\n";
		$self->messengerQuit(">>> QUIT : File received from $self->{fid} -> $fi{name}($fi{size}byte) : FAILURE\n");
		exit(1);
	}
	$self->messengerQuit(">>> QUIT : File received from $self->{fid} -> $fi{name}($fi{size}byte) : SUCCESS\n");
}

sub messengerP2p {
	my $self = shift if ref ($_[0]);
	my $recvbuf = $_[0];
	my $fr = $_[1];
	my $pid = undef;
	my $ffp = undef;
	my @fileinfo = undef;
	my @recva = undef;
	my @recvaa = undef;

	my @recva = split(/\s/, $recvbuf);
	$self->{p2pcookie} = (!$fr) ? $recva[3] : $self->{p2pcookie};
	$self->{frcookie} = ($fr) ? $recva[4] : $self->{frcookie};

	$ffp = $self->fifoPop("$self->{fid} FILE REQUEST");

	if ($ffp) {
		chomp $ffp;
		@recva = split(/\s/, $ffp);
		@recvaa = split(/%09/, $recva[4]);
		@fileinfo = split(/\|/, $recvaa[2]);
		$self->{fileinfo}{name} = $fileinfo[0];
		$self->{fileinfo}{size} = $fileinfo[1];
		$self->{fileinfo}{cookie} = $fileinfo[2];
	}

	$pid = fork();
	if ($pid > 0) {
		$self->messengerP2pdetach($recvbuf, $fr);
	}
}

sub messengerConnect {
	my $self = shift if ref ($_[0]);
	my $id = $_[0];
	my $pw = $_[1];
	my $hostname = hostname();
	my $inet_addr = inet_aton($hostname);
	my $ip = ($inet_addr) ? inet_ntoa($inet_addr) : '192.168.0.2';
	$self->{loginid} = $id;
	$self->{loginpw} = $pw;
	$self->{hostname} = $hostname;
	$self->{ip} = $ip;
	$self->{fifo} = "/tmp/$id";
	unlink($self->{fifo});

	print ">>> Login Server Connect $self->{loginserver}->{SERVER}:$self->{loginserver}->{PORT}\n" if($self->{debug});
	exit(1) if !$self->socketConnect($self->{loginserver}->{SERVER}, $self->{loginserver}->{PORT});
	$self->messengerNotify($id);
	$self->messengerAuth($id, $pw);
	$self->messengerBuddylist();
	$self->messengerStatus("O");
	$self->socketNonblock();
	$self->{nssock} = $self->{sock};
	$self->messengerNick();
	$self->messengerLoop();
}

sub messengerNick {
	my $self = shift if ref ($_[0]);
	my $nick = ($_[0]) ? $self->messengerString($_[0], "NS") : "NateOnPbot";
	# >>> CNIK [TID] [NICK]\r\n
	$self->sendLine("CNIK $self->{tid} $nick\r\n", $self->{nssock});
}

sub messengerTicket {
	my $self = shift if ref ($_[0]);
	my $recvbuf = $_[0];
	my @recva = split(/\s/, $recvbuf);

	$self->{ticket} = $recva[2];
}

sub messengerStatus {
	# O - ¶
	# A - ڸ
	# B - ٸ빫
	# P - ȭ
	# M - ȸ
	# X -  ǥ
	my $self = shift if ref ($_[0]);
	my $status = $_[0];
	my $ret = undef;
	my $recvbuf = undef;

	$self->{tid}++;
	$self->sendLine("ONST $self->{tid} $status 0 %00 1\r\n");
}

sub messengerBuddyaccept {
	my $self = shift if ref ($_[0]);
	my $uniq = $_[0];
	my $fid = $_[1];
	# <<< ADDB 0 RL 10002735296 addnick@nate.com ߰شٿ! KR\r\n
	# >>> ADSB [TID] ACCPT [UNIQ] [UID] 0 %00\r\n
	# >>> ADSB 18 ACCPT 10002735296 addnick@nate.com 0 %00\r\n
	$self->sendLine("ADSB $self->{tid} ACCPT $uniq $fid 0 %00\r\n");
}

sub messengerBuddystatus {
	# O - ¶
	# A - ڸ
	# B - ٸ빫
	# P - ȭ
	# M - ȸ
	# F - 
	my $self = shift if ref ($_[0]);
	my $recvbuf = $_[0];
	my %list = %{$self->{list}};
	my @lista = split(/\s/, $recvbuf);
	my $fid = $lista[2];

	$list{$fid}{'status'} = $lista[3];

	$self->{list} = \%list;
}

sub messengerBuddypush {
	my $self = shift if ref ($_[0]);
	my $recvbuf = $_[0];
	my @lista = split(/\s/, $recvbuf);
	my $fid = $lista[5];

	$self->{list}->{$fid}{'status'} = 'F';
	$self->{list}->{$fid}{'uniq'} = $lista[6];
	$self->{list}->{$fid}{'name'} = $lista[7];
	$self->{list}->{$fid}{'nick'} = $lista[8];
	$self->{list}->{$fid}{'phone'} = $lista[9];
	$self->{list}->{$fid}{'birthday'} = $lista[11];

}

sub messengerBuddylist {
	my $self = shift if ref ($_[0]);
	my $ret = undef;
	my $recvbuf = undef;

	# GLST - ׷  (屸 !)
	$self->{tid}++;
	$self->sendLine("GLST $self->{tid}\r\n");
	$recvbuf = $self->recvLine();
	if ($recvbuf =~ /GLST $self->{tid}/i) {
		my @glsta = split(/\s/, $recvbuf);

		if ($glsta[2] > 0) {
			$recvbuf = $self->recvLine();
			my @glsta = split(/\s/, $recvbuf);
			foreach(2 .. $glsta[3]) {
				$recvbuf = $self->recvLine();
			}
		}

	}

	# LIST -  
	# LIST [TID] [SEQ] [TOTAL] 1101 [FRIEND ID] [UNIQ] [NAME] %00 [PHONE] %00 [BIRTHDAY] %00 1 1 %00 %00 N KR
	$self->{tid}++;
	$self->sendLine("LIST $self->{tid}\r\n");
	$recvbuf = $self->recvLine();
	if ($recvbuf =~ /LIST $self->{tid}/i) {
		my @lista = split(/\s/, $recvbuf);
		my $listn = $lista[3];
		$self->messengerBuddypush($recvbuf);
		foreach(2 .. $listn) {
			$recvbuf = $self->recvLine();
			if ($recvbuf =~ /LIST $self->{tid}/i) {
				$self->messengerBuddypush($recvbuf);
			}
		}
		
	}
}

sub messengerAuth {
	my $self = shift if ref ($_[0]);
	my $id = $_[0];
	my $pw = $_[1];
	my $ret = undef;
	my $recvbuf = undef;
	my $digest = undef;
	my @ida = undef;
	my @lsina = undef;
	my $ctx = Digest::MD5->new();	

	$self->{tid}++;

	@ida = ($id =~ /nate\.com$/i) ? split(/\@/, $id) : $id;
	$ctx->add($pw . $ida[0]);
	$digest = $ctx->hexdigest;
	$digest = ($self->{pwtype}) ? $pw : $digest;
	$self->sendLine("LSIN $self->{tid} $id $digest MD5 3.33 $self->{lang}\r\n");
	$recvbuf = $self->recvLine();

	if ($recvbuf =~ /LSIN $self->{tid}/i) {
		@lsina = split(/\s/, $recvbuf);
		$self->{uniq} = $lsina[2];
		$self->{name} = $lsina[3];
		$self->{nick} = $lsina[4];
		$self->{phone} = $lsina[5];
		$self->{email} = $lsina[14];
		$self->{ticket} = $lsina[7];
		$self->{retval}++;
		$ret = 1;
	}
	if(!$ret) {
		$self->{retval} = 0;
		print "::: ERROR : Auth : $recvbuf\n";
		exit(1);	
	}
}

sub messengerNotify {
	my $self = shift if ref ($_[0]);
	my $id = $_[0];
	my %si = $self->{notifyserver};
	my $ret = undef;
	my $recvbuf = undef;
	my @reqsa = undef;
	my $offset = (localtime)[5];

	$self->{tid}++;

	$self->sendLine("PVER $self->{tid} $self->{cver} $self->{sver} $self->{lang}.$self->{os}\r\n");
	
	$recvbuf = $self->recvLine();

	if ($recvbuf =~ /PVER $self->{tid}/i) {
		$self->{tid}++;
		$self->sendLine("AUTH $self->{tid} DES\r\n");
		$recvbuf = $self->recvLine();
		if ($recvbuf =~ /AUTH $self->{tid} DES/i) {
			$self->{tid}++;
			$self->sendLine("REQS $self->{tid} DES $id\r\n");
			$recvbuf = $self->recvLine();
			if ($recvbuf =~ /REQS $self->{tid}/i) {
				@reqsa = split(/\s/, $recvbuf);
				$si{'SERVER'} = $reqsa[3];
				$si{'PORT'} = $reqsa[4];
				$self->socketColse();
				exit(1) if !$self->socketConnect($si{'SERVER'}, $si{'PORT'});
				print ">>> Notify Server Connect $si{'SERVER'}:$si{'PORT'}\n" if($self->{debug});
				$self->{retval}++;
				$ret = 1;
			}
		}
	}
	if(!$ret) {
		$self->{retval} = 0;
		print "::: ERROR : Notification : $recvbuf\n";
		exit(1);	
	}
}

sub messengerString {
	my $self = shift if ref ($_[0]);
	my $repbuf = $_[0];
	my $reptype = $_[1];
	#   ߱ ؼ  Ű hash  ƴ 2 迭 
	my @repa = (["\%" => '%25'],
				[" " => '%20'],
				["\t"=> '%20'],
				["\n"=> '%0A']
	);

	# NateOn Send Type (Ʈ¿  ȯ Ÿ)
	if ($reptype eq "NS") {
		foreach (0 .. $#repa) {
			$repbuf =~ s/@{$repa[$_]}[0]/@{$repa[$_]}[1]/g;
		}
	}
	# NateOn Recv Type (Ʈ¿  ȯ Ÿ)
	if ($reptype eq "NR") {
		foreach (0 .. $#repa) {
			$repbuf =~ s/@{$repa[$_]}[1]/@{$repa[$_]}[0]/g;
		}
	}
	return $repbuf;
}

sub messengerMesgsend {
	my $self = shift if ref ($_[0]);
	my $fid = $_[0];
	my $content = $_[1];
	my $sendbuf = undef;
	my $recvbuf = undef;
	my $ret = undef;

	if (!$self->{sbsock}) {
		# ̹  SB  ִٸ ο  ü ǹ.
		# SB   ʾ ƾ̴.
		print ">>> Mesgsend sbsock create!\n";
		$self->sendLine("RESS $self->{tid}\r\n", $self->{nssock});
		$recvbuf = $self->recvLine($self->{nssock});
		$self->messengerSwitch($recvbuf, $fid, $content);
		
	}

	$content = $self->messengerString($content, 'NS');
	# >>> MESG 1 MSG [ü]%09[ڻ]%09[ȿ]%09[]
	$sendbuf = "MESG $self->{tid} MSG ü%090%09%09$content\r\n";
	$self->sendLine($sendbuf, $self->{sbsock});
}

sub messengerMemosend {
	my $self = shift if ref ($_[0]);
	my $fid = $_[0];
	my $content = "From : $self->{fid} -> [NateOnPbot] -> ſ\r\n" . $_[1];
	my $sendbuf = undef;
	my ($day,$month,$year,$hour,$min,$sec) = (localtime)[3,4,5,2,1,0];
	my $date = sprintf("%04d%02d%02d%02d%02d%02d",1900+$year,$month+1,$day,$hour,$min,$sec);
	my @contenta = split(/\s/, $content);
	my $title = $contenta[int(rand($#contenta))];
	srand(time() ^ ($$ + ($$ << 15)));
	my $matrix = int(rand(2**32));
	my $ctx = Digest::MD5->new();
	my $digest = $ctx->add($matrix . 'v0zlt')->hexdigest;
	my $uuid = undef;

	$uuid  = substr($digest, 0, 8) . '-';
	$uuid .= substr($digest, 8, 4) . '-';
	$uuid .= substr($digest, 12, 4) . '-';
	$uuid .= substr($digest, 16, 4) . '-';
	$uuid .= substr($digest, 20, 12);

	# CTOC 0 [޴»] [ɻ]\r\n
	# IMSG\r\n
	# CONTENTS
	#  Ȯ confirm:1
	$sendbuf  = "IMSG\r\n";
	$sendbuf .= "contenttype:text\r\n";
	$sendbuf .= "date:$date\r\n";
	$sendbuf .= "font-color:#050505\r\n";
	$sendbuf .= "font-name:\r\n";
	$sendbuf .= "font-size:9\r\n";
	$sendbuf .= "font-style:%00\r\n";
	$sendbuf .= "from:$self->{loginid}\r\n";
	$sendbuf .= "length:" . length($content) . "\r\n";
	$sendbuf .= "ref:$fid\r\n";
	$sendbuf .= "session_id:$matrix\r\n";
	$sendbuf .= "title:$title\r\n";
	$sendbuf .= "uuid:$uuid\r\n";
	$sendbuf .= "\r\n";
	$sendbuf .= "$content";
	$sendbuf = "CTOC 0 $fid " . length($sendbuf) . "\r\n" . $sendbuf;

	$self->sendLine($sendbuf, $self->{nssock});
}

sub messengerPing {
	my $self = shift if ref ($_[0]);
	my $recvbuf = $_[0];
	my $ret = undef;
	if ($recvbuf =~ /PING/i) {
		$self->sendLine("PING $self->{tid}\r\n");
	}
}

sub messengerQuit {
	my $self = shift if ref ($_[0]);
	my $msg = ($_[0]) ? $_[0] : '>>> QUIT';
	print "$msg\n";
	$self->socketColse();
	exit(0);
}

1;

####################################################################
# Nateon Package End
####################################################################

__END__


=head1 NAME

NateOnPbot - NateOn Perl Bot

=head1 SYNOPSIS

 perl Nateon
 perl Nateon [ID] [PASSWORD]

 OR

 my $NATEON = Nateon::new();
 $NATEON->messengerConnect('mynick@nate.com', 'plaintext');

 OR

 my $NATEON = Nateon::new();
 $NATEON->{pwtype} = "DES";
 $NATEON->messengerConnect('mynick@nate.com', '2a40b8b33ea57a0846q3rf9ac6c15030');

 OR

 # Debug Level = 0(NONE) / 1(ASCII) / 2(BINARY)
 my $NATEON = Nateon::new($DEBUG);
 $NATEON->messengerConnect('mynick@nate.com', 'plaintext');

=head1 DESCRIPTION

NateOnPbot is a program of the bot form which to makes with perl.

The following methods are provided by this module:

=over

=item I<messengerEvent($event, $recvbuf)>

{ Event control routine }

=item I<messengerMesg($recvbuf)>

{ Message control routine }

=over

=head1 AUTHOR

YoungJoo-Kim <bando@bando.org>

=cut

