技术

HTTP Access to Email Stores

访问邮箱的标准且广泛使用的协议有两个,pop3 和 imap4。在这个桌面程序日渐式微,web应用极大丰富的时代,现在又有人鼓捣起了基于 http 的访问协议:http://tools.ietf.org/html/draft-dusseault-httpmail-00

这个概念相当有意思,我很是期待这个草案获得通过并最后成为广泛应用标准的一天——我猜想首先是 dovecot 开始支持它,然后是某些web应用开始集成邮件访问功能,接着各个 AJAX/RIA 框架推出对应的内置组件,widget,...

这个协议大概不会得到现在 webmail 提供商的支持,前景还很难说,且拭目以待吧。

尝试了一下 pycairo

在 python 里处理图形,通常来说是用的 PIL 这个包。最近在对比哪种字体在12px下渲染最好看,试了很多,总觉得不好看。我突然想到,为什么不利用 cairo 来渲染字体呢,毕竟这东西随着 Linux 桌面的发展一直在进步,而 PIL 很久没有更新了?

利用 python-cairo 自带的 sample,以及文泉驿正黑,生成了下面这个图。看起来还行,就是在老系统上装 cairo 依赖关系是大问题,新的项目上可以考虑。

From blog 配图
Topic: 技术

DELL 笔记本还是很好拆的

最近一段时间家里的笔记本放 x264 的片子总是有问题,时有停顿,双核CPU表现比我的老赛扬1.5G还差。偶尔还会突然死机,短时间内再也起不来,过一段时间才可以运行(现在想来,是温度过热的自动保护)

装了一个软件(Notebook Hardware Control),发现这个 1.8G 的CPU自始自终在800MHz的频率下运行。又找了个软件(RightMark CPU Clock Utility),强行让它在1.8G下运行,然后就看温度监控短时间内急剧升高到80多度,死机

今晚从 DELL 网站上下了一个 pdf,对照着把笔记本拆了——所以说家里有2台以上的PC还是很有必要的。大卸八块后把整个散热单元取下来除灰。

刷干净散热片和风扇后,才发现一个严峻的问题,以前的硅胶早就干了,现在手头哪里还有这玩意啊。然后怀着忐忑不安的心情装配回去...居然能启动。自动就运行在了 1.8G 频率上,平时大概CPU 40多度,看了一部片,工作中温度在60度以下,CPU Load 在60%-70%的样子,还是很满意滴。

邱可心小朋友在旁边指导参观了整个过程,并动手卸下并装配了几个螺丝。。。我也觉得PC比乐高有意思多了.

Topic: 技术

MTA 2.0 ?

From blog 配图

昨天有一组 bizanga.com (发音:bi-zan-ga)的人来访。本来以为他们又是一个 AntiSpam 解决方案提供商而已,但接触下来让我大跌眼镜——他们居然是一个,MTA 供应商!!

他们的方案是:提供高效的,灵活可配置的,已经预置 n 种知名 antispam antivirus 集成接口,n 种认证接口的 MTA。给客户带来的好处是进一步缩减硬件成本,以及管理成本。针对于 MTA 集群,他们也能做到一个中央服务器同时管理配置,并收集所有的连接信息,在各个服务器之间共享。

实际上他们的思路和 sohu 所做的挺吻合,把 MTA solution 分成两个部分,其一是MTA 服务器以及用户lookup/auth机制,另一个是内容检测机制。搜狐/Bizanga 负责第一部分,内容检测交给第三方厂商做。

Bizanga 的风格和我以前接触的邮件相关厂商不一样,演示用的是黑色的 Macbook,上面还跑了一个虚拟机!!!直接给我展示其 MTA 灵活配置的特性。它的 web 配置界面和 MTA 的紧密集成特性,给我留下了极为深刻的印象。总之他们号称自己的效率是 postfix 的 6 倍,我倒是不太怀疑,因为看得出他们在 MTA 层面下了很大的功夫。

难道 postfix 的性能已经如此不堪了吗?我带着这个疑问搜索了一下,发现这么一系列有趣的文章:Some thoughts on MTA architecture - Google Tech Talk 2008-06-02。学习了一下当今 MTA 界最新思潮,再结合历史我就释然了——当初 apache 是多么的如日中天,但后来一样是受到了 lighttpd/nginx 的强力挑战,最近又出了一个什么 cherokee,如今在 MTA 领域出现一个商业公司 bizanga 像当初 Zeus 那样挑战 postfix 也算正常。

不过它们的产品看起来虽好,我觉得并不适合我们。咳咳,至少对 coremail 系和 eyou 系出身的技术团队来说,MTA 方案没有什么吸引力。传统电信行业,或者 mail-hosting 企业我觉得更需要他们的帮助。还有,他们如果想在中国展开业务,需要和中国本地的 antispam 解决方案提供商有更多合作,我已经向它们推荐了汉启,不知道以后如何。

以后如果俺们有精力,说不定用 erlang 或 stackless python 搞一个 MTA 来玩玩,集成 web-admin 和 XMPP server,接口和 postfix 保持一致... 哈,也就是想想而已,反正今年是不可能有这个时间的了

Topic: 技术

反垃圾邮件年会感受

今天去参加反垃圾邮件年会,发现原来硕琦的周宏明居然调转枪头成了一个邮件营销企业的老总,这个事情立刻把我惊住了。

其实我和周宏明先生没有任何交往,只是在很多次相关会议中看到他风度翩翩的发言,那时候觉得还算是eyou的竞争对手,加上很显著的台湾味,所以就记下来了。但转眼间他就开始“发垃圾邮件”了,这个事情让我挺难以接受。

不过再看到我们的anti-spam技术合作伙伴(也可以说是供应商)的新名片上赫然印着"smart EDM",俺就有些无语了。

这个事情怎么说呢... 大概是 3,4 年前,我在eyou的一个内部业务讨论中抛出一个观点:单独的 anti-spam gateway 是没有长期市场的,anti-spam 技术最好成为 email system 的一部分,而不是作为独立的网关,否则很难利用用户使用 email 的信息进行更有效的过滤(比如利用地址本作白名单,个性化的贝叶斯处理);因此长期看,独立网关产品在技术上是没有什么竞争力的,不如集中精力专心发展单一的 webmail solution... 现在看这个细分行业的冬天是来了,虽然未必如我当初的判断逻辑,但大家纷纷改行从做盾去制矛却是一个非常尴尬的现状。回想起来,行业老大 ironport 甘愿被 cisco 收购是不是就预示着颓势的到来?

可能还有另一层原因,防御者(邮件运营者)和进攻者(大宗邮件发送者)对盾牌后面东西的价值认知是不一致的。这种状态下资源当然会朝进攻方面汇集。想想 eyou 的客户群体:学校/政府机关/电信/企业,大家都是以免费服务提供的立场来对待自己的用户,而发送者看到的是什么?消费者! 消费者! 消费者!

总之,对有志于用户运营的MSP来说,Anti-Spam技术一定要有自己的积累。完全交给第三方,很不让人放心。而对Anti-Spam企业来说,我觉得扩张期已经过了,保持成本,放低心态;有资金的可以考虑兼并,没资金的份额也不高的就及早抽身吧。

Topic: 商业 技术

tkhtml

From blog 配图

上期的 lwn 介绍了一个开源浏览器 hv3,它在保持了一个很小的体积同时,还通过了 ACID2 测试,这点就令老牌的 dillo 相形见绌。此外它有 win32 下的 build,这点也比 dillo 有亲和力,就是不支持中文。

最让我感兴趣的是 hv3 背后的 html layout 引擎 tkhtml 是用 C 完成的,如果做相关的工作,tkhtml 是一个不错的研究起点。

Topic: 技术

network 还是 networking

"network 还是 networking", 大家应该都是从麦田老师那里看来的。但什么是 network, 什么是 networking, 估计大部分人只是对这两个单词是朦朦胧胧有感觉,却难以用熟悉的母语表述。麦田老师在某次访谈中也仅仅简单的汉化为"网络化还是正在网络"——老实说,这样的翻译更容易让人摸不着头脑。

直到今天,听说 linux 2.6.28 发布的消息,于是习惯的去看Kernel Newbies 的更新描述,不经意的发现 kernel development 里对 network 和 networking 的区分

  • Networking
    1. tcp: Port redirection support for TCP
    2. ipv4: Implement IP_TRANSPARENT socket option
    3. ...
  • Network
    1. e1000e: add support for 82567LM-3 and 82567LF-3 (ICH10D) parts...
    2. libertas_tf: New driver supporting "Marvell 8xxx Libertas WLAN driver support with thin firmware"...
    3. ...
  • 从这个角度看 Network 和 Networking 该怎么翻译就呼之欲出了:"网络还是互联"?

    Topic: 商业 技术

    口琴

    有一句广告词我很喜欢——男人,要对自己好一点。本着这个原则,在圣诞前夕,我给自己买了一个小礼物,SUZUKI 口琴一支,40 元人民币。(看样子,日本大公司真是什么都做啊。不过这也是国产的,要不然就不会是这个价位了)这是我的第三支口琴,虽然我技术很烂,不过口琴倒挺多。不是我奢侈,这其中也是有原因滴。

    第一支买得很早。大概是 92/93 年左右,牌子是国光,如果没记错价格应该是 7 块。

    为什么没事买什么口琴呢,估计是我很小的时候听过我四姨夫吹口琴,这在我的潜意识里应该对我影响挺大,我觉得这个东东应该不算太难玩,所以想来想去,觉得口琴是唯一一种不需要老师教,弄出声音来也不会太难听的而且能买得起的乐器,另外,它体型小,便于隐匿。

    我从小有一个词听的比较多,玩物丧志。专门买个乐器来玩,特别是在学业越来越紧张的初中毕业高中阶段,这估计是会丧志的。丧不丧志的我可以不管,可是我还是要考虑父母的感受嘛,不是我太尊敬父母,而是这感受直接影响到我能不能玩这个乐器。如果我弄把吉他回来,藏也没处藏,父母天天看着这个东西,肯定总有一天会给扔了,所以弄个小的,眼不见心不烦,大家相安无事。

    在我的记忆中,商店里面的口琴只有一种,就是我买的国光牌重音口琴。7 块钱在那个时候不比现在的 40 元少,在那个时候,一个十来岁的孩子口袋里有这么多钱,也知足了。口琴买回来了,没有老师,没有教材,只有随琴附送的一本薄薄几页的小册子,告诉我低音 1 到高音 7 的位置以及几种常用的演奏技巧。我对自己也没什么要求,能把首歌连续地吹出来就行,没谱子,自己边吹边找音调,慢慢的,也对付出几首歌的谱子。不过,在那个时候,吹口琴的时间的确是很少,每天的作业就够我受的了。这第一支口琴的作用也就是满足了当年的我的一个小小的愿望。

    我的技术那是很菜,自己听听还可,要是天天在别人耳旁这么吹,是会招来鞋子的,所以我大学期间,几乎忘掉口琴这回事了。在天津的时候,有独自居住的条件,有次我回老家想起这件事,把尘封的口琴找出来,洗干净,晾在一边,准备带去天津好好研习。结果我老爸对我这种行为好像不是很理解。我也懒得深究不理解的原因,既然不理解,那我就不带了,到天津我再买一个新的。

    于是我有了第二个口琴,如果没记错,这个口琴应该是在同安道上的一个店买的,15元左右。当时我踌躇了很久,是买一个贵的还是买个便宜的呢?买个贵的好处是,可能会因为它贵,不忍闲着它,多练习练习,坏处是,也有可能买回来束之高阁,浪费钱。权衡利弊,还是买了个便宜的。天鹅牌,依然是重音口琴,跟原来那个国光的除了琴身上刻的 logo 不一样,其他一模一样,我后来一直怀疑这两个是不是都是 OEM 的啊。

    这个口琴我吹得依旧不多,不过比之前的第一支相对还是多多了。我把它从天津带到了北京,想起来会玩玩。因为没有老师也没有去买过教材,我不知道如何循序渐进。我玩口琴仅满足于把平常听得烂熟的旋律优美又不复杂的歌曲不看谱子慢慢试着吹出来,这跟我哥弹钢琴有本质的区别,非要做个类比,大概是剑宗跟气宗的区别。不过我和他都也是没办法。如果他只满足把一首首歌弹出来,电子琴就绰绰有余了,既然买了钢琴就要高标准严要求,而且钢琴的课本一抓一大把,网上的视频也很多,方便循序渐进。钢琴的示范也相对比较明了,可口琴就费劲了,别人大口深含着口琴,高手需要通过舌头打拍子,我看视频永远看不到这其中的玄妙,自己每次想体会一把,搞得口水流得哪哪都是,也仍旧是摸不着门。

    上口琴的网站,看到有介绍口琴的分类的。这我才发现我一直在犯一个错误——把重音口琴的重读成 zhong(四声)(虽然我也不知道怎么个"重音"法),其实应该读 chong(二声)。大家常见的口琴基本上都是复音口琴。我买的重音口琴是复音口琴的一种。口琴分上下两排,普通的复音口琴上下两排格的发出的音是一样的,重音口音上排格比下排格高八度。重音口琴的这个特点我一直有体会,现在我才搞明白,原来重音的重就是这么来的。不过有一个很明显的事实,我以前在店里没有看到过普通的复音口琴,要不然怎么也不会一点印象也没有。这是为什么呢?把这两种口琴摆一起很困难吗?我现在深刻怀疑我两次买口琴时的商店压根也分不清这两种口琴。网站上还说入门应该从普通的复音口琴练起,我于是找到给自已再买一支口琴的借口。

    上淘宝搜了一下,觉得铃木 study-24 C 调复音口琴这个还不错,关键是总算不是同一个 OEM 出品了。买回来后,吹了没两下就发现声音明显比之前的国光和天鹅好听,更悠扬一些,而且吹的时候琴身也会随着声音微微振动,这感觉很不错。再就是这个口琴明显比前两个口琴重,不知道是重在琴格上还是里面铜片上了。之前在网上看到有人说口琴的声音比较尖,比钢琴的标准 C 高八度,我以前没这种感觉,现在算是体会出来了。重音口琴的下排格发出的声音是正常的,这支复音口琴的两排发出的声音都跟重音口琴的上排声音一样,1 相当于钢琴 C 的高音 1。以后找调子要费点劲了,还需要再适应适应。

    别的不说了,上图比较

    天鹅和铃木2

    天鹅和铃木3

    我的第一支口琴最后还是被 dada 从湖北搬来了北京,我最近见到它,已经被大卸八块了~~~

    sohu 邮件支持 Gears 做附件断点上传了

    附件断点上次这个需求很早就提出了,但我一直不觉得我们邮件中心来做一个浏览器插件有什么可持续性,因此没有多想。直到 gears 0.4 发布前夕,看到了它的 feature list,包括了 blob upload 的功能,这才决定利用这个特性来实现断点上载。

    除了技术外,还有一个商业上的考虑就是在 sohu 的产品里,去引用一个来自 google 的服务是否好呢?我的意见是完全没有问题,我并不觉得这样会伤害我们自己的品牌或者商誉,反而是有助于传播我们开放的形象。当然,慎重起见,我也和KCN交换了这个观点,他并不反对我这么做。

    从产品的角度,我们并没有在免费邮箱里面去提示用户安装Gears——毕竟现在只支持10M附件,在这个容量级别,需要断点上载的必要性并不大,因此也没有必要在这里干扰用户——只不过是如果你浏览器有Gears支持的话,我们自动利用Gears的特性上载。在有更大附件服务的 VIP 邮箱,以及未来的网络U盘产品,是会鼓励用户安装Gears的。

    我想未来我们可能会更多的利用来自 google,或者其它厂商的网络API,来完善我们的邮件系统。当然,我们也会逐步开放自己的 API,以及一部分代码滴。

    Topic: 商业 技术

    iconv(3)

    iconv 可能是我遇过的最让人困惑的C标准库函数了——因为它竟然一次性的返回 5 个值,如果算上全局变量 errno 的话,那就是 6 个(如果你知道还有哪个 libc 函数能超过它的,请告诉我)。而作为调用者,必须对返回的 6 个值逐一检查,然后,OMG,可能还需要再调用 iconv 继续转码...如此反复。

    所以每当我需要在 C 里面 iconv 一个字符串的话,我会去找 php 4.x 的源代码(现在最新应该是 4.4.9),从 ext/iconv/iconv.c 里面 Copy&Paste 一段代码,再自己简单包装一下使用。

    在上周我帮一个程序员提供这个函数包装的时候,我不禁开始思考怎么会有一个如此违背 UNIX 设计哲学的函数存在,后来想到两种可能。一个是字符编码转换这件事情,本来就是一个不那么 UNIX 的操作,再牛的天才,也只能如此设计接口;另一个可能是这个函数完全是 UNIX 商业化过程中为了向非 ANSI 字符语种国家推广,而由一个标准化委员会搞出来的怪物。

    如果对 iconv 使用的复杂程度还没有一个感性认识的话,从 PHP 搞来的这段东西会帮助理解这一点:

    1. /*
    2. --------------------------------------------------------------------
    3.                   The PHP License, version 3.01
    4. Copyright (c) 1999 - 2008 The PHP Group. All rights reserved.
    5. --------------------------------------------------------------------
    6.  
    7.      "This product includes PHP software, freely available from
    8.      <<a href="http://www.php.net/software/>".
    9. */
    10. #include">http://www.php.net/software/>".
    11. */
    12. #include</a> <stdlib.h>
    13. #include <string.h>
    14. #include <iconv.h>
    15. #include <errno.h>
    16.  
    17. //from PHP 4.4.9 ext/iconv/iconv.c
    18. //为了便于在 blog 上表现,把返回简化成 3, 2, 1, 0, -1, -2, -3
    19. //返回值非零表示转码失败,其中大于零则说明返回的 out 不需要 free
    20. //这段代码只在 Linux 下测试
    21. int _iconv_string(const char *in_p, size_t in_len, char **out, size_t *out_len, const char *in_charset, const char *out_charset)
    22. {
    23.     iconv_t cd;
    24.     size_t in_left, out_size, out_left;
    25.     char *out_p, *out_buf, *tmp_buf;
    26.     size_t bsz, result = 0;
    27.     int retval = 0;
    28.  
    29.     cd = iconv_open(out_charset, in_charset);
    30.     if (cd == (iconv_t)(-1)) {
    31.         if (errno == EINVAL) {
    32.             return 1; // WRONG_CHARSET
    33.         } else {
    34.             return 2;
    35.         }
    36.     }
    37.  
    38.     in_left= in_len;
    39.     out_left = in_len + 32; /* Avoid realloc() most cases */
    40.     out_size = 0;
    41.     bsz = out_left;
    42.     out_buf = (char *)malloc(bsz+1);
    43.     out_p = out_buf;
    44.  
    45.     while (in_left > 0) {
    46.         result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left);
    47.         out_size = bsz - out_left;
    48.         if (result == (size_t)(-1)) {
    49.             if (errno == E2BIG && in_left > 0) {
    50.                 /* converted string is longer than out buffer */
    51.                 bsz += in_len;
    52.                 tmp_buf = (char*)realloc(out_buf, bsz+1);
    53.                 if (tmp_buf != NULL) {
    54.                     out_p = out_buf = tmp_buf;
    55.                     out_p += out_size;
    56.                     out_left = bsz - out_size;
    57.                     continue;
    58.                 }
    59.             }
    60.         }
    61.         break;
    62.     }
    63.     if (result != (size_t)(-1)) {
    64.         /* flush the shift-out sequences */
    65.         for (;;) {
    66.             result = iconv(cd, NULL, NULL, (char **) &out_p, &out_left);
    67.             out_size = bsz - out_left;
    68.             if (result != (size_t)(-1)) {
    69.                 break;
    70.             }
    71.             if (errno == E2BIG) {
    72.                 bsz += 16;
    73.                 tmp_buf = (char *)realloc(out_buf, bsz);
    74.                 if (tmp_buf == NULL) {
    75.                     break;
    76.                 }
    77.                 out_p = out_buf = tmp_buf;
    78.                 out_p += out_size;
    79.                 out_left = bsz - out_size;
    80.             } else {
    81.                 break;
    82.             }
    83.         }
    84.     }
    85.     iconv_close(cd);
    86.     if (result == (size_t)(-1)) {
    87.         switch (errno) {
    88.             case EINVAL:
    89.                 retval = -1;
    90.                 break;
    91.             case EILSEQ:
    92.                 retval = -2;
    93.                 break;
    94.             case E2BIG:
    95.                 retval = -3;
    96.                 break;
    97.             default:
    98.                 free(out_buf);
    99.                 return 3;
    100.         }
    101.     }
    102.     *out_p = '\0';
    103.     *out = out_buf;
    104.     *out_len = out_size;
    105.     return retval;
    106. }
    107.  
    108. //qyb wrap _iconv_string
    109. //由调用者负责 free 返回值
    110. char *iconv_string(const char *string, const char *in_charset, const char *out_charset)
    111. {
    112.     char *result;
    113.     int retval;
    114.     size_t in_len, out_len;
    115.     in_len = strlen(string);
    116.     retval = _iconv_string(string, in_len, &result, &out_len, in_charset, out_charset);
    117.     if (retval > 0) {
    118.         return NULL;
    119.     }
    120.     return result;
    121. }
    Topic: 技术
    订阅 RSS - 技术 | BT的花