#pragma ident "@(#) actions/Cms3Client.java 0.0.5 2012.02.01,22:35"
package cms3.actions;
import java.io.*;
import java.net.*;
//import java.util.ArrayList;
import java.awt.TextField;

import javax.swing.JOptionPane;


/** CMS3クライアントプロトコル本仕様プログラム
 * CMSの受信サーバー（CMS3　バージョン管理サーバから応答を受信する）
 * <br>
 * <pre>
 * 基本仕様
 * ・本プロトコルは「Complete Walker Revision Administrator β7」の機能を利用している。
 * ・「Complete Walker Revision Administrator β7」は現在 Vine Linux 5.2 上で稼動中である。
 * ・USERとPASSはCMSの２種類のログインユーザを使用する（/musr /fusr）
 * ・fusrはソースコードのサーバー側のリビジョン情報を管理するがネットワーク側には公開しない。musr はネットワーク側にリビジョン情報を公開する。
 * ・CMS側はRUBYスクリプトでソケット通信を行う
 * ・差分ファイルの記録を行うkorn-shellコマンドはRUBYスクリプトからの呼び出しで行う
 * ・最新ファイルのGET及び差分登録のPUTは組込みFTPクライアント機能での送受信を行う
 * ・ソケット通信に使用するポートはCMS3が3390~3399番ポートを使用する
 * ・クライアント側のユーザインターフェースはJAVA-SwingのEclipseプラグインプログラムである本プログラム を利用する
 * ・Eclipseプラグインのインストールは、http://codoo2hk.corede.net/cms3/cms3install/ リポジトリから直接可能である。
 * ・Eclipseプラグインのアップデートは、http://codoo2hk.corede.net/cms3/cms3update/ リポジトリから直接可能である。
 * ・また、Eclipseプラグインの臨時アップデートは、http://codoo2hk.corede.net/cms3/cms3update2/ リポジトリから直接可能となっている。
 * ・PUTを行った後では誰でもGETが可能となる。
 * ・PUTはファイルを送信後にサーバー側でリビジョンの登録を行う。サーバーは処理を一度に行うため送信は最も早く行わなければならない。
 * ・PUTはリビジョンの登録後に /cms/diff/cmssetq のユーザにもしメールアドレスが登録されている場合、そのアドレスにPUT完了のメールを送信する。
 * ・PUTはメール送信時、プラグイン操作においてメモ入力がされている場合はそのメモの内容をメールの本文に記録する。
 * ・PUTはユーザのメールアドレスが登録されていない場合はCMSの代わりのFTPアドレスであるFTPSにそのメールを転送する。
 *  ※FTPSのユーザIDは FTPS であり、パスワードは yumura01 である。
 * ・NEWFILEはその後にUNGETを行わないと他の開発者がGET出来なくなる。
 * ・NEWFILEの実行時サーバー側に指定したディレクトリが存在しなければ自動的にそれを作成する。ディレクトリを作成するのはFTPプロトコルである。
 * ・UNGETコマンドを利用出来るのはファイルをGETしたユーザとCMS管理者だけである。
 * ・VGETは同時にそのリビジョンの差分ファイルも一緒に受信する。差分ファイル名にはバージョンとリビジョン番号が追加されている。
 * ・ファイルの存在と排他制御を確認するのはサーバーのSTATコマンドになる。
 * ・実際にファイルの送受信を行うのは組込みFTPプロトコルである。
 * ・組込みFTPプロトコル及び、FTPメソッドは以下の動作を行う。
 * 	１）もし、テーブルファイルに多重階層のディレクトリを用いたファイルの設定があった場合、そのファイルを遡ってRETRを行う。
 * 	２）もし、ローカル側（Windows)でテーブルファイルに登録された階層のフォルダが無かった場合、新たにフォルダを作成してファイルを受信する。
 * 	３）もし、サーバー側（Linux)でテーブルファイルに登録された階層のディレクトリが無かった場合、新たにディレクトリを作成してファイルを送信する。
 * 	※ディレクトリ及びフォルダの階層は最大６４階層まで作成可能。
 *  ※組込みFTPは/home/cms/fusr/ をホームディレクトリとすること。
 * 
 * リポジトリ仕様
 * ・専用サーバのユーザID　cms　を利用してリポジトリを管理する。
 * ・cms　は既にsshにおけるバージョン/リビジョン管理システムとして利用出来る環境を保有する。
 * ・各リポジトリは  /cms/fusr 配下に置かれ、リポジトリ配下の階層管理が可能となっている。
 * ・リポジトリを管理するコマンドは /cms/bin に用意されている。
 * ・専用サーバではリポジトリ管理の他に故障管理と修正管理を行うことが出来る。
 * ・リポジトリを利用出来るユーザはsshにおいて２種類のタイプを持つ。（/cms/fusr と /cms/musr）
 * ・ネットワークからCMS3プロトコルを通して本リポジトリを利用出来るユーザは /cms/diff/cmssetq にパスワードの存在するユーザだけである。
 * ・リポジトリ管理のためのユーザIDは　cms　である。これはsshにおいてcms　を利用するユーザは誰でもリポジトリ管理者となることを意味する。
 * ・サーバー側に於いてリポジトリを操作するコマンドは　cf　である。このコマンドはファイラーであり、視覚的にリビジョンを管理する。
 * ・リポジトリ操作のためのマニュアルは/cms/doc/cms.txt の最後に記述されている。
 * ・リポジトリに登録できるファイルはテキストファイルのみである。拡張子は .c .cc .java .sh .ksh .bash .rb .py .php 等多岐に渡って登録可能である。
 * ・リビジョン管理されたファイルの最初の１行にバージョン/リビジョン番号と登録した日付が振られることになる。
 * ・ネットワークからリポジトリを操作するプログラムはCMS3プロトコルである。
 * 
 * プロトコル仕様
 *  サーバ側の常駐プログラムは cms3-server.rb スクリプトである。このスクリプトは ruby で記述されている。
 *  このプログラムはプロジェクトのリポジトリ名ごとに　cms　にログインし、リポジトリディレクトリのkorn-shll 環境で　.profile　を実行した後に起動しなければならない。
 *  常駐するためのコマンドラインは以下となる。
 *  	nohup cms3-server.rb -p 3390 > /home/cms/logs/{username}.3390.log &
 *  オプション -p の次にあるポート番号はリポジトリごとに　3390〜3399までが利用出来る。各ポートごとのソケットのFIFOキューは５つ用意してある。
 *  現在用意したリポジトリ管理サーバのアドレスは codoo2hk.corede.net となる。これは個人のサーバであるためcmsのためのsshのパスワードは公開出来ない。
 *  但し、ftpのためのユーザIDとパスワードは公開している。（user-id:ftps  password:yumura01）
 *  cmsではリビジョンのコンフリクト（衝突）を防止するためリビジョンを登録出来るユーザは必ず毎時１ユーザだけに限られる。但しファイルの編集は誰でもいつでも出来る。
 *  
 *  </pre>
 * USER - ユーザIDを確認する。サーバー側は/home/cms/diff/cmssetq のユーザIDと照合し、OKであれば　"+OK USER" を返信する。
 * PASS - パスワードを確認する。サーバー側は/home/cms/diff/cmssetq のユーザIDに対するパスワードを照合し、OKであれば　"+OK PASS" を返信する。
 * STAT 0 - カレントディレクトリを調査し、PWD[0]に/fusr または /musr のディレクトリを格納する。
 * STAT 1 - サーバー側のファイルがターゲットリポジトリにあるかどうかを調査する。ファイルが存在する場合は　"+OK STAT 1" を返信する。存在しない場合は"+NG STAT 1"を返信する。
 * STAT 2 - WHOコマンドのためにある機能。サーバの/home/cms/diff/lock/ 配下にある排他制御用ファイルを確認し、もしロックしてあればどのユーザがGETしているのかを報告する。
 * 			OKであれば　"-OK STAT 2" を返信する。既にGETされている場合は "-NT STAT 2"を送信する。また、ファイルが存在しない場合は"+NG STAT 2"を返信する。
 * STAT 3 - ファイルがサーバの/home/cms/fusr/リポジトリ（開発システム名：Eclipseではプロジェクト名）に存在する場合には"+OK STAT 3" 存在しない場合には"+NT STAT 3"を返信する。
 * STAT 4 - GETのための調査を行う。サーバーの排他制御ファイルのlockを確認し、lockが確認された場合は/cms/diff/log/getlog.{Version}のGET情報を返信する。
 * 			GETが利用出来ない場合は"+NT STAT 4"とGET情報。利用可能な場合は"+OK STAT 4"を返信する。
 * LIST 0 - 何もしない。リスト表示は行わない。
 * LIST 1 - /home/cms/diff/tabs/リポジトリ名+tab ファイルの中にあるターゲットファイル名をリストし送信する。
 * STOR 0 - 何も実行しない。"+OK STOR 0"を返信する。
 * STOR 1 - サーバーは/home/cms/bin/cms3-put.ksh スクリプトを実行する。その時リポジトリ環境変数のバージョン番号を読み取りそれをパラメータに渡し実行する。
 * 			cms3-put.ksh file-name user-name version-number
 * 			コマンドが実行に成功した場合は"+OK STOR 1" 失敗した場合には "+NT STOR 1"　を返信する。
 *    cms3-put.ksh からのエラーメッセージは以下の７文字の応答コードに要約されている。サーバーはこれらのコードに応じて処理を行わなければならない。
 *    "Not determine the system name."
 *    "-NT SYS"
 *
 *    "$1 is not registered in the table."
 *    "-NT TBL"
 *
 *    "Target file not found."
 *    "-NT FND"
 *
 *    "$2 is not a registered user."
 *    "-NT REG"
 *
 *    "There is no directory for exclusive control."
 *    "-NT LCK"
 *
 *    "$File does not exist."
 *    "-NT EXT"
 *
 *    "$File has not changed. PUT does not."
 *    "-NT CHG"
 *    
 *    "Complete"
 *    "-OK PUT"
 *    
 * 
 * STOR 2 - リポジトリに新規のファイルを登録する場合実行する。サーバでは以下のコマンドを実行する。
 *  		cms3-newfile.ksh file-name user-name version-number
 *   		コマンドが実行に成功した場合は"+OK STOR 2" 失敗した場合には "+NT STOR 2"　を返信する。
 *   cms3-newfile.ksh からのエラーメッセージは以下の７文字の応答コードに要約されている。サーバーはこれらのコードに応じて処理を行わなければならない。
 *   
 *    "Is not set environment requires CMS SYSNAME and TABFILE."
 *    "-NT SYS"
 *   
 *    "${File} is not defined in ${TABFILE}."
 *    "-NT TAB"
 *    
 *    "${User} is a user registered in the CMS"
 *    "-NT CMS"
 *    
 *    "$File dose not exist."
 *    -NT EXT"
 *    
 *    "${Targetfile} complete."
 *    "-OK NEW"
 *    
 *   
 * RETR 0 - 何も実行しない。"+OK RETR 0" を返信する。
 * RETR 1 - リポジトリから最新のファイルを呼び出し、プロジェクトのファイルと入れ替える。以下のコマンドを実行する。
 *  		cms3-get.ksh file-name user-name version-number
 *   		コマンドが実行に成功した場合は"+OK RETR 1" 失敗した場合には "+NT RETR 1"　を返信する。
 *   
 *   cms3-get.ksh からのエラーメッセージは以下の７文字の応答コードに要約されている。サーバーはこれらのコードに応じて処理を行わなければならない。
 *   "$1 user has been found tablefile."
 *    "-NT TBL"
 *    
 *    "$2  is not a registered user to CMS."
 *    "-NT USR"
 *    
 *    "Create a directory and not lock / CMS is."
 *    "-NT LCK"
 *    
 *    "$File exist."
 *    "-OK EXT"
 *    
 *    "${File} は ${op} {File} has {} to get"
 *    "-OK GET"
 *    
 *    "SUBMIT to $ {File} is $ {op} (Fix completion notice) are."
 *    "-OK SUB"
 *    
 *    "${File} The COMMIT (end version) are."
 *    "-OK COM"
 *    
 *    "We have different $ {User}."
 *    "-NT DUR"
 *    
 *    "Complete"
 *    "-OK GET"
 *    
 *   
 * RETR 2 - リポジトリからGETしたファイルのGETを取り消す。以下のコマンドを実行する。
 *  		cms3-unget.ksh file-name user-name version-number
 *   		コマンドが実行に成功した場合は"+OK RETR 2" 失敗した場合には "+NT RETR 2"　を返信する。
 *   cms3-unget.ksh からのエラーメッセージは以下の７文字の応答コードに要約されている。サーバーはこれらのコードに応じて処理を行わなければならない。
 *   
 *    "$1 name is not SYSTEM."
 *    "-NT SYS"
 *    
 * 	  "$1 Can not find the file table,"
 *    "-NT NFL"
 *  
 *    "$2 Username not found."
 *    "-NT USR"
 *  
 *    "$File does not exist."
 *    "-NT EXT"
 *  
 *    "SUBMIT to $ {File} is $ {op} (Fix completion notice) are."
 *    "-OK SUB"
 *    
 *    "Complete"
 *    "-OK UNG"
 *    
 *    
 * RETR 3 - リポジトリからファイルの履歴を数値でリストし、PUTしたファイルのリビジョンごとにGETを行う。以下のコマンドを実行する。
 *  		cms3-vget.ksh file-name user-name version-number revision-number(00 - 99)
 *   		コマンドが実行に成功した場合は"+OK RETR 3" 失敗した場合には "+NT RETR 3"　を返信する。
 *   cms3-vget.ksh からのエラーメッセージは以下の７文字の応答コードに要約されている。サーバーはこれらのコードに応じて処理を行わなければならない。
 *   
 *   "Name is not SYSTEM"
 *   "-NT SYS"
 *   
 *   "Can not find the file table"
 *   "-NT TBL"
 *   
 *   "There is $1 in the table file"
 *   "-NT NTB"
 *   
 *   "In the $2 CMS users do not"
 *   "-NT NUS"
 *   
 *   "Will submit a ${File} ${op} (complete correction) are"
 *   "-NT SUB"
 *   
 *   "Located in the current directory ${File}"
 *   "-OK EXT"
 *   
 *   "No differences were recorded files."
 *   "-NT MDF"
 *   
 *   "${File}: Version ${Version}. There is no record of the difference between ${Revision}．"
 *   "-NT MDR"
 *   
 *   "Revision file ${Version}. There is no ${Revision}"
 *   "-NT RVF"
 *   
 *   "${Version} in the current directory. There is a ${Revision}."
 *   "-OK RVF"
 *   
 *   "Complete"
 *   "-OK VGT"
 *   
 *
 * RETR 4 - リポジトリからVGETしたファイルのVGETを取り消す。以下のコマンドを実行する。
 *  		cms3-unvget.ksh file-name user-name version-number revision-number(00 - 99)
 *   		コマンドが実行に成功した場合は"+OK RETR 4" 失敗した場合には "+NT RETR 4"　を返信する。
 *   cms3-unvget.ksh からのエラーメッセージは以下の７文字の応答コードに要約されている。サーバーはこれらのコードに応じて処理を行わなければならない。
 * 
 *   "$1 name is not SYSTEM."
 *   "-NT SYS"
 *   
 *   "$1 Can not find the file table,"
 *   "-NT NFL"
 *   
 *   "$2 Username not found."
 *   "-NT USR"
 *   
 *   "$File does not exist."
 *   "-NT EXT"
 *   
 *   "Will submit a ${File} ${op} (complete correction) are."
 *   "-OK SUB"
 *   
 *   "Complete"
 *   "-OK UNV"
 *  
 * 
 *   
 * QUIT   - 何もしない。終わりの印にすぎないことに注意すること。
 * 
 * <pre>
 * <br>
 * ECLIPSEプラグインの仕様についての注意事項
 * 
 * Eclipseで本リビジョン管理を行う場合以下の点に注意する必要がある。
 * ・Eclipse 側のソースファイルはEclipseのプロジェクト管理の元に置かれるため、実際にリビジョン管理する場合次の操作が必要になる。
 * 	1)Eclipseの src フォルダ配下のソースファイルを直接操作可能。そのためWindowsのレジストリにフォルダ登録する機能が付属している。
 * 	2)PUT,GET、NEWFILE等のコマンドは src フォルダ配下のソースファイルを直接扱うことが出来るので、GETする場合は現在のソースを上書きすることになるため
 *   最新のソースファイルは必ずPUTしてからGETする必要がある。
 * ・GET,VGET,NEWFILE,PUT,UNGETとも階層的な管理が可能である。
 * 	階層管理とはリビジョンテーブルファイルに Skigae/SekigaeOno.java という記述をした場合CMSはリポジトリの管理下に Sekigae ディレクトリを登録する。
 * 	この時、Eclipse 側では src フォルダの配下に Sekigae というフォルダを作成して置かないと PUT,GETともファイルの送受信が出来ない。
 * 
 * 操作方法
 * ・Eclipseプラグインをインストールする。
 *   ※「新規ソフトウェアのインストール」で http://codoo2hk.corede.net/cms3/cms3update/ のアドレスを「作業対象」に貼り付け「次へ」ボタンをクリック。
 * ・Eclipseにて新規プロジェクトを作成する。
 * ・次に新規ファイルを作成する。
 *   ※この時、パッケージ名を net.npaka.gestureex とした場合、Eclipse は自動的に　net\npaka\gestureex のフォルダを作成しそこに新規ファイルを保存する。
 * ・プロジェクト名とソースファイル名をCMS管理者に通知する。（例えば npaka の下が階層的になっている場合はその構造も通知する）
 *   ※現在本プログラムはディレクトリ階層を自動的に最大64階層まで作成します。
 *   ※以下のプロジェクト配置はGestureEx プロジェクトのフォルダ実装例です。
 *   
 *   C:\Documents and Settings\son.CMS2\workspace\GestureEx\src\net\npaka\gestureex
 *   
 * ・ログインユーザIDとパスワードを管理者からもらう。
 * ・管理者はCMSサーバー側でCMS3プロトコルを起動する。
 * ・開発者は新規プロジェクトの、例えば npaka フォルダに新規ソースファイルを置き、プラグインを起動する。
 *   ※サーバー側では Eclipse のプロジェクト構造のうち、例えば npaka フォルダ配下からの管理を行います。
 *　・プラグインの「ポート番号」に3390〜3399のうち、管理者から指定されたポート番号と「ユーザID」「パスワード」を入力する。
 *  ※現在 net.npaka プロジェクトのユーザIDは android　で設定完了しています。パスワードは yumura です。ポート番号は3399になります。
 *　・「登録フォルダ」テキストボックスをクリックし、フォルダ選択ダイアログからプロジェクトのソースのあるフォルダを選択する。（androidユーザの場合 npaka になります）
 *
 *    例：C:\Documents and Settings\son.CMS2\workspace\GestureEx\src\net\npaka
 *    
 *    上の場所を選択して「保存」ボタンをクリックすることで、以降このフォルダ上でリビジョン管理を行うころが出来ます。
 *    リビジョン管理されるソースファイルは以下のページからダウンロードしたものです。
 *    http://www.saturn.dti.ne.jp/~npaka/android/
 *    
 * ・プラグインから「LISTの実行」ボタンでファイルの一覧をコンボボックスに読み込み、リビジョン登録するファイルを選択する。（または入力する）
 *   ※この時、例えばGestureプロジェクトの npaka フォルダで GestureEx.java を新規に作成する場合、「登録ファイル」に入力する形式は以下のようになります。
 *   
 *     gesture/GestureEx.java
 * 
 *   ※これはサーバーのリポジトリが npaka 配下からの管理になるためです。フォルダ名が小文字になっていることに注意してください。
 *   
 * ・「NEWFILE」ボタンでリポジトリに登録する。登録が完了したら「UNGET」ボタンをクリックし、他の開発者がGET出来るようにしておきます。
 * 
 *   ※現在 net.npaka プロジェクトは全てNEWFILE　登録が完了していますので、「GET」ボタンでファイルを呼び出すだけになっています。
 *   
 * ・登録したファイルを修正した後、プラグインから「PUT」ボタンでリビジョン登録することが出来ます。（「PUT」を実行すると修正前のファイルとの差分が登録されます）
 * ・リビジョン登録が完了したソースファイルは他の開発者が誰でも「GET」ボタンで呼び出すことが可能となります。
 * ・リビジョン管理ファイルは選択したフォルダのファイルに直接上書きされます。（ネットワークでの利用上途中ファイル転送が行われます）
 *   「WHO」ボタンで誰がGETしているのを確認することが出来ますが、今回は android の１ユーザだけですので、ファイルがロックされていてもUNGETボタンですぐに解消できます。
 * 
 * ★ここから以降は npaka プロジェクトでは必要ありません。
 * ・ファイルの修正が完了しプログラムが結合試験等に入った場合は、管理者にSUBMIT申請を行います。
 * 	以上、SUBMITが完了した場合ファイルのリビジョン管理は出来なくなります。（再開したい場合は管理者に通知する）
 * ・プロジェクトが完成し、最初のバージョンのリリースが行われた場合、COMMIT申請を行います。
 * 	COMMIT申請を行なった場合は最初のバージョンでのリビジョン管理は出来なくなります。（再開したい場合はバージョン番号がプラスされてから再開されます）
 * 
 * ※通常のリビジョン管理はユーザID（musr）のディレクトリで行います。特別のリビジョン管理はプロジェクトID（fusr）のディレクトリで行います。
 * ※特別のリビジョン管理は結合テストの後で行われます。リリースの管理も fusr で行います。
 * ※現在リビジョン管理サーバー codoo2hk.corede.net で管理する /musr 配下のユーザは以下になります。
 * 		android takaha hirai hatori tatikawa yamasaki ikeya mai takayama test
 * 
 * 注意点
 * ・サーバー側にはその他多くの管理コマンドがあるが、ネットワーク側には公開しません。
 * 
 * その他
 * 本プロトコルはPOP3プロトコルに似せてあるのでPOP3を参考にすると良い
 * 
 * Copyright(c) 2012 S.Ono
 * </pre>
 */


public class Cms3Client extends Cms3Swing {
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	public static String[] PWD = new String[1];
	/**
	 * CMSサーバー（CMS）用のCMSクライアント開始
	 */
	public static void cmsMain(String filename,String dirname,String Revision,TextField username, String password, int cmd) {
		//バージョン管理サーバーアドレス
		//final String hostname = "codoo2hk.corede.net";
		if(portno == null)
			return;
		if(portno.isEmpty() == true)
			return;
		if(username == null)
			return;
		if(password.isEmpty() == true)
			return;
		//テストサーバのCMS3用ポート番号
		int port = Integer.parseInt(portno);
		
		Socket socket;
		BufferedReader reader;
		BufferedWriter writer;
		
		//getの場合ターゲットファイルは存在してはならない
		int getflg = 0;

		try {
			//ホスト名からグローバルIPアドレスを取得する。
			InetAddress inetaddr = InetAddress.getByName(hostname);
			//グローバルアドレスと固定のポート番号でサーバにアクセスする。
			socket = new Socket(inetaddr, port);
			//ソケットからの入力ストリーム
			reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			//ソケットへの出力ストリーム
			writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
			//CMS3プロトコルの核心部。 putかput&newfileまたはget、listの分岐を行う。
			switch(cmd)
			{
			case 0://PUTを実行する
				if(filename == null)
					return;
				if(dirname == null)
					return;
				File f = new File(dirname + "\\" + filename);
				if(f.exists() == true)
				{
					try
					{
						CmsFtpMain('P',username.getText(),filename,dirname);
						JOptionPane.showMessageDialog(null, dirname + " からPUTはファイル転送を完了しました。", "PUT",JOptionPane.INFORMATION_MESSAGE);
					} catch (Exception e)
					{
						e.printStackTrace();
					}
				}
				else
				{
					JOptionPane.showMessageDialog(null, dirname + "\\" + filename + "　は見つかりません。", "PUT",JOptionPane.INFORMATION_MESSAGE);
				}
				if(Memo[0].length() == 0)
				{
					JOptionPane.showMessageDialog(null, "メモはありません。No-Neno に設定します。", "PUT",JOptionPane.INFORMATION_MESSAGE);
					Memo[0] = "No-Memo";
				}
				writer.write("USER " + username.getText() +  "\r\n");
				writer.write("PASS " + password + "\r\n");
				writer.write("STAT 3 " + filename + "\r\n");//ここでファイルの存在を確認する。（PUTの場合ファイル必ず存在しなければならない）
				writer.write("LIST 0 " + filename + "\r\n");
				writer.write("STOR 1 " + filename + ":" + "\"\"" + Memo[0] + "\"\"" + "\r\n");//★ここでPUTを行う。この文字列にメモを追加する必要がある。
				writer.write("RETR 0 " + filename + "\r\n");//ここでGETは行わない
				writer.write("QUIT \r\n");
				break;
			case 1://GETを実行する
				if(filename == null)
					return;
				if(dirname == null)
					return;
				writer.write("USER " + username.getText() +  "\r\n");
				writer.write("PASS " + password + "\r\n");
				writer.write("STAT 4 " + filename + "\r\n");//ここでファイルの存在を確認する。（GETの場合ファイルは存在してはならない）
				writer.write("LIST 0 " + filename + "\r\n");
				writer.write("STOR 0 " + filename + "\r\n");//ここでPUTは行わない
				writer.write("RETR 1 " + filename + "\r\n");//ここでGETを行う
				writer.write("QUIT \r\n");
				break;
			case 2://NEWFILEを実行する
				int ret = JOptionPane.showConfirmDialog(null, "NEWFILEを実行します。新しくファイルがリポジトリに登録されます。よろしいですか？", "NEWFILEの登録", JOptionPane.YES_NO_OPTION); 
				if (ret == JOptionPane.NO_OPTION)
				{
					return;
				}
				f = new File(dirname + "\\" + filename);
				if(f.exists() == true)
				{
					try
					{
						//☆ NEWFILE実行時ディレクトリが存在しない場合は新たに作成する。（最大64階層作成可能）
						CmsFtpMain('S',username.getText(),filename,dirname);
						//ファイル送信を開始する。
						CmsFtpMain('P',username.getText(),filename,dirname);
						JOptionPane.showMessageDialog(null, "NEWFILEはファイル転送を完了しました。次にファイル登録のチェックを行います。", "NEWFILE",JOptionPane.INFORMATION_MESSAGE);
					} catch (Exception e)
					{
						e.printStackTrace();
					}
				}
				else
				{
					JOptionPane.showMessageDialog(null, dirname + "\\" + filename + "　は見つかりません。", "NEWFILE",JOptionPane.INFORMATION_MESSAGE);
				}
				writer.write("USER " + username.getText() +  "\r\n");
				writer.write("PASS " + password + "\r\n");
				writer.write("STAT 1 " + filename + "\r\n");
				writer.write("LIST 0 " + filename + "\r\n");
				writer.write("STOR 2 " + filename + ":" + "\"\"" + Memo[0] + "\"\"" + "\r\n");//ここでNEWFILEを行う
				writer.write("RETR 1 " + filename + "\r\n");//ここでGETを行う
				writer.write("QUIT \r\n");
				break;
			case 3://LISTだけを実行する
				writer.write("USER " + username.getText() +  "\r\n");
				writer.write("PASS " + password + "\r\n");
				writer.write("STAT 0 " + "\r\n");//カレントディレクトリを取得する
				writer.write("LIST 1 " + "\r\n");//ここでLIST表示を行う
				writer.write("STOR 0 " + "\r\n");//ここでPUTは行わない
				writer.write("RETR 0 " + "\r\n");//ここでGETは行わない
				writer.write("QUIT \r\n");
				break;
			case 4://UNGETを実行する
				if(filename == null)
					return;
				ret = JOptionPane.showConfirmDialog(null, "UNGETを実行します。現在のファイルは削除されます。よろしいですか？", "GETの取消", JOptionPane.YES_NO_OPTION); 
				if (ret == JOptionPane.OK_OPTION)
				{
					writer.write("USER " + username.getText() +  "\r\n");
					writer.write("PASS " + password + "\r\n");
					writer.write("STAT 2 " + filename + "\r\n");
					writer.write("LIST 0 " + filename + "\r\n");
					writer.write("STOR 0 " + filename + "\r\n");//ここでPUTは行わない
					writer.write("RETR 2 " + filename + "\r\n");//ここでUNGETを行う
					writer.write("QUIT \r\n");
				}
				else
				{
					reader.close();
					writer.close();
					socket.close();
					System.out.println("socket close ok.");
					return;
				}
				break;
			case 5: //WHOを実行する
				if(filename == null)
					return;
				writer.write("USER " + username.getText() +  "\r\n");
				writer.write("PASS " + password + "\r\n");
				writer.write("STAT 2 " + filename + "\r\n");
				writer.write("LIST 0 " + filename + "\r\n");
				writer.write("STOR 0 " + filename + "\r\n");//ここでPUTは行わない
				writer.write("RETR 0 " + filename + "\r\n");//ここでUNGETを行う
				writer.write("QUIT \r\n");
				break;
			case 6:	//リビジョンのリストを実行する
				if(filename == null)
					return;
				writer.write("USER " + username.getText() +  "\r\n");
				writer.write("PASS " + password + "\r\n");
				writer.write("STAT 0 " + "\r\n");
				writer.write("LIST 2 " + filename + "\r\n");//ここでリビジョン表示を行う
				writer.write("STOR 0 " + "\r\n");//ここでPUTは行わない
				writer.write("RETR 0 " + "\r\n");//ここでGETは行わない
				writer.write("QUIT \r\n");
				break;
			case 7://VGETを実行する
				if(filename == null)
					return;
				writer.write("USER " + username.getText() +  "\r\n");
				writer.write("PASS " + password + "\r\n");
				writer.write("STAT 0 " + filename + "\r\n");
				writer.write("LIST 0 " + filename + "\r\n");
				writer.write("STOR 0 " + filename + "\r\n");//ここでPUTは行わない
				writer.write("RETR 3 " + filename + ":" + Revision + "\r\n");//ここでVGETを行う
				writer.write("QUIT \r\n");
				break;
			case 8://UNVGETを実行する
				if(filename == null)
					return;
				if(Revision == null)
					return;
				int ret2 = JOptionPane.showConfirmDialog(null, "UNVGETを実行します。現在のファイルは削除されます。よろしいですか？", "VGETの取消", JOptionPane.YES_NO_OPTION); 
				if (ret2 == JOptionPane.OK_OPTION)
				{
					writer.write("USER " + username.getText() +  "\r\n");
					writer.write("PASS " + password + "\r\n");
					writer.write("STAT 2 " + filename + "\r\n");
					writer.write("LIST 0 " + filename + "\r\n");
					writer.write("STOR 0 " + filename + "\r\n");//ここでPUTは行わない
					writer.write("RETR 4 " + filename + ":" + Revision + "\r\n");//ここでUNVGETを行う
					writer.write("QUIT \r\n");
				}
				else
				{
					reader.close();
					writer.close();
					socket.close();
					System.out.println("socket close ok.");
					return;
				}
				break;
			}
			//貯めたバッファを一度に書き込む
			writer.flush();
			//対話的処理を行うため標準入力ストリームからの文字を読み込む準備をする。
	        //BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
			int count = 0;
			while (true){
				//BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
				String line = reader.readLine();
				//ソケットからの応答に何も無い場合の処理
				if ( line == null ){
					break;
				}
				//デバッグ
				System.out.printf("%d:%s\n",count,line);
				//サーバーの応答メッセージに対応する
				switch(count)
				{
				case 0:
					//ユーザを確認
					if(line.substring(0,8).compareTo("+OK USER") == 0)
					{
						System.out.println("ユーザーを認識しました。");
					}
					else
					{
						System.out.println("CMSユーザを認識しませんでした。終了します。");
						JOptionPane.showMessageDialog(null, "CMSにLogin 出来ません。ユーザが違います。 ", "USER",JOptionPane.INFORMATION_MESSAGE);
						writer.write("QUIT \r\n");
						socket.close();
						reader.close();
						return;
					}
					break;
				//PASS
				case 1:
					//パスワードを確認
					if(line.substring(0,8).compareTo("+OK PASS") == 0)
					{
						System.out.println("パスワードを確認しCMSに　Login しました。認証OKです。");
					}
					else
					{
						System.out.println("CMSにLogin 出来ません。パスワードが違います。");
						JOptionPane.showMessageDialog(null, "CMSにLogin 出来ません。パスワードが違います。 ", "PASS",JOptionPane.INFORMATION_MESSAGE);
						writer.write("QUIT \r\n");
						socket.close();
						reader.close();
						return;
					}
					break;
				//STAT
				case 2:
					//リビジョン登録ファイルが存在するかを確認(lockされている場合一応getlogを調査し、調査結果を返信する)
					if(line.substring(0,10).compareTo("-OK STAT 2") == 0)
					{
						//WHOのための処理
						System.out.printf("%s\n",line);
						JOptionPane.showMessageDialog(null, line.substring(11) + " GETされています。 ", "WHO",JOptionPane.INFORMATION_MESSAGE);
					}
					//ファイルがロックされていない場合の返信コード（Available GET）
					if(line.substring(0,10).compareTo("-NT STAT 2") == 0)
					{
						//WHOのための処理
						System.out.printf("%s\n",line);
						JOptionPane.showMessageDialog(null, line.substring(11) + " GET出来ます。 ", "WHO",JOptionPane.INFORMATION_MESSAGE);
					}
					/*
					if(line.substring(0,10).compareTo("+OK STAT 2") == 0)
					{
						System.out.printf("%s\n",line);
					}
					*/
					//NEWFILEのための処理。カレントディレクトリに新規ファイルが用意されていれば+OK STAT 1 そうでない場合は +NG STAT 1
					if(line.substring(0,10).compareTo("+OK STAT 1") == 0)
					{
						System.out.printf("%s\n",line);
						JOptionPane.showMessageDialog(null, "このファイルは存在します。", "STAT 1",JOptionPane.INFORMATION_MESSAGE);
					}
					//NEWFILEのための処理。カレントディレクトリに新規ファイルが用意されていれば+OK STAT 1 そうでない場合は +NG STAT 1
					if(line.substring(0,10).compareTo("+NG STAT 1") == 0)
					{
						System.out.printf("+NG STAT 1 = %s\n",line);
						JOptionPane.showMessageDialog(null, "このファイルはサーバでUNGETかPUTされています。", "STAT 1",JOptionPane.INFORMATION_MESSAGE);
						getflg = 1;
					}
					/*
					if(line.substring(0,10).compareTo("-NG STAT 2") == 0)
					{
						System.out.printf("%s\n",line);
						JOptionPane.showMessageDialog(null, "-NG STAT 2", "WHO",JOptionPane.INFORMATION_MESSAGE);
						getflg = 1;
					}
					*/
					//GETの時ファイルがlockされていない場合の処理
					if(line.substring(0,10).compareTo("+OK STAT 4") == 0)
					{
						System.out.printf("%s\n",line);
						//JOptionPane.showMessageDialog(null, "+OK STAT4", "GET",JOptionPane.INFORMATION_MESSAGE);
						getflg = 1;
					}
					//GETの時、リビジョン登録ファイルが存在するかを確認(lockされている場合一応getlogを調査し、調査結果を返信する)
					if(line.substring(0,10).compareTo("+NT STAT 4") == 0)
					{
						System.out.println("STAT GETされています。");
						JOptionPane.showMessageDialog(null, line.substring(11) + " GETされています。 ", "GET(WHO)",JOptionPane.INFORMATION_MESSAGE);
						//getflg = 1;
					}
					//カレントユーザが musr なのか fusr なのかを調査する。（ファイル送受信のための準備処理）
					if(line.substring(0,10).compareTo("+OK STAT 0") == 0 || line.substring(0,10).compareTo("+OK STAT 0") == 0)
					{
						System.out.printf("+OK STAT 0 = %s\n",line);
						if(line.indexOf("/cms/fusr") != -1)
						{
							PWD[0] = "/fusr";
						}
						if(line.indexOf("/cms/musr") != -1)
						{
							PWD[0] = "/musr";
						}
						System.out.printf("PWD = %s\n",PWD[0]);
						getflg = 0;
					}
					//PUTのための処理。PUTするファイルがカレントディレクトリにあればOK。lockされていてもいなくても送信OKの返信を行う。
					if(line.substring(0,10).compareTo("+OK STAT 3") == 0)
					{
						try
						{
							//CmsFtpMain('P',username.getText(),filename,"test");
							JOptionPane.showMessageDialog(null, "PUTはファイル転送を完了しました。引き続き差分の登録を行います。", "PUT",JOptionPane.INFORMATION_MESSAGE);
						} catch (Exception e)
						{
							e.printStackTrace();
						}
						getflg = 0;
					}
					//カレントユーザが musr なのか fusr なのかを調査する。（ファイル送受信のための準備処理）（LIST表示のための処理）
					if(line.substring(0,10).compareTo("+NT STAT 0") == 0)
					{
						System.out.println("STAT LISTコマンドはファイル検査をしません。");
						System.out.printf("+OK STAT 0 = %s\n",line);
						if(line.indexOf("/cms/fusr") != -1)
						{
							PWD[0] = "/fusr";
						}
						if(line.indexOf("/cms/musr") != -1)
						{
							PWD[0] = "/musr";
						}
						System.out.printf("PWD = %s\n",PWD[0]);
						getflg = 0;
						//break;
					}
					break;
				//LIST コマンドでログインディレクトリのリビジョン管理ファイルを表示する
				case 3:
					//ファイルの数を確認
					System.out.println(line);
					if(line.substring(0,8).compareTo("+OK LIST") == 0){
						if(line.substring(8,10).compareTo(" 0") == 0)
						{
							break;
						}
					}
					if(line.substring(0,8).compareTo("+OK LIST") == 0)
					{
						if(line.substring(8,10).compareTo(" 1") == 0)
						{
							System.out.println("LIST ファイルを表示します。");
							System.out.println(line.substring(9));

							String List = line.substring(10);
							String[] item = new String[1];
							item = List.split(" ");
							//アプレットのチョイス（コンボボックス）にリストする
							for (int i=0;i < item.length;i++)
							{
								choice_1.add(item[i]);
							}
							JOptionPane.showMessageDialog(null, "LIST が完了しました。「ファイルの選択」を行なって下さい。", "LIST",JOptionPane.INFORMATION_MESSAGE);
						}
						else if(line.substring(8,10).compareTo(" 2") == 0)
						{
							System.out.println("LIST リビジョンを表示します。");
							System.out.println(line.substring(9));

							String Rev = line.substring(10);
							String[] item2 = new String[1];
							item2 = Rev.split(" ");
							//アプレットのチョイス（コンボボックス）にリストする
							for (int i=0;i < item2.length;i++)
							{
								choice_2.add(item2[i]);
							}
						} else
						{
							//System.out.println(line);
							System.out.println("LIST がうまくいきません。終了します。");
							JOptionPane.showMessageDialog(null, "LIST がうまくいきません。終了します。", "LIST",JOptionPane.INFORMATION_MESSAGE);
							writer.write("QUIT \r\n");
							socket.close();
							reader.close();
							return;
						}
					}
					break;
				//STOR コマンドでputを実行すｆる。
				case 4:
					if(line.substring(0,10).compareTo("+NT STOR 1") == 0)
					{
						System.out.println("STOR 変更されていません。PUT は行いません。");
						JOptionPane.showMessageDialog(null, filename + "は変更されていません。PUT は行いません。", "PUT",JOptionPane.INFORMATION_MESSAGE);
					}
					//STORコマンドを実行するパターンの場合だけ処理される　　
					if(line.substring(0,10).compareTo("+OK STOR 1") == 0)
					{
						System.out.println("STOR 変更の差分を登録し、PUTは完了しました。");
						JOptionPane.showMessageDialog(null, filename + " の変更の差分を登録し、PUTは完了しました。", "PUT",JOptionPane.INFORMATION_MESSAGE);
						getflg = 0;
					} else if(line.substring(0,10).compareTo("+OK STOR 2") == 0)
					{
						System.out.println("STOR ファイルをNEWFILEで登録します。");
						JOptionPane.showMessageDialog(null, filename + " のファイルをNEWFILEで登録します。", "NEWFILE",JOptionPane.INFORMATION_MESSAGE);
						getflg = 0;
					} 
					//しかしエラーがあった場合は以下の処理を行う。そしてプログラムを終了する。
					else if(line.substring(0,4).compareTo("-ERR") == 0)
			        {
						System.out.println("STOR ファイルのPUTに失敗しました。");
						JOptionPane.showMessageDialog(null, "ファイルのPUTに失敗しました。", "PUT",JOptionPane.INFORMATION_MESSAGE);
						writer.write("QUIT \r\n");
						reader.close();
						//writer.close();
						socket.close();
						return;
			        }
					break;
				//RETR コマンドでgetまたは ungetを実行する。
				case 5:
			        if(line.substring(0,10).compareTo("+OK RETR 0") == 0)
			        {
			        	System.out.println("GETは何も行ないませんでした。");
			        	break;
			        }
			        if (line.substring(0,10).compareTo("+OK RETR 1") == 0)
			        {
			        	try
						{
					        if(getflg == 1)
					        {
					        	System.out.println("GETを実行します。");
					        	CmsFtpMain('G',username.getText(),filename,dirname);
					        }
						} catch (Exception e)
						{
							e.printStackTrace();
						}
			        	break;
			        }
			        if (line.substring(0,10).compareTo("+OK RETR 2") == 0)
			        {
			        	System.out.println("UNGETを実行しました。");
			        	JOptionPane.showMessageDialog(null, "UNGETを実行しました。", "UNGET",JOptionPane.INFORMATION_MESSAGE);
			        	break;
			        }
		        	if(line.substring(0,10).compareTo("+NT RETR 1") == 0)
		        	{
		        		System.out.println("GETを実行出来ません。");
		        		JOptionPane.showMessageDialog(null, line.substring(10) + " 既にGETされています。 ", "GET",JOptionPane.INFORMATION_MESSAGE);
		        		writer.write("QUIT \r\n");
		        		socket.close();
		        		reader.close();
		        		return;
		        	}
		        	if(line.substring(0,10).compareTo("+NT RETR 2") == 0)
		        	{
		        		System.out.println("UNGETを実行出来ません。");
		        		JOptionPane.showMessageDialog(null, line.substring(11) + " UNGETを実行出来ません。 サーバーから+OK UNGがありません。", "UNGET",JOptionPane.INFORMATION_MESSAGE);
		        		writer.write("QUIT \r\n");
		        		socket.close();
		        		reader.close();
		        		return;
		        	}
		        	if(line.substring(0,10).compareTo("+NT RETR 3") == 0)
		        	{
		        		System.out.println("VGETを実行出来ません。");
		        		JOptionPane.showMessageDialog(null,"VGETを実行出来ません。 サーバーから+OK UNVがありません。 ", "UNGET",JOptionPane.INFORMATION_MESSAGE);
		        		writer.write("QUIT \r\n");
		        		socket.close();
		        		reader.close();
		        		return;
		        	}
		        	if(line.substring(0,10).compareTo("+OK RETR 3") == 0)
		        	{
		        		System.out.println("VGETを実行します。");
		        		File dir = new File(".");
		        		dir.getPath();
		        		System.out.printf("pwd=%s\n",dir.getPath());
		        		JOptionPane.showMessageDialog(null, " VGETを実行します。 ", "VGET",JOptionPane.INFORMATION_MESSAGE);
		        		try
						{
							CmsFtpMain('G',username.getText(),filename,dirname);
							CmsFtpMain('G',username.getText(),filename + "_" + Revision,dirname);
							JOptionPane.showMessageDialog(null, " 指定したリビジョンファイルと、その差分ファイルを受信しました。 ", "VGET",JOptionPane.INFORMATION_MESSAGE);
						} catch (Exception e)
						{
							e.printStackTrace();
						}
		        		writer.write("QUIT \r\n");
		        		socket.close();
		        		reader.close();
		        		return;
		        	}
		        	if(line.substring(0,10).compareTo("+OK RETR 4") == 0)
		        	{
		        		System.out.println("UNVGETを実行しました。");
		        		JOptionPane.showMessageDialog(null, " UNVGETを実行しました。 ", "UNVGET",JOptionPane.INFORMATION_MESSAGE);
		        	}
		        	if(line.substring(0,10).compareTo("+NT RETR 4") == 0)
		        	{
		        		System.out.println("UNVGETを実行出来ません。");
		        		JOptionPane.showMessageDialog(null, " UNVGETを実行出来ません。 ", "UNVGET",JOptionPane.INFORMATION_MESSAGE);
		        	}
					break;
				case 6:
					//QUITコマンドを実行する
					if(line.substring(0,8).compareTo("+OK QUIT") == 0)
					{
						System.out.println("QUIT コマンドで終了します。");
						//JOptionPane.showMessageDialog(null, "サーバーとの接続を切断します。", "QUIT",JOptionPane.INFORMATION_MESSAGE);
					} 
			        else
			        {
			        	System.out.println("QUIT コマンドで終了出来ません。");
			        }
					break;
				default:
					break;
				}
				//デバッグ
				//System.out.println(line);
				count++;
			}
			reader.close();
			writer.close();
			socket.close();
			System.out.println("socket close ok.");

		} catch (UnknownHostException e){
			e.printStackTrace();
		} catch (IOException e){
			e.printStackTrace();
		}
	}


		public static void CmsFtpMain(char cmd, String userdir,String filename, String direname) throws Exception {

	        // ホスト名を設定する
	        //以下のホスト名をFTPサイトに合わせて変更すること
	        //FtpSimpleClient ftp = new FtpSimpleClient("rocketcarmen.dyndns.info", false);
	        CmsFtpClient ftp = new CmsFtpClient("codoo2hk.corede.net", false);
			// デバッグモードを利用する
	        ftp.setDebug(true);
	        //パッシブモードは使わない
	        ftp.setPassive(false);

	        // 接続
	        ftp.connect();

	        // ログイン
	        //以下のユーザIDとパスワードをFTPサイトに合わせて変更すること
	        ftp.logon("cms", "kei0914");

	        // データ形式
	        ftp.type(false);

	        // コマンドは標準入力から取得する
	        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
	        System.out.printf("PWD=%s",PWD[0]+ "/" + userdir);
	        ftp.cwd(PWD[0]+ "/" + userdir);
	        
	        // ファイル名はストリング文字列なのでnullで初期化する
	        //String filename = null;
	        //String direname = null;

			while(true)
			{
				switch(cmd)
				{
				case 'S':
            		/** ☆ ディレクトリ調査。そしてなければ作成する。
            		 * @param String direname
            		 * 　ここにサーバー側のディレクトリを最大64階層でも作成する機能を追加する必要がある。（現在２階層しか出来ない）
            		 * Windows側は最大64階層作成可能
            		 */
					int stat;
					int cx;
					String Direname;

					if((cx = filename.indexOf('/')) > 0)
					{
						Direname = filename.substring(0,cx);
						stat = ftp.stat(Direname);
					
						//System.out.printf("%3d:STAT\n",stat);
						//String ss = String.format("%3d",stat);
						//JOptionPane.showMessageDialog(null, Direname + " MKD " + ss + ":", "NEWFILE",JOptionPane.INFORMATION_MESSAGE);
						if(stat == 2)
						{
							ftp.mkd(Direname);
						}
					}
					ftp.disconnect();
					return;

				case 'C':
	            	/** ディレクトリ移動
	            	* @param String direname
	            	*/
					direname = in.readLine();
					ftp.cwd(direname);;
					break;
				case 'D':
	            	/** ファイル削除
	            	* @param String filename
	            	*/
					filename = in.readLine();
					if(filename.length() == 0)
						break;
					ftp.dele(filename);;
					break;
				case 'M':
	            	/** ディレクトリ作成
	            	* @param String direname 
	            	*/
					direname = in.readLine();
					if(direname.length() == 0)
						break;
					ftp.mkd(direname);;
					break;
				case 'R':
	            	/** ディレクトリ削除
	            	* @param String direname
	            	*/
					direname = in.readLine();
					if(direname.length() == 0)
						break;
					ftp.rmd(direname);;
					break;
				case 'P':
	            	/*　☆追加処理１：ファイル送信のファイル判定
	            	 * 　　　PUTを実行する前に判定を行う処理を追加済み
	            	*/
					try {
						/*
						// ダブルコマンドの後の引数の文字列を格納
						filename = in.readLine();
						// 文字列の長さを判定
						if(filename.length() == 0)
							break;
						// ファイルオブジェクトを利用してファイルの存在を確認する
						 */
						File file = new File(direname + "\\" + filename);
						if(file.exists() == false)
						{
							System.out.printf("指定したフォルダに送信するファイルがありません。");
							JOptionPane.showMessageDialog(null, direname + "\\" + filename + " 指定したフォルダに送信するファイルがありません。", "PUT",JOptionPane.INFORMATION_MESSAGE);
							return;
						}
						//もしファイル名の中にディレクトリ区切り文字があった場合は区切り文字より前をディレクトリとして認識する。
						if((cx = filename.indexOf('/')) != -1)
						{
							//64階層まで送信出来る準備
							//String unBasename;
							//String Basename;
							
							int len = filename.length();
							int j = filename.lastIndexOf("/");
							int i = len - j;
							//パスの最後にあるファイル名
							String Basename = filename.substring(j+1);

							//サーバーのリビジョンテーブルファイルから読み取ったディレクトリ階層の数だけディレクトリを作成する。
							//この時、FTPはサーバーの階層をCWDしながら目的のディレクトリにたどり着きファイル送信プロトコルを実行する。
							String direname2;
							direname2 = ftp.pwd();
							//フォルダ＆ディレクトリの階層は64階層まで作成可能
							String[] splitpath = new String[64];
							splitpath = filename.split("/");
							//System.out.printf("splitpath.length=%d\n",splitpath.length);
							for(i=0;i < (splitpath.length)-1 && i < 64;i++)
							{
								//System.out.printf("splitpath[i]=%d\n",splitpath[i].length());
								stat = ftp.stat(splitpath[i]);
								//JOptionPane.showMessageDialog(null, Direname + " MKD " + ss + ":", "NEWFILE",JOptionPane.INFORMATION_MESSAGE);
								//もしディレクトリが無い場合は作成する。
								if(stat == 2)
								{
									ftp.mkd(splitpath[i]);
								}
								ftp.cwd(splitpath[i]);
								direname2 = direname2 + "/" + splitpath[i];
							}
							// ファイルインプットストリームを利用する
							FileInputStream input = new FileInputStream(direname + "\\" + filename);
							// データインプットストリームを利用する
							DataInputStream indata = new DataInputStream(input);
							// 送信用ストリームのサイズを調査する
							len = indata.available();
							// 適切なサイズのバイト列を確保
							byte buf[] = new byte[len];
							// バイト列をストリームから読み込む
							indata.read(buf);
							// イメージファイルを送信可能なImageモードに変更する
							ftp.type(true);
							// 送信を実行
							if(ftp.put(Basename,buf) == true)
							{
								System.out.println("ファイルを送信しました。");
								JOptionPane.showMessageDialog(null, "ファイルの送信が完了しました。", "PUT",JOptionPane.INFORMATION_MESSAGE);
							}
							else
							{
								JOptionPane.showMessageDialog(null, "ファイルの送信が失敗しました。", "PUT",JOptionPane.INFORMATION_MESSAGE);
							}
								
							//　オープンしたデータストリームとファイルをクローズする
							indata.close();
							input.close();
						}
						else
						{
							// ファイルインプットストリームを利用する
							FileInputStream input = new FileInputStream(direname + "\\" + filename);
							// データインプットストリームを利用する
							DataInputStream indata = new DataInputStream(input);
							// 送信用ストリームのサイズを調査する
							int len = indata.available();
							// 適切なサイズのバイト列を確保
							byte buf[] = new byte[len];
							// バイト列をストリームから読み込む
							indata.read(buf);
							// イメージファイルを送信可能なImageモードに変更する
							ftp.type(true);
							// 送信を実行
							if(ftp.put(filename,buf) == true)
							{
								System.out.println("ファイルを送信しました。");
								JOptionPane.showMessageDialog(null, "ファイルの送信が完了しました。", "PUT",JOptionPane.INFORMATION_MESSAGE);
							}
							else
							{
								JOptionPane.showMessageDialog(null, "ファイルの送信が失敗しました。", "PUT",JOptionPane.INFORMATION_MESSAGE);
							}
								
							//　オープンしたデータストリームとファイルをクローズする
							indata.close();
							input.close();
						}
						ftp.disconnect();
					} catch (IOException e) {
						System.out.println(e);
					}
					return;
				case 'G':
	            	/*　☆ファイル受信
	            	* @param File filename
	            	* @param DataOutputStream outdata
	            	*/
					try {
						/*
						filename = in.readLine();
						if(filename.length() == 0)
							break;
						*/
						File file = new File(direname + "\\" + filename);
						if(file.exists())
						{
							System.out.printf("カレントディレクトリに同名のファイルが存在します。上書きしますか？");
							int ret = JOptionPane.showConfirmDialog(null, "カレントディレクトリに同名のファイルが存在します。上書きしますか？", "GET", JOptionPane.YES_NO_OPTION); 
							if (ret != JOptionPane.OK_OPTION)
							{
								ftp.disconnect();
								return;
							}
						}
						// バイナリファイルも受信出来るようにする
						ftp.type(true);
						//2階層まで受信出来る準備
						//String unBasename;
						String Basename;
						

						//もしファイル名の中にディレクトリ区切り文字があった場合は区切り文字より前をディレクトリとして認識する。
						if((cx = filename.indexOf('/')) != -1)
						{
							int len = filename.length();
							int j = filename.lastIndexOf("/");
							int i = len - j;
							//パスの最後にあるファイル名
							Basename = filename.substring(j+1);

							//階層を数えてリビジョンテーブルファイルから読み取ったディレクトリ階層のあるファイルはその階層の数だけディレクトリを作成する。
							//この時、FTPはサーバーの階層をCWDしながら目的のディレクトリにたどり着きファイル受信プロトコルを起動する。
							int n = 0;
							String direname2;
							direname2 = direname;
							//フォルダ＆ディレクトリの階層は64階層まで作成可能
							String[] splitpath = new String[64];
							splitpath = filename.split("/");
							//System.out.printf("splitpath.length=%d\n",splitpath.length);
							for(i=0;i < (splitpath.length)-1 && i < 64;i++)
							{
								//System.out.printf("splitpath[i]=%d\n",splitpath[i].length());
								File newdir = new File(direname2 + "\\" + splitpath[i]);
								if((newdir.exists()) == false)
									newdir.mkdir();
								direname2 = direname2 + "\\" + splitpath[i];
								n++;
							}
							
							//System.out.printf("unBasename=%s\n",unBasename);
							//System.out.printf("n=%d\n",n);
							for(i=0;i<n;i++)
							{
								System.out.printf("%s ",splitpath[i]);
								//2階層以上の場合はそのディレクトリに移動する
					        	ftp.cwd(splitpath[i]);
							}

				        	// ファイルアウトプットストリームを利用する
				        	FileOutputStream output = new FileOutputStream(direname + "\\" + filename);
				        	// データアウトプットストリームを利用する
				        	DataOutputStream outdata = new DataOutputStream(output);
				        	// 受信を実行
				        	if(ftp.get(Basename,outdata) == false)
				        		//if(ftp.get(direname + "\\" + filename,outdata) == false)
				        	{
				        		System.out.println("指定したファイル名が違います");
				        		JOptionPane.showMessageDialog(null, " 指定したファイル名が違います。", "GET",JOptionPane.INFORMATION_MESSAGE);
				        		outdata.close();
				        		output.close();
				        		return;
				        	}
				        	// ファイルの内容をデータアウトプットストリームから読み込む
				        	outdata = new DataOutputStream(outdata);
				        	//　オープンしたデータストリームとファイルをクローズする
				        	outdata.close();
				        	output.close();
				        }
				        else
				        {
							// ファイルアウトプットストリームを利用する
							FileOutputStream output = new FileOutputStream(direname + "\\" + filename);
							// データアウトプットストリームを利用する
					        DataOutputStream outdata = new DataOutputStream(output);
							// 受信を実行
							if(ftp.get(filename,outdata) == false)
							{
								System.out.println("指定したファイル名が違います");
								output.close();
								return;
							}
							// ファイルの内容をデータアウトプットストリームから読み込む
					        outdata = new DataOutputStream(outdata);
					     	//　オープンしたデータストリームとファイルをクローズする
					        outdata.close();
					        output.close();
				        }
						// 切断して終了
						ftp.disconnect();

						JOptionPane.showMessageDialog(null, filename + " " + direname + " ファイルの受信が完了しました。", "GET",JOptionPane.INFORMATION_MESSAGE);
						/*
						//ms-dosコマンドの copy を利用してプロジェクトのフォルダにコピーする。
						if(doscopy(filename,direname) != 0)
						{
							JOptionPane.showMessageDialog(null, "ファイルのコピーが失敗しました。", "dos copy",JOptionPane.INFORMATION_MESSAGE);
						}
						else
						{
							System.out.println(direname + "\\" + filename + "にファイルを受信しました。");
					        JOptionPane.showMessageDialog(null,direname + "\\" + filename +  "　にファイルの受信が完了しました。", "GET",JOptionPane.INFORMATION_MESSAGE);
						}
						//コピー元のファイルはeclisepの作業ディレクトリから削除する。
						if(dosdel(filename) != 0)
						{
							JOptionPane.showMessageDialog(null, "ファイルの削除が失敗しました。", "dos del",JOptionPane.INFORMATION_MESSAGE);
						}
						*/

						return;
					} catch  (IOException e) {
							System.out.println(e);
							// 切断して終了
							ftp.disconnect();
							
					}
					ftp.disconnect();
					return;

			/*		
				// 以下は単独コマンド

				case 'l':
					//リスト（LIST）コマンドの送信
					ftp.type(false);
					System.out.println("LIST:\n" + ftp.list());
					break;
				case 'i':
					//送受信ファイルをイメージタイプに変更
					ftp.type(true);
					break;
				case 'a':
					//送受信ファイルをアスキータイプに変更
					ftp.type(false);
					break;
				case 'c':
					//カレントディレクトリにpublic_htmlが存在していた場合そのディレクトリに移動
					ftp.cwd("./public_html");
					System.out.println("PWD:" + ftp.pwd());
					break;
				case 'p':
					//PWDコマンドを実行（Print Working Directory）
					System.out.println("PWD:" + ftp.pwd());
					break;
				case 'u':
					//ディレクトリを一つ上に移動
					ftp.cwd("..");
					System.out.println("PWD:" + ftp.pwd());
					break;
				case 's':
	            	//送信テスト
			        ftp.type(true);
	            	ftp.put("sample.txt", "FtpSimpleClient PORT test".getBytes());
	            	break;
				case 'r':
					// ファイルの内容の受信
					baos = new ByteArrayOutputStream();
					ftp.get("sample.txt", baos);
					System.out.println(baos.toString());
					break;
				case 'q':
					// 切断して終了
					ftp.disconnect();
					return;
				default:
					break;
			*/
						
	        	}
			}
	    }

		/*
		//MS-DOSコマンドの copy で eclipse の作業フォルダから指定のフォルダにコピーする。
	    private static int doscopy(String filename, String direname) throws IOException {
	        int rc = 0;
	        String copy;
	        copy = String.format("cmd /c copy /A /Y %s \"%s\"",filename,direname);
	        Process ps = Runtime.getRuntime().exec(copy);	
	        try {
	            rc = ps.waitFor();
	        	
	        } catch ( InterruptedException ie ) {}
	        return rc;
	    }
		//MS-DOSコマンドの del で eclipse の作業フォルダに残ったファイルを削除する。
	    private static int dosdel(String filename) throws IOException {
	        int rc = 0;
	        String delete;
	        delete = String.format("cmd /c del %s",filename);
	        Process ps = Runtime.getRuntime().exec(delete);	
	        try {
	            rc = ps.waitFor();
	        	
	        } catch ( InterruptedException ie ) {}
	        return rc;
	    }
	    */
	}




