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/>.
47 typedef struct xmpp_server_t {
62 struct xmpp_server_t *next;
65 typedef struct xmpp_channel_t {
70 struct xmpp_channel_t *next;
74 static xmpp_server_t *servers;
75 static xmpp_channel_t *channels;
78 static xmpp_server_t *find_server(const char *name, int create)
80 xmpp_server_t *cur = NULL, *last = NULL;
81 for (cur = servers; cur; last = cur, cur = cur->next)
82 if (match(cur->name, name))
85 cur = new0(xmpp_server_t);
86 cur->name = get_name(name);
95 static xmpp_channel_t *find_channel(const char *name, int create)
97 xmpp_channel_t *cur = NULL, *last = NULL;
98 for (cur = channels; cur; last = cur, cur = cur->next)
99 if (match(cur->name, name))
101 if (!cur && create) {
102 cur = new0(xmpp_channel_t);
103 cur->name = get_name(name);
112 static void on_start(void *_srv, const char *tag, const char **attrs)
114 xmpp_server_t *srv = _srv;
118 srv->indent*4, "", tag);
119 for (int i = 0; attrs[i] && attrs[i+1]; i += 2) {
120 debug("%*s%s=\"%s\"%s",
122 attrs[i+0], attrs[i+1],
123 attrs[i+2] ? "" : ">");
128 if (srv->state == XMPP_RECV_FEATURES) {
129 if (match(tag, "starttls")) {
130 debug("xmpp: features -> starttls");
131 srv->state = XMPP_SEND_STARTTLS;
134 if (srv->state == XMPP_RECV_PROCEED) {
135 if (match(tag, "proceed")) {
136 debug("xmpp: proceed -> encrypt");
137 srv->state = XMPP_ENCRYPT;
142 static void on_end(void *_srv, const char *tag)
144 xmpp_server_t *srv = _srv;
150 (char*)srv->buf.data);
156 static void on_data(void *_srv, const char *data, int len)
158 xmpp_server_t *srv = _srv;
161 append(&srv->buf, data, len);
164 static void on_recv(void *_srv, char *buf, int len)
166 xmpp_server_t *srv = _srv;
170 XML_Parse(srv->expat, buf, len, 0);
174 if (srv->state == XMPP_SEND_STREAM) {
175 if (net_print(&srv->net,
176 "<?xml version='1.0'?>"
182 " xmlns='jabber:client'"
183 " xmlns:stream='http://etherx.jabber.org/streams'>",
184 srv->jid, srv->host)) {
185 debug("xmpp: stream -> features");
186 srv->state = XMPP_RECV_FEATURES;
189 if (srv->state == XMPP_SEND_STARTTLS) {
190 if (net_print(&srv->net,
191 "<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>")) {
192 debug("xmpp: startls -> proceed");
193 srv->state = XMPP_RECV_PROCEED;
196 if (srv->state == XMPP_ENCRYPT) {
197 /* Encrypt connection */
198 net_encrypt(&srv->net);
201 if (!(XML_ParserReset(srv->expat, NULL)))
202 error("Error resetting XML parser");
203 XML_SetUserData(srv->expat, srv);
204 XML_SetStartElementHandler(srv->expat, on_start);
205 XML_SetEndElementHandler(srv->expat, on_end);
206 XML_SetCharacterDataHandler(srv->expat, on_data);
209 debug("xmpp: encrypt -> stream");
210 srv->state = XMPP_SEND_STREAM;
215 static void xmpp_connect(xmpp_server_t *srv)
218 srv->net.recv = on_recv;
220 net_open(&srv->net, srv->host, srv->port);
223 if (!(srv->expat = XML_ParserCreate(NULL)))
224 error("Error creating XML parser");
225 XML_SetUserData(srv->expat, srv);
226 XML_SetStartElementHandler(srv->expat, on_start);
227 XML_SetEndElementHandler(srv->expat, on_end);
228 XML_SetCharacterDataHandler(srv->expat, on_data);
231 srv->state = XMPP_SEND_STREAM;
237 for (xmpp_server_t *cur = servers; cur; cur = cur->next) {
238 if (!match(cur->protocol, "xmpp"))
243 error("jid is required");
249 void xmpp_config(const char *group, const char *name, const char *key, const char *value)
252 xmpp_channel_t *chan;
254 if (match(group, "server")) {
255 srv = find_server(name, 1);
256 if (match(key, "protocol") &&
257 match(value, "xmpp"))
258 srv->protocol = get_string(value);
259 if (match(srv->protocol, "xmpp")) {
260 if (match(key, "connect"))
261 srv->connect = get_bool(value);
262 else if (match(key, "host"))
263 srv->host = get_string(value);
264 else if (match(key, "port"))
265 srv->port = get_number(value);
266 else if (match(key, "jid"))
267 srv->jid = get_string(value);
268 else if (match(key, "pass"))
269 srv->pass = get_string(value);
271 } else if (match(group, "channel")) {
272 chan = find_channel(name, 1);
273 if (match(key, "server") &&
274 find_server(value, 0))
275 chan->server = get_string(value);
277 if (match(key, "channel"))
278 chan->channel = get_string(value);
279 else if (match(key, "join"))
280 chan->join = get_bool(value);
285 void xmpp_send(const char *channel, const char *msg)