changeset 3:db4813125eb8

many changes.
author pyon@macmini
date Thu, 11 Oct 2018 22:11:09 +0900
parents 7fe3417cefc8
children 06342fc544e4
files app.conf doc/Todo go/client.go go/crypto.go go/server.go include/auth.h include/main.h include/rsearcher.h src/auth.cpp src/main.cpp src/rsearcher.cpp
diffstat 11 files changed, 491 insertions(+), 164 deletions(-) [+]
line wrap: on
line diff
--- a/app.conf	Tue Oct 02 21:20:05 2018 +0900
+++ b/app.conf	Thu Oct 11 22:11:09 2018 +0900
@@ -1,5 +1,8 @@
 [Geometry]
-x=383
-y=48
-w=1220
-h=967
+x=487
+y=118
+w=1136
+h=721
+[Server]
+server=192.168.79.124:3910
+proxy=
--- a/doc/Todo	Tue Oct 02 21:20:05 2018 +0900
+++ b/doc/Todo	Thu Oct 11 22:11:09 2018 +0900
@@ -20,22 +20,22 @@
 ** crypto/crypto.exe の機能 *****************************************************
 * crypto.go 作成
 	+ auth 用 ( ハッシュ化 )
-		* -a で plaintext を暗号化
-			> crypto.exe -a plaintext -s salt	// done.
-		* -b で auth.csv を暗号化
+		* -a で plaintext を暗号化	# server/client
+			> crypto.exe -a plaintext -s salt
+		* -b で auth.csv を暗号化	# server
 			> crypto.exe -b auth.csv -s salt > auth.db
-		* -c で 認証チェック
+		* -c で 認証チェック		# gui
 	   		> crypto.exe -c auth.db -s salt user passwd
-			+ user/passwd が一致したら "39 user" を返す
+			+ user/passwd が一致したら "valid user を表示し "39 を返す
 			+ 認証なしのテストのときは user/passwd: test/test
 		+ auth.db のための salt は gui に内蔵する
 	+ hhs 用 ( 双方向、キーは crypto.go と gui に内蔵 )
-		* -d で復号化、-e で暗号化
-			> crypto.exe -d hhs.db key > hhs.csv
-			> crypto.exe -e hhs.csv > hhs.db
-		* -f で 認証チェック
+		* -d で復号化、-e で暗号化	# server
+			> crypto.exe -d hhs.db  key > hhs.csv
+			> crypto.exe -e hhs.csv key > hhs.db
+		* -f で 認証チェック		# gui
 			> crypto.exe -f hhs.db hhs key
-			+ hhs/key が一致したら "39 hhs" を返す
+			+ hhs/key が一致したら hhs の情報を返す
 
 ** imgtgz の機能 ****************************************************************
 * jpeg を 1.jpg, ..., 5.jpg とリネームし tgz にする.
@@ -44,10 +44,10 @@
 * 単なる web-server
     + upload 機能を追加 ( ver1.1 )
     + log 機能を追加 ( ver1.2 )
+    + log 機能を強化(user-id) ( ver1.3 )
 
 ** grsearcher の機能 ****************************************************************
  * 10分間 Idle なら password
- * auth.cpp pw の最後にカーソル、 xボタン無効化
  * mouse gesture 次、前のタブへ
  * dark-mode の搭載
  * プライベートフォルダに写真 userid/startup.jpg, default.jpg, avatar.jpg
--- a/go/client.go	Tue Oct 02 21:20:05 2018 +0900
+++ b/go/client.go	Thu Oct 11 22:11:09 2018 +0900
@@ -1,7 +1,7 @@
 /*
  client.go  : client-program.
- Version    : 1.0
- Last Change: 2018-10-01 Mon 21:45:18.
+ Version    : 1.0a
+ Last Change: 2018-10-03 豌エ 13:44:11.
 
  install to: rsearcher_root/
 
@@ -12,7 +12,7 @@
                + auth.db ( temporary )
                + hhs.db  ( temporary )
                + index.db ( 10 days )
-               + image/*.png
+               + image/*.png, *.jpg
                + doc/
                + .cache/*.jpg ( temporary )
 
@@ -158,8 +158,8 @@
             return err
 		}
         //f, _ :=  os.Create( hdr.Name )
-        fn := fmt.Sprintf( "%s_%d.jpg", d, i )
-        fn = fmt.Sprintf( "00000000_%d", i )    // for test
+        fn := fmt.Sprintf( "%s_%d", d, i )	// 1.0a
+        //fn = fmt.Sprintf( "00000000_%d", i )  // for test
 
         fn = filepath.Join( ".cache", fn )
         f, _ :=  os.Create( fn )
--- a/go/crypto.go	Tue Oct 02 21:20:05 2018 +0900
+++ b/go/crypto.go	Thu Oct 11 22:11:09 2018 +0900
@@ -1,7 +1,7 @@
 /*
  crypto.go  : crypto-program.
  Version    : 0.0
- Last Change: 2018-09-30 Sun 16:47:45.
+ Last Change: 2018-10-11 譛ィ 13:54:56.
 
  install to: rsearcher_root/
              server_root/
@@ -9,22 +9,30 @@
 package main
 
 import (
+	"crypto/aes"
+	"crypto/cipher"
+	"crypto/rand"
 	"crypto/sha256"
+	"encoding/csv"
+	"encoding/hex"
 	"fmt"
 	"flag"
+	"io"
+	"io/ioutil"
+	"log"
 	"os"
 )
 
 func main() {
-	salt := flag.String( "s", "#!@-", "salt." )
+	salt := flag.String( "s", "dummysalt", "salt." )
+
 	enca := flag.String( "a", "", "encrypt plaintext." )
 	encb := flag.String( "b", "", "encrypt csv-file." )
 	coll := flag.String( "c", "", "collate user/password." )
 
 	decr := flag.String( "d", "", "deecrypt hhs." )
 	encr := flag.String( "e", "", "encrypt hhs." )
-	chdb := flag.String( "f", "", "collate hhs." )
-	chhs := flag.String( "g", "", "collate hhs." )
+	ghhs := flag.String( "f", "", "get hhs info." )
 
 	flag.Parse()
 
@@ -35,7 +43,41 @@
 	}
 
 	if *encb != "" {
-		r := csv.NewReader(strings.NewReader(in))
+		f, err := os.Open( *encb ); if err != nil {
+			log.Fatal( err )
+		}
+		defer f.Close()
+
+		r := csv.NewReader( f )
+		for {
+			record, err := r.Read()
+			if err == io.EOF {
+				break
+			}
+			if err != nil {
+				log.Fatal( err )
+			}
+			buf := *salt + enc_sha256( record[ 1 ] ) + *salt
+			fmt.Println( record[ 0 ], enc_sha256( buf ) )
+		}
+		os.Exit( 0 )	// done.
+	}
+
+	if *coll != "" {
+		f, err := os.Open( *coll ); if err != nil {
+			log.Fatal( err )
+		}
+		defer f.Close()
+
+		if flag.NArg() != 2 {
+			fmt.Fprintf( os.Stderr, "bad argument\n" )
+			os.Exit( 1 )
+		}
+		user := flag.Arg( 0 )
+		pw   := flag.Arg( 1 )
+
+		r := csv.NewReader( f )
+		r.Comma = ' '
 		for {
 			record, err := r.Read()
 			if err == io.EOF {
@@ -44,21 +86,77 @@
 			if err != nil {
 				log.Fatal( err )
 			}
-			buf := *salt + enc_sha256( record[1] ) + *salt
-			fmt.Println( record[0], ",", enc_sha256( buf ) )
+
+			if record[ 0 ] == user {
+				buf := *salt + enc_sha256( pw ) + *salt
+				if record[ 1 ] == enc_sha256( buf ) {
+					fmt.Println( "valid" )
+					os.Exit( 39 )
+				}
+			}
 		}
-	}
-
-	if *coll != "" {
+		os.Exit( 0 )	// done.
 	}
 
+	key, _ := hex.DecodeString( "f368616e676520746869732070617373" )	// len = 32
+
 	if *decr != "" {
+		f, err := os.Open( *decr ); if err != nil {
+			log.Fatal( err )
+		}
+		defer f.Close()
+
+		ciphertext, err := ioutil.ReadAll( f )
+		if err != nil {
+			log.Fatal( err )
+		}
+
+		block, err := aes.NewCipher( key )
+		if err != nil {
+			panic( err )
+		}
+
+		iv := ciphertext[ :aes.BlockSize ]
+		plaintext := make( []byte, len( ciphertext ) - aes.BlockSize )
+		stream := cipher.NewCTR( block, iv )
+		stream.XORKeyStream( plaintext, ciphertext[ aes.BlockSize: ] )
+
+		fmt.Printf( "%s", plaintext )
+		os.Exit( 0 )
 	}
 
+
 	if *encr != "" {
+		f, err := os.Open( *encr ); if err != nil {
+			log.Fatal( err )
+		}
+		defer f.Close()
+
+		plaintext, err := ioutil.ReadAll( f )
+		if err != nil {
+			log.Fatal( err )
+		}
+
+		block, err := aes.NewCipher( key )
+		if err != nil {
+			panic( err )
+		}
+
+		// IV 縺ッ蜈ャ髢九@縺ヲ繧ゅ>縺縺ョ縺ァ蜈磯ュ縺ォ縺、縺代※縺翫¥
+		ciphertext := make( []byte, aes.BlockSize + len( plaintext ) )
+		iv := ciphertext[ :aes.BlockSize ]
+		if _, err := io.ReadFull( rand.Reader, iv ); err != nil {
+			panic( err )
+		}
+
+		stream := cipher.NewCTR( block, iv )
+		stream.XORKeyStream( ciphertext[ aes.BlockSize: ], plaintext )
+
+		fmt.Printf( "%x", ciphertext )
+		os.Exit( 0 )
 	}
 
-	if *chdb != "" && *chhs != "" {
+	if *ghhs != "" {
 	}
 
 	fmt.Fprintf( os.Stderr, "bad argument\n" )
@@ -71,7 +169,3 @@
 	return fmt.Sprintf( "%x", h.Sum( nil ) )
 }
 
-func encrypt( text string ) []byte {
-	return nil
-}
-
--- a/go/server.go	Tue Oct 02 21:20:05 2018 +0900
+++ b/go/server.go	Thu Oct 11 22:11:09 2018 +0900
@@ -1,7 +1,7 @@
 /*
  server.go  : server-program.
  Version    : 1.0
- Last Change: 2018-10-01 Mon 22:58:23.
+ Last Change: 2018-10-03 豌エ 10:22:04.
 
  install to: server_root/
 
@@ -20,14 +20,21 @@
 	"net"
     "net/http"
 	"os"
+	"time"
 )
 
+var server string
+var port   string
+var server_root string
+
+func init() {
+	port = ":3910"
+    server_root = filepath.Dir( os.Args[0] )
+}
+
 func main() {
 
-	var server string
-    var port = ":3910"
-    var server_root = filepath.Dir (os.Args[0] )
-
+	// setting IP-Address & Port
 	addrs, err := net.InterfaceAddrs()
 	if err != nil {
 		log.Fatal( err )
@@ -40,18 +47,20 @@
 		}
 	}
 
+	// start Web-server
 	fmt.Println( "server start [", server, "]" )
-	http.HandleFunc( "/", func( w http.ResponseWriter, r *http.Request ) {
-        file := filepath.Join( server_root, filepath.FromSlash( r.URL.Path ) )
-        fmt.Println( file )
-        f, err := os.Open( file )
-        if err != nil {
-            http.NotFound( w, r )
-            return
-        }
-        defer f.Close()
-        io.Copy( w, f )
-    } )
+	http.HandleFunc( "/", handler )
 	log.Fatal( http.ListenAndServe( server, nil ) )
 }
 
+func handler( w http.ResponseWriter, r *http.Request ) {
+	file := filepath.Join( server_root, filepath.FromSlash( r.URL.Path ) )
+	fmt.Println( "[access]", r.RemoteAddr, "|", time.Now().Format( "2006-01-02 15:04" ), "|", file )
+	f, err := os.Open( file )
+	if err != nil {
+		http.NotFound( w, r )
+		return
+	}
+	defer f.Close()
+	io.Copy( w, f )
+}
--- a/include/auth.h	Tue Oct 02 21:20:05 2018 +0900
+++ b/include/auth.h	Thu Oct 11 22:11:09 2018 +0900
@@ -1,5 +1,5 @@
 // Filename   : auth.h
-// Last Change: 2018-10-01 Mon 23:08:10.
+// Last Change: 2018-10-11 木 16:23:21.
 //
 
 #ifndef __AUTH_H__
@@ -9,9 +9,11 @@
 #include <wx/font.h>
 #include <wx/colour.h>
 #include <wx/settings.h>
+#include <wx/button.h>
 #include <wx/textctrl.h>
 #include <wx/sizer.h>
 #include <wx/stattext.h>
+#include <wx/textfile.h>
 #include <wx/dialog.h>
 #include <wx/msgdlg.h> 
 
@@ -19,7 +21,10 @@
 {
     DECLARE_EVENT_TABLE()
 	private:
-        wxArrayString users;
+		bool		  m_load = false;
+		wxString      m_server;
+		wxString	  m_user;
+        wxArrayString m_users;
 	
 	protected:
 		enum {
@@ -33,17 +38,23 @@
 		wxStaticText* m_staticTextPw;
 		wxTextCtrl*   m_textCtrlPw;
 		wxStaticText* m_staticTextPwmsg;
+		wxButton*     m_buttonLogin;
+		wxButton*     m_buttonCancel;
 	
 	public:
 		AuthDialog( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, long style = wxDEFAULT_DIALOG_STYLE ); 
 		~AuthDialog();
-        void OnKey( wxKeyEvent& event );
+
+		void SetServer( wxString server ) { m_server = server; };
+        void CreateControls( void );
+		bool IsValidUser( void );
+		wxString GetUser( void ) { return m_user; };
+        void InDevelop( bool ); 
+
+		void OnShow( wxShowEvent& event );
+        void OnEnter( wxCommandEvent& event );
         void OnCheckUserID( wxCommandEvent& event );
         void OnCheckPassword( wxCommandEvent& event );
-        void OnEnter( wxCommandEvent& event );
-        void CreateControls( void );
-        void LoadUserID( void );
-        void InDevelop( bool ); 
 };
 
 #endif //__AUTH_H__
--- a/include/main.h	Tue Oct 02 21:20:05 2018 +0900
+++ b/include/main.h	Thu Oct 11 22:11:09 2018 +0900
@@ -1,9 +1,10 @@
 // Filename   : main.h
-// Last Change: 2018-10-02 Tue 21:17:28.
+// Last Change: 2018-10-03 水 18:11:51.
 //
 #include <wx/wx.h>
 #include <wx/config.h>
 #include <wx/fileconf.h>
+#include <wx/splash.h>
 
 enum {
 	ID_MAIN = wxID_HIGHEST + 1,
@@ -31,7 +32,6 @@
 
 		void InitSetting();
 		void SaveSetting();
-        void GetData();
 };
 
 DECLARE_APP( MyApp )
--- a/include/rsearcher.h	Tue Oct 02 21:20:05 2018 +0900
+++ b/include/rsearcher.h	Thu Oct 11 22:11:09 2018 +0900
@@ -1,5 +1,5 @@
 // Filename   : rsearcher.h
-// Last Change: 2018-10-02 Tue 19:36:21.
+// Last Change: 2018-10-11 木 18:29:13.
 //
 
 #ifndef __RSEARCH_H__
@@ -25,7 +25,10 @@
 #include <wx/msgdlg.h> 
 #include <wx/filefn.h> 
 #include <wx/regex.h>
+#include <wx/progdlg.h>
+#include <wx/utils.h> 
 #include <wx/textfile.h>
+#include <wx/timer.h>
 
 class MySearchCtrl : public wxSearchCtrl
 {
@@ -40,7 +43,8 @@
 class MyStaticBitmap : public wxStaticBitmap
 {
 	private:
-        int m_dragx, m_dragy;
+        int m_dragx, m_dragy;	// for image drag
+		int cx, cy;             // for mouse-gesture
         int m_zoom = 0;
         wxBitmap m_bmp[5];
 		wxScrolledWindow* m_parent;
@@ -51,6 +55,8 @@
 
         void OnLeftDown( wxMouseEvent& event );
         void OnLeftUp( wxMouseEvent& event );
+		void OnStartRGesture( wxMouseEvent& event );
+		void OnEndRGesture( wxMouseEvent& event );
         void OnMotion( wxMouseEvent& event );
         void OnWheel( wxMouseEvent& event );
         void SetImage( int i, wxBitmap bmp ) { m_bmp[i] = bmp; };
@@ -64,7 +70,9 @@
 		bool		  startup = true;
 		wxString	  m_server;
 		wxString	  m_hhs;
+		wxString	  m_user;
 		wxArrayString m_index;
+		wxTimer       m_timer;
 	
 	protected:
 		enum {
@@ -72,7 +80,8 @@
 			ID_LIST,
 			ID_NBOOK,
 			ID_SLDR,
-			ID_PRINT,
+			ID_TIMER,
+			ID_LOGOUT,
             ID_TEST,
 		};
 		
@@ -100,27 +109,34 @@
 		wxTextCtrl* 		m_textCtrlLog;
 		wxSlider*           m_slider;
 		wxButton*           m_buttonPrint;
+		wxButton*           m_buttonLogout;
 		wxButton*           m_buttonTest;
 	
 	public:
 		MainFrame( wxWindow* parent, wxWindowID id = wxID_ANY, const wxString& title = wxT( "Searcher Remote" ), const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( 500,300 ), long style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
 		~MainFrame();
+
 		void SetServer( wxString server ) { m_server = server; };
+		void SetUser( wxString user ) { m_user = user; };
 		void CreateControls( void );
 		void Cmd( wxString cmd );
 		void Search( void );
-		void LoadIndex( void );
+		void LoadDB( void );
         void LoadBitmap( wxScrolledWindow* sc, wxStaticBitmap* sb, wxString file );
         void LoadBitmaps( wxString date );
         void GetImages( wxString hhs, wxString date );
+		void PrintImages( void );
 		void RemoveFile( wxString pattern );
-		void SaveConfig( wxCloseEvent& event );
         void InDevelop( bool );
 
 		void OnItemSelected( wxDataViewEvent& event );
 		void OnItemDClicked( wxDataViewEvent& event );
         void OnNBookChanged( wxBookCtrlEvent& event );
-		//void OnIdle( wxIdleEvent& event );
+        void OnPrint( wxCommandEvent& event );
+		void OnClose( wxCloseEvent& event );	// save config
+		void OnIdle( wxIdleEvent& event );
+		void OnTimer( wxTimerEvent& event );
+        void OnLogout( wxCommandEvent& event );
         void OnTestButton( wxCommandEvent& event );
 };
 
--- a/src/auth.cpp	Tue Oct 02 21:20:05 2018 +0900
+++ b/src/auth.cpp	Thu Oct 11 22:11:09 2018 +0900
@@ -1,5 +1,5 @@
 // Filename   : auth.cpp
-// Last Change: 2018-10-01 Mon 23:15:27.
+// Last Change: 2018-10-11 譛ィ 16:47:30.
 //
 
 #include "auth.h"
@@ -8,7 +8,6 @@
     : wxDialog( parent, id, title, pos, size, style )
 {
     CreateControls();
-    LoadUserID();
 }
 
 AuthDialog::~AuthDialog()
@@ -17,31 +16,58 @@
 
 // Event Table
 BEGIN_EVENT_TABLE( AuthDialog, wxDialog )
+	EVT_SHOW( AuthDialog::OnShow )
     EVT_TEXT( ID_UID, AuthDialog::OnCheckUserID )
     EVT_TEXT( ID_PW,  AuthDialog::OnCheckPassword )
     EVT_TEXT_ENTER( ID_UID, AuthDialog::OnEnter )
     EVT_TEXT_ENTER( ID_PW,  AuthDialog::OnEnter )
+	EVT_BUTTON( wxID_OK,    AuthDialog::OnEnter )
 END_EVENT_TABLE()
 
 // Event Handler
+void AuthDialog::OnShow( wxShowEvent& WXUNUSED(event) )
+{
+	if ( m_load ) return;
+	wxArrayString args;	// http get ( auth.db, hhs.db, index.db )
+	args.Add( wxT( "client.exe" ) );
+	args.Add( wxT( "-u" ) );
+	args.Add( m_server );
+
+	wxExecute( wxJoin( args, ' ', '\\' ), wxEXEC_SYNC|wxEXEC_HIDE_CONSOLE );
+
+	wxTextFile file;
+	file.Open( wxT( "auth.db" ) );
+	for ( int i = 0; i < file.GetLineCount(); i++ ) {
+		wxArrayString line = wxSplit( file.GetLine( i ), ' ', '\\' );
+		m_users.Add( line[ 0 ] );
+	}
+	file.Close();
+	
+	m_load = true;
+}
+
 void AuthDialog::OnCheckUserID( wxCommandEvent& WXUNUSED(event) )
 {
     wxString id = m_textCtrlId->GetValue();
-    if ( 1 ) {
-        m_staticTextIdmsg->SetLabel( "ok" );
-        m_staticTextPwmsg->SetLabel( wxT("竊 input") );
-    }
-    else {
-        m_staticTextIdmsg->SetLabel( wxT("竊 input") );
-        m_staticTextIdmsg->SetLabel( wxEmptyString );
-    }
+	for ( int i = 0; i < m_users.GetCount(); i++ ) {
+		if ( id.IsSameAs( m_users[ i ], true ) ) {
+			m_staticTextIdmsg->SetLabel( wxT( "ok" ) );
+			m_staticTextPwmsg->SetLabel( wxT( "竊 input" ) );
+			m_textCtrlPw->SetValue( wxEmptyString );
+			m_textCtrlPw->SetFocus();
+			return;
+		} else {
+			m_staticTextIdmsg->SetLabel( wxT( "竊 input" ) );
+			m_staticTextPwmsg->SetLabel( wxEmptyString );
+		}
+	}
 }
 
 void AuthDialog::OnCheckPassword( wxCommandEvent& WXUNUSED(event) )
 {
     wxString pw = m_textCtrlPw->GetValue();
     if ( pw.Len() < 4 ) {
-        m_staticTextPwmsg->SetLabel( wxT("竊 too short") );
+        m_staticTextPwmsg->SetLabel( wxT( "竊 too short" ) );
     }
     else {
         m_staticTextPwmsg->SetLabel( wxEmptyString );
@@ -50,24 +76,17 @@
 
 void AuthDialog::OnEnter( wxCommandEvent& WXUNUSED(event) )
 {
-    Close();
+	m_staticTextPwmsg->SetLabel( wxEmptyString );
+	if ( IsValidUser() ) {
+		m_user = m_textCtrlId->GetValue();
+		EndModal( wxID_OK );
+	}
+	m_staticTextPwmsg->SetLabel( wxT( "Bad User/Password !!" ) );
+	m_textCtrlPw->SelectAll();
+	return;
 }
 
 // Functions
-void AuthDialog::LoadUserID( void )
-{
-    // 繝輔ぃ繧、繝ォ縺九i UserID 繧定ェュ縺ソ霎シ繧
-}
-
-void AuthDialog::InDevelop( bool flag )
-{
-    if ( !flag ) return;
-    SetTitle( "now on test" );
-    m_textCtrlId->SetValue( "test" );
-    m_textCtrlPw->SetValue( "test" );
-    m_textCtrlPw->SetFocus();
-}
-
 void AuthDialog::CreateControls( void )
 {
     this->SetIcon( wxIcon( wxT( "sample" ) ) );
@@ -77,7 +96,7 @@
 	wxGridSizer* gSizer = new wxGridSizer( 0, 3, 0, 0 );
 	
     // user id
-	m_staticTextId = new wxStaticText( this, wxID_ANY, wxT("User ID"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticTextId = new wxStaticText( this, wxID_ANY, wxT( "User ID" ), wxDefaultPosition, wxDefaultSize, 0 );
 	gSizer->Add( m_staticTextId, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT, 5 );
 	
 	m_textCtrlId = new wxTextCtrl( this, ID_UID, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PROCESS_ENTER );
@@ -88,7 +107,7 @@
 	gSizer->Add( m_staticTextIdmsg, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
 	
     // password
-	m_staticTextPw = new wxStaticText( this, wxID_ANY, wxT("Password"), wxDefaultPosition, wxDefaultSize, 0 );
+	m_staticTextPw = new wxStaticText( this, wxID_ANY, wxT( "Password" ), wxDefaultPosition, wxDefaultSize, 0 );
 	gSizer->Add( m_staticTextPw, 0, wxALL|wxALIGN_CENTER_VERTICAL|wxALIGN_RIGHT, 5 );
 	
 	m_textCtrlPw = new wxTextCtrl( this, ID_PW, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_PASSWORD|wxTE_PROCESS_ENTER );
@@ -97,11 +116,50 @@
 	m_staticTextPwmsg = new wxStaticText( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, 0 );
 	m_staticTextPwmsg->SetForegroundColour( wxColour( 250, 0, 0 ) );
 	gSizer->Add( m_staticTextPwmsg, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+
+	// buttons
+	gSizer->AddSpacer( 1 );
+
+	m_buttonLogin = new wxButton( this, wxID_OK, wxT( "Login" ), wxDefaultPosition, wxDefaultSize, 0 );
+	gSizer->Add( m_buttonLogin, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+	
+	m_buttonCancel = new wxButton( this, wxID_CANCEL, wxT( "Cancel" ), wxDefaultPosition, wxDefaultSize, 0 );
+	gSizer->Add( m_buttonCancel, 0, wxALL|wxALIGN_CENTER_VERTICAL, 5 );
+	
 	
 	this->SetSizer( gSizer );
 	this->Layout();
 	gSizer->Fit( this );
 	
 	this->Centre( wxBOTH );
+    m_textCtrlId->SetFocus();
 }
 
+bool AuthDialog::IsValidUser( void )
+{
+	wxString id = m_textCtrlId->GetValue();
+	wxString pw = m_textCtrlPw->GetValue();
+
+	wxArrayString args;
+	args.Add( wxT( "crypto.exe" ) );
+	args.Add( wxT( "-c" ) );
+	args.Add( wxT( "auth.db" ) );
+	args.Add( wxT( "-s" ) );
+	args.Add( wxT( "@#!;" ) );	// salt
+	args.Add( id );
+	args.Add( pw );
+
+	int ret = wxExecute( wxJoin( args, ' ', '\\' ), wxEXEC_SYNC|wxEXEC_HIDE_CONSOLE );
+	if ( ret == 39 ) return true;
+
+	return false;
+}
+
+void AuthDialog::InDevelop( bool flag )
+{
+    if ( !flag ) return;
+    m_textCtrlId->SetValue( "test" );
+    m_textCtrlPw->SetValue( "test" );
+    m_textCtrlPw->SetFocus();
+}
+
--- a/src/main.cpp	Tue Oct 02 21:20:05 2018 +0900
+++ b/src/main.cpp	Thu Oct 11 22:11:09 2018 +0900
@@ -1,5 +1,5 @@
 // Filename   : main.cpp
-// Last Change: 2018-10-02 Tue 21:00:32.
+// Last Change: 2018-10-11 譛ィ 16:52:40.
 //
 #include "main.h"
 #include "auth.h"
@@ -24,9 +24,15 @@
     wxImage::AddHandler( new wxJPEGHandler );
     wxImage::AddHandler( new wxPNGHandler  );
 	InitSetting();
-    GetData();
 
-    AuthDialog *authdlg = new AuthDialog( NULL, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize );
+	wxBitmap bmp;
+	if ( bmp.LoadFile( "./image/startup.png", wxBITMAP_TYPE_PNG ) ){
+		wxSplashScreen* splash = new wxSplashScreen( bmp, wxSPLASH_CENTRE_ON_SCREEN|wxSPLASH_TIMEOUT, 4000, NULL, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE|wxSTAY_ON_TOP );
+	}
+
+    AuthDialog *authdlg = new AuthDialog( NULL, wxID_ANY, wxT( "Check User" ), wxDefaultPosition, wxDefaultSize, wxCAPTION );
+	authdlg->SetServer( m_server );
+
     MainFrame *mainframe = new MainFrame( NULL, ID_MAIN, wxT( "Re:Searcher" ), wxPoint( rect.x, rect.y ), rect.GetSize(), wxDEFAULT_FRAME_STYLE );
 	mainframe->SetServer( m_server );
 
@@ -35,10 +41,13 @@
         mainframe->InDevelop( true );
     }
 
-    authdlg->ShowModal();
-    authdlg->Destroy();
-
-    mainframe->Show( true );
+    if ( authdlg->ShowModal() == wxID_OK ) {
+		mainframe->SetUser( authdlg->GetUser() );
+		mainframe->Show( true );
+	} else {
+		mainframe->Destroy();
+	}
+	authdlg->Destroy();
 
     return true;
 }
@@ -60,11 +69,13 @@
     config->Read( wxT( "w" ), &rect.width );
     config->Read( wxT( "h" ), &rect.height );
 
+	wxString proxy;
     config->SetPath( wxT( "/Server" ) );
     config->Read( wxT( "server" ), &m_server );
-    config->Read( wxT( "proxy" ),  &m_server );
+    config->Read( wxT( "proxy" ), &proxy );
     delete config;
 
+    if ( !proxy.IsSameAs( wxEmptyString, false ) ) m_server = proxy;
 	//m_server = wxT( "192.168.79.124:80" );
     if ( m_server.IsSameAs( wxEmptyString, false ) ) 
         m_server = wxT( "192.168.21.151:80" );	// nginx
@@ -72,29 +83,13 @@
 
 void MyApp::SaveSetting()
 {
-    config = new wxFileConfig( wxT("MyApp"), wxT("T.Mutoh"), conf_file, wxEmptyString, wxCONFIG_USE_LOCAL_FILE );
+    config = new wxFileConfig( wxT( "MyApp" ), wxT( "T.Mutoh" ), conf_file, wxEmptyString, wxCONFIG_USE_LOCAL_FILE );
 
-    config->SetPath( wxT("/Geometry") );
-    config->Write( wxT("x"), rect.x );
-    config->Write( wxT("y"), rect.y );
-    config->Write( wxT("w"), rect.width );
-    config->Write( wxT("h"), rect.height );
+    config->SetPath( wxT( "/Geometry" ) );
+    config->Write( wxT( "x" ), rect.x );
+    config->Write( wxT( "y" ), rect.y );
+    config->Write( wxT( "w" ), rect.width );
+    config->Write( wxT( "h" ), rect.height );
     delete config;
 }
 
-void MyApp::GetData()
-{
-	/*
-    // Go 縺ョ繝励Ο繧ー繝ゥ繝繧定オキ蜍輔@シ梧囓蜿キ蛹悶&縺 auth, hhs, index 繝繝シ繧ソ繧貞叙蠕
-	wxArrayString output, errors;
-	wxString cmd = wxT( "./client.exe -u " ) + m_server;
-	wxExecute( cmd, output, errors, wxEXEC_SYNC, NULL ); // ok
-	*/
-	wxArrayString args;	// http get
-	args.Add( wxT( "client.exe -u" ) );
-	args.Add( m_server );
-
-	//wxMessageBox( wxJoin( args, ' ', '\\' ) );
-	wxExecute( wxJoin( args, ' ', '\\' ), wxEXEC_ASYNC|wxEXEC_HIDE_CONSOLE );
-}
-
--- a/src/rsearcher.cpp	Tue Oct 02 21:20:05 2018 +0900
+++ b/src/rsearcher.cpp	Thu Oct 11 22:11:09 2018 +0900
@@ -1,8 +1,9 @@
 // Filename   : rsearcher.cpp
-// Last Change: 2018-10-02 Tue 19:43:14.
+// Last Change: 2018-10-11 木 18:28:07.
 //
 
 #include <wx/arrstr.h> 
+#include <wx/html/htmprint.h>
 #include "rsearcher.h"
 #include "main.h"
 
@@ -74,18 +75,25 @@
     : wxStaticBitmap( parent, id, label, pos, size, style, name )
 {
 	m_parent = parent;
-    Connect( wxEVT_LEFT_DOWN,  wxMouseEventHandler( MyStaticBitmap::OnLeftDown ), NULL, this );
-    Connect( wxEVT_LEFT_UP,    wxMouseEventHandler( MyStaticBitmap::OnLeftUp   ), NULL, this );
-    Connect( wxEVT_MOTION,     wxMouseEventHandler( MyStaticBitmap::OnMotion   ), NULL, this );
-    Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( MyStaticBitmap::OnWheel    ), NULL, this );
+    Connect( wxEVT_LEFT_DOWN,  wxMouseEventHandler( OnLeftDown ), NULL, this );
+    Connect( wxEVT_LEFT_UP,    wxMouseEventHandler( OnLeftUp   ), NULL, this );
+    Connect( wxEVT_MOTION,     wxMouseEventHandler( OnMotion   ), NULL, this );
+    Connect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( OnWheel    ), NULL, this );
+
+    Connect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( OnStartRGesture ), NULL, this );
+    Connect( wxEVT_RIGHT_UP,   wxMouseEventHandler( OnEndRGesture   ), NULL, this );
 }
 
 MyStaticBitmap::~MyStaticBitmap()
 {
-    Disconnect( wxEVT_LEFT_DOWN,  wxMouseEventHandler( MyStaticBitmap::OnLeftDown ), NULL, this );
-    Disconnect( wxEVT_LEFT_UP,    wxMouseEventHandler( MyStaticBitmap::OnLeftUp   ), NULL, this );
-    Disconnect( wxEVT_MOTION,     wxMouseEventHandler( MyStaticBitmap::OnMotion   ), NULL, this );
-    Disconnect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( MyStaticBitmap::OnWheel    ), NULL, this );
+    Disconnect( wxEVT_LEFT_DOWN,  wxMouseEventHandler( OnLeftDown ), NULL, this );
+    Disconnect( wxEVT_LEFT_UP,    wxMouseEventHandler( OnLeftUp   ), NULL, this );
+    Disconnect( wxEVT_MOTION,     wxMouseEventHandler( OnMotion   ), NULL, this );
+    Disconnect( wxEVT_MOUSEWHEEL, wxMouseEventHandler( OnWheel    ), NULL, this );
+
+    Disconnect( wxEVT_RIGHT_DOWN, wxMouseEventHandler( OnStartRGesture ), NULL, this );
+    Disconnect( wxEVT_RIGHT_UP,   wxMouseEventHandler( OnEndRGesture   ), NULL, this );
+
 }
 
 // Event Handlers
@@ -138,6 +146,38 @@
     }
 }
 
+/* right-gesture: start detect */
+void MyStaticBitmap::OnStartRGesture( wxMouseEvent& event )
+{
+    event.GetPosition( &cx, &cy );
+}
+
+/* right-gesture: judge */
+void MyStaticBitmap::OnEndRGesture( wxMouseEvent& event )
+{
+    int x, y;
+    event.GetPosition( &x, &y );
+
+    int dx = x - cx;
+    int dy = y - cy;
+    float rad = fabs( atan2( dy, dx ) );
+    float pi = 3.14159;
+
+    // to right
+    if ( rad < pi/8 && dx > 0 ) {
+		wxMessageBox("right");
+    }
+    // to left
+    else if ( rad > pi/8*7 && rad < pi && dx < 0 ) { 
+		wxMessageBox("left");
+    }
+    // to up-right
+    else if ( rad > pi/8 && rad < pi/8*3 && dx > 0 ) {
+		wxMessageBox("right-up");
+        //Close();
+    }
+}
+
 // Functions
 
 /********************/
@@ -146,8 +186,10 @@
 MainFrame::MainFrame( wxWindow* parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long style ) 
 	: wxFrame( parent, id, title, pos, size, style )
 {
-	LoadIndex();
 	CreateControls();
+	LoadDB();
+    LoadBitmaps( wxEmptyString );
+	m_timer.SetOwner( this, ID_TIMER );
 }
 
 MainFrame::~MainFrame()
@@ -162,9 +204,12 @@
     EVT_DATAVIEW_SELECTION_CHANGED( ID_LIST, MainFrame::OnItemSelected )
     EVT_DATAVIEW_ITEM_ACTIVATED( ID_LIST, MainFrame::OnItemDClicked )
     EVT_NOTEBOOK_PAGE_CHANGED( ID_NBOOK, MainFrame::OnNBookChanged )
+	EVT_BUTTON( wxID_PRINT, MainFrame::OnPrint )
+	EVT_BUTTON( ID_LOGOUT, MainFrame::OnLogout )
 	EVT_BUTTON( ID_TEST, MainFrame::OnTestButton )
-	EVT_CLOSE( MainFrame::SaveConfig )
-    //EVT_IDLE( MainFrame::OnIdle )
+	EVT_CLOSE( MainFrame::OnClose )
+    EVT_IDLE( MainFrame::OnIdle )
+    EVT_TIMER( ID_TIMER, MainFrame::OnTimer )
 END_EVENT_TABLE()
 
 
@@ -173,19 +218,27 @@
 {
     int r = m_dataViewListCtrl->GetSelectedRow();
     wxString ready = m_dataViewListCtrl->GetTextValue( r, 2 );
-	if ( ready.IsSameAs( wxT( "ok" ), true ) ) {
-		wxString buf = m_dataViewListCtrl->GetTextValue( r, 1 );
-		LoadBitmaps( wxT( "00000000" ) );
+	if ( ready.IsSameAs( wxT( "OK" ), true ) ) {
+		wxString date = m_dataViewListCtrl->GetTextValue( r, 1 );
+		date.Replace( wxT( "-" ), wxEmptyString, true );
+		LoadBitmaps( date );
+	} else {
+		LoadBitmaps( wxEmptyString );
 	}
 }
 
 void MainFrame::OnItemDClicked( wxDataViewEvent& WXUNUSED(event) )
 {
     int r = m_dataViewListCtrl->GetSelectedRow();
+	wxString status = m_dataViewListCtrl->GetTextValue( r, 2 );
+	if ( status.IsSameAs( wxT( "OK" ), true ) )	return;
+
     wxString date = m_dataViewListCtrl->GetTextValue( r, 1 );
 	date.Replace( wxT( "-" ), wxEmptyString, true );
 	GetImages( m_hhs, date );
-	LoadBitmaps( wxT( "00000000" ) );
+	LoadBitmaps( date );
+
+    m_dataViewListCtrl->SetTextValue( wxT( "OK" ), r, 2 );
 }
 
 void MainFrame::OnNBookChanged( wxBookCtrlEvent& WXUNUSED(event) )
@@ -196,14 +249,7 @@
     m_notebook->SetPageImage( m_notebook->GetSelection(), 0 );
 }
 
-/*
-void MainFrame::OnIdle( wxIdleEvent& WXUNUSED(event) )
-{
-}
-
-*/
-
-void MainFrame::SaveConfig( wxCloseEvent& WXUNUSED(event) )
+void MainFrame::OnClose( wxCloseEvent& WXUNUSED(event) )	// save config
 {
     if ( !IsIconized() && !IsMaximized() ) {
         wxGetApp().rect = this->GetRect();
@@ -211,11 +257,38 @@
     Destroy();
 }
 
+void MainFrame::OnPrint( wxCommandEvent& WXUNUSED(event) )
+{
+	PrintImages();
+}
+
+void MainFrame::OnLogout( wxCommandEvent& WXUNUSED(event) )
+{
+	wxMessageBox("logout");
+	return;
+}
+
 void MainFrame::OnTestButton( wxCommandEvent& WXUNUSED(event) )
 {
 	return;
 }
 
+
+void MainFrame::OnTimer( wxTimerEvent& WXUNUSED(event) )
+{
+	wxMessageBox( "timer !" );
+	// logout
+}
+
+void MainFrame::OnIdle( wxIdleEvent& event )
+{
+	if ( !m_timer.IsRunning() ) {
+        m_timer.Start( 300 * 1000, wxTIMER_ONE_SHOT );
+    }
+    event.RequestMore();
+    event.Skip();
+}
+
 // Functions
 void MainFrame::CreateControls( void )
 {
@@ -290,9 +363,12 @@
 	m_slider = new wxSlider( this, ID_SLDR, 1, 1, 5, wxDefaultPosition, wxSize( -1, 200 ), wxSL_AUTOTICKS|wxSL_INVERSE|wxSL_LABELS|wxSL_VERTICAL );
 	bSizerRight->Add( m_slider, 0, wxALL, 5 );
 	
-	m_buttonPrint = new wxButton( this, ID_PRINT, wxT( "Print" ), wxDefaultPosition, wxDefaultSize, 0 );
+	m_buttonPrint = new wxButton( this, wxID_PRINT, wxT( "Print" ), wxDefaultPosition, wxDefaultSize, 0 );
 	bSizerRight->Add( m_buttonPrint, 0, wxALL, 5 );
 	
+	m_buttonLogout = new wxButton( this, ID_LOGOUT, wxT( "Logout" ), wxDefaultPosition, wxDefaultSize, 0 );
+	bSizerRight->Add( m_buttonLogout, 0, wxALL, 5 );
+	
 	m_buttonTest = new wxButton( this, ID_TEST, wxT( "Test" ), wxDefaultPosition, wxDefaultSize, 0 );
 	bSizerRight->Add( m_buttonTest, 0, wxALL, 5 );
 	
@@ -325,13 +401,27 @@
 		return;
     }
 
-    if ( cmd.IsSameAs( wxT( "." ), true ) ) {
+    if ( cmd.IsSameAs( wxT( "k" ), true ) ) {
+		// hiragana kensaku
+        return;
+	}
+
+    if ( cmd.IsSameAs( wxT( "." ), false ) ) {
         wxString appdir = wxGetCwd();
         wxString execmd = wxT( "explorer " ) + appdir;
         wxExecute( execmd );
         return;
     }
 
+    if ( cmd.IsSameAs( wxT( "*" ), false ) ) {
+		// cmd = clipboard // paste clipboard
+	}
+
+    if ( cmd.IsSameAs( wxT( "+" ), false ) ) {
+		// print
+        return;
+	}
+
     wxRegEx reHhs( wxT( "^0[1238][0-9]{8}$" ) );
     if ( reHhs.Matches( cmd ) ) {
 		m_hhs = m_searchCtrl->GetValue();
@@ -339,7 +429,7 @@
 		return;
 	}
 
-	wxMessageBox( wxT( "Bad Input!!" ) );
+	wxMessageBox( wxT( "Bad Input !!" ) );
 }
 
 void MainFrame::LoadBitmap( wxScrolledWindow* sc, wxStaticBitmap* sb, wxString file )
@@ -357,7 +447,7 @@
     int ww, wh;
     sc->GetSize( &ww, &wh );
 
-    float w = ww - 50;
+    float w = ww - 30;
     float h = w * height / width;
     sb->SetBitmap( wxBitmap( img.Scale( w, h, wxIMAGE_QUALITY_HIGH ) ) );
     sc->SetScrollbars( 10, 10, w / 10, h / 10 );
@@ -387,7 +477,15 @@
 	args.Add( date );
 
 	//wxMessageBox( wxJoin( args, ' ', '\\' ) );
+	int estimate = 5;
+    wxProgressDialog pd( wxT( "Connecting Server" ), wxT( "Start..." ), estimate, NULL, wxPD_APP_MODAL|wxPD_ELAPSED_TIME|wxPD_REMAINING_TIME|wxPD_AUTO_HIDE );
+    pd.SetSize( wxSize( 320, 140 ) );
+	
 	wxExecute( wxJoin( args, ' ', '\\' ), wxEXEC_ASYNC|wxEXEC_HIDE_CONSOLE );
+	for ( int i = 0; i < estimate; i++ ) {
+		wxSleep( 1 );
+		pd.Update( i, wxT( "Now Loading..." ) );
+	}
 }
 
 void MainFrame::Search( void )
@@ -405,10 +503,10 @@
 			data.clear();
 		}
 	}
-	if ( match_cnt == 0 ) wxMessageBox( wxT( "Not Matched!!" ) );
+	if ( match_cnt == 0 ) wxMessageBox( wxT( "Not Matched !!" ) );
 }
 
-void MainFrame::LoadIndex( void )
+void MainFrame::LoadDB( void )
 {
 	wxTextFile file;
 	file.Open( wxT( "index.db" ) );
@@ -416,6 +514,50 @@
 		m_index.Add( file.GetLine( i ) );
 	file.Close();
 	m_index.Sort( true );
+
+	/*
+	file.Open( wxT( "hhs.db" ) );
+	for ( int i = 0; i < file.GetLineCount(); i++ ) {
+	//
+	}
+	file.Close();
+	*/
+}
+
+void MainFrame::PrintImages( void )
+{
+    int r = m_dataViewListCtrl->GetSelectedRow();
+    wxString ready = m_dataViewListCtrl->GetTextValue( r, 2 );
+
+	if ( !ready.IsSameAs( wxT( "OK" ), true ) ) {
+		wxMessageBox( wxT( "Not Ready for Print !!" ) );
+		return;
+	}
+
+	wxDateTime now = wxDateTime::Now();
+	wxString nowstr = now.Format( "%Y/%m/%d %H:%M", wxDateTime::GMT9 ).c_str();
+
+	wxString date = m_dataViewListCtrl->GetTextValue( r, 1 );
+	date.Replace( wxT( "-" ), wxEmptyString, true );
+
+	wxString html, file;
+	html = wxT( "<html><body>\n" );
+
+	for ( int i = 1; i < 6; i++ ) {
+		file = wxString::Format( wxT( ".cache/%08s_%d" ), date, i );
+		html = html + wxT( "<img src=\"" ) + file + wxT( "\" width=\"750\" height=\"1060\"/>\n" );
+		html = html + wxT( "<div align=right><font size=-2><u>" ) + m_hhs + wxT( "@" ) + m_user + wxT( "#" ) + nowstr + wxT( "</u></font></div>\n\n" );
+	}
+	html = html + wxT( "</body></html>" );
+
+	// start printing
+	wxHtmlPrintout hpout( wxT( "Re:Searcher" ) );
+	hpout.SetMargins( 0, 0, 0, 0, 0 );
+	wxPrintDialogData pd;
+	wxPrinter p( &pd );
+
+	hpout.SetHtmlText( html, wxEmptyString, false );
+	p.Print( NULL, &hpout, true );
 }
 
 void MainFrame::RemoveFile( wxString pattern )
@@ -430,21 +572,20 @@
 void MainFrame::InDevelop( bool flag )
 {
     if ( !flag ) return;
-    //LoadBitmaps( wxT( "00000000" ) );
-    LoadBitmaps( wxEmptyString );
     
-	m_slider->Enable( false );
-	m_slider->Show( false );
+	bool lo = false;
+	m_buttonLogout->Enable( lo );
+	m_buttonLogout->Show( lo );
 
-	bool pr = true;
-	m_buttonPrint->Enable( false );
-	m_buttonPrint->Show( true );
+	bool sl = false;
+	m_slider->Enable( sl );
+	m_slider->Show( sl );
 
-	bool tb = true;
+	bool tb = false;
 	m_buttonTest->Enable( tb );
 	m_buttonTest->Show( tb );
 
-	bool srch = true;
-	m_searchCtrl->Enable( srch );
+	// search
+	m_searchCtrl->SetValue( wxT( "0100122642" ) );
 }