用了一段时间 Gnus,对 Gnus 中的各种编码设定有了些了解,写出来与大家分享。
Gnus 是构建在 Emacs 之上的,自然也就利用了 Emacs 超强的多国语言编码支持。
所以如果你有一封乱码的邮件,如果 Gnus 看不了的话,那么估计卖糕的也不会有办
法了。
为了处理各种编码的邮件,gnus 提供了很多可以设置的变量。不过变量多了也会带
来麻烦,如果你设置不好的话,就有可能开枪打中自己的脚。
** 先谈谈邮件编码
邮件可以分为两个部分: header 和 body。比较文明的邮件会在 header 的
`Content-Type' 这一行中用 MIME 说明邮件采用了什么编码。而不文明的邮件则缺
少这种说明,对于只有英文的邮件,这样做不会有问题,而对于包含中文的邮件,
就有可能这是导致乱码,小比尔的 Outlook Express 就喜欢发出这种邮件,一些
webmail 也经常干这种事。
另外,在邮件头中,还可以指定邮件的传输编码。如果邮件的内容都是7位的
us-ascii字符,就不会出现什么传输编码的问题,但是因为汉字的编码一般都是8
位的,而有些邮件网关只能传输7bit字符,最高位作其它用途了,所以就出现了
base64, quoted-printable 等把8位字符转换成7位编码进行传输的编码方案。
邮件的传输编码可以在邮件头中用 `Content-Transfer-Encoding' 指出来。
我们可以让 Gnus 把 `Content-Type' 和 `Content-Transfer-Encoding' 字段显示
出来:
(add-hook 'gnus-startup-hook
'(lambda ()
(setq gnus-visible-headers
(concat "^User-Agent:\\|^Content-Type:\\|"
"Content-Transfer-Encoding:\\|"
"^X-mailer:\\|^X-Newsreader:\\|^X-Sender:\\|"
gnus-visible-headers))))
这样我们就可以看到邮件采用了什么编码(顺便还可以看到对方用的是什么客户端
软件),如果邮件指定了编码,你就会在邮件头部看到这一行:
Content-Type: text/plain; charset=GB18030
如果邮件指定了传输编码,就可以看到这样一行:
Content-Transfer-Encoding: base64
** Gnus 中与编码有关的变量
需要说明的是,大多数情况下,邮件都是比较文明的,在 Content-Type 字段已经
说明了邮件采用的编码,那么 Gnus 将自动按指定的编码显示邮件。除非 Emacs 本
身就不支持这种编码,否则是不会出现乱码的。
一个常见情况就是使用 Emacs21 或 Emacs22,而不安装 mule-gbk,要知道
Emacs21/22 本身就不支持 GBK 和GB18030,这样对于 charset=gbk, 或
charset=gb18030 的邮件出现乱码就不奇怪了。所以,如果你使用的是 Emacs21 或
Emacs22, 赶紧去下载 mule-gbk 装上吧。注意,对于 Emacs22,mule-gbk 的设置
中一定要加上这一句:
(utf-translate-cjk-load-tables)
否则 Emacs22 无法进行 gbk <--> utf-8 的转换,而 gnus 是先用 utf-8 编写邮
件,再转换成指定的编码发出去,如果不加上这句设置,就会出现只能发 utf-8
的邮件,不能发 gbk 邮件的怪现象。
下面讨论的设置适用于 Emacs22+mule-gbk 和 Emacs23。
如果邮件中已经用 Content-Type 和 Content-Transfer-Encoding 指定了编码,
那么 gnus 将忠实地采用这些编码处理邮件,这时是不应该出现乱码的。所以,我
们所做的设置基本上都是为了对付那些捣乱的,不指明编码的邮件。
现在我们来看看 gnus 中与编码设置有关的变量。这些变量可以分为两种类型,一
种是与邮件内容有关的,另一种是与组名(group name)有关的。
** 与邮件内容有关的变量
*** gnus-default-charset
这个变量指定查看邮件所用编码的默认值(对于未指定编码的邮件)。但是这
个变量的会被下一个变量(gnus-group-charset-alist)覆盖。如果不设置这个
变量,它的值将由 `current-language-environment' 确定。
例如:(setq gnus-default-charset 'gbk)
*** gnus-group-charset-alist
这个变量根据组名确定本组的默认编码。设置这个变量时我们要给出一个
(regexp charset) 对,其中 regexp 时匹配组名的正则表达式,charset 是制
定的编码。在这个变量的默认设置中,我们可以查到如下内容:
("\\(^\\|:\\)hk\\>\\|\\(^\\|:\\)tw\\>\\|\\" cn-big5)
("\\(^\\|:\\)cn\\>\\|\\" cn-gb-2312)
可以看出,对于以 hk 或 tw 开头(或者组名中包含 :hk 或 :tw)的组,采用
big5编码。而对于以 cn 开头或组名中包含 :cn 的组采用 cn-gb-2312 的编
码。
因为现在 gbk 比 gb2312 应用更广泛,所以我们需要更改这个变量的设置:
(add-to-list 'gnus-group-charset-alist
'("\\(^\\|:\\)cn\\>\\|\\" gbk))
这个变量也可以在 group parameter 中以 (charset . gbk) 的方式指定。
*** gnus-summary-show-article-charset-alist
有时候,默认的编码还不能解决问题,例如,有人把 big5 编码的邮件投递到
了 cn 开头的组里,而且邮件头中又没有编码设定(插一句,这些邮件一般
都是垃圾邮件),这时就需要手工指定编码。
(setq gnus-summary-show-article-charset-alist
'((1 . utf-8)
(2 . big5)
(3 . gbk)
(4 . utf-7)))
进行了这种设定以后,我们看到乱码邮件时就可以用 `1 g' 指定采用 utf-8,
`2 g' 指定big5等等,不过能不能正确解码就要看你自己猜的对不对了。
** 与组名有关的变量
我们订阅新闻组时,可以看到有些服务器上的组名都是英文的,比如在
`news.cn99.com' 这个服务器中组名都是这样的:
gnu.emacs.help
cn.comp.os.linux
tw.bbs.os.linux
而有些服务器的组名却是包含中文的,比如新帆`news.newsfan.net'的组名:
计算机.软件.操作系统.FreeBSD
计算机.软件.操作系统.linux
休闲娱乐.游戏天地.Diablo
下面两个变量是为了让gnus能正确地处理非ascii组名的。
*** gnus-group-name-charset-group-alist
这个变量根据组名确定组名采用的编码,默认值是`((".*" utf-8))',也就是
默认用 utf-8 处理所有组名。我们可以这样这样设置:
(setq gnus-group-name-charset-group-alist
'(("\\.com\\.cn:" . gbk)
("news\\.newsfan\\.net" . gbk)))
这样所有组名中含有 .com.cn 或 news.newsfan.net 的组,其名称都采用 gbk
解码。
不过如果我们把 news.newsfan.net 设置为 native method, 那么组名中就不
会出现 news.newsfan.net,那么这个变量就发挥不了作用,怎么办呢?可以采
用下面这个变量。
*** gnus-group-name-charset-method-alist
还记得吗?我们选择新闻服务器时是怎么设定的?对了,我们是通过设置
method 来选择服务器的,比如:
(setq gnus-select-method '(nntp "news.newsfan.net"))
(setq gnus-secondary-select-methods '((nnml "")))
这个变量可以根据我们选择的 method,为来自这个 method 的组设置组名的
编码。
(setq gnus-group-name-charset-method-alist
'(((nntp "news.newsfan.net") . gbk)))
这样,所有来自新帆服务器的组名都采用gbk来解码。
** 设置发出邮件的编码: mm-coding-system-priorities
当我们向外发送邮件时,也可以指定编码,比如我们希望发出的邮件采用gb2312编
码,就可以这样设置:
(setq mm-coding-system-priorities '(iso-8859-1 gb2312 utf-8))
这样,gnus将先试这采用 iso-8859-1 编码邮件,如果不行就采用 gb2312,实在
不行再采用 utf-8 编码。
这样如果你写了一封纯英文的信件,将会采用 iso-8859-1 发出;如果你写了一封
中文信件,但其中的汉字都在 gb2312 的范围内,则采用gb2312发出;如果你的信
件中含有gb2312以外的字符,则会被以utf-8编码发出。
那么如果想对不同的组采用不同的编码发信,有办法实现吗?可以,通过设置
posting-style 就可以实现。
(setq gnus-posting-styles
'((".*"
(name "Brep")
(address "brep@bogus.com")
(eval (setq mm-coding-system-priorities
'(iso-8859-1 utf-8))))
("^cn\\.comp"
(name "Brep")
(address "brep@smth.org")
(eval (setq mm-coding-system-priorities
'(iso-8859-1 gb2312 utf-8))))
("^tw\\.comp"
(name "Brep")
(address "brep@ptt.cc")
(eval (setq mm-coding-system-priorities
'(iso-8859-1 big5 utf-8))))))
这样对于 cn.comp 开头的组,gnus会先尝试采用gb2312发送邮件,不行再用utf-8,
而对于 tw.comp 开头的组,会先尝试采用big5发送邮件,不行再用utf-8。
** 处理有问题的邮件: gnus-newsgroup-ignored-charsets
有些客户端发出的邮件没有指定正确的MIME类型,例如本来这封邮件是用 gbk 编
码的,但是 MIME 类型却设置成了 x-gbk:
Content-Type: text/plain; charset=x-gbk
这时gnus解码时会遇到困难,我们可以把这种 MIME 类型加入到
gnus-newsgroup-ignored-charsets 列表中,让 gnus 采用默认的编码处理它。
再比如,有些邮件的 MIME 类型是 charset=gb18030, 对于 emacs23,这是没问题
的,因为 Emacs23 支持 gb18030 编码。但是 emacs22+mule-gbk 根本就不支持
gb18030,那么该怎么办呢?同样我们可以把 gb18030 加入
gnus-newsgroup-ignored-charsets 列表中:
(setq gnus-newsgroup-ignored-charsets
'(unknown-8bit x-unknown x-gbk gb18030))
ignored-charsets 也可以在 group parameters 中这样指定:
(ignored-charsets x-unknown iso-8859-1)
** 指定传输编码:gnus-group-posting-charset-alist
这个变量可以用来设置邮件头中的 Content-Transfer-Encoding 字段,为邮件指
定传输编码。这个变量的默认值已经设置的很好了,我从来没有遇到需要设置这个
变量的情况。
** 不要让自己发出乱码的邮件(指定附件文件名和subject的编码方式)
gnus 默认采用 RFC2231 对附件文件名进行编码,有些 MUA 无法识别这种编码。现
在比较流行的方式是采用 RFC2047 对附件文件名进行编码。可以采用如下设定,让
gnus 也采用这种方式对文件名进行编码:
(defalias 'mail-header-encode-parameter 'rfc2047-encode-parameter)
有很多差劲的邮件客户端无法解码 quoted-printable 编码(看到过 subject 中有
很多 `=' 号的乱码邮件吗?就是由于这个原因产生的。)为了保证我们发出的邮件
subject 采用 base64 编码,而不是采用quoted-printable 编码,最好加上这两句:
(add-to-list 'rfc2047-charset-encoding-alist '(gbk . B))
(add-to-list 'rfc2047-charset-encoding-alist '(gb18030 . B))
** 参考设置
最后给出一个参考设置吧,适用于 Emacs22+mule-gbk 或者 Emacs23:
(setq gnus-default-charset 'gbk)
(add-to-list 'gnus-group-charset-alist
'("\\(^\\|:\\)cn\\>\\|\\" gbk))
(setq gnus-summary-show-article-charset-alist
'((1 . utf-8)
(2 . big5)
(3 . gbk)
(4 . utf-7)))
(setq gnus-group-name-charset-group-alist
'(("\\.com\\.cn:" . gbk)
("news\\.newsfan\\.net" . gbk)))
(setq gnus-group-name-charset-method-alist
'(((nntp "news.newsfan.net") . gbk)))
(setq gnus-newsgroup-ignored-charsets
'(unknown-8bit x-unknown x-gbk gb18030))
(defalias 'mail-header-encode-parameter 'rfc2047-encode-parameter)
(add-to-list 'rfc2047-charset-encoding-alist '(gbk . B))
(add-to-list 'rfc2047-charset-encoding-alist '(gb18030 . B))
(setq gnus-posting-styles
'((".*"
(name "Brep")
(address "brep@bogus.com")
(eval (setq mm-coding-system-priorities
'(iso-8859-1 utf-8))))
("^cn\\.comp"
(name "Brep")
(address "brep@smth.org")
(eval (setq mm-coding-system-priorities
'(iso-8859-1 gb2312 utf-8))))
("^tw\\.comp"
(name "Brep")
(address "brep@ptt.cc")
(eval (setq mm-coding-system-priorities
'(iso-8859-1 big5 utf-8))))))
(add-hook 'gnus-startup-hook
'(lambda ()
(setq gnus-visible-headers
(concat "^User-Agent:\\|^Content-Type:\\|"
"Content-Transfer-Encoding:\\|"
"^X-mailer:\\|^X-Newsreader:\\|^X-Sender:\\|"
gnus-visible-headers))))
** 不要让自己发出乱码的邮件(指定附件文件名和subject的编码方式)
gnus 默认采用 RFC2231 对附件文件名进行编码,有些 MUA 无法识别这种编码。现
在比较流行的方式是采用 RFC2047 对附件文件名进行编码。可以采用如下设定,让
gnus 也采用这种方式对文件名进行编码:
(defalias 'mail-header-encode-parameter 'rfc2047-encode-parameter)
有很多差劲的邮件客户端无法解码 quoted-printable 编码(看到过 subject 中有
很多 `=' 号的乱码邮件吗?就是由于这个原因产生的。)为了保证我们发出的邮件
subject 采用 base64 编码,而不是采用quoted-printable 编码,最好加上这两句:
(add-to-list 'rfc2047-charset-encoding-alist '(gbk . B))
(add-to-list 'rfc2047-charset-encoding-alist '(gb18030 . B))
因为这篇文章主要是讨论Gnus的编码问题,所以这里列出的仅仅是与编码有关的设置。
# Local Variables:
# mode: org
# coding: utf-8
# End:
阅读(2829) | 评论(1) | 转发(0) |