1 /*
2  * Copyright (C) 2007 Colin DIDIER
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License along
14  * with this program; if not, write to the Free Software Foundation, Inc.,
15  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16  */
17 
18 #include <stdlib.h>
19 
20 #include "module.h"
21 #include "channels.h"
22 #include "nicklist.h"
23 #include "recode.h"
24 #include "settings.h"
25 #include "signals.h"
26 #include "window-item-def.h"
27 
28 #include "xmpp-commands.h"
29 #include "xmpp-queries.h"
30 #include "xmpp-servers.h"
31 #include "rosters-tools.h"
32 #include "tools.h"
33 
34 const char *xmpp_commands[] = {
35 	"away",
36 	"quote",
37 	"roster",
38 	"whois",
39 	"presence",
40 	NULL
41 };
42 
43 const char *xmpp_command_roster[] = {
44 	"full",
45 	"add",
46 	"remove",
47 	"name",
48 	"group",
49 	NULL
50 };
51 
52 const char *xmpp_command_presene[] = {
53 	"accept",
54 	"deny",
55 	"subscribe",
56 	"unsubscribe",
57 	NULL
58 };
59 
60 static char *
cmd_connect_get_line(const char * data)61 cmd_connect_get_line(const char *data)
62 {
63 	GHashTable *optlist;
64 	const char *port;
65 	char *line, *jid, *password, *network, *network_free, *host, *host_free;
66 	void *free_arg;
67 
68 	line = host_free = network_free = NULL;
69 	if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_OPTIONS,
70 	    "xmppconnect", &optlist, &jid, &password))
71 		return NULL;
72 	if (*password == '\0')
73 		password = g_strdup("\r"); /* we will prompt for password later */
74 	if (*jid == '\0' || password == NULL || *password == '\0'
75 	    || !xmpp_have_domain(jid)) {
76 		cmd_params_free(free_arg);
77 		signal_emit("error command", 1,
78 		    GINT_TO_POINTER(CMDERR_NOT_ENOUGH_PARAMS));
79 		signal_stop();
80 		return NULL;
81 	}
82 	network = g_hash_table_lookup(optlist, "network");
83 	if (network == NULL || *network == '\0') {
84 		char *stripped = xmpp_strip_resource(jid);
85 		network = network_free = g_strconcat("xmpp:", stripped, (void *)NULL);
86 		g_free(stripped);
87 	}
88 	host = g_hash_table_lookup(optlist, "host");
89 	if (host == NULL || *host == '\0')
90 		host = host_free = xmpp_extract_domain(jid);
91 	port = g_hash_table_lookup(optlist, "port");
92 	if (port == NULL)
93 		port = "0";
94 	line = g_strdup_printf("%s-xmppnet \"%s\" %s %d \"%s\" \"%s\"",
95 	    (g_hash_table_lookup(optlist, "ssl") != NULL) ? "-ssl " : "",
96 	    network, host, atoi(port), password, jid);
97 	g_free(network_free);
98 	g_free(host_free);
99 	cmd_params_free(free_arg);
100 	return line;
101 }
102 
103 /* SYNTAX: XMPPCONNECT [-ssl] [-host <server>] [-port <port>]
104  *                     <jid>[/<resource>] <password> */
105 static void
cmd_xmppconnect(const char * data,SERVER_REC * server,WI_ITEM_REC * item)106 cmd_xmppconnect(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
107 {
108 	char *line, *cmd_line;
109 
110 	if ((line = cmd_connect_get_line(data)) == NULL)
111 		return;
112 	cmd_line = g_strconcat(settings_get_str("cmdchars"), "CONNECT ",
113 	    line, (void *)NULL);
114 	g_free(line);
115 	signal_emit("send command", 3, cmd_line, server, item);
116 	g_free(cmd_line);
117 }
118 
119 /* SYNTAX: XMPPSERVER [-ssl] [-host <server>] [-port <port>]
120  *                    <jid>[/<resource>] <password> */
121 static void
cmd_xmppserver(const char * data,SERVER_REC * server,WI_ITEM_REC * item)122 cmd_xmppserver(const char *data, SERVER_REC *server, WI_ITEM_REC *item)
123 {
124 	char *line, *cmd_line;
125 
126 	if ((line = cmd_connect_get_line(data)) == NULL)
127 		return;
128 	cmd_line = g_strconcat(settings_get_str("cmdchars"), "SERVER ",
129 	    line, (void *)NULL);
130 	g_free(line);
131 	signal_emit("send command", 3, cmd_line, server, item);
132 	g_free(cmd_line);
133 }
134 
135 static void
set_away(XMPP_SERVER_REC * server,const char * data)136 set_away(XMPP_SERVER_REC *server, const char *data)
137 {
138 	char **tmp;
139 	const char *reason;
140 	int show, priority;
141 
142 	if (!IS_XMPP_SERVER(server))
143 		return;
144 	priority = settings_get_int("xmpp_priority");
145 	tmp = g_strsplit(data, " ", 2);
146 	if (*data == '\0') {
147 		show = XMPP_PRESENCE_AVAILABLE;
148 		reason = NULL;
149 	} else {
150 		show = xmpp_get_show(tmp[0]);
151 		if (show == XMPP_PRESENCE_AVAILABLE && g_ascii_strcasecmp(
152 		    xmpp_presence_show[XMPP_PRESENCE_ONLINE], tmp[0]) != 0) {
153 			show = xmpp_get_show(
154 			    settings_get_str("xmpp_default_away_mode"));
155 			reason = data;
156 		} else
157 			reason = tmp[1];
158 		if (show == XMPP_PRESENCE_AWAY)
159 			priority = settings_get_int("xmpp_priority_away");
160 	}
161 	signal_emit("xmpp set presence", 4, server, show, reason,
162 	    priority);
163 	g_strfreev(tmp);
164 }
165 
166 /* SYNTAX: AWAY [-one | -all] [away|dnd|xa|chat] [<reason>] */
167 static void
cmd_away(const char * data,XMPP_SERVER_REC * server)168 cmd_away(const char *data, XMPP_SERVER_REC *server)
169 {
170 	GHashTable *optlist;
171 	char *reason;
172 	void *free_arg;
173 
174 	CMD_XMPP_SERVER(server);
175 	if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS |
176 	    PARAM_FLAG_GETREST, "away", &optlist, &reason))
177 		return;
178 	if (g_hash_table_lookup(optlist, "one") != NULL)
179 		set_away(server, reason);
180 	else
181 		g_slist_foreach(servers, (GFunc)set_away, reason);
182 	cmd_params_free(free_arg);
183 }
184 
185 /* SYNTAX: QUOTE <raw_command> */
186 static void
cmd_quote(const char * data,XMPP_SERVER_REC * server)187 cmd_quote(const char *data, XMPP_SERVER_REC *server)
188 {
189 	char *recoded;
190 
191 	CMD_XMPP_SERVER(server);
192 	if (*data == '\0')
193 		cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
194 	g_strstrip((char *)data);
195 	if (*data == '\0')
196 		cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
197 	signal_emit("xmpp xml out", 2, server, data);
198 	recoded = xmpp_recode_out(data);
199 	lm_connection_send_raw(server->lmconn, recoded, NULL);
200 	g_free(recoded);
201 }
202 
203 /* SYNTAX: ROSTER */
204 static void
cmd_roster(const char * data,XMPP_SERVER_REC * server,WI_ITEM_REC * item)205 cmd_roster(const char *data, XMPP_SERVER_REC *server, WI_ITEM_REC *item)
206 {
207 	CMD_XMPP_SERVER(server);
208 	if (*data == '\0')
209 		signal_emit("xmpp roster show", 1, server);
210 	else
211 		command_runsub(xmpp_commands[XMPP_COMMAND_ROSTER], data,
212 		    server, item);
213 }
214 
215 /* SYNTAX: ROSTER FULL */
216 static void
cmd_roster_full(const char * data,XMPP_SERVER_REC * server,WI_ITEM_REC * item)217 cmd_roster_full(const char *data, XMPP_SERVER_REC *server, WI_ITEM_REC *item)
218 {
219 	gboolean oldvalue;
220 
221 	CMD_XMPP_SERVER(server);
222 	oldvalue = settings_get_bool("xmpp_roster_show_offline");
223 	if (!oldvalue)
224 		settings_set_bool("xmpp_roster_show_offline", TRUE);
225 	signal_emit("xmpp roster show", 1, server);
226 	if (!oldvalue)
227 		settings_set_bool("xmpp_roster_show_offline", oldvalue);
228 }
229 
230 /* SYNTAX: ROSTER ADD <jid> */
231 static void
cmd_roster_add(const char * data,XMPP_SERVER_REC * server)232 cmd_roster_add(const char *data, XMPP_SERVER_REC *server)
233 {
234 	LmMessage *lmsg;
235 	LmMessageNode *query_node, *item_node;
236 	GHashTable *optlist;
237 	const char *jid;
238 	char *jid_recoded;
239 	void *free_arg;
240 
241 	CMD_XMPP_SERVER(server);
242 	if (!cmd_get_params(data, &free_arg, 1 | PARAM_FLAG_OPTIONS,
243 	    "roster add", &optlist, &jid))
244 		return;
245 	if (*jid == '\0')
246 		cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
247 	lmsg = lm_message_new_with_sub_type(NULL,
248 	    LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET);
249 	query_node = lm_message_node_add_child(lmsg->node, "query", NULL);
250 	lm_message_node_set_attribute(query_node, "xmlns", "jabber:iq:roster");
251 	jid_recoded = xmpp_recode_out(jid);
252 	item_node = lm_message_node_add_child(query_node, "item", NULL);
253 	lm_message_node_set_attribute(item_node, "jid", jid_recoded);
254 	signal_emit("xmpp send iq", 2, server, lmsg);
255 	lm_message_unref(lmsg);
256 	if (g_hash_table_lookup(optlist, "nosub") == NULL) {
257 		lmsg = lm_message_new_with_sub_type(jid_recoded,
258 		    LM_MESSAGE_TYPE_PRESENCE, LM_MESSAGE_SUB_TYPE_SUBSCRIBE);
259 		signal_emit("xmpp send presence", 2, server, lmsg);
260 		lm_message_unref(lmsg);
261 	}
262 	g_free(jid_recoded);
263 	cmd_params_free(free_arg);
264 }
265 
266 
267 /* SYNTAX: ROSTER REMOVE <jid> */
268 static void
cmd_roster_remove(const char * data,XMPP_SERVER_REC * server)269 cmd_roster_remove(const char *data, XMPP_SERVER_REC *server)
270 {
271 	LmMessage *lmsg;
272 	LmMessageNode *query_node, *item_node;
273 	XMPP_ROSTER_USER_REC *user;
274 	const char *jid;
275 	char *recoded;
276 	void *free_arg;
277 
278 	CMD_XMPP_SERVER(server);
279 	if (!cmd_get_params(data, &free_arg, 1, &jid))
280 		return;
281 	if (*jid == '\0')
282 		cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
283 	user = rosters_find_user(server->roster, jid, NULL, NULL);
284 	if (user == NULL) {
285 		signal_emit("xmpp not in roster", 2, server, jid);
286 		goto out;
287 	}
288 	lmsg = lm_message_new_with_sub_type(NULL,
289 	    LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET);
290 	query_node = lm_message_node_add_child(lmsg->node, "query", NULL);
291 	lm_message_node_set_attribute(query_node, "xmlns", "jabber:iq:roster");
292 	item_node = lm_message_node_add_child(query_node, "item", NULL);
293 	recoded = xmpp_recode_out(jid);
294 	lm_message_node_set_attribute(item_node, "jid", recoded);
295 	g_free(recoded);
296 	lm_message_node_set_attribute(item_node, "subscription", "remove");
297 	signal_emit("xmpp send iq", 2, server, lmsg);
298 	lm_message_unref(lmsg);
299 
300 out:
301 	cmd_params_free(free_arg);
302 }
303 
304 /* SYNTAX: ROSTER NAME <jid> [<name>] */
305 static void
cmd_roster_name(const char * data,XMPP_SERVER_REC * server)306 cmd_roster_name(const char *data, XMPP_SERVER_REC *server)
307 {
308 	LmMessage *lmsg;
309 	LmMessageNode *query_node, *item_node;
310 	XMPP_ROSTER_USER_REC *user;
311 	XMPP_ROSTER_GROUP_REC *group;
312 	const char *jid, *name;
313 	char *recoded;
314 	void *free_arg;
315 
316 	CMD_XMPP_SERVER(server);
317 	if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST, &jid,
318 	    &name))
319 		return;
320 	if (*jid == '\0')
321 		cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
322 	user = rosters_find_user(server->roster, jid, &group, NULL);
323 	if (user == NULL) {
324 		signal_emit("xmpp not in roster", 2, server, jid);
325 		goto out;
326 	}
327 	lmsg = lm_message_new_with_sub_type(NULL,
328 	    LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET);
329 	query_node = lm_message_node_add_child(lmsg->node, "query", NULL);
330 	lm_message_node_set_attribute(query_node, "xmlns", "jabber:iq:roster");
331 	item_node = lm_message_node_add_child(query_node, "item", NULL);
332 	recoded = xmpp_recode_out(jid);
333 	lm_message_node_set_attribute(item_node, "jid", recoded);
334 	g_free(recoded);
335 	if (group->name != NULL) {
336 		recoded = xmpp_recode_out(group->name);
337 		lm_message_node_add_child(item_node, "group", recoded);
338 		g_free(recoded);
339 	}
340 	if (*name != '\0') {
341 		recoded = xmpp_recode_out(name);
342 		lm_message_node_set_attribute(item_node, "name", recoded);
343 		g_free(recoded);
344 	}
345 	signal_emit("xmpp send iq", 2, server, lmsg);
346 	lm_message_unref(lmsg);
347 
348 out:
349 	cmd_params_free(free_arg);
350 }
351 
352 /* SYNTAX: ROSTER GROUP <jid> [<group>] */
353 static void
cmd_roster_group(const char * data,XMPP_SERVER_REC * server)354 cmd_roster_group(const char *data, XMPP_SERVER_REC *server)
355 {
356 	LmMessage *lmsg;
357 	LmMessageNode *query_node, *item_node;
358 	XMPP_ROSTER_USER_REC *user;
359 	XMPP_ROSTER_GROUP_REC *group;
360 	const char *jid, *group_name;
361 	char *recoded;
362 	void *free_arg;
363 
364 	CMD_XMPP_SERVER(server);
365 	if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST, &jid,
366 	    &group_name))
367 		return;
368 	if (*jid == '\0')
369 		cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
370 	user = rosters_find_user(server->roster, jid, &group, NULL);
371 	if (user == NULL) {
372 		signal_emit("xmpp not in roster", 2, server, jid);
373 		goto out;
374 	}
375 	lmsg = lm_message_new_with_sub_type(NULL,
376 	    LM_MESSAGE_TYPE_IQ, LM_MESSAGE_SUB_TYPE_SET);
377 	query_node = lm_message_node_add_child(lmsg->node, "query", NULL);
378 	lm_message_node_set_attribute(query_node, "xmlns", "jabber:iq:roster");
379 	item_node = lm_message_node_add_child(query_node, "item", NULL);
380 	recoded = xmpp_recode_out(jid);
381 	lm_message_node_set_attribute(item_node, "jid", recoded);
382 	g_free(recoded);
383 	if (*group_name != '\0') {
384 		recoded = xmpp_recode_out(group_name);
385 		lm_message_node_add_child(item_node, "group", recoded);
386 		g_free(recoded);
387 	}
388 	if (user->name != NULL) {
389 		recoded = xmpp_recode_out(user->name);
390 		lm_message_node_set_attribute(item_node, "name", recoded);
391 		g_free(recoded);
392 	}
393 	signal_emit("xmpp send iq", 2, server, lmsg);
394 	lm_message_unref(lmsg);
395 
396 out:
397 	cmd_params_free(free_arg);
398 }
399 
400 /* SYNTAX: PRESENCE */
401 static void
cmd_presence(const char * data,XMPP_SERVER_REC * server,WI_ITEM_REC * item)402 cmd_presence(const char *data, XMPP_SERVER_REC *server, WI_ITEM_REC *item)
403 {
404 	CMD_XMPP_SERVER(server);
405 	if (*data == '\0')
406 		cmd_return_error(CMDERR_NOT_ENOUGH_PARAMS);
407 	else
408 		command_runsub(xmpp_commands[XMPP_COMMAND_PRESENCE], data,
409 		    server, item);
410 }
411 
412 
413 /* SYNTAX: PRESENCE ACCEPT <jid> */
414 static void
cmd_presence_accept(const char * data,XMPP_SERVER_REC * server)415 cmd_presence_accept(const char *data, XMPP_SERVER_REC *server)
416 {
417 	LmMessage *lmsg;
418 	const char *jid;
419 	char *recoded;
420 	void *free_arg;
421 
422 	CMD_XMPP_SERVER(server);
423 	if (!cmd_get_params(data, &free_arg, 1, &jid))
424 		return;
425 	if (*jid == '\0')
426 		cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
427 	recoded = xmpp_recode_out(jid);
428 	lmsg = lm_message_new_with_sub_type(recoded,
429 	    LM_MESSAGE_TYPE_PRESENCE, LM_MESSAGE_SUB_TYPE_SUBSCRIBED);
430 	g_free(recoded);
431 	signal_emit("xmpp send presence", 2, server, lmsg);
432 	lm_message_unref(lmsg);
433 	cmd_params_free(free_arg);
434 }
435 
436 /* SYNTAX: PRESENCE DENY <jid> */
437 static void
cmd_presence_deny(const char * data,XMPP_SERVER_REC * server)438 cmd_presence_deny(const char *data, XMPP_SERVER_REC *server)
439 {
440 	LmMessage *lmsg;
441 	const char *jid;
442 	char *recoded;
443 	void *free_arg;
444 
445 	CMD_XMPP_SERVER(server);
446 	if (!cmd_get_params(data, &free_arg, 1, &jid))
447 		return;
448 	if (*jid == '\0')
449 		cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
450 	recoded = xmpp_recode_out(jid);
451 	lmsg = lm_message_new_with_sub_type(recoded,
452 	    LM_MESSAGE_TYPE_PRESENCE,LM_MESSAGE_SUB_TYPE_UNSUBSCRIBED);
453 	g_free(recoded);
454 	signal_emit("xmpp send presence", 2, server, lmsg);
455 	lm_message_unref(lmsg);
456 	cmd_params_free(free_arg);
457 }
458 
459 /* SYNTAX: PRESENCE SUBSCRIBE <jid> [<reason>] */
460 static void
cmd_presence_subscribe(const char * data,XMPP_SERVER_REC * server)461 cmd_presence_subscribe(const char *data, XMPP_SERVER_REC *server)
462 {
463 	LmMessage *lmsg;
464 	const char *jid, *reason;
465 	char *recoded;
466 	void *free_arg;
467 
468 	CMD_XMPP_SERVER(server);
469 	if (!cmd_get_params(data, &free_arg, 2 | PARAM_FLAG_GETREST, &jid,
470 	    &reason))
471 		return;
472 	if (*jid == '\0')
473 		cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
474 	recoded = xmpp_recode_out(jid);
475 	lmsg = lm_message_new_with_sub_type(recoded,
476 	    LM_MESSAGE_TYPE_PRESENCE, LM_MESSAGE_SUB_TYPE_SUBSCRIBE);
477 	g_free(recoded);
478 	if (*reason != '\0') {
479 		recoded = xmpp_recode_out(reason);
480 		lm_message_node_add_child(lmsg->node, "status", recoded);
481 		g_free(recoded);
482 	}
483 	signal_emit("xmpp send presence", 2, server, lmsg);
484 	lm_message_unref(lmsg);
485 	cmd_params_free(free_arg);
486 }
487 
488 /* SYNTAX: PRESENCE UNSUBSCRIBE <jid> */
489 static void
cmd_presence_unsubscribe(const char * data,XMPP_SERVER_REC * server)490 cmd_presence_unsubscribe(const char *data, XMPP_SERVER_REC *server)
491 {
492 	LmMessage *lmsg;
493 	const char *jid;
494 	char *recoded;
495 	void *free_arg;
496 
497 	CMD_XMPP_SERVER(server);
498 	if (!cmd_get_params(data, &free_arg, 1, &jid))
499 		return;
500 	if (*jid == '\0')
501 		cmd_param_error(CMDERR_NOT_ENOUGH_PARAMS);
502 	recoded = xmpp_recode_out(jid);
503 	lmsg = lm_message_new_with_sub_type(recoded,
504 	    LM_MESSAGE_TYPE_PRESENCE, LM_MESSAGE_SUB_TYPE_UNSUBSCRIBE);
505 	g_free(recoded);
506 	signal_emit("xmpp send presence", 2, server, lmsg);
507 	lm_message_unref(lmsg);
508 	cmd_params_free(free_arg);
509 }
510 
511 /* SYNTAX: ME <message> */
512 static void
cmd_me(const char * data,XMPP_SERVER_REC * server,WI_ITEM_REC * item)513 cmd_me(const char *data, XMPP_SERVER_REC *server, WI_ITEM_REC *item)
514 {
515 	const char *target;
516 	char *str, *recoded;
517 	int type;
518 
519 	CMD_XMPP_SERVER(server);
520 	if (item == NULL || *data == '\0')
521 		return;
522 	g_strstrip((char *)data);
523 	if (*data == '\0')
524 		return;
525 	target = window_item_get_target(item);
526 	type = IS_CHANNEL(item) ? SEND_TARGET_CHANNEL : SEND_TARGET_NICK;
527 	if (type == SEND_TARGET_NICK)
528 		signal_emit("message xmpp own_action", 4, server, data, target,
529 		    SEND_TARGET_NICK);
530 	str = g_strconcat("/me ", data, (void *)NULL);
531 	recoded = recode_out(SERVER(server), str, target);
532 	g_free(str);
533 	server->send_message(SERVER(server), target, recoded, type);
534 	g_free(recoded);
535 }
536 
537 char *
xmpp_get_dest(const char * cmd_dest,XMPP_SERVER_REC * server,WI_ITEM_REC * item)538 xmpp_get_dest(const char *cmd_dest, XMPP_SERVER_REC *server, WI_ITEM_REC *item)
539 {
540 	NICK_REC *nick;
541 	char *dest;
542 
543 	if (cmd_dest == NULL || *cmd_dest == '\0')
544 		return IS_QUERY(item) ? g_strdup(QUERY(item)->name)
545 		    : g_strconcat(server->jid, "/", server->resource, (void *)NULL);
546 	if (IS_CHANNEL(item)
547 	    && (nick = nicklist_find(CHANNEL(item), cmd_dest)) != NULL)
548 		return g_strdup(nick->host);
549 	if ((dest = rosters_resolve_name(server, cmd_dest)) != NULL)
550 		return dest;
551 	return g_strdup(cmd_dest);
552 }
553 
554 void
xmpp_commands_init(void)555 xmpp_commands_init(void)
556 {
557 	command_set_options("connect", "+xmppnet");
558 	command_set_options("server add", "-xmppnet");
559 	command_bind("xmppconnect", NULL, (SIGNAL_FUNC)cmd_xmppconnect);
560 	command_set_options("xmppconnect", "ssl -network -host @port");
561 	command_bind("xmppserver", NULL, (SIGNAL_FUNC)cmd_xmppserver);
562 	command_bind_xmpp("away", NULL, (SIGNAL_FUNC)cmd_away);
563 	command_bind_xmpp("quote", NULL, (SIGNAL_FUNC)cmd_quote);
564 	command_bind_xmpp("roster", NULL, (SIGNAL_FUNC)cmd_roster);
565 	command_bind_xmpp("roster full", NULL, (SIGNAL_FUNC)cmd_roster_full);
566 	command_bind_xmpp("roster add", NULL, (SIGNAL_FUNC)cmd_roster_add);
567 	command_set_options("roster add", "nosub");
568 	command_bind_xmpp("roster remove", NULL,
569 	    (SIGNAL_FUNC)cmd_roster_remove);
570 	command_bind_xmpp("roster name", NULL, (SIGNAL_FUNC)cmd_roster_name);
571 	command_bind_xmpp("roster group", NULL, (SIGNAL_FUNC)cmd_roster_group);
572 	command_bind_xmpp("presence", NULL, (SIGNAL_FUNC)cmd_presence);
573 	command_bind_xmpp("presence accept", NULL,
574 	    (SIGNAL_FUNC)cmd_presence_accept);
575 	command_bind_xmpp("presence deny", NULL,
576 	    (SIGNAL_FUNC)cmd_presence_deny);
577 	command_bind_xmpp("presence subscribe", NULL,
578 	    (SIGNAL_FUNC)cmd_presence_subscribe);
579 	command_bind_xmpp("presence unsubscribe", NULL,
580 	    (SIGNAL_FUNC)cmd_presence_unsubscribe);
581 	command_bind_xmpp("me", NULL, (SIGNAL_FUNC)cmd_me);
582 	settings_add_str("xmpp", "xmpp_default_away_mode", "away");
583 }
584 
585 void
xmpp_commands_deinit(void)586 xmpp_commands_deinit(void)
587 {
588 	command_unbind("xmppconnect", (SIGNAL_FUNC)cmd_xmppconnect);
589 	command_unbind("xmppserver", (SIGNAL_FUNC)cmd_xmppserver);
590 	command_unbind("away", (SIGNAL_FUNC)cmd_away);
591 	command_unbind("quote", (SIGNAL_FUNC)cmd_quote);
592 	command_unbind("roster", (SIGNAL_FUNC)cmd_roster);
593 	command_unbind("roster full", (SIGNAL_FUNC)cmd_roster_full);
594 	command_unbind("roster add", (SIGNAL_FUNC)cmd_roster_add);
595 	command_unbind("roster remove", (SIGNAL_FUNC)cmd_roster_remove);
596 	command_unbind("roster name", (SIGNAL_FUNC)cmd_roster_name);
597 	command_unbind("roster group", (SIGNAL_FUNC)cmd_roster_group);
598 	command_unbind("presence", (SIGNAL_FUNC)cmd_presence);
599 	command_unbind("presence accept", (SIGNAL_FUNC)cmd_presence_accept);
600 	command_unbind("presence deny", (SIGNAL_FUNC)cmd_presence_deny);
601 	command_unbind("presence subscribe",
602 	    (SIGNAL_FUNC)cmd_presence_subscribe);
603 	command_unbind("presence unsubscribe",
604 	    (SIGNAL_FUNC)cmd_presence_unsubscribe);
605 	command_unbind("me", (SIGNAL_FUNC)cmd_me);
606 }
607