2 * Copyright (C) 2017 Andy Spencer <andy753421@gmail.com>
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
50 typedef struct xmpp_server_t {
66 struct xmpp_server_t *next;
69 typedef struct xmpp_channel_t {
74 struct xmpp_channel_t *next;
78 static xmpp_server_t *servers;
79 static xmpp_channel_t *channels;
82 static xmpp_server_t *find_server(const char *name, int create)
84 xmpp_server_t *cur = NULL, *last = NULL;
85 for (cur = servers; cur; last = cur, cur = cur->next)
86 if (match(cur->name, name))
89 cur = new0(xmpp_server_t);
90 cur->name = get_name(name);
99 static xmpp_channel_t *find_channel(const char *name, int create)
101 xmpp_channel_t *cur = NULL, *last = NULL;
102 for (cur = channels; cur; last = cur, cur = cur->next)
103 if (match(cur->name, name))
105 if (!cur && create) {
106 cur = new0(xmpp_channel_t);
107 cur->name = get_name(name);
116 static void on_start(void *_srv, const char *tag, const char **attrs)
118 xmpp_server_t *srv = _srv;
122 srv->indent*4, "", tag);
123 for (int i = 0; attrs[i] && attrs[i+1]; i += 2) {
124 debug("%*s%s=\"%s\"%s",
126 attrs[i+0], attrs[i+1],
127 attrs[i+2] ? "" : ">");
132 if (srv->state == XMPP_RECV_FEATURES) {
133 if (match(tag, "starttls")) {
134 debug("xmpp: features -> starttls");
135 srv->state = XMPP_SEND_STARTTLS;
137 if (match(tag, "mechanisms")) {
138 debug("xmpp: features -> auth");
139 srv->state = XMPP_SEND_AUTH;
142 if (srv->state == XMPP_RECV_PROCEED) {
143 if (match(tag, "proceed")) {
144 debug("xmpp: proceed -> encrypt");
145 srv->state = XMPP_ENCRYPT;
148 if (srv->state == XMPP_RECV_SUCCESS) {
149 if (match(tag, "success")) {
150 debug("xmpp: success -> restart");
151 srv->state = XMPP_RESTART;
156 static void on_end(void *_srv, const char *tag)
158 xmpp_server_t *srv = _srv;
164 (char*)srv->buf.data);
170 static void on_data(void *_srv, const char *data, int len)
172 xmpp_server_t *srv = _srv;
175 append(&srv->buf, data, len);
178 static void on_recv(void *_srv, char *buf, int len)
180 static char plain[AUTH_LEN];
181 static char coded[AUTH_LEN];
183 xmpp_server_t *srv = _srv;
187 XML_Parse(srv->expat, buf, len, 0);
191 if (srv->state == XMPP_SEND_STREAM) {
192 if (net_print(&srv->net,
193 "<?xml version='1.0'?>"
199 " xmlns='jabber:client'"
200 " xmlns:stream='http://etherx.jabber.org/streams'>",
201 srv->jid, srv->host)) {
202 debug("xmpp: stream -> features");
203 srv->state = XMPP_RECV_FEATURES;
206 if (srv->state == XMPP_SEND_STARTTLS) {
207 if (net_print(&srv->net,
208 "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>")) {
209 debug("xmpp: startls -> proceed");
210 srv->state = XMPP_RECV_PROCEED;
213 if (srv->state == XMPP_SEND_AUTH) {
214 len = snprintf(plain, AUTH_LEN, "%s%c%s%c%s",
215 srv->user, '\0', srv->user, '\0', srv->pass);
216 len = base64(plain, len, coded, AUTH_LEN);
217 if (net_print(&srv->net,
219 " xmlns='urn:ietf:params:xml:ns:xmpp-sasl'"
220 " mechanism='PLAIN'>%.*s</auth>",
222 debug("xmpp: auth -> success");
223 srv->state = XMPP_RECV_SUCCESS;
226 if (srv->state == XMPP_ENCRYPT) {
227 /* Encrypt connection */
228 net_encrypt(&srv->net);
231 if (!(XML_ParserReset(srv->expat, NULL)))
232 error("Error resetting XML parser");
233 XML_SetUserData(srv->expat, srv);
234 XML_SetStartElementHandler(srv->expat, on_start);
235 XML_SetEndElementHandler(srv->expat, on_end);
236 XML_SetCharacterDataHandler(srv->expat, on_data);
239 debug("xmpp: encrypt -> stream");
240 srv->state = XMPP_SEND_STREAM;
243 if (srv->state == XMPP_RESTART) {
245 if (!(XML_ParserReset(srv->expat, NULL)))
246 error("Error resetting XML parser");
247 XML_SetUserData(srv->expat, srv);
248 XML_SetStartElementHandler(srv->expat, on_start);
249 XML_SetEndElementHandler(srv->expat, on_end);
250 XML_SetCharacterDataHandler(srv->expat, on_data);
253 debug("xmpp: restart -> stream");
254 srv->state = XMPP_SEND_STREAM;
259 static void xmpp_connect(xmpp_server_t *srv)
262 srv->net.recv = on_recv;
264 net_open(&srv->net, srv->host, srv->port);
267 if (!(srv->expat = XML_ParserCreate(NULL)))
268 error("Error creating XML parser");
269 XML_SetUserData(srv->expat, srv);
270 XML_SetStartElementHandler(srv->expat, on_start);
271 XML_SetEndElementHandler(srv->expat, on_end);
272 XML_SetCharacterDataHandler(srv->expat, on_data);
275 srv->state = XMPP_SEND_STREAM;
281 for (xmpp_server_t *cur = servers; cur; cur = cur->next) {
282 if (!match(cur->protocol, "xmpp"))
287 error("jid is required");
293 void xmpp_config(const char *group, const char *name, const char *key, const char *value)
296 xmpp_channel_t *chan;
298 if (match(group, "server")) {
299 srv = find_server(name, 1);
300 if (match(key, "protocol") &&
301 match(value, "xmpp"))
302 srv->protocol = get_string(value);
303 if (match(srv->protocol, "xmpp")) {
304 if (match(key, "connect"))
305 srv->connect = get_bool(value);
306 else if (match(key, "host"))
307 srv->host = get_string(value);
308 else if (match(key, "port"))
309 srv->port = get_number(value);
310 else if (match(key, "jid"))
311 srv->jid = get_string(value);
312 else if (match(key, "user"))
313 srv->user = get_string(value);
314 else if (match(key, "pass"))
315 srv->pass = get_string(value);
317 } else if (match(group, "channel")) {
318 chan = find_channel(name, 1);
319 if (match(key, "server") &&
320 find_server(value, 0))
321 chan->server = get_string(value);
323 if (match(key, "channel"))
324 chan->channel = get_string(value);
325 else if (match(key, "join"))
326 chan->join = get_bool(value);
331 void xmpp_send(const char *channel, const char *msg)