- 论坛徽章:
- 0
|
版本:gaim 2.0 beta 6
一、源码组织
gaim/console: gaim的文本界面
gaim/gtk: gaim的图形界面
gaim/libgaim: gaim的内核
gaim/libgaim/protocols: gaim支持的各协议
gaim/libgaim/plugins: 其他gaim插件(之所以说其他,是因为gaim的协议支持也是一种插件)
协议和插件的接口相关源码主要就在gaim/libgaim/下的plugin.h(c),prpl.h(c)四个文件中。
二、主要的数据结构
/*plugin.h*/
struct _GaimPluginInfo
{
unsigned int magic;
unsigned int major_version;
unsigned int minor_version;
GaimPluginType type;
char *ui_requirement;
unsigned long flags;
GList *dependencies;
GaimPluginPriority priority;
char *id;
char *name;
char *version;
char *summary;
char *description;
char *author;
char *homepage;
gboolean (*load)(GaimPlugin *plugin);
gboolean (*unload)(GaimPlugin *plugin);
void (*destroy)(GaimPlugin *plugin);
void *ui_info;
void *extra_info;
GaimPluginUiInfo *prefs_info;
GList *(*actions)(GaimPlugin *plugin, gpointer context);
};
struct _GaimPlugin
{
gboolean native_plugin; /**< Native C plugin. */
gboolean loaded; /**< The loaded state. */
void *handle; /**< The module handle. */
char *path; /**< The path to the plugin. */
GaimPluginInfo *info; /**< The plugin information. */
char *error;
void *ipc_data; /**< IPC data. */
void *extra; /**< Plugin-specific data. */
gboolean unloadable; /**< Unloadable */
GList *dependent_plugins; /**< Plugins depending on this */
};
/*prpl.h*/
struct _GaimPluginProtocolInfo
{
GaimProtocolOptions options; /**< Protocol options. */
GList *user_splits; /* A GList of GaimAccountUserSplit */
GList *protocol_options; /* A GList of GaimAccountOption */
GaimBuddyIconSpec icon_spec; /* The icon spec. */
const char *(*list_icon)(GaimAccount *account, GaimBuddy *buddy);
void (*list_emblems)(GaimBuddy *buddy, const char **se, const char **sw,
const char **nw, const char **ne);
char *(*status_text)(GaimBuddy *buddy);
void (*tooltip_text)(GaimBuddy *buddy, GaimNotifyUserInfo *user_info, gboolean full);
GList *(*status_types)(GaimAccount *account);
GList *(*blist_node_menu)(GaimBlistNode *node);
GList *(*chat_info)(GaimConnection *);
GHashTable *(*chat_info_defaults)(GaimConnection *, const char *chat_name);
void (*login)(GaimAccount *);
void (*close)(GaimConnection *);
int (*send_im)(GaimConnection *, const char *who,
const char *message,
GaimMessageFlags flags);
void (*set_info)(GaimConnection *, const char *info);
unsigned int (*send_typing)(GaimConnection *, const char *name, GaimTypingState state);
void (*get_info)(GaimConnection *, const char *who);
void (*set_status)(GaimAccount *account, GaimStatus *status);
void (*set_idle)(GaimConnection *, int idletime);
void (*change_passwd)(GaimConnection *, const char *old_pass,
const char *new_pass);
void (*add_buddy)(GaimConnection *, GaimBuddy *buddy, GaimGroup *group);
void (*add_buddies)(GaimConnection *, GList *buddies, GList *groups);
void (*remove_buddy)(GaimConnection *, GaimBuddy *buddy, GaimGroup *group);
void (*remove_buddies)(GaimConnection *, GList *buddies, GList *groups);
void (*add_permit)(GaimConnection *, const char *name);
void (*add_deny)(GaimConnection *, const char *name);
void (*rem_permit)(GaimConnection *, const char *name);
void (*rem_deny)(GaimConnection *, const char *name);
void (*set_permit_deny)(GaimConnection *);
void (*join_chat)(GaimConnection *, GHashTable *components);
void (*reject_chat)(GaimConnection *, GHashTable *components);
char *(*get_chat_name)(GHashTable *components);
void (*chat_invite)(GaimConnection *, int id,
const char *message, const char *who);
void (*chat_leave)(GaimConnection *, int id);
void (*chat_whisper)(GaimConnection *, int id,
const char *who, const char *message);
int (*chat_send)(GaimConnection *, int id, const char *message, GaimMessageFlags flags);
void (*keepalive)(GaimConnection *);
void (*register_user)(GaimAccount *);
void (*get_cb_info)(GaimConnection *, int, const char *who);
void (*get_cb_away)(GaimConnection *, int, const char *who);
void (*alias_buddy)(GaimConnection *, const char *who,
const char *alias);
void (*group_buddy)(GaimConnection *, const char *who,
const char *old_group, const char *new_group);
void (*rename_group)(GaimConnection *, const char *old_name,
GaimGroup *group, GList *moved_buddies);
void (*buddy_free)(GaimBuddy *);
void (*convo_closed)(GaimConnection *, const char *who);
const char *(*normalize)(const GaimAccount *, const char *);
void (*set_buddy_icon)(GaimConnection *, const char *cached_path);
void (*remove_group)(GaimConnection *gc, GaimGroup *group);
char *(*get_cb_real_name)(GaimConnection *gc, int id, const char *who);
void (*set_chat_topic)(GaimConnection *gc, int id, const char *topic);
GaimChat *(*find_blist_chat)(GaimAccount *account, const char *name);
GaimRoomlist *(*roomlist_get_list)(GaimConnection *gc);
void (*roomlist_cancel)(GaimRoomlist *list);
void (*roomlist_expand_category)(GaimRoomlist *list, GaimRoomlistRoom *category);
gboolean (*can_receive_file)(GaimConnection *, const char *who);
void (*send_file)(GaimConnection *, const char *who, const char *filename);
GaimXfer *(*new_xfer)(GaimConnection *, const char *who);
gboolean (*offline_message)(const GaimBuddy *buddy);
GaimWhiteboardPrplOps *whiteboard_prpl_ops;
int (*send_raw)(GaimConnection *gc, const char *buf, int len);
char *(*roomlist_room_serialize)(GaimRoomlistRoom *room);
};
解释:
_GaimPlugin中的成员info,是一个指向_GaimPluginInfo类型的指针;而_GaimPlugin和 _GaimPluginInfo,各有一个void*型的指针extra和extra_info,而_GaimPluginProtocolInfo的内容,主要就是一些函数指针。在运行时刻,gaim的主程序对每一个插件维护一个GaimPlugin(typedef struct _GaimPlugin GaimPlugin,下同)的结构,而每一个插件自己则维护一个GaimPluginInfo的结构,和一个插件特定的结构(对于协议插件就是 GaimPluginProtocolInfo,协议插件也是一种插件嘛)。下面将要看到,在插件装载时,主程序传递给插件一个GaimPlugin的指针,由插件自己将其中的info指向自己的GaimPluginInfo结构,这样通过GaimPlugin-->GaimPluginInfo- ->GaimPluginProtocolInfo,gaim主程序就可以分别调用各协议的特定代码。
三、运行代码:
/*gaim/libgaim/plugin.c*/
void
gaim_plugins_probe(const char *ext)
{
......
/* Probe plugins */
for (cur = search_paths; cur != NULL; cur = cur->next)
{
......
while ((file = g_dir_read_name(dir)) != NULL)
{
path = g_build_filename(search_path, file, NULL);
if (ext == NULL || has_file_extension(file, ext))
plugin = gaim_plugin_probe(path);
......
}
}
......
}
GaimPlugin *
gaim_plugin_probe(const char *filename)
{
......
plugin = gaim_plugin_new(has_file_extension(filename, G_MODULE_SUFFIX), filename);
......
plugin->handle = g_module_open(filename, G_MODULE_BIND_LOCAL);
......
if (!g_module_symbol(plugin->handle, "gaim_init_plugin",
&unpunned))
.......
gaim_init_plugin = unpunned;
.......
if (!gaim_init_plugin(plugin) || plugin->info == NULL)
.......
/*如果是协议插件,那么还需要至少实现了list_icon,login,close三个函数*/
if (plugin->info->type == GAIM_PLUGIN_PROTOCOL)
{
/* If plugin is a PRPL, make sure it implements the required functions */
if ((GAIM_PLUGIN_PROTOCOL_INFO(plugin)->list_icon == NULL) ||
(GAIM_PLUGIN_PROTOCOL_INFO(plugin)->login == NULL) ||
(GAIM_PLUGIN_PROTOCOL_INFO(plugin)->close == NULL))
......
return plugin;
}
解释:
扫描指定目录,对每一个动态库文件(*.so),寻找并执行其中的gaim_init_plugin()。
但是gaim_init_plugin的实现代码并不在各插件实现代码(gaim/libgaim/protocols(plugins)/...)中,而是在gaim/libgaim/plugin.h中定义了一个宏
# define GAIM_INIT_PLUGIN(pluginname, initfunc, plugininfo) \
G_MODULE_EXPORT gboolean gaim_init_plugin(GaimPlugin *plugin); \
G_MODULE_EXPORT gboolean gaim_init_plugin(GaimPlugin *plugin) { \
plugin->info = &(plugininfo); \
initfunc((plugin)); \
return gaim_plugin_register(plugin); \
}
所以各插件只需要包含这个宏,并传递参数就行了。
四、协议实现举例
以msn为例
/*gaim/libgaim/protocols/msn/msn.c*/
static GaimPluginProtocolInfo prpl_info =
{
OPT_PROTO_MAIL_CHECK,
NULL, /* user_splits */
NULL, /* protocol_options */
{"png", 0, 0, 96, 96, 0, GAIM_ICON_SCALE_SEND}, /* icon_spec */
msn_list_icon, /* list_icon */
msn_list_emblems, /* list_emblems */
msn_status_text, /* status_text */
msn_tooltip_text, /* tooltip_text */
msn_status_types, /* away_states */
msn_blist_node_menu, /* blist_node_menu */
NULL, /* chat_info */
NULL, /* chat_info_defaults */
msn_login, /* login */
msn_close, /* close */
msn_send_im, /* send_im */
NULL, /* set_info */
msn_send_typing, /* send_typing */
msn_get_info, /* get_info */
msn_set_status, /* set_away */
msn_set_idle, /* set_idle */
NULL, /* change_passwd */
msn_add_buddy, /* add_buddy */
NULL, /* add_buddies */
msn_rem_buddy, /* remove_buddy */
NULL, /* remove_buddies */
msn_add_permit, /* add_permit */
msn_add_deny, /* add_deny */
msn_rem_permit, /* rem_permit */
msn_rem_deny, /* rem_deny */
msn_set_permit_deny, /* set_permit_deny */
NULL, /* join_chat */
NULL, /* reject chat invite */
NULL, /* get_chat_name */
msn_chat_invite, /* chat_invite */
msn_chat_leave, /* chat_leave */
NULL, /* chat_whisper */
msn_chat_send, /* chat_send */
msn_keepalive, /* keepalive */
NULL, /* register_user */
NULL, /* get_cb_info */
NULL, /* get_cb_away */
NULL, /* alias_buddy */
msn_group_buddy, /* group_buddy */
msn_rename_group, /* rename_group */
NULL, /* buddy_free */
msn_convo_closed, /* convo_closed */
msn_normalize, /* normalize */
msn_set_buddy_icon, /* set_buddy_icon */
msn_remove_group, /* remove_group */
NULL, /* get_cb_real_name */
NULL, /* set_chat_topic */
NULL, /* find_blist_chat */
NULL, /* roomlist_get_list */
NULL, /* roomlist_cancel */
NULL, /* roomlist_expand_category */
msn_can_receive_file, /* can_receive_file */
msn_send_file, /* send_file */
msn_new_xfer, /* new_xfer */
NULL, /* offline_message */
NULL, /* whiteboard_prpl_ops */
NULL, /* send_raw */
NULL, /* roomlist_room_serialize */
};
static GaimPluginInfo info =
{
GAIM_PLUGIN_MAGIC,
GAIM_MAJOR_VERSION,
GAIM_MINOR_VERSION,
GAIM_PLUGIN_PROTOCOL, /**< type */
NULL, /**< ui_requirement */
0, /**< flags */
NULL, /**< dependencies */
GAIM_PRIORITY_DEFAULT, /**< priority */
"prpl-msn", /**< id */
"MSN", /**< name */
VERSION, /**< version */
/** summary */
N_("MSN Protocol Plugin"),
/** description */
N_("MSN Protocol Plugin"),
"Christian Hammond <chipx86@gnupdate.org>", /**< author */
GAIM_WEBSITE, /**< homepage */
msn_load, /**< load */
msn_unload, /**< unload */
NULL, /**< destroy */
NULL, /**< ui_info */
&prpl_info, /**< extra_info */
/*这里,指向自己的GaimProtocolPluginInfo*/
NULL, /**< prefs_info */
msn_actions
};
static void
init_plugin(GaimPlugin *plugin)
{
......
}
GAIM_INIT_PLUGIN(msn, init_plugin, info);
prpl_info的成员,为库内的函数指针,比如msn_list_icon:
static const char *
msn_list_icon(GaimAccount *a, GaimBuddy *b)
{
return "msn";
}
[ 本帖最后由 shaver 于 2007-3-22 11:28 编辑 ] |
|