1952c67d49711e3319fb4cab18446a261d6e2094
[sip-router] / modules_k / presence / publish.c
1 /*
2  * $Id$
3  *
4  * presence module - presence server implementation
5  *
6  * Copyright (C) 2006 Voice Sistem S.R.L.
7  *
8  * This file is part of openser, a free SIP server.
9  *
10  * openser is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version
14  *
15  * openser is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License 
21  * along with this program; if not, write to the Free Software 
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  *
24  * History:
25  * --------
26  *  2006-08-15  initial version (anca)
27  */
28
29 #include <time.h>
30
31 #include "../../ut.h"
32 #include "../../str.h"
33 #include "../../parser/parse_to.h"
34 #include "../../parser/parse_uri.h" 
35 #include "../../parser/parse_expires.h" 
36 #include "../../parser/parse_event.h" 
37 #include "../../parser/parse_content.h" 
38 #include "../../lock_ops.h"
39 #include "../../hash_func.h"
40 #include "../../db/db.h"
41 #include "presence.h"
42 #include "notify.h"
43 #include "utils_func.h"
44 #include "publish.h"
45 #include "presentity.h"
46
47 extern db_con_t* pa_db;
48 extern db_func_t pa_dbf;
49 extern gen_lock_set_t* set;
50 extern int counter ;
51 extern int pid;
52 extern int startup_time;
53
54 static str pu_400a_rpl = str_init("Bad request");
55 static str pu_400b_rpl = str_init("Invalid request");
56
57 void msg_presentity_clean(unsigned int ticks,void *param)
58 {
59         db_key_t db_keys[2];
60         db_val_t db_vals[2];
61         db_op_t  db_ops[2] ;
62         db_key_t result_cols[6];
63         db_res_t *result = NULL;
64         db_row_t *row ; 
65         db_val_t *row_vals ;
66         int i =0, size= 0;
67         presentity_t** p= NULL;
68         presentity_t* pres= NULL;
69         int n= 0;
70         int event_col, etag_col, user_col, domain_col;
71         event_t e;
72         str user, domain, etag, event;
73         int n_result_cols= 0;
74         str pres_uri;
75         str* rules_doc= NULL;
76
77         if (pa_dbf.use_table(pa_db, presentity_table) < 0) 
78         {
79                 LOG(L_ERR, "PRESENCE:msg_presentity_clean: Error in use_table\n");
80                 return ;
81         }
82         
83         DBG("PRESENCE:msg_presentity_clean:cleaning expired presentity"
84                         " information\n");
85
86         db_keys[0] ="expires";
87         db_ops[0] = OP_LT;
88         db_vals[0].type = DB_INT;
89         db_vals[0].nul = 0;
90         db_vals[0].val.int_val = (int)time(NULL);
91                 
92         result_cols[user_col= n_result_cols++] = "username";
93         result_cols[domain_col=n_result_cols++] = "domain";
94         result_cols[etag_col=n_result_cols++] = "etag";
95         result_cols[event_col=n_result_cols++] = "event";
96
97         if(pa_dbf.query(pa_db, db_keys, db_ops, db_vals, result_cols,
98                                                 1, n_result_cols, "username", &result )< 0)
99         {
100                 LOG(L_ERR,
101                         "PRESENCE:msg_presentity_clean: ERROR while querying database"
102                         " for expired messages\n");
103                 if(result)
104                         pa_dbf.free_result(pa_db, result);
105                 return;
106         }
107         if(result== NULL)
108                 return;
109
110         if(result && result->n<= 0)
111         {
112                 pa_dbf.free_result(pa_db, result);      
113                 return;
114         }
115         DBG("PRESENCE:msg_presentity_clean: found n= %d expires messages\n ",
116                         result->n);
117
118         n= result->n;
119         
120         p= (presentity_t**)pkg_malloc(n* sizeof(presentity_t*));
121         if(p== NULL)
122         {
123                 LOG(L_ERR, "PRESENCE:msg_presentity_clean:  ERROR while"
124                                 " allocating memory\n");
125                 goto error;
126         }
127         memset(p, 0, n* sizeof(presentity_t*));
128
129         for(i = 0; i< n; i++)
130         {       
131                 row = &result->rows[i];
132                 row_vals = ROW_VALUES(row);     
133         
134                 user.s= (char*)row_vals[user_col].val.string_val;
135                 user.len= strlen(user.s);
136                 
137                 domain.s= (char*)row_vals[domain_col].val.string_val;
138                 domain.len= strlen(domain.s);
139
140                 etag.s= (char*)row_vals[etag_col].val.string_val;
141                 etag.len= strlen(etag.s);
142
143                 event.s= (char*)row_vals[event_col].val.string_val;
144                 event.len= strlen(event.s);
145                 
146                 size= sizeof(presentity_t)+ user.len+ domain.len+ etag.len; 
147                 pres= (presentity_t*)pkg_malloc(size);
148                 if(pres== NULL)
149                 {
150                         LOG(L_ERR, "PRESENCE:msg_presentity_clean:  ERROR while allocating memory\n");
151                         goto error;
152                 }
153                 memset(pres, 0, size);
154                 size= sizeof(presentity_t);
155                 
156                 pres->user.s= (char*)pres+ size;        
157                 memcpy(pres->user.s, user.s, user.len);
158                 pres->user.len= user.len;
159                 size+= user.len;
160
161                 pres->domain.s= (char*)pres+ size;
162                 memcpy(pres->domain.s, domain.s, domain.len);
163                 pres->domain.len= domain.len;
164                 size+= domain.len;
165
166                 pres->etag.s= (char*)pres+ size;
167                 memcpy(pres->etag.s, etag.s, etag.len);
168                 pres->etag.len= etag.len;
169                 size+= etag.len;
170                         
171                 pres->event= contains_event(&event, &e);
172                 if(pres->event== NULL)
173                 {
174                         LOG(L_ERR, "PRESENCE:msg_presentity_clean: ERROR while searching"
175                                         " for event\n");
176                         goto error;
177                 }       
178                 p[i]= pres;
179
180                 /* delete from hash table */
181                 if(uandd_to_uri(user, domain, &pres_uri)< 0)
182                 {
183                         LOG(L_ERR,"PRESENCE:pres_htable_restore:ERROR constructing uri\n");
184                         goto error;
185                 }
186
187                 if(delete_phtable(&pres_uri, e.parsed)< 0)
188                 {
189                         LOG(L_ERR, "PRESENCE:msg_presentity_clean:  ERROR"
190                                         " deleting from pres hash table\n");
191                         pkg_free(pres_uri.s);
192                         goto error;
193                 }
194                 pkg_free(pres_uri.s);
195
196         }
197         pa_dbf.free_result(pa_db, result);
198         result= NULL;
199         
200         for(i= 0; i<n ; i++)
201         {
202                 rules_doc= NULL;
203                 DBG( "PRESENCE:msg_presentity_clean:found expired publish"
204                                 " for [user]=%.*s  [domanin]=%.*s\n",p[i]->user.len,p[i]->user.s,
205                                 p[i]->domain.len, p[i]->domain.s);
206                 
207                 if(p[i]->event->get_rules_doc && 
208                 p[i]->event->get_rules_doc(&p[i]->user, &p[i]->domain, &rules_doc)< 0)
209                 {
210                         LOG(L_ERR, "PRESENCE:msg_presentity_clean:ERROR getting rules doc\n");
211                         goto error;
212                 }
213                 if(publ_notify( p[i], NULL, &p[i]->etag, rules_doc)< 0)
214                 {
215                         LOG(L_ERR, "PRESENCE:msg_presentity_clean: ERROR while sending Notify\n");
216                         goto error;
217                 }
218                 if(rules_doc)
219                 {
220                         if(rules_doc->s)
221                                 pkg_free(rules_doc->s);
222                         pkg_free(rules_doc);
223                 }
224                 rules_doc= NULL;
225         }
226
227         if (pa_dbf.use_table(pa_db, presentity_table) < 0) 
228         {
229                 LOG(L_ERR, "PRESENCE:msg_presentity_clean: Error in use_table\n");
230                 goto error;
231         }
232         
233         if (pa_dbf.delete(pa_db, db_keys, db_ops, db_vals, 1) < 0) 
234                 LOG(L_ERR,"PRESENCE:msg_presentity_clean: ERROR cleaning expired"
235                                 " messages\n");
236         
237         for(i= 0; i< n; i++)
238         {
239                 if(p[i])
240                         pkg_free(p[i]);
241         }
242         pkg_free(p);
243
244         return;
245
246 error:
247         if(result)
248                 pa_dbf.free_result(pa_db, result);
249         if(p)
250         {
251                 for(i= 0; i< n; i++)
252                 {
253                         if(p[i])
254                                 pkg_free(p[i]);
255                         else
256                                 break;
257                 }
258                 pkg_free(p);
259         }
260         if(rules_doc)
261         {
262                 if(rules_doc->s)
263                         pkg_free(rules_doc->s);
264                 pkg_free(rules_doc);
265         }
266
267         return; 
268 }
269
270 /**
271  * PUBLISH request handling
272  *
273  */
274 int handle_publish(struct sip_msg* msg, char* sender_uri, char* str2)
275 {
276         struct sip_uri puri;
277         str body;
278         int lexpire;
279         presentity_t* presentity = 0;
280         struct hdr_field* hdr;
281         int found= 0, etag_gen = 0;
282         str etag={0, 0};
283         int error_ret = -1; /* error return code */
284         str* sender= NULL;
285         static char buf[256];
286         int buf_len= 255;
287         pres_ev_t* event= NULL;
288         str pres_user;
289         str pres_domain;
290         struct sip_uri pres_uri;
291
292         counter++;
293         if ( parse_headers(msg,HDR_EOH_F, 0)==-1 )
294         {
295                 LOG(L_ERR, "PRESENCE:handle_publish:ERROR parsing headers\n");
296                 if (slb.reply(msg, 400, &pu_400a_rpl) == -1)
297                         LOG(L_ERR, "PRESENCE: handle_publish: Error while sending"
298                                                 " reply\n");
299                 else
300                         error_ret = 0;
301                 return error_ret;
302         }
303         memset(&body, 0, sizeof(str));
304         
305         /* inspecting the Event header field */
306         
307         if(msg->event && msg->event->body.len > 0)
308         {
309                 if (!msg->event->parsed && (parse_event(msg->event) < 0))
310                 {
311                         LOG(L_ERR,
312                                 "PRESENCE:handle_publish:ERROR cannot parse Event header\n");
313                         goto error;
314                 }
315                 if(((event_t*)msg->event->parsed)->parsed & EVENT_OTHER)
316                 {       
317                         goto unsupported_event;
318                 }
319         }
320         else
321                 goto unsupported_event;
322
323         /* search event in the list */
324         event= search_event((event_t*)msg->event->parsed);
325         if(event== NULL)
326         {
327                 goto unsupported_event;
328         }
329         
330         /* examine the SIP-If-Match header field */
331         hdr = msg->headers;
332         while (hdr!= NULL)
333         {
334                 if(strncmp(hdr->name.s, "SIP-If-Match",12)==0|| 
335                                 strncmp(hdr->name.s,"Sip-If-Match",12)==0 )
336                 {
337                         found = 1;
338                         break;
339                 }
340                 hdr = hdr->next;
341         }
342         if(found==0 )
343         {
344                 DBG("PRESENCE:handle_publish: SIP-If-Match not found\n");
345                 etag.s = generate_ETag(0);
346                 if(etag.s == NULL)
347                 {
348                         LOG(L_ERR,
349                                 "PRESENCE:handle_publish:ERROR while generating etag\n");
350                         return -1;
351                 }
352                 etag.len=(strlen(etag.s));
353                 etag_gen=1;
354                 DBG("PRESENCE:handle_publish: new etag  = %.*s \n", etag.len,
355                                 etag.s);
356         }
357         else
358         {
359                 DBG("PRESENCE:handle_publish: SIP-If-Match found\n");
360                 etag.s = (char*)pkg_malloc((hdr->body.len+ 1)* sizeof(char));
361                 if(etag.s== NULL)
362                 {
363                         LOG(L_ERR, "PRESENCE:handle_publish: ERROR No more memory\n");
364                         goto error;
365                 }
366                 memcpy(etag.s, hdr->body.s, hdr->body.len );
367                 etag.len = hdr->body.len;        
368                 etag.s[ etag.len] = '\0';
369                 DBG("PRESENCE:handle_publish: existing etag  = %.*s \n", etag.len,
370                                 etag.s);
371         }
372
373         /* examine the expire header field */
374         if(msg->expires && msg->expires->body.len > 0)
375         {
376                 if (!msg->expires->parsed && (parse_expires(msg->expires) < 0))
377                 {
378                         LOG(L_ERR,
379                                 "PRESENCE: handle_publish: ERROR cannot parse Expires header\n");
380                         goto error;
381                 }
382                 DBG("PRESENCE: handle_publish: 'expires' found\n");
383                 lexpire = ((exp_body_t*)msg->expires->parsed)->val;
384                 DBG("PRESENCE: handle_publish: lexpire= %d\n", lexpire);
385
386         }
387         else 
388         {
389                 DBG("PRESENCE: handle_publish: 'expires' not found; default=%d\n",
390                                 event->default_expires);
391                 lexpire = event->default_expires;
392         }
393         if(lexpire > max_expires)
394                 lexpire = max_expires;
395
396         /* get pres_uri from Request-URI*/
397         if( parse_uri(msg->first_line.u.request.uri.s, 
398                                 msg->first_line.u.request.uri.len, &pres_uri)< 0)
399         {
400                 LOG(L_ERR, "PRESENCE: handle_publish:error parsing Request URI\n");
401                 goto error;
402         }
403         pres_user= pres_uri.user;
404         pres_domain= pres_uri.host;
405
406         if (!msg->content_length) 
407         {
408                 LOG(L_ERR,"PRESENCE: handle_publish: ERROR no Content-Length"
409                                 " header found!\n");
410                 goto error;
411         }       
412
413         /* process the body */
414         if ( get_content_length(msg) == 0 )
415         {
416                 body.s = NULL;
417                 if (etag_gen)
418                 {
419                         LOG(L_ERR,"PRESENCE:handle_publish:No E-Tag and no body found\n");
420                         if (slb.reply(msg, 400, &pu_400b_rpl) == -1)
421                         {
422                                 LOG(L_ERR, "PRESENCE:handle_publish:ERROR sending reply\n");
423                         }
424                         else
425                                 error_ret = 0;
426                         goto error;
427                 }
428         }
429         else
430         {
431                 body.s=get_body(msg);
432                 if (body.s== NULL) 
433                 {
434                         LOG(L_ERR,"PRESENCE: handle_publish: ERROR cannot extract body\n");
435                         goto error;
436                 }
437                 body.len= get_content_length( msg );
438         }       
439         memset(&puri, 0, sizeof(struct sip_uri));
440         if(sender_uri && sender_uri!= "")
441         {
442                 sender=(str*)pkg_malloc(sizeof(str));
443                 if(sender== NULL)
444                 {
445                         LOG(L_ERR, "PRESENCE: handle_publish: ERROR while allocating memery\n");
446                         goto error;
447                 }       
448                 if(xl_printf(msg, (xl_elem_t*)sender_uri, buf, &buf_len)<0)
449                 {
450                         LOG(L_ERR, "PRESENCE: handle_publish:error - cannot print the format\n");
451                         goto error;
452                 }
453                 if(parse_uri(buf, buf_len, &puri)!=0)
454                 {
455                         LOG(L_ERR, "PRESENCE: handle_publish: bad owner SIP address!\n");
456                         goto error;
457                 } else {
458                         DBG("PRESENCE: handle_publish:using user id [%.*s]\n",buf_len,buf);
459                 }
460                 sender->s= buf;
461                 sender->len= buf_len;
462         }
463         /* call event specific handling function*/
464         if(event->evs_publ_handl)
465         {
466                 if(event->evs_publ_handl(msg)< 0)
467                 {
468                         LOG(L_ERR, "PRESENCE: handle_publish: ERROR in event specific"
469                                         " publish handling\n");
470                         goto error;
471                 }
472         }
473
474         /* now we have all the necessary values */
475         /* fill in the filds of the structure */
476
477         presentity= new_presentity(&pres_domain, &pres_user, lexpire, event, &etag, sender);
478         if(presentity== NULL)
479         {
480                 LOG(L_ERR,"PRESENCE: handle_publish: ERORR creating presentity\n");
481                 goto error;
482         }
483
484         /* querry the database and update or insert */
485         if(update_presentity(msg, presentity, &body, etag_gen) <0)
486         {
487                 LOG(L_ERR, "PRESENCE:handle_publish: ERROR occured while updating"
488                                 " presentity\n");
489                 goto error;
490         }
491
492         if(presentity)
493                 pkg_free(presentity);
494         if(etag.s)
495                 pkg_free(etag.s);
496         if(sender)
497                 pkg_free(sender);
498
499         return 1;
500
501 error:
502         LOG(L_ERR, "PRESENCE: handle_publish: ERROR occured\n");
503         
504         if(presentity)
505                 pkg_free(presentity);
506         if(etag.s)
507                 pkg_free(etag.s);
508         if(sender)
509                 pkg_free(sender);
510         
511         return error_ret;
512
513 unsupported_event:
514         
515         LOG(L_ERR, "PRESENCE: handle_publish:Missing or unsupported event"
516                         " header field value\n");
517                 
518         if(msg->event && msg->event->body.s && msg->event->body.len>0)
519                 LOG(L_ERR, "\tevent=[%.*s]\n", msg->event->body.len,
520                         msg->event->body.s);
521         
522         if(reply_bad_event(msg)< 0)
523                 return -1;
524
525         return 0;
526
527 }
528
529