citadel
About: Citadel is an advanced messaging and collaboration system for groupware and BBS applications (preferred OS: Linux).
  Fossies Dox: citadel.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

Loading...
Searching...
No Matches
xmpp_query_namespace.c
Go to the documentation of this file.
1/*
2 * Handle <iq> <get> <query> type situations (namespace queries)
3 *
4 * Copyright (c) 2007-2015 by Art Cancro and citadel.org
5 *
6 * This program is open source software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 3.
8 *
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.
13 */
14
15#include "../../sysdep.h"
16#include <stdlib.h>
17#include <unistd.h>
18#include <stdio.h>
19#include <fcntl.h>
20#include <signal.h>
21#include <pwd.h>
22#include <errno.h>
23#include <sys/types.h>
24#include <time.h>
25#include <sys/wait.h>
26#include <string.h>
27#include <limits.h>
28#include <ctype.h>
29#include <expat.h>
30#include <libcitadel.h>
31#include "../../citadel.h"
32#include "../../server.h"
33#include "../../citserver.h"
34#include "../../support.h"
35#include "../../config.h"
36#include "../../internet_addressing.h"
37#include "../../ctdl_module.h"
38#include "serv_xmpp.h"
39
40
41/*
42 * Output a single roster item, for roster queries or pushes
43 */
44void xmpp_roster_item(struct CitContext *cptr) {
45 char xmlbuf1[256];
46 char xmlbuf2[256];
47
48 cprintf("<item jid=\"%s\" name=\"%s\" subscription=\"both\">",
49 xmlesc(xmlbuf1, cptr->cs_principal_id, sizeof xmlbuf1),
50 xmlesc(xmlbuf2, cptr->user.fullname, sizeof xmlbuf2)
51 );
52 cprintf("<group>%s</group>", xmlesc(xmlbuf1, CtdlGetConfigStr("c_humannode"), sizeof xmlbuf1));
53 cprintf("</item>");
54}
55
56
57/*
58 * Return the results for a "jabber:iq:roster:query"
59 *
60 * Since we are not yet managing a roster, we simply return the entire wholist
61 * (minus any entries for this user -- don't tell me about myself)
62 *
63 */
65{
66 struct CitContext *cptr;
67 int nContexts, i;
68
69 syslog(LOG_DEBUG, "xmpp: roster push!");
70 cprintf("<query xmlns=\"jabber:iq:roster\">");
71 cptr = CtdlGetContextArray(&nContexts);
72 if (cptr) {
73 for (i=0; i<nContexts; i++) {
74 if (xmpp_is_visible(&cptr[i], CC)) {
75 syslog(LOG_DEBUG, "xmpp: rosterizing %s", cptr[i].user.fullname);
76 xmpp_roster_item(&cptr[i]);
77 }
78 }
79 free (cptr);
80 }
81 cprintf("</query>");
82}
83
84
85/*
86 * Client is doing a namespace query. These are all handled differently.
87 */
88void xmpp_query_namespace(char *iq_id, char *iq_from, char *iq_to, char *query_xmlns)
89{
90 int supported_namespace = 0;
91 int roster_query = 0;
92 char xmlbuf[256];
93 int reply_must_be_from_my_jid = 0;
94
95 /* We need to know before we begin the response whether this is a supported namespace, so
96 * unfortunately all supported namespaces need to be defined here *and* down below where
97 * they are handled.
98 */
99 if (
100 (!strcasecmp(query_xmlns, "jabber:iq:roster:query"))
101 || (!strcasecmp(query_xmlns, "jabber:iq:auth:query"))
102 || (!strcasecmp(query_xmlns, "http://jabber.org/protocol/disco#items:query"))
103 || (!strcasecmp(query_xmlns, "http://jabber.org/protocol/disco#info:query"))
104 ) {
105 supported_namespace = 1;
106 }
107
108 syslog(LOG_DEBUG, "xmpp: xmpp_query_namespace(id=%s, from=%s, to=%s, xmlns=%s)", iq_id, iq_from, iq_to, query_xmlns);
109
110 /*
111 * Beginning of query result.
112 */
113
114 if (!strcasecmp(query_xmlns, "jabber:iq:roster:query")) {
115 reply_must_be_from_my_jid = 1;
116 }
117
118 char dom[1024]; // client is expecting to see the reply
119 if (reply_must_be_from_my_jid) { // coming "from" the user's jid
120 safestrncpy(dom, XMPP->client_jid, sizeof(dom));
121 char *slash = strchr(dom, '/');
122 if (slash) {
123 *slash = 0;
124 }
125 }
126 else {
127 safestrncpy(dom, XMPP->client_jid, sizeof(dom)); // client is expecting to see the reply
128 if (IsEmptyStr(dom)) { // coming "from" the domain of the user's jid
129 safestrncpy(dom, XMPP->server_name, sizeof(dom));
130 }
131 char *at = strrchr(dom, '@');
132 if (at) {
133 strcpy(dom, ++at);
134 }
135 char *slash = strchr(dom, '/');
136 if (slash) {
137 *slash = 0;
138 }
139 }
140
141 if (supported_namespace) {
142 cprintf("<iq type=\"result\" from=\"%s\" ", xmlesc(xmlbuf, dom, sizeof xmlbuf) );
143 }
144 else {
145 cprintf("<iq type=\"error\" from=\"%s\" ", xmlesc(xmlbuf, dom, sizeof xmlbuf) );
146 }
147 if (!IsEmptyStr(iq_from)) {
148 cprintf("to=\"%s\" ", xmlesc(xmlbuf, iq_from, sizeof xmlbuf));
149 }
150 cprintf("id=\"%s\">", xmlesc(xmlbuf, iq_id, sizeof xmlbuf));
151
152 /*
153 * Is this a query we know how to handle?
154 */
155
156 if (!strcasecmp(query_xmlns, "jabber:iq:roster:query")) {
157 roster_query = 1;
159 }
160
161 else if (!strcasecmp(query_xmlns, "jabber:iq:auth:query")) {
162 cprintf("<query xmlns=\"jabber:iq:auth\">"
163 "<username/><password/><resource/>"
164 "</query>"
165 );
166 }
167
168 // Extension "xep-0030" (http://xmpp.org/extensions/xep-0030.html) (return an empty set of results)
169 else if (!strcasecmp(query_xmlns, "http://jabber.org/protocol/disco#items:query")) {
170 cprintf("<query xmlns=\"%s\"/>", xmlesc(xmlbuf, query_xmlns, sizeof xmlbuf));
171 }
172
173 // Extension "xep-0030" (http://xmpp.org/extensions/xep-0030.html) (return an empty set of results)
174 else if (!strcasecmp(query_xmlns, "http://jabber.org/protocol/disco#info:query")) {
175 cprintf("<query xmlns=\"%s\"/>", xmlesc(xmlbuf, query_xmlns, sizeof xmlbuf));
176 }
177
178 /*
179 * If we didn't hit any known query namespaces then we should deliver a
180 * "service unavailable" error (see RFC3921 section 2.4 and 11.1.5.4)
181 */
182
183 else {
184 syslog(LOG_DEBUG, "xmpp: unknown query namespace '%s' - returning <service-unavailable/>", query_xmlns);
185 cprintf("<error code=\"503\" type=\"cancel\">"
186 "<service-unavailable xmlns=\"urn:ietf:params:xml:ns:xmpp-stanzas\"/>"
187 "</error>"
188 );
189 }
190
191 cprintf("</iq>");
192
193 /* If we told the client who is on the roster, we also need to tell the client
194 * who is *not* on the roster. (It's down here because we can't do it in the same
195 * stanza; this will be an unsolicited push.)
196 */
197 if (roster_query) {
199 }
200}
char * CtdlGetConfigStr(char *key)
Definition: config.c:363
CitContext * CtdlGetContextArray(int *count)
Definition: context.c:418
#define CC
Definition: context.h:136
void free(void *)
char * xmlesc(char *buf, char *str, int bufsiz)
Definition: serv_xmpp.c:100
int xmpp_is_visible(struct CitContext *from, struct CitContext *to_whom)
Definition: xmpp_presence.c:66
void xmpp_delete_old_buddies_who_no_longer_exist_from_the_client_roster(void)
#define XMPP
Definition: serv_xmpp.h:43
struct ctdluser user
Definition: context.h:105
char cs_principal_id[256]
Definition: context.h:90
char fullname[64]
Definition: citadel.h:80
void cprintf(const char *format,...)
Definition: sysdep.c:369
void xmpp_iq_roster_query(void)
void xmpp_roster_item(struct CitContext *cptr)
void xmpp_query_namespace(char *iq_id, char *iq_from, char *iq_to, char *query_xmlns)