TinyMail研究—Camel-lite的插件系统
转载时请注明出处和作者联系方式:http://blog.csdn.net/absurd
作者联系方式:李先静<xianjimli at hotmail dot com>
更新时间:2007-4-19
TinyMail是一套针对移动设备设计的邮件系统框架,为了达到最大的灵活性,它采用了很多设计模式和先进的编程技术,让框架的每一部分都可以定制和配置。TinyMail流行的趋势非常明显,Nokia770/800和GPE Phone Edition等项目中都使用了它。因为我们也要开发邮件系统,所以花了几天时间去研究它的实现,这里记录一些研究笔记,供有兴趣的朋友参考。本文介绍一下Camel-lite的插件系统。
邮件的收/发协议有好几种,比如SMTP、POP和IMAP等等,Tinymail并不依赖于特定的收/发协议,这些协议都是以插件的方式加入进来的,扩展和裁减都很方便。Tinymail把协议的实现称为提供者(provider)。
提供者(provider)可以分为两类:STORE和TRANSPORT。前者实现CamelStore接口,用于邮件的接收,比如POP3和IMAP。后者实现CamelTransport接口,用于邮件的发送,比如SMTP和Sendmail。
CamelProvider定义了provider的公共数据结构,其中包括像协议、名称、描述、配置和许可证等等信息,其中最重要的是object_types成员,它描述了STORE或TRANSPORT的类型,用它来创建协议实现的实例。
每个provider都以独立的共享库方形提供,并且export出camel_provider_module_init函数,在该函数内,provider调用camel_provider_register向系统注册自己,只有注册之后才能被使用者使用。而系统在初始化时,调用camel_provider_init去加载所有的provider。
CamelService是STORE和TRANSPORT共同的基类,它定义了一些两者都要实现的虚函数,比如connect/ disconnect用于建立和断开连接,cancel_connect用于取消连接,query_auth_ types用于查询认证类型。
CamelTransport是发送协议必须实现的接口,它只有一个函数send_to,它的参数包括邮件、发件人和收件人等信息。
CamelStore是接收协议必须实现的接口,它和IMAP能很好的对应起来。它的要求看起来非常复杂,它并没有提供接收邮件的函数,相反它提供了一些管理folder的函数。要接收邮件,先用get_folder得到CamelFolder,然后调用CamelFolder的函数get_message才行。
下面的例子展示了发送邮件的方法:
static char *types[] = { "to", "cc", "bcc" }; void sendMail(CamelMimeMessage *msg, CamelException *ex) { CamelInternetAddress *from, *addr, *to; CamelTransport *trans; if (camel_mime_message_get_from(msg) == NULL) { camel_exception_setv(ex, CAMEL_EXCEPTION_SYSTEM, _("Cannot send message: No from address set"); return; } trans = (CamelTransport *)camel_session_get_service(session, "smtp://localhost/", ex); if (camel_exception_is_set(ex)) return; camel_service_connect(trans, ex); if (camel_exception_is_set(ex)) goto noconnect; to = camel_internet_address_new(); for (i=0;i<sizeof(types)/sizeof(types[0]);i++) { CamelInternetAddress *addr = camel_mime_message_get_recipients(msg, types[i]); if (addr) camel_address_cat(to, addr); } camel_transport_send_to(trans, msg, camel_mime_message_get_from(msg), to, ex); camel_object_unref(to); camel_transport_disconnect(trans, FALSE, NULL); noconnect: camel_object_unref(trans); } |
下面的例子展示了接收邮件的方法:
#include <camel/camel.h> #include <camel/camel-store.h> #include <camel/camel-session.h> #include <camel/camel-folder.h> int main(int argc, char* argv[]) { g_type_init(); g_thread_init(NULL); camel_init(NULL, 0); camel_provider_init(); CamelException* ex = camel_exception_new(); CamelSession* session = CAMEL_SESSION(camel_object_new(CAMEL_SESSION_TYPE)); camel_session_construct(session, "/tmp"); CamelStore* store = CAMEL_STORE(camel_session_get_service_connected(session, "pop://topmailtester:top321@pop.sohu.com", CAMEL_PROVIDER_STORE, ex)); CamelFolder* inbox = camel_store_get_inbox(store, ex); GPtrArray* uids = camel_folder_get_uids(inbox); int i = 0; for(i = 0; i < uids->len; i++) { CamelMimeMessage* message = camel_folder_get_message(inbox, uids->pdata[i], CAMEL_FOLDER_RECEIVE_FULL, 0, ex); camel_mime_message_dump(message, 1); CamelStream* fs = camel_stream_fs_new_with_name(uids->pdata[i], O_CREAT|O_RDWR, 0664); camel_data_wrapper_write_to_stream(CAMEL_DATA_WRAPPER(message), fs); camel_object_unref(CAMEL_OBJECT(fs)); camel_object_unref(CAMEL_OBJECT(message)); printf("%p/n", uids->pdata[i]); } camel_folder_free_uids(inbox, uids); camel_object_unref(CAMEL_OBJECT(store)); camel_object_unref(CAMEL_OBJECT(session)); camel_exception_free(ex); return 0; } |
参考资料:
~~end~~