all: updated FSF address in GPL text
[sip-router] / modules / ims_registrar_scscf / regpv.c
1 /*
2  * $Id$
3  *
4  * Export vontact attrs as PV
5  *
6  * Copyright (C) 2008 Daniel-Constantin Mierla (asipto.com)
7  *
8  * This file is part of Kamailio, a free SIP server.
9  *
10  * Kamailio 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  * Kamailio 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
23  */
24
25 /*!
26  * \file
27  * \brief SIP registrar module - export contacts as PV
28  * \ingroup registrar   
29  */  
30
31
32 #include <string.h>
33 #include "../../dprint.h"
34 #include "../../mem/mem.h"
35 #include "../../mod_fix.h"
36 #include "../ims_usrloc_scscf/usrloc.h"
37 #include "reg_mod.h"
38 #include "common.h"
39 #include "regpv.h"
40
41 typedef struct _regpv_profile {
42         str pname;
43         str domain;
44         str aor;
45         int flags;
46         unsigned int aorhash;
47         int nrc;
48         ucontact_t* contacts;
49         struct _regpv_profile *next;
50 } regpv_profile_t;
51
52 typedef struct _regpv_name {
53         regpv_profile_t *rp;
54         int attr;
55 } regpv_name_t;
56
57 static regpv_profile_t *_regpv_profile_list = NULL;
58
59 static inline regpv_profile_t* regpv_get_profile(str *name)
60 {
61         regpv_profile_t *rp;
62
63         if(name==NULL || name->len<=0)
64         {
65                 LM_ERR("invalid parameters\n");
66                 return NULL;
67         }
68
69         rp = _regpv_profile_list;
70         while(rp)
71         {
72                 if(rp->pname.len == name->len
73                                 && strncmp(rp->pname.s, name->s, name->len)==0)
74                         return rp;
75                 rp = rp->next;
76         }
77
78         rp = (regpv_profile_t*)pkg_malloc(sizeof(regpv_profile_t));
79         if(rp==NULL)
80         {
81                 LM_ERR("no more pkg\n");
82                 return NULL;
83         }
84         memset(rp, 0, sizeof(regpv_profile_t));
85         rp->pname.s = (char*)pkg_malloc((name->len+1)*sizeof(char));
86         if(rp->pname.s==NULL)
87         {
88                 LM_ERR("no more pkg\n");
89                 pkg_free(rp);
90                 return NULL;
91         }
92         memcpy(rp->pname.s, name->s, name->len);
93         rp->pname.s[name->len] = '\0';
94         rp->pname.len = name->len;
95
96         rp->next = _regpv_profile_list;
97         _regpv_profile_list = rp;
98         return rp;
99 }
100
101 static void regpv_free_profile(regpv_profile_t *rpp)
102 {
103         ucontact_t* ptr;
104         ucontact_t* ptr0;
105
106         if(rpp==NULL)
107                 return;
108
109         ptr = rpp->contacts;
110         while(ptr)
111         {
112                 ptr0 = ptr;
113                 ptr = ptr->next;
114                 pkg_free(ptr0);
115         }
116         if(rpp->domain.s!=NULL)
117         {
118                 rpp->domain.s = 0;
119                 rpp->domain.len = 0;
120         }
121         if(rpp->aor.s!=NULL)
122         {
123                 pkg_free(rpp->aor.s);
124                 rpp->aor.s = 0;
125                 rpp->aor.len = 0;
126         }
127
128         rpp->flags = 0;
129         rpp->aorhash = 0;
130         rpp->nrc = 0;
131         rpp->contacts = 0;
132
133 }
134
135 void regpv_free_profiles(void)
136 {
137         regpv_profile_t *rp;
138         regpv_profile_t *rp0;
139
140         rp = _regpv_profile_list;
141
142         while(rp)
143         {
144                 if(rp->pname.s!=NULL)
145                         pkg_free(rp->pname.s);
146                 rp0 = rp;
147                 regpv_free_profile(rp0);
148                 rp = rp->next;
149         }
150         _regpv_profile_list = 0;
151 }
152
153 int pv_get_ulc(struct sip_msg *msg,  pv_param_t *param,
154                 pv_value_t *res)
155 {
156         regpv_name_t *rp;
157         regpv_profile_t *rpp;
158         ucontact_t *c;
159         int idx;
160         int i;
161
162         if(param==NULL)
163         {
164                 LM_ERR("invalid params\n");
165                 return -1;
166         }
167         rp = (regpv_name_t*)param->pvn.u.dname;
168         if(rp==NULL || rp->rp==NULL)
169         {
170                 LM_DBG("no profile in params\n");
171                 return pv_get_null(msg, param, res);
172         }
173         rpp = rp->rp;
174
175         if(rpp->flags==0 || rpp->contacts==NULL)
176         {
177                 LM_DBG("profile not set or no contacts there\n");
178                 return pv_get_null(msg, param, res);
179         }
180         /* get index */
181         if(pv_get_spec_index(msg, param, &idx, &i)!=0)
182         {
183                 LM_ERR("invalid index\n");
184                 return -1;
185         }
186
187         /* work only with positive indexes by now */
188         if(idx<0)
189                 idx = 0;
190
191         /* get contact */
192         i = 0;
193         c = rpp->contacts;
194         while(rpp)
195         {
196                 if(i == idx)
197                         break;
198                 i++;
199                 c = c->next;
200         }
201         if(c==NULL)
202                 return pv_get_null(msg, param, res);
203
204         switch(rp->attr)
205         {
206                 case 0: /* aor */
207                         return  pv_get_strval(msg, param, res, &rpp->aor);
208                 break;
209                 case 1: /* domain */
210                         return  pv_get_strval(msg, param, res, &rpp->domain);
211                 break;
212                 case 2: /* aorhash */
213                         return pv_get_uintval(msg, param, res, rpp->aorhash);
214                 break;
215                 case 3: /* addr */
216                         return  pv_get_strval(msg, param, res, &c->c);
217                 break;
218                 case 4: /* path */
219                         return  pv_get_strval(msg, param, res, &c->path);
220                 break;
221                 case 5: /* received */
222                         return  pv_get_strval(msg, param, res, &c->received);
223                 break;
224                 case 6: /* expires */
225                         return pv_get_uintval(msg, param, res,
226                                         (unsigned int)c->expires);
227                 break;
228                 case 7: /* callid */
229                         return  pv_get_strval(msg, param, res, &c->callid);
230                 break;
231                 case 8: /* q */
232                         return pv_get_sintval(msg, param, res, (int)c->q);
233                 break;
234                 case 9: /* cseq */
235                         return pv_get_sintval(msg, param, res, c->cseq);
236                 break;
237                 case 10: /* flags */
238                         return pv_get_uintval(msg, param, res, c->flags);
239                 break;
240                 case 11: /* cflags */
241                         return pv_get_uintval(msg, param, res, c->cflags);
242                 break;
243                 case 12: /* user agent */
244                         return  pv_get_strval(msg, param, res, &c->user_agent);
245                 break;
246                 case 14: /* socket */
247                         if(c->sock==NULL)
248                                 return pv_get_null(msg, param, res);
249                         return pv_get_strval(msg, param, res, &c->sock->sock_str);
250                 break;
251                 case 15: /* modified */
252                         return pv_get_uintval(msg, param, res,
253                                         (unsigned int)c->last_modified);
254                 break;
255                 case 16: /* methods */
256                         return pv_get_uintval(msg, param, res, c->methods);
257                 break;
258                 case 17: /* count */
259                         return pv_get_sintval(msg, param, res, rpp->nrc);
260                 break;
261         }
262
263         return pv_get_null(msg, param, res);
264 }
265
266 int pv_set_ulc(struct sip_msg* msg, pv_param_t *param,
267                 int op, pv_value_t *val)
268 {
269         return 0;
270 }
271
272 int pv_parse_ulc_name(pv_spec_p sp, str *in)
273 {
274         str pn;
275         str pa;
276         regpv_name_t *rp;
277         regpv_profile_t *rpp;
278
279         if(sp==NULL || in==NULL || in->len<=0)
280                 return -1;
281
282         pa.s = in->s;
283         while(pa.s < in->s + in->len - 2)
284         {
285                 if(*pa.s=='=')
286                         break;
287                 pa.s++;
288         }
289         
290         if(pa.s >= in->s + in->len - 2)
291         {
292                 LM_ERR("invalid contact pv name %.*s\n", in->len, in->s);
293                 return -1;
294         }
295         if(*(pa.s+1) != '>')
296         {
297                 LM_ERR("invalid contact pv name %.*s.\n", in->len, in->s);
298                 return -1;
299         }
300
301         pn.s = in->s;
302         pn.len = pa.s - pn.s;
303
304         LM_DBG("get profile [%.*s]\n", pn.len, pn.s);
305
306         rpp = regpv_get_profile(&pn);
307         if(rpp==NULL)
308         {
309                 LM_ERR("cannot get profile [%.*s]\n", pn.len, pn.s);
310                 return -1;
311         }
312         pa.s += 2;
313         pa.len = in->s + in->len - pa.s;
314         LM_DBG("get attr [%.*s]\n", pa.len, pa.s);
315
316         rp = (regpv_name_t*)pkg_malloc(sizeof(regpv_name_t));
317         if(rp==0)
318         {
319                 LM_ERR("no more pkg\n");
320                 return -1;
321         }
322         memset(rp, 0, sizeof(regpv_name_t));
323         rp->rp = rpp;
324
325         switch(pa.len)
326         {
327                 case 1: 
328                         if(strncmp(pa.s, "q", 1)==0)
329                                 rp->attr = 8;
330                         else goto error;
331                 break;
332                 case 3: 
333                         if(strncmp(pa.s, "aor", 3)==0)
334                                 rp->attr = 0;
335                         else goto error;
336                 break;
337                 case 4: 
338                         if(strncmp(pa.s, "addr", 4)==0)
339                                 rp->attr = 3;
340                         else if(strncmp(pa.s, "path", 4)==0)
341                                 rp->attr = 4;
342                         else if(strncmp(pa.s, "cseq", 4)==0)
343                                 rp->attr = 9;
344                         else goto error;
345                 break;
346                 case 5: 
347                         if(strncmp(pa.s, "flags", 5)==0)
348                                 rp->attr = 10;
349                         else if(strncmp(pa.s, "count", 5)==0)
350                                 rp->attr = 17;
351                         else goto error;
352                 break;
353                 case 6: 
354                         if(strncmp(pa.s, "domain", 6)==0)
355                                 rp->attr = 1;
356                         else if(strncmp(pa.s, "callid", 6)==0)
357                                 rp->attr = 7;
358                         else if(strncmp(pa.s, "cflags", 6)==0)
359                                 rp->attr = 11;
360                         else if(strncmp(pa.s, "socket", 6)==0)
361                                 rp->attr = 14;
362                         else goto error;
363                 break;
364                 case 7: 
365                         if(strncmp(pa.s, "aorhash", 7)==0)
366                                 rp->attr = 2;
367                         else if(strncmp(pa.s, "expires", 7)==0)
368                                 rp->attr = 6;
369                         else if(strncmp(pa.s, "methods", 7)==0)
370                                 rp->attr = 16;
371                         else goto error;
372                 break;
373                 case 8: 
374                         if(strncmp(pa.s, "received", 8)==0)
375                                 rp->attr = 5;
376                         else if(strncmp(pa.s, "modified", 8)==0)
377                                 rp->attr = 15;
378                         else goto error;
379                 break;
380                 case 10: 
381                         if(strncmp(pa.s, "user_agent", 10)==0)
382                                 rp->attr = 12;
383                         else goto error;
384                 break;
385                 default:
386                         goto error;
387         }
388         sp->pvp.pvn.u.dname = (void*)rp;
389         sp->pvp.pvn.type = PV_NAME_PVAR;
390
391         return 0;
392
393 error:
394         LM_ERR("unknown contact attr name in %.*s\n", in->len, in->s);
395         return -1;
396 }
397
398 int pv_fetch_contacts(struct sip_msg* msg, char* table, char* uri,
399                 char* profile)
400 {
401         impurecord_t* r;
402         ucontact_t* ptr;
403         ucontact_t* ptr0;
404         ucontact_t* c0;
405         regpv_profile_t *rpp;
406         str aor = {0, 0};
407         str u = {0, 0};
408         int res;
409         int olen;
410         int ilen;
411         int n;
412         char *p;
413
414         rpp = regpv_get_profile((str*)profile);
415         if(rpp==0)
416         {
417                 LM_ERR("invalid parameters\n");
418                 return -1;
419         }
420
421         /* check and free if profile already set */
422         if(rpp->flags)
423                 regpv_free_profile(rpp);
424
425         if(fixup_get_svalue(msg, (gparam_p)uri, &u)!=0 || u.len<=0)
426         {
427                 LM_ERR("invalid uri parameter\n");
428                 return -1;
429         }
430
431         if (extract_aor(&u, &aor) < 0) {
432                 LM_ERR("failed to extract Address Of Record\n");
433                 return -1;
434         }
435
436         /* copy aor and ul domain */
437         rpp->aor.s = (char*)pkg_malloc(aor.len*sizeof(char));
438         if(rpp->aor.s==NULL)
439         {
440                 LM_ERR("no more pkg\n");
441                 return -1;
442         }
443         memcpy(rpp->aor.s, aor.s, aor.len);
444         rpp->aor.len = aor.len;
445         rpp->domain = *((udomain_head_t*)table)->name;
446         rpp->flags = 1;
447
448         /* copy contacts */
449         ilen = sizeof(ucontact_t);
450         ul.lock_udomain((udomain_t*)table, &aor);
451         res = ul.get_impurecord((udomain_t*)table, &aor, &r);
452         if (res > 0) {
453                 LM_DBG("'%.*s' Not found in usrloc\n", aor.len, ZSW(aor.s));
454                 ul.unlock_udomain((udomain_t*)table, &aor);
455                 return -1;
456         }
457
458         ptr = r->contacts;
459         ptr0 = NULL;
460         n = 0;
461         while(ptr)
462         {
463                 olen = (ptr->c.len + ptr->received.len + ptr->path.len
464                         + ptr->callid.len + ptr->user_agent.len)*sizeof(char) + ilen;
465                 c0 = (ucontact_t*)pkg_malloc(olen);
466                 if(c0==NULL)
467                 {
468                         LM_ERR("no more pkg\n");
469                         ul.unlock_udomain((udomain_t*)table, &aor);
470                         goto error;
471                 }
472                 memcpy(c0, ptr, ilen);
473                 c0->domain = NULL;
474                 c0->aor = NULL;
475                 c0->next = NULL;
476                 c0->prev = NULL;
477
478                 c0->c.s = (char*)c0 + ilen;
479                 memcpy(c0->c.s, ptr->c.s, ptr->c.len);
480                 c0->c.len = ptr->c.len;
481                 p = c0->c.s + c0->c.len;
482                 
483                 if(ptr->received.s!=NULL)
484                 {
485                         c0->received.s = p;
486                         memcpy(c0->received.s, ptr->received.s, ptr->received.len);
487                         c0->received.len = ptr->received.len;
488                         p += c0->received.len;
489                 }
490                 if(ptr->path.s!=NULL)
491                 {
492                         c0->path.s = p;
493                         memcpy(c0->path.s, ptr->path.s, ptr->path.len);
494                         c0->path.len = ptr->path.len;
495                         p += c0->path.len;
496                 }
497                 c0->callid.s = p;
498                 memcpy(c0->callid.s, ptr->callid.s, ptr->callid.len);
499                 c0->callid.len = ptr->callid.len;
500                 p += c0->callid.len;
501                 if(ptr->user_agent.s!=NULL)
502                 {
503                         c0->user_agent.s = p;
504                         memcpy(c0->user_agent.s, ptr->user_agent.s, ptr->user_agent.len);
505                         c0->user_agent.len = ptr->user_agent.len;
506                         p += c0->user_agent.len;
507                 }
508
509                 if(ptr0==NULL)
510                 {
511                         rpp->contacts = c0;
512                 } else {
513                         ptr0->next = c0;
514                         c0->prev = ptr0;
515                 }
516                 n++;
517                 ptr0 = c0;
518                 ptr = ptr->next;
519         }
520         ul.unlock_udomain((udomain_t*)table, &aor);
521         rpp->nrc = n;
522         LM_DBG("fetched <%d> contacts for <%.*s> in [%.*s]\n",
523                         n, aor.len, aor.s, rpp->pname.len, rpp->pname.s);
524         return 1;
525
526 error:
527         regpv_free_profile(rpp);
528         return -1;
529 }
530 int pv_free_contacts(struct sip_msg* msg, char* profile, char* s2)
531 {
532         regpv_profile_t *rpp;
533
534         rpp = regpv_get_profile((str*)profile);
535         if(rpp==0)
536                 return -1;
537
538         regpv_free_profile(rpp);
539
540         return 1;
541 }