public ProtocolInterpreter(TcpClient clientConn, IDictionary <string, Account> accounts) { this.connection_ = clientConn; this.currentDTP_ = new DataTransferProcess(); this.currentAccount_ = new LoginAccount( accounts ?? new Dictionary <string, Account>()); }
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(); }