免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1393 | 回复: 1
打印 上一主题 下一主题

Gaim 2.0的协议插件接口 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-03-22 11:18 |只看该作者 |倒序浏览
版本: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 编辑 ]

论坛徽章:
0
2 [报告]
发表于 2007-03-22 11:22 |只看该作者
原来发在我的博客了。但考虑到那里看的人少,所以又重复发在这里,希望版主不要怪罪,也希望能对大家有用。

[ 本帖最后由 shaver 于 2007-3-22 11:24 编辑 ]
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP