////////////////////////////////////////////////////////////////////////////
// CSyInstance クラスのインプリメンテーション
//
////////////////////////////////////////////////////////////////////////////

#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <string>


#include "CommandID.h"
#include "SyInstance.h"
#include "ProcStart.h"
#include "NegCmd.h"
#include "FD.h"
#include "VPtr.h"

using namespace NNabikiVPtr;

////////////////////////////////////////////////////////////////////////////
// 構築/破棄
////////////////////////////////////////////////////////////////////////////

CSyInstance::CSyInstance() :
	pErrorMsg( NULL )
{

}

CSyInstance::~CSyInstance()
{

}

////////////////////////////////////////////////////////////////////////////
// メソッド
////////////////////////////////////////////////////////////////////////////

// 初期化
bool CSyInstance::Initialize()
{
	const char *p = getenv( SCEV_COMMUNITY_PATH );

	if ( NULL == p ) {
		fprintf( stderr, "ERROR Syuhitu server : %s environment valuable is empty.\n", SCEV_COMMUNITY_PATH );
		return false;
	}
	CommunityPath = p;

	listInstance.clear();

	return true;
}

// 既存の主筆の情報を取得
void CSyInstance::UpdateExistTaEditInfo()
{
	list< TAEDIT_INFO > wList;

	if ( !SearchExistTaEditInfo( &wList ) )
		fprintf( stderr, "ERROR Syuhitu server : It failed to update exist Syuhitu information.\n" );
	else
		listInstance = wList;
}

// 既存の主筆の情報を取得
bool CSyInstance::SearchExistTaEditInfo( list< TAEDIT_INFO > *pList )
{
	DIR *pDir;
	struct dirent *pEnt;
	const char *p;
	string DirName;
	int suflen;
	string fname;

	assert( pList );

	// 名前付きパイプが格納されるディレクトリを取得
	p = getenv( SCEV_COMMUNITY_PATH );
	if ( !p ) return false;

	DirName = p;
	if ( DirName.length() <= 0 ) DirName = ".";
	if ( DirName[ DirName.length() - 1 ] == '/' )
		DirName = DirName.substr( 0, DirName.length() - 1 );

    // ディレクトリを開く
	pDir = opendir( DirName.c_str() );
	if ( NULL == pDir ) return false;

	suflen = strlen( SCPX_TO_SYUHITU );
	while ( -1 ) {
		// 次のファイルを検索する
		pEnt = readdir( pDir );
		if ( !pEnt ) break;

		string subname = pEnt->d_name;

		// 主筆へデータを送信するためのパイプか否か
		if ( strncmp( pEnt->d_name, SCPX_TO_SYUHITU, suflen ) ) continue;

		// ファイル名からpidを取得
		int pid = atoi( subname.c_str() + suflen );

		// ファイル名を問い合わせる	
		if ( RequestFileName_ToTaEdit( pid, &fname ) ) {
			// リストに追加する
			TAEDIT_INFO wInfo( fname, pid );
			pList->push_back( wInfo );
			// サーバが再起動されたことを通知する
			NoticeServerReboot_ToTaEdit( pid );
		}
	}

	// ハンドルを閉じる
	closedir( pDir );

	return true;
}

// ファイルを開く（主筆の起動ないしアクティブ化）
void CSyInstance::OpenFile_CS( const CNegCmd &rCmd, CNegCmd *pToClient )
{
	list< TAEDIT_INFO >::iterator itr;

	assert( this );
	pToClient->AddData( SCI_R_STOPPED, SCID_RSTOP_RESUME );

	// ファイル名を取得
	const string &FileName = rCmd.GetData( SCI_S_FILE_NAME, string( "" ) );

	// 指定されたファイルを開いている「主筆」の有無を確認
	if ( !FileName.empty() ) {
		itr = listInstance.begin();
		for (; itr != listInstance.end() && itr->FileName != FileName; itr++ );
	}
	else
		itr = listInstance.end();

	if ( itr == listInstance.end() ) {
		// そのファイルを開いている物がなかった場合は、新しく起動する
		if ( StartSyuhitu( FileName, rCmd ) >= 0 )
			pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_OK );
		else {
			pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_ERR );
			pToClient->AddData( SCI_R_FREE_MSG, "It failed to start Syuhitu." );
		}
	}
	else {
		// 指定されたファイルを開いているものをアクティブにする
		if ( ActivateSyuhitu( itr->pid, rCmd ) )
			pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_OK );
		else {
			pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_ERR );
			pToClient->AddData( SCI_R_FREE_MSG, "It failed to avtivate syuhitu." );
		}
	}
}

// 主筆側でファイルが開かれる
void CSyInstance::OpenFile_TS( const CNegCmd &rCmd, CNegCmd *pToClient )
{
	list< TAEDIT_INFO >::iterator itr1, itr2;
	int pid;

	// ファイル名とプロセスIDを取得
	const string &FileName = rCmd.GetData( SCI_S_FILE_NAME, string( "" ) );
	pid = rCmd.GetData( SCI_S_PID, -1 );
	if ( FileName.empty() || pid < 0 ) {
		pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_ERR );
		pToClient->AddData( SCI_R_STOPPED, SCID_RSTOP_STOP );
		pToClient->AddData( SCI_R_FREE_MSG, "Command data is insufficiency." );
		return ;
	}

	// 呼び出し元プロセスの情報を検索
	itr1 = listInstance.begin();
	for (; itr1 != listInstance.end() && itr1->pid != pid; itr1++ );

	// 指定されたファイルを開いている「主筆」の有無を確認
	if ( !FileName.empty() ) {
		itr2 = listInstance.begin();
		for (; itr2 != listInstance.end() && itr2->FileName != FileName; itr2++ );
	}
	else
		itr2 = listInstance.end();

	if ( itr2 == listInstance.end() ) {
		// 当該のファイルを開いている奴がなければ、呼び出し元に開かせる
		pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_OK );
		pToClient->AddData( SCI_R_STOPPED, SCID_RSTOP_RESUME );

		// 呼び出し元プロセスの情報を更新する
		if ( itr1 != listInstance.end() )
			itr1->FileName = FileName;
		else
			listInstance.push_back( TAEDIT_INFO( FileName, pid ) );
	}
	else {
		if ( itr2->pid == pid ) {
			// 呼び出し元が開いているファイルを再度開く場合は、
			// 特にすることはない
			pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_OK );
			// （ただし、呼び出し元の主筆には再読込を行わせる）
			pToClient->AddData( SCI_R_STOPPED, SCID_RSTOP_RESUME );
		}
		else {
			// （アクティブ化の成功・失敗に関わらず、呼び出し側でファイルを開かせない）
			pToClient->AddData( SCI_R_STOPPED, SCID_RSTOP_STOP );

			// 指定されたファイルを開いている主筆をアクティブにする
			if ( !ActivateSyuhitu( itr2->pid, rCmd ) ) {
				pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_ERR );
				pToClient->AddData( SCI_R_FREE_MSG, "It failed to activate Syuhitu." );
			}
			else {
				pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_OK );
			}
		}
	}
}

// 主筆側で新規作成が行われる
void CSyInstance::NewFile_TS( const CNegCmd &rCmd, CNegCmd *pToClient )
{
	list< TAEDIT_INFO >::iterator itr;
	int pid;

	// pidを取得
	pid = rCmd.GetData( SCI_S_PID, -1 );
	if ( pid < -1 ) {
		pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_ERR );
		pToClient->AddData( SCI_R_STOPPED, SCID_RSTOP_STOP );
		pToClient->AddData( SCI_R_FREE_MSG, "Command data is insufficiency." );
		return ;
	}

	// インスタンスを検索
	itr = listInstance.begin();
	for (; itr != listInstance.end() && itr->pid != pid; itr++ );

	// ファイル名を更新する
	if ( itr != listInstance.end() )
		itr->FileName = "";
	else
		// 情報がなかった場合は、とりあえず新しく追加しておく
		listInstance.push_back( TAEDIT_INFO( "", pid ) );

	pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_OK );
	pToClient->AddData( SCI_R_STOPPED, SCID_RSTOP_RESUME );
}

// 主筆側でファイルに名前を付けて保存が行われる
void CSyInstance::WriteFile_TS( const CNegCmd &rCmd, CNegCmd *pToClient )
{
	list< TAEDIT_INFO >::iterator itr1, itr2;
	int pid;

	// ファイル名とプロセスIDを取得
	const string &FileName = rCmd.GetData( SCI_S_FILE_NAME, string( "" ) );
	pid = rCmd.GetData( SCI_S_PID, -1 );
	if ( FileName.empty() || pid < 0 ) {
		pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_ERR );
		pToClient->AddData( SCI_R_STOPPED, SCID_RSTOP_STOP );
		pToClient->AddData( SCI_R_FREE_MSG, "Command data is insufficiency." );
		return ;
	}

	// 指定されたファイルを開いているプロセスを検索
	itr2 = listInstance.begin();
	for (; itr2 != listInstance.end() && itr2->FileName != FileName; itr2++ );

	if ( itr2 == listInstance.end() ) {
		// 指定されたファイルを開いている奴はない

		// 呼び出し元のプロセスを検索
		itr1 = listInstance.begin();
		for (; itr1 != listInstance.end() && itr1->pid != pid; itr1++ );

		if ( itr1 == listInstance.end() ) {
			// 呼び出し元プロセスが不明
			// （エラーを返しても仕方がないので、新規に情報を登録しておく）
			listInstance.push_back( TAEDIT_INFO( FileName, pid ) );
		}
		else {
			// ファイル名を更新しておく
			itr1->FileName = FileName;
		}
		pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_OK );
		pToClient->AddData( SCI_R_STOPPED, SCID_RSTOP_RESUME );
	}
	else {
		if ( itr2->pid != pid ) {
			// 指定されたファイルは、他の主筆によって開かれている
			pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_OK );
			pToClient->AddData( SCI_R_STOPPED, SCID_RSTOP_STOP );
			pToClient->AddData( SCI_R_MSG_NUMBER, SCID_RMSG_FILEISOPEND );
		}
		else {
			// 結局の所上書き保存
			pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_OK );
			pToClient->AddData( SCI_R_STOPPED, SCID_RSTOP_RESUME );
		}
	}
}

// 主筆側が終了する
void CSyInstance::Exit_TS( const CNegCmd &rCmd, CNegCmd *pToClient )
{
	list< TAEDIT_INFO >::iterator itr;
	int pid;

	// 終了するのだから、中断させても仕方がない
	pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_OK );
	pToClient->AddData( SCI_R_STOPPED, SCID_RSTOP_RESUME );

	// pidを取得
	pid = rCmd.GetData( SCI_S_PID, -1 );
	if ( pid < -1 ) {
		// 一応エラーを返しておく
		pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_ERR );
		pToClient->AddData( SCI_R_FREE_MSG, "Command data is insufficiency." );
		return ;
	}

	// インスタンスを検索
	itr = listInstance.begin();
	for (; itr != listInstance.end() && itr->pid != pid; itr++ );

	// mapから削除する
	if ( itr != listInstance.end() )
		listInstance.erase( itr );
}

// サーバを停止させることが可能か否か
bool CSyInstance::CanBeStopServer() const
{
	// 起動中の主筆が存在しなければ、安全に停止することができる
	return listInstance.empty();
}

// サーバを強制停止させる
void CSyInstance::StopServerByForce_CS()
{
	CNegCmd send_cmd;
	CNegCmd resp_cmd;
	list< TAEDIT_INFO >::iterator itr;

	// コマンドを構築
	send_cmd.AddData( SCI_S_COMMAND, SCID_CMD_SET_STANDALONE_ST );

	// 全ての主筆に、スタンドアロンモードにするよう指示を出す
	for ( itr = listInstance.begin(); itr != listInstance.end(); itr++ ) {
		// コマンドを送信
		// エラーが発生しても強行する
		SendCmdToTaEdit( send_cmd, itr->pid, &resp_cmd );
	}
}

// 新しい主筆でファイルを開く
void CSyInstance::OpenFileNW_TS( const CNegCmd &rCmd, CNegCmd *pToClient )
{
	list< TAEDIT_INFO >::iterator itr1, itr2;

	assert( this );
	pToClient->AddData( SCI_R_STOPPED, SCID_RSTOP_STOP );

	// ファイル名とプロセスIDを取得
	const string &FileName = rCmd.GetData( SCI_S_FILE_NAME, string( "" ) );
	int pid = rCmd.GetData( SCI_S_PID, -1 );
	if ( FileName.empty() || pid < 0 ) {
		pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_ERR );
		pToClient->AddData( SCI_R_FREE_MSG, "Command data is insufficiency." );
		return ;
	}

	// 呼び出し元プロセスの情報を検索
	itr1 = listInstance.begin();
	for (; itr1 != listInstance.end() && itr1->pid != pid; itr1++ );
	if ( itr1 == listInstance.end() ) {
		// 呼び出し元プロセスの情報が見つからない
		pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_ERR );
		pToClient->AddData( SCI_R_FREE_MSG, "Unexpected error." );
		return ;
	}

	// 指定されたファイルを開いている「主筆」の有無を確認
	itr2 = listInstance.begin();
	for (; itr2 != listInstance.end() && itr2->FileName != FileName; itr2++ );
	if ( itr2 != listInstance.end() ) {
		if ( itr1->pid != itr2->pid ) {
			// 指定されたファイルを開いている主筆をアクティブにする
			if ( ActivateSyuhitu( itr2->pid, rCmd ) )
				pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_OK );
			else {
				pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_ERR );
				pToClient->AddData( SCI_R_FREE_MSG, "It failed to avtivate syuhitu." );
			}
		}
		else
			// 呼び出し元が開いているから、何もする必要がない
			pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_OK );
	}
	else {
		// 主筆を新しく起動する
		if ( StartSyuhitu( FileName, rCmd ) >= 0 )
			pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_OK );
		else {
			pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_ERR );
			pToClient->AddData( SCI_R_FREE_MSG, "It failed to start Syuhitu." );
		}
	}
}

// 主筆がコンストラクション・モードに参加する
void CSyInstance::Join_TS( const CNegCmd &rCmd, CNegCmd *pToClient )
{
	list< TAEDIT_INFO >::iterator itr;

	assert( this );
	pToClient->AddData( SCI_R_STOPPED, SCID_RSTOP_RESUME );

	// ファイル名とプロセスIDを取得
	const string &FileName = rCmd.GetData( SCI_S_FILE_NAME, string( "" ) );
	int pid = rCmd.GetData( SCI_S_PID, -1 );
	if ( pid < 0 ) {
		pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_ERR );
		pToClient->AddData( SCI_R_FREE_MSG, "Command data is insufficiency." );
		return ;
	}

	// 呼び出し元プロセスを検索
	itr = listInstance.begin();
	for (; itr != listInstance.end() && itr->pid != pid; itr++ );

	// 呼び出し元の情報がすでに登録されていた場合は、その情報を更新して終了
	if ( itr != listInstance.end() ) {
		itr->FileName = FileName;
		pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_OK );
		return ;
	}

	// 指定されたファイルを開いている主筆を検索
	if ( !FileName.empty() ) {
		itr = listInstance.begin();
		for (; itr != listInstance.end() && itr->FileName != FileName; itr++ );
	}
	else
		itr = listInstance.end();

	if ( itr == listInstance.end() ) {
		// ファイルの重複がなければ、情報を追加して終了
		listInstance.push_back( TAEDIT_INFO( FileName, pid ) );
		pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_OK );
		return ;
	}

	// 同じファイルを開いている奴がいるため、参加を拒絶する
	pToClient->AddData( SCI_R_STATUS, SCID_RSTAT_ERR );
	pToClient->AddData( SCI_R_MSG_NUMBER, SCID_RMSG_FILEISOPEND );
}

// 主筆を起動
int CSyInstance::StartSyuhitu( const string &FileName, const CNegCmd &rCmd ) const
{
	int pid;
	const char *SyuhituCommand = getenv( SCEV_TAEDIT_PATH );
	CProcStart procStart;

	int LineNumber = rCmd.GetData( SCI_S_LINE_NUMBER, 0 );
	const string &SyntaxName = rCmd.GetData( SCI_S_SYNTAX, string( "" ) );
	const string &StdOutName = rCmd.GetData( SCI_S_STDOUT, string( "" ) );
	const string &StdErrName = rCmd.GetData( SCI_S_STDERR, string( "" ) );
	int OldFD_StdOout = -1;	// 待避した標準出力
	int OldFD_StdErr = -1;	// 待避した標準エラー出力

	if ( NULL == SyuhituCommand ) return -1;

	// コマンド
	procStart.SpecifyCommand( SyuhituCommand );

	// ファイル名
	if ( FileName.length() > 0 )
		procStart.AddArg( string( "/file:" ) + FileName );

	// 行番号
	if ( LineNumber > 0 ) {
		char Buf[30];
		snprintf( Buf, 30, "/line:%d", LineNumber );
		procStart.AddArg( string( Buf ) );
	}

	// 構文
	if ( SyntaxName.length() > 0 )
		procStart.AddArg( string( "/syntax:" ) + SyntaxName );

	// コンストラクションモード
	procStart.AddArg( string( "/construction" ) );

	// 標準出力・標準エラー出力の差し替えを行うと、
	// ディスクリプタを浪費するため、リリース版ではこの処理は行わない。

	// 標準出力などを差し替える
/*	if ( StdOutName.length() > 0 )
		OldFD_StdOout = BindFD( 1, StdOutName, false );
	if ( StdErrName.length() > 0 )
		OldFD_StdErr = BindFD( 2, StdErrName, false );
*/
	// 起動
	pid = procStart.Start();
/*
	// 標準出力などを元に戻す
	if ( OldFD_StdOout >= 0 ) dup2( OldFD_StdOout, 1 );
	if ( OldFD_StdErr >= 0 ) dup2( OldFD_StdErr, 2 );
*/
	return pid;
}

// 指定された主筆をアクティブにする
bool CSyInstance::ActivateSyuhitu( int pid, const CNegCmd &rCmd ) const
{
	CNegCmd send_cmd;
	CNegCmd resp_cmd;
	int LineNumber = rCmd.GetData( SCI_S_LINE_NUMBER, 0 );
	const string &SyntaxName = rCmd.GetData( SCI_S_SYNTAX, string( "" ) );

	// 主筆に送信するコマンドを構築
	send_cmd.AddData( SCI_S_COMMAND, SCID_CMD_ACTIVATE_ST );
	if ( LineNumber > 0 )
		send_cmd.AddData( SCI_S_LINE_NUMBER, LineNumber );
	if ( !SyntaxName.empty() )
		send_cmd.AddData( SCI_S_SYNTAX, SyntaxName.c_str() );

	// コマンドを送信
	if ( !SendCmdToTaEdit( send_cmd, pid, &resp_cmd ) )
		return false;

	// 結果を解釈
	if ( resp_cmd.GetData( SCI_R_STATUS, SCID_RSTAT_ERR ) == SCID_RSTAT_OK )
		return true;
	else
		return false;
}

// 与えられた名前のパイプを指定されたディスクリプタと置き換える
// fdのディスクリプタを待避した先のディスクリプタを返す
int CSyInstance::BindFD( int fd, const string &FName, bool IsRead ) const
{
	int d = -1;
	int newFD = -1;

	// 指定されたファイルを開く
	if ( IsRead )
		d = open( FName.c_str(), O_RDONLY );
	else
		d = open( FName.c_str(), O_WRONLY );
	if ( d < 0 ) return -1;

	// fdのファイルディスクリプタを複製する
	newFD = dup( fd );
	if ( newFD < 0 ) goto ERR_EXIT;

	// fdを開いたファイルのディスクリプタに差し替える
	if ( dup2( d, fd ) < 0 ) goto ERR_EXIT;

	return newFD;

ERR_EXIT:
	if ( d > 0 ) close( d );
	if ( newFD > 0 ) close( newFD );
	return -1;
}

// 主筆に開いているファイル名を問い合わせる
bool CSyInstance::RequestFileName_ToTaEdit( int pid, string *pFName )
{
	CNegCmd send_cmd;
	CNegCmd resp_cmd;

	assert( NULL != pFName );

	// コマンドを構築
	send_cmd.AddData( SCI_S_COMMAND, SCID_CMD_RQ_FNAME_ST );

	// コマンドを送信
	if ( !SendCmdToTaEdit( send_cmd, pid, &resp_cmd ) ) return false;

	// 結果を取得
	if ( !resp_cmd.HasData( SCI_S_FILE_NAME ) )
		return false;
	(*pFName) = resp_cmd.GetData( SCI_S_FILE_NAME, "" );
	return true;
}

// 主筆にサーバが再起動したことを通知する
bool CSyInstance::NoticeServerReboot_ToTaEdit( int pid )
{
	CNegCmd send_cmd;
	CNegCmd resp_cmd;

	// コマンドを構築
	send_cmd.AddData( SCI_S_COMMAND, SCID_CMD_SVR_RESTART_ST );

	// コマンドを送信
	if ( !SendCmdToTaEdit( send_cmd, pid, &resp_cmd ) ) return false;

	// 結果を解釈
	if ( resp_cmd.GetData( SCI_R_STATUS, SCID_RSTAT_ERR ) == SCID_RSTAT_OK )
		return true;
	else
		return false;	
}

// 主筆にコマンドを送信する
bool CSyInstance::SendCmdToTaEdit( const CNegCmd& r, int pid, CNegCmd *pRet ) const
{
	string DirName;
	string fname_ST;	// サーバから主筆へのパイプの名前
	string fname_TS;	// 主筆からサーバへのパイプの名前
	CFD fd_ST;			// 送信用ディスクリプタ
	CFD fd_TS;			// 受信用ディスクリプタ
	char Buf[15];
	struct stat wStat;

	assert( pRet );

	// 名前付きパイプが格納されるディレクトリを取得
	const char *p = getenv( SCEV_COMMUNITY_PATH );
	if ( !p ) {
		fprintf( stderr, "ERROR Syuhitu server : %s environment valuable is empty.\n", SCEV_COMMUNITY_PATH );
		return "";
	}
	DirName = p;
	if ( DirName.length() <= 0 ) DirName = ".";
	if ( DirName[ DirName.length() - 1 ] != '/' ) DirName += '/';

	// ファイル名を生成
	snprintf( Buf, sizeof( Buf ) * sizeof( char ), "%d", pid );
	fname_ST = DirName + SCPX_TO_SYUHITU + Buf;
	fname_TS = DirName + SCPX_FROM_SYUHITU + Buf;

	// 二つのファイルがパイプであることを確認する
	if ( stat( fname_ST.c_str(), &wStat ) ) return false;
	if ( !S_ISFIFO( wStat.st_mode ) ) return false;
	if ( stat( fname_TS.c_str(), &wStat ) ) return false;
	if ( !S_ISFIFO( wStat.st_mode ) ) return false;

	// パイプを開く
	if ( !fd_ST.Open( fname_ST.c_str(), O_WRONLY ) ) return false;
	if ( !fd_TS.Open( fname_TS.c_str(), O_RDONLY ) ) return false;

	// 送信用データを取得
	string SendData = r.GetSendData();

	// コマンドを送信
	if ( !fd_ST.Write( SendData.c_str(), SendData.length() ) )
		return false;

	// 結果を受信
	CNegCmd response( fd_TS );
	(*pRet) = response;

	return true;
}
