使用libpurple函数库接入服务器

代码;

#define CUSTOM_USER_DIRECTORY  "/dev/null"					// 定义用户目录
#define CUSTOM_PLUGIN_PATH ""							// 定义插件目录
#define PLUGIN_SAVE_PREF "/purple/nullclient/plugins/saved"		// 定义插件头目录
#define UI_ID "nullclient"										// 定义用户接口ID
#include <purple.h>											// 包含libpurple库
#include <glib.h>											// 包含GLib库
#include <signal.h>
#include <string.h>
#include <unistd.h>
#define PURPLE_GLIB_READ_COND  (G_IO_IN | G_IO_HUP | G_IO_ERR)		// 定义GLib读成员
#define PURPLE_GLIB_WRITE_COND (G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL)
														// 定义GLib写成员
typedef struct _PurpleGLibIOClosure {							// 该结构用于作为回调函数参数
   PurpleInputFunction function;								// 函数名
   guint result;												// 返回结果
   gpointer data;											// 数据参数
} PurpleGLibIOClosure;




static void purple_glib_io_destroy(gpointer data)					// 该函数用于清除数据
{
   g_free(data);											// 释放data所指向的内存空间
}

static gboolean purple_glib_io_invoke(GIOChannel *source,
                                   GIOCondition condition,
                                   gpointer data)				// 调用GLib输入输出接口
{
   PurpleGLibIOClosure *closure = data;							// 创建libpurple输入输出终止符
   PurpleInputCondition purple_cond = 0;							// 创建libpurple输入条件对象
   if (condition & PURPLE_GLIB_READ_COND)					// 判断条件是否为读取
      purple_cond |= PURPLE_INPUT_READ;					// 将libpurple输入条件对象设为读取
   if (condition & PURPLE_GLIB_WRITE_COND)					// 判断条件是否为写入
      purple_cond |= PURPLE_INPUT_WRITE;					// 将libpurple输入条件对象设为写入
   closure->function(closure->data, g_io_channel_unix_get_fd(source),
           purple_cond);										// 调用回调函数执行输入输出操作
   return TRUE;
}

static guint glib_input_add(gint fd,
                         PurpleInputCondition condition,
                         PurpleInputFunction function,
                         gpointer data)						// 加入一个GLib输入接口
{
   PurpleGLibIOClosure *closure = g_new0(PurpleGLibIOClosure, 1);	// 创建libpurple输入输出终止符
   GIOChannel *channel;										// 声明GLib通道对象
   GIOCondition cond = 0;									// 声明GLib输入输出条件
   closure->function = function;								// 定义回调函数
   closure->data = data;										// 定义数据指针
   if (condition & PURPLE_INPUT_READ)						// 判断条件是否为读取
      cond |= PURPLE_GLIB_READ_COND; 					// 将libpurple输入条件对象设为读取
   if (condition & PURPLE_INPUT_WRITE) 						// 判断条件是否为写入
      cond |= PURPLE_GLIB_WRITE_COND; 					// 将libpurple输入条件对象设为写入
   channel = g_io_channel_unix_new(fd);							// 创建GLib通道
   closure->result = g_io_add_watch_full(channel,
                                      G_PRIORITY_DEFAULT,
                                      cond,
                                      purple_glib_io_invoke,
                                      closure,
                                      purple_glib_io_destroy);		// 设置通道中的回调函数
   g_io_channel_unref(channel);								// 将通道对象托管
   return closure->result;
}

static PurpleEventLoopUiOps glib_eventloops = 					// 定义GLib事件循环
{
   g_timeout_add,											// 超时处理
   g_source_remove,										// 源删除
   glib_input_add,											// 添加输入管道
   g_source_remove,										// 源删除
   NULL,
#if GLIB_CHECK_VERSION(2,14,0)								// 判断GLib版本是否为2.14.0
   g_timeout_add_seconds,									// 超时秒数
#else
   NULL,
#endif
   NULL
};

static void null_write_conv(PurpleConversation *conv,				// 会话标识符
                         const char *who,						// 好友ID
                         const char *alias,						// 昵称
                         const char *message,					// 消息
                         PurpleMessageFlags flags,				// 消息类型
                         time_t mtime)							// 发送时间
{
   const char *name;										// 用于保存好友名称
   if (alias && *alias)										// 判断存在好友昵称
      name = alias;											// 将好友名称设为昵称
   else if (who && *who)										// 判断好友ID存在
      name = who;											// 将好友名称设为好友ID
   else
      name = NULL;
   printf("(%s) %s %s: %s\n", purple_conversation_get_name(conv),
         purple_utf8_strftime("(%H:%M:%S)", localtime(&mtime)),
         name, message);									// 输出会话
}

static PurpleConversationUiOps null_conv_uiops = 					// 定义会话UI选项
{
   NULL,													// 创建会话
   NULL,													// 清除会话
   NULL,													// 输入聊天消息
   NULL,													// 输入通信信息
   null_write_conv,											// 写入会话
   NULL,													// 添加联系人
   NULL,													// 修改联系人名
   NULL,													// 删除联系人
   NULL,													// 更新联系人姓名
   NULL,													// 当前时间
   NULL,													// 获得焦点
   NULL,													// 增加表情
   NULL,													// 输入表情
   NULL,													// 关闭表情
   NULL,													// 发送确认
};

static void null_ui_init(void)									// 初始化用户接口
{
   purple_conversations_set_ui_ops(&null_conv_uiops);				// 使用会话UI选项初始化用户接口
}

static PurpleCoreUiOps null_core_uiops = 						// 定义核心用户接口选项
{
   NULL, NULL, null_ui_init, NULL
};

static void init_libpurple(void)									// 初始化libpurple
{
   purple_util_set_user_dir(CUSTOM_USER_DIRECTORY);			// 设置用户目录
   purple_debug_set_enabled(FALSE);							// 不接受调试信息
   purple_core_set_ui_ops(&null_core_uiops);						// 设置核心用户接口选项
   purple_eventloop_set_ui_ops(&glib_eventloops);					// 设置GLib事件循环
   purple_plugins_add_search_path(CUSTOM_PLUGIN_PATH);		// 添加搜索插件路径
   if (!purple_core_init(UI_ID)) {								// 初始化libpurple环境
      fprintf(stderr,
            "libpurple初始化失败!\n");
      abort();
   }
   purple_set_blist(purple_blist_new());							// 读取联系人列表
   purple_blist_load();
   purple_prefs_load();										// 读取用户配置
   purple_plugins_load_saved(PLUGIN_SAVE_PREF);				// 加载插件
   purple_pounces_load();									// 完成初始化
}

static void signed_on(PurpleConnection *gc, gpointer null)			// 接收libpurple信号
{
   PurpleAccount *account = purple_connection_get_account(gc);		// 读取本地账户信息
   printf("Account connected: %s %s\n", account->username, account->protocol_id);
}

static void connect_to_signals_for_demonstration_purposes_only(void)	// 对信号进行过滤
{
   static int handle;											// 用于保存句柄
   purple_signal_connect(purple_connections_get_handle(), "signed-on", &handle,
            PURPLE_CALLBACK(signed_on), NULL);				// 设置过滤器和回调函数
}

int main(int argc, char *argv[])
{
   GList *iter;												// 声明GList链表节点
   int i, num;												// 用户循环控制变量
   GList *names = NULL;										// 声明GList链表
   const char *prpl;
   char name[128];											// 用于保存用户名
   char *password;											// 用于保存密码
   GMainLoop *loop = g_main_loop_new(NULL, FALSE);			// 创建一个主循环
   PurpleAccount *account;									// 定义libpurple账户
   PurpleSavedStatus *status;									// 定义libpurple状态
   char *res;												// 用于用户输入交互
   signal(SIGCHLD, SIG_IGN);								// 设置libpurple信号
   init_libpurple();											// 初始化libpurple库
   printf("libpurple初始化成功。\n");
   iter = purple_plugins_get_protocols();							// 通过插件获得即时通信协议
   for (i = 0; iter; iter = iter->next) {								// 遍历GList链表
      PurplePlugin *plugin = iter->data;							// 取得libpurple插件信息
      PurplePluginInfo *info = plugin->info;
      if (info && info->name) {
         printf("\t%d: %s\n", i++, info->name);						// 输出libpurple插件名
         names = g_list_append(names, info->id);					// 将libpurple插件名加入GList链表
      }
   }
   printf("请选择一个协议 [0-%d]: ", i-1);							// 提示用户选择一个IM协议
   res = fgets(name, sizeof(name), stdin);							// 从终端读取用户输入
   if (!res) {
      fprintf(stderr, "协议选择不正确");
      abort();
   }
   sscanf(name, "%d", &num);									// 输入协议编号
   prpl = g_list_nth_data(names, num);							// 在GList链表中读取相关协议信息
   printf("用户名: ");											// 提述输入用户名
   res = fgets(name, sizeof(name), stdin);							// 从终端读取用户输入
   if (!res) {
      fprintf(stderr, "无法读取用户名");
      abort();
   }
   name[strlen(name) - 1] = 0;
   account = purple_account_new(name, prpl);					// 创建账户
   password = getpass("请输入密码: ");
   purple_account_set_password(account, password);				// 获取用户密码
   purple_account_set_enabled(account, UI_ID, TRUE);				// 激活账户
   status = purple_savedstatus_new(NULL, 
                                  PURPLE_STATUS_AVAILABLE);	// 设置当前状态为可用
   purple_savedstatus_activate(status);							// 设置用户状态为“活动”
   connect_to_signals_for_demonstration_purposes_only();			// 接收IM服务器传来的消息
   g_main_loop_run(loop);									// 启动GLib主循环
   return 0;
}

编译;

运行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/711840.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何实现电脑监视员工的电脑屏幕?六个方法偷偷分享给你

实现电脑监视员工的电脑屏幕&#xff0c;通常需要借助专业的监控软件或系统&#xff0c;这些工具旨在帮助企业管理者监督员工的工作状态&#xff0c;确保工作效率&#xff0c;同时保护公司资产和数据安全。以下是几种常见的实现方式。 1. 使用专业的远程监控软件 安企神软件&a…

如何进行LLM大模型推理优化

解密LLM大模型推理优化本质 一、LLM推理的本质以及考量点 LLM推理聚焦Transformer架构的Decoder以生成文本。过程分两步&#xff1a;首先&#xff0c;模型初始化并加载输入文本&#xff1b;接着&#xff0c;进入解码阶段&#xff0c;模型自回归地生成文本&#xff0c;直至满足…

微服务feign组件学习

手写不易&#xff0c;对您有帮助。麻烦一键三连。也欢饮各位大料指正&#xff0c;交流。 微服务feign组件学习 1.概念1.1 feign 概念1.2 Ribbon概念 2.使用2.1 集成feign2.1.1 maven依赖2.1.2 项目结构 2.2 使用2.2.1 定义feign接口2.2.2 消费端服务调用2.2.3 消费端扫描feig…

基于scikit-learn的机器学习分类任务实践——集成学习

一、传统机器学习分类流程与经典思想算法简述 传统机器学习是指&#xff0c;利用线性代数、数理统计与优化算法等数学方式从设计获取的数据集中构建预测学习器&#xff0c;进而对未知数据分类或回归。其主要流程大致可分为七个部分&#xff0c;依次为设计获取数据特征集&#x…

20240615给飞凌的OK3588-C开发板刷Rockchip原厂的Buildroot后的测试报告

20240615给飞凌的OK3588-C开发板刷Rockchip原厂的Buildroot后的测试报告&#xff1a; 【切记&#xff0c;由于没有替换DTS的&#xff0c;开发板发热量巨大&#xff01;因此配备鼓风机进行加强散热了】 0、adb 默认没有 1、HDMI IN 4K 2024/6/15 20:32 4K全屏 2、HDMI OUT …

博客论坛系统java博客管理系统基于springboot+vue的前后端分离博客论坛系统

文章目录 博客论坛系统一、项目演示二、项目介绍三、部分功能截图四、部分代码展示五、底部获取项目源码&#xff08;9.9&#xffe5;带走&#xff09; 博客论坛系统 一、项目演示 博客论坛系统 二、项目介绍 基于springbootvue的前后端分离博客论坛系统 系统角色&#xff1a…

【Arthas案例】某应用依赖两个GAV不同但包含两个相同全限定类名StaticLoggerBinder,引起log4j.Level类找不到异常

3分钟内解决问题 两个不同的GAV依赖冲突&#xff0c;包含相同全限定类名&#xff0c;引起ClassNotFoundException Maven依赖的三坐标体系GAV(G-groupId&#xff0c;A-artifactId&#xff0c;V-version) 【案例1】某应用依赖两个GAV不同的jar&#xff0c;但包含两个相同全限定类…

虚函数机制-动态绑定的应用

虚函数使得程序在运行的时候根据指针指向对象的类型来确定调用哪个函数。 下图中&#xff1a;都为静态绑定。因为在编译器就确定了可以调用的函数 此时当基类指针指向派生类对象时&#xff0c;因为没有virtual关键字&#xff0c;所以在编译阶段就根据指针类型确定了要指向的函…

MEMS:Lecture 17 Noise MDS

讲义 Minimum Detectable Signal (MDS) Minimum Detectable Signal&#xff08;最小可检测信号&#xff09;是指当信号-噪声比&#xff08;Signal-to-Noise Ratio, SNR&#xff09;等于1时的输入信号水平。简单来说&#xff0c;MDS 是一个系统能够分辨出信号存在的最低输入信号…

Tomcat基础详解

第一篇&#xff1a;Tomcat基础篇 lecture&#xff1a;邓澎波 一、构建Tomcat源码环境 工欲善其事必先利其器&#xff0c;为了学好Tomcat源码&#xff0c;我们需要先在本地构建一个Tomcat的运行环境。 1.源码环境下载 源码有两种下载方式&#xff1a; 1.1 官网下载 https://…

matplotlib twinx多y轴但单个图例

matplotlib 用 twinx 画多 y 轴参考 [1]。现想在画图例时&#xff0c;多个 y 轴的图例画在一起&#xff0c;写法参考 [2]。本文展示一个简例&#xff0c;效果&#xff1a; Code 要手动指定颜色&#xff0c;否则原 y 轴的用色和新 y 轴会重合。 import matplotlib.pyplot as…

基于SVD的点云配准(下)

点云配准及特征提取详细解读 本篇博客将介绍一个用于点云配准的 C++ 代码示例,该示例使用 PCL(Point Cloud Library)库来处理和配准两个点云数据集。我们将逐步解析代码的关键部分,并解释每个步骤的作用。 代码说明 代码的整体结构及其主要功能: int main(int argc, ch…

VRChat 2024年裁员原因与背景深度分析

VRChat&#xff0c;作为2022年元宇宙/VR社交领域的巨头&#xff0c;近期在2024年宣布裁员计划&#xff0c;其背后原因和背景值得业界尤其是仍在纯元宇宙虚拟空间创业的同仁们重点关注。 一、创始人决策失误 根据CEO的邮件披露&#xff0c;VRChat的创始人因缺乏经验和过度自信…

Vue基本使用-02

上节我们讲了什么是mvvm模型&#xff0c;以及我们vue的一些常用指令&#xff0c;今天给大家讲一下vue的基本使用&#xff0c;在将之前我们需要重点讲解我们的一个指令&#xff0c;v-model指令 v-model v-model 可以在组件上使用以实现双向绑定,什么是双向绑定呢?意思就是当我们…

[C#]使用C#部署yolov10的目标检测tensorrt模型

【测试通过环境】 win10 x64vs2019 cuda11.7cudnn8.8.0 TensorRT-8.6.1.6 opencvsharp4.9.0 .NET Framework4.7.2 NVIDIA GeForce RTX 2070 Super cuda和tensorrt版本和上述环境版本不一样的需要重新编译TensorRtExtern.dll&#xff0c;TensorRtExtern源码地址&#xff1a;T…

IP地址、子网掩码、网段、网关

前面相同就是在同一个网段 如果子网掩码和网络号相与的结果是一样的&#xff0c;那么他们就在同一个子网 IP地址、子网掩码、网络号、主机号、网络地址、主机地址以及ip段/数字-如192.168.0.1/24是什么意思?_掩码248可以用几个ip-CSDN博客

第九届星华杯网络邀请赛

T1喵星人的身高 T2犇犇碑 T3嘤嘤词典 T4三角区间和

REST风格

黑马程序员Spring Boot2 文章目录 1、REST简介1.1 优点1.2 REST风格简介1.3 注意事项 2、RESTful入门案例 1、REST简介 1.1 优点 隐藏资源的访问行为&#xff0c;无法通过地址的值对资源适合中操作书写简化 1.2 REST风格简介 按照RST风格访问资源时使用行为动作区分对资源进…

滚珠螺杆失效的常见原因及应对措施!

滚珠螺杆&#xff0c;由螺杆、螺母、钢球、预压片、反向器和防尘器组成&#xff0c;是精密机床中必不可少的组件&#xff0c;也是工业界使用最广泛的零组件之一。在长期使用过程中&#xff0c;滚珠螺杆难免会发生失效或运动停止的情况&#xff0c;影响机械设备的正常运行和最终…

PlugLink:让数据分析与工作流无缝连接(附源码)

PlugLink&#xff1a;让数据分析与工作流无缝连接 引言 数据分析和自动化工作流已成为各个企业和个人提高效率的关键手段。今天&#xff0c;我要介绍一款名为PlugLink的工具&#xff0c;它不仅能帮助你轻松进行数据分析&#xff0c;还能将这些分析结果无缝连接到你的工作流中&…