Browse code

RLS modified to be usable not only with XCAP server, but with standard web server too, with short description in presence handbook about how to simulate XCAP server with web server

Vaclav Kubart authored on 21/11/2005 15:54:37
Showing 6 changed files
... ...
@@ -202,7 +202,7 @@ conn.close()
202 202
 # store resource-list document for user
203 203
 #
204 204
 
205
-uri = "/xcap-root/resource-lists/users/smith"
205
+uri = "/xcap-root/resource-lists/users/smith/resource-list.xml"
206 206
 headers = {"Content-Type": "application/resource-lists+xml"}
207 207
 bf = file("list.xml", "r")
208 208
 body = bf.read(65536);
... ...
@@ -263,17 +263,17 @@ conn.close()
263 263
 This document can contain references to users buddy lists like
264 264
 <quote>smith-list@iptel.org</quote> which points to buddy list for user smith
265 265
 named <quote>default</quote> and can contain such lists directly.
266
-<caution><para>EyeBeam stores user's <quote>buddy list</quote> in 
266
+<!--<caution><para>EyeBeam stores user's <quote>buddy list</quote> in 
267 267
 <filename>&lt;XCAP-root&gt;/users/&lt;username&gt;/resource-list.xml</filename>, 
268 268
 not in
269 269
 <filename>&lt;XCAP-root&gt;/users/&lt;username&gt;</filename> which was used in 
270
-these examples.</para></caution>
270
+these examples.</para></caution>-->
271 271
 </para>
272 272
 <programlisting>
273 273
 &lt;?xml version="1.0" encoding="UTF-8"?&gt;
274 274
 &lt;rls-services&gt;
275 275
 	&lt;service uri="sip:smith-list@iptel.org"&gt;
276
-		&lt;resource-list&gt;http://localhost/xcap-root/resource-lists/users/smith/~~/resource-lists/list[@name=%22default%22]&lt;/resource-list&gt;
276
+		&lt;resource-list&gt;http://localhost/xcap-root/resource-lists/users/smith/resource-list.xml/~~/resource-lists/list[@name=%22default%22]&lt;/resource-list&gt;
277 277
 		&lt;packages&gt;
278 278
 			&lt;package&gt;presence&lt;/package&gt;
279 279
 		&lt;/packages&gt;
... ...
@@ -345,6 +345,189 @@ exist extensions for particular types of configuration - for purpose of this
345 345
 document only configuration from presence area will be mentioned.
346 346
 </para>-->
347 347
 
348
+<section><title>XCAP server simulation</title>
349
+<para>XCAP server is a HTTP server with some features like document validation
350
+or ability of working with parts of stored documents. If you have no XCAP
351
+server, you can simulate it using standard web server. There are not many XCAP
352
+servers available today, thus the simulation may be interesting for - at least -
353
+demonstration or testing purposes.
354
+</para>
355
+
356
+<para>Depending on your needs you can
357
+<itemizedlist>
358
+	<listitem><para>create hierarchical directory structure of XML documents according to
359
+	<xref linkend="pres_draft_xcap"/></para></listitem>
360
+	<listitem><para>allow upload (handle HTTP PUT method) which stores documents into the 
361
+	directory structure</para></listitem>
362
+	<listitem><para>improve upload to validate documents according to schema
363
+	(every sort of XCAP document should have their XSD published)</para></listitem>
364
+	<listitem><para>allow document removing (handle DELETE method)</para></listitem>
365
+	<listitem><para>process HTTP GET requests with a CGI-script so it processes
366
+	queries for partial documents</para></listitem>
367
+</itemizedlist>
368
+</para>
369
+
370
+<section><title>Directory structure</title>
371
+<para>Presence modules use XCAP documents stored in structure like this:
372
+<itemizedlist><title>xcap-root</title>
373
+	<listitem><para><filename>pres-rules</filename></para>
374
+	<itemizedlist>
375
+		<listitem><para><filename>users</filename></para>
376
+		<itemizedlist>
377
+			<listitem><para><filename>smith</filename></para>
378
+			<itemizedlist>
379
+				<listitem><para><filename>presence-rules.xml</filename> (file
380
+				containg presence authorization rules for user smith)</para></listitem>
381
+			</itemizedlist>
382
+			</listitem>
383
+			<listitem><para><filename>joe</filename></para>
384
+			<itemizedlist>
385
+				<listitem><para><filename>presence-rules.xml</filename> (file containing
386
+				presence authorization rules for user joe)</para></listitem>
387
+			</itemizedlist>
388
+			</listitem>
389
+			<listitem><para>... (directories for other users)</para></listitem>
390
+		</itemizedlist>
391
+		</listitem>
392
+	</itemizedlist></listitem>
393
+	
394
+	<listitem><para><filename>resource-lists</filename></para>
395
+	<itemizedlist>
396
+		<listitem><para><filename>users</filename></para>
397
+		<itemizedlist>
398
+			<listitem><para><filename>smith</filename></para>
399
+			<itemizedlist>
400
+				<listitem><para><filename>resource-list.xml</filename> (file
401
+				containing resources lists for user smith)</para></listitem>
402
+			</itemizedlist>
403
+			</listitem>
404
+			<listitem><para><filename>joe</filename></para>
405
+			<itemizedlist>
406
+				<listitem><para><filename>resource-list.xml</filename> (file
407
+				containing resource lists for user joe)</para></listitem>
408
+			</itemizedlist>
409
+			</listitem>
410
+			<listitem><para>... (directories for other users)</para></listitem>
411
+		</itemizedlist>
412
+		</listitem>
413
+		<!-- rls-services globals used instead this
414
+		<listitem><para><filename>global</filename></para>
415
+		<itemizedlist>
416
+			<listitem><para><filename>index</filename> (file containing global
417
+			resource lists)</para></listitem>
418
+		</itemizedlist>
419
+		</listitem>-->
420
+	</itemizedlist></listitem>
421
+	
422
+	<listitem><para><filename>rls-services</filename></para>
423
+	<itemizedlist>
424
+		<listitem><para><filename>global</filename></para>
425
+		<itemizedlist>
426
+			<listitem><para><filename>index</filename> (file containing global
427
+			rls-services documents)</para></listitem>
428
+		</itemizedlist>
429
+		</listitem>
430
+	</itemizedlist></listitem>
431
+	
432
+</itemizedlist>
433
+</para>
434
+</section> <!-- directory structure -->
435
+
436
+<section><title>Usage with SER</title>
437
+<para>You don't need a full XCAP server for presence authorization documents -
438
+these are read as standalone documents from directories of standalone users.
439
+</para>
440
+
441
+<para>For resource lists you have to install a full XCAP server. Only if you use
442
+<quote>simple</quote> mode of list subscription processing (see <link
443
+linkend="rls.parameters">RLS module parameters</link>) you do not need it.
444
+</para>
445
+</section>
446
+
447
+<section><title>XCAP simulation examples</title>
448
+<para>Examples presented here can be used as simple XCAP server simulation. It
449
+is able to handle PUT method (for whole XML documents).
450
+</para>
451
+
452
+<example><title>Apache2 configuration</title>
453
+<programlisting><![CDATA[
454
+...
455
+Alias /xcap-root /var/simulated-xcap-root
456
+<Directory /var/simulated-xcap-root>
457
+	Options Indexes FollowSymLinks MultiViews
458
+	Script PUT /cgi-bin/upload
459
+	<Limit PUT DELETE GET>
460
+		Order Allow,Deny
461
+		Deny from none
462
+		Allow from all
463
+	</Limit>
464
+</Directory>
465
+...
466
+]]></programlisting>
467
+</example>
468
+
469
+<example><title>Simple (and dangerous) cgi-script for upload</title>
470
+<para>This code is written in C and it is able to create directories if needed, but its usage in
471
+presented form is realy unsafe! You have to compile it and put into directory
472
+with other CGI scripts.</para>
473
+<programlisting><![CDATA[
474
+#include <stdio.h>
475
+#include <stdlib.h>
476
+#include <string.h>
477
+
478
+#include <sys/stat.h>
479
+#include <sys/types.h>
480
+
481
+void copy_file(const char *filename)
482
+{
483
+	char buf[2048];
484
+	int r;
485
+	FILE *f;
486
+	
487
+	f = fopen(filename, "wb");
488
+	if (f) {
489
+		while (!feof(stdin)) {
490
+			r = fread(buf, 1, sizeof(buf), stdin);
491
+			fwrite(buf, 1, r, f);
492
+		}
493
+		fclose(f);
494
+	}
495
+}
496
+
497
+int main(int argc, char **argv)
498
+{
499
+	char *filename, *x;
500
+	char tmp[1024];
501
+	int res = 0;
502
+	
503
+	filename = getenv ("PATH_TRANSLATED");
504
+
505
+	strcpy(tmp, filename);
506
+	x = strrchr(tmp, '/');
507
+	if (x) {
508
+		*x = 0;
509
+		res = mkdir(tmp, 0755);		/* ! dangerous ! */
510
+	}
511
+	else {
512
+		printf("Status: 500\n");
513
+		printf("Content-Type: text/html\n\n");
514
+		printf("<html><head/>\n<body>Incorrect filename</body></html>\n");	
515
+		return -1;
516
+	}
517
+	
518
+	copy_file(filename); /* ! dangerous ! */
519
+		
520
+	printf("Status: 200\n");
521
+	printf("Content-Type: text/html\n\n");
522
+	printf("<html><head><title>Upload</title>\n</head>\n<body>Finished...</body></html>\n");
523
+	
524
+	return 0;
525
+}
526
+]]></programlisting>
527
+</example>
528
+
529
+</section><!-- XCAP simulation examples -->
348 530
 
531
+</section> <!-- XCAP server simulation -->
349 532
 
350 533
 </section>
... ...
@@ -108,6 +108,31 @@ char *xcap_uri_for_rls_resource(const char *xcap_root, const str_t *uri)
108 108
 	return dst;
109 109
 }
110 110
 
111
+char *xcap_uri_for_rls_services(const char *xcap_root)
112
+{
113
+	dstring_t s;
114
+	int l;
115
+	char *dst = NULL;
116
+
117
+	if (!xcap_root) return NULL;
118
+	l = strlen(xcap_root);
119
+	dstr_init(&s, 2 * l + 32);
120
+	dstr_append(&s, xcap_root, l);
121
+	if (xcap_root[l - 1] != '/') dstr_append(&s, "/", 1);
122
+	dstr_append_zt(&s, "rls-services/global/index");
123
+	
124
+	l = dstr_get_data_length(&s);
125
+	if (l > 0) {
126
+		dst = (char *)cds_malloc(l + 1);
127
+		if (dst) {
128
+			dstr_get_data(&s, dst);
129
+			dst[l] = 0;
130
+		}
131
+	}
132
+	dstr_destroy(&s);
133
+	return dst;
134
+}
135
+
111 136
 void free_flat_list(flat_list_t *list)
112 137
 {
113 138
 	flat_list_t *f, *e;
... ...
@@ -492,6 +517,21 @@ static int verify_package(service_t *srv, const str_t *package)
492 517
 	return 0;
493 518
 }
494 519
 
520
+static service_t *find_service(rls_services_t *rls, const str_t *uri)
521
+{
522
+	service_t *srv;
523
+	
524
+	if (!rls) return NULL;
525
+	
526
+	srv = SEQUENCE_FIRST(rls->rls_services);
527
+	while (srv) {
528
+		TRACE_LOG("comparing %s to %.*s\n", srv->uri, FMT_STR(*uri));
529
+		if (str_strcmp(uri, srv->uri) == 0) return srv;
530
+		srv = SEQUENCE_NEXT(srv);
531
+	}
532
+	return NULL;
533
+}
534
+
495 535
 /* ------- rls examining ------- */
496 536
 
497 537
 int get_rls(const char *xcap_root, const str_t *uri, xcap_query_t *xcap_params, const str_t *package, flat_list_t **dst)
... ...
@@ -543,7 +583,7 @@ int get_rls(const char *xcap_root, const str_t *uri, xcap_query_t *xcap_params,
543 583
 
544 584
 	/* verify the package */
545 585
 	if (verify_package(service, package) != 0) {
546
-		cds_free(service);
586
+		free_service(service);
547 587
 		return RES_BAD_EVENT_PACKAGE_ERR;
548 588
 	}
549 589
 	
... ...
@@ -561,6 +601,81 @@ int get_rls(const char *xcap_root, const str_t *uri, xcap_query_t *xcap_params,
561 601
 	return RES_OK;
562 602
 }
563 603
 
604
+int get_rls_from_full_doc(const char *xcap_root, const str_t *uri, xcap_query_t *xcap_params, const str_t *package, flat_list_t **dst)
605
+{
606
+	char *data = NULL;
607
+	int dsize = 0;
608
+	rls_services_t *rls = NULL;
609
+	service_t *service = NULL;
610
+	xcap_query_t xcap;
611
+	str_t curi;
612
+	int res;
613
+
614
+	if (!dst) return RES_INTERNAL_ERR;
615
+	
616
+	if (xcap_params) {
617
+		xcap = *xcap_params;
618
+	}
619
+	else memset(&xcap, 0, sizeof(xcap));
620
+
621
+	/* get basic document */
622
+	xcap.uri = xcap_uri_for_rls_services(xcap_root);
623
+	TRACE_LOG("XCAP uri \'%s\'\n", xcap.uri ? xcap.uri: "???");
624
+	res = xcap_query(&xcap, &data, &dsize);
625
+	if (res != 0) {
626
+		ERROR_LOG("get_rls(): XCAP problems for uri \'%s\'\n", xcap.uri ? xcap.uri: "???");
627
+		if (data) {
628
+			cds_free(data);
629
+		}
630
+		if (xcap.uri) cds_free(xcap.uri);
631
+		return RES_XCAP_QUERY_ERR;
632
+	}
633
+	if (xcap.uri) cds_free(xcap.uri);
634
+	xcap.uri = NULL;
635
+	
636
+	/* parse document as a service element in rls-sources */
637
+	if (parse_rls_services_xml(data, dsize, &rls) != 0) {
638
+		ERROR_LOG("Parsing problems!\n");
639
+		if (rls) free_rls_services(rls);
640
+		if (data) {
641
+			cds_free(data);
642
+		}
643
+		return RES_XCAP_PARSE_ERR;
644
+	}
645
+/*	DEBUG_LOG("%.*s\n", dsize, data);*/
646
+	if (data) cds_free(data);
647
+
648
+	/* try to find given service according to uri */
649
+	canonicalize_uri(uri, &curi);
650
+	service = find_service(rls, &curi); 
651
+	str_free_content(&curi);
652
+	
653
+	if (!service) {
654
+		if (rls) free_rls_services(rls);
655
+		ERROR_LOG("Empty service!\n");
656
+		return RES_INTERNAL_ERR;
657
+	}
658
+
659
+	/* verify the package */
660
+	if (verify_package(service, package) != 0) {
661
+		free_rls_services(rls);
662
+		return RES_BAD_EVENT_PACKAGE_ERR;
663
+	}
664
+	
665
+	/* create flat document */
666
+	res = create_flat_list(service, &xcap, xcap_root, dst);
667
+	if (res != RES_OK) {
668
+		ERROR_LOG("Flat list creation error\n");
669
+		free_rls_services(rls);
670
+		free_flat_list(*dst);
671
+		*dst = NULL;
672
+		return res;
673
+	}
674
+	free_rls_services(rls);
675
+	
676
+	return RES_OK;
677
+}
678
+
564 679
 char *xcap_uri_for_resource_list(const char *xcap_root, const str_t *user)
565 680
 {
566 681
 	dstring_t s;
... ...
@@ -620,8 +735,8 @@ int get_resource_list_as_rls(const char *xcap_root, const str_t *user, xcap_quer
620 735
 	if (xcap.uri) cds_free(xcap.uri);
621 736
 	xcap.uri = NULL;
622 737
 	
623
-	/* parse document as a list element in rls-sources */
624
-	if (parse_list_xml(data, dsize, &list) != 0) {
738
+	/* parse document as a list element in resource-lists */
739
+	if (parse_as_list_content_xml(data, dsize, &list) != 0) {
625 740
 		ERROR_LOG("Parsing problems!\n");
626 741
 		if (list) free_list(list);
627 742
 		if (data) {
... ...
@@ -631,6 +746,8 @@ int get_resource_list_as_rls(const char *xcap_root, const str_t *user, xcap_quer
631 746
 	}
632 747
 /*	DEBUG_LOG("%.*s\n", dsize, data);*/
633 748
 	if (data) cds_free(data);
749
+
750
+	/* rs -> list */
634 751
 	
635 752
 	if (!list) {
636 753
 		ERROR_LOG("Empty resource list!\n");
... ...
@@ -43,6 +43,7 @@ typedef struct _flat_list_t {
43 43
 char *xcap_uri_for_rls_resource(const char *xcap_root, const str_t *uri);
44 44
 void canonicalize_uri(const str_t *uri, str_t *dst);
45 45
 int get_rls(const char *xcap_root, const str_t *uri, xcap_query_t *xcap_params, const str_t *package, flat_list_t **dst);
46
+int get_rls_from_full_doc(const char *xcap_root, const str_t *uri, xcap_query_t *xcap_params, const str_t *package, flat_list_t **dst);
46 47
 int get_resource_list_as_rls(const char *xcap_root, const str_t *user, xcap_query_t *xcap_params, flat_list_t **dst);
47 48
 void free_flat_list(flat_list_t *list);
48 49
 
... ...
@@ -149,7 +149,7 @@ static int read_external(xmlNode *entry_node, external_t **dst)
149 149
 	return 0;
150 150
 }
151 151
 
152
-int read_list(xmlNode *list_node, list_t **dst)
152
+int read_list(xmlNode *list_node, list_t **dst, int read_content_only)
153 153
 {
154 154
 	int res = 0;
155 155
 	xmlAttr *a;
... ...
@@ -164,10 +164,12 @@ int read_list(xmlNode *list_node, list_t **dst)
164 164
 	memset(*dst, 0, sizeof(list_t));
165 165
 
166 166
 	/* get attributes */
167
-	a = find_attr(list_node->properties, "name");
168
-	if (a) {
169
-		a_val = get_attr_value(a);
170
-		if (a_val) (*dst)->name = zt_strdup(a_val);
167
+	if (!read_content_only) {
168
+		a = find_attr(list_node->properties, "name");
169
+		if (a) {
170
+			a_val = get_attr_value(a);
171
+			if (a_val) (*dst)->name = zt_strdup(a_val);
172
+		}
171 173
 	}
172 174
 
173 175
 	/* read entries */
... ...
@@ -180,7 +182,7 @@ int read_list(xmlNode *list_node, list_t **dst)
180 182
 			memset(l, 0, sizeof(*l));
181 183
 			
182 184
 			if (cmp_node(n, "list", rl_namespace) >= 0) {
183
-				res = read_list(n, &l->u.list);
185
+				res = read_list(n, &l->u.list, 0);
184 186
 				if (res == 0) {
185 187
 					if (l->u.list) {
186 188
 						l->type = lct_list;
... ...
@@ -266,7 +268,7 @@ static int read_resource_lists(xmlNode *root, resource_lists_t **dst)
266 268
 	while (n) {
267 269
 		if (n->type == XML_ELEMENT_NODE) {
268 270
 			if (cmp_node(n, "list", rl_namespace) >= 0) {
269
-				res = read_list(n, &l);
271
+				res = read_list(n, &l, 0);
270 272
 				if (res == 0) {
271 273
 					if (l) SEQUENCE_ADD(rl->lists, last_l, l);
272 274
 				}
... ...
@@ -309,7 +311,25 @@ int parse_list_xml(const char *data, int data_len, list_t **dst)
309 311
 		return -1;
310 312
 	}
311 313
 	
312
-	res = read_list(xmlDocGetRootElement(doc), dst);
314
+	res = read_list(xmlDocGetRootElement(doc), dst, 0);
315
+
316
+	xmlFreeDoc(doc);
317
+	return res;
318
+}
319
+
320
+int parse_as_list_content_xml(const char *data, int data_len, list_t **dst)
321
+{
322
+	int res = 0;
323
+	xmlDocPtr doc; /* the resulting document tree */
324
+
325
+	if (dst) *dst = NULL;
326
+	doc = xmlReadMemory(data, data_len, NULL, NULL, xml_parser_flags);
327
+	if (doc == NULL) {
328
+		ERROR_LOG("can't parse document\n");
329
+		return -1;
330
+	}
331
+	
332
+	res = read_list(xmlDocGetRootElement(doc), dst, 1);
313 333
 
314 334
 	xmlFreeDoc(doc);
315 335
 	return res;
... ...
@@ -90,11 +90,16 @@ typedef struct {
90 90
 
91 91
 int parse_resource_lists_xml(const char *data, int data_len, resource_lists_t **dst);
92 92
 int parse_list_xml(const char *data, int data_len, list_t **dst);
93
+int parse_as_list_content_xml(const char *data, int data_len, list_t **dst);
93 94
 int parse_entry_xml(const char *data, int data_len, entry_t **dst);
94 95
 void free_resource_lists(resource_lists_t *rl);
95 96
 void free_list(list_t *l);
96 97
 void free_entry(entry_t *e);
97 98
 void free_display_names(display_name_t *sequence_first);
98
-int read_list(xmlNode *list_node, list_t **dst);
99
+
100
+/* if read_content_only set then the root element need not to be a list element
101
+ * it may be whatever, but content is parsed as if it is list (useful for reading
102
+ * resource-list as list */
103
+int read_list(xmlNode *list_node, list_t **dst, int read_content_only);
99 104
 
100 105
 #endif
... ...
@@ -130,7 +130,7 @@ int read_service(xmlNode *list_node, service_t **dst)
130 130
 			if (first_node) {
131 131
 				/* element must be list or resource-list */
132 132
 				if (cmp_node(n, "list", rls_namespace) >= 0) {
133
-					res = read_list(n, &(*dst)->content.list);
133
+					res = read_list(n, &(*dst)->content.list, 0);
134 134
 					if ( (res == 0) && ((*dst)->content.list) ) {
135 135
 						(*dst)->content_type = stc_list;
136 136
 					}