Vulpes - XMPP Bot
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

243 lines
7.4 KiB

/*
* vim: expandtab:ts=2:sts=2:sw=2
*
* Copyright (C) 2021 DebXWoody <stefan@devlug.de>
*
* This file is part of vulpes.
*
* vulpes is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* vulpes is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with buteo. If not, see <http://www.gnu.org/licenses/>.
*/
#include "mod_rss.h"
#include <assert.h>
#include <curl/urlapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/xpath.h>
#define MOD_NAME "mod_rss"
#define MOD_VERSION "0.0.0-dev"
#define LOG_DOMAIN "vulpes-mod-rss"
#define MOD_HELP_PREFIX "!help"
#define MOD_COMMAND_PREFIX "!rss"
#define HELP_TXT "Module " MOD_NAME " - " MOD_VERSION "\n\
!rss list - balblabla\n \
!rss add - blablabl\n"
#define BUFFER_SIZE 1048576
GString *_vulpes_download(vulpes_ctx_t *vulpes_ctx,GString *url, vulpes_action_t *action);
size_t _write_callback(char *ptr, size_t size, size_t nmemb, void *userdata);
void _parse(vulpes_ctx_t *vulpes_ctx, GString *data, vulpes_action_t *a);
GString* _atom_item(vulpes_ctx_t *vulpes_ctx, xmlNodePtr cur, vulpes_action_t *a);
GString *xmlurldata;
static void _show_help(vulpes_ctx_t *vulpes_ctx, const lutjanus_xmpp_adr_t* from, const char *const message);
vulpes_err_code_t module_load(vulpes_ctx_t *vulpes_ctx) {
g_log(LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, "Loading %s (%s)...", MOD_NAME, MOD_VERSION );
mod_api_backend_create("mod_rss_feeds", "ID INTEGER PRIMARY KEY ASC, URL_FEED TEXT, URL_ITEM TEXT, TITLE TEXT, PUB_DATE DATE, ADDED_DATE");
return VULPES_SUCCESS;
}
vulpes_err_code_t chat(vulpes_ctx_t *vulpes_ctx, const lutjanus_xmpp_adr_t* from, const char *const message) {
g_log(LOG_DOMAIN, G_LOG_LEVEL_INFO, "Incoming messsage from %s: %s", from, message);
if ( g_str_has_prefix (message, MOD_HELP_PREFIX ) ) {
_show_help(vulpes_ctx, from,message);
return VULPES_SUCCESS;
}
if ( !g_str_has_prefix (message, MOD_COMMAND_PREFIX ) ) {
return VULPES_SUCCESS;
}
gchar** tokens = g_strsplit (message," ", 5);
if ( tokens[0] && g_strcmp0( MOD_COMMAND_PREFIX , tokens[0]) == 0 ) {
if ( tokens[1] && g_strcmp0( "add" , tokens[1]) == 0 ) {
if ( tokens[2] && is_admin(vulpes_ctx, from) ) {
gchar* text = g_strdup_printf("Adding RSS URL: %s", tokens[2]);
GString* url = g_string_new(tokens[2]);
GString* urlfile = _vulpes_download(vulpes_ctx, url, NULL);
mod_api_send_chat_message(vulpes_ctx, from, text);
}
}
}
}
vulpes_err_code_t module_unload(vulpes_ctx_t *vulpes_ctx) {
return VULPES_SUCCESS;
}
vulpes_err_code_t group_command_execute(vulpes_ctx_t *vulpes_ctx,
const char *const command) {
return VULPES_SUCCESS;
}
static void _show_help(vulpes_ctx_t *vulpes_ctx, const lutjanus_xmpp_adr_t* from, const char *const message) {
mod_api_send_chat_message(vulpes_ctx, from, HELP_TXT);
}
GString *_vulpes_download(vulpes_ctx_t *vulpes_ctx, GString *url, vulpes_action_t *action) {
g_assert(url);
g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Downloading %s", url->str);
CURL *curl = curl_easy_init();
if (curl) {
xmlurldata = g_string_new("");
curl_easy_setopt(curl, CURLOPT_URL, url->str);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, _write_callback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, action);
curl_easy_perform(curl);
g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "Done!");
_parse(vulpes_ctx, xmlurldata, action);
curl_easy_cleanup(curl);
}
return NULL;
}
size_t _write_callback(char *ptr, size_t size, size_t nmemb, void *userdata) {
//g_assert(userdata);
// vulpes_action_t* a = (vulpes_action_t*) userdata;
g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "write_callback size: %ld %ld\n", size,
nmemb);
gchar s[BUFFER_SIZE];
g_strlcpy(s, ptr, BUFFER_SIZE);
g_string_append(xmlurldata, s);
// g_log(LOG_DOMAIN, G_LOG_LEVEL_DEBUG, "XML %s", message->str);
return nmemb;
}
GString* _atom_item(vulpes_ctx_t *vulpes_ctx, xmlNodePtr cur, vulpes_action_t *a) {
GString *title = NULL;
GString *link = NULL;
GString *pubDate = NULL;
xmlNode *cur_node = NULL;
for (cur_node = cur->children; cur_node; cur_node = cur_node->next) {
if (cur_node->type == XML_ELEMENT_NODE) {
if (g_strcmp0("title", (const char *)cur_node->name) == 0) {
title = g_string_new((const char *)cur_node->children->content);
} else if (g_strcmp0("link", (const char *)cur_node->name) == 0) {
link = g_string_new((const char *)cur_node->children->content);
} else if (g_strcmp0("pubDate", (const char *)cur_node->name) == 0) {
pubDate = g_string_new((const char *)cur_node->children->content);
}
}
}
printf("%s %s %s\n", pubDate->str, title->str, link->str);
GString *text = g_string_new(pubDate->str);
g_string_append(text, " - ");
g_string_append(text, title->str);
g_string_append(text, " - ");
g_string_append(text, link->str);
g_log(LOG_DOMAIN, G_LOG_LEVEL_MESSAGE, "RSS: %s\n", text->str);
lutjanus_xmpp_adr_t* operator_muc = mod_api_get_operator_muc(vulpes_ctx);
mod_api_send_groupchat_message(vulpes_ctx, operator_muc, text->str);
//vulpes_action_set_mesage(a, text);
//vulpes_action(a);
return text;
}
void _parse(vulpes_ctx_t *vulpes_ctx, GString *data, vulpes_action_t *a) {
xmlDocPtr doc = NULL;
doc = xmlReadMemory(data->str, strlen(data->str), "noname.xml", NULL, 0);
if (doc == NULL) {
fprintf(stderr, "Failed to parse document\n");
}
LIBXML_TEST_VERSION
xmlNodePtr root_element = xmlDocGetRootElement(doc);
xmlNodePtr a_node = root_element;
xmlNodePtr cur_node;
for (cur_node = a_node; cur_node; cur_node = cur_node->next) {
if (cur_node->type == XML_ELEMENT_NODE) {
printf("node type: Element, name: %s\n", cur_node->name);
}
}
xmlXPathContextPtr xpathCtx;
xmlXPathObjectPtr xpathObj;
xpathCtx = xmlXPathNewContext(doc);
xpathObj =
xmlXPathEvalExpression((const xmlChar *)"/rss/channel/item", xpathCtx);
if (xpathObj == NULL) {
printf("Not found\n");
}
xmlNodeSetPtr nodes = xpathObj->nodesetval;
printf("Nr: %d\n", nodes->nodeNr);
xmlNodePtr cur;
int i;
for (i = 0; i < nodes->nodeNr; ++i) {
assert(nodes->nodeTab[i]);
if (nodes->nodeTab[i]->type == XML_NAMESPACE_DECL) {
xmlNsPtr ns;
ns = (xmlNsPtr)nodes->nodeTab[i];
cur = (xmlNodePtr)ns->next;
if (cur->ns) {
fprintf(stdout, "= namespace \"%s\"=\"%s\" for node %s:%s\n",
ns->prefix, ns->href, cur->ns->href, cur->name);
} else {
fprintf(stdout, "= namespace \"%s\"=\"%s\" for node %s\n", ns->prefix,
ns->href, cur->name);
}
} else if (nodes->nodeTab[i]->type == XML_ELEMENT_NODE) {
cur = nodes->nodeTab[i];
if (cur->ns) {
fprintf(stdout, "= element node \"%s:%s\"\n", cur->ns->href, cur->name);
} else {
_atom_item(vulpes_ctx, cur, a);
}
} else {
cur = nodes->nodeTab[i];
fprintf(stdout, "= node \"%s\": type %d\n", cur->name, cur->type);
}
}
xmlFreeDoc(doc);
}