# Copyright (C) 2005 FishGrove Inc.
#
# 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.
#
# $Id: Handshaker_c.pm,v 1.18 2006/03/07 14:39:11 slash5234 Exp $

package Affelio::SNS::Handshaker_c;
{
    use strict;
    use lib("../../../extlib/");
    use Crypt::DH;
    use XMLRPC::Lite;
    use Error qw(:try);
    use MIME::Base64;

    use lib("../../../lib/");
    use Affelio::misc::CGIError;
    use Affelio::misc::Debug;
    use Affelio::misc::MyCrypt;
    use Affelio::misc::Time;
    use Affelio::exception::Exception;
    use Affelio::exception::InvalidInputException;
    use Affelio::exception::IOException;
    use Affelio::exception::NetworkException;

    use Exporter;
    @Affelio::SNS::Handshaker_c::ISA= "Exporter";
    @Affelio::SNS::Handshaker_c::EXPORT = qw(send_HandShake reply_HandShake get_F2List post_Message get_news);

    #################################################################
    # send_HandShake(dest_url =>  $dest_uri, 
    #                my_nickname => my_nickname,
    #                my_AFID => my_AFID,
    #                mesg => mesg,
    #                timestamp => timestamp); 
    # proto_ver: 1.1
    #################################################################
    sub send_HandShake {
	my %arg = @_;
	my $dest_uri = $arg{dest_uri};
	my $my_nickname = $arg{my_nickname};
	my $my_AFID = $arg{my_AFID};
	my $my_mesg = $arg{mesg};
	my $timestamp = $arg{timestamp};

	my $proto_ver = 1.1;
	my $MIMed_mesg = encode_base64($my_mesg);

	#################################
	#Arg check (1): dest_uri
	#################################
	if ($dest_uri !~ /^http/) {
	    throw Affelio::exception::InvalidInputException("dest_url");
	}
	my $dest_xml_uri = $dest_uri . "/bin/xml-rpc-serv.cgi";

	#################################################
	#prepare DH pub key 
        #RFC 2412 - The OAKLEY Key Determination Protocol
        #Group 1:  A 768 bit prime
	#################################################
	my $mydh = Crypt::DH->new;
        my $DH_g="2";
        my $DH_p="1552518092300708935130918131258481755631334049434514313202351194902966239949102107258669453876591642442910007680288864229150803718918046342632727613031282983744380820890196288509170691316593175367469551763119843371637221007210577919";
	$mydh->g($DH_g);
	$mydh->p($DH_p);
	$mydh->generate_keys;
	my $my_DH_pub_key_str = $mydh->pub_key->bstr;
	my $my_DH_pri_key_str = $mydh->priv_key->bstr;

	debug_print("send_HandShake: [$dest_xml_uri $proto_ver $timestamp $my_nickname $my_AFID $my_DH_pub_key_str $my_mesg $MIMed_mesg]");
 
	#################################
	#Execute XMLRPC
	#################################
	my $res = eval {
	    XMLRPC::Lite
		->proxy($dest_xml_uri)
		->call(
		       'affelio.HandShake', 
		       $proto_ver,
		       $timestamp,
		       $my_nickname,
		       $my_AFID,
		       $my_DH_pub_key_str,
		       $MIMed_mesg)
		->result;
	  };
	debug_print("send_HandShake: RPC returned.\n");
	if ($@) {
	    throw Affelio::exception::NetworkException($@);
	}
	if($res->{flerror} ne "0"){
	    throw Affelio::exception::NetworkException("Flerror > 0: $res->{message}");
	}

	debug_print("send_HandShake: OK:[$res->{flerror}] [$res->{message}]"); 
	debug_print("send_HandShake: end.");
	return $my_DH_pri_key_str; 
    }


    #################################################################
    # reply_HandShake(dest_url =>  $dest_uri, 
    #                 timestamp => $timestamp,
    #                 my_nickname => my_nickname,
    #                 my_AFID => my_AFID,
    #                 DH_pub_key_str => DH_pub_key_str,
    #                 my_mesg => mesg);
    # proto_ver: 1.1
    #################################################################
    sub reply_HandShake {
	my %arg = @_;
	#
	my $proto_ver = 1.1;
	my $dest_uri = $arg{dest_uri};
	my $timestamp = $arg{timestamp};
	my $my_nickname = $arg{my_nickname};
	my $my_AFID = $arg{my_AFID};
	my $my_DH_pub_key_str = $arg{DH_pub_key_str};
	my $my_mesg = $arg{mesg};

	debug_print("reply_HandShake: [$dest_uri $proto_ver $timestamp $my_nickname $my_AFID $my_DH_pub_key_str $my_mesg]");
	
	#################################
	#Arg check
	#################################
	if ($dest_uri !~ /^http/) {
	    throw Affelio::exception::InvalidInputException("dest_url");
	}
	my $dest_xml_uri = $dest_uri . "/bin/xml-rpc-serv.cgi";
	
	#################################
	#Execute XMLRPC
	#################################
	my $res = eval {
	    XMLRPC::Lite
		->proxy($dest_xml_uri)
		->call(
		       'affelio.HandShakeReply', 
		       $proto_ver,
		       $timestamp,
		       $my_nickname,
		       $my_AFID,
		       $my_DH_pub_key_str,
		       $my_mesg
		       )
		->result;
	  };
	debug_print("reply_HandShake: RPC returned.\n");
	if ($@) {
	    throw Affelio::exception::NetworkException($@);
	}
	if($res->{flerror} ne "0"){
	    throw Affelio::exception::NetworkException($res->{message});
	}

	debug_print("reply_HandShake: [$res->{flerror}] [$res->{message}]");
	debug_print("reply_HandShake: end.");
	return $res;
    }

    ##################################################################
    #get_news
    # proto_ver: 1
    ##################################################################
    sub get_news{
	my %arg = @_;
	my $proto_ver = 1.0;
	my $dest_uri = $arg{dest_uri};
	my $xwsse_mesg = $arg{xwsse_mesg};
	my $format = "plain";

	debug_print("C::get_news: dest=[$dest_uri]");
	debug_print("C::get_news: wsse=[$xwsse_mesg]");

	#################################
	#Arg check
	#################################
	if ($dest_uri !~ /^http/) {
	    throw Affelio::exception::InvalidInputException("dest_uri");
	}
	my $dest_xml_uri = $dest_uri . "/bin/xml-rpc-serv.cgi";

	#################################
	#Execute XMLRPC
	#################################
	my $res = eval {
	    XMLRPC::Lite
		->proxy($dest_xml_uri) #XML
		->call(
		       'affelio.get_news',
		       $proto_ver,
		       $xwsse_mesg,
		       $format,
		       )
		->result;
	  };

	debug_print("C::get_news: RPC returned.\n");
	if ($@) {
	    throw Affelio::exception::NetworkException($@);
	}
	if($res->{flerror} ne "0"){
	    throw Affelio::exception::NetworkException("XML-RPC Error: " . $res->{message});
	}

	debug_print("C::get_news: OK: [$res->{flerror}] [$res->{message}]");
	debug_print("C::get_news: end.");
	return $res;
    }

    #################################################################
    # post_Message
    # proto_ver: 1
    #################################################################
    sub post_Message{
	my %arg = @_;
	#arg (part 1)
	my $proto_ver = 1.0;
	my $dest_uri = $arg{dest_uri};
	my $src = $arg{src};
	my $password = $arg{password};

	#arg (part 2)
	my $msg_from = $arg{msg_from};
	my $msg_from_nickname = $arg{msg_from_nickname};
	my $msg_to = $arg{msg_to};
	my $msg_timestamp = $arg{msg_timestamp};
	my $MIMed_msg_title = encode_base64($arg{msg_title});
	my $MIMed_msg_body = encode_base64($arg{msg_body});

	debug_print("C::post_Message: dest=[$dest_uri]");
	debug_print("C::post_Message: $msg_from, $msg_from_nickname, $msg_to, $msg_timestamp, [$MIMed_msg_title], [$MIMed_msg_body]");

	############################
	#Generate XML
	############################
	my $XMLbody = <<EOT;
<message>
<header>
<from>$msg_from</from>
<from_nickname>$msg_from_nickname</from_nickname>
<to>$src</to>
<timestamp>$msg_timestamp</timestamp>
<title>$MIMed_msg_title</title>
</header>
<body>
<text>$MIMed_msg_body</text>
</body>
</message>
<src>$src</src>
EOT
	############################
	#Encryption
	############################
	my $encrypted = msg_encrypt($XMLbody, $password);

	############################
	#MIME encode
	############################
	my $MIMed = encode_base64($encrypted);
	debug_print("C::post_Message: [$MIMed]");

	############################
	#xml uri
	############################
	if ($dest_uri !~ /^http/) {
	    throw Affelio::exception::InvalidInputException("dest_uri");
	}
	my $dest_xml_uri = $dest_uri . "/bin/xml-rpc-serv.cgi";

	############################
	#Send to the destination through XMLRPC
	############################
	my $res = eval {
	    XMLRPC::Lite
		->proxy($dest_xml_uri) #XML
		->call(
		       'affelio.post_Message', 
		       $proto_ver,
		       get_timestamp(),
		       $src,
		       $MIMed
		       )
		->result;
	  };
	debug_print("C::post_Message: RPC returned.\n");
	if ($@) {
	    throw Affelio::exception::NetworkException($@);
	}
	if($res->{flerror} ne "0"){
	    throw Affelio::exception::NetworkException("XML-RPC Error: " . $res->{message});
	}

	debug_print("C::post_mesg: OK: [$res->{flerror}] [$res->{message}]");
	debug_print("C::post_mesg: end.");
	return $res;
    }

    #################################################################
    # get_F2List(dest_uri, timestamp)
    # proto_ver: 1
    #################################################################
    sub get_F2List {
	my %arg = @_;
	my $proto_ver = 1.0;
	my $dest_uri = $arg{dest_uri};
	my $timestamp = $arg{timestamp};

	debug_print("get_F2List: $dest_uri $proto_ver $timestamp");

	#################################
	#Arg check
	#################################
	if ($dest_uri !~ /^http/) {
	    throw Affelio::exception::InvalidInputException("dest_uri");
	}
	my $dest_xml_uri = $dest_uri . "/bin/xml-rpc-serv.cgi";

	#################################
	#Execute XMLRPC
	#################################
	my $res = eval {
	    XMLRPC::Lite
		->proxy($dest_xml_uri)
		->call(
		       'affelio.F2List', 
		       $proto_ver,
		       $timestamp,
		       )
		->result;
	  };
	debug_print("C::get_F2List: RPC returned.\n");
	if ($@) {
	    throw Affelio::exception::NetworkException($@);
	}
	if($res->{flerror} ne "0"){
	    throw Affelio::exception::NetworkException($res->{message});
	}

	debug_print("C::get_F2list: OK: [$res->{flerror}] [$res->{message}]");
	debug_print("C::get_F2list: end.");
	return $res;
    }



}
1;
