registrar_notify.c

Go to the documentation of this file.
00001 /*
00002  * $Id: registrar_notify.c 591 2008-10-15 12:46:34Z vingarzan $
00003  *  
00004  * Copyright (C) 2004-2006 FhG Fokus
00005  *
00006  * This file is part of Open IMS Core - an open source IMS CSCFs & HSS
00007  * implementation
00008  *
00009  * Open IMS Core is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * For a license to use the Open IMS Core software under conditions
00015  * other than those described here, or to purchase support for this
00016  * software, please contact Fraunhofer FOKUS by e-mail at the following
00017  * addresses:
00018  *     info@open-ims.org
00019  *
00020  * Open IMS Core is distributed in the hope that it will be useful,
00021  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  * GNU General Public License for more details.
00024  * 
00025  * It has to be noted that this Open Source IMS Core System is not 
00026  * intended to become or act as a product in a commercial context! Its 
00027  * sole purpose is to provide an IMS core reference implementation for 
00028  * IMS technology testing and IMS application prototyping for research 
00029  * purposes, typically performed in IMS test-beds.
00030  * 
00031  * Users of the Open Source IMS Core System have to be aware that IMS
00032  * technology may be subject of patents and licence terms, as being 
00033  * specified within the various IMS-related IETF, ITU-T, ETSI, and 3GPP
00034  * standards. Thus all Open IMS Core users have to take notice of this 
00035  * fact and have to agree to check out carefully before installing, 
00036  * using and extending the Open Source IMS Core System, if related 
00037  * patents and licences may become applicable to the intended usage 
00038  * context.  
00039  *
00040  * You should have received a copy of the GNU General Public License
00041  * along with this program; if not, write to the Free Software
00042  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00043  * 
00044  */
00045  
00055 #include "registrar_notify.h"
00056 
00057 #include "registrar_storage.h"
00058 #include "mod.h" 
00059 #include "../../mem/mem.h"
00060 #include "../../mem/shm_mem.h"
00061 #include "../../parser/parse_uri.h"
00062 #include "../../locking.h"
00063 #include "../tm/tm_load.h"
00064 #include "sip.h"
00065 #include "ims_pm.h"
00066 
00067 extern struct tm_binds tmb;                 
00069 extern str scscf_name_str;                          
00071 extern int subscription_default_expires;    
00072 extern int subscription_min_expires;        
00073 extern int subscription_max_expires;        
00075 extern time_t time_now;                     
00077 extern int r_hash_size;                     
00078 extern r_hash_slot *registrar;              
00080 r_notification_list *notification_list=0;   
00085 int r_notify_init()
00086 {
00087     notification_list = shm_malloc(sizeof(r_notification_list));
00088     if (!notification_list) return 0;
00089     memset(notification_list,0,sizeof(r_notification_list));
00090     notification_list->lock = lock_alloc();
00091     if (!notification_list->lock) return 0;
00092     notification_list->lock = lock_init(notification_list->lock);
00093     return 1;
00094 }
00095 
00099 void r_notify_destroy()
00100 {
00101     r_notification *n,*nn;
00102     lock_get(notification_list->lock);
00103     n = notification_list->head;
00104     while(n){
00105         nn = n->next;
00106         free_r_notification(n);
00107         n = nn;
00108     }
00109     lock_destroy(notification_list->lock);
00110     lock_dealloc(notification_list->lock);  
00111     shm_free(notification_list);
00112 }
00113 
00114 
00115 static str lookup_sip={"sip:",4};
00128 int S_can_subscribe(struct sip_msg *msg,char *str1,char *str2)
00129 {
00130     int ret=CSCF_RETURN_FALSE;
00131     struct sip_uri puri;
00132     str uri={0,0};
00133     str event;
00134     str asserted_id;
00135     r_public *p=0;
00136     r_contact *c=0;
00137     ims_public_identity *pi=0;
00138     int i,j;
00139 
00140     LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: Checking if allowed to SUBSCRIBE\n");
00141 
00142     /* First check the parameters */
00143     if (msg->first_line.type!=SIP_REQUEST)
00144     {
00145         LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: This message is not a request\n");
00146         goto error;
00147     }       
00148     if (msg->first_line.u.request.method.len != 9 ||
00149         memcmp(msg->first_line.u.request.method.s,"SUBSCRIBE",9)!=0)
00150     {
00151         LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: This message is not a SUBSCRIBE\n");
00152         goto error;
00153     }
00154 
00155     /* 1. Get the event     */
00156     event = cscf_get_event(msg);
00157     if (event.len!=3||strncasecmp(event.s,"reg",3)!=0){
00158         LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: Accepting only <Event: reg>. Found: <%.*s>\n",
00159             event.len,event.s);
00160         ret = CSCF_RETURN_FALSE;    
00161         goto done;
00162     } 
00163     
00164     /* 2. Get the target of the SUBSCRIBE from RequestURI */
00165     if (msg->new_uri.s) uri = msg->new_uri;
00166     else uri = msg->first_line.u.request.uri;
00167     
00168     if (parse_uri(uri.s, uri.len, &puri) < 0) {
00169         LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: Error parsing uri <%.*s>\n",
00170             uri.len,uri.s);
00171         goto error;
00172     }
00173     uri.len = lookup_sip.len+puri.user.len+1+puri.host.len;
00174     uri.s = pkg_malloc(uri.len);
00175     if (!uri.s){
00176         LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: Error allocating %d bytes\n",uri.len);
00177         goto error;
00178     }
00179     uri.len=0;
00180     memcpy(uri.s,lookup_sip.s,lookup_sip.len);
00181     uri.len+=lookup_sip.len;
00182     memcpy(uri.s+uri.len,puri.user.s,puri.user.len);
00183     uri.len+=puri.user.len;
00184     uri.s[uri.len++]='@';
00185     memcpy(uri.s+uri.len,puri.host.s,puri.host.len);
00186     uri.len+=puri.host.len;
00187 
00188     /* 3. Check if the asserted identity is in the same group with the ReqURI */
00189     asserted_id = cscf_get_asserted_identity(msg);
00190     if (!asserted_id.len){
00191         LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: P-Asserted-Identity empty.\n");
00192         ret =  CSCF_RETURN_FALSE;
00193         goto done;      
00194     }
00195     LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: P-Asserted-Identity <%.*s>.\n",
00196         asserted_id.len,asserted_id.s);
00197     
00198     p = get_r_public(uri);
00199     
00200     if (!p){
00201         LOG(L_ERR,"ERR:"M_NAME":S_can_subscribe: Identity not found <%.*s>\n",
00202             uri.len,uri.s);
00203         ret =  CSCF_RETURN_FALSE;
00204         goto done;
00205     }
00206     if (p->aor.len == asserted_id.len &&
00207         strncasecmp(p->aor.s,asserted_id.s,asserted_id.len)==0)
00208     {
00209         LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: Identity found as AOR <%.*s>\n",
00210             uri.len,uri.s);
00211         ret = CSCF_RETURN_TRUE;
00212         goto done;
00213     }
00214     if (p->s){
00215         for(i=0;i<p->s->service_profiles_cnt;i++)
00216             for(j=0;j<p->s->service_profiles[i].public_identities_cnt;j++)
00217             {
00218                 pi = &(p->s->service_profiles[i].public_identities[j]);
00219                 if (!pi->barring &&
00220                     pi->public_identity.len == asserted_id.len &&
00221                     strncasecmp(pi->public_identity.s,asserted_id.s,asserted_id.len)==0)
00222                 {
00223                     LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: Identity found in SP[%d][%d]\n",
00224                         i,j);
00225                     ret = CSCF_RETURN_TRUE;
00226                     goto done;
00227                 }   
00228             }
00229     }
00230     
00231     /* 4. Check if it present in any of the Path headers */
00232     c=p->head;
00233 
00234     while(c){
00235         if (c->path.len){
00236             for(i=0;i<c->path.len-asserted_id.len;i++)
00237                 if (strncasecmp(c->path.s+i,asserted_id.s,asserted_id.len)==0){
00238                     LOG(L_DBG,"DBG:"M_NAME":S_can_subscribe: Identity found in Path <%.*s>\n",
00239                         c->path.len,c->path.s);
00240                     ret = CSCF_RETURN_TRUE;
00241                     goto done;
00242                 }
00243         }
00244         c = c->next;
00245     }
00246     
00247     
00248 done:
00249     if (p) r_unlock(p->hash);
00250     if (uri.s) pkg_free(uri.s);
00251     return ret;
00252 error:
00253     if (p) r_unlock(p->hash);
00254     if (uri.s) pkg_free(uri.s);
00255     ret=CSCF_RETURN_ERROR;
00256     return ret; 
00257 }
00258 
00259 
00267 int S_subscribe(struct sip_msg *msg,char *str1,char *str2)
00268 {
00269     int ret=CSCF_RETURN_FALSE;
00270     struct sip_uri puri;
00271     str uri={0,0};
00272     str event;
00273     int event_i=IMS_EVENT_NONE;
00274     int expires=0,expires_time=0;
00275     str subscriber;
00276     r_public *p=0;
00277     r_subscriber *s=0,*new_s=0;
00278     dlg_t *dialog=0;
00279 
00280     LOG(L_DBG,"DBG:"M_NAME":S_subscribe: Saving SUBSCRIBE\n");
00281 
00282     /* First check the parameters */
00283     if (msg->first_line.type!=SIP_REQUEST)
00284     {
00285         LOG(L_ERR,"ERR:"M_NAME":S_subscribe: This message is not a request\n");
00286         goto error;
00287     }       
00288     if (msg->first_line.u.request.method.len != 9 ||
00289         memcmp(msg->first_line.u.request.method.s,"SUBSCRIBE",9)!=0)
00290     {
00291         LOG(L_ERR,"ERR:"M_NAME":S_subscribe: This message is not a SUBSCRIBE\n");
00292         goto error;
00293     }
00294 
00295     /* 1. Get the event     */
00296     event = cscf_get_event(msg);
00297     if (event.len!=3||strncasecmp(event.s,"reg",3)!=0){
00298         LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Accepting only <Event: reg>. Found: <%.*s>\n",
00299             event.len,event.s);
00300         ret = CSCF_RETURN_FALSE;    
00301         goto done;
00302     } 
00303     if (event.len==0 && strncasecmp(event.s,"reg",3)==0)
00304         event_i = IMS_EVENT_REG;
00305     
00306     /* 2. Get the target of the SUBSCRIBE from RequestURI */
00307     if (msg->new_uri.s) uri = msg->new_uri;
00308     else uri = msg->first_line.u.request.uri;
00309     
00310     if (parse_uri(uri.s, uri.len, &puri) < 0) {
00311         LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Error parsing uri <%.*s>\n",
00312             uri.len,uri.s);
00313         goto error;
00314     }
00315     uri.len = lookup_sip.len+puri.user.len+1+puri.host.len;
00316     uri.s = pkg_malloc(uri.len);
00317     if (!uri.s){
00318         LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Error allocating %d bytes\n",uri.len);
00319         goto error;
00320     }
00321     uri.len=0;
00322     memcpy(uri.s,lookup_sip.s,lookup_sip.len);
00323     uri.len+=lookup_sip.len;
00324     memcpy(uri.s+uri.len,puri.user.s,puri.user.len);
00325     uri.len+=puri.user.len;
00326     uri.s[uri.len++]='@';
00327     memcpy(uri.s+uri.len,puri.host.s,puri.host.len);
00328     uri.len+=puri.host.len;
00329 
00330     /* 3. Get the Subscriber's Identity */
00331     subscriber = cscf_get_contact(msg);
00332     if (!subscriber.len){
00333         LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Contact empty.\n");
00334         ret =  CSCF_RETURN_FALSE;
00335         goto done;      
00336     }
00337     LOG(L_DBG,"DBG:"M_NAME":S_subscribe: Contact <%.*s>.\n",
00338         subscriber.len,subscriber.s);
00339     
00340     p = get_r_public(uri);
00341 
00342     /* Registration is possible even if the user is not registered... so just create one */
00343     if (!p){
00344         p = add_r_public(uri,0,0);
00345     }
00346     if (!p){        
00347         LOG(L_ERR,"ERR:"M_NAME":S_subscribe: Identity not found and error on creation <%.*s>\n",
00348             uri.len,uri.s);
00349         ret =  CSCF_RETURN_FALSE;
00350         goto done;
00351     }
00352         
00353     expires = cscf_get_expires_hdr(msg);
00354     if (expires == -1) expires = subscription_default_expires;
00355     if (expires > 0) {
00356         if (expires < subscription_min_expires) expires = subscription_min_expires;
00357         if (expires > subscription_max_expires) expires = subscription_max_expires;
00358         r_act_time();
00359         expires_time = expires + time_now;
00360         
00361         /* get the old subscriber - if any */
00362         s = get_r_subscriber(p,subscriber,event_i); 
00363         if (!s){
00364             /* create a new dialog */
00365             if (tmb.new_dlg_uas(msg, 200, &dialog) < 0) {       
00366                 LOG(L_ERR,"ERR:"M_NAME":S_subscribe:  Error while creating dialog state\n");
00367                 ret = CSCF_RETURN_FALSE;
00368                 goto error;
00369             }
00370         }else
00371             dialog = s->dialog;
00372         
00373         /* update the subscriber */
00374         if ((new_s=update_r_subscriber(p,subscriber,event_i,&expires_time,dialog))!=0){     
00375             //if (!s)   /* Only on first subscription, not on refreshes, send a notify */
00376                 S_event_reg(p,0,new_s,IMS_REGISTRAR_SUBSCRIBE,0);
00377             ret = CSCF_RETURN_TRUE;
00378         }
00379         else
00380             ret = CSCF_RETURN_FALSE;    
00381     }else{
00382         /* Unsubscribe */
00383         /* get the old subscriber - if any */
00384         r_act_time();
00385         s = get_r_subscriber(p,subscriber,event_i); 
00386         if (s) {
00387             s->expires = time_now;
00388             S_event_reg(p,0,s,IMS_REGISTRAR_UNSUBSCRIBE,1);
00389             del_r_subscriber(p,s);
00390         }
00391         ret = CSCF_RETURN_TRUE;
00392     }
00393 done:   
00394     r_unlock(p->hash);
00395     if (expires ==0 )S_SUBSCRIBE_reply(msg,200,MSG_REG_UNSUBSCRIBE_OK,&expires,&uri);
00396     else S_SUBSCRIBE_reply(msg,200,MSG_REG_SUBSCRIBE_OK,&expires,&uri);
00397     if (uri.s) pkg_free(uri.s);
00398     return ret;
00399 error:
00400     if (p) r_unlock(p->hash);
00401     if (uri.s) pkg_free(uri.s);
00402     ret=CSCF_RETURN_FALSE;
00403     return ret; 
00404 }
00405 
00406 
00407 
00408 str expires_hdr1={"Expires: ",9};
00409 str expires_hdr2={"\r\n",2};
00410 str contact_hdr1={"Contact: <",10};
00411 str contact_hdr2={">\r\n",3};
00422 int S_SUBSCRIBE_reply(struct sip_msg *msg, int code,  char *text,int *expires,str *contact)
00423 {
00424     str hdr={0,0};
00425     tmb.t_newtran(msg);
00426     
00427     if (expires){
00428         hdr.len = expires_hdr1.len+12+expires_hdr1.len;
00429         hdr.s = pkg_malloc(hdr.len);
00430         if (!hdr.s){
00431             LOG(L_ERR,"ERR:"M_NAME":S_SUBSCRIBE_reply: Error allocating %d bytes.\n",
00432                 hdr.len);           
00433         }else{
00434             hdr.len=0;
00435             STR_APPEND(hdr,expires_hdr1);
00436             sprintf(hdr.s+hdr.len,"%d",*expires);
00437             hdr.len += strlen(hdr.s+hdr.len);
00438             STR_APPEND(hdr,expires_hdr2);
00439             cscf_add_header_rpl(msg,&hdr);      
00440             pkg_free(hdr.s);
00441         }
00442     }
00443 
00444     if (contact){
00445         hdr.len = contact_hdr1.len+contact->len+contact_hdr2.len;
00446         hdr.s = pkg_malloc(hdr.len);
00447         if (!hdr.s){
00448             LOG(L_ERR,"ERR:"M_NAME":S_SUBSCRIBE_reply: Error allocating %d bytes.\n",
00449                 hdr.len);           
00450         }else{
00451             hdr.len=0;
00452             STR_APPEND(hdr,contact_hdr1);
00453             STR_APPEND(hdr,*contact);
00454             STR_APPEND(hdr,contact_hdr2);
00455             cscf_add_header_rpl(msg,&hdr);      
00456             pkg_free(hdr.s);
00457         }
00458     }
00459     
00460     return tmb.t_reply(msg,code,text);
00461 }
00462 
00463 
00464 
00465 
00466 static str ruri_lr={";lr",3};
00467 static str subs_terminated={"terminated",10};
00468 static str subs_active={"active;expires=",15};
00477 static void r_create_notifications(void *pv,void *cv,void *ps,str content,long expires)
00478 {
00479     r_notification *n;
00480     r_public *p=(r_public*)pv;
00481 //  r_contact *c;
00482     r_subscriber *for_s=(r_subscriber*)ps;
00483     r_subscriber *s;    
00484     str uri={0,0},req_uri={0,0},subscription_state={"active;expires=10000000000",26},
00485         event={0,0},content_type={"application/reginfo+xml",23};
00486         
00487     uri = p->aor;
00488     if (!for_s) s = p->shead;
00489     else s = for_s;
00490     
00491     while(s){
00492         req_uri.len = s->subscriber.len+ruri_lr.len;
00493         req_uri.s = pkg_malloc(req_uri.len);
00494         if (!req_uri.s) {
00495             LOG(L_ERR,"ERR:"M_NAME":r_create_notifications: Error allocating %d bytes.\n",req_uri.len);
00496             return;         
00497         }
00498         memcpy(req_uri.s,s->subscriber.s,s->subscriber.len);
00499         memcpy(req_uri.s+s->subscriber.len,ruri_lr.s,ruri_lr.len);
00500         //route = s->path;
00501         if (s->expires>time_now) {
00502             subscription_state.s = pkg_malloc(32);
00503             subscription_state.len=0;
00504             if (subscription_state.s){
00505                 sprintf(subscription_state.s,"%.*s%ld",subs_active.len,subs_active.s,expires);
00506                 subscription_state.len=strlen(subscription_state.s);
00507             }                   
00508         }else {                 
00509             STR_PKG_DUP(subscription_state,subs_terminated,"pkg subs state");
00510         }
00511         n = new_r_notification(req_uri,uri,subscription_state,event,
00512             content_type,content,s->dialog,s->version++);                       
00513         if (req_uri.s) pkg_free(req_uri.s);
00514         if (subscription_state.s) pkg_free(subscription_state.s);   
00515         if (n) {
00516             #ifdef WITH_IMS_PM
00517                 n->is_scscf_dereg=(expires==0);
00518             #endif 
00519             add_r_notification(n);
00520         }       
00521         
00522         if (!for_s) s = s->next;                
00523         else s = 0;
00524     }
00525     return;
00526 out_of_memory:
00527     if (req_uri.s) pkg_free(req_uri.s);
00528     return; 
00529 }
00530 
00532 #define MAX_REGINFO_SIZE 16384
00533 
00534 
00535 
00542 static inline long r_update_subscription_status(r_public *p)
00543 {
00544     r_subscriber *s;
00545     r_contact *c;
00546     long expires=0;
00547     int cnt=0;
00548     
00549     r_act_time();
00550     
00551     c = p->head;
00552     while(c){
00553         if (r_valid_contact(c)){
00554             if (c->expires-time_now+30>expires)
00555                 expires = c->expires-time_now+30;
00556             cnt++;
00557         }
00558         c = c->next;
00559     }       
00560     if (!cnt){
00561         s = p->shead;
00562         while(s){
00563             s->expires = time_now-1;
00564             s = s->next;
00565         }   
00566     }
00567     return expires;
00568 }
00569 
00570 static str xml_start={"<?xml version=\"1.0\"?>\n",22};
00571 
00572 static str r_full={"full",4};
00573 static str r_partial={"partial",7};
00574 static str r_reginfo_s={"<reginfo xmlns=\"urn:ietf:params:xml:ns:reginfo\" version=\"%s\" state=\"%.*s\">\n",74};
00575 static str r_reginfo_e={"</reginfo>\n",11};
00576 
00577 //static str r_init={"init",4};
00578 static str r_active={"active",6};
00579 static str r_terminated={"terminated",10};
00580 static str registration_s={"\t<registration aor=\"%.*s\" id=\"%p\" state=\"%.*s\">\n",48};
00581 static str registration_e={"\t</registration>\n",17};
00582 
00583 static str r_registered={"registered",10};
00584 static str r_created={"created",7};
00585 static str r_refreshed={"refreshed",9};
00586 static str r_shortened={"shortened",9};
00587 static str r_expired={"expired",7};
00588 static str r_deactivated={"deactivated",11};
00589 static str r_probation={"probation",9};
00590 static str r_unregistered={"unregistered",12};
00591 static str r_rejected={"rejected",8};
00592 static str contact_s={"\t\t<contact id=\"%p\" state=\"%.*s\" event=\"%.*s\" expires=\"%d\">\n",59};
00593 static str contact_s_q={"\t\t<contact id=\"%p\" state=\"%.*s\" event=\"%.*s\" expires=\"%d\" q=\"%.3f\">\n",69};
00594 static str contact_e={"\t\t</contact>\n",13};
00595 
00596 static str uri_s={"\t\t\t<uri>",8};
00597 static str uri_e={"</uri>\n",7};
00605 str r_get_reginfo_full(void *pv,int event_type,long *subsExpires)
00606 {       
00607     str x={0,0};
00608     str buf,pad;    
00609     char bufc[MAX_REGINFO_SIZE],padc[MAX_REGINFO_SIZE];
00610 
00611     r_public *p=(r_public*)pv,*p2;
00612     r_contact *c;
00613     ims_public_identity *pi;
00614     int i,j;
00615     unsigned int hash;
00616     
00617     buf.s = bufc;
00618     buf.len=0;
00619     pad.s = padc;
00620     pad.len=0;
00621     
00622     *subsExpires = r_update_subscription_status(p);
00623     
00624     STR_APPEND(buf,xml_start);
00625     sprintf(pad.s,r_reginfo_s.s,"%d",r_full.len,r_full.s);
00626     pad.len = strlen(pad.s);
00627     STR_APPEND(buf,pad);
00628     
00629     
00630     if (p->s){
00631         for(i=0;i<p->s->service_profiles_cnt;i++)
00632             for(j=0;j<p->s->service_profiles[i].public_identities_cnt;j++){
00633                 pi = &(p->s->service_profiles[i].public_identities[j]);
00634                 if (!pi->barring){
00635                     hash = get_aor_hash(pi->public_identity,r_hash_size);
00636                     if (hash == p->hash) /* because we already have the lock on p->hash */
00637                         p2 = get_r_public_nolock(pi->public_identity);
00638                     else 
00639                         p2 = get_r_public(pi->public_identity);
00640                     if (p2){
00641                         if (p2->reg_state==REGISTERED)
00642                             sprintf(pad.s,registration_s.s,p2->aor.len,p2->aor.s,p2,r_active.len,r_active.s);
00643                         else 
00644                             sprintf(pad.s,registration_s.s,p2->aor.len,p2->aor.s,p2,r_terminated.len,r_terminated.s);
00645                         pad.len = strlen(pad.s);
00646                         STR_APPEND(buf,pad);
00647                         c = p2->head;
00648                         while(c){
00649                             if(c->qvalue != -1) {
00650                                 float q = (float)c->qvalue/1000;
00651                                 sprintf(pad.s,contact_s_q.s,c,r_active.len,r_active.s,r_registered.len,r_registered.s,c->expires-time_now, q);
00652                             }
00653                             else
00654                                 sprintf(pad.s,contact_s.s,c,r_active.len,r_active.s,r_registered.len,r_registered.s,c->expires-time_now);
00655                             pad.len = strlen(pad.s);
00656                             STR_APPEND(buf,pad);                            
00657                             STR_APPEND(buf,uri_s);
00658                             STR_APPEND(buf,c->uri);
00659                             STR_APPEND(buf,uri_e);
00660                             STR_APPEND(buf,contact_e);
00661                             c = c->next;
00662                         }
00663                         STR_APPEND(buf,registration_e);
00664                         if (p2->hash != p->hash) r_unlock(p2->hash);
00665                     }
00666                 }
00667             }               
00668     }
00669 
00670     STR_APPEND(buf,r_reginfo_e);
00671 
00672     
00673     x.s = pkg_malloc(buf.len+1);
00674     if (x.s){
00675         x.len = buf.len;
00676         memcpy(x.s,buf.s,buf.len);
00677         x.s[x.len]=0;
00678     }
00679     return x;
00680 }
00681 
00682 
00691 str r_get_reginfo_partial( void *pv,void *pc,int event_type,long *subsExpires)
00692 {       
00693     str x={0,0};
00694     str buf,pad;    
00695     char bufc[MAX_REGINFO_SIZE],padc[MAX_REGINFO_SIZE];
00696     int expires=-1;
00697 
00698     r_public *p=(r_public*)pv;
00699     r_contact *c=(r_contact*)pc;
00700     str state,event;
00701     
00702     buf.s = bufc;
00703     buf.len=0;
00704     pad.s = padc;
00705     pad.len=0;
00706 
00707     *subsExpires = r_update_subscription_status(p);
00708     
00709     STR_APPEND(buf,xml_start);
00710     sprintf(pad.s,r_reginfo_s.s,"%d",r_partial.len,r_partial.s);
00711     pad.len = strlen(pad.s);
00712     STR_APPEND(buf,pad);
00713     
00714     
00715     if (p){
00716         expires = c->expires-time_now;
00717         if (p->head == c && p->tail == c && 
00718             (event_type==IMS_REGISTRAR_CONTACT_EXPIRED ||
00719              event_type==IMS_REGISTRAR_CONTACT_DEACTIVATED||
00720              event_type==IMS_REGISTRAR_CONTACT_UNREGISTERED||
00721              event_type==IMS_REGISTRAR_CONTACT_REJECTED)
00722            )
00723             sprintf(pad.s,registration_s.s,p->aor.len,p->aor.s,p,r_terminated.len,r_terminated.s);
00724         else 
00725             sprintf(pad.s,registration_s.s,p->aor.len,p->aor.s,p,r_active.len,r_active.s);
00726         pad.len = strlen(pad.s);
00727         STR_APPEND(buf,pad);
00728         if (c){
00729             switch(event_type){
00730                 case IMS_REGISTRAR_CONTACT_REGISTERED:
00731                     state = r_active;
00732                     event = r_registered;
00733                     break;
00734                 case IMS_REGISTRAR_CONTACT_CREATED:
00735                     state = r_active;
00736                     event = r_created;
00737                     break;
00738                 case IMS_REGISTRAR_CONTACT_REFRESHED:
00739                     state = r_active;
00740                     event = r_refreshed;
00741                     break;
00742                 case IMS_REGISTRAR_CONTACT_SHORTENED:
00743                     state = r_active;
00744                     event = r_shortened;
00745                     break;
00746                 case IMS_REGISTRAR_CONTACT_EXPIRED:
00747                     state = r_terminated;
00748                     event = r_expired;
00749                     expires = 0;
00750                     break;
00751                 case IMS_REGISTRAR_CONTACT_DEACTIVATED:
00752                     state = r_terminated;
00753                     event = r_deactivated;
00754                     break;
00755                 case IMS_REGISTRAR_CONTACT_PROBATION:
00756                     state = r_terminated;
00757                     event = r_probation;
00758                     break;
00759                 case IMS_REGISTRAR_CONTACT_UNREGISTERED:
00760                     state = r_terminated;
00761                     event = r_unregistered;
00762                     expires = 0;
00763                     break;
00764                 case IMS_REGISTRAR_CONTACT_REJECTED:            
00765                     state = r_terminated;
00766                     event = r_rejected;
00767                     break;              
00768                 default:
00769                     state = r_active;
00770                     event = r_registered;
00771             }
00772             if(c->qvalue != -1) {
00773                             float q = (float)c->qvalue/1000;
00774                                 sprintf(pad.s,contact_s_q.s,c,r_active.len,r_active.s,r_registered.len,r_registered.s,c->expires-time_now, q);
00775                         }
00776             else
00777                 sprintf(pad.s,contact_s.s,c,state.len,state.s,event.len,event.s,expires);
00778             pad.len = strlen(pad.s);
00779             STR_APPEND(buf,pad);                            
00780             STR_APPEND(buf,uri_s);
00781             STR_APPEND(buf,c->uri);
00782             STR_APPEND(buf,uri_e);
00783             STR_APPEND(buf,contact_e);
00784             STR_APPEND(buf,registration_e);
00785         }
00786     }
00787 
00788     STR_APPEND(buf,r_reginfo_e);
00789 
00790     
00791     x.s = pkg_malloc(buf.len+1);
00792     if (x.s){
00793         x.len = buf.len;
00794         memcpy(x.s,buf.s,buf.len);
00795         x.s[x.len]=0;       
00796     }
00797     return x;
00798 }
00799 
00810 int S_event_reg(void *pv,void *c,void *ps,int event_type,int send_now)
00811 {
00812     r_public *p=(r_public*)pv;
00813     r_subscriber *s=(r_subscriber*)ps;
00814     str content={0,0};
00815     long subsExpires=-1;
00816 
00817     r_act_time();
00818     switch (event_type){
00819         case IMS_REGISTRAR_NONE:
00820             if (send_now) notification_timer(0,0);
00821             return 0;
00822             break;
00823         case IMS_REGISTRAR_SUBSCRIBE:
00824             content = r_get_reginfo_full(p,event_type,&subsExpires);
00825             r_create_notifications(p,0,s,content,subsExpires);          
00826             if (content.s) pkg_free(content.s);
00827             if (send_now) notification_timer(0,0);
00828             return 1;
00829             break;
00830         case IMS_REGISTRAR_UNSUBSCRIBE:
00831             subsExpires=0;
00832             r_create_notifications(p,0,s,content,subsExpires);          
00833             if (content.s) pkg_free(content.s);
00834             if (send_now) notification_timer(0,0);
00835             return 1;
00836             break;
00837             
00838         case IMS_REGISTRAR_CONTACT_REGISTERED:
00839         case IMS_REGISTRAR_CONTACT_CREATED: 
00840         case IMS_REGISTRAR_CONTACT_REFRESHED:
00841         case IMS_REGISTRAR_CONTACT_SHORTENED:
00842         case IMS_REGISTRAR_CONTACT_EXPIRED:
00843         case IMS_REGISTRAR_CONTACT_DEACTIVATED:
00844         case IMS_REGISTRAR_CONTACT_PROBATION:
00845         case IMS_REGISTRAR_CONTACT_UNREGISTERED:
00846         case IMS_REGISTRAR_CONTACT_REJECTED:
00847             content = r_get_reginfo_partial(p,c,event_type,&subsExpires);   
00848             r_create_notifications(p,c,s,content,subsExpires);
00849             if (content.s) pkg_free(content.s);
00850             if (send_now) notification_timer(0,0);
00851             return 1;
00852             break;
00853                 
00854         default:
00855             LOG(L_ERR,"ERR:"M_NAME":S_event_reg: Unknown event %d\n",event_type);
00856             if (send_now) notification_timer(0,0);
00857             return 0;   
00858     }       
00859 }
00860 
00861 
00862 static str method={"NOTIFY",6};
00863 static str event_hdr ={"Event: reg\r\n",12};
00864 static str maxfwds_hdr ={"Max-Forwards: 70\r\n",18};
00865 static str subss_hdr1={"Subscription-State: ",20};
00866 static str subss_hdr2={"\r\n",2};
00867 static str ctype_hdr1={"Content-Type: ",14};
00868 static str ctype_hdr2={"\r\n",2};
00869 
00870 #ifdef WITH_IMS_PM
00871     static str zero={0,0};
00872 #endif
00873 
00876 void uac_request_cb(struct cell *t,int type,struct tmcb_params *ps)
00877 {
00878     LOG(L_DBG,"DBG:"M_NAME":uac_request_cb: Type %d\n",type);
00879     #ifdef WITH_IMS_PM          
00880         if (((int) *ps->param) && (ps->rpl != (void*)-1) ){
00881             if (ps->code>=200 && ps->code<300) IMS_PM_LOG12(UR_SuccDeRegCscf,cscf_get_call_id(ps->rpl,0),cscf_get_cseq(ps->rpl,0),ps->code);
00882             else if (ps->code>=300) IMS_PM_LOG12(UR_FailDeRegCscf,cscf_get_call_id(ps->rpl,0),cscf_get_cseq(ps->rpl,0),ps->code);           
00883         }       
00884     #endif
00885 }
00886 
00891 void send_notification(r_notification *n)
00892 {
00893     str h={0,0};
00894     int k=0;
00895 
00896     LOG(L_DBG,"DBG:"M_NAME":send_notification: NOTIFY about <%.*s>\n",n->uri.len,n->uri.s);
00897     
00898     //tmb.print_dlg(stdout,n->dialog);
00899     
00900     h.len = 0;
00901     h.len += contact_hdr1.len + n->uri.len + contact_hdr2.len ;
00902     if (n->subscription_state.len) h.len += subss_hdr1.len + subss_hdr2.len + n->subscription_state.len;
00903     h.len+=event_hdr.len;
00904     h.len+=maxfwds_hdr.len;
00905     if (n->content_type.len) h.len += ctype_hdr1.len + ctype_hdr2.len + n->content_type.len;
00906     h.s = pkg_malloc(h.len);
00907     if (!h.s){
00908         LOG(L_ERR,"ERR:"M_NAME":send_notification: Error allocating %d bytes\n",h.len);
00909         h.len = 0;
00910     }
00911 
00912     h.len = 0;
00913     STR_APPEND(h,contact_hdr1);
00914     STR_APPEND(h,n->uri);
00915     STR_APPEND(h,contact_hdr2);
00916 
00917     STR_APPEND(h,event_hdr);
00918     STR_APPEND(h,maxfwds_hdr);
00919     if (n->subscription_state.len) {
00920         STR_APPEND(h,subss_hdr1);
00921         STR_APPEND(h,n->subscription_state);
00922         STR_APPEND(h,subss_hdr2);
00923     }
00924     if (n->content_type.len) {
00925         STR_APPEND(h,ctype_hdr1);
00926         STR_APPEND(h,n->content_type);
00927         STR_APPEND(h,ctype_hdr2);
00928     }
00929     
00930     //LOG(L_CRIT,"DLG:%p\n",n->dialog);
00931     #ifdef WITH_IMS_PM
00932         k = n->is_scscf_dereg;
00933     #endif 
00934     if (n->content.len) 
00935         tmb.t_request_within(&method, &h, &(n->content), n->dialog, uac_request_cb, (void*)k);      
00936     else 
00937         tmb.t_request_within(&method, &h, 0, n->dialog, uac_request_cb, (void*)k);      
00938     if (h.s) pkg_free(h.s);
00939     
00940     #ifdef WITH_IMS_PM
00941         if (n->is_scscf_dereg) IMS_PM_LOG11(UR_AttDeRegCscf,n->dialog->id.call_id,n->dialog->loc_seq.value);
00942     #endif 
00943 }
00944 
00945 
00946 
00947 
00954 void notification_timer(unsigned int ticks, void* param)
00955 {
00956     r_notification *n;
00957     lock_get(notification_list->lock);
00958     while(notification_list->head){
00959         n = notification_list->head;
00960         notification_list->head = n->next;
00961         if (n->next) n->next->prev=0;
00962         else notification_list->tail=n->next;
00963         lock_release(notification_list->lock);          
00964         
00965         send_notification(n);
00966         free_r_notification(n);
00967         lock_get(notification_list->lock);
00968     }   
00969     lock_release(notification_list->lock);              
00970 }
00971 
00972 
00973 
00985 r_notification* new_r_notification(str req_uri,str uri,str subscription_state,str event,
00986                     str content_type,str content,dlg_t *dialog,int version)
00987 {
00988     r_notification *n=0;
00989     str buf;    
00990     char bufc[MAX_REGINFO_SIZE];
00991     
00992     n = shm_malloc(sizeof(r_notification));
00993     if (!n){
00994         LOG(L_ERR,"ERR:"M_NAME":new_r_notification: Error allocating %d bytes\n",
00995             sizeof(r_notification));
00996         goto error;
00997     }
00998     memset(n,0,sizeof(r_notification));
00999     
01000     STR_SHM_DUP(n->req_uri,req_uri,"new_r_notification");
01001     
01002     STR_SHM_DUP(n->uri,uri,"new_r_notification");
01003     
01004     STR_SHM_DUP(n->subscription_state,subscription_state,"new_r_notification");
01005     
01006     STR_SHM_DUP(n->event,event,"new_r_notification");
01007     
01008     STR_SHM_DUP(n->content_type,content_type,"new_r_notification");
01009     
01010     sprintf(bufc,content.s,version);
01011     buf.s = bufc;
01012     buf.len = strlen(bufc);
01013     STR_SHM_DUP(n->content,buf,"new_r_notification");
01014     
01015     n->dialog = dialog;
01016     
01017