registrar(k): reset local interator to contacts headers
[sip-router] / modules_k / registrar / save.c
1 /*
2  * $Id$
3  *
4  * Process REGISTER request and send reply
5  *
6  * Copyright (C) 2001-2003 FhG Fokus
7  * Copyright (C) 2006 Voice Sistem SRL
8  *
9  * This file is part of Kamailio, a free SIP server.
10  *
11  * Kamailio is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version
15  *
16  * Kamailio is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License 
22  * along with this program; if not, write to the Free Software 
23  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
24  *
25  * History:
26  * ----------
27  * 2003-01-27 next baby-step to removing ZT - PRESERVE_ZT (jiri)
28  * 2003-02-28 scrathcpad compatibility abandoned (jiri)
29  * 2003-03-21 save_noreply added, patch provided by Maxim Sobolev 
30  *            <sobomax@portaone.com> (janakj)
31  * 2005-07-11 added sip_natping_flag for nat pinging with SIP method
32  *            instead of UDP package (bogdan)
33  * 2006-04-13 added tcp_persistent_flag for keeping the TCP connection as long
34  *            as a TCP contact is registered (bogdan)
35  * 2006-11-22 save_noreply and save_memory merged into save() (bogdan)
36  * 2006-11-28 Added statistic support for the number of accepted/rejected 
37  *            registrations. (Jeffrey Magder - SOMA Networks) 
38  * 2007-02-24  sip_natping_flag moved into branch flags, so migrated to 
39  *             nathelper module (bogdan)
40  */
41 /*!
42  * \file
43  * \brief SIP registrar module - Process REGISTER request and send reply
44  * \ingroup registrar   
45  */  
46
47
48 #include "../../str.h"
49 #include "../../socket_info.h"
50 #include "../../parser/parse_allow.h"
51 #include "../../parser/parse_methods.h"
52 #include "../../parser/msg_parser.h"
53 #include "../../parser/parse_to.h"
54 #include "../../parser/parse_uri.h"
55 #include "../../dprint.h"
56 #include "../../trim.h"
57 #include "../../ut.h"
58 #include "../../qvalue.h"
59 #include "../../dset.h"
60 #include "../../mod_fix.h"
61 #include "../../lib/kcore/cmpapi.h"
62 #include "../../lib/kcore/statistics.h"
63 #ifdef USE_TCP
64 #include "../../tcp_server.h"
65 #endif
66 #include "../usrloc/usrloc.h"
67 #include "common.h"
68 #include "sip_msg.h"
69 #include "rerrno.h"
70 #include "reply.h"
71 #include "reg_mod.h"
72 #include "regtime.h"
73 #include "path.h"
74 #include "save.h"
75 #include "config.h"
76
77 static int mem_only = 0;
78
79 /*! \brief
80  * Process request that contained a star, in that case, 
81  * we will remove all bindings with the given username 
82  * from the usrloc and return 200 OK response
83  */
84 static inline int star(udomain_t* _d, str* _a)
85 {
86         urecord_t* r;
87         ucontact_t* c;
88         
89         ul.lock_udomain(_d, _a);
90
91         if (!ul.get_urecord(_d, _a, &r)) {
92                 c = r->contacts;
93                 while(c) {
94                         if (mem_only) {
95                                 c->flags |= FL_MEM;
96                         } else {
97                                 c->flags &= ~FL_MEM;
98                         }
99                         c = c->next;
100                 }
101         } else {
102                 r = NULL;
103         }
104
105         if (ul.delete_urecord(_d, _a, r) < 0) {
106                 LM_ERR("failed to remove record from usrloc\n");
107                 
108                      /* Delete failed, try to get corresponding
109                       * record structure and send back all existing
110                       * contacts
111                       */
112                 rerrno = R_UL_DEL_R;
113                 if (!ul.get_urecord(_d, _a, &r)) {
114                         build_contact(r->contacts);
115                         ul.release_urecord(r);
116                 }
117                 ul.unlock_udomain(_d, _a);
118                 return -1;
119         }
120         ul.unlock_udomain(_d, _a);
121         return 0;
122 }
123
124
125 /*! \brief
126  */
127 static struct socket_info *get_sock_hdr(struct sip_msg *msg)
128 {
129         struct socket_info *sock;
130         struct hdr_field *hf;
131         str socks;
132         str hosts;
133         int port;
134         int proto;
135         char c;
136
137         if (parse_headers( msg, HDR_EOH_F, 0) == -1) {
138                 LM_ERR("failed to parse message\n");
139                 return 0;
140         }
141
142         for (hf=msg->headers; hf; hf=hf->next) {
143                 if (cmp_hdrname_str(&hf->name, &sock_hdr_name)==0)
144                         break;
145         }
146
147         /* hdr found? */
148         if (hf==0)
149                 return 0;
150
151         trim_len( socks.len, socks.s, hf->body );
152         if (socks.len==0)
153                 return 0;
154
155         /*FIXME: This is a hack */
156         c = socks.s[socks.len];
157         socks.s[socks.len] = '\0';
158         if (parse_phostport( socks.s, &hosts.s, &hosts.len,
159         &port, &proto)!=0) {
160                 socks.s[socks.len] = c;
161                 LM_ERR("bad socket <%.*s> in \n",
162                         socks.len, socks.s);
163                 return 0;
164         }
165         socks.s[socks.len] = c;
166         sock = grep_sock_info(&hosts,(unsigned short)port,(unsigned short)proto);
167         if (sock==0) {
168                 LM_ERR("non-local socket <%.*s>\n",     socks.len, socks.s);
169                 return 0;
170         }
171
172         LM_DBG("%d:<%.*s>:%d -> p=%p\n", proto,socks.len,socks.s,port_no,sock );
173
174         return sock;
175 }
176
177
178
179 /*! \brief
180  * Process request that contained no contact header
181  * field, it means that we have to send back a response
182  * containing a list of all existing bindings for the
183  * given username (in To HF)
184  */
185 static inline int no_contacts(udomain_t* _d, str* _a)
186 {
187         urecord_t* r;
188         int res;
189         
190         ul.lock_udomain(_d, _a);
191         res = ul.get_urecord(_d, _a, &r);
192         if (res < 0) {
193                 rerrno = R_UL_GET_R;
194                 LM_ERR("failed to retrieve record from usrloc\n");
195                 ul.unlock_udomain(_d, _a);
196                 return -1;
197         }
198         
199         if (res == 0) {  /* Contacts found */
200                 build_contact(r->contacts);
201                 ul.release_urecord(r);
202         } else {  /* No contacts found */
203                 build_contact(NULL);
204         }
205         ul.unlock_udomain(_d, _a);
206         return 0;
207 }
208
209
210
211 /*! \brief
212  * Fills the common part (for all contacts) of the info structure
213  */
214 static inline ucontact_info_t* pack_ci( struct sip_msg* _m, contact_t* _c,
215                                                                                         unsigned int _e, unsigned int _f)
216 {
217         static ucontact_info_t ci;
218         static str no_ua = str_init("n/a");
219         static str callid;
220         static str path_received = {0,0};
221         static str path;
222         static str received = {0,0};
223         static int received_found;
224         static unsigned int allowed, allow_parsed;
225         static struct sip_msg *m = 0;
226         int_str val;
227
228         if (_m!=0) {
229                 memset( &ci, 0, sizeof(ucontact_info_t));
230
231                 /* Get callid of the message */
232                 callid = _m->callid->body;
233                 trim_trailing(&callid);
234                 if (callid.len > CALLID_MAX_SIZE) {
235                         rerrno = R_CALLID_LEN;
236                         LM_ERR("callid too long\n");
237                         goto error;
238                 }
239                 ci.callid = &callid;
240
241                 /* Get CSeq number of the message */
242                 if (str2int(&get_cseq(_m)->number, (unsigned int*)&ci.cseq) < 0) {
243                         rerrno = R_INV_CSEQ;
244                         LM_ERR("failed to convert cseq number\n");
245                         goto error;
246                 }
247
248                 /* set received socket */
249                 if (_m->flags&sock_flag) {
250                         ci.sock = get_sock_hdr(_m);
251                         if (ci.sock==0)
252                                 ci.sock = _m->rcv.bind_address;
253                 } else {
254                         ci.sock = _m->rcv.bind_address;
255                 }
256
257                 /* additional info from message */
258                 if (parse_headers(_m, HDR_USERAGENT_F, 0) != -1 && _m->user_agent &&
259                 _m->user_agent->body.len>0 && _m->user_agent->body.len<UA_MAX_SIZE) {
260                         ci.user_agent = &_m->user_agent->body;
261                 } else {
262                         ci.user_agent = &no_ua;
263                 }
264
265                 /* extract Path headers */
266                 if (path_enabled) {
267                         if (build_path_vector(_m, &path, &path_received) < 0) {
268                                 rerrno = R_PARSE_PATH;
269                                 goto error;
270                         }
271                         if (path.len && path.s) {
272                                 ci.path = &path;
273                                 if (path_mode != PATH_MODE_OFF) {
274                                         /* save in msg too for reply */
275                                         if (set_path_vector(_m, &path) < 0) {
276                                                 rerrno = R_PARSE_PATH;
277                                                 goto error;
278                                         }
279                                 }
280                         }
281                 }
282
283                 ci.last_modified = act_time;
284
285                 /* set flags */
286                 ci.flags  = _f;
287                 getbflagsval(0, &ci.cflags);
288
289                 /* get received */
290                 if (path_received.len && path_received.s) {
291                         ci.cflags |= ul.nat_flag;
292                         ci.received = path_received;
293                 }
294
295                 allow_parsed = 0; /* not parsed yet */
296                 received_found = 0; /* not found yet */
297                 m = _m; /* remember the message */
298         }
299
300         if(_c!=0) {
301                 /* Calculate q value of the contact */
302                 if (calc_contact_q(_c->q, &ci.q) < 0) {
303                         rerrno = R_INV_Q;
304                         LM_ERR("failed to calculate q\n");
305                         goto error;
306                 }
307
308                 /* set expire time */
309                 ci.expires = _e;
310
311                 /* Get methods of contact */
312                 if (_c->methods) {
313                         if (parse_methods(&(_c->methods->body), &ci.methods) < 0) {
314                                 rerrno = R_PARSE;
315                                 LM_ERR("failed to parse contact methods\n");
316                                 goto error;
317                         }
318                 } else {
319                         /* check on Allow hdr */
320                         if (allow_parsed == 0) {
321                                 if (m && parse_allow( m ) != -1) {
322                                         allowed = get_allow_methods(m);
323                                 } else {
324                                         allowed = ALL_METHODS;
325                                 }
326                                 allow_parsed = 1;
327                         }
328                         ci.methods = allowed;
329                 }
330
331                 /* get received */
332                 if (ci.received.len==0) {
333                         if (_c->received) {
334                                 ci.received = _c->received->body;
335                         } else {
336                                 if (received_found==0) {
337                                         memset(&val, 0, sizeof(int_str));
338                                         if (rcv_avp_name.n!=0
339                                                                 && search_first_avp(rcv_avp_type, rcv_avp_name, &val, 0)
340                                                                 && val.s.len > 0) {
341                                                 if (val.s.len>RECEIVED_MAX_SIZE) {
342                                                         rerrno = R_CONTACT_LEN;
343                                                         LM_ERR("received too long\n");
344                                                         goto error;
345                                                 }
346                                                 received = val.s;
347                                         } else {
348                                                 received.s = 0;
349                                                 received.len = 0;
350                                         }
351                                         received_found = 1;
352                                 }
353                                 ci.received = received;
354                         }
355                 }
356
357         }
358
359         return &ci;
360 error:
361         return 0;
362 }
363
364
365
366 /*! \brief
367  * Message contained some contacts, but record with same address
368  * of record was not found so we have to create a new record
369  * and insert all contacts from the message that have expires
370  * > 0
371  */
372 static inline int insert_contacts(struct sip_msg* _m, udomain_t* _d, str* _a)
373 {
374         ucontact_info_t* ci;
375         urecord_t* r;
376         ucontact_t* c;
377         contact_t* _c;
378         unsigned int flags;
379         int num, expires;
380 #ifdef USE_TCP
381         int e_max, tcp_check;
382         struct sip_uri uri;
383 #endif
384
385         flags = mem_only;
386 #ifdef USE_TCP
387         if ( (_m->flags&tcp_persistent_flag) &&
388         (_m->rcv.proto==PROTO_TCP||_m->rcv.proto==PROTO_TLS)) {
389                 e_max = 0;
390                 tcp_check = 1;
391         } else {
392                 e_max = tcp_check = 0;
393         }
394 #endif
395         _c = get_first_contact(_m);
396         for( num=0,r=0,ci=0 ; _c ; _c = get_next_contact(_c) ) {
397                 /* calculate expires */
398                 calc_contact_expires(_m, _c->expires, &expires);
399                 /* Skip contacts with zero expires */
400                 if (expires == 0)
401                         continue;
402
403                 if (cfg_get(registrar, registrar_cfg, max_contacts)
404                                 && (num >= cfg_get(registrar, registrar_cfg, max_contacts))) {
405                         LM_INFO("too many contacts (%d) for AOR <%.*s>\n", 
406                                         num, _a->len, _a->s);
407                         rerrno = R_TOO_MANY;
408                         goto error;
409                 }
410                 num++;
411
412                 if (r==0) {
413                         if (ul.insert_urecord(_d, _a, &r) < 0) {
414                                 rerrno = R_UL_NEW_R;
415                                 LM_ERR("failed to insert new record structure\n");
416                                 goto error;
417                         }
418                 }
419
420                 /* pack the contact_info */
421                 if ( (ci=pack_ci( (ci==0)?_m:0, _c, expires, flags))==0 ) {
422                         LM_ERR("failed to extract contact info\n");
423                         goto error;
424                 }
425
426                 if ( r->contacts==0 ||
427                 ul.get_ucontact(r, &_c->uri, ci->callid, ci->path, ci->cseq+1, &c) != 0) {
428                         if (ul.insert_ucontact( r, &_c->uri, ci, &c) < 0) {
429                                 rerrno = R_UL_INS_C;
430                                 LM_ERR("failed to insert contact\n");
431                                 goto error;
432                         }
433                 } else {
434                         if (ul.update_ucontact( r, c, ci) < 0) {
435                                 rerrno = R_UL_UPD_C;
436                                 LM_ERR("failed to update contact\n");
437                                 goto error;
438                         }
439                 }
440 #ifdef USE_TCP
441                 if (tcp_check) {
442                         /* parse contact uri to see if transport is TCP */
443                         if (parse_uri( _c->uri.s, _c->uri.len, &uri)<0) {
444                                 LM_ERR("failed to parse contact <%.*s>\n", 
445                                                 _c->uri.len, _c->uri.s);
446                         } else if (uri.proto==PROTO_TCP || uri.proto==PROTO_TLS) {
447                                 if (e_max) {
448                                         LM_WARN("multiple TCP contacts on single REGISTER\n");
449                                         if (expires>e_max) e_max = expires;
450                                 } else {
451                                         e_max = expires;
452                                 }
453                         }
454                 }
455 #endif
456         }
457
458         if (r) {
459                 if (r->contacts)
460                         build_contact(r->contacts);
461                 ul.release_urecord(r);
462         } else { /* No contacts found */
463                 build_contact(NULL);
464         }
465
466 #ifdef USE_TCP
467         if ( tcp_check && e_max>0 ) {
468                 e_max -= act_time;
469                 /*FIXME: Do we want this in the sr core?*/
470                 /*force_tcp_conn_lifetime( &_m->rcv , e_max + 10 );*/
471         }
472 #endif
473
474         return 0;
475 error:
476         if (r)
477                 ul.delete_urecord(_d, _a, r);
478         return -1;
479 }
480
481
482 static int test_max_contacts(struct sip_msg* _m, urecord_t* _r, contact_t* _c,
483                                                                                                                 ucontact_info_t *ci)
484 {
485         int num;
486         int e;
487         ucontact_t* ptr, *cont;
488         int ret;
489         
490         num = 0;
491         ptr = _r->contacts;
492         while(ptr) {
493                 if (VALID_CONTACT(ptr, act_time)) {
494                         num++;
495                 }
496                 ptr = ptr->next;
497         }
498         LM_DBG("%d valid contacts\n", num);
499         
500         for( ; _c ; _c = get_next_contact(_c) ) {
501                 /* calculate expires */
502                 calc_contact_expires(_m, _c->expires, &e);
503
504                 ret = ul.get_ucontact( _r, &_c->uri, ci->callid, ci->path, ci->cseq, &cont);
505                 if (ret==-1) {
506                         LM_ERR("invalid cseq for aor <%.*s>\n",_r->aor.len,_r->aor.s);
507                         rerrno = R_INV_CSEQ;
508                         return -1;
509                 } else if (ret==-2) {
510                         continue;
511                 }
512                 if (ret > 0) {
513                         /* Contact not found */
514                         if (e != 0) num++;
515                 } else {
516                         if (e == 0) num--;
517                 }
518         }
519         
520         LM_DBG("%d contacts after commit\n", num);
521         if (num > cfg_get(registrar, registrar_cfg, max_contacts)) {
522                 LM_INFO("too many contacts for AOR <%.*s>\n", _r->aor.len, _r->aor.s);
523                 rerrno = R_TOO_MANY;
524                 return -1;
525         }
526
527         return 0;
528 }
529
530
531 /*! \brief
532  * Message contained some contacts and appropriate
533  * record was found, so we have to walk through
534  * all contacts and do the following:
535  * 1) If contact in usrloc doesn't exists and
536  *    expires > 0, insert new contact
537  * 2) If contact in usrloc exists and expires
538  *    > 0, update the contact
539  * 3) If contact in usrloc exists and expires
540  *    == 0, delete contact
541  */
542 static inline int update_contacts(struct sip_msg* _m, urecord_t* _r,
543                                                                                 int _mode)
544 {
545         ucontact_info_t *ci;
546         ucontact_t *c, *ptr, *ptr0;
547         int expires, ret, updated;
548         unsigned int flags;
549 #ifdef USE_TCP
550         int e_max, tcp_check;
551         struct sip_uri uri;
552 #endif
553         int rc;
554         contact_t* _c;
555
556         /* mem flag */
557         flags = mem_only;
558
559         rc = 0;
560         /* pack the contact_info */
561         if ( (ci=pack_ci( _m, 0, 0, flags))==0 ) {
562                 LM_ERR("failed to initial pack contact info\n");
563                 goto error;
564         }
565
566         if (cfg_get(registrar, registrar_cfg, max_contacts)) {
567                 _c = get_first_contact(_m);
568                 if(test_max_contacts(_m, _r, _c, ci) != 0)
569                         goto error;
570         }
571
572 #ifdef USE_TCP
573         if ( (_m->flags&tcp_persistent_flag) &&
574         (_m->rcv.proto==PROTO_TCP||_m->rcv.proto==PROTO_TLS)) {
575                 e_max = -1;
576                 tcp_check = 1;
577         } else {
578                 e_max = tcp_check = 0;
579         }
580 #endif
581
582         _c = get_first_contact(_m);
583         updated=0;
584         for( ; _c ; _c = get_next_contact(_c) ) {
585                 /* calculate expires */
586                 calc_contact_expires(_m, _c->expires, &expires);
587
588                 /* search for the contact*/
589                 ret = ul.get_ucontact( _r, &_c->uri, ci->callid, ci->path, ci->cseq, &c);
590                 if (ret==-1) {
591                         LM_ERR("invalid cseq for aor <%.*s>\n",_r->aor.len,_r->aor.s);
592                         rerrno = R_INV_CSEQ;
593                         goto error;
594                 } else if (ret==-2) {
595                         if(expires!=0 && _mode)
596                                 break;
597                         continue;
598                 }
599
600                 if ( ret > 0 ) {
601                         /* Contact not found -> expired? */
602                         if (expires==0)
603                                 continue;
604
605                         /* pack the contact_info */
606                         if ( (ci=pack_ci( 0, _c, expires, 0))==0 ) {
607                                 LM_ERR("failed to extract contact info\n");
608                                 goto error;
609                         }
610
611                         if (ul.insert_ucontact( _r, &_c->uri, ci, &c) < 0) {
612                                 rerrno = R_UL_INS_C;
613                                 LM_ERR("failed to insert contact\n");
614                                 goto error;
615                         }
616                         rc = 1;
617                         if(_mode)
618                         {
619                                 ptr=_r->contacts;
620                                 while(ptr)
621                                 {
622                                         ptr0 = ptr;
623                                         if(ptr!=c)
624                                                 ul.delete_ucontact(_r, ptr);
625                                         ptr=ptr0->next;
626                                 }
627                                 updated=1;
628                         }
629                 } else {
630                         /* Contact found */
631                         if (expires == 0) {
632                                 /* it's expired */
633                                 if (mem_only) {
634                                         c->flags |= FL_MEM;
635                                 } else {
636                                         c->flags &= ~FL_MEM;
637                                 }
638
639                                 if (ul.delete_ucontact(_r, c) < 0) {
640                                         rerrno = R_UL_DEL_C;
641                                         LM_ERR("failed to delete contact\n");
642                                         goto error;
643                                 }
644                                 rc = 3;
645                         } else {
646                                 /* do update */
647                                 /* pack the contact specific info */
648                                 if ( (ci=pack_ci( 0, _c, expires, 0))==0 ) {
649                                         LM_ERR("failed to pack contact specific info\n");
650                                         goto error;
651                                 }
652
653                                 if(_mode)
654                                 {
655                                         ptr=_r->contacts;
656                                         while(ptr)
657                                         {
658                                                 ptr0 = ptr;
659                                                 if(ptr!=c)
660                                                         ul.delete_ucontact(_r, ptr);
661                                                 ptr=ptr0->next;
662                                         }
663                                         updated=1;
664                                 }
665                                 if (ul.update_ucontact(_r, c, ci) < 0) {
666                                         rerrno = R_UL_UPD_C;
667                                         LM_ERR("failed to update contact\n");
668                                         goto error;
669                                 }
670                                 rc = 2;
671                         }
672                 }
673 #ifdef USE_TCP
674                 if (tcp_check) {
675                         /* parse contact uri to see if transport is TCP */
676                         if (parse_uri( _c->uri.s, _c->uri.len, &uri)<0) {
677                                 LM_ERR("failed to parse contact <%.*s>\n", 
678                                                 _c->uri.len, _c->uri.s);
679                         } else if (uri.proto==PROTO_TCP || uri.proto==PROTO_TLS) {
680                                 if (e_max>0) {
681                                         LM_WARN("multiple TCP contacts on single REGISTER\n");
682                                 }
683                                 if (expires>e_max) e_max = expires;
684                         }
685                 }
686 #endif
687                 /* have one contact only -- break */
688                 if(updated)
689                         break;
690         }
691
692 #ifdef USE_TCP
693         if ( tcp_check && e_max>-1 ) {
694                 if (e_max) e_max -= act_time;
695                 /*FIXME: Do we want this in the sr core? */
696                 /*force_tcp_conn_lifetime( &_m->rcv , e_max + 10 );*/
697         }
698 #endif
699
700         return rc;
701 error:
702         return -1;
703 }
704
705
706 /*! \brief
707  * This function will process request that
708  * contained some contact header fields
709  */
710 static inline int add_contacts(struct sip_msg* _m, udomain_t* _d,
711                 str* _a, int _mode)
712 {
713         int res;
714         int ret;
715         urecord_t* r;
716
717         ret = 0;
718         ul.lock_udomain(_d, _a);
719         res = ul.get_urecord(_d, _a, &r);
720         if (res < 0) {
721                 rerrno = R_UL_GET_R;
722                 LM_ERR("failed to retrieve record from usrloc\n");
723                 ul.unlock_udomain(_d, _a);
724                 return -2;
725         }
726
727         if (res == 0) { /* Contacts found */
728                 if ((ret=update_contacts(_m, r, _mode)) < 0) {
729                         build_contact(r->contacts);
730                         ul.release_urecord(r);
731                         ul.unlock_udomain(_d, _a);
732                         return -3;
733                 }
734                 build_contact(r->contacts);
735                 ul.release_urecord(r);
736         } else {
737                 if (insert_contacts(_m, _d, _a) < 0) {
738                         ul.unlock_udomain(_d, _a);
739                         return -4;
740                 }
741                 ret = 1;
742         }
743         ul.unlock_udomain(_d, _a);
744         return ret;
745 }
746
747
748 /*!\brief
749  * Process REGISTER request and save it's contacts
750  */
751 #define is_cflag_set(_name) (((unsigned int)_cflags)&(_name))
752 int save(struct sip_msg* _m, udomain_t* _d, int _cflags)
753 {
754         contact_t* c;
755         int st, mode;
756         str aor;
757         int ret;
758
759         rerrno = R_FINE;
760         ret = 1;
761
762         if (parse_message(_m) < 0) {
763                 goto error;
764         }
765
766         if (check_contacts(_m, &st) > 0) {
767                 goto error;
768         }
769         
770         get_act_time();
771         c = get_first_contact(_m);
772
773         if (extract_aor(&get_to(_m)->uri, &aor) < 0) {
774                 LM_ERR("failed to extract Address Of Record\n");
775                 goto error;
776         }
777
778         mem_only = is_cflag_set(REG_SAVE_MEM_FL)?FL_MEM:FL_NONE;
779
780         if (c == 0) {
781                 if (st) {
782                         if (star((udomain_t*)_d, &aor) < 0) goto error;
783                         else ret=3;
784                 } else {
785                         if (no_contacts((udomain_t*)_d, &aor) < 0) goto error;
786                         else ret=4;
787                 }
788         } else {
789                 mode = is_cflag_set(REG_SAVE_REPL_FL)?1:0;
790                 if ((ret=add_contacts(_m, (udomain_t*)_d, &aor, mode)) < 0)
791                         goto error;
792                 ret = (ret==0)?1:ret;
793         }
794
795         update_stat(accepted_registrations, 1);
796
797         /* Only send reply upon request, not upon reply */
798         if ((is_route_type(REQUEST_ROUTE)) && !is_cflag_set(REG_SAVE_NORPL_FL) && (reg_send_reply(_m) < 0))
799                 return -1;
800
801         return ret;
802 error:
803         update_stat(rejected_registrations, 1);
804         if (is_route_type(REQUEST_ROUTE) && !is_cflag_set(REG_SAVE_NORPL_FL) )
805                 reg_send_reply(_m);
806
807         return 0;
808 }
809
810 int unregister(struct sip_msg* _m, char* _d, char* _uri)
811 {
812         str aor = {0, 0};
813         str uri = {0, 0};
814
815         if(fixup_get_svalue(_m, (gparam_p)_uri, &uri)!=0 || uri.len<=0)
816         {
817                 LM_ERR("invalid uri parameter\n");
818                 return -1;
819         }
820
821         if (extract_aor(&uri, &aor) < 0) {
822                 LM_ERR("failed to extract Address Of Record\n");
823                 return -1;
824         }
825
826         if (star((udomain_t*)_d, &aor) < 0)
827         {
828                 LM_ERR("error unregistering user [%.*s]\n", aor.len, aor.s);
829                 return -1;
830         }
831         return 1;
832 }
833