1/*!
2 * @file message.c
3 *
4 * vim: expandtab:ts=2:sts=2:sw=2
5 *
6 * @authors
7 * Copyright (C) 2020 Anoxinon e.V.
8 *
9 * @copyright
10 * This file is part of xmppc.
11 *
12 * xmppc is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, either version 3 of the License, or
15 * (at your option) any later version.
16 *
17 * xmppc is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with Foobar. If not, see <http://www.gnu.org/licenses/>.
24 *
25 * German
26 *
27 * Diese Datei ist Teil von xmppc.
28 *
29 * xmppc ist Freie Software: Sie können es unter den Bedingungen
30 * der GNU General Public License, wie von der Free Software Foundation,
31 * Version 3 der Lizenz oder (nach Ihrer Wahl) jeder neueren
32 * veröffentlichten Version, weiter verteilen und/oder modifizieren.
33 *
34 * xmppc wird in der Hoffnung, dass es nützlich sein wird, aber
35 * OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite
36 * Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
37 * Siehe die GNU General Public License für weitere Details.
38 *
39 * Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
40 * Programm erhalten haben. Wenn nicht, siehe <https://www.gnu.org/licenses/>.
41 */
42
43#include "message.h"
44#include "mam.h"
45#include "glib.h"
46#include "stdbool.h"
47#include "stdlib.h"
48#include "string.h"
49
50#define SID_NS "urn:xmpp:sid:0"
51
52typedef struct {
53 char *to;
54 char *message_id;
55 char *archive_id;
56 bool done;
57} message_send_t;
58
59static void _message_send_text(xmppc_t *xmppc, char* to, char* message);
60static void _message_archive_id_found(xmpp_conn_t *conn, const char *archive_id, void *userdata);
61static void _message_finish_sent(xmpp_conn_t *conn, message_send_t *sent);
62static void _message_send_free(message_send_t *sent);
63static void _message_print_sent(message_send_t *sent);
64static void _message_print_escaped_attr(const char *text);
65
66void message_execute_command(xmppc_t *xmppc, int argc, char *argv[]) {
67 if( argc == 3 && ( strcmp("chat", argv[0] ) == 0)) {
68 _message_send_text(xmppc, argv[1],argv[2]);
69 } else {
70 logError(xmppc, "Befehl unbekannt");
71 xmpp_disconnect(xmppc->conn);
72 }
73}
74
75void _message_send_text(xmppc_t *xmppc, char* to, char* text) {
76 xmpp_conn_t *conn = xmppc->conn;
77 xmpp_ctx_t *ctx = xmpp_conn_get_context(conn);
78 xmpp_stanza_t *message;
79 char* id = xmpp_uuid_gen(xmppc->ctx);
80 message = xmpp_message_new(ctx, "chat", to, id);
81 int res = xmpp_message_set_body(message, text);
82 if(res == 0) {
83 xmpp_stanza_t *origin = xmpp_stanza_new(ctx);
84 xmpp_stanza_set_name(origin, "origin-id");
85 xmpp_stanza_set_ns(origin, SID_NS);
86 xmpp_stanza_set_attribute(origin, "id", id);
87 xmpp_stanza_add_child(message, origin);
88 xmpp_stanza_release(origin);
89
90 message_send_t *sent = g_new0(message_send_t, 1);
91 sent->to = g_strdup(to);
92 sent->message_id = g_strdup(id);
93
94 xmpp_send(conn, message);
95 mam_lookup_message_archive_id(xmppc, to, id, _message_archive_id_found, sent);
96 } else {
97 xmpp_disconnect(conn);
98 }
99 xmpp_stanza_release(message);
100 free(id);
101}
102
103static void _message_archive_id_found(xmpp_conn_t *conn, const char *archive_id, void *userdata) {
104 message_send_t *sent = (message_send_t *)userdata;
105
106 if (archive_id) {
107 sent->archive_id = g_strdup(archive_id);
108 }
109
110 _message_finish_sent(conn, sent);
111}
112
113static void _message_finish_sent(xmpp_conn_t *conn, message_send_t *sent) {
114 if (sent->done) {
115 return;
116 }
117
118 sent->done = true;
119 _message_print_sent(sent);
120 _message_send_free(sent);
121 xmpp_disconnect(conn);
122}
123
124static void _message_send_free(message_send_t *sent) {
125 g_free(sent->to);
126 g_free(sent->message_id);
127 g_free(sent->archive_id);
128 g_free(sent);
129}
130
131static void _message_print_sent(message_send_t *lookup) {
132 printf("<sent archive-id=\"");
133 _message_print_escaped_attr(lookup->archive_id ? lookup->archive_id : "");
134 printf("\" message-id=\"");
135 _message_print_escaped_attr(lookup->message_id);
136 printf("\" to=\"");
137 _message_print_escaped_attr(lookup->to);
138 printf("\"/>\n");
139 fflush(stdout);
140}
141
142static void _message_print_escaped_attr(const char *text) {
143 const unsigned char *p = (const unsigned char *)(text ? text : "");
144
145 while (*p) {
146 switch (*p) {
147 case '&':
148 printf("&");
149 break;
150 case '<':
151 printf("<");
152 break;
153 case '>':
154 printf(">");
155 break;
156 case '"':
157 printf(""");
158 break;
159 case '\n':
160 printf(" ");
161 break;
162 case '\r':
163 printf(" ");
164 break;
165 case '\t':
166 printf("	");
167 break;
168 default:
169 if (*p < 0x20) {
170 printf("&#x%02X;", *p);
171 } else {
172 putchar(*p);
173 }
174 break;
175 }
176 p++;
177 }
178}