2006-01-19

《小王子》的测试

fox.
You are the fox.


Saint Exupery's 'The Little Prince' Quiz.
brought to you by Quizilla

用.netrc来自动登录

linux里面的好多程序都靠$HOME/.netrc来获取密码,进行认证。自己常用的lftp就是这样,也不知道为什么,它就是不用我已经配置好的ssh public key来,非得配置.netrc才能实现自动登录。
machine 202.108.35.239
login xyb
password mask

machine 202.106.182.247
login yanbo
password mask

这样配置好了,lftp就能自己查询相应的用户名和密码登录了。

Mass Transit - How Python wins on the Web

由于Ruby on Rails带来的压力和展示出的美好前景,Python圈子里一时Web Framework流行。SubwayTurbogearsDjango,一个一个新的框架蓬勃发展。看起来生机勃勃,不过……Mass Transit回顾了python的“重量级”应用,反思了最近的Framework的热潮,Python的魅力到底在那里呢?在“How Python wins on the Web”这篇文章里,他提出了自己的一些观点。说实话,从使用者的角度来看,开发语言是Python还是Perl还是Ruby,都不重要,重要的是产品的功能是我用得着的,同样重要的是产品是好维护的:一个egg就可以部署的WSGI应用确实要更方便一些。

Read more at www.aminus.org/blogs/in...

2006-01-10

基于postfix实现邮件用户的分布式处理

基于一些特殊的考虑,现在邮件系统经常面临把用户分散在几个不同服务器上的需求。这里谈一下我在使用postfix完成该功能时的一点认识和实践,需求所限,没有涉及到用户通过SMTP或者POP3登录收发邮件的部分。请各位朋友谅解并指正。

一般分布情况下,MX和用户所在的服务器是分离的;本文所描述的即是这种设计。下面把用户所在的服务器简称为单元(UNIT)。

MX

MX是接受邮件的关键,可以由一台或一组服务器组成。它对外开放SMTP端口,负责接受邮件并转投到收件人所在单元服务器。

简单的说,一封信投递到我们的系统中,首先会进入MX,MX检查收件人是否存在,然后根据用户的信息把信通过smtp协议转发到他所在的UNIT上。

由于用户分散在不同主机中,所以MX对用户进行查证的工作必须进行特殊的处理;这里大家可以集思广益,设计一两百种方案我看是没什么问题。不过,我们的任务是说明postfix如何处理用户分布的情况,所以我们假定已经有一个写好了的函数,调用它就可以查证用户了。我们利用它,就可以实现dict_unit这个map。利用选项 local_recipient_maps,使外部发信到我们的用户时,调用我们指定的接口对用户查证;输入为收件人的邮件地址。
local_recipient_maps = unit:smtpcheck

这里dict_unit的实现在后面详细解释。

用户查证是在访问者发出“RCPT ”指令时,如果postfix确认了该用户存在,就开始准备接收“DATA”指令发过来的邮件正文了。成功收到邮件后,通过配置好的 transport_maps,postfix可以询问我们的dict_unit,获得下一步处理的指令。比如,输入收件人邮件地址“user@my.com”,输出“smtp:unit12.my.com”,这就会让postfix通过smtp把信转投到unit12.my.com域名的这台机器上。
transport_maps = unit:transportmx


UNIT

邮件系统中的用户通过注册、转移等方式,被存放在不同的单元服务器中。他们负责接收从MX转投过来的信件,并最终放入存储系统中。

在这里,一样会使用local_recipient_maps检查收件人是否真实存在。但与MX不同的是,这是信件的最终目的地,transport_maps查询的结果就不能再是“smtp:unit12.my.com”,要设置成合适的本地处理程序,比如local或者指定mda的名称(在etc/master.cf中设置)等。

local_recipient_maps = unit:smtpcheck
transport_maps = unit:transportunit


自定义的map

这里是dict_unit的实现示意。通过这个map,我们可以把前面提到的用户查证、转发邮件、处理邮件的所有指引工作在一起完成;实际上,它相当于一个多向的阀门,可以让邮件流向不同的方向。

注意,这仅仅是示意的代码。有需要做开发的朋友请自行参考dict_pam[1]的实现,那是真正可执行的代码。请不要写信询问我如何编写并调试可用的dict,google[2]postfix官方网站[3]上都可以查到。

这个函数负责处理用户查证的工作。
static int dict_unit_smtpcheck(const char *name, char *result)
{
char userhost[128] = {0};

if (msg_verbose)
msg_info("dict_unit: lookup smtp user: %s", name);
ret = getuser(name, &userhost);
if (ret != 0){
if (msg_verbose)
msg_warn("dict_unit: lookup smtp failed, name: %s", name);
return 1;
}
if (msg_verbose)
msg_info("dict_unit: lookup transport successed, name: %s, host: %s, path: %s",
name,
userhost);

strncpy(result, userhost, sizeof(userhost));
return 0;
}


这个函数负责控制MX服务中邮件的流向。

static int dict_unit_transportmx(const char *name, char *result)
{
char userhost[128] = {0};

if (msg_verbose)
msg_info("dict_unit: lookup transport user: %s", name);

ret = getuser(name, &userhost);
if (ret != 0){
if (msg_verbose)
msg_warn("dict_unit: lookup transport failed, name: %s", name);
return 1;
}
if (msg_verbose)
msg_info("dict_unit: lookup transport successed, name: %s, host: %s,",
name,
userhost);

/* result formal like: "smtp:unit12.my.com" */
strncpy(result, "smtp:", sizeof(userhost));
strncat(result, userhost, sizeof(userhost)-strlen("smtp:"));
return 0;
}


这个函数负责控制UNIT中的邮件的流向。值得一提的是,这里我们使用了var_myhostname来鉴别该用户是不是本机的(很简陋,演示嘛),要正确编译的话,在src/global/dict_unit.c中,必须加入这一行:
#include "mail_params.h"

要正确运行的话,则必须再在etc/main.cf中配置好正确的本机域名:
myhostname = unit12.my.com

最后,我们这里的是调用了一个定制的MDA程序“mymda”来完成最终信件的投递。要让它能正确运行,得配置etc/master.cf,请自行查阅手册。

static int dict_unit_transportunit(const char *name, char *result)
{
char userhost[128] = {0};

if (msg_verbose)
msg_info("dict_unit: lookup transport user: %s", name);

ret = getuser(name, &userhost);
if (ret != 0){
if (msg_verbose)
msg_warn("dict_unit: lookup transport failed, name: %s", name);
return 1;
}
if (msg_verbose)
msg_info("dict_unit: lookup transport successed, name: %s, host: %s",
name,
userhost);

/* for local user, result is: "mymda:"
* for remote user, result is: "smtp:mx.my.com"
*/
if (0==strnstr(userhost, var_myhostname, sizeof(userhost)))
/* MX can delivery it */
strncpy(result, "smtp:mx.my.com", sizeof(userhost));
else
/* local MDA is ok */
strncpy(result, "mymda:", sizeof(userhost));

return 0;
}


最后,为了让上面的三个lookup能真正工作起来,要在dict对外提供的接口处调用他们。这个分流是通过lookup时传入的dict->service来辨认的,也就是在main.cf中的配置“unit:smtpcheck”冒号后面的部分。

static const char *dict_unit_lookup(DICT *dict, const char *name)
{
DICT_unit *dp = (DICT_unit *) dict;
char result[128] = {0};
int ret;

if (0 == strcmp(vstring_str(dp->service), "smtpcheck"))
ret = dict_unit_smtpcheck(name, result);
else if (0 == strcmp(vstring_str(dp->service), "transportmx"))
ret = dict_unit_transportmx(name, result);
else if (0 == strcmp(vstring_str(dp->service), "transportunit"))
ret = dict_unit_transportunit(name, result);
else
{
if (msg_verbose)
msg_error("dict_unit: lookup unknown service %s, name %s.",
vstring_str(dp->service), name);
return (0);
}
if ((0 != ret) || (0 == result[0]))
return (0);

succ:
if (msg_verbose)
msg_info("dict_unit: service %s, name: %s, result: %s.",
vstring_str(dp->service), name, result);
vstring_strncpy(dp->result, result, sizeof(result));
return vstring_str(dp->result);
}


组装在一起,这个控制邮件流向的大阀门就算是完工了。

以上是利用postfix实现用户分布的一次实践。当然,方案并非只有一种,大家各有不同。请大家多多讨论,共同进步。

本文基于创作共用协议[4]之“署名-保持一致”[5]许可证发表,使用前请阅读该协议。-- xyb

参考
[1] http://d.scn.ru/proj/postfix/dict_pam/
[2] http://www.google.com/
[3] http://www.postfix.org/
[4] http://www.creativecommons.cn/
[5] http://creativecommons.cn/licenses/by-sa/1.0/

2006-01-07

txt2pdbdoc

经常用palm看些电子书,所以用txt2pdbdoc自己做.pdb文件是免不了的。可是要命的是,中文文本用它制作时,常常发生core dump。今天没事,分析了一下,发现问题处在compress这个函数上。这是个非常简单的压缩算法;但该算法效率最差时,压缩之后的数据要比之前的还要大。看来这个算法对英文等字符集较小的文字效率不错,但对中文就有点水土不服啦。因为压缩后的数据超出了预期大小,造成了缓冲区溢出,引发莫名其妙的问题就在所难免了。

找到问题所在,解决就很简单了:对中文文档,指定参数“-c”,不进行压缩。不过,这样其实是指标不治本,还是修改一下代码来的实在。把缓冲区增大到压缩算法效率最差时需要的空间。这里是修改之后的patch,把缓冲区增加到原来的两倍,问题解决。

2006-01-06

How Do People See You?

Slow and Steady

Your friends see you as painstaking and fussy.

They see you as very cautious, extremely careful, a slow and steady plodder.

It'd really surprise them if you ever did something impulsively or on the spur of the moment.

They expect you to examine everything carefully from every angle and then usually decide against it.

厄,这是评测男生的吗?

2006-01-03

2006的第一场爱国卫生运动

昨天晚上睡觉,觉得背上有点痒。突然想到,住进来一直没有好好收拾过屋子和床铺,可能最近穿衣服、睡觉总是有点痒跟床上不干净有关系。今天起来大动干戈,把能洗的都拿去洗了,好好清扫了一下屋里的卫生。好多土呀。幸亏还有前两年非典剩下的口罩,劳动生产正好用上,哈哈。

最近事稍微少了一点,刚刚上网正好看见有个Grsync,翻译量很少,拿来即兴翻译了一下,提交给了作者。希望今年上半年能多些自主的时间,可以参与些开源项目。

注:刚发完信一刻钟,Grsync的作者就回信了,反应倒是真快。算起来那边的时间该吃中午饭了,我也吃晚饭去啦 :)