summaryrefslogtreecommitdiff
path: root/src/rexmpp_console.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rexmpp_console.c')
-rw-r--r--src/rexmpp_console.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/src/rexmpp_console.c b/src/rexmpp_console.c
new file mode 100644
index 0000000..47c0bfa
--- /dev/null
+++ b/src/rexmpp_console.c
@@ -0,0 +1,224 @@
+/**
+ @file rexmpp_console.c
+ @brief A console module
+ @author defanor <defanor@uberspace.net>
+ @date 2020
+ @copyright MIT license.
+
+ The "console" is supposed to provide a few common and basic
+ commands, and to be easily embeddable into programs, similarly to
+ an XML console.
+*/
+
+#include <string.h>
+
+#include "rexmpp.h"
+#include "rexmpp_openpgp.h"
+#include "rexmpp_console.h"
+
+
+void rexmpp_console_printf (rexmpp_t *s, const char *format, ...)
+{
+ va_list args;
+ if (s->console_print_cb != NULL) {
+ va_start(args, format);
+ s->console_print_cb (s, format, args);
+ va_end(args);
+ }
+}
+
+char *rexmpp_console_message_string (rexmpp_t *s, xmlNodePtr node) {
+ char *ret = NULL;
+ xmlNodePtr openpgp =
+ rexmpp_xml_find_child(node, "urn:xmpp:openpgp:0", "openpgp");
+ if (openpgp != NULL) {
+ int valid;
+ xmlNodePtr elem = rexmpp_openpgp_decrypt_verify_message(s, node, &valid);
+ if (! valid) {
+ rexmpp_console_printf(s, "An invalid OpenPGP message!\n");
+ }
+
+ if (elem != NULL) {
+ xmlNodePtr payload =
+ rexmpp_xml_find_child(elem, "urn:xmpp:openpgp:0", "payload");
+ if (payload != NULL) {
+ xmlNodePtr pl_body =
+ rexmpp_xml_find_child(payload, "jabber:client", "body");
+ if (pl_body != NULL) {
+ ret = xmlNodeGetContent(pl_body);
+ }
+ }
+ xmlFreeNode(elem);
+ }
+ }
+ if (ret == NULL) {
+ xmlNodePtr body = rexmpp_xml_find_child(node, "jabber:client", "body");
+ ret = xmlNodeGetContent(body);
+ }
+ return ret;
+}
+
+void rexmpp_console_on_send (rexmpp_t *s, xmlNodePtr node) {
+ if (rexmpp_xml_match(node, "jabber:client", "message")) {
+ char *to = xmlGetProp(node, "to");
+ if (to != NULL) {
+ /* "from" should be set for verification. */
+ char *from = xmlGetProp(node, "from");
+ xmlAttrPtr fromProp = NULL;
+ if (from == NULL) {
+ fromProp = xmlNewProp(node, "from", to);
+ }
+ char *str = rexmpp_console_message_string(s, node);
+ if (fromProp != NULL) {
+ xmlRemoveProp(fromProp);
+ }
+ if (str != NULL) {
+ rexmpp_console_printf(s, "You tell %s: %s\n", to, str);
+ free(str);
+ }
+ free(to);
+ }
+ }
+ if (rexmpp_xml_match(node, "jabber:client", "presence")) {
+ char *presence_type = xmlGetProp(node, "type");
+ rexmpp_console_printf(s, "Becoming %s\n",
+ (presence_type == NULL) ?
+ "available" :
+ presence_type);
+ if (presence_type != NULL) {
+ free(presence_type);
+ }
+ }
+}
+
+void rexmpp_console_on_recv (rexmpp_t *s, xmlNodePtr node) {
+ if (rexmpp_xml_match(node, "jabber:client", "message")) {
+ char *from = xmlGetProp(node, "from");
+ if (from != NULL) {
+ char *str = rexmpp_console_message_string(s, node);
+ if (str != NULL) {
+ rexmpp_console_printf(s, "%s tells you: %s\n", from, str);
+ free(str);
+ }
+ free(from);
+ }
+ }
+ if (rexmpp_xml_match(node, "jabber:client", "presence")) {
+ char *presence_type = xmlGetProp(node, "type");
+ char *from = xmlGetProp(node, "from");
+ rexmpp_console_printf(s, "%s is %s\n", from,
+ (presence_type == NULL) ?
+ "available" :
+ presence_type);
+ if (presence_type != NULL) {
+ free(presence_type);
+ }
+ if (from != NULL) {
+ free(from);
+ }
+ }
+}
+
+void rexmpp_console_feed (rexmpp_t *s, char *str, ssize_t str_len) {
+ /* todo: buffering */
+ char *words_save_ptr;
+ char *word, *jid_str, *msg_text;
+ struct rexmpp_jid jid;
+ word = strtok_r(str, " ", &words_save_ptr);
+ if (word == NULL) {
+ return;
+ }
+
+ const char *help =
+ "Available commands:\n"
+ "help\n"
+ "quit\n"
+ "tell <jid> <message>\n"
+ "signcrypt <jid> <message>\n"
+ "publish-key <fingerprint>\n"
+ "join <conference> [as] <nick>\n"
+ ;
+
+ if (! strcmp(word, "help")) {
+ rexmpp_console_printf(s, help);
+ }
+
+ if (! strcmp(word, "quit")) {
+ rexmpp_console_printf(s, "Quitting.\n");
+ rexmpp_stop(s);
+ return;
+ }
+
+ if (! strcmp(word, "publish-key")) {
+ char *fingerprint = strtok_r(NULL, " ", &words_save_ptr);
+ rexmpp_openpgp_publish_key(s, fingerprint);
+ }
+
+ if (! strcmp(word, "tell")) {
+ jid_str = strtok_r(NULL, " ", &words_save_ptr);
+ if (jid_str == NULL || rexmpp_jid_parse(jid_str, &jid)) {
+ return;
+ }
+ msg_text = jid_str + strlen(jid_str) + 1;
+ xmlNodePtr msg = rexmpp_xml_add_id(s, xmlNewNode(NULL, "message"));
+ xmlNewProp(msg, "to", jid.full);
+ xmlNewProp(msg, "type", "chat");
+ xmlNewTextChild(msg, NULL, "body", msg_text);
+ rexmpp_send(s, msg);
+ }
+
+ if (! strcmp(word, "signcrypt")) {
+ jid_str = strtok_r(NULL, " ", &words_save_ptr);
+ if (jid_str == NULL || rexmpp_jid_parse(jid_str, &jid)) {
+ return;
+ }
+ msg_text = jid_str + strlen(jid_str) + 1;
+ xmlNodePtr body = xmlNewNode(NULL, "body");
+ xmlNewNs(body, "jabber:client", NULL);
+ xmlNodeAddContent(body, msg_text);
+ const char *rcpt[2];
+ rcpt[0] = jid.full;
+ rcpt[1] = NULL;
+ char *b64 = rexmpp_openpgp_encrypt_sign(s, body, rcpt);
+ xmlNodePtr openpgp = xmlNewNode(NULL, "openpgp");
+ openpgp->ns = xmlNewNs(openpgp, "urn:xmpp:openpgp:0", NULL);
+ xmlNodeAddContent(openpgp, b64);
+ free(b64);
+
+ xmlNodePtr msg = rexmpp_xml_add_id(s, xmlNewNode(NULL, "message"));
+ xmlNewProp(msg, "to", jid.full);
+ xmlNewProp(msg, "type", "chat");
+ xmlAddChild(msg, openpgp);
+
+ body = xmlNewNode(NULL, "body");
+ xmlNewNs(body, "jabber:client", NULL);
+ xmlNodeAddContent(body, "This is a secret message.");
+ xmlAddChild(msg, body);
+
+ rexmpp_send(s, msg);
+ }
+
+ if (! strcmp(word, "join")) {
+ jid_str = strtok_r(NULL, " ", &words_save_ptr);
+ if (jid_str == NULL || rexmpp_jid_parse(jid_str, &jid)) {
+ return;
+ }
+ word = strtok_r(NULL, " ", &words_save_ptr);
+ if (! strcmp(word, "as")) {
+ word = strtok_r(NULL, " ", &words_save_ptr);
+ }
+ if (word == NULL) {
+ return;
+ }
+ char *full_jid = malloc(strlen(jid.bare) + strlen(word) + 2);
+ snprintf(full_jid, strlen(jid_str) + strlen(word) + 2, "%s/%s",
+ jid.bare, word);
+ xmlNodePtr presence = rexmpp_xml_add_id(s, xmlNewNode(NULL, "presence"));
+ xmlNewProp(presence, "from", s->assigned_jid.full);
+ xmlNewProp(presence, "to", full_jid);
+ xmlNodePtr x = xmlNewNode(NULL, "x");
+ xmlNewNs(x, "http://jabber.org/protocol/muc", NULL);
+ xmlAddChild(presence, x);
+ rexmpp_send(s, presence);
+ }
+}