jabberd2
2.2.17
Main Page
Data Structures
Files
File List
Globals
sm
mod_disco.c
Go to the documentation of this file.
1
/*
2
* jabberd - Jabber Open Source Server
3
* Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4
* Ryan Eatmon, Robert Norris
5
*
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
10
*
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14
* GNU General Public License for more details.
15
*
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19
*/
20
21
#include "
sm.h
"
22
30
#define ACTIVE_SESSIONS_NAME "Active sessions"
31
33
typedef
struct
service_st
*
service_t
;
34
struct
service_st
{
35
jid_t
jid
;
36
37
char
name
[257];
38
39
char
category
[257];
40
char
type
[257];
41
42
xht
features
;
43
};
44
46
typedef
struct
disco_st
*
disco_t
;
47
struct
disco_st
{
49
char
*
category
;
50
char
*
type
;
51
char
*
name
;
52
54
int
agents
;
55
57
xht
dyn
;
58
xht
stat
;
59
61
xht
un
;
62
64
pkt_t
disco_info_result
;
65
pkt_t
disco_items_result
;
66
pkt_t
agents_result
;
67
};
68
69
/* union for xhash_iter_get to comply with strict-alias rules for gcc3 */
70
union
xhashv
71
{
72
void
**
val
;
73
service_t *
svc_val
;
74
sess_t
*
sess_val
;
75
const
char
**
char_val
;
76
};
77
79
static
void
_disco_unify_walker
(
const
char
*key,
int
keylen,
void
*val,
void
*arg) {
80
service_t svc = (
service_t
) val;
81
xht
dest = (
xht
) arg;
82
83
/* if its already there, skip this one */
84
if
(
xhash_get
(dest,
jid_full
(svc->
jid
)) != NULL)
85
return
;
86
87
log_debug
(
ZONE
,
"unify: %s"
,
jid_full
(svc->
jid
));
88
89
xhash_put
(dest,
jid_full
(svc->
jid
), (
void
*) svc);
90
}
91
93
static
void
_disco_unify_lists
(disco_t d) {
94
log_debug
(
ZONE
,
"unifying lists"
);
95
96
if
(d->
un
!= NULL)
97
xhash_free
(d->
un
);
98
99
d->
un
=
xhash_new
(101);
100
101
/* dynamic overrieds static */
102
xhash_walk
(d->
dyn
,
_disco_unify_walker
, (
void
*) d->
un
);
103
xhash_walk
(d->
stat
,
_disco_unify_walker
, (
void
*) d->
un
);
104
}
105
107
static
pkt_t
_disco_items_result
(
module_t
mod, disco_t d) {
108
pkt_t
pkt;
109
int
ns;
110
service_t svc;
111
union
xhashv
xhv;
112
113
pkt =
pkt_create
(mod->
mm
->
sm
,
"iq"
,
"result"
, NULL, NULL);
114
ns =
nad_add_namespace
(pkt->nad,
uri_DISCO_ITEMS
, NULL);
115
nad_append_elem
(pkt->nad, ns,
"query"
, 2);
116
117
if
(
xhash_iter_first
(d->
un
))
118
do
{
119
xhv.
svc_val
= &svc;
120
xhash_iter_get
(d->
un
, NULL, NULL, xhv.
val
);
121
122
nad_append_elem
(pkt->nad, ns,
"item"
, 3);
123
nad_append_attr
(pkt->nad, -1,
"jid"
,
jid_full
(svc->
jid
));
124
125
if
(svc->
name
[0] !=
'\0'
)
126
nad_append_attr
(pkt->nad, -1,
"name"
, svc->
name
);
127
}
while
(
xhash_iter_next
(d->
un
));
128
129
return
pkt;
130
}
131
133
static
pkt_t
_disco_info_result
(
module_t
mod, disco_t d) {
134
pkt_t
pkt;
135
int
el, ns;
136
const
char
*key;
137
int
keylen;
138
139
pkt =
pkt_create
(mod->
mm
->
sm
,
"iq"
,
"result"
, NULL, NULL);
140
ns =
nad_add_namespace
(pkt->
nad
,
uri_DISCO_INFO
, NULL);
141
nad_append_elem
(pkt->
nad
, ns,
"query"
, 2);
142
143
/* identity */
144
nad_append_elem
(pkt->
nad
, ns,
"identity"
, 3);
145
nad_append_attr
(pkt->
nad
, -1,
"category"
, d->
category
);
146
nad_append_attr
(pkt->
nad
, -1,
"type"
, d->
type
);
147
nad_append_attr
(pkt->
nad
, -1,
"name"
, d->
name
);
148
149
/* fill in our features */
150
if
(
xhash_iter_first
(mod->
mm
->
sm
->
features
))
151
do
{
152
xhash_iter_get
(mod->
mm
->
sm
->
features
, &key, &keylen, NULL);
153
154
el =
nad_append_elem
(pkt->
nad
, ns,
"feature"
, 3);
155
nad_set_attr
(pkt->
nad
, el, -1,
"var"
, (
char
*) key, keylen);
156
}
while
(
xhash_iter_next
(mod->
mm
->
sm
->
features
));
157
158
/* put it throuhg disco_extend chain to add
159
* XEP-0128 Service Discovery Extensions */
160
mm_disco_extend
(mod->
mm
, pkt);
161
162
return
pkt;
163
}
164
166
static
pkt_t
_disco_agents_result
(
module_t
mod, disco_t d) {
167
pkt_t
pkt;
168
int
ns;
169
const
char
*key;
170
int
keylen;
171
service_t svc;
172
union
xhashv
xhv;
173
174
pkt =
pkt_create
(mod->
mm
->
sm
,
"iq"
,
"result"
, NULL, NULL);
175
ns =
nad_add_namespace
(pkt->nad,
uri_AGENTS
, NULL);
176
nad_append_elem
(pkt->nad, ns,
"query"
, 2);
177
178
/* fill in the items */
179
if
(
xhash_iter_first
(d->
un
))
180
do
{
181
xhv.
svc_val
= &svc;
182
xhash_iter_get
(d->
un
, &key, &keylen, xhv.
val
);
183
184
nad_append_elem
(pkt->nad, ns,
"agent"
, 3);
185
nad_append_attr
(pkt->nad, -1,
"jid"
,
jid_full
(svc->
jid
));
186
187
if
(svc->
name
[0] !=
'\0'
) {
188
nad_append_elem
(pkt->nad, ns,
"name"
, 4);
189
nad_append_cdata
(pkt->nad, svc->
name
, strlen(svc->
name
), 5);
190
}
191
192
nad_append_elem
(pkt->nad, ns,
"service"
, 4);
193
nad_append_cdata
(pkt->nad, svc->
type
, strlen(svc->
type
), 5);
194
195
/* map features to the old agent flags */
196
if
(
xhash_get
(svc->
features
,
uri_REGISTER
) != NULL)
197
nad_append_elem
(pkt->nad, ns,
"register"
, 4);
198
if
(
xhash_get
(svc->
features
,
uri_SEARCH
) != NULL)
199
nad_append_elem
(pkt->nad, ns,
"search"
, 4);
200
if
(
xhash_get
(svc->
features
,
uri_GATEWAY
) != NULL)
201
nad_append_elem
(pkt->nad, ns,
"transport"
, 4);
202
203
/* conference gets special treatment */
204
if
(strcmp(svc->
category
,
"conference"
) == 0)
205
nad_append_elem
(pkt->nad, ns,
"groupchat"
, 4);
206
}
while
(
xhash_iter_next
(d->
un
));
207
208
return
pkt;
209
}
210
212
static
void
_disco_generate_packets
(
module_t
mod, disco_t d) {
213
log_debug
(
ZONE
,
"regenerating packets"
);
214
215
if
(d->
disco_items_result
!= NULL)
216
pkt_free
(d->
disco_items_result
);
217
d->
disco_items_result
=
_disco_items_result
(mod, d);
218
219
if
(d->
disco_info_result
!= NULL)
220
pkt_free
(d->
disco_info_result
);
221
d->
disco_info_result
=
_disco_info_result
(mod, d);
222
223
if
(d->
agents
) {
224
if
(d->
agents_result
!= NULL)
225
pkt_free
(d->
agents_result
);
226
d->
agents_result
=
_disco_agents_result
(mod, d);
227
}
228
229
}
230
232
static
mod_ret_t
_disco_pkt_sm_populate
(
mod_instance_t
mi,
pkt_t
pkt)
233
{
234
module_t
mod = mi->
mod
;
235
disco_t d = (
disco_t
) mod->
private
;
236
int
ns, qelem, elem, attr;
237
service_t svc;
238
239
/* it has to come from the service itself - don't want any old user messing with the table */
240
if
(pkt->
from
->
node
[0] !=
'\0'
|| pkt->
from
->
resource
[0] !=
'\0'
)
241
{
242
log_debug
(
ZONE
,
"disco response from %s, not allowed"
,
jid_full
(pkt->
from
));
243
return
-
stanza_err_NOT_ALLOWED
;
244
}
245
246
ns =
nad_find_scoped_namespace
(pkt->
nad
,
uri_DISCO_INFO
, NULL);
247
qelem =
nad_find_elem
(pkt->
nad
, 1, ns,
"query"
, 1);
248
249
elem =
nad_find_elem
(pkt->
nad
, qelem, ns,
"identity"
, 1);
250
if
(elem < 0)
251
return
-
stanza_err_BAD_REQUEST
;
252
253
/* we don't want to list other im servers on the router */
254
if
(
nad_find_attr
(pkt->
nad
, elem, -1,
"category"
,
"server"
) >= 0
255
&&
nad_find_attr
(pkt->
nad
, elem, -1,
"type"
,
"im"
) >= 0) {
256
pkt_free
(pkt);
257
return
mod_HANDLED
;
258
}
259
260
/* see if we already have this service */
261
svc =
xhash_get
(d->
dyn
,
jid_full
(pkt->
from
));
262
if
(svc == NULL)
263
{
264
/* make a new one */
265
svc = (
service_t
) calloc(1,
sizeof
(
struct
service_st
));
266
267
svc->jid =
jid_dup
(pkt->
from
);
268
269
svc->features =
xhash_new
(11);
270
271
/* link it in */
272
xhash_put
(d->
dyn
,
jid_full
(svc->jid), (
void
*) svc);
273
274
/* unify */
275
_disco_unify_lists
(d);
276
}
277
278
/* fill in the name */
279
attr =
nad_find_attr
(pkt->
nad
, elem, -1,
"name"
, NULL);
280
if
(attr < 0)
281
svc->name[0] =
'\0'
;
282
else
283
snprintf(svc->name, 257,
"%.*s"
,
NAD_AVAL_L
(pkt->
nad
, attr),
NAD_AVAL
(pkt->
nad
, attr));
284
285
/* category and type */
286
attr =
nad_find_attr
(pkt->
nad
, elem, -1,
"category"
, NULL);
287
if
(attr >= 0)
288
snprintf(svc->category, 257,
"%.*s"
,
NAD_AVAL_L
(pkt->
nad
, attr),
NAD_AVAL
(pkt->
nad
, attr));
289
else
290
strcpy(svc->category,
"unknown"
);
291
292
attr =
nad_find_attr
(pkt->
nad
, elem, -1,
"type"
, NULL);
293
if
(attr >= 0)
294
snprintf(svc->type, 257,
"%.*s"
,
NAD_AVAL_L
(pkt->
nad
, attr),
NAD_AVAL
(pkt->
nad
, attr));
295
else
296
strcpy(svc->type,
"unknown"
);
297
298
/* features */
299
elem =
nad_find_elem
(pkt->
nad
, qelem, -1,
"feature"
, 1);
300
while
(elem >= 0)
301
{
302
attr =
nad_find_attr
(pkt->
nad
, elem, -1,
"var"
, NULL);
303
if
(attr < 0)
304
{
305
elem =
nad_find_elem
(pkt->
nad
, elem, -1,
"feature"
, 0);
306
continue
;
307
}
308
309
xhash_put
(svc->features,
pstrdupx
(
xhash_pool
(svc->features),
NAD_AVAL
(pkt->
nad
, attr),
NAD_AVAL_L
(pkt->
nad
, attr)), (
void
*) 1);
310
311
elem =
nad_find_elem
(pkt->
nad
, elem, -1,
"feature"
, 0);
312
}
313
314
/* regenerate packets */
315
_disco_generate_packets
(mod, d);
316
317
pkt_free
(pkt);
318
319
return
mod_HANDLED
;
320
}
321
323
static
mod_ret_t
_disco_in_sess_result
(
mod_instance_t
mi,
sess_t
sess,
pkt_t
pkt)
324
{
325
/* it has to have no to address or self bare jid */
326
if
(pkt->
to
!= NULL && strcmp(
jid_user
(sess->
jid
),
jid_full
(pkt->
to
)))
327
{
328
return
mod_PASS
;
329
}
330
331
/* identity */
332
nad_append_elem
(pkt->
nad
, -1,
"identity"
, 3);
333
nad_append_attr
(pkt->
nad
, -1,
"category"
,
"account"
);
334
nad_append_attr
(pkt->
nad
, -1,
"type"
,
"registered"
);
335
336
/* tell them */
337
nad_set_attr
(pkt->
nad
, 1, -1,
"type"
,
"result"
, 6);
338
pkt_sess
(
pkt_tofrom
(pkt), sess);
339
340
return
mod_HANDLED
;
341
}
342
344
static
void
_disco_sessions_result
(
module_t
mod, disco_t d,
pkt_t
pkt) {
345
int
ns;
346
sess_t
sess;
347
union
xhashv
xhv;
348
349
ns =
nad_add_namespace
(pkt->
nad
,
uri_DISCO_ITEMS
, NULL);
350
nad_append_elem
(pkt->
nad
, ns,
"query"
, 2);
351
nad_append_attr
(pkt->
nad
, -1,
"node"
,
"sessions"
);
352
353
if
(
xhash_iter_first
(mod->
mm
->
sm
->
sessions
))
354
do
{
355
xhv.
sess_val
= &sess;
356
xhash_iter_get
(mod->
mm
->
sm
->
sessions
, NULL, NULL, xhv.
val
);
357
358
nad_append_elem
(pkt->
nad
, ns,
"item"
, 3);
359
nad_append_attr
(pkt->
nad
, -1,
"jid"
,
jid_full
(sess->
jid
));
360
nad_append_attr
(pkt->
nad
, -1,
"name"
,
"Active session"
);
361
}
while
(
xhash_iter_next
(mod->
mm
->
sm
->
sessions
));
362
}
363
365
static
mod_ret_t
_disco_pkt_sm
(
mod_instance_t
mi,
pkt_t
pkt) {
366
module_t
mod = mi->
mod
;
367
disco_t d = (
disco_t
) mod->
private
;
368
pkt_t
result;
369
int
node, ns;
370
371
/* disco info results go to a seperate function */
372
if
(pkt->
type
==
pkt_IQ_RESULT
&& pkt->
ns
==
ns_DISCO_INFO
)
373
return
_disco_pkt_sm_populate
(mi, pkt);
374
375
/* check whether the requested domain is serviced here */
376
if
(
xhash_get
(mod->
mm
->
sm
->
hosts
, pkt->
to
->
domain
) == NULL)
377
return
-
stanza_err_ITEM_NOT_FOUND
;
378
379
/* we want disco or agents gets */
380
if
(pkt->
type
!=
pkt_IQ
|| !(pkt->
ns
==
ns_DISCO_INFO
|| pkt->
ns
==
ns_DISCO_ITEMS
|| pkt->
ns
==
ns_AGENTS
))
381
return
mod_PASS
;
382
383
/* generate the caches if we haven't yet */
384
if
(d->
disco_info_result
== NULL)
385
_disco_generate_packets
(mod, d);
386
387
node =
nad_find_attr
(pkt->
nad
, 2, -1,
"node"
, NULL);
388
389
/* they want to know about us */
390
if
(pkt->
ns
==
ns_DISCO_INFO
) {
391
/* respond with cached disco info packet if no node given */
392
if
(node < 0) {
393
result =
pkt_dup
(d->
disco_info_result
,
jid_full
(pkt->
from
),
jid_full
(pkt->
to
));
394
395
node =
nad_find_attr
(pkt->
nad
, 2, -1,
"node"
, NULL);
396
if
(node >= 0) {
397
nad_set_attr
(result->nad, 2, -1,
"node"
,
NAD_AVAL
(pkt->
nad
, node),
NAD_AVAL_L
(pkt->
nad
, node));
398
}
399
400
pkt_id
(pkt, result);
401
pkt_free
(pkt);
402
403
/* off it goes */
404
pkt_router
(result);
405
406
return
mod_HANDLED
;
407
}
408
else
if
(
NAD_AVAL_L
(pkt->
nad
, node) == 8 && strncmp(
"sessions"
,
NAD_AVAL
(pkt->
nad
, node), 8) == 0) {
409
/* priviliged op, make sure they're allowed */
410
if
(!
aci_check
(mod->
mm
->
sm
->
acls
,
"disco"
, pkt->
from
))
411
return
-
stanza_err_ITEM_NOT_FOUND
;
/* we never advertised it, so we can pretend its not here */
412
413
result =
pkt_create
(mod->
mm
->
sm
,
"iq"
,
"result"
,
jid_full
(pkt->
from
),
jid_full
(pkt->
to
));
414
pkt_id
(pkt, result);
415
pkt_free
(pkt);
416
417
ns =
nad_add_namespace
(result->nad,
uri_DISCO_INFO
, NULL);
418
nad_append_elem
(result->nad, ns,
"query"
, 2);
419
nad_append_elem
(result->nad, ns,
"identity"
, 3);
420
nad_append_attr
(result->nad, -1,
"category"
,
"hierarchy"
);
421
nad_append_attr
(result->nad, -1,
"type"
,
"branch"
);
422
nad_append_attr
(result->nad, -1,
"name"
,
ACTIVE_SESSIONS_NAME
);
423
nad_append_elem
(result->nad, -1,
"feature"
, 3);
424
nad_append_attr
(result->nad, -1,
"var"
,
uri_DISCO_INFO
);
425
nad_append_elem
(result->nad, -1,
"feature"
, 3);
426
nad_append_attr
(result->nad, -1,
"var"
,
uri_DISCO_ITEMS
);
427
428
/* off it goes */
429
pkt_router
(result);
430
431
return
mod_HANDLED
;
432
}
433
else
434
return
-
stanza_err_ITEM_NOT_FOUND
;
435
}
436
437
/* handle agents */
438
if
(pkt->
ns
==
ns_AGENTS
) {
439
/* make sure we're supporting compat */
440
if
(!d->
agents
)
441
return
-
stanza_err_NOT_ALLOWED
;
442
443
result =
pkt_dup
(d->
agents_result
,
jid_full
(pkt->
from
),
jid_full
(pkt->
to
));
444
pkt_id
(pkt, result);
445
pkt_free
(pkt);
446
447
/* off it goes */
448
pkt_router
(result);
449
450
return
mod_HANDLED
;
451
}
452
453
/* they want to know who we know about */
454
if
(node < 0) {
455
/* no node, so toplevel services */
456
result =
pkt_dup
(d->
disco_items_result
,
jid_full
(pkt->
from
),
jid_full
(pkt->
to
));
457
pkt_id
(pkt, result);
458
pkt_free
(pkt);
459
460
/* if they have privs, then show them any administrative things they can disco to */
461
if
(
aci_check
(mod->
mm
->
sm
->
acls
,
"disco"
, result->to)) {
462
nad_append_elem
(result->nad,
NAD_ENS
(result->nad, 2),
"item"
, 3);
463
nad_append_attr
(result->nad, -1,
"jid"
,
jid_full
(result->from));
464
nad_append_attr
(result->nad, -1,
"node"
,
"sessions"
);
465
nad_append_attr
(result->nad, -1,
"name"
,
ACTIVE_SESSIONS_NAME
);
466
}
467
468
pkt_router
(result);
469
470
return
mod_HANDLED
;
471
}
472
473
/* active sessions */
474
if
(
NAD_AVAL_L
(pkt->
nad
, node) == 8 && strncmp(
"sessions"
,
NAD_AVAL
(pkt->
nad
, node), 8) == 0) {
475
/* priviliged op, make sure they're allowed */
476
if
(!
aci_check
(mod->
mm
->
sm
->
acls
,
"disco"
, pkt->
from
))
477
return
-
stanza_err_ITEM_NOT_FOUND
;
/* we never advertised it, so we can pretend its not here */
478
479
result =
pkt_create
(mod->
mm
->
sm
,
"iq"
,
"result"
,
jid_full
(pkt->
from
),
jid_full
(pkt->
to
));
480
pkt_id
(pkt, result);
481
pkt_free
(pkt);
482
483
_disco_sessions_result
(mod, d, result);
484
485
/* off it goes */
486
pkt_router
(result);
487
488
return
mod_HANDLED
;
489
}
490
491
/* I dunno what they're asking for */
492
return
-
stanza_err_ITEM_NOT_FOUND
;
493
}
494
496
static
mod_ret_t
_disco_in_sess
(
mod_instance_t
mi,
sess_t
sess,
pkt_t
pkt) {
497
module_t
mod = mi->
mod
;
498
disco_t d = (
disco_t
) mod->
private
;
499
pkt_t
result;
500
501
/* disco info requests go to a seperate function */
502
if
(pkt->
type
==
pkt_IQ
&& pkt->
ns
==
ns_DISCO_INFO
)
503
return
_disco_in_sess_result
(mi, sess, pkt);
504
505
/* we want agents gets */
506
if
(pkt->
type
!=
pkt_IQ
|| pkt->
ns
!=
ns_AGENTS
|| pkt->
to
!= NULL)
507
return
mod_PASS
;
508
509
/* fail if its not enabled */
510
if
(!d->
agents
)
511
return
-
stanza_err_NOT_ALLOWED
;
512
513
/* generate the caches if we haven't yet */
514
if
(d->
disco_info_result
== NULL)
515
_disco_generate_packets
(mod, d);
516
517
/* pre-canned response */
518
result =
pkt_dup
(d->
agents_result
, NULL, NULL);
519
pkt_id
(pkt, result);
520
pkt_free
(pkt);
521
522
/* off it goes */
523
pkt_sess
(result, sess);
524
525
return
mod_HANDLED
;
526
}
527
529
static
mod_ret_t
_disco_pkt_router
(
mod_instance_t
mi,
pkt_t
pkt)
530
{
531
module_t
mod = mi->
mod
;
532
disco_t d = (
disco_t
) mod->
private
;
533
service_t svc;
534
pkt_t
request;
535
int
ns;
536
537
/* we want advertisements with a from address */
538
if
(pkt->
from
== NULL || !(pkt->
rtype
&
route_ADV
))
539
return
mod_PASS
;
540
541
/* component online */
542
if
(pkt->
rtype
==
route_ADV
)
543
{
544
log_debug
(
ZONE
,
"presence from component %s, issuing discovery request"
,
jid_full
(pkt->
from
));
545
546
/* new disco get packet */
547
request =
pkt_create
(mod->
mm
->
sm
,
"iq"
,
"get"
,
jid_full
(pkt->
from
), mod->
mm
->
sm
->
id
);
548
pkt_id_new
(request);
549
ns =
nad_add_namespace
(request->nad,
uri_DISCO_INFO
, NULL);
550
nad_append_elem
(request->nad, ns,
"query"
, 2);
551
552
pkt_router
(request);
553
554
/* done with this */
555
pkt_free
(pkt);
556
557
return
mod_HANDLED
;
558
}
559
560
/* it went away. find it and remove it */
561
svc =
xhash_get
(d->
dyn
,
jid_full
(pkt->
from
));
562
if
(svc != NULL)
563
{
564
log_debug
(
ZONE
,
"dropping entry for %s"
,
jid_full
(pkt->
from
));
565
566
xhash_zap
(d->
dyn
,
jid_full
(pkt->
from
));
567
568
jid_free
(svc->jid);
569
xhash_free
(svc->features);
570
free(svc);
571
572
/* unify */
573
_disco_unify_lists
(d);
574
_disco_generate_packets
(mod, d);
575
}
576
577
/* done */
578
pkt_free
(pkt);
579
580
return
mod_HANDLED
;
581
}
582
583
static
void
_disco_free_walker
(
const
char
*key,
int
keylen,
void
*
val
,
void
*arg) {
584
service_t svc = (
service_t
) val;
585
586
jid_free
(svc->
jid
);
587
xhash_free
(svc->
features
);
588
free(svc);
589
}
590
591
static
void
_disco_free
(
module_t
mod) {
592
disco_t d = (
disco_t
) mod->
private
;
593
594
xhash_walk
(d->
stat
,
_disco_free_walker
, NULL);
595
xhash_walk
(d->
dyn
,
_disco_free_walker
, NULL);
596
597
xhash_free
(d->
stat
);
598
xhash_free
(d->
dyn
);
599
xhash_free
(d->
un
);
600
601
if
(d->
disco_info_result
!= NULL)
pkt_free
(d->
disco_info_result
);
602
if
(d->
disco_items_result
!= NULL)
pkt_free
(d->
disco_items_result
);
603
if
(d->
agents_result
!= NULL)
pkt_free
(d->
agents_result
);
604
605
free(d);
606
}
607
608
DLLEXPORT
int
module_init
(
mod_instance_t
mi,
char
*arg)
609
{
610
module_t
mod = mi->
mod
;
611
disco_t d;
612
nad_t
nad;
613
int
items, item, jid, name, category, type, ns;
614
service_t svc;
615
616
if
(mod->
init
)
return
0;
617
618
log_debug
(
ZONE
,
"disco module init"
);
619
620
d = (
disco_t
) calloc(1,
sizeof
(
struct
disco_st
));
621
622
/* new hashes to store the lists in */
623
d->
dyn
=
xhash_new
(51);
624
d->
stat
=
xhash_new
(51);
625
626
/* identity */
627
d->
category
=
config_get_one
(mod->
mm
->
sm
->
config
,
"discovery.identity.category"
, 0);
628
if
(d->
category
== NULL) d->
category
=
"server"
;
629
d->
type
=
config_get_one
(mod->
mm
->
sm
->
config
,
"discovery.identity.type"
, 0);
630
if
(d->
type
== NULL) d->
type
=
"im"
;
631
d->
name
=
config_get_one
(mod->
mm
->
sm
->
config
,
"discovery.identity.name"
, 0);
632
if
(d->
name
== NULL) d->
name
=
"Jabber IM server"
;
633
634
/* agents compatibility */
635
d->
agents
=
config_get
(mod->
mm
->
sm
->
config
,
"discovery.agents"
) != NULL;
636
637
if
(d->
agents
)
638
log_debug
(
ZONE
,
"agents compat enabled"
);
639
640
/* our data */
641
mod->
private
= (
void
*) d;
642
643
/* our handlers */
644
mod->
pkt_sm
=
_disco_pkt_sm
;
645
mod->
in_sess
=
_disco_in_sess
;
646
mod->
pkt_router
=
_disco_pkt_router
;
647
mod->
free
=
_disco_free
;
648
649
nad = mod->
mm
->
sm
->
config
->
nad
;
650
651
/* we support a number of things */
652
feature_register
(mod->
mm
->
sm
,
uri_DISCO_INFO
);
653
feature_register
(mod->
mm
->
sm
,
uri_DISCO_ITEMS
);
654
if
(d->
agents
)
655
feature_register
(mod->
mm
->
sm
,
uri_AGENTS
);
656
657
/* populate the static list from the config file */
658
if
((items =
nad_find_elem
(nad, 0, -1,
"discovery"
, 1)) < 0 || (items =
nad_find_elem
(nad, items, -1,
"items"
, 1)) < 0)
659
return
0;
660
661
item =
nad_find_elem
(nad, items, -1,
"item"
, 1);
662
while
(item >= 0)
663
{
664
/* jid is required */
665
jid =
nad_find_attr
(nad, item, -1,
"jid"
, NULL);
666
if
(jid < 0)
667
{
668
item =
nad_find_elem
(nad, item, -1,
"item"
, 0);
669
continue
;
670
}
671
672
/* new service */
673
svc = (
service_t
) calloc(1,
sizeof
(
struct
service_st
));
674
675
svc->
features
=
xhash_new
(13);
676
677
svc->
jid
=
jid_new
(
NAD_AVAL
(nad, jid),
NAD_AVAL_L
(nad, jid));
678
679
/* link it in */
680
xhash_put
(d->
stat
,
jid_full
(svc->
jid
), (
void
*) svc);
681
682
/* copy the name */
683
name =
nad_find_attr
(nad, item, -1,
"name"
, NULL);
684
if
(name >= 0)
685
snprintf(svc->
name
, 257,
"%.*s"
,
NAD_AVAL_L
(nad, name),
NAD_AVAL
(nad, name));
686
687
/* category and type */
688
category =
nad_find_attr
(nad, item, -1,
"category"
, NULL);
689
if
(category >= 0)
690
snprintf(svc->
category
, 257,
"%.*s"
,
NAD_AVAL_L
(nad, category),
NAD_AVAL
(nad, category));
691
else
692
strcpy(svc->
category
,
"unknown"
);
693
694
type =
nad_find_attr
(nad, item, -1,
"type"
, NULL);
695
if
(type >= 0)
696
snprintf(svc->
type
, 257,
"%.*s"
,
NAD_AVAL_L
(nad, type),
NAD_AVAL
(nad, type));
697
else
698
strcpy(svc->
type
,
"unknown"
);
699
700
/* namespaces */
701
ns =
nad_find_elem
(nad, item, -1,
"ns"
, 1);
702
while
(ns >= 0)
703
{
704
if
(
NAD_CDATA_L
(nad, ns) > 0)
705
xhash_put
(svc->
features
,
pstrdupx
(
xhash_pool
(svc->
features
),
NAD_CDATA
(nad, ns),
NAD_CDATA_L
(nad, ns)), (
void
*) 1);
706
707
ns =
nad_find_elem
(nad, ns, -1,
"ns"
, 0);
708
}
709
710
item =
nad_find_elem
(nad, item, -1,
"item"
, 0);
711
712
log_debug
(
ZONE
,
"added %s to static list"
,
jid_full
(svc->
jid
));
713
}
714
715
/* generate the initial union list */
716
_disco_unify_lists
(d);
717
718
/* we don't generate the packets here, because the router conn isn't up yet, and so we don't have a nad cache */
719
720
return
0;
721
}
Generated by
1.8.1.1