Evolution邮件客户端中是使用一种叫“provider”的方式来使用各种不同的邮件协议的。“provider”的使用,使得上层的代码进行邮件的各种操作的时候,底层协议的不同对其是完全透明的。这样的方法使代码具有很强的扩展性,可以很方便地给程序提供新协议的支持。“provider”是一种插件机制。
Camel是Evolution中是现基本功能的库。Camel中Services被分为两种:Store和Transport,Store用来读取邮件,而Transport则用来发送邮件。在具体使用时,用户只用负责从CamelStore里面读数据和往CamelTransport中发数据就行了,具体的与服务器通信的细节,则是在其派生类中定义的(也就是在provider中所要做的)。Camel中定义了调用provider的时候使用的接口,也就是说,只要实现provider的时候按照这样的接口来实现它,那么它就是一个合法的provider。首先,provider必须提供一个void camel_provider_module_init(void)的函数,在这个函数中必须填充一个CamelProvider的结构体变量,并用camel_provider_register()函数注册之。
结构体定义如下:
以POP3的provider为例,它首先简单的填充了那些固定不变的信息:
剩下的部分被放到了 camel_provider_module_init(void)函数中实现:
我觉得最值得一提的是这一句:
pop3_provider.object_types[CAMEL_PROVIDER_STORE] = camel_pop3_store_get_type();
camel_pop3_store_get_type();能返回一个CamelType类型,而取得这个类型值的代码可以根据这个类型之创建一个CamelPop3Store类型的对象, CamelPop3Store正是CamelStore的派生类。在执行最后一条语句 camel_provider_register(&pop3_provider);以后,就等于说向主程序注册了这个provider了,主程序可以通过一个通用的方法来获得CamelPop3Store提供的服务,而系统只知道它是一个CamelStore。
CamelPop3Store的定义可以些在另外的源文件里面,其做的最多的一件事就是,默默地实现了基类中定义的大量虚函数,而其自己只增加了少量的几个函数。
那么,主函数都是怎么知道有那些provider的呢?它只是简单地打开一个默认的路径,搜索里面的所有文件。每个provider包括一个动态库文件和文件名与之对应的*.urls文件,这个文件很简单,只是写了provider提供的协议的名字。主函数可以根据需要,动态地把provider载入盗内存中使用。
Camel是Evolution中是现基本功能的库。Camel中Services被分为两种:Store和Transport,Store用来读取邮件,而Transport则用来发送邮件。在具体使用时,用户只用负责从CamelStore里面读数据和往CamelTransport中发数据就行了,具体的与服务器通信的细节,则是在其派生类中定义的(也就是在provider中所要做的)。Camel中定义了调用provider的时候使用的接口,也就是说,只要实现provider的时候按照这样的接口来实现它,那么它就是一个合法的provider。首先,provider必须提供一个void camel_provider_module_init(void)的函数,在这个函数中必须填充一个CamelProvider的结构体变量,并用camel_provider_register()函数注册之。
结构体定义如下:
- typedef struct {
- /* Provider name used in CamelURLs. */
- char *protocol;
- /* Provider name as used by people. (May be the same as protocol) */
- char *name;
- /* Description of the provider. A novice user should be able
- * to read this description, and the information provided by
- * an ISP, IS department, etc, and determine whether or not
- * this provider is relevant to him, and if so, which
- * information goes with it.
- */
- char *description;
- /* The category of message that this provider works with.
- * (evolution-mail will only list a provider in the store/transport
- * config dialogs if its domain is "mail".)
- */
- char *domain;
- /* Flags describing the provider, flags describing its URLs */
- int flags, url_flags;
- /* The ConfEntry and AutoDetect functions will probably be
- * DEPRECATED in a future release */
- /* Extra configuration information */
- CamelProviderConfEntry *extra_conf;
- /* auto-detection function */
- CamelProviderAutoDetectFunc auto_detect;
- /* CamelType(s) of its store and/or transport. If both are
- * set, then they are assumed to be linked together and the
- * transport type can only be used in an account that also
- * uses the store type (eg, Exchange or NNTP).
- */
- CamelType object_types[CAMEL_NUM_PROVIDER_TYPES];
- /* GList of CamelServiceAuthTypes the provider supports */
- GList *authtypes;
- CamelObjectBag *service_cache[CAMEL_NUM_PROVIDER_TYPES];
- GHashFunc url_hash;
- GCompareFunc url_equal;
- /* gettext translation domain (NULL for providers in the
- * evolution source tree).
- */
- char *translation_domain;
- /* This string points to the provider's gconf key value
- */
- const char *license;
- /* This holds the license file name [ ascii text format ] containing
- * the license agreement. This should be the absolute file path. This
- * is read only when the HAS_LICENSE flag is set
- */
- const char *license_file;
- /* Private to the provider */
- void *priv;
- } CamelProvider;
- static CamelProviderConfEntry pop3_conf_entries[] = {
- { CAMEL_PROVIDER_CONF_SECTION_START, "storage", NULL,
- N_("Message storage") },
- { CAMEL_PROVIDER_CONF_CHECKBOX, "keep_on_server", NULL,
- N_("Leave messages on server"), "0" },
- { CAMEL_PROVIDER_CONF_CHECKSPIN, "delete_after", NULL,
- N_("Delete after %s day(s)"), "0:1:7:365" },
- { CAMEL_PROVIDER_CONF_CHECKBOX, "disable_extensions", NULL,
- N_("Disable support for all POP3 extensions"), "0" },
- { CAMEL_PROVIDER_CONF_SECTION_END },
- { CAMEL_PROVIDER_CONF_END }
- };
- static CamelProvider pop3_provider = {
- "pop",
- N_("POP"),
- N_("For connecting to and downloading mail from POP servers."),
- "mail",
- CAMEL_PROVIDER_IS_REMOTE | CAMEL_PROVIDER_IS_SOURCE |
- CAMEL_PROVIDER_SUPPORTS_SSL,
- CAMEL_URL_NEED_USER | CAMEL_URL_NEED_HOST | CAMEL_URL_ALLOW_AUTH,
- pop3_conf_entries,
- /* ... */
- };
- void
- camel_provider_module_init(void)
- {
- CamelServiceAuthType *auth;
- pop3_provider.object_types[CAMEL_PROVIDER_STORE] = camel_pop3_store_get_type();
- pop3_provider.url_hash = camel_url_hash;
- pop3_provider.url_equal = camel_url_equal;
- pop3_provider.authtypes = camel_sasl_authtype_list (FALSE);
- auth = camel_sasl_authtype("LOGIN");
- if (auth)
- pop3_provider.authtypes = g_list_prepend(pop3_provider.authtypes, auth);
- pop3_provider.authtypes = g_list_prepend(pop3_provider.authtypes, &camel_pop3_apop_authtype);
- pop3_provider.authtypes = g_list_prepend(pop3_provider.authtypes, &camel_pop3_password_authtype);
- pop3_provider.translation_domain = GETTEXT_PACKAGE;
- camel_provider_register(&pop3_provider);
- }
camel_pop3_store_get_type();能返回一个CamelType类型,而取得这个类型值的代码可以根据这个类型之创建一个CamelPop3Store类型的对象, CamelPop3Store正是CamelStore的派生类。在执行最后一条语句 camel_provider_register(&pop3_provider);以后,就等于说向主程序注册了这个provider了,主程序可以通过一个通用的方法来获得CamelPop3Store提供的服务,而系统只知道它是一个CamelStore。
CamelPop3Store的定义可以些在另外的源文件里面,其做的最多的一件事就是,默默地实现了基类中定义的大量虚函数,而其自己只增加了少量的几个函数。
那么,主函数都是怎么知道有那些provider的呢?它只是简单地打开一个默认的路径,搜索里面的所有文件。每个provider包括一个动态库文件和文件名与之对应的*.urls文件,这个文件很简单,只是写了provider提供的协议的名字。主函数可以根据需要,动态地把provider载入盗内存中使用。