[分享] 打造 Unicode 的環境

常言道:『飲水思源』,在 Open Source 的世界裡,我們常常需要別人的幫助,但是在您有所心得的時候請記得分享給大家,『幫助人是快樂的喔』。歡迎您在使用 debian 的過程中的任何心得分享給大家。

re:[分享] 打造 Unicode 的環境

文章d2207197 » 週二 1月 18, 2005 4:36 pm

beep-media-player 呢?
頭像
d2207197
鑽研的研究生
鑽研的研究生
 
文章: 1763
註冊時間: 週二 5月 27, 2003 9:57 pm
來自: 火星

Re: re:[分享] 打造 Unicode 的環境

文章twu2 » 週一 2月 21, 2005 12:45 pm

chinson 寫:剛測試了一下, SmarfFTP支援 Unicode 檔名 "顯示" ,但是 Unicode 中文目錄進不去,換成 big5 檔名就沒問題..... :w_40:


最近在測這個, 在 smartftp 中, transfer 的設定中, 把 default codepage 的設定由 auto 改成 utf8 就可以正常在 utf8 的中文目錄切換, 不過, 這樣子 big5 的就不行了.
twu2
懵懂的國中生
懵懂的國中生
 
文章: 219
註冊時間: 週二 3月 11, 2003 2:58 pm
來自: Taipei

Re: re:[分享] 打造 Unicode 的環境

文章twu2 » 週二 2月 22, 2005 12:52 pm

aadia 寫:ProFTPD - iconv() charset conversion patch

http://home.h01.itscom.net/para/softwar ... dex-e.html


不知道有沒有人使用這個 patch.
想問一下, 在使用這個 patch 之後, 如果 ftpd 的環境是 utf8, 是不是反而支援 utf8 的 client 連上之後, 看到的中文反而因為被轉成 big5 而變成亂碼?
twu2
懵懂的國中生
懵懂的國中生
 
文章: 219
註冊時間: 週二 3月 11, 2003 2:58 pm
來自: Taipei

vsftpd, UTF-8? Big5? 隨便你都可以...

文章twu2 » 週二 2月 22, 2005 4:52 pm

前幾天 "不小心" 把自己家裡的主機內的檔案名, 都改成 UTF-8 來處理, 在 samba 上頭是可以很正常的處理, 不過.... 發現在使用 ftp 時, 問題就不小了.

如果是支援 UTF-8 的 ftp client, 是可以正常運作, 如 gftp, smartftp....

不過, 在用了一天的 smartftp 之後, 實在發現和之前用 filezilla 的習慣大不相同, 用起來實在不習慣.

原本打算動手改 filezilla 的程式碼.... 只是, 在 windows 下頭, 似乎沒有 iconv 可以用... 又懶的去找 win32 可以用的函式... 所以, 就直接改 server 上的 vsftpd 來配合非 UTF-8 的 ftp client.

修改的構想主要來自 proftpd 的 iconv patch:
http://home.h01.itscom.net/para/softwar ... dex-e.html

我是修改 Debian 的 vsftpd 2.0.1 的版本.
patch 如下:

代碼: 選擇全部
diff -Nur vsftpd-2.0.1/features.c vsftpd-2.0.1.patched/features.c
--- vsftpd-2.0.1/features.c   2004-07-02 19:22:45.000000000 +0800
+++ vsftpd-2.0.1.patched/features.c   2005-02-22 12:21:56.000000000 +0800
@@ -25,6 +25,7 @@
   vsf_cmdio_write_raw(p_sess, " EPSV\r\n");
   vsf_cmdio_write_raw(p_sess, " MDTM\r\n");
   vsf_cmdio_write_raw(p_sess, " PASV\r\n");
+  vsf_cmdio_write_raw(p_sess, " ICNV\r\n");
   if (tunable_ssl_enable)
   {
     vsf_cmdio_write_raw(p_sess, " PBSZ\r\n");
diff -Nur vsftpd-2.0.1/ftpcmdio.c vsftpd-2.0.1.patched/ftpcmdio.c
--- vsftpd-2.0.1/ftpcmdio.c   2004-07-02 19:23:02.000000000 +0800
+++ vsftpd-2.0.1.patched/ftpcmdio.c   2005-02-22 11:48:44.000000000 +0800
@@ -7,6 +7,9 @@
  * Routines applicable to reading and writing the FTP command stream.
  */
 
+#include <stdlib.h>
+#include <string.h>
+#include "utility.h"
 #include "ftpcmdio.h"
 #include "ftpcodes.h"
 #include "str.h"
@@ -170,6 +173,16 @@
   control_getline(p_cmd_str, p_sess);
   str_split_char(p_cmd_str, p_arg_str, ' ');
   str_upper(p_cmd_str);
+  if (!str_isempty(p_arg_str)) {
+      char *tmp_str;
+
+      tmp_str = remote2local(str_getbuf(p_arg_str));
+      if (tmp_str != NULL) {
+     str_empty(p_arg_str);
+          str_append_text(p_arg_str, tmp_str);
+     vsf_sysutil_free(tmp_str);
+      }
+  }
   if (tunable_log_ftp_protocol)
   {
     static struct mystr s_log_str;
diff -Nur vsftpd-2.0.1/ls.c vsftpd-2.0.1.patched/ls.c
--- vsftpd-2.0.1/ls.c   2004-07-02 19:23:34.000000000 +0800
+++ vsftpd-2.0.1.patched/ls.c   2005-02-22 11:48:56.000000000 +0800
@@ -7,6 +7,9 @@
  * Would you believe, code to handle directory listing.
  */
 
+#include <stdlib.h>
+#include <string.h>
+#include "utility.h"
 #include "ls.h"
 #include "access.h"
 #include "str.h"
@@ -363,6 +366,7 @@
                const struct vsf_sysutil_statbuf* p_stat)
 {
   static struct mystr s_tmp_str;
+  char *tmp_filename;
   filesize_t size = vsf_sysutil_statbuf_get_size(p_stat);
   /* Permissions */
   str_alloc_text(p_str, vsf_sysutil_statbuf_get_perms(p_stat));
@@ -432,7 +436,13 @@
                                                       tunable_use_localtime));
   str_append_char(p_str, ' ');
   /* Filename */
-  str_append_str(p_str, p_filename_str);
+  tmp_filename = local2remote(str_getbuf(p_filename_str));
+  if (tmp_filename == NULL)
+    str_append_str(p_str, p_filename_str);
+  else {
+    str_append_text(p_str, tmp_filename);
+    vsf_sysutil_free(tmp_filename);
+  }
   str_append_text(p_str, "\r\n");
 }
 
diff -Nur vsftpd-2.0.1/parseconf.c vsftpd-2.0.1.patched/parseconf.c
--- vsftpd-2.0.1/parseconf.c   2004-07-02 19:23:56.000000000 +0800
+++ vsftpd-2.0.1.patched/parseconf.c   2005-02-22 11:49:12.000000000 +0800
@@ -94,6 +94,7 @@
   { "ssl_sslv3", &tunable_sslv3 },
   { "ssl_tlsv1", &tunable_tlsv1 },
   { "tilde_user_enable", &tunable_tilde_user_enable },
+  { "enable_iconv", &tunable_enable_iconv },
   { 0, 0 }
 };
 
@@ -158,6 +159,8 @@
   { "rsa_cert_file", &tunable_rsa_cert_file },
   { "dsa_cert_file", &tunable_dsa_cert_file },
   { "ssl_ciphers", &tunable_ssl_ciphers },
+  { "local_charset", &tunable_local_charset },
+  { "remote_charset", &tunable_remote_charset },
   { 0, 0 }
 };
 
diff -Nur vsftpd-2.0.1/postlogin.c vsftpd-2.0.1.patched/postlogin.c
--- vsftpd-2.0.1/postlogin.c   2004-07-02 19:24:01.000000000 +0800
+++ vsftpd-2.0.1.patched/postlogin.c   2005-02-22 15:54:14.000000000 +0800
@@ -5,6 +5,9 @@
  * postlogin.c
  */
 
+#include <stdlib.h>
+#include <string.h>
+#include "utility.h"
 #include "postlogin.h"
 #include "session.h"
 #include "oneprocess.h"
@@ -157,6 +160,29 @@
     {
       handle_pwd(p_sess);
     }
+    else if (str_equal_text(&p_sess->ftp_cmd_str, "ICNV"))
+    {
+      str_upper(&p_sess->ftp_arg_str);
+      if (str_equal_text(&p_sess->ftp_arg_str, "ON"))
+      {
+        tunable_enable_iconv = 1;
+        vsf_cmdio_write(p_sess, FTP_CWDOK, "enable iconv().");
+      }
+      else if (str_equal_text(&p_sess->ftp_arg_str, "OFF"))
+      {
+        tunable_enable_iconv = 0;
+        vsf_cmdio_write(p_sess, FTP_CWDOK, "disable iconv().");
+      }
+      else {
+        if (tunable_enable_iconv) {
+          vsf_cmdio_write(p_sess, FTP_CWDOK, "iconv() enabled.");
+        }
+        else
+        {
+          vsf_cmdio_write(p_sess, FTP_CWDOK, "iconv() disabled.");
+        }
+      }
+    }
     else if (str_equal_text(&p_sess->ftp_cmd_str, "CWD") ||
              str_equal_text(&p_sess->ftp_cmd_str, "XCWD"))
     {
@@ -404,6 +430,7 @@
 static void
 handle_pwd(struct vsf_session* p_sess)
 {
+  char *tmp_str;
   static struct mystr s_cwd_buf_mangle_str;
   static struct mystr s_pwd_res_str;
   str_getcwd(&s_cwd_buf_mangle_str);
@@ -411,7 +438,13 @@
   str_replace_text(&s_cwd_buf_mangle_str, "\"", "\"\"");
   /* Enclose pathname in quotes */
   str_alloc_text(&s_pwd_res_str, "\"");
-  str_append_str(&s_pwd_res_str, &s_cwd_buf_mangle_str);
+  tmp_str = local2remote(str_getbuf(&s_cwd_buf_mangle_str));
+  if (tmp_str == NULL)
+    str_append_str(&s_pwd_res_str, &s_cwd_buf_mangle_str);
+  else {
+    str_append_text(&s_pwd_res_str, tmp_str);
+    vsf_sysutil_free(tmp_str);
+  }
   str_append_text(&s_pwd_res_str, "\"");
   vsf_cmdio_write_str(p_sess, FTP_PWDOK, &s_pwd_res_str);
 }
@@ -435,6 +468,24 @@
   }
   else
   {
+    if (tunable_enable_iconv) {
+      char *tmp_str;
+
+      tmp_str = local2remote(str_getbuf(&p_sess->ftp_arg_str));
+      if (tmp_str != NULL) {
+        str_empty(&p_sess->ftp_arg_str);
+        str_append_text(&p_sess->ftp_arg_str, tmp_str);
+        vsf_sysutil_free(tmp_str);
+        retval = str_chdir(&p_sess->ftp_arg_str);
+        if (retval == 0)
+        {
+          /* Handle any messages */
+          vsf_banner_dir_changed(p_sess, FTP_CWDOK);
+          vsf_cmdio_write(p_sess, FTP_CWDOK, "Directory successfully changed.");
+     return;
+        }
+      }
+    }
     vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to change directory.");
   }
 }
@@ -640,8 +691,29 @@
   opened_file = str_open(&p_sess->ftp_arg_str, kVSFSysStrOpenReadOnly);
   if (vsf_sysutil_retval_is_error(opened_file))
   {
-    vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file.");
-    return;
+    if (tunable_enable_iconv) {
+      char *tmp_str;
+
+      tmp_str = local2remote(str_getbuf(&p_sess->ftp_arg_str));
+      if (tmp_str != NULL) {
+   str_empty(&p_sess->ftp_arg_str);
+   str_append_text(&p_sess->ftp_arg_str, tmp_str);
+   vsf_sysutil_free(tmp_str);
+   opened_file = str_open(&p_sess->ftp_arg_str, kVSFSysStrOpenReadOnly);
+   if (vsf_sysutil_retval_is_error(opened_file)) {
+          vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file.");
+          return;
+   }
+      }
+      else {
+        vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file.");
+        return;
+      }
+    }
+    else {
+      vsf_cmdio_write(p_sess, FTP_FILEFAIL, "Failed to open file.");
+      return;
+    }
   }
   vsf_sysutil_fstat(opened_file, &s_p_statbuf);
   /* No games please */
@@ -1623,7 +1695,7 @@
   vsf_cmdio_write_raw(p_sess,
 " RNTO SITE SIZE SMNT STAT STOR STOU STRU SYST TYPE USER XCUP XCWD XMKD\r\n");
   vsf_cmdio_write_raw(p_sess,
-" XPWD XRMD\r\n");
+" XPWD XRMD ICNV\r\n");
   vsf_cmdio_write(p_sess, FTP_HELP, "Help OK.");
 }
 
diff -Nur vsftpd-2.0.1/tunables.c vsftpd-2.0.1.patched/tunables.c
--- vsftpd-2.0.1/tunables.c   2004-07-02 19:26:17.000000000 +0800
+++ vsftpd-2.0.1.patched/tunables.c   2005-02-22 12:17:52.000000000 +0800
@@ -66,6 +66,7 @@
 int tunable_sslv3 = 0;
 int tunable_tlsv1 = 1;
 int tunable_tilde_user_enable = 0;
+int tunable_enable_iconv = 0;
 
 unsigned int tunable_accept_timeout = 60;
 unsigned int tunable_connect_timeout = 60;
@@ -115,4 +116,7 @@
 const char* tunable_rsa_cert_file = "/usr/share/ssl/certs/vsftpd.pem";
 const char* tunable_dsa_cert_file = 0;
 const char* tunable_ssl_ciphers = "DES-CBC3-SHA";
+const char* tunable_local_charset = "UTF-8";
+const char* tunable_remote_charset = "BIG5";
+
 
diff -Nur vsftpd-2.0.1/tunables.h vsftpd-2.0.1.patched/tunables.h
--- vsftpd-2.0.1/tunables.h   2004-06-29 07:08:31.000000000 +0800
+++ vsftpd-2.0.1.patched/tunables.h   2005-02-22 11:50:27.000000000 +0800
@@ -62,6 +62,7 @@
 extern int tunable_sslv3;                     /* Allow SSLv3 */
 extern int tunable_tlsv1;                     /* Allow TLSv1 */
 extern int tunable_tilde_user_enable;         /* Support e.g. ~chris */
+extern int tunable_enable_iconv;         /* Convert filename use iconv */
 
 /* Integer/numeric defines */
 extern unsigned int tunable_accept_timeout;
@@ -110,6 +111,8 @@
 extern const char* tunable_rsa_cert_file;
 extern const char* tunable_dsa_cert_file;
 extern const char* tunable_ssl_ciphers;
+extern const char* tunable_local_charset;
+extern const char* tunable_remote_charset;
 
 #endif /* VSF_TUNABLES_H */
 
diff -Nur vsftpd-2.0.1/utility.c vsftpd-2.0.1.patched/utility.c
--- vsftpd-2.0.1/utility.c   2004-07-02 19:26:30.000000000 +0800
+++ vsftpd-2.0.1.patched/utility.c   2005-02-22 14:05:46.000000000 +0800
@@ -5,6 +5,13 @@
  * utility.c
  */
 
+#include <stdarg.h>
+#include <iconv.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include "tunables.h"
 #include "utility.h"
 #include "sysutil.h"
 #include "str.h"
@@ -50,3 +57,71 @@
   vsf_sysutil_exit(0);
 }
 
+char *
+local2remote(const char *buf)
+{
+  char *in_ptr;
+  char *out_ptr;
+  size_t inbytesleft, outbytesleft;
+  char *p;
+  iconv_t ic;
+
+  if (tunable_enable_iconv == 0) return NULL;
+  ic = iconv_open(tunable_remote_charset, tunable_local_charset);
+  if (ic == (iconv_t)(-1)) return NULL;
+  iconv(ic, NULL, NULL, NULL, NULL);
+
+  inbytesleft = strlen(buf);
+  outbytesleft = inbytesleft * 6;
+  p = vsf_sysutil_malloc(outbytesleft+1);
+
+  in_ptr = buf;
+  out_ptr = p;
+  while (inbytesleft) {
+    if (iconv(ic, &in_ptr, &inbytesleft, &out_ptr, &outbytesleft) == (size_t)(-1)) {
+      iconv_close(ic);
+      vsf_sysutil_free(p);
+      return NULL;
+    }
+  }
+
+  *out_ptr = 0;
+
+  iconv_close(ic);
+  return p;
+}
+
+char *
+remote2local(const char *buf)
+{
+  char *in_ptr;
+  char *out_ptr;
+  size_t inbytesleft, outbytesleft;
+  char *p;
+  iconv_t ic;
+
+  if (tunable_enable_iconv == 0) return NULL;
+  ic = iconv_open(tunable_local_charset, tunable_remote_charset);
+  if (ic == (iconv_t)(-1)) return NULL;
+  iconv(ic, NULL, NULL, NULL, NULL);
+
+  inbytesleft = strlen(buf);
+  outbytesleft = inbytesleft * 6;
+  p = vsf_sysutil_malloc(outbytesleft+1);
+
+  in_ptr = buf;
+  out_ptr = p;
+  while (inbytesleft) {
+    if (iconv(ic, &in_ptr, &inbytesleft, &out_ptr, &outbytesleft) == (size_t)(-1)) {
+      iconv_close(ic);
+      vsf_sysutil_free(p);
+      return NULL;
+    }
+  }
+
+  *out_ptr = 0;
+
+  iconv_close(ic);
+  return p;
+}
+
diff -Nur vsftpd-2.0.1/utility.h vsftpd-2.0.1.patched/utility.h
--- vsftpd-2.0.1/utility.h   2004-04-16 06:46:29.000000000 +0800
+++ vsftpd-2.0.1.patched/utility.h   2005-02-22 11:47:51.000000000 +0800
@@ -40,5 +40,7 @@
  */
 void vsf_exit(const char* p_text);
 
+char *local2remote(const char *buf);
+char *remote2local(const char *buf);
 #endif
 


可以到這兒抓
http://www.teatime.com.tw/~tommy/linux/ ... conv.patch

如果是使用 Debian Sarge, 也可以直接用這個:
http://www.teatime.com.tw/~tommy/debian ... 1_i386.deb

在使用這個 patch 之後, 你可以在 vsftpd.conf 中指定下面三個參數
代碼: 選擇全部
enable_iconv=YES
local_charset=UTF-8
remote_charset=BIG5


local_charset 是主機檔案名稱使用的編碼. 內定為 UTF-8.
remote_charset 是 ftp client 的編碼. 內定為 BIG5.
enable_iconv 預設是關閉的, 也就是所有的動作應該都與沒加上這個 patch 時一樣. 如果設為 true/yes 時, 就會使用 iconv 來轉換檔名.

動作如下:
1. 所有的 client 送來的指令, 參數, 檔案或路徑名稱, 會使用 iconv 由 remote_charset 轉成 local_charset. 所以, 實際存取是使用 local_charset 的編碼.
2. 在 ls 指令時, 要送出檔名之前, 會用 iconv 由 local_charset 轉成 remote_charset 再送出.
3. 如果轉碼的動作是失敗的, 就不做轉碼的動作.
4. 加上一個 icnv on/off 指令 (非 ftp 標準), 可以讓 client 決定是否打開這個功能.
5. 主機上頭的檔案存取, 如果在轉成 local_charset 時, 存取失敗的話, 就假設該檔案或路徑為 remote_charset 的編碼格式, 再試一次.

以上述主機使用 UTF-8, client 使用 Big5 的情形下, 不管主機上頭的檔案路徑名稱是用 UTF-8 或 Big5, 都會轉成 Big5 送到 client 上頭, 所以當我們使用像 filezilla 之類不支援 UTF-8 的程式時, 所收到的都會是 Big5 編碼的資料.
如果我們使用支援 UTF-8 的 client 時, 如 gftp, 會發現, 反而原本在 UTF-8 的檔名, 在轉成 Big5 之後, 反而看不到正確的名稱. 此時, 可以使用上述的 icnv off 指令 (gftp 使用 site icnv off, 其他程式可能用 quote icnv off) 把轉碼的動作關閉, 就可以正常看到 UTF-8 編碼的檔案.

而在檔案抓取或更換目錄時, 會先用 UTF-8 試一次, 如果失敗, 再用 Big5 試一次. 以確定主機上頭的檔名無論是 Big5 或 UTF-8 都可以被存取.
而在檔案儲存或建立目錄時, 主機上只會使用 UTF-8 來編碼.
最後由 twu2 於 週日 2月 27, 2005 11:21 pm 編輯,總共編輯了 1 次。
twu2
懵懂的國中生
懵懂的國中生
 
文章: 219
註冊時間: 週二 3月 11, 2003 2:58 pm
來自: Taipei

文章twu2 » 週五 2月 25, 2005 11:02 am

修改幾個會出問題的指令. 如: rmdir, dele, rename, size, chmod.

新的 patch 可以到這兒抓
http://www.teatime.com.tw/~tommy/linux/ ... conv.patch

如果是使用 Debian Sarge, 也可以直接用這個:
http://www.teatime.com.tw/~tommy/debian ... 1_i386.deb
最後由 twu2 於 週日 2月 27, 2005 11:22 pm 編輯,總共編輯了 1 次。
twu2
懵懂的國中生
懵懂的國中生
 
文章: 219
註冊時間: 週二 3月 11, 2003 2:58 pm
來自: Taipei

文章Tetralet » 週五 2月 25, 2005 11:59 am

twu2 寫:修改幾個會出問題的指令. 如: rmdir, dele, rename, size, chmod.

新的 patch 可以到這兒抓
http://www.teatime.com.tw/~tommy/linux/ ... conv.patch

如果是使用 Debian Sarge, 也可以直接用這個:
http://www.teatime.com.tw/~tommy/debian ... 0_i386.deb

辛苦您了,
趕快來試試!:w_28:


一個小小的建議...

我們似乎還缺一個支援 Unicode <-> Big5 的 FTP Client。
也就是不管對方的 FTPd 使用的是 Unicode 或是 Big5 編碼,
我們可以(或由手動)切換我們在瀏覽時所使用的編碼;
(那麼我們就可以在 zh_TW.UTF-8 的環境下檢視以 Big5 編碼的 FTP 站台了)
而在存檔時,則依照 LC_CTYPE 的資訊來決定存檔的編碼方式...
(也就是說,在 zh_TW.UTF-8 環境下,它會自動以 UTF-8 的編碼方式來存檔)

我記得沒錯的話,
Samba 就是用這種方式在實作的。
我想這應該可以試試看...


或者,我們也可以只實作後半段,
即我們可以指定存檔時所使用的編碼方式,
比如說,我們可以用類似 LC_ALL=zh_TW.Big5 ftp 的方式來啟動 ftp 軟體,
但在存檔時我們可以指定它使用 UTF-8 編碼來存檔...
(在實作上,我在猜,應該不難...)

這樣子,我們應該就可以正式向 Big5 說 ByeBye 了...
時間並不能治療我心中的疼痛
南方的春天說什麼也溫暖不了我冰冷的血

誦唱大復活咒文,今天的 Tetralet 又在唧唧喳喳了 重生!
Tetralet
俺是博士
俺是博士
 
文章: 3078
註冊時間: 週四 11月 28, 2002 3:02 pm

文章twu2 » 週五 2月 25, 2005 2:06 pm

ftp 的問題實際上應該還有一段不短的路要走. 畢竟在目前 rfc 上頭, 就只有 rfc-2640 與 utf-8 有點關係, 裡頭也只有建議所有的 ftp server/client 都使用 utf-8 編碼來傳送指令. 也另外提出一個 lang 的指令, 來更改 ftp server 送出的訊息編碼方式.

可是.... 目前支援 rfc-2640 的 server/client 少的可憐.

理想狀況下, 如果所有的 client/server 都支援 rfc-2640 下, 那麼可以保證在傳送 ftp 指令的時候, 所有的檔名都是用 utf-8 編碼, 不管 ftp server/client 各自用那一種編碼, 在送出檔名時, 都會轉成 utf-8 送出, 收到檔名時, 也會由 utf-8 轉成本身使用的編碼.

但是 rfc-2640 有個問題 (個人覺得, 也許我看錯), 就是, 在於 rfc-2640 的支援與否, 是由 server 決定. 也就是當 server 支援 rfc-2640 時, client 只能被動的由 feat 指令的結果, 是否有 UTF8 來判斷 server 是否支援 rfc-2640.

也就是, 如果 ftp client 支援 rfc-2640, 自然會判斷出 server 是否有支援, 進而得知傳送的檔名是否為 utf-8 編碼, 接著不管 client 本身或 server 那端本身使用那一種編碼, 都能正確運作.

但是... 如果 client 不支援 rfc-2640 時, 自然不認得 feat 中有個 UTF8, 此時, 除非 client 的環境, 本身就是 utf-8, 否則, 所有的檔名編碼都變亂碼了.

由此看來, 如果我們只修改 ftp server 支援 rfc-2640, 而不管 client 的情形下, 除非 client 也支援 rfc-2640 或 client 就是用 utf-8, 否則會有問題.

在目前的現實上頭, 幾乎所有的 client 都不支援 rfc-2640, 如果我們把 server 改成支援 rfc-2640 時, 反而造成多數的 client 無法使用.

所以... 我前面那個 patch, 並不是把 vsftpd 改成支援 rfc-2640, 而是剛好相反, 為了讓目前多數不支援 rfc-2640 的 client 可以運作, 反而把檢名傳送的編碼, 也成不是 utf-8. 但是, 這就造成另外一個問題:

如果 client 在 utf-8 的環境下頭, 連上這個修改的 server 時, 反而收到一些非 utf-8 編碼的檔名. (這也是 patch 裡頭加上 icnv off 指令的原因, 只是.... 這不在 rfc 裡頭, 自然沒有 ftp client 支援, 要想辦法自己打...)
twu2
懵懂的國中生
懵懂的國中生
 
文章: 219
註冊時間: 週二 3月 11, 2003 2:58 pm
來自: Taipei

文章twu2 » 週五 2月 25, 2005 2:10 pm

所以.... ftp 的問題, 我想除非等到多數的 ftp client 都支援 rfc-2640, 才能夠解決吧. 這個問題.... 主要是 client 的修改, 對於 server 端來說, 可以做的實在不多.
twu2
懵懂的國中生
懵懂的國中生
 
文章: 219
註冊時間: 週二 3月 11, 2003 2:58 pm
來自: Taipei

文章forgetter » 週五 2月 25, 2005 7:24 pm

不知道有没有可能帮gftp补上patch
把它自定义remote charset的功能实现?

viewtopic.php?p=30473#30473
forgetter
可愛的小學生
可愛的小學生
 
文章: 38
註冊時間: 週四 10月 21, 2004 12:53 am

文章twu2 » 週五 2月 25, 2005 11:22 pm

gftp 的修改很簡單.
而且, 修改這個後, 就可以不用我之前加上的那個非標準的 icnv off 指令, 由 gftp 本身就可以處理 utf-8 (或支援 rfc-2640) 的 server, 加上 remote_charsets 設定, 也可以處理其它指定的編碼.

代碼: 選擇全部
diff -Nur gftp-2.0.18/lib/protocols.c gftp-2.0.18.patched/lib/protocols.c

--- gftp-2.0.18/lib/protocols.c   2005-01-25 10:34:18.000000000 +0800
+++ gftp-2.0.18.patched/lib/protocols.c   2005-02-25 23:07:11.000000000 +0800
@@ -450,11 +450,16 @@
     {
       ret = g_convert_with_iconv (str, -1, request->iconv, &bread, &bwrite,
                                   &error);
-      if (ret == NULL)
-        printf (_("Error converting string '%s' from character set %s to character set %s: %s\n"),
-                str, _("<unknown>"), "UTF-8", error->message);
-
-      return (ret);
+      if (ret == NULL) {
+//        printf (_("Error converting string '%s' from character set %s to character set %s: %s\n"),
+//                str, _("<unknown>"), "UTF-8", error->message);
+        g_iconv_close (request->iconv);
+        request->iconv = NULL;
+        request->iconv_initialized = 0;
+      }
+      else {
+        return (ret);
+      }
     }

   gftp_lookup_request_option (request, "remote_charsets", &tempstr);
@@ -521,11 +526,16 @@
     {
       ret = g_convert_with_iconv (str, -1, request->iconv, &bread, &bwrite,
                                   &error);
-      if (ret == NULL)
-        printf (_("Error converting string '%s' from character set %s to character set %s: %s\n"),
-                str, "UTF-8", _("<unknown>"), error->message);
-
-      return (ret);
+      if (ret == NULL) {
+//        printf (_("Error converting string '%s' from character set %s to character set %s: %s\n"),
+//                str, "UTF-8", _("<unknown>"), error->message);
+        g_iconv_close (request->iconv);
+        request->iconv = NULL;
+        request->iconv_initialized = 0;
+      }
+      else {
+        return (ret);
+      }
     }

   gftp_lookup_request_option (request, "remote_charsets", &tempstr);


patch 檔案在:
http://www.teatime.com.tw/~tommy/linux/ ... sets.patch

給 sarge 用的 deb 在這兒:
http://www.teatime.com.tw/~tommy/debian ... -9_all.deb
http://www.teatime.com.tw/~tommy/debian ... 9_i386.deb
http://www.teatime.com.tw/~tommy/debian ... 9_i386.deb
http://www.teatime.com.tw/~tommy/debian ... 9_i386.deb
最後由 twu2 於 週日 2月 27, 2005 11:22 pm 編輯,總共編輯了 1 次。
twu2
懵懂的國中生
懵懂的國中生
 
文章: 219
註冊時間: 週二 3月 11, 2003 2:58 pm
來自: Taipei

文章windcloud » 週六 2月 26, 2005 1:25 am

twu2 寫:gftp 的修改很簡單.
而且, 修改這個後, 就可以不用我之前加上的那個非標準的 icnv off 指令, 由 gftp 本身就可以處理 utf-8 (或支援 rfc-2640) 的 server, 加上 remote_charsets 設定, 也可以處理其它指定的編碼.

代碼: 選擇全部
diff -Nur gftp-2.0.18/lib/protocols.c gftp-2.0.18.patched/lib/protocols.c

--- gftp-2.0.18/lib/protocols.c   2005-01-25 10:34:18.000000000 +0800
+++ gftp-2.0.18.patched/lib/protocols.c   2005-02-25 23:07:11.000000000 +0800
@@ -450,11 +450,16 @@
     {
       ret = g_convert_with_iconv (str, -1, request->iconv, &bread, &bwrite,
                                   &error);
-      if (ret == NULL)
-        printf (_("Error converting string '%s' from character set %s to character set %s: %s\n"),
-                str, _("<unknown>"), "UTF-8", error->message);
-
-      return (ret);
+      if (ret == NULL) {
+//        printf (_("Error converting string '%s' from character set %s to character set %s: %s\n"),
+//                str, _("<unknown>"), "UTF-8", error->message);
+        g_iconv_close (request->iconv);
+        request->iconv = NULL;
+        request->iconv_initialized = 0;
+      }
+      else {
+        return (ret);
+      }
     }

   gftp_lookup_request_option (request, "remote_charsets", &tempstr);
@@ -521,11 +526,16 @@
     {
       ret = g_convert_with_iconv (str, -1, request->iconv, &bread, &bwrite,
                                   &error);
-      if (ret == NULL)
-        printf (_("Error converting string '%s' from character set %s to character set %s: %s\n"),
-                str, "UTF-8", _("<unknown>"), error->message);
-
-      return (ret);
+      if (ret == NULL) {
+//        printf (_("Error converting string '%s' from character set %s to character set %s: %s\n"),
+//                str, "UTF-8", _("<unknown>"), error->message);
+        g_iconv_close (request->iconv);
+        request->iconv = NULL;
+        request->iconv_initialized = 0;
+      }
+      else {
+        return (ret);
+      }
     }

   gftp_lookup_request_option (request, "remote_charsets", &tempstr);


patch 檔案在:
http://www.teatime.com.tw/~tommy/linux/ ... sets.patch

給 sarge 用的 deb 在這兒:
http://www.teatime.com.tw/~tommy/debian ... -1_all.deb
http://www.teatime.com.tw/~tommy/debian ... 1_i386.deb
http://www.teatime.com.tw/~tommy/debian ... 1_i386.deb
http://www.teatime.com.tw/~tommy/debian ... 1_i386.deb

耶.....謝謝您的分享.......
終於可以用gftp看中文的檔名了
目前在用windows servU架的FTP站可以看的到中文檔名了
不過請問一下那下載下來...中文檔名會變成亂碼是正常的嗎
謝謝
windcloud
可愛的小學生
可愛的小學生
 
文章: 35
註冊時間: 週一 11月 29, 2004 11:25 pm

文章twu2 » 週六 2月 26, 2005 8:28 am

下載回來會亂碼.... 當然不正常. 用 convmv 轉一下看看是不是 BIG5 碼?
這個我沒有測, 今天有空再試看看.
twu2
懵懂的國中生
懵懂的國中生
 
文章: 219
註冊時間: 週二 3月 11, 2003 2:58 pm
來自: Taipei

文章ifgh » 週六 2月 26, 2005 10:45 am

今早試過, 中文沒問題囉;)真是太感謝囉 :finger1: :finger1:
ifgh
可愛的小學生
可愛的小學生
 
文章: 14
註冊時間: 週六 12月 06, 2003 2:02 pm

文章twu2 » 週六 2月 26, 2005 1:08 pm

由於 gftp 內部在處理資料時, 似乎都轉成 utf-8 處理, 但是程式中這部份的邏輯似乎有點怪怪的, 除了在 remote_charsets 有設定時, 會把所有送出給 remote 的資料由 utf-8 再轉成所設定的編碼, 也會把由 remote 收到的資料由 remote_charsets 所設定的編碼轉成 utf-8 外, 對於 local (還有其他非 ftp 協定?), 也一直呼叫相同的函式來處理. (看不出有什麼判斷來決定那些要轉, 那些不用轉, 所以... 有些不該轉的也轉了... 有些該轉的, 又做了兩次轉換, 又轉回去原本的編碼)

原本打算把 gftp 修改成符合 rfc-2640.
1. 連線時送出 FEAT 指令, 判斷對方是否支援 rfc-2640. 也就是有 UTF8 feature.
2. 如果對於有支援 rfc-2640, 則不要使用 remote_charsets 的設定來轉碼. 應直接使用 utf-8.
3. 所有 local 端的檔名, 再由 utf-8 <-> local 之間互轉.

不過... 有些邏輯看了一上午, 實在看不太出來. 所以決定就用最簡單的改法. 就是假定 local 端一律使用 utf-8, 檔案儲存的時候, 如果檔名非 utf-8 就轉成 utf-8.

這個改法並非每個人都適用, 如果你的 locale 並沒設定為 utf-8, 應該會有問題.

至少, 這個改法, 符合我目前本身使用的需求. 可以正常看到中文檔名, 傳檔回來也是正常的 utf-8 中文檔名.

patch 與 deb 的檔名都沒改, 和上一篇的路徑相同, 直接抓就可以了.
twu2
懵懂的國中生
懵懂的國中生
 
文章: 219
註冊時間: 週二 3月 11, 2003 2:58 pm
來自: Taipei

文章twu2 » 週六 2月 26, 2005 6:02 pm

修改一下 vsftpd, 以符合 rfc-2640 的需求. (如果我沒看錯的話)

新的 patch 可以到這兒抓
http://www.teatime.com.tw/~tommy/linux/ ... conv.patch

如果是使用 Debian Sarge, 也可以直接用這個:
http://www.teatime.com.tw/~tommy/debian ... 1_i386.deb

同之前的設定, 在把 enable_iconv 設為 yes, 且 remote_charset 設為 UTF-8 的時候, 會在 Clinet 使用 FEAT 指令時, 傳回 UTF8 表示支援檔名使用 UTF-8 編碼. (rfc-2640 好像就是要求 FEAT 有 UTF8, 且檔名都用 UTF-8 傳送)

另外, 我也改了一份 FileZilla 2.2.11 支援 rfc-2640 的版本. 麻煩測試一下.
http://www.teatime.com.tw/~tommy/FileZilla.zip

這個版本的 FileZilla 比較小, 因為沒支援 libidn.a (我還找不到 win32 的版本), 所以... domain name 不能用非英文的名字.
製造時, 我的 Visual Studio 2003 說無法載入 FzSFtp 的那個 project, 不過似乎還是可以使用 sftp.

與原本的版本差異除了上述 libidn.a 外, 就是在一開始連線時, 在送出 FEAT 指令後, 如果對方有回 UTF8, 在這之後, 就一律使用 UTF-8 來傳送檔名. 程式會將收到的檔名, 由 UTF-8 轉成 Windows 的 Unicode, 再轉成 ANSI CodePage (在繁體中文下就是 CP950), 在送出指令時, 會由 Windows 的 ANSI CodePage 轉成 Unicode 再轉成 UTF-8, 然後送出.
當然, 如果對方不支援 rfc-2640 的話, 也就應該不會有 UTF8 出現在 FEAT 中, 就不會做任何的轉換.

如果沒有問題的話, 這個 FileZilla 的相關 patch, 我整理一下再公開, 也會試著寄給 FileZilla 的作者.

PS. 剛剛忘了把我用來除錯的功能關了, 所以如果你有抓這個連結的 FileZilla.zip 的話, 請再抓一次, 不然.... 會有個 c:\fz.log 會一直長大.
最後由 twu2 於 週四 3月 03, 2005 2:39 pm 編輯,總共編輯了 2 次。
twu2
懵懂的國中生
懵懂的國中生
 
文章: 219
註冊時間: 週二 3月 11, 2003 2:58 pm
來自: Taipei

上一頁下一頁

回到 share

誰在線上

正在瀏覽這個版面的使用者:沒有註冊會員 和 1 位訪客