using System;
using System.Net;
using System.IO;
using System.Text;
using System.Net.Sockets;
using System.Diagnostics;
using System.Xml;
using NJC.Common;
namespace NJC.With.MAPRT.Foundation
{
#region Ftp機能クラス
public class FtpClient
{
#region 変数定義
private string _server = null;
private string _username = null;
private string _password = null;
private string _message = null;
private string _result = null;
private int _bytes = 0;
private int _resultCode = 0;
private bool _loggedin = false;
private bool _binMode = false;
private Byte[] _buffer = new Byte[512];
private Socket _clientSocket = null;
private string[] _strFileDirectory = null;
#endregion
#region FTP コマンドバリュー
// Data connection already open; transfer starting
private const int DATA_TRANSFER = 125;
// Command okay
private const int COMMAND_OKEY = 200;
// File status okay: about to open data connection
private const int OPEN_CONNECTION = 150;
//Command not implemented, superfluous at this site
private const int SITE = 202;
// Service ready for new user
private const int NEW_USER = 220;
// User logged in
private const int USER_LOGIN = 230;
// Closing data connection
private const int CLOSE_DATA = 226;
// Entering Passive Mode
private const int ENTER_MODE = 227;
// Requested file action okay.
private const int FILE_OKEY = 250;
// User name okay and need password
private const int USERNAME_OKEY = 331;
// Requested file action pending further information
private const int FILE_INFORMATION = 350;
private const string Error_FileExist = "550";
#endregion
#region コンストラクタ
/// <summary>
/// コンストラクタ
/// 配置ファイルから、Ftp接続情報を設定する
/// </summary>
public FtpClient()
{
// get the server address from the NJC.With.Batch.Common.xml file
_server = ConfigurationManager.GetItem("FtpLogIn", "Server");
// get the username address from the NJC.With.Batch.Common.xml file
_username = ConfigurationManager.GetItem("FtpLogIn", "UserName");
// get the password address from the NJC.With.Batch.Common.xml file
_password = ConfigurationManager.GetItem("FtpLogIn", "PassWord");
// get the File Directory from the NJC.With.Batch.Common.xml file
_strFileDirectory = ConfigurationManager.GetItem("FilePath", "ImagePath").Split('\\');
}
#endregion
#region 通信モード
/// <summary>
/// 通信モードを設定できる。
/// ASCII BINARY二種がサポートする
/// </summary>
public bool BinaryMode
{
get
{
return this._binMode;
}
set
{
if (this._binMode == value)
{
return;
}
else
{
this._binMode = value;
}
if (value)
{
SendCommand("TYPE I");
}
else
{
SendCommand("TYPE A");
}
if (this._resultCode != COMMAND_OKEY)
{
throw new FTPException(this._result);
}
}
}
#endregion
#region 登録
/// <summary>
/// Ftpサーバへ登録する
/// </summary>
public void Login()
{
int iTime = 0;
// 3秒に停頓する
while (iTime < 1000000000)
{
++iTime;
}
if (this._loggedin)
{
this.Close();
}
IPAddress addr = null;
IPEndPoint ep = null;
try
{
//create a socket
this._clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//use DNS to analyzes the server to IpAddress
addr = Dns.Resolve(this._server).AddressList[0];
ep = new IPEndPoint(addr, 21);
//the client computer links the server computer
this._clientSocket.Connect(ep);
}
catch(Exception ex)
{
// judge the if the client has already conneted the FTP Server or the client is not null
if (this._clientSocket != null && this._clientSocket.Connected)
{
this._clientSocket.Close();
}
throw new FTPException("Couldn't connect to remote server", ex);
}
// get the result of the RFC
this.ReadResponse();
if (this._resultCode != NEW_USER)
{
this.Close();
throw new FTPException(this._result);
}
this.SendCommand("USER " + _username);
if (!(this._resultCode == USERNAME_OKEY || this._resultCode == USER_LOGIN))
{
this.CleanUp();
throw new FTPException(this._result);
}
if (this._resultCode != USER_LOGIN)
{
this.SendCommand("PASS " + _password);
if (!(this._resultCode == USER_LOGIN || this._resultCode == SITE))
{
this.CleanUp();
throw new FTPException(this._result);
}
}
this._loggedin = true;
}
#endregion
#region 接続はクローズする
/// <summary>
/// Ftp接続をクローズする
/// </summary>
public void Close()
{
if (this._clientSocket != null )
{
// Quit ftp server
this.SendCommand("QUIT");
}
this.CleanUp();
}
#endregion
#region Ftpサーバから、ファイルをダウンロード/アップロードする
/// <summary>
/// Ftpサーバから、CSVファイルをダウンロードする
/// ローカルファイル名がEmptyになった場合、サーバ側
/// ファイル名と同じく設定する
/// </summary>
/// <param name="remFileName">サーバ側ファイル名</param>
/// <param name="locFileName">ローカルファイル名</param>
/// <param name="resume"></param>
public void Download(string remFileName, string locFileName)
{
if (!this._loggedin)
{
this.Login();
}
this.BinaryMode = true;
if (locFileName.Equals(""))
{
locFileName = remFileName;
}
FileStream output = null;
if (!File.Exists(locFileName))
{
output = File.Create(locFileName);
}
else
{
output = new FileStream(locFileName, FileMode.Open);
}
Socket cSocket = CreateDataSocket();
this.SendCommand("RETR " + remFileName);
while ( true )
{
this._bytes = cSocket.Receive(_buffer, _buffer.Length, 0);
output.Write(this._buffer,0,this._bytes);
if ( this._bytes <= 0)
{
break;
}
}
output.Close();
if ( cSocket.Connected )
{
cSocket.Close();
}
this.ReadResponse();
}
/// <summary>
///
/// </summary>
public void SavePicture(string fileName, string strDirName, string strDirNameTwo)
{
if (!this._loggedin)
{
this.Login();
}
Socket cSocket = null ;
try
{
this.BinaryMode = true;
}
catch(Exception)
{
// file not exist
}
// open stream to read file
FileStream input = new FileStream(fileName, FileMode.Open);
// dont create untill we know that we need it
cSocket = this.CreateDataSocket();
// サーバ上での格納場所は「(Withシステム用イメージ格納ディレクトリ)/イメージNo/イメージNo枝番」でデ
// ィレクトリを作成し、その配下にイメージファイルを格納する。
foreach (string strFileDirectory in _strFileDirectory)
{
SendCommand("MKD " + @strFileDirectory);
SendCommand("CWD " + @strFileDirectory);
}
SendCommand("MKD " + @strDirName);
SendCommand("CWD " + @strDirName);
SendCommand("MKD " + @strDirNameTwo);
SendCommand("CWD " + @strDirNameTwo);
// イメージファイルを新規に指定された場合は、指定したイメージファイルをサーバ上にアップロードして格納
SendCommand("STOR " + Path.GetFileName(fileName));
while ((_bytes = input.Read(_buffer,0,_buffer.Length)) > 0)
{
cSocket.Send(_buffer, _bytes, 0);
}
input.Close();
if (this._resultCode != DATA_TRANSFER && this._resultCode != OPEN_CONNECTION)
{
throw new FTPException(this._result);
}
if (cSocket.Connected)
{
cSocket.Close();
}
this.ReadResponse();
if (this._resultCode != CLOSE_DATA && this._resultCode != FILE_OKEY)
{
throw new FTPException(this._result);
}
}
/// <summary>
/// Delete Picture
/// </summary>
public bool DeletePicture(string fileName, string strDirName, string strDirNameTwo)
{
// Begin Connect
if (!this._loggedin)
{
this.Login();
}
try
{
this.BinaryMode = true;
}
catch(Exception)
{
// file not exist
}
// 法人リスク事例情報の削除時にイメージファイル群も削除する必要があるが、
// この場合は「(Withシステム用イメージ格納ディレクトリ)/イメージNo」配下をディレクトリ毎全て削除すればよい。
string strSave = @ConfigurationManager.GetItem("FilePath", "ImagePath").ToString() + @"\"
+ strDirName + @"\" + strDirNameTwo;
SendCommand("CWD " + strSave);
// Check File Exist
if (_message.Trim().Substring(0,3) == Error_FileExist)
{
return false;
}
SendCommand("DELE " + Path.GetFileName(fileName));
// Check File Exist
if (_message.Trim().Substring(0,3) == Error_FileExist)
{
return false;
}
SendCommand("CDUP ");
if (_message.Trim().Substring(0,3) == Error_FileExist)
{
return false;
}
SendCommand("RMD " + strDirNameTwo);
if (this._resultCode != CLOSE_DATA && this._resultCode != FILE_OKEY)
{
throw new FTPException(this._result);
}
return true;
}
#region Ftp通信内容を解析する
/// <summary>
/// Ftpサーバから返事を解析
/// </summary>
private void ReadResponse()
{
this._message = "";
this._result = this.ReadLine();
if (this._result.Length > 3)
{
this._resultCode = int.Parse( this._result.Substring(0, 3));
}
else
{
this._result = null;
}
}
/// <summary>
/// Ftpサーバから返事をとる
/// </summary>
/// <returns></returns>
private string ReadLine()
{
while(true)
{
_bytes = _clientSocket.Receive(this._buffer, this._buffer.Length, 0);
_message += Encoding.ASCII.GetString(this._buffer, 0, this._bytes);
if (this._bytes < this._buffer.Length)
{
break;
}
}
return _message;
}
#endregion
#region アップロード(ダウンロード)に必要なネットワーク処理を用意する
/// <summary>
/// Ftpサーバへコマンドを送信する
/// Ftpサーバからの返事も受ける
/// </summary>
/// <param name="command"></param>
private void SendCommand(String command)
{
// 送信データを片付ける
Byte[] cmdBytes = Encoding.GetEncoding("Shift_JIS").GetBytes(command + "\r\n") ;
// 送信する
_clientSocket.Send(cmdBytes, cmdBytes.Length, SocketFlags.OutOfBand);
// 受信する
this.ReadResponse();
}
/// <summary>
/// ネットワーク通信のため、ソケットをクリエートする
/// </summary>
/// <returns>Connected socket</returns>
private Socket CreateDataSocket()
{
this.SendCommand("PASV");
if (this._resultCode != ENTER_MODE)
{
throw new FTPException(this._result);
}
int index1 = this._result.IndexOf('(');
int index2 = this._result.IndexOf(')');
string ipData = this._result.Substring(index1 + 1,index2 - index1 - 1);
int[] parts = new int[6];
int len = ipData.Length;
int partCount = 0;
string buf="";
for (int i = 0; i < len && partCount <= 6; i++)
{
char ch = char.Parse(ipData.Substring(i,1));
if (char.IsDigit(ch))
{
buf+=ch;
}
else if (ch != ',')
{
throw new FTPException("Malformed PASV result: " + _result);
}
if ( ch == ',' || i+1 == len )
{
try
{
parts[partCount++] = int.Parse(buf);
buf = "";
}
catch (Exception ex)
{
throw new FTPException("Malformed PASV result (not supported?): " + this._result, ex);
}
}
}
string ipAddress = parts[0] + "."+ parts[1]+ "." + parts[2] + "." + parts[3];
int port = (parts[4] << 8) + parts[5];
Socket socket = null;
IPEndPoint ep = null;
try
{
socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
ep = new IPEndPoint(Dns.Resolve(ipAddress).AddressList[0], port);
socket.Connect(ep);
}
catch(Exception ex)
{
// doubtfull....
if ( socket != null && socket.Connected ) socket.Close();
throw new FTPException("Can't connect to remote server", ex);
}
return socket;
}
#endregion
#region 資源解放を行う
/// <summary>
/// ソケットをクローズして、資源の解放
/// </summary>
private void CleanUp()
{
if (this._clientSocket!=null)
{
//close the commuication between the client and the server
this._clientSocket.Close();
this._clientSocket = null;
}
this._loggedin = false;
}
#endregion
}
#endregion
#region FTP例外クラス 機能しません
/// <summary>
/// FTPException の概要の説明です。
/// 只今、処理は入っていない。
/// </summary>
public class FTPException : ApplicationException
{
/// <summary>
/// FTPException クラスのコンストラクタ。
/// </summary>
public FTPException()
{
}
/// <summary>
/// 1 つの文字列メッセージを受け付けるコンストラクタ。
/// </summary>
/// <param name="message"></param>
public FTPException(string message) : base(message)
{
}
/// <summary>
/// 1 つの文字列メッセージと、このカスタム例外クラスによってラッピングされる
/// 内側例外を受け付けるコンストラクタ。
/// </summary>
/// <param name="message"></param>
/// <param name="innerException"></param>
public FTPException(string message, Exception innerException) : base(message, innerException)
{
}
}
#endregion
#region 配置情報取得 機能しません
/// <summary>
/// 配置情報取得
/// </summary>
public class ConfigurationManager
{
/// <summary>
/// バッチ配置ファイル
/// デフォルトは: DataFiles\Config\SectionValue\FtpConfig.xml
/// 勿論カスタマイズができます。
/// </summary>
private string _batchConfigFile;
/// <summary>
/// Construct
/// </summary>
public ConfigurationManager()
{
_batchConfigFile = "FtpConfig";
}
/// <summary>
/// 外部から配置ファイルの取得ができます
/// Path + 拡張子は必要ではありません
/// Path = DataFiles\Config\SectionValue
/// 拡張子 = ".xml"
/// </summary>
public string ConfigFile
{
get
{
return _batchConfigFile;
}
}
/// <summary>
/// セクションネッム+キーによって、対応バリューを取得する
/// </summary>
/// <param name="sectionName">セクションネッム</param>
/// <param name="key">キー</param>
/// <returns>バリュー</returns>
public static string GetItem(string sectionName, string key)
{
string strItem = NJC.Common.SectionValueItemCache.GetAppSetting("FtpConfig", sectionName, key);
//キーによって、バリューの取得ができない場合は [""] を返却する
return strItem == null ? String.Empty : strItem;
}
/// <summary>
/// セクションネッム+キーによって、対応バリューを取得する
/// </summary>
/// <param name="fileName">Configファイル名</param>
/// <param name="sectionName">セクションネッム</param>
/// <param name="key">キー</param>
/// <returns>バリュー</returns>
public static string GetItem(string fileName, string sectionName, string key)
{
string strItem = NJC.Common.SectionValueItemCache.GetAppSetting(fileName, sectionName, key);
//キーによって、バリューの取得ができない場合は [""] を返却する
return strItem == null ? String.Empty : strItem;
}
}
}
#endregion
#endregion