Browse code

modules_k/rls, modules_k/presence: Support for splitting large RLS NOTIFY requests into multiple NOTIFY requests

- Many SIP devices (including proxies and SBCs) are not able to handle
vary large SIP requests. Requests over 64k in size when using TCP
are a common problem.

It is easily possible with large (and even not so large) resource
lists for RLS to generate NOTIFY requests that are too big for some
SIP devices to handle.

This enhancement gives RLS the ability to split these large NOTIFY
requests into multiple smaller requests (that still comply with the)
RFC.

The default behaviour is the old (send a single big NOTIFY request)
behaviour.

- Feature added by Andrew Miller at Crocodile RCS

pd authored on 01/08/2011 12:47:52
Showing 9 changed files
... ...
@@ -360,9 +360,8 @@ int update_shtable(shtable_t htable,unsigned int hash_code,
360 360
 	}
361 361
 	else
362 362
 	{
363
-		subs->local_cseq= s->local_cseq;
364
-		s->local_cseq++;	
365
-		s->version= subs->version+ 1;
363
+		subs->local_cseq = ++s->local_cseq;
364
+		s->version = ++subs->version;
366 365
 	}
367 366
 	
368 367
 	if(strncmp(s->contact.s, subs->contact.s, subs->contact.len))
... ...
@@ -37,6 +37,7 @@ Anca-Maria Vamanu
37 37
               3.12. rls_event (str)
38 38
               3.13. outbound_proxy (str)
39 39
               3.14. server_address (str)
40
+              3.15. max_notify_body_length (int)
40 41
 
41 42
         4. Exported Functions
42 43
 
... ...
@@ -64,9 +65,10 @@ Anca-Maria Vamanu
64 64
    1.12. Set rls_event parameter
65 65
    1.13. Set outbound_proxy parameter
66 66
    1.14. Set server_address parameter
67
-   1.15. rls_handle_subscribe usage
68
-   1.16. rls_handle_notify usage
69
-   1.17. rls_update_subs usage
67
+   1.15. Set max_notify_body_length parameter
68
+   1.16. rls_handle_subscribe usage
69
+   1.17. rls_handle_notify usage
70
+   1.18. rls_update_subs usage
70 71
 
71 72
 Chapter 1. Admin Guide
72 73
 
... ...
@@ -94,6 +96,7 @@ Chapter 1. Admin Guide
94 94
         3.12. rls_event (str)
95 95
         3.13. outbound_proxy (str)
96 96
         3.14. server_address (str)
97
+        3.15. max_notify_body_length (int)
97 98
 
98 99
    4. Exported Functions
99 100
 
... ...
@@ -166,6 +169,7 @@ Chapter 1. Admin Guide
166 166
    3.12. rls_event (str)
167 167
    3.13. outbound_proxy (str)
168 168
    3.14. server_address (str)
169
+   3.15. max_notify_body_length (int)
169 170
 
170 171
 3.1. db_url(str)
171 172
 
... ...
@@ -338,6 +342,17 @@ modparam("rls", "outbound_proxy", "sip:presence.kamailio.org")
338 338
 modparam("rls", "server_address", "sip:rls@ip.address.ofyour.proxy:5060")
339 339
 ...
340 340
 
341
+3.15. max_notify_body_length (int)
342
+
343
+   The maximum size that the body of a NOTIFY message may be. If set to 0
344
+   (the default), no size limit is applied. Note that this refers only to
345
+   the body, not the complete NOTIFY message.
346
+
347
+   Example 1.15. Set max_notify_body_length parameter
348
+...
349
+modparam("rls", "max_notify_body_length", 32000)
350
+...
351
+
341 352
 4. Exported Functions
342 353
 
343 354
    4.1. rls_handle_subscribe()
... ...
@@ -353,7 +368,7 @@ modparam("rls", "server_address", "sip:rls@ip.address.ofyour.proxy:5060")
353 353
 
354 354
    This function can be used from REQUEST_ROUTE.
355 355
 
356
-   Example 1.15. rls_handle_subscribe usage
356
+   Example 1.16. rls_handle_subscribe usage
357 357
 ...
358 358
 For presence and rls on the same machine:
359 359
         modparam("rls", "to_presence_code", 10)
... ...
@@ -381,7 +396,7 @@ For rls only:
381 381
 
382 382
    This function can be used from REQUEST_ROUTE.
383 383
 
384
-   Example 1.16. rls_handle_notify usage
384
+   Example 1.17. rls_handle_notify usage
385 385
 ...
386 386
 if(method=="NOTIFY")
387 387
     rls_handle_notify();
... ...
@@ -400,7 +415,7 @@ if(method=="NOTIFY")
400 400
 
401 401
    This function can be used from ANY_ROUTE.
402 402
 
403
-   Example 1.17. rls_update_subs usage
403
+   Example 1.18. rls_update_subs usage
404 404
 ...
405 405
 Within event_route[xhttp:request]:
406 406
         case "PUT":
... ...
@@ -378,6 +378,23 @@ modparam("rls", "server_address", "sip:rls@ip.address.ofyour.proxy:5060")
378 378
 		</example>
379 379
 	</section>
380 380
 
381
+	<section>
382
+		<title><varname>max_notify_body_length</varname> (int)</title>
383
+		<para>
384
+			The maximum size that the body of a NOTIFY message may be. 
385
+            If set to 0 (the default), no size limit is applied.
386
+            Note that this refers only to the body, not the complete NOTIFY message.
387
+		</para>
388
+		<example>
389
+		<title>Set <varname>max_notify_body_length</varname> parameter</title>
390
+		<programlisting format="linespecific">
391
+...
392
+modparam("rls", "max_notify_body_length", 32000)
393
+...
394
+		</programlisting>
395
+		</example>
396
+	</section>
397
+
381 398
 </section>
382 399
 
383 400
 <section>
... ...
@@ -51,19 +51,22 @@
51 51
 
52 52
 typedef struct res_param
53 53
 {
54
-	xmlNodePtr list_node;
55
-	db1_res_t* db_result;
56
-	char** cid_array;
54
+    struct uri_link **next;
57 55
 }res_param_t;
58 56
 
57
+typedef struct uri_link
58
+{
59
+    char *uri;
60
+    struct uri_link *next;
61
+} uri_link_t;
62
+
59 63
 int resource_uri_col=0, content_type_col, pres_state_col= 0,
60 64
 	auth_state_col= 0, reason_col= 0;
61 65
 
62
-str* constr_rlmi_doc(db1_res_t* result, str* rl_uri, int version,
66
+xmlDocPtr constr_rlmi_doc(db1_res_t* result, str* rl_uri, int version,
63 67
 		xmlNodePtr rl_node, char*** cid_array,
64 68
 		str username, str domain);
65
-str* constr_multipart_body(db1_res_t* result,char** cid_array,
66
-		char* boundary_string);
69
+void constr_multipart_body(str *multipart_body, const str *const content_type, const str *const body, str *cid, int boundary_len, char *boundary_string);
67 70
 
68 71
 dlg_t* rls_notify_dlg(subs_t* subs);
69 72
 
... ...
@@ -72,19 +75,28 @@ void rls_notify_callback( struct cell *t, int type, struct tmcb_params *ps);
72 72
 int parse_xcap_uri(char *uri, str *host, unsigned short *port, str *path);
73 73
 int rls_get_resource_list(str *rl_uri, str *username, str *domain,
74 74
 		xmlNodePtr *rl_node, xmlDocPtr *xmldoc);
75
+int add_resource_to_list(char* uri, void* param);
76
+int add_resource(char* uri, xmlNodePtr list_node, str *multipart_body, char * boundary_string, db1_res_t *result, int *len_est);
75 77
 
76
-int send_full_notify(subs_t* subs, xmlNodePtr rl_node, int version, str* rl_uri,
78
+int send_full_notify(subs_t* subs, xmlNodePtr rl_node, str* rl_uri,
77 79
 		unsigned int hash_code)
78 80
 {
79
-	str* rlmi_body= NULL;
81
+	xmlDocPtr rlmi_body= NULL;
82
+    xmlNodePtr list_node= NULL;
80 83
 	str* multipart_body= NULL;
81 84
 	db_key_t query_cols[2], update_cols[2], result_cols[7];
82 85
 	db_val_t query_vals[2], update_vals[2];
83 86
 	db1_res_t *result= NULL;
84
-	int n_result_cols= 0, i;
87
+	int n_result_cols= 0;
85 88
 	char* boundary_string;
86
-	char** cid_array= NULL;
87 89
 	str rlsubs_did= {0, 0};
90
+    str* rlmi_cont= NULL;
91
+    uri_link_t *uri_list_head = NULL;
92
+    int len_est;
93
+    res_param_t param;
94
+    char* body_buffer;
95
+    int size= BUF_REALLOC_SIZE;
96
+    int resource_added = 0; /* Flag to indicate that we have added at least one resource */
88 97
 
89 98
 	LM_DBG("start\n");
90 99
 	/* query in alfabetical order */
... ...
@@ -121,36 +133,99 @@ int send_full_notify(subs_t* subs, xmlNodePtr rl_node, int version, str* rl_uri,
121 121
 	if(result== NULL)
122 122
 		goto error;
123 123
 
124
-	rlmi_body= constr_rlmi_doc(result, rl_uri, version, rl_node, &cid_array, subs->from_user, subs->from_domain);
125
-	if(rlmi_body== NULL)
124
+    /* Allocate an initial buffer for the multipart body.
125
+	 * This buffer will be reallocated if neccessary */
126
+    body_buffer= (char *)pkg_malloc(size);
127
+	if(body_buffer== NULL)
128
+	{
129
+		ERR_MEM(PKG_MEM_STR);
130
+	}
131
+    
132
+    multipart_body= (str*)pkg_malloc(sizeof(str));
133
+	if(multipart_body== NULL)
126 134
 	{
127
-		LM_ERR("while constructing rlmi doc\n");
135
+		ERR_MEM(PKG_MEM_STR);
136
+	}
137
+
138
+	multipart_body->s= body_buffer;
139
+	multipart_body->len= 0;
140
+
141
+    /* Create an empty rlmi document */
142
+	len_est = create_empty_rlmi_doc(&rlmi_body, &list_node, rl_uri, subs->version, 1);
143
+	xmlDocSetRootElement(rlmi_body, list_node);
144
+
145
+    /* Find all the uri's to which we are subscribed */
146
+	param.next = &uri_list_head;
147
+	if(	process_list_and_exec(rl_node, subs->from_user, subs->from_domain, add_resource_to_list,(void*)(&param))< 0)
148
+	{
149
+		LM_ERR("in process_list_and_exec function\n");
128 150
 		goto error;
129 151
 	}
130 152
 
131 153
 	boundary_string= generate_string((int)time(NULL), BOUNDARY_STRING_LEN);
132 154
 	
133
-	if(result->n> 0)
134
-	{
135
-		multipart_body= constr_multipart_body(result, cid_array, 
136
-				boundary_string);
137
-		if(multipart_body== NULL)
155
+    while (uri_list_head)
156
+	{
157
+        uri_link_t *last = uri_list_head;
158
+        if (add_resource(uri_list_head->uri, list_node, multipart_body, boundary_string, result, &len_est) >0)
159
+        {
160
+            if (resource_added == 0)
161
+            {
162
+                /* We have exceeded our length estimate without adding any resource.
163
+                   We cannot send this resource, move on. */
164
+                LM_ERR("Failed to add a single resource %d vs %d\n", len_est, rls_max_notify_body_len);
165
+                uri_list_head = uri_list_head->next;
166
+                pkg_free(last);
167
+            }
168
+            else
169
+            {
170
+                LM_DBG("send_full_notify estimate exceeded %d vs %d\n", len_est, rls_max_notify_body_len);
171
+                /* If add_resource returns > 0 the resource did not fit in our size limit */
172
+                rlmi_cont= (str*)pkg_malloc(sizeof(str));
173
+                if(rlmi_cont== NULL)
174
+                {
175
+                    ERR_MEM(PKG_MEM_STR);
176
+                }
177
+                /* Where we are worried about length we won't use padding */
178
+                xmlDocDumpFormatMemory(rlmi_body,(xmlChar**)(void*)&rlmi_cont->s,
179
+                        &rlmi_cont->len, 0);
180
+                xmlFreeDoc(rlmi_body);
181
+
182
+                if(agg_body_sendn_update(rl_uri, boundary_string, rlmi_cont,
183
+                    multipart_body, subs, hash_code)< 0)
184
+                {
185
+                    LM_ERR("in function agg_body_sendn_update\n");
186
+                    goto error;
187
+                }
188
+                
189
+                /* Create a new rlmi body, but not a full_state one this time */
190
+                len_est = create_empty_rlmi_doc(&rlmi_body, &list_node, rl_uri, subs->version, 0);
191
+                xmlDocSetRootElement(rlmi_body, list_node);
192
+                multipart_body->len = 0;
193
+                resource_added = 0;
194
+            }
195
+        }
196
+        else
138 197
 		{
139
-			LM_ERR("while constructing multipart body\n");
140
-			goto error;
141
-		}
142
-		for(i = 0; i<result->n; i++)
143
-		{
144
-			if(cid_array[i])
145
-				pkg_free(cid_array[i]);
198
+            resource_added = 1;
199
+            uri_list_head = uri_list_head->next;
200
+            pkg_free(last);
146 201
 		}
147 202
 	}
148
-	pkg_free(cid_array);
149
-	cid_array= NULL;
203
+    
204
+	rlmi_cont= (str*)pkg_malloc(sizeof(str));
205
+	if(rlmi_cont== NULL)
206
+	{
207
+		ERR_MEM(PKG_MEM_STR);
208
+	}
209
+	xmlDocDumpFormatMemory(rlmi_body,(xmlChar**)(void*)&rlmi_cont->s,
210
+			&rlmi_cont->len, (rls_max_notify_body_len == 0));
211
+	xmlFreeDoc(rlmi_body);
212
+
150 213
 	rls_dbf.free_result(rls_db, result);
151 214
 	result= NULL;
152 215
 
153
-	if(agg_body_sendn_update(rl_uri, boundary_string, rlmi_body,
216
+	if(agg_body_sendn_update(rl_uri, boundary_string, rlmi_cont,
154 217
 		multipart_body, subs, hash_code)< 0)
155 218
 	{
156 219
 		LM_ERR("in function agg_body_sendn_update\n");
... ...
@@ -175,8 +250,8 @@ int send_full_notify(subs_t* subs, xmlNodePtr rl_node, int version, str* rl_uri,
175 175
 		goto error;
176 176
 	}
177 177
 
178
-	xmlFree(rlmi_body->s);
179
-	pkg_free(rlmi_body);
178
+	xmlFree(rlmi_cont->s);
179
+	pkg_free(rlmi_cont);
180 180
 
181 181
 	if(multipart_body)			
182 182
 	{
... ...
@@ -188,11 +263,11 @@ int send_full_notify(subs_t* subs, xmlNodePtr rl_node, int version, str* rl_uri,
188 188
 	return 0;
189 189
 error:
190 190
 
191
-	if(rlmi_body)
191
+	if(rlmi_cont)
192 192
 	{
193
-		if(rlmi_body->s)
194
-			xmlFree(rlmi_body->s);
195
-		pkg_free(rlmi_body);
193
+		if(rlmi_cont->s)
194
+			xmlFree(rlmi_cont->s);
195
+		pkg_free(rlmi_cont);
196 196
 	}
197 197
 	if(multipart_body)
198 198
 	{
... ...
@@ -201,13 +276,6 @@ error:
201 201
 		pkg_free(multipart_body);
202 202
 	}
203 203
 	
204
-	if(cid_array)
205
-	{
206
-		for(i= 0; i< result->n ; i++)
207
-			if(cid_array[i])
208
-				pkg_free(cid_array[i]);
209
-		pkg_free(cid_array);
210
-	}
211 204
 	if(result)
212 205
 		rls_dbf.free_result(rls_db, result);
213 206
 	if(rlsubs_did.s)
... ...
@@ -287,7 +355,8 @@ error:
287 287
 
288 288
 
289 289
 int add_resource_instance(char* uri, xmlNodePtr resource_node,
290
-		db1_res_t* result, char** cid_array)
290
+		db1_res_t* result, str *multipart_body, char * boundary_string,
291
+        int *len_est)
291 292
 {
292 293
 	xmlNodePtr instance_node= NULL;
293 294
 	db_row_t *row;	
... ...
@@ -295,8 +364,11 @@ int add_resource_instance(char* uri, xmlNodePtr resource_node,
295 295
 	int i, cmp_code;
296 296
 	char* auth_state= NULL;
297 297
 	int contor= 0;
298
-	str cid;
299 298
 	int auth_state_flag;
299
+    int boundary_len = strlen(boundary_string);
300
+    str cid;
301
+  	str content_type= {0, 0};
302
+    str body= {0, 0};
300 303
 
301 304
 	for(i= 0; i< result->n; i++)
302 305
 	{
... ...
@@ -311,16 +383,7 @@ int add_resource_instance(char* uri, xmlNodePtr resource_node,
311 311
 		if(cmp_code== 0)
312 312
 		{
313 313
 			contor++;
314
-			instance_node= xmlNewChild(resource_node, NULL, 
315
-					BAD_CAST "instance", NULL);
316
-			if(instance_node== NULL)
317
-			{
318
-				LM_ERR("while adding instance child\n");
319
-				goto error;
320
-			}
321 314
 		
322
-			xmlNewProp(instance_node, BAD_CAST "id",
323
-					BAD_CAST generate_string(contor, 8));
324 315
 			auth_state_flag= row_vals[auth_state_col].val.int_val;
325 316
 			auth_state= get_auth_string(auth_state_flag );
326 317
 			if(auth_state== NULL)
... ...
@@ -328,20 +391,52 @@ int add_resource_instance(char* uri, xmlNodePtr resource_node,
328 328
 				LM_ERR("bad authorization status flag\n");
329 329
 				goto error;
330 330
 			}
331
-			xmlNewProp(instance_node, BAD_CAST "state", BAD_CAST auth_state);
331
+            *len_est += strlen(auth_state) + 38; /* <instance id="12345678" state="[auth_state]" />r/n */
332 332
 
333 333
 			if(auth_state_flag & ACTIVE_STATE)
334 334
 			{
335 335
 				cid.s= generate_cid(uri, strlen(uri));
336 336
 				cid.len= strlen(cid.s);
337
-
338
-				cid_array[i]= (char*)pkg_malloc((1+ cid.len)*sizeof(char));
339
-				if(cid_array[i]== NULL)
337
+                body.s= (char*)row_vals[pres_state_col].val.string_val;
338
+                body.len= strlen(body.s);
339
+                trim(&body);
340
+
341
+                *len_est += cid.len + 8; /* cid="[cid]" */
342
+				content_type.s = (char*)row_vals[content_type_col].val.string_val;
343
+				content_type.len = strlen(content_type.s);
344
+				*len_est += 4 + boundary_len
345
+ 						 + 35
346
+						 + 16 + cid.len
347
+						 + 18 + content_type.len
348
+						 + 4 + body.len + 8;
349
+			}
350
+			else
351
+			if(auth_state_flag & TERMINATED_STATE)
340 352
 				{
341
-					ERR_MEM(PKG_MEM_STR);
342
-				}	
343
-				memcpy(cid_array[i], cid.s, cid.len);
344
-				cid_array[i][cid.len]= '\0';
353
+			    *len_est += strlen(row_vals[resource_uri_col].val.string_val) + 10; /* reason="[resaon]" */
354
+			}
355
+            if (rls_max_notify_body_len > 0 && *len_est > rls_max_notify_body_len)
356
+            {
357
+                /* We have a limit on body length set, and we were about to exceed it */
358
+                return *len_est;
359
+			}
360
+            
361
+            instance_node= xmlNewChild(resource_node, NULL, 
362
+					BAD_CAST "instance", NULL);
363
+			if(instance_node== NULL)
364
+			{
365
+				LM_ERR("while adding instance child\n");
366
+				goto error;
367
+			}
368
+		
369
+            /* OK, we are happy this will fit */
370
+			xmlNewProp(instance_node, BAD_CAST "id",
371
+					BAD_CAST generate_string(contor, 8));
372
+			xmlNewProp(instance_node, BAD_CAST "state", BAD_CAST auth_state);
373
+
374
+			if(auth_state_flag & ACTIVE_STATE)
375
+			{
376
+                constr_multipart_body (multipart_body, &content_type, &body, &cid, boundary_len, boundary_string);
345 377
 
346 378
 				xmlNewProp(instance_node, BAD_CAST "cid", BAD_CAST cid.s);
347 379
 			}
... ...
@@ -360,206 +455,156 @@ error:
360 360
 	return -1;
361 361
 }
362 362
 
363
-int add_resource(char* uri, void* param)
363
+int add_resource(char* uri, xmlNodePtr list_node, str *multipart_body, char * boundary_string, db1_res_t *result, int *len_est)
364 364
 {
365
-	char** cid_array= ((res_param_t*)param)->cid_array;
366
-	xmlNodePtr list_node= ((res_param_t*)param)->list_node;
367 365
 	xmlNodePtr resource_node= NULL;
368
-	db1_res_t *result= ((res_param_t*)param)->db_result;
369
-
370
-	LM_DBG("uri= %s\n", uri);
366
+    int res;
367
+
368
+    if (rls_max_notify_body_len > 0)
369
+    {
370
+        *len_est += strlen (uri) + 35; /* <resource uri="[uri]"></resource>/r/n */
371
+        if (*len_est > rls_max_notify_body_len)
372
+        {
373
+            return *len_est;
374
+        }
375
+    }
371 376
 	resource_node= xmlNewChild(list_node, NULL, BAD_CAST "resource", NULL);
372 377
 	if(resource_node== NULL)
373 378
 	{
374
-		LM_ERR("while adding new rsource_node\n");
375 379
 		goto error;
376 380
 	}
377 381
 	xmlNewProp(resource_node, BAD_CAST "uri", BAD_CAST uri);
378 382
 
379
-	if(add_resource_instance(uri, resource_node, result, cid_array)< 0)
383
+    res = add_resource_instance(uri, resource_node, result, multipart_body, boundary_string, len_est);
384
+	if(res < 0)
380 385
 	{
381 386
 		LM_ERR("while adding resource instance node\n");
382 387
 		goto error;
383 388
 	}
384 389
 
385
-	return 0;
390
+	return res;
386 391
 error:
387 392
 	return -1;
388 393
 }
389 394
 
390
-str* constr_rlmi_doc(db1_res_t *result, str* rl_uri, int version,
391
-		xmlNodePtr rl_node, char*** rlmi_cid_array,
392
-		str username, str domain)
395
+int add_resource_to_list(char* uri, void* param)
393 396
 {
394
-	xmlDocPtr doc= NULL;
395
-	xmlNodePtr list_node= NULL;
396
-	str* rlmi_cont= NULL;
397
-	int len; 
398
-	char* uri;
399
-	res_param_t param;
400
-	char** cid_array= NULL;
401
-	int n= result->n;
402
-
403
-	LM_DBG("start\n");
404
-	cid_array= (char**)pkg_malloc(n* sizeof(char*));
405
-	if(cid_array== NULL)
397
+    struct uri_link **next = ((res_param_t*)param)->next;
398
+    *next = pkg_malloc(sizeof(uri_link_t));
399
+    if (*next == NULL)
406 400
 	{
407
-		ERR_MEM(PKG_MEM_STR);
401
+    	LM_ERR("while creating linked list element\n");
402
+		goto error;
408 403
 	}
409
-	memset(cid_array, 0, n* sizeof(char*));
410 404
 
411
-	doc= xmlNewDoc(BAD_CAST "1.0");
412
-	if(doc== NULL)
405
+    (*next)->next = NULL;
406
+    (*next)->uri = pkg_malloc(strlen(uri) + 1);
407
+    if ((*next)->uri == NULL)
413 408
 	{
414
-		LM_ERR("while constructing new xml doc\n");
409
+    	LM_ERR("while creating uri store\n");
410
+        pkg_free(*next);
411
+        *next = NULL;
415 412
 		goto error;
416 413
 	}
417
-	list_node= xmlNewNode(NULL, BAD_CAST "list");
418
-	if(list_node== NULL)
414
+    strcpy((*next)->uri, uri);
415
+    ((res_param_t*)param)->next = &(*next)->next;
416
+
417
+	return 0;
418
+error:
419
+	return -1;
420
+}
421
+
422
+int create_empty_rlmi_doc(xmlDocPtr *rlmi_doc, xmlNodePtr *list_node, str *uri, int version, int full_state)
423
+{
424
+    /* length is an pessimitic estimate of the size of an empty document
425
+       We calculate it once for performance reasons.
426
+       We add in the uri length each time as this varies, and it is cheap to add */
427
+    static int length = 0;
428
+    char* rl_uri= NULL;
429
+    int len;
430
+    
431
+    /* make new rlmi and multipart documents */
432
+    *rlmi_doc= xmlNewDoc(BAD_CAST "1.0");
433
+    if(*rlmi_doc== NULL)
434
+    {
435
+        LM_ERR("when creating new xml doc\n");
436
+        return 0;
437
+    }
438
+    *list_node= xmlNewNode(NULL, BAD_CAST "list");
439
+    if(*list_node== NULL)
419 440
 	{
420 441
 		LM_ERR("while creating new xml node\n");
421
-		goto error;
442
+        return 0;
422 443
 	}
423
-	uri= (char*)pkg_malloc(rl_uri->len+ 1);
424
-	if(uri== NULL)
444
+    rl_uri= (char*)pkg_malloc((uri->len+ 1)* sizeof(char));
445
+    if(rl_uri==  NULL)
425 446
 	{
426 447
 		ERR_MEM(PKG_MEM_STR);
427 448
 	}
428
-	memcpy(uri, rl_uri->s, rl_uri->len);
429
-	uri[rl_uri->len]= '\0';
430
-	xmlNewProp(list_node, BAD_CAST "uri", BAD_CAST uri);
431
-	pkg_free(uri);
449
+    memcpy(rl_uri, uri->s, uri->len);
450
+    rl_uri[uri->len]= '\0';
432 451
 
433
-	xmlNewProp(list_node, BAD_CAST "xmlns",
452
+    xmlNewProp(*list_node, BAD_CAST "uri", BAD_CAST rl_uri);
453
+    xmlNewProp(*list_node, BAD_CAST "xmlns",
434 454
 			BAD_CAST "urn:ietf:params:xml:ns:rlmi");
435
-	xmlNewProp(list_node, BAD_CAST "version", BAD_CAST int2str(version, &len));
436
-	xmlNewProp(list_node, BAD_CAST "fullState", BAD_CAST "true");
437
-
438
-	xmlDocSetRootElement(doc, list_node);
455
+    xmlNewProp(*list_node, BAD_CAST "version",
456
+            BAD_CAST int2str(version, &len));
457
+    if (full_state)               
458
+        xmlNewProp(*list_node, BAD_CAST "fullState", BAD_CAST "true");
459
+    else
460
+        xmlNewProp(*list_node, BAD_CAST "fullState", BAD_CAST "false");
439 461
 	
440
-	/* go through the list -- and add the appropriate 'resource' nodes*/
441
-	
442
-	param.list_node= list_node;
443
-	param.db_result= result;
444
-	param.cid_array= cid_array;
445
-
446
-	if(process_list_and_exec(rl_node, username, domain, add_resource,(void*)(&param))< 0)
447
-	{
448
-		LM_ERR("in process_list_and_exec function\n");
449
-		goto error;
450
-	}
451
-	rlmi_cont= (str*)pkg_malloc(sizeof(str));
452
-	if(rlmi_cont== NULL)
453
-	{
454
-		ERR_MEM(PKG_MEM_STR);
462
+    xmlDocSetRootElement(*rlmi_doc, *list_node);
463
+    pkg_free(rl_uri);  /* xmlNewProp takes a copy, so we can free this now */
464
+
465
+    if (length == 0)
466
+	{
467
+        /* We haven't found out how big an empty doc is
468
+           Let's find out now ! */
469
+        xmlChar* dumped_document;
470
+        /* Where we are worried about length we won't use padding */
471
+        xmlDocDumpFormatMemory( *rlmi_doc,&dumped_document, &length, 0);
472
+        xmlFree(dumped_document);
473
+        length -= uri->len; /* The uri varies, so we will add it each time */
455 474
 	}
456
-	xmlDocDumpFormatMemory(doc,(xmlChar**)(void*)&rlmi_cont->s,
457
-			&rlmi_cont->len, 1);
458
-
459
-	*rlmi_cid_array= cid_array;
460
-	
461
-	xmlFreeDoc(doc);
462
-
463
-	return rlmi_cont;
464
-
475
+    return length + uri->len;
465 476
 error:
466
-	if(doc)
467
-		xmlFreeDoc(doc);
468
-	return NULL;	
477
+    return 0;
469 478
 }
470 479
 
471 480
 
472
-str* constr_multipart_body(db1_res_t* result, char** cid_array, 
473
-		char* boundary_string)
481
+void constr_multipart_body(str *multipart_body, const str *const content_type, const str *const body, str *cid, int boundary_len, char *boundary_string)
474 482
 {
475
-	char* buf= NULL;
483
+	char* buf= multipart_body->s;
476 484
 	int size= BUF_REALLOC_SIZE;
477
-	int i, length= 0;
478
-	db_row_t *row;	
479
-	db_val_t *row_vals;
480
-	str content_id = {0, 0};
481
-	str body= {0, 0};
482
-	str content_type= {0, 0};
485
+	int length= multipart_body->len;
483 486
 	int chunk_len;
484
-	str* multi_body= NULL;
485
-	str bstr = {0, 0};
486 487
 	
487 488
 	LM_DBG("start\n");
488
-	buf= pkg_malloc(size* sizeof(char));
489
-	if(buf== NULL)
490
-	{
491
-		ERR_MEM(PKG_MEM_STR);
492
-	}
493
-
494
-	bstr.s = boundary_string;
495
-	bstr.len = strlen(bstr.s);
496
-
497
-	for(i= 0; i< result->n; i++)
498
-	{
499
-		row = &result->rows[i];
500
-		row_vals = ROW_VALUES(row);
501
-	
502
-		if(row_vals[auth_state_col].val.int_val!= ACTIVE_STATE)
503
-			continue;
504
-	
505
-		body.s= (char*)row_vals[pres_state_col].val.string_val;
506
-		body.len= strlen(body.s);
507
-		trim(&body);
508
-		content_type.s = (char*)row_vals[content_type_col].val.string_val;
509
-		content_type.len = strlen(content_type.s);
510
-		content_id.s= cid_array[i];
511
-		if(content_id.s== NULL)
512
-		{
513
-			LM_ERR("No cid found in array for uri= %s\n",
514
-					row_vals[resource_uri_col].val.string_val);
515
-			goto error;
516
-		}
517
-		content_id.len = strlen(content_id.s);
518 489
 
519
-
520
-		chunk_len = 4 + bstr.len
521
-					+ 35
522
-					+ 16 + content_id.len
523
-					+ 18 + content_type.len
524
-					+ 4 + body.len + 8;
490
+    chunk_len = 4 + boundary_len
491
+                + 35
492
+                + 16 + cid->len
493
+                + 18 + content_type->len
494
+                + 4 + body->len + 8;
525 495
 		if(length + chunk_len >= size)
526 496
 		{
527 497
 			REALLOC_BUF
528 498
 		}
529 499
 
530 500
 		length+= sprintf(buf+ length, "--%.*s\r\n",
531
-				bstr.len, bstr.s);
501
+            boundary_len, boundary_string);
532 502
 		length+= sprintf(buf+ length, "Content-Transfer-Encoding: binary\r\n");
533 503
 		length+= sprintf(buf+ length, "Content-ID: <%.*s>\r\n",
534
-				content_id.len, content_id.s);
504
+            cid->len, cid->s);
535 505
 		length+= sprintf(buf+ length, "Content-Type: %.*s\r\n\r\n",
536
-				content_type.len, content_type.s);
506
+            content_type->len, content_type->s);
537 507
 		length+= sprintf(buf+length,"%.*s\r\n\r\n",
538
-				body.len, body.s);
539
-	}
540
-
541
-	if(length+ strlen( boundary_string)+ 7> size )
542
-	{
543
-		REALLOC_BUF
544
-	}
545
-	buf[length]= '\0';
546
-	
547
-	multi_body= (str*)pkg_malloc(sizeof(str));
548
-	if(multi_body== NULL)
549
-	{
550
-		ERR_MEM(PKG_MEM_STR);
551
-	}
552
-
553
-	multi_body->s= buf;
554
-	multi_body->len= length;
555
-
556
-	return multi_body;
508
+            body->len, body->s);
557 509
 
558 510
 error:
559 511
 
560
-	if(buf)
561
-		pkg_free(buf);
562
-	return NULL;
512
+	return;
563 513
 }
564 514
 
565 515
 str* rls_notify_extra_hdr(subs_t* subs, char* start_cid, char* boundary_string)
... ...
@@ -892,7 +937,6 @@ int process_list_and_exec(xmlNodePtr list_node, str username, str domain,
892 892
 	char* uri = NULL;
893 893
 	int res = 0;
894 894
 
895
-	LM_DBG("start\n");
896 895
 	for(node= list_node->children; node; node= node->next)
897 896
 	{
898 897
 		if(xmlStrcasecmp(node->name,(unsigned char*)"resource-list")==0)
... ...
@@ -1177,7 +1221,7 @@ int rls_get_resource_list(str *rl_uri, str *username, str *domain,
1177 1177
 	*xmldoc = xmlParseMemory(body.s, body.len);
1178 1178
 	if(*xmldoc==NULL)
1179 1179
 	{
1180
-		LM_ERR("while parsing XML memory\n");
1180
+		LM_ERR("while parsing XML memory. len = %d\n", body.len);
1181 1181
 		goto error;
1182 1182
 	}
1183 1183
 
... ...
@@ -47,7 +47,7 @@
47 47
 		{	ERR_MEM("constr_multipart_body");}
48 48
 
49 49
 int send_full_notify(subs_t* subs, xmlNodePtr rl_node, 
50
-		int version, str* rl_uri, unsigned int hash_code);
50
+                     str* rl_uri, unsigned int hash_code);
51 51
 
52 52
 typedef int (*list_func_t)(char* uri, void* param); 
53 53
 
... ...
@@ -59,5 +59,5 @@ char* get_auth_string(int flag);
59 59
 int agg_body_sendn_update(str* rl_uri, char* boundary_string, str* rlmi_body,
60 60
 		str* multipart_body, subs_t* subs, unsigned int hash_code);
61 61
 int rls_send_notify(subs_t* subs,str* body,char* start_cid,char* boundary_string);
62
-
62
+int create_empty_rlmi_doc(xmlDocPtr *rlmi_doc, xmlNodePtr *list_node, str *uri, int version, int full_state);
63 63
 #endif
... ...
@@ -61,6 +61,385 @@ static str su_200_rpl     = str_init("OK");
61 61
 	dest_len= source_len;\
62 62
 	size+= source_len;
63 63
 
64
+int parse_rlsubs_did(char* str_did, str* callid, str* from_tag, str* to_tag)
65
+{
66
+	char* smc= NULL;
67
+
68
+	smc= strstr(str_did, RLS_DID_SEP);
69
+    if(smc== NULL)
70
+    {
71
+        LM_ERR("bad format for resource list Subscribe dialog"
72
+            " indentifier[rlsubs did]= %s\n", str_did);
73
+        return -1;
74
+    }
75
+	callid->s= str_did;
76
+	callid->len= smc- str_did;
77
+			
78
+	from_tag->s= smc+ RLS_DID_SEP_LEN;
79
+	smc= strstr(from_tag->s, RLS_DID_SEP);
80
+	if(smc== NULL)
81
+    {
82
+        LM_ERR("bad format for resource list Subscribe dialog"
83
+            " indentifier(rlsubs did)= %s\n", str_did);
84
+        return -1;
85
+    }
86
+	from_tag->len= smc- from_tag->s;
87
+		
88
+	to_tag->s= smc+ RLS_DID_SEP_LEN;
89
+	to_tag->len= strlen(str_did)- 2* RLS_DID_SEP_LEN- callid->len- from_tag->len;
90
+
91
+	return 0;
92
+}
93
+
94
+
95
+void get_dialog_from_did(char* did, subs_t **dialog, unsigned int *hash_code)
96
+{
97
+    str callid, to_tag, from_tag;
98
+    subs_t* s;
99
+    
100
+    *dialog= NULL;
101
+
102
+    /* search the subscription in rlsubs_table*/		
103
+    if( parse_rlsubs_did(did, &callid, &from_tag, &to_tag)< 0)
104
+	{
105
+        LM_ERR("bad format for "
106
+            "resource list Subscribe dialog indentifier(rlsubs did)\n");
107
+        return;
108
+	}
109
+    *hash_code= core_hash(&callid, &to_tag, hash_size);
110
+    
111
+    lock_get(&rls_table[*hash_code].lock);
112
+    s= pres_search_shtable(rls_table,callid,to_tag,from_tag,*hash_code);
113
+    if(s== NULL)
114
+	{
115
+        LM_ERR("record not found in hash_table [rlsubs_did]= %s\n",
116
+                did);
117
+        lock_release(&rls_table[*hash_code].lock);
118
+        return;
119
+	}
120
+
121
+    /* save dialog info */
122
+    *dialog= pres_copy_subs(s, PKG_MEM_TYPE);
123
+    if(*dialog== NULL)
124
+	{
125
+        LM_ERR("while copying subs_t structure\n");
126
+	}
127
+    lock_release(&rls_table[*hash_code].lock);
128
+	
129
+}
130
+
131
+int send_notify(xmlDocPtr * rlmi_doc, char * buf, int buf_len, 
132
+                 const str bstr, subs_t * dialog, unsigned int hash_code)
133
+{
134
+    int result = 0;
135
+    str rlmi_cont= {0, 0}, multi_cont;
136
+
137
+    xmlDocDumpFormatMemory(*rlmi_doc,(xmlChar**)(void*)&rlmi_cont.s,
138
+				&rlmi_cont.len, 0);
139
+		
140
+    multi_cont.s= buf;
141
+    multi_cont.len= buf_len;
142
+
143
+    result =agg_body_sendn_update(&dialog->pres_uri, bstr.s, &rlmi_cont, 
144
+                 (buf_len==0)?NULL:&multi_cont, dialog, hash_code);
145
+    xmlFree(rlmi_cont.s);
146
+    xmlFreeDoc(*rlmi_doc);
147
+    *rlmi_doc= NULL;
148
+    return result;
149
+}
150
+
151
+
152
+void send_notifies(db1_res_t *result, int did_col, int resource_uri_col, int auth_state_col, int reason_col,
153
+                   int pres_state_col, int content_type_col, subs_t* subscription, int external_hash)
154
+{
155
+    int i;
156
+	char* prev_did= NULL, * curr_did= NULL;
157
+	db_row_t *row;	
158
+	db_val_t *row_vals;
159
+	char* resource_uri;
160
+	str pres_state = {0, 0};
161
+	xmlDocPtr rlmi_doc= NULL;
162
+	xmlNodePtr list_node= NULL, instance_node= NULL, resource_node;
163
+	unsigned int hash_code= 0;
164
+	int size= BUF_REALLOC_SIZE, buf_len= 0;	
165
+	char* buf= NULL, *auth_state= NULL, *boundary_string= NULL;
166
+	str cid = {0,0};
167
+	str content_type= {0, 0};
168
+	int contor= 0, auth_state_flag;
169
+	int chunk_len=0;
170
+	str bstr= {0, 0};
171
+	subs_t* dialog= NULL;
172
+    int len_est = 0;
173
+    int resource_added = 0; /* Flag to indicate that we have added at least one resource */
174
+
175
+	/* generate the boundary string */
176
+    boundary_string= generate_string((int)time(NULL), BOUNDARY_STRING_LEN);
177
+	bstr.len= strlen(boundary_string);
178
+	bstr.s= (char*)pkg_malloc((bstr.len+ 1)* sizeof(char));
179
+	if(bstr.s== NULL)
180
+	{
181
+		ERR_MEM(PKG_MEM_STR);
182
+	}
183
+	memcpy(bstr.s, boundary_string, bstr.len);
184
+	bstr.s[bstr.len]= '\0';
185
+
186
+	/* Allocate an initial buffer for the multipart body.
187
+	 * This buffer will be reallocated if neccessary */
188
+	buf= pkg_malloc(size* sizeof(char));
189
+	if(buf== NULL)
190
+	{
191
+		ERR_MEM(PKG_MEM_STR);
192
+	}
193
+
194
+    if (subscription == NULL)
195
+	{
196
+        dialog = subscription;
197
+        /* If we have been given a subscription to use
198
+           We should also have been given a hash value. */
199
+        hash_code = external_hash;
200
+	}
201
+
202
+	LM_DBG("found %d records with updated state\n", result->n);
203
+	for(i= 0; i< result->n; i++)
204
+	{
205
+		row = &result->rows[i];
206
+		row_vals = ROW_VALUES(row);
207
+		
208
+		curr_did=     (char*)row_vals[did_col].val.string_val;
209
+        resource_uri= (char*)row_vals[resource_uri_col].val.string_val;
210
+		auth_state_flag=     row_vals[auth_state_col].val.int_val;
211
+		pres_state.s=   (char*)row_vals[pres_state_col].val.string_val;
212
+		pres_state.len = strlen(pres_state.s);
213
+		trim(&pres_state);
214
+		
215
+        /* If we have moved onto a new resource list Subscribe dialog indentifier, 
216
+           Send a NOTIFY for the previous ID and then drop the existing documents. */
217
+		if(prev_did!= NULL && strcmp(prev_did, curr_did)) 
218
+		{
219
+            if (send_notify(&rlmi_doc, buf, buf_len, bstr, dialog, hash_code))
220
+            {  
221
+                LM_ERR("in send_notify\n");
222
+                goto error;
223
+            }
224
+            len_est = 0;
225
+            
226
+            if (subscription == NULL)
227
+            {
228
+                pkg_free(dialog);
229
+                dialog= NULL;
230
+            }
231
+        }
232
+
233
+		/*if first or different*/
234
+		if(prev_did==NULL || strcmp(prev_did, curr_did)!=0)
235
+        {
236
+            if (subscription == NULL)
237
+            {
238
+                /* We have not been given a subscription
239
+                   Work it out from the did. */
240
+                get_dialog_from_did(curr_did, &dialog, &hash_code);
241
+                if(dialog== NULL)
242
+                {
243
+                    prev_did = NULL;
244
+                    LM_ERR("Dialog is NULL\n");
245
+                    continue;
246
+                }
247
+            }
248
+		
249
+            len_est = create_empty_rlmi_doc(&rlmi_doc, &list_node, &dialog->pres_uri, dialog->version, 0);
250
+            len_est += 2*strlen(boundary_string)+4+102+2+50+strlen(resource_uri)+20;
251
+			buf_len= 0;
252
+
253
+			/* !!!! for now I will include the auth state without checking if 
254
+			 * it has changed - > in future chech if it works */		
255
+        }
256
+
257
+		/* add a node in rlmi_doc and if any presence state registered add 
258
+		 * it in the buffer */
259
+		
260
+		resource_node= xmlNewChild(list_node,NULL,BAD_CAST "resource", NULL);
261
+		if(resource_node== NULL)
262
+        {
263
+			LM_ERR("when adding resource child\n");
264
+			goto done;
265
+        }
266
+		xmlNewProp(resource_node, BAD_CAST "uri", BAD_CAST resource_uri);
267
+        len_est += strlen (resource_uri) + 35; /* <resource uri="[uri]"></resource>/r/n */
268
+
269
+		/* there might be more records with the same uri- more instances-
270
+		 * search and add them all */
271
+		
272
+		contor= 0;
273
+		while(1)
274
+		{
275
+			contor++;
276
+			cid.s= NULL;
277
+			cid.len= 0;
278
+			
279
+			auth_state= get_auth_string(auth_state_flag);
280
+			if(auth_state== NULL)
281
+            {
282
+				LM_ERR("bad authorization status flag\n");
283
+                goto error;
284
+            }	
285
+			len_est += strlen(auth_state) + 38; /* <instance id="12345678" state="[auth_state]" />r/n */
286
+
287
+			if(auth_state_flag & ACTIVE_STATE)
288
+            {
289
+				cid.s= generate_cid(resource_uri, strlen(resource_uri));
290
+                cid.len = strlen(cid.s);
291
+                len_est += cid.len + 8; /* cid="[cid]" */
292
+				content_type.s = (char*)row_vals[content_type_col].val.string_val;
293
+				content_type.len = strlen(content_type.s);
294
+				chunk_len = 4 + bstr.len
295
+							+ 35
296
+							+ 16 + cid.len
297
+							+ 18 + content_type.len
298
+							+ 4 + pres_state.len + 8;
299
+                len_est += chunk_len;
300
+            }
301
+			else
302
+			if(auth_state_flag & TERMINATED_STATE)
303
+            {
304
+			    len_est += strlen(row_vals[resource_uri_col].val.string_val) + 10; /* reason="[resaon]" */
305
+            }
306
+            
307
+            if (rls_max_notify_body_len > 0 && len_est > rls_max_notify_body_len)
308
+            {
309
+                /* We have a limit on body length set, and we were about to exceed it */
310
+                if (resource_added == 1)
311
+                {
312
+                    /* We added at least one resource. */
313
+                    LM_ERR("timer_send_notify hit the size limit. len_est = %d\n", len_est);
314
+                    if (send_notify(&rlmi_doc, buf, buf_len, bstr, dialog, hash_code))
315
+                    {
316
+                        LM_ERR("in send_notify\n");
317
+                        goto error;
318
+                    }
319
+                    i --;
320
+                }
321
+                else
322
+                {
323
+                    LM_ERR("timer_send_notify hit the size limit. NO RESOURCE ADDED len_est = %d\n", len_est);
324
+                }
325
+                len_est = 0;
326
+
327
+                if (subscription == NULL)
328
+                {
329
+                    pkg_free(dialog);
330
+                    dialog= NULL;
331
+                }
332
+                
333
+                curr_did=NULL;
334
+                break;
335
+            }
336
+
337
+            /* OK, we are happy this will fit */
338
+            instance_node= xmlNewChild(resource_node, NULL, BAD_CAST "instance", NULL);
339
+            if(instance_node== NULL)
340
+            {
341
+				LM_ERR("while adding instance child\n");
342
+				goto error;
343
+            }	
344
+
345
+            xmlNewProp(instance_node, BAD_CAST "id", 
346
+					BAD_CAST generate_string(contor, 8));
347
+            if(auth_state_flag & ACTIVE_STATE)
348
+            {
349
+                xmlNewProp(instance_node, BAD_CAST "state", BAD_CAST auth_state);
350
+            }
351
+			else
352
+			if(auth_state_flag & TERMINATED_STATE)
353
+            {
354
+            	xmlNewProp(instance_node, BAD_CAST "reason",
355
+					BAD_CAST row_vals[resource_uri_col].val.string_val);
356
+            }
357
+            xmlNewProp(instance_node, BAD_CAST "cid", BAD_CAST cid.s);
358
+
359
+			/* add in the multipart buffer */
360
+			if(cid.s)
361
+			{
362
+	
363
+				if(buf_len + chunk_len >= size)
364
+				{
365
+					REALLOC_BUF
366
+				}
367
+				buf_len+= sprintf(buf+ buf_len, "--%.*s\r\n", bstr.len,
368
+						bstr.s);
369
+				buf_len+= sprintf(buf+ buf_len,
370
+						"Content-Transfer-Encoding: binary\r\n");
371
+				buf_len+= sprintf(buf+ buf_len, "Content-ID: <%.*s>\r\n",
372
+						cid.len, cid.s);
373
+				buf_len+= sprintf(buf+ buf_len, "Content-Type: %.*s\r\n\r\n",
374
+						content_type.len, content_type.s);
375
+				buf_len+= sprintf(buf+buf_len,"%.*s\r\n\r\n", pres_state.len,
376
+						pres_state.s);
377
+			}
378
+
379
+			i++;
380
+			if(i== result->n)
381
+			{
382
+				i--;
383
+				break;
384
+			}
385
+	
386
+			row = &result->rows[i];
387
+			row_vals = ROW_VALUES(row);
388
+
389
+			if(strncmp(resource_uri, row_vals[resource_uri_col].val.string_val,
390
+					strlen(resource_uri))
391
+				|| strncmp(curr_did, row_vals[did_col].val.string_val,
392
+					strlen(curr_did)))
393
+			{
394
+				i--;
395
+				break;
396
+			}
397
+			resource_uri= (char*)row_vals[resource_uri_col].val.string_val;
398
+			auth_state_flag=     row_vals[auth_state_col].val.int_val;
399
+			pres_state.s=   (char*)row_vals[pres_state_col].val.string_val;
400
+			pres_state.len= strlen(pres_state.s);
401
+			trim(&pres_state);
402
+		}
403
+
404
+		prev_did= curr_did;
405
+	}
406
+
407
+	if(rlmi_doc)
408
+	{
409
+        LM_ERR("timer_send_notify at end len_est = %d resource_added = %d\n", len_est, resource_added);
410
+        if (resource_added == 1)
411
+        {
412
+            send_notify(&rlmi_doc, buf, buf_len, bstr, dialog, hash_code);
413
+        }
414
+        if (subscription == NULL)
415
+        {
416
+            /* We are using a derived subscription */
417
+            if(dialog)
418
+            {
419
+                pkg_free(dialog);
420
+            }
421
+            dialog= NULL;
422
+        }
423
+	}
424
+
425
+	
426
+error:
427
+done:
428
+	if(bstr.s)
429
+		pkg_free(bstr.s);
430
+
431
+	if(buf)
432
+		pkg_free(buf);
433
+    if (subscription == NULL)
434
+	{
435
+        /* We are using a derived subscription */
436
+        if(dialog)
437
+            pkg_free(dialog);
438
+    }
439
+	return;
440
+}
441
+
442
+
64 443
 int parse_subs_state(str auth_state, str** reason, int* expires)
65 444
 {
66 445
 	str str_exp;
... ...
@@ -87,10 +466,10 @@ int parse_subs_state(str auth_state, str** reason, int* expires)
87 87
 		{
88 88
 			LM_ERR("terminated state and no reason found");
89 89
 			return -1;
90
-		}
90
+        }
91 91
 		res= (str*)pkg_malloc(sizeof(str));
92 92
 		if(res== NULL)
93
-		{
93
+        {
94 94
 			ERR_MEM(PKG_MEM_STR);
95 95
 		}
96 96
 		len=  auth_state.len- 10- 1- 7;
... ...
@@ -103,7 +482,7 @@ int parse_subs_state(str auth_state, str** reason, int* expires)
103 103
 		res->len= len;
104 104
 		return TERMINATED_STATE;
105 105
 	}
106
-
106
+	
107 107
 	if(flag> 0)
108 108
 	{
109 109
 		smc= strchr(auth_state.s, ';');
... ...
@@ -111,7 +490,7 @@ int parse_subs_state(str auth_state, str** reason, int* expires)
111 111
 		{
112 112
 			LM_ERR("active or pending state and no expires parameter found");
113 113
 			return -1;
114
-		}
114
+        }	
115 115
 		if(strncmp(smc+1, "expires=", 8))
116 116
 		{
117 117
 			LM_ERR("active or pending state and no expires parameter found");
... ...
@@ -121,10 +500,10 @@ int parse_subs_state(str auth_state, str** reason, int* expires)
121 121
 		str_exp.len= auth_state.s+ auth_state.len- smc- 9;
122 122
 
123 123
 		if( str2int(&str_exp, (unsigned int*)expires)< 0)
124
-		{
124
+        {
125 125
 			LM_ERR("while getting int from str\n");
126 126
 			return -1;
127
-		}
127
+        }
128 128
 		return flag;
129 129
 	
130 130
 	}
... ...
@@ -175,9 +554,9 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2)
175 175
 	{
176 176
 		LM_ERR("cannot parse TO header\n");
177 177
 		return -1;
178
-	}
178
+    }
179 179
 	if(msg->to->parsed != NULL)
180
-	{
180
+    {
181 181
 		pto = (struct to_body*)msg->to->parsed;
182 182
 		LM_DBG("'To' header ALREADY PARSED: <%.*s>\n",
183 183
 				pto->uri.len, pto->uri.s );	
... ...
@@ -190,13 +569,13 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2)
190 190
 		{
191 191
 			LM_ERR(" 'To' header NOT parsed\n");
192 192
 			return -1;
193
-		}
193
+	}
194 194
 		pto = &TO;
195 195
 	}
196 196
 	memset(&dialog, 0, sizeof(ua_pres_t));
197 197
 	dialog.watcher_uri= &pto->uri;
198 198
     if (pto->tag_value.s==NULL || pto->tag_value.len==0 )
199
-	{  
199
+	{
200 200
 		LM_ERR("to tag value not parsed\n");
201 201
 		goto error;
202 202
 	}
... ...
@@ -220,12 +599,12 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2)
220 220
 		if ( parse_from_header( msg )<0 ) 
221 221
 		{
222 222
 			LM_ERR("cannot parse From header\n");
223
-			goto error;
224
-		}
223
+            goto error;
224
+        }
225 225
 	}
226 226
 	pfrom = (struct to_body*)msg->from->parsed;
227 227
 	dialog.pres_uri= &pfrom->uri;
228
-		
228
+
229 229
 	if( pfrom->tag_value.s ==NULL || pfrom->tag_value.len == 0)
230 230
 	{
231 231
 		LM_ERR("no from tag value present\n");
... ...
@@ -256,7 +635,7 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2)
256 256
 	{
257 257
 		LM_ERR("'Subscription-State' header not found\n");
258 258
 		goto error;
259
-	}	
259
+	}
260 260
 	auth_state = hdr->body;
261 261
 
262 262
 	/* extract state and reason */
... ...
@@ -266,7 +645,7 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2)
266 266
 		LM_ERR("while parsing 'Subscription-State' header\n");
267 267
 		goto error;
268 268
 	}
269
-	if(pua_get_record_id(&dialog, &res_id)< 0) // verify if within a stored dialog
269
+	if(pua_get_record_id(&dialog, &res_id)< 0) /* verify if within a stored dialog */
270 270
 	{
271 271
 		LM_ERR("occured when trying to get record id\n");
272 272
 		goto error;
... ...
@@ -280,22 +659,23 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2)
280 280
 		 */
281 281
 		if(auth_flag==TERMINATED_STATE)
282 282
 			goto done;
283
-		LM_ERR("no presence dialog record for non-TERMINATED state\n");
283
+        LM_ERR("no presence dialog record for non-TERMINATED state uri pres_uri = %.*s watcher_uri = %.*s\n",
284
+                dialog.pres_uri->len, dialog.pres_uri->s, dialog.watcher_uri->len, dialog.watcher_uri->s);
284 285
 		goto error;
285 286
 	}
286
-
287
+		
287 288
 	if(msg->content_type== NULL || msg->content_type->body.s== NULL)
288 289
 	{
289 290
 		LM_DBG("cannot find content type header header\n");
290 291
 	}
291 292
 	else
292 293
 		content_type= msg->content_type->body;
293
-
294
+					
294 295
 	/*constructing the xml body*/
295 296
 	if(get_content_length(msg) == 0 )
296
-	{
297
-		goto done;
298
-	}	
297
+    {	
298
+        goto done;
299
+    }	
299 300
 	else
300 301
 	{
301 302
 		if(content_type.s== 0)
... ...
@@ -313,7 +693,7 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2)
313 313
 
314 314
 	}
315 315
 	/* update in rlpres_table where rlsusb_did= res_id and resource_uri= from_uri*/
316
-	
316
+
317 317
 	LM_DBG("body= %.*s\n", body.len, body.s);
318 318
 
319 319
 	query_cols[n_query_cols]= &str_rlsubs_did_col;
... ...
@@ -321,7 +701,7 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2)
321 321
 	query_vals[n_query_cols].nul = 0;
322 322
 	query_vals[n_query_cols].val.str_val= *res_id; 
323 323
 	n_query_cols++;
324
-	
324
+
325 325
 	query_cols[n_query_cols]= &str_resource_uri_col;
326 326
 	query_vals[n_query_cols].type = DB1_STR;
327 327
 	query_vals[n_query_cols].nul = 0;
... ...
@@ -333,7 +713,7 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2)
333 333
 	query_vals[n_query_cols].nul = 0;
334 334
 	query_vals[n_query_cols].val.int_val= UPDATED_TYPE; 
335 335
 	n_query_cols++;
336
-
336
+		
337 337
 	query_cols[n_query_cols]= &str_auth_state_col;
338 338
 	query_vals[n_query_cols].type = DB1_INT;
339 339
 	query_vals[n_query_cols].nul = 0;
... ...
@@ -353,13 +733,13 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2)
353 353
 	query_vals[n_query_cols].nul = 0;
354 354
 	query_vals[n_query_cols].val.str_val= content_type;
355 355
 	n_query_cols++;
356
-
356
+			
357 357
 	query_cols[n_query_cols]= &str_presence_state_col;
358 358
 	query_vals[n_query_cols].type = DB1_STR;
359 359
 	query_vals[n_query_cols].nul = 0;
360 360
 	query_vals[n_query_cols].val.str_val= body;
361 361
 	n_query_cols++;
362
-	
362
+		
363 363
 	query_cols[n_query_cols]= &str_expires_col;
364 364
 	query_vals[n_query_cols].type = DB1_INT;
365 365
 	query_vals[n_query_cols].nul = 0;
... ...
@@ -373,7 +753,7 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2)
373 373
 	}
374 374
 	/* query-> if not present insert // else update */
375 375
 	result_cols[0]= &str_updated_col;
376
-
376
+			
377 377
 	if(rls_dbf.query(rls_db, query_cols, 0, query_vals, result_cols,
378 378
 					2, 1, 0, &result)< 0)
379 379
 	{
... ...
@@ -386,7 +766,7 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2)
386 386
 		goto error;
387 387
 	n= result->n;
388 388
 	rls_dbf.free_result(rls_db, result);
389
-
389
+		
390 390
 	if(n<= 0)
391 391
 	{
392 392
 		if(rls_dbf.insert(rls_db, query_cols, query_vals, n_query_cols)< 0)
... ...
@@ -406,7 +786,7 @@ int rls_handle_notify(struct sip_msg* msg, char* c1, char* c2)
406 406
 			goto error;
407 407
 		}
408 408
 	}
409
-	
409
+
410 410
 	LM_DBG("Updated rlpres_table\n");	
411 411
 	/* reply 200OK */
412 412
 done:
... ...
@@ -414,7 +794,7 @@ done:
414 414
 	{
415 415
 		LM_ERR("while sending reply\n");
416 416
 		goto error;
417
-	}	
417
+	}
418 418
 
419 419
 	if(res_id!=NULL)
420 420
 	{
... ...
@@ -430,38 +810,8 @@ error:
430 430
 		pkg_free(res_id);
431 431
 	}
432 432
 	return -1;
433
-}
434
-/* callid, from_tag, to_tag parameters must be allocated */
435
-
436
-int parse_rlsubs_did(char* str_did, str* callid, str* from_tag, str* to_tag)
437
-{
438
-	char* smc= NULL;
439
-
440
-	smc= strstr(str_did, RLS_DID_SEP);
441
-	if(smc== NULL)
442
-	{
443
-		LM_ERR("bad format for resource list Subscribe dialog"
444
-				" indentifier[rlsubs did]= %s\n", str_did);
445
-		return -1;
446 433
 	}
447
-	callid->s= str_did;
448
-	callid->len= smc- str_did;
449
-			
450
-	from_tag->s= smc+ RLS_DID_SEP_LEN;
451
-	smc= strstr(from_tag->s, RLS_DID_SEP);
452
-	if(smc== NULL)
453
-	{
454
-		LM_ERR("bad format for resource list Subscribe dialog"
455
-				" indentifier(rlsubs did)= %s\n", str_did);
456
-		return -1;
457
-	}
458
-	from_tag->len= smc- from_tag->s;
459
-		
460
-	to_tag->s= smc+ RLS_DID_SEP_LEN;
461
-	to_tag->len= strlen(str_did)- 2* RLS_DID_SEP_LEN- callid->len- from_tag->len;
462
-
463
-	return 0;
464
-}
434
+/* callid, from_tag, to_tag parameters must be allocated */
465 435
 
466 436
 void timer_send_notify(unsigned int ticks,void *param)
467 437
 {
... ...
@@ -469,29 +819,9 @@ void timer_send_notify(unsigned int ticks,void *param)
469 469
 	db_val_t query_vals[2], update_vals[1];
470 470
 	int did_col, resource_uri_col, auth_state_col, reason_col,
471 471
 		pres_state_col, content_type_col;
472
-	int n_result_cols= 0, i;
472
+	int n_result_cols= 0;
473 473
 	db1_res_t *result= NULL;
474
-	char* prev_did= NULL, * curr_did= NULL;
475
-	db_row_t *row;	
476
-	db_val_t *row_vals;
477
-	char* resource_uri;
478
-	str pres_state = {0, 0};
479
-	str callid, to_tag, from_tag;
480
-	xmlDocPtr rlmi_doc= NULL;