- replaced LOG/DBG with LM_
[sip-router] / modules_k / presence / presentity.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 <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <time.h>
33
34 #include "../../db/db.h"
35 #include "../../dprint.h"
36 #include "../../mem/shm_mem.h"
37 #include "../../str.h"
38 #include "../alias_db/alias_db.h"
39 #include "../../data_lump_rpl.h"
40 #include "presentity.h"
41 #include "presence.h" 
42 #include "notify.h"
43 #include "publish.h"
44 #include "hash.h"
45 #include "utils_func.h"
46
47 extern int use_db;
48 extern char* presentity_table;
49 extern db_con_t* pa_db;
50 extern db_func_t pa_dbf;
51
52 static str pu_200_rpl  = str_init("OK");
53 static str pu_412_rpl  = str_init("Conditional request failed");
54
55 #define ETAG_LEN  128
56
57 char* generate_ETag(int publ_count)
58 {
59         char* etag= NULL;
60         int size = 0;
61
62         etag = (char*)pkg_malloc(ETAG_LEN*sizeof(char));
63         if(etag ==NULL)
64         {
65                 ERR_MEM(PKG_MEM_STR);
66         }
67         memset(etag, 0, ETAG_LEN*sizeof(char));
68         size = sprintf (etag, "%c.%d.%d.%d.%d",prefix, startup_time, pid, counter, publ_count);
69         if( size <0 )
70         {
71                 LM_ERR("unsuccessfull sprintf\n ");
72                 pkg_free(etag);
73                 return NULL;
74         }
75         if(size+ 1> ETAG_LEN)
76         {
77                 LM_ERR("buffer size overflown\n");
78                 pkg_free(etag);
79                 return NULL;
80         }
81
82         etag[size] = '\0';
83         LM_DBG("etag= %s / %d\n ",etag, size);
84         return etag;
85
86 error:
87         return NULL;
88
89 }
90
91 int publ_send200ok(struct sip_msg *msg, int lexpire, str etag)
92 {
93         char buf[128];
94         int buf_len= 128, size;
95         str hdr_append= {0, 0}, hdr_append2= {0, 0} ;
96
97         LM_DBG("send 200OK reply\n");   
98         LM_DBG("etag= %s - len= %d\n", etag.s, etag.len);
99         
100         hdr_append.s = buf;
101         hdr_append.s[0]='\0';
102         hdr_append.len = sprintf(hdr_append.s, "Expires: %d\r\n",lexpire -
103                         expires_offset);
104         if(hdr_append.len < 0)
105         {
106                 LM_ERR("unsuccessful sprintf\n");
107                 goto error;
108         }
109         if(hdr_append.len > buf_len)
110         {
111                 LM_ERR("buffer size overflown\n");
112                 goto error;
113         }
114         hdr_append.s[hdr_append.len]= '\0';
115                 
116         if (add_lump_rpl( msg, hdr_append.s, hdr_append.len, LUMP_RPL_HDR)==0 )
117         {
118                 LM_ERR("unable to add lump_rl\n");
119                 goto error;
120         }
121
122         size= sizeof(char)*(20+etag.len) ;
123         hdr_append2.s = (char *)pkg_malloc(size);
124         if(hdr_append2.s == NULL)
125         {
126                 ERR_MEM(PKG_MEM_STR);
127         }
128         hdr_append2.s[0]='\0';
129         hdr_append2.len = sprintf(hdr_append2.s, "SIP-ETag: %s\r\n", etag.s);
130         if(hdr_append2.len < 0)
131         {
132                 LM_ERR("unsuccessful sprintf\n ");
133                 goto error;
134         }
135         if(hdr_append2.len+1 > size)
136         {
137                 LM_ERR("buffer size overflown\n");
138                 goto error;
139         }
140
141         hdr_append2.s[hdr_append2.len]= '\0';
142         if (add_lump_rpl(msg, hdr_append2.s, hdr_append2.len, LUMP_RPL_HDR)==0 )
143         {
144                 LM_ERR("unable to add lump_rl\n");
145                 goto error;
146         }
147
148         if( slb.reply( msg, 200, &pu_200_rpl)== -1)
149         {
150                 LM_ERR("sending reply\n");
151                 goto error;
152         }
153
154         pkg_free(hdr_append2.s);
155         return 0;
156
157 error:
158
159         if(hdr_append2.s)
160                 pkg_free(hdr_append2.s);
161
162         return 0;
163
164 }       
165 presentity_t* new_presentity( str* domain,str* user,int expires, 
166                 pres_ev_t* event, str* etag, str* sender)
167 {
168         presentity_t *presentity= NULL;
169         int size, init_len;
170         
171         /* allocating memory for presentity */
172         size = sizeof(presentity_t)+ (domain->len+ user->len+ etag->len + 50)
173                 * sizeof(char);
174         if(sender)
175                 size+= sizeof(str)+ sender->len* sizeof(char);
176         
177         init_len= size;
178
179         presentity = (presentity_t*)pkg_malloc(size);
180         if(presentity == NULL)
181         {
182                 ERR_MEM(PKG_MEM_STR);
183         }
184         memset(presentity, 0, size);
185         size= sizeof(presentity_t);
186
187         presentity->domain.s = (char*)presentity+ size;
188         strncpy(presentity->domain.s, domain->s, domain->len);
189         presentity->domain.len = domain->len;
190         size+= domain->len;     
191         
192         presentity->user.s = (char*)presentity+size;
193         strncpy(presentity->user.s, user->s, user->len);
194         presentity->user.len = user->len;
195         size+= user->len;
196
197         presentity->etag.s = (char*)presentity+ size;
198         memcpy(presentity->etag.s, etag->s, etag->len);
199         presentity->etag.s[etag->len]= '\0';
200         presentity->etag.len = etag->len;
201
202         size+= etag->len+1;
203         
204         if(sender)
205         {
206                 presentity->sender= (str*)((char*)presentity+ size);
207                 size+= sizeof(str);
208                 presentity->sender->s= (char*)presentity + size;
209                 memcpy(presentity->sender->s, sender->s, sender->len);
210                 presentity->sender->len= sender->len;
211                 size+= sender->len;
212         }
213
214         if(size> init_len)
215         {
216                 LM_ERR("buffer size overflow init_len= %d, size= %d\n", init_len, size);
217                 goto error;
218         }
219         presentity->event= event;
220         presentity->expires = expires;
221         presentity->received_time= (int)time(NULL);
222         return presentity;
223     
224 error:
225         if(presentity)
226                 pkg_free(presentity);
227         return NULL;
228 }
229
230 int update_presentity(struct sip_msg* msg, presentity_t* presentity, str* body,
231                 int new_t)
232 {
233         db_key_t query_cols[11], update_keys[7], result_cols[5];
234         db_op_t  query_ops[11];
235         db_val_t query_vals[11], update_vals[7];
236         db_res_t *result= NULL;
237         int n_query_cols = 0;
238         int n_update_cols = 0;
239         char* dot= NULL;
240         str etag= {0, 0};
241         str cur_etag= {0, 0};
242         str* rules_doc= NULL;
243
244         if(presentity->event->req_auth)
245         {
246                 /* get rules_document */
247                 if(presentity->event->get_rules_doc(&presentity->user,
248                                         &presentity->domain, &rules_doc))
249                 {
250                         LM_ERR("getting rules doc\n");
251                         goto error;
252                 }
253         }
254
255         query_cols[n_query_cols] = "domain";
256         query_ops[n_query_cols] = OP_EQ;
257         query_vals[n_query_cols].type = DB_STR;
258         query_vals[n_query_cols].nul = 0;
259         query_vals[n_query_cols].val.str_val = presentity->domain;
260         n_query_cols++;
261         
262         query_cols[n_query_cols] = "username";
263         query_ops[n_query_cols] = OP_EQ;
264         query_vals[n_query_cols].type = DB_STR;
265         query_vals[n_query_cols].nul = 0;
266         query_vals[n_query_cols].val.str_val = presentity->user;
267         n_query_cols++;
268
269         query_cols[n_query_cols] = "event";
270         query_ops[n_query_cols] = OP_EQ;
271         query_vals[n_query_cols].type = DB_STR;
272         query_vals[n_query_cols].nul = 0;
273         query_vals[n_query_cols].val.str_val = presentity->event->name;
274         n_query_cols++;
275
276         query_cols[n_query_cols] = "etag";
277         query_ops[n_query_cols] = OP_EQ;
278         query_vals[n_query_cols].type = DB_STR;
279         query_vals[n_query_cols].nul = 0;
280         query_vals[n_query_cols].val.str_val = presentity->etag;
281         n_query_cols++;
282
283         result_cols[0]= "expires"; 
284
285         if(new_t) 
286         {
287                 /* insert new record in hash_table */
288                 
289                 if(insert_phtable(&msg->first_line.u.request.uri, 
290                                         presentity->event->evp->parsed)< 0)
291                 {
292                         LM_ERR("inserting record in hash table\n");
293                         goto error;
294                 }
295                 
296                 /* insert new record into database */   
297                 query_cols[n_query_cols] = "expires";
298                 query_vals[n_query_cols].type = DB_INT;
299                 query_vals[n_query_cols].nul = 0;
300                 query_vals[n_query_cols].val.int_val = presentity->expires+
301                                 (int)time(NULL);
302                 n_query_cols++;
303
304                 query_cols[n_query_cols] = "body";
305                 query_vals[n_query_cols].type = DB_BLOB;
306                 query_vals[n_query_cols].nul = 0;
307                 query_vals[n_query_cols].val.str_val = *body;
308                 n_query_cols++;
309                 
310                 query_cols[n_query_cols] = "received_time";
311                 query_vals[n_query_cols].type = DB_INT;
312                 query_vals[n_query_cols].nul = 0;
313                 query_vals[n_query_cols].val.int_val = presentity->received_time;
314                 n_query_cols++;
315
316                 if (pa_dbf.use_table(pa_db, presentity_table) < 0) 
317                 {
318                         LM_ERR("unsuccessful use_table\n");
319                         goto error;
320                 }
321
322                 LM_DBG("inserting %d cols into table\n",n_query_cols);
323                                 
324                 if (pa_dbf.insert(pa_db, query_cols, query_vals, n_query_cols) < 0) 
325                 {
326                         LM_ERR("inserting new record in database\n");
327                         goto error;
328                 }
329                 if( publ_send200ok(msg, presentity->expires, presentity->etag)< 0)
330                 {
331                         LM_ERR("sending 200OK\n");
332                         goto error;
333                 }
334                 goto send_notify;
335         }
336         else
337         {
338                 if (pa_dbf.use_table(pa_db, presentity_table) < 0) 
339                 {
340                         LM_ERR("unsuccessful sql use table\n");
341                         goto error;
342                 }
343
344                 if (pa_dbf.query (pa_db, query_cols, query_ops, query_vals,
345                          result_cols, n_query_cols, 1, 0, &result) < 0) 
346                 {
347                         LM_ERR("unsuccessful sql query\n");
348                         goto error;
349                 }
350                 if(result== NULL)
351                         goto error;
352
353                 if (result->n > 0)
354                 {
355                         pa_dbf.free_result(pa_db, result);
356                         result= NULL;
357
358                         if(presentity->expires == 0) 
359                         {
360                                 if( publ_send200ok(msg, presentity->expires, presentity->etag)< 0)
361                                 {
362                                         LM_ERR("sending 200OK reply\n");
363                                         goto error;
364                                 }
365                                 if( publ_notify( presentity, body, &presentity->etag, rules_doc)< 0 )
366                                 {
367                                         LM_ERR("while sending notify\n");
368                                         goto error;
369                                 }
370                                 
371                                 if (pa_dbf.use_table(pa_db, presentity_table) < 0) 
372                                 {
373                                         LM_ERR("unsuccessful sql use table\n");
374                                         goto error;
375                                 }
376
377                                 LM_DBG("expires =0 -> deleting from database\n");
378                                 if(pa_dbf.delete(pa_db,query_cols,0,query_vals,n_query_cols)<0)
379                                 {
380                                         LM_ERR("unsuccessful sql delete operation");
381                                         goto error;
382                                 }
383                                 LM_DBG("deleted from db %.*s\n",        presentity->user.len,
384                                                 presentity->user.s);
385
386                                 /* delete from hash table */
387         
388                                 if(delete_phtable(&msg->first_line.u.request.uri,
389                                                         presentity->event->evp->parsed)< 0)
390                                 {
391                                         LM_ERR("deleting record from hash table\n");
392                                         goto error;
393                                 }
394                                 return 1;
395                         }
396
397                         n_update_cols= 0;
398                         if(presentity->event->etag_not_new== 0)
399                         {       
400                                 /* generate another etag */
401                                 unsigned int publ_nr;
402                                 str str_publ_nr= {0, 0};
403
404                                 dot= presentity->etag.s+ presentity->etag.len;
405                                 while(*dot!= '.' && str_publ_nr.len< presentity->etag.len)
406                                 {
407                                         str_publ_nr.len++;
408                                         dot--;
409                                 }
410                                 if(str_publ_nr.len== presentity->etag.len)
411                                 {
412                                         LM_ERR("wrong etag\n");
413                                         return -1;                      
414                                 }       
415                                 str_publ_nr.s= dot+1;
416                                 str_publ_nr.len--;
417         
418                                 if( str2int(&str_publ_nr, &publ_nr)< 0)
419                                 {
420                                         LM_ERR("converting string to int\n");
421                                         goto error;
422                                 }
423                                 etag.s = generate_ETag(publ_nr+1);
424                                 if(etag.s == NULL)
425                                 {
426                                         LM_ERR("while generating etag\n");
427                                         return -1;
428                                 }
429                                 etag.len=(strlen(etag.s));
430                                 
431                                 cur_etag= etag;
432
433                                 update_keys[n_update_cols] = "etag";
434                                 update_vals[n_update_cols].type = DB_STR;
435                                 update_vals[n_update_cols].nul = 0;
436                                 update_vals[n_update_cols].val.str_val = etag;
437                                 n_update_cols++;
438
439                         }
440                         else
441                                 cur_etag= presentity->etag;
442                         
443                         update_keys[n_update_cols] = "expires";
444                         update_vals[n_update_cols].type = DB_INT;
445                         update_vals[n_update_cols].nul = 0;
446                         update_vals[n_update_cols].val.int_val= presentity->expires +
447                                 (int)time(NULL);
448                         n_update_cols++;
449
450                         update_keys[n_update_cols] = "received_time";
451                         update_vals[n_update_cols].type = DB_INT;
452                         update_vals[n_update_cols].nul = 0;
453                         update_vals[n_update_cols].val.int_val= presentity->received_time;
454                         n_update_cols++;
455
456                         if(body && body->s)
457                         {
458                                 update_keys[n_update_cols] = "body";
459                                 update_vals[n_update_cols].type = DB_BLOB;
460                                 update_vals[n_update_cols].nul = 0;
461                                 update_vals[n_update_cols].val.str_val = *body;
462                                 n_update_cols++;
463                         }
464
465                         if( pa_dbf.update( pa_db,query_cols, query_ops, query_vals,
466                         update_keys,update_vals, n_query_cols, n_update_cols )<0) 
467                         {
468                                 LM_ERR("updating published info in database\n");
469                                 goto error;
470                         }
471                         
472                         /* send 200OK */
473                         if( publ_send200ok(msg, presentity->expires, cur_etag)< 0)
474                         {
475                                 LM_ERR("sending 200OK reply\n");
476                                 if(etag.s)
477                                         pkg_free(etag.s);
478                                 return -1;
479                         }
480                         if(etag.s)
481                                 pkg_free(etag.s);
482                         etag.s= NULL;
483                         
484                         if(!body)
485                                 return 0;
486                 
487                         goto send_notify;
488                 }  
489                 else  /* if there isn't no registration with those 3 values */
490                 {
491                         pa_dbf.free_result(pa_db, result);
492                         result= NULL;
493                         LM_ERR("No E_Tag match\n");
494                         if (slb.reply(msg, 412, &pu_412_rpl) == -1)
495                         {
496                                 LM_ERR("sending '412 Conditional request failed' reply\n");
497                                 goto error;
498                         }
499                 }
500         }
501
502 send_notify:
503                         
504         /* send notify with presence information */
505         if (publ_notify(presentity, body, NULL, rules_doc)<0)
506         {
507                 LM_ERR("while sending Notify requests to watchers\n");
508                 goto error;
509         }
510
511         if(rules_doc)
512         {
513                 if(rules_doc->s)
514                         pkg_free(rules_doc->s);
515                 pkg_free(rules_doc);
516         }
517
518         return 0;
519
520 error:
521         if(result)
522                 pa_dbf.free_result(pa_db, result);
523         if(etag.s)
524                 pkg_free(etag.s);
525         if(rules_doc)
526         {
527                 if(rules_doc->s)
528                         pkg_free(rules_doc->s);
529                 pkg_free(rules_doc);
530         }
531         return -1;
532
533 }
534
535 int pres_htable_restore(void)
536 {
537         /* query all records from presentity table and insert records 
538          * in presentity table */
539         db_key_t result_cols[5];
540         db_res_t *result= NULL;
541         db_row_t *row= NULL ;   
542         db_val_t *row_vals;
543         int  i;
544         str user, domain, ev_str, uri;
545         int n_result_cols= 0;
546         int user_col, domain_col, event_col, expires_col;
547         int event;
548         event_t e;
549
550         result_cols[user_col= n_result_cols++]= "username";
551         result_cols[domain_col= n_result_cols++]= "domain";
552         result_cols[event_col= n_result_cols++]= "event";
553         result_cols[expires_col= n_result_cols++]= "expires";
554
555         if (pa_dbf.use_table(pa_db, presentity_table) < 0) 
556         {
557                 LM_ERR("unsuccessful use table sql operation\n");
558                 goto error;
559         }
560
561         if (pa_dbf.query (pa_db, 0, 0, 0,result_cols,0, n_result_cols,
562                                 "username", &result) < 0)
563         {
564                 LM_ERR("querying presentity\n");
565                 goto error;
566         }
567         if(result== NULL)
568                 goto error;
569
570         if(result->n<= 0)
571         {
572                 pa_dbf.free_result(pa_db, result);
573                 return 0;
574         }
575                 
576         for(i= 0; i< result->n; i++)
577         {
578                 row = &result->rows[i];
579                 row_vals = ROW_VALUES(row);
580
581                 if(row_vals[expires_col].val.int_val< (int)time(NULL))
582                         continue;
583
584                 user.s= (char*)row_vals[user_col].val.string_val;
585                 user.len= strlen(user.s);
586                 domain.s= (char*)row_vals[domain_col].val.string_val;
587                 domain.len= strlen(domain.s);
588                 ev_str.s= (char*)row_vals[event_col].val.string_val;
589                 ev_str.len= strlen(ev_str.s);
590         
591                 if(event_parser(ev_str.s, ev_str.len, &e)< 0)
592                 {
593                         LM_ERR("parsing event\n");
594                         goto error;
595                 }
596                 event= e.parsed;
597
598                 if(uandd_to_uri(user, domain, &uri)< 0)
599                 {
600                         LM_ERR("constructing uri\n");
601                         goto error;
602                 }
603                 /* insert in hash_table*/
604                 if(insert_phtable(&uri, event)< 0)
605                 {
606                         LM_ERR("inserting record in presentity hash table");
607                         pkg_free(uri.s);
608                         goto error;
609                 }
610                 pkg_free(uri.s);
611         }
612         pa_dbf.free_result(pa_db, result);
613
614         return 0;
615
616 error:
617         if(result)
618                 pa_dbf.free_result(pa_db, result);
619         return -1;      
620 }