public ProtocolInterpreter(TcpClient clientConn, IDictionary <string, Account> accounts)
 {
     this.connection_     = clientConn;
     this.currentDTP_     = new DataTransferProcess();
     this.currentAccount_ = new LoginAccount(
         accounts ?? new Dictionary <string, Account>());
 }
Exemple #2
0
        public void StartPassive()
        {
            if (this.Address == null)
            {
                return;
            }

            if (this.IsPassive)
            {
                this.StopPassive();

                this.passiveListener_ = new TcpListener(this.Address);
                this.passiveListener_.Start();
                this.passiveListener_.BeginAcceptTcpClient(new AsyncCallback((result) => {
                    DataTransferProcess owner = result.AsyncState as DataTransferProcess;

                    try
                    {
                        if (result.IsCompleted /* && result.CompletedSynchronously */)
                        {
                            owner.passiveClient_ = owner.passiveListener_?.EndAcceptTcpClient(result);
                            owner.passiveAccepted_.Set();
                        }
                    }
                    catch (ObjectDisposedException)
                    {
                        owner.passiveClient_ = null;
                    }
                }), this);
            }
        }
        private void Run()
        {
            DataTransferProcess dtp = new DataTransferProcess();

            StreamWriter writer = new StreamWriter(this.connection_.GetStream());
            StreamReader reader = new StreamReader(this.connection_.GetStream(), Encoding.GetEncoding(932));

            writer.AutoFlush = true;

            var replyer = new Replyer(writer);

            this.OnLogger(replyer.Send(ReplyCode._220));

            while (true)
            {
                string commandline;

                try
                {
                    commandline = reader.ReadLine();
                }
                catch (Exception e)
                {
                    this.OnLogger(e.Message);
                    break;
                }

                if (String.IsNullOrEmpty(commandline))
                {
                    break;
                }

                this.OnLogger(commandline);

                // RFC959
                var isQuit  = false;
                var command = new Command(commandline);

                switch (this.currentAccount_.State)
                {
                case LoginAccount.LoginState.NoLogin:
                    switch (command.Name)
                    {
                    case "USER":            // 認証するユーザー名
                        this.DoUSER(command, replyer);
                        break;

                    default:
                        this.OnLogger(replyer.Send(ReplyCode._502));
                        break;
                    }
                    break;

                case LoginAccount.LoginState.Queried:
                    switch (command.Name)
                    {
                    case "PASS":            // 認証パスワード。
                        this.DoPASS(command, replyer);
                        break;

                    default:
                        this.OnLogger(replyer.Send(ReplyCode._502));
                        break;
                    }
                    break;

                case LoginAccount.LoginState.Passed:
                    switch (command.Name)
                    {
                    case "APPE":            // 引数に示したファイルに対して追記する。
                        this.DoAPPE(command, replyer);
                        break;

                    case "CDUP":            // 親ディレクトリに移動する。
                        this.DoCDUP(command, replyer);
                        break;

                    case "CWD":             // 作業ディレクトリの変更。引数は移動するディレクトリ。
                        this.DoCWD(command, replyer);
                        break;

                    case "DELE":            // ファイルを削除する。引数は削除するファイル。
                        this.DoDELE(command, replyer);
                        break;

                    case "HELP":            // コマンドの一覧。引数を指定するとより詳しいコマンド情報を返す。
                        replyer.Send(ReplyCode._202);
                        break;

                    case "LIST":            // 引数に指定したファイルの情報やディレクトリの一覧。指定しない場合、現在のディレクトリの情報を一覧。
                        this.DoLIST(command, replyer);
                        break;

                    case "XMKD":
                    case "MKD":             // 引数に指定した名前のディレクトリを作成する。
                        this.DoMKD(command, replyer);
                        break;

                    case "NLST":            // 引数に指定したディレクトリのファイル一覧を返す。
                        this.DoNLST(command, replyer);
                        break;

                    case "NOOP":            // 何もしない。接続維持のためダミーパケットとして使われることがほとんど。
                        replyer.Send(ReplyCode._200);
                        break;

                    case "MODE":            // 転送モードの設定(ストリーム、ブロック、圧縮)。
                        replyer.Send(ReplyCode._202);
                        break;

                    case "PASS":            // 認証パスワード。
                        this.DoPASS(command, replyer);
                        break;

                    case "PASV":            // パッシブモードに移行する。
                        this.DoPASV(command, replyer);
                        break;

                    case "PORT":            // サーバが接続すべきポートとアドレスを指定する。
                        this.DoPORT(command, replyer);
                        break;

                    case "XPWD":
                    case "PWD":             // 作業ディレクトリを取得する。
                        this.DoPWD(command, replyer);
                        break;

                    case "QUIT":            // 接続を終了する。
                        replyer.Send(ReplyCode._221);

                        isQuit = true;
                        break;

                    case "RETR":            // リモートファイルをダウンロード(Retrieve)する。
                        this.DoRETR(command, replyer);
                        break;

                    case "XRMD":
                    case "RMD":             // 引数に指定したディレクトリを削除する。
                        this.DoRMD(command, replyer);
                        break;

                    case "STOR":            // ファイルをアップロード(Stor)する。
                        this.DoSTOR(command, replyer);
                        break;

                    case "STOU":            // ファイル名が重複しないようにファイルをアップロードする。
                        this.DoSTOU(command, replyer);
                        break;

                    case "TYPE":            // 転送モードを設定する(アスキーモード、バイナリモード)。
                        this.DoTYPE(command, replyer);
                        break;

                    case "USER":            // 認証するユーザー名
                        this.DoUSER(command, replyer);
                        break;

                    case "ABOR":            // ファイルの転送を中止する。
                    case "ACCT":            // アカウント情報。引数はユーザアカウントを示す文字列。
                    case "ALLO":            // ファイルを受け取るために十分なディスクスペースを割り当てる。引数は予約するサイズ。
                    case "REIN":            // 接続を再初期化する。
                    case "RNFR":            // 引数に指定した名前のファイル(ディレクトリ)をリネームする。
                    case "RNTO":            // 引数に指定した名前のファイル(ディレクトリ)にリネームする。
                    case "SITE":            // RFCで定義されていないようなリモートサーバ特有のコマンドを送信する。
                    case "SMNT":            // ファイル構造をマウントする
                    case "STRU":            // 転送するファイルの構造を設定する。
                    case "STAT":            // 現在の状態を取得する。
                    case "SYST":            // システムの種別を返す。
                        this.OnLogger(replyer.Send(ReplyCode._502));
                        break;

                    default:
                        this.OnLogger(replyer.Send(ReplyCode._502));
                        break;
                    }
                    break;

                default:
                    this.OnLogger(replyer.Send(ReplyCode._502));
                    break;
                }

                if (isQuit)
                {
                    break;
                }
            }

            this.currentDTP_.StopPassive();
        }