2008年1月10日木曜日

PC⇔Linux をtclの ftpd(tcllib)で繋ぐ

普段、仕事ではWindowsからtelnetでlinux接続がメイン。
だけどやはりWindowsで文書は管理したいし、メールの添付ファイルは99%MS-Officeで書かれているから、Windows使わないと。
なにせ、telnet上ではscreen + mutt + fdclone + w3mでほとんど全てのことをやっているから、Windows不要的感覚に囚われてしまう。
で、 telnet先のlinux上でmutt使ってメール読んでると、「付いて来た添付ファイルが開けん」ので、Windows上で改めてメールボックス 開いて、pdfとか表示させるはめになる。これもなんかバカらしいというか、マウス使うのが億劫というか、なんとも「全部linux上で」と世間でよくあ るlinuxかっこいい・症候群に瞬間、ハマルわけ。
「な~んか良い方法はないものか」と、さらに深くlinux症候群へ

これま で何度となく、PCとlinux間をftpで繋ぐ方法を考えたような。良い方法はなかなか無いものです。かつてftpmount(だったかな)って のを見たとき「good idea!」、そう感じたのを思い出します。結局安定感がないやら、日本語無視だったりで使い物にならなかった。

だけど今でも諦めていません・・というわけで。PC⇔linux結合をば、また考えています。

[方針]

①PC上でftpdを走らせる
②telnet先のlinuxでftpクライアントを使う

ま あ当たり前の状況ですが、①のPC上のftpサーバでは、転送されてきたファイルをWindows上で実行してしまうという細工をすると良いことがある と考えます。通常のftpサーバは転送されてきたファイルを所望の場所へ保存する機能を持ちますが、実行出来そうなファイルは開いて欲しいと。

linux上のftpクライアントがhoge.pdfをputしてきたら、.pdfに関連図けられた実行コマンドを探し出して、(ここではAcrobat)それを実行してPC画面に表示するということ。

簡単に実現したい。
①TCLのTCLLIBにあるftpdとftpパッケージをいじって使用します。
②PCではActiveStateのTCLをインストール
③linuxではtcllib.sourceforge.netからtcllibをインストール

tclilib のftpdサーバ/ftpクライアント・サンプルスクリプトを多少改造したのが下記2つのスクリプトになります。PC上のftpdサーバ側 スクリプトをActiveTCLのwish.exeに食わせると、例では7777ポートが接続可能になります。telnet先からはftpクライアントプ ログラムへ表示したいファイルを指定してあげると、WindowsPC上の適切なプログラム(Exce,WordやAcrobatなどなど)が立ち上がり ftp転送されてきたファイルを表示します。後はWindowsPC上での作業の世界ですね。

[①PC側のftpdサーバスクリプト]

#! /bin/sh
# -*- tcl -*- \
exec wish "$0" ${1+"$@"}
# Custom FTP daemon to talk WindowsPC and Linux.

package require Tcl 8.3
package require ftpd
package require log

variable docRoot {c://Tcl/tmp}
variable store_path {}

proc ftplog {level text} {
if {[string equal $level note]} {set level notice}
log::log $level $text
}
proc noauth {args} {
return 1
}
proc fakefs {cmd path args} {
# Use the standard unix fs, i.e. "::ftpd::fsFile::fs",
# but rewrite the incoming path
# to stay in the /tmp directory.

variable docRoot
set path [file join $docRoot [file tail $path]]
variable store_path $path
eval [linsert $args 0 ::ftpd::fsFile::fs $cmd $path]
}
proc exapp {s s2 f b name e} {
variable store_path
if {$store_path!={}} {
regsub -all -- {/} $store_path {\\} store_path
.name configure -text "Filename:$store_path"
} else {
.name configure -text "Filename:nothing"
}
if {$store_path!={} && [set app [get_appli $store_path]]!={}} {
.ftype configure -text "HelperApplication:$app"
if {[regexp {(exefile|batfile)} $app]} {
exec $store_path
} else {
exec $app $store_path
}
} else {
.ftype configure -text "HelperApplication:unknown"
}
set store_path {}
return 1
}
proc get_appli {path} {
set type {}
if {[set extension [file extension [file tail $path]]]!={}} {
if {[regexp {\S+=(.+)} [exec cmd /C assoc $extension] all assoc]} {
.assoc configure -text " Assoc-Command:$assoc"
if {[regexp {exefile} $assoc]} {return $assoc}
if {[regexp {batfile} $assoc]} {return $assoc}
if {[regexp {\S+=(.+)} [exec cmd /C ftype $assoc] all ftype]} {
regsub -all {\"} $ftype {} type
regsub -all {\\} $type {/} type
regexp -nocase -- {(^.*.exe)} $type all type
}
}
}
return $type
}

::ftpd::config -authUsrCmd noauth -authFileCmd noauth -fsCmd fakefs -logCmd ftplog -xferDoneCmd exapp
set ::ftpd::welcome {Welcome HOMEPC FTPd}
set ::ftpd::port 7777 ; # Listen on user port
set ::ftpd::cwd $docRoot

::ftpd::server

button .b -command "exit" -text {<>}
label .name -text " Filename:nothing"
label .assoc -text " Assoc-Command:nothing"
label .ftype -text " HelperApplication:unknown"
pack .b .name .assoc .ftype -side top
wm iconify .
wm title . "PC<=>Linux"

[②linux側のftpクライアントスクリプト]

#!/usr/bin/tclsh
package require ftp

# SAMPLE convmv : proc euc-jp2sjis {euc} { return [set sjis [lindex [exec convmv -f euc-jp -t shiftjis $euc |& grep mv] end]] }
proc euc-jp2sjis {euc} { return [exec echo $euc | nkf -s] }
proc latest_file {dir} {
set latest {}
if {[catch {set files [glob ${dir}/*]}]} {puts "Directory empty :$dir";return {}}
foreach f [set files $files] { if {[file isfile $f]} {set mtime([file mtime $f]) $f }}
return [set latest $mtime([lindex [lsort -decreasing -integer [array names mtime]] 0])]
}

if {[llength $argv]>0} {
set ip $env(REMOTEHOST)
set port 7777
while {[regexp -- {(-port\s+(\d+)|-ip\s+(\d+[\d\.]+))} $argv a 1]} {
regsub -- ${a} $argv {} argv
set argv [string trim $argv]
}
set path [join $argv]
if {[file isdirectory $path]} {
if {[set path [latest_file $path]]=={}} { exit 0 }
}
if {[file isfile $path]} {
set euc_path $path
set sjis_path [euc-jp2sjis $euc_path]
puts "ip=$ip port=$port path=$euc_path"
if {$euc_path != $sjis_path} {
file rename $euc_path $sjis_path
}
set path $sjis_path
} else {
set start_bat /tmp/start.bat
puts "creating $start_bat about $path"
set sb [open $start_bat w]
puts $sb "@echo off"
puts $sb "start $path"
close $sb
set path $start_bat
}
if {[set srv [::ftp::Open $ip no no -port $port]]>=0} {
::ftp::Put $srv $path
::ftp::Close $srv
} else {
puts "FTPservice unavailable"
}
if {[info exists euc_path] && $euc_path != $sjis_path} {
file rename $sjis_path $euc_path
} else {
file delete $start_bat
}
exit 1
}

0 件のコメント: