pupnp (libupnp) snapshot from SourceForge: git clone git://pupnp.git.sourceforge...
[igd2-for-linux:pandonghui1211s-igd2-for-linux.git] / pupnp_branch-1.6.x / upnp / src / genlib / service_table / service_table.c
1 /*******************************************************************************
2  *
3  * Copyright (c) 2000-2003 Intel Corporation 
4  * All rights reserved. 
5  *
6  * Redistribution and use in source and binary forms, with or without 
7  * modification, are permitted provided that the following conditions are met: 
8  *
9  * - Redistributions of source code must retain the above copyright notice, 
10  * this list of conditions and the following disclaimer. 
11  * - Redistributions in binary form must reproduce the above copyright notice, 
12  * this list of conditions and the following disclaimer in the documentation 
13  * and/or other materials provided with the distribution. 
14  * - Neither name of Intel Corporation nor the names of its contributors 
15  * may be used to endorse or promote products derived from this software 
16  * without specific prior written permission.
17  * 
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR 
22  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
23  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
24  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
25  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 
26  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  *
30  ******************************************************************************/
31
32
33 /************************************************************************
34 * Purpose: This file defines the functions for services. It defines 
35 * functions for adding and removing services to and from the service table, 
36 * adding and accessing subscription and other attributes pertaining to the 
37 * service 
38 ************************************************************************/
39
40 #include "config.h"
41 #include "service_table.h"
42
43 #ifdef INCLUDE_DEVICE_APIS
44
45 /************************************************************************
46 *       Function :      copy_subscription
47 *
48 *       Parameters :
49 *               subscription *in ;      Source subscription
50 *               subscription *out ;     Destination subscription
51 *
52 *       Description :   Makes a copy of the subscription
53 *
54 *       Return : int ;
55 *               HTTP_SUCCESS - On Sucess
56 *
57 *       Note :
58 ************************************************************************/
59 int
60 copy_subscription( subscription * in,
61                    subscription * out )
62 {
63     int return_code = HTTP_SUCCESS;
64
65     memcpy( out->sid, in->sid, SID_SIZE );
66     out->sid[SID_SIZE] = 0;
67     out->eventKey = in->eventKey;
68     out->ToSendEventKey = in->ToSendEventKey;
69     out->expireTime = in->expireTime;
70     out->active = in->active;
71     if( ( return_code =
72           copy_URL_list( &in->DeliveryURLs, &out->DeliveryURLs ) )
73         != HTTP_SUCCESS )
74         return return_code;
75     out->next = NULL;
76     return HTTP_SUCCESS;
77 }
78
79 /************************************************************************
80 *       Function :      RemoveSubscriptionSID
81 *
82 *       Parameters :
83 *               Upnp_SID sid ;  subscription ID
84 *               service_info * service ;        service object providing the list of
85 *                                               subscriptions
86 *
87 *       Description :   Remove the subscription represented by the
88 *               const Upnp_SID sid parameter from the service table and update 
89 *               the service table.
90 *
91 *       Return : void ;
92 *
93 *       Note :
94 ************************************************************************/
95 void
96 RemoveSubscriptionSID( Upnp_SID sid,
97                        service_info * service )
98 {
99     subscription *finger = service->subscriptionList;
100     subscription *previous = NULL;
101
102     while( finger ) {
103         if( !( strcmp( sid, finger->sid ) ) ) {
104             if( previous )
105                 previous->next = finger->next;
106             else
107                 service->subscriptionList = finger->next;
108             finger->next = NULL;
109             freeSubscriptionList( finger );
110             finger = NULL;
111             service->TotalSubscriptions--;
112         } else {
113             previous = finger;
114             finger = finger->next;
115         }
116     }
117
118 }
119
120
121 subscription *GetSubscriptionSID(const Upnp_SID sid, service_info *service)
122 {
123     subscription *next = service->subscriptionList;
124     subscription *previous = NULL;
125     subscription *found = NULL;
126
127     time_t current_time;
128
129     while( ( next ) && ( found == NULL ) ) {
130         if( !strcmp( next->sid, sid ) )
131             found = next;
132         else {
133             previous = next;
134             next = next->next;
135         }
136     }
137     if( found ) {
138         //get the current_time
139         time( &current_time );
140         if( ( found->expireTime != 0 )
141             && ( found->expireTime < current_time ) ) {
142             if( previous )
143                 previous->next = found->next;
144             else
145                 service->subscriptionList = found->next;
146             found->next = NULL;
147             freeSubscriptionList( found );
148             found = NULL;
149             service->TotalSubscriptions--;
150         }
151     }
152     return found;
153
154 }
155
156 /************************************************************************
157 *       Function :      GetNextSubscription
158 *
159 *       Parameters :
160 *               service_info * service ; service object providing the list of
161 *                                               subscriptions
162 *               subscription *current ; current subscription object
163 *
164 *       Description :   Get current and valid subscription from the service 
165 *               table.
166 *
167 *       Return : subscription * - Pointer to the next subscription node;
168 *
169 *       Note :
170 ************************************************************************/
171 subscription *
172 GetNextSubscription( service_info * service,
173                      subscription * current )
174 {
175     time_t current_time;
176     subscription *next = NULL;
177     subscription *previous = NULL;
178     int notDone = 1;
179
180     //get the current_time
181     time( &current_time );
182     while( ( notDone ) && ( current ) ) {
183         previous = current;
184         current = current->next;
185
186         if( current == NULL ) {
187             notDone = 0;
188             next = current;
189         } else
190             if( ( current->expireTime != 0 )
191                 && ( current->expireTime < current_time ) ) {
192             previous->next = current->next;
193             current->next = NULL;
194             freeSubscriptionList( current );
195             current = previous;
196             service->TotalSubscriptions--;
197         } else if( current->active ) {
198             notDone = 0;
199             next = current;
200         }
201     }
202     return next;
203 }
204
205 /************************************************************************
206 *       Function :      GetFirstSubscription
207 *
208 *       Parameters :
209 *               service_info *service ; service object providing the list of
210 *                                               subscriptions
211 *
212 *       Description :   Gets pointer to the first subscription node in the 
213 *               service table.
214 *
215 *       Return : subscription * - pointer to the first subscription node ;
216 *
217 *       Note :
218 ************************************************************************/
219 subscription *
220 GetFirstSubscription( service_info * service )
221 {
222     subscription temp;
223     subscription *next = NULL;
224
225     temp.next = service->subscriptionList;
226     next = GetNextSubscription( service, &temp );
227     service->subscriptionList = temp.next;
228     //  service->subscriptionList=next;
229     return next;
230 }
231
232 /************************************************************************
233 *       Function :      freeSubscription
234 *
235 *       Parameters :
236 *               subscription * sub ;    subscription to be freed
237 *
238 *       Description :   Free's the memory allocated for storing the URL of 
239 *               the subscription.
240 *
241 *       Return : void ;
242 *
243 *       Note :
244 ************************************************************************/
245 void
246 freeSubscription( subscription * sub )
247 {
248     if( sub ) {
249         free_URL_list( &sub->DeliveryURLs );
250     }
251 }
252
253 /************************************************************************
254 *       Function :      freeSubscriptionList
255 *
256 *       Parameters :
257 *               subscription * head ;   head of the subscription list
258 *
259 *       Description :   Free's memory allocated for all the subscriptions 
260 *               in the service table. 
261 *
262 *       Return : void ;
263 *
264 *       Note :
265 ************************************************************************/
266 void
267 freeSubscriptionList( subscription * head )
268 {
269     subscription *next = NULL;
270
271     while( head ) {
272         next = head->next;
273         freeSubscription( head );
274         free( head );
275         head = next;
276     }
277 }
278
279 /************************************************************************
280 *       Function :      FindServiceId
281 *
282 *       Parameters :
283 *               service_table *table ;  service table
284 *               const char * serviceId ;string representing the service id 
285 *                                                               to be found among those in the table    
286 *               const char * UDN ;              string representing the UDN 
287 *                                                               to be found among those in the table    
288 *
289 *       Description :   Traverses through the service table and returns a 
290 *               pointer to the service node that matches a known service  id 
291 *               and a known UDN
292 *
293 *       Return : service_info * - pointer to the matching service_info node;
294 *
295 *       Note :
296 ************************************************************************/
297 service_info *
298 FindServiceId( service_table * table,
299                const char *serviceId,
300                const char *UDN )
301 {
302     service_info *finger = NULL;
303
304     if( table ) {
305         finger = table->serviceList;
306         while( finger ) {
307             if( ( !strcmp( serviceId, finger->serviceId ) ) &&
308                 ( !strcmp( UDN, finger->UDN ) ) ) {
309                 return finger;
310             }
311             finger = finger->next;
312         }
313     }
314
315     return NULL;
316 }
317
318 /************************************************************************
319 *       Function :      FindServiceEventURLPath
320 *
321 *       Parameters :
322 *               service_table *table ;  service table
323 *               char * eventURLPath ;   event URL path used to find a service 
324 *                                                               from the table  
325 *
326 *       Description :   Traverses the service table and finds the node whose
327 *               event URL Path matches a know value 
328 *
329 *       Return : service_info * - pointer to the service list node from the 
330 *               service table whose event URL matches a known event URL;
331 *
332 *       Note :
333 ************************************************************************/
334 service_info *
335 FindServiceEventURLPath( service_table * table,
336                          char *eventURLPath )
337 {
338     service_info *finger = NULL;
339     uri_type parsed_url;
340     uri_type parsed_url_in;
341
342     if( ( table )
343         &&
344         ( parse_uri
345           ( eventURLPath, strlen( eventURLPath ), &parsed_url_in ) ) ) {
346
347         finger = table->serviceList;
348         while( finger ) {
349             if( finger->eventURL )
350                 if( ( parse_uri
351                       ( finger->eventURL, strlen( finger->eventURL ),
352                         &parsed_url ) ) ) {
353
354                     if( !token_cmp
355                         ( &parsed_url.pathquery,
356                           &parsed_url_in.pathquery ) )
357                         return finger;
358
359                 }
360             finger = finger->next;
361         }
362     }
363
364     return NULL;
365 }
366
367 /************************************************************************
368 *       Function :      FindServiceControlURLPath
369 *
370 *       Parameters :
371 *               service_table * table ; service table
372 *               char * controlURLPath ; control URL path used to find a service 
373 *                                                               from the table  
374 *
375 *       Description :   Traverses the service table and finds the node whose
376 *               control URL Path matches a know value 
377 *
378 *       Return : service_info * - pointer to the service list node from the 
379 *               service table whose control URL Path matches a known value;
380 *
381 *       Note :
382 ************************************************************************/
383 service_info *
384 FindServiceControlURLPath( service_table * table,
385                            const char *controlURLPath )
386 {
387     service_info *finger = NULL;
388     uri_type parsed_url;
389     uri_type parsed_url_in;
390
391     if( ( table )
392         &&
393         ( parse_uri
394           ( controlURLPath, strlen( controlURLPath ),
395             &parsed_url_in ) ) ) {
396         finger = table->serviceList;
397         while( finger ) {
398             if( finger->controlURL )
399                 if( ( parse_uri
400                       ( finger->controlURL, strlen( finger->controlURL ),
401                         &parsed_url ) ) ) {
402                     if( !token_cmp
403                         ( &parsed_url.pathquery,
404                           &parsed_url_in.pathquery ) )
405                         return finger;
406                 }
407             finger = finger->next;
408         }
409     }
410
411     return NULL;
412
413 }
414
415 /************************************************************************
416 *       Function :      printService
417 *
418 *       Parameters :
419 *               service_info *service ;Service whose information is to be printed
420 *               Upnp_LogLevel level ; Debug level specified to the print function
421 *               Dbg_Module module ;     Debug module specified to the print function
422 *
423 *       Description :   For debugging purposes prints information from the 
424 *               service passed into the function.
425 *
426 *       Return : void ;
427 *
428 *       Note :
429 ************************************************************************/
430 #ifdef DEBUG
431 void printService(
432     service_info *service,
433     Upnp_LogLevel level,
434     Dbg_Module module )
435 {
436     if( service ) {
437         if( service->serviceType ) {
438             UpnpPrintf( level, module, __FILE__, __LINE__,
439                 "serviceType: %s\n", service->serviceType );
440         }
441         if( service->serviceId ) {
442             UpnpPrintf( level, module, __FILE__, __LINE__,
443                 "serviceId: %s\n", service->serviceId );
444         }
445         if( service->SCPDURL ) {
446             UpnpPrintf( level, module, __FILE__, __LINE__,
447                 "SCPDURL: %s\n", service->SCPDURL );
448         }
449         if( service->controlURL ) {
450             UpnpPrintf( level, module, __FILE__, __LINE__,
451                 "controlURL: %s\n", service->controlURL );
452         }
453         if( service->eventURL ) {
454             UpnpPrintf( level, module, __FILE__, __LINE__,
455                 "eventURL: %s\n", service->eventURL );
456         }
457         if( service->UDN ) {
458             UpnpPrintf( level, module, __FILE__, __LINE__,
459                 "UDN: %s\n\n", service->UDN );
460         }
461         if( service->active ) {
462             UpnpPrintf( level, module, __FILE__, __LINE__,
463             "Service is active\n" );
464         } else {
465             UpnpPrintf( level, module, __FILE__, __LINE__,
466             "Service is inactive\n" );
467         }
468     }
469 }
470 #endif
471
472 /************************************************************************
473 *       Function :      printServiceList
474 *
475 *       Parameters :
476 *               service_info *service ; Service whose information is to be printed
477 *               Upnp_LogLevel level ;   Debug level specified to the print function
478 *               Dbg_Module module ;     Debug module specified to the print function
479 *
480 *       Description :   For debugging purposes prints information of each 
481 *               service from the service table passed into the function.
482 *
483 *       Return : void ;
484 *
485 *       Note :
486 ************************************************************************/
487 #ifdef DEBUG
488 void printServiceList(
489     service_info * service,
490     Upnp_LogLevel level,
491     Dbg_Module module )
492 {
493     while( service ) {
494         if( service->serviceType ) {
495             UpnpPrintf( level, module, __FILE__, __LINE__,
496                 "serviceType: %s\n", service->serviceType );
497         }
498         if( service->serviceId ) {
499             UpnpPrintf( level, module, __FILE__, __LINE__,
500                 "serviceId: %s\n", service->serviceId );
501         }
502         if( service->SCPDURL ) {
503             UpnpPrintf( level, module, __FILE__, __LINE__,
504                 "SCPDURL: %s\n", service->SCPDURL );
505         }
506         if( service->controlURL ) {
507             UpnpPrintf( level, module, __FILE__, __LINE__,
508                 "controlURL: %s\n", service->controlURL );
509         }
510         if( service->eventURL ) {
511             UpnpPrintf( level, module, __FILE__, __LINE__,
512                 "eventURL: %s\n", service->eventURL );
513         }
514         if( service->UDN ) {
515             UpnpPrintf( level, module, __FILE__, __LINE__,
516                 "UDN: %s\n\n", service->UDN );
517         }
518         if( service->active ) {
519             UpnpPrintf( level, module, __FILE__, __LINE__,
520                 "Service is active\n" );
521         } else {
522             UpnpPrintf( level, module, __FILE__, __LINE__,
523                 "Service is inactive\n" );
524         }
525         service = service->next;
526     }
527 }
528 #endif
529
530 /************************************************************************
531 *       Function :      printServiceTable
532 *
533 *       Parameters :
534 *               service_table * table ; Service table to be printed
535 *               Upnp_LogLevel level ;   Debug level specified to the print function
536 *               Dbg_Module module ;     Debug module specified to the print function
537 *
538 *       Description :   For debugging purposes prints the URL base of the table
539 *               and information of each service from the service table passed into 
540 *               the function.
541 *
542 *       Return : void ;
543 *
544 *       Note :
545 ************************************************************************/
546 #ifdef DEBUG
547 void printServiceTable(
548     service_table * table,
549     Upnp_LogLevel level,
550     Dbg_Module module )
551 {
552     UpnpPrintf( level, module, __FILE__, __LINE__,
553         "URL_BASE: %s\n", table->URLBase );
554     UpnpPrintf( level, module, __FILE__, __LINE__,
555         "Services: \n" );
556     printServiceList( table->serviceList, level, module );}
557 #endif
558
559 /************************************************************************
560 *       Function :      freeService
561 *
562 *       Parameters :
563 *               service_info *in ;      service information that is to be freed
564 *
565 *       Description :   Free's memory allocated for the various components 
566 *               of the service entry in the service table.
567 *
568 *       Return : void ;
569 *
570 *       Note :
571 ************************************************************************/
572 void freeService( service_info * in )
573 {
574     if( in ) {
575         if( in->serviceType )
576             ixmlFreeDOMString( in->serviceType );
577
578         if( in->serviceId )
579             ixmlFreeDOMString( in->serviceId );
580
581         if( in->SCPDURL )
582             free( in->SCPDURL );
583
584         if( in->controlURL )
585             free( in->controlURL );
586
587         if( in->eventURL )
588             free( in->eventURL );
589
590         if( in->UDN )
591             ixmlFreeDOMString( in->UDN );
592
593         if( in->subscriptionList )
594             freeSubscriptionList( in->subscriptionList );
595
596         in->TotalSubscriptions = 0;
597         free( in );
598     }
599 }
600
601 /************************************************************************
602 *       Function :      freeServiceList
603 *
604 *       Parameters :
605 *               service_info * head ;   Head of the service list to be freed
606 *
607 *       Description :   Free's memory allocated for the various components 
608 *               of each service entry in the service table.
609 *
610 *       Return : void ;
611 *
612 *       Note :
613 ************************************************************************/
614 void
615 freeServiceList( service_info * head )
616 {
617     service_info *next = NULL;
618
619     while( head ) {
620         if( head->serviceType )
621             ixmlFreeDOMString( head->serviceType );
622         if( head->serviceId )
623             ixmlFreeDOMString( head->serviceId );
624         if( head->SCPDURL )
625             free( head->SCPDURL );
626         if( head->controlURL )
627             free( head->controlURL );
628         if( head->eventURL )
629             free( head->eventURL );
630         if( head->UDN )
631             ixmlFreeDOMString( head->UDN );
632         if( head->subscriptionList )
633             freeSubscriptionList( head->subscriptionList );
634
635         head->TotalSubscriptions = 0;
636         next = head->next;
637         free( head );
638         head = next;
639     }
640 }
641
642 /************************************************************************
643 *       Function :      freeServiceTable
644 *
645 *       Parameters :
646 *               service_table * table ; Service table whose memory needs to be 
647 *                                                               freed
648 *
649 *       Description : Free's dynamic memory in table.
650 *               (does not free table, only memory within the structure)
651 *
652 *       Return : void ;
653 *
654 *       Note :
655 ************************************************************************/
656 void
657 freeServiceTable( service_table * table )
658 {
659     ixmlFreeDOMString( table->URLBase );
660     freeServiceList( table->serviceList );
661     table->serviceList = NULL;
662     table->endServiceList = NULL;
663 }
664
665 /************************************************************************
666 *       Function :      getElementValue
667 *
668 *       Parameters :
669 *               IXML_Node *node ;       Input node which provides the list of child 
670 *                                                       nodes
671 *
672 *       Description :   Returns the clone of the element value
673 *
674 *       Return : DOMString ;
675 *
676 *       Note : value must be freed with DOMString_free
677 ************************************************************************/
678 DOMString
679 getElementValue( IXML_Node * node )
680 {
681     IXML_Node *child = ( IXML_Node * ) ixmlNode_getFirstChild( node );
682     const DOMString temp = NULL;
683
684     if( ( child != 0 ) && ( ixmlNode_getNodeType( child ) == eTEXT_NODE ) ) {
685         temp = ixmlNode_getNodeValue( child );
686         return ixmlCloneDOMString( temp );
687     } else {
688         return NULL;
689     }
690 }
691
692 /************************************************************************
693 *       Function :      getSubElement
694 *
695 *       Parameters :
696 *               const char *element_name ;      sub element name to be searched for
697 *               IXML_Node *node ;       Input node which provides the list of child 
698 *                                                       nodes
699 *               IXML_Node **out ;       Ouput node to which the matched child node is
700 *                                                       returned.
701 *
702 *       Description :   Traverses through a list of XML nodes to find the 
703 *               node with the known element name.
704 *
705 *       Return : int ;
706 *               1 - On Success
707 *               0 - On Failure
708 *
709 *       Note :
710 ************************************************************************/
711 int
712 getSubElement( const char *element_name,
713                IXML_Node * node,
714                IXML_Node ** out )
715 {
716
717     const DOMString NodeName = NULL;
718     int found = 0;
719
720     IXML_Node *child = ( IXML_Node * ) ixmlNode_getFirstChild( node );
721
722     ( *out ) = NULL;
723
724     while( ( child != NULL ) && ( !found ) ) {
725
726         switch ( ixmlNode_getNodeType( child ) ) {
727             case eELEMENT_NODE:
728
729                 NodeName = ixmlNode_getNodeName( child );
730                 if( !strcmp( NodeName, element_name ) ) {
731                     ( *out ) = child;
732                     found = 1;
733                     return found;
734                 }
735                 break;
736
737             default:
738                 break;
739         }
740
741         child = ( IXML_Node * ) ixmlNode_getNextSibling( child );
742     }
743
744     return found;
745 }
746
747 /************************************************************************
748 *       Function :      getServiceList
749 *
750 *       Parameters :
751 *               IXML_Node *node ;       XML node information
752 *               service_info **end ; service added is returned to the output
753 *                                                       parameter
754 *               char * URLBase ;        provides Base URL to resolve relative URL 
755 *
756 *       Description :   Returns pointer to service info after getting the 
757 *               sub-elements of the service info. 
758 *
759 *       Return : service_info * - pointer to the service info node ;
760 *
761 *       Note :
762 ************************************************************************/
763 service_info *
764 getServiceList( IXML_Node * node,
765                 service_info ** end,
766                 char *URLBase )
767 {
768     IXML_Node *serviceList = NULL;
769     IXML_Node *current_service = NULL;
770     IXML_Node *UDN = NULL;
771
772     IXML_Node *serviceType = NULL;
773     IXML_Node *serviceId = NULL;
774     IXML_Node *SCPDURL = NULL;
775     IXML_Node *controlURL = NULL;
776     IXML_Node *eventURL = NULL;
777     DOMString tempDOMString = NULL;
778     service_info *head = NULL;
779     service_info *current = NULL;
780     service_info *previous = NULL;
781     IXML_NodeList *serviceNodeList = NULL;
782     int NumOfServices = 0;
783     int i = 0;
784     int fail = 0;
785
786     if( getSubElement( "UDN", node, &UDN ) &&
787         getSubElement( "serviceList", node, &serviceList ) ) {
788
789         serviceNodeList = ixmlElement_getElementsByTagName( ( IXML_Element
790                                                               * )
791                                                             serviceList,
792                                                             "service" );
793
794         if( serviceNodeList != NULL ) {
795             NumOfServices = ixmlNodeList_length( serviceNodeList );
796             for( i = 0; i < NumOfServices; i++ ) {
797                 current_service = ixmlNodeList_item( serviceNodeList, i );
798                 fail = 0;
799
800                 if( current ) {
801                     current->next =
802                         ( service_info * )
803                         malloc( sizeof( service_info ) );
804
805                     previous = current;
806                     current = current->next;
807                 } else {
808                     head =
809                         ( service_info * )
810                         malloc( sizeof( service_info ) );
811                     current = head;
812                 }
813
814                 if( !current ) {
815                     freeServiceList( head );
816                     return NULL;
817                 }
818
819                 current->next = NULL;
820                 current->controlURL = NULL;
821                 current->eventURL = NULL;
822                 current->serviceType = NULL;
823                 current->serviceId = NULL;
824                 current->SCPDURL = NULL;
825                 current->active = 1;
826                 current->subscriptionList = NULL;
827                 current->TotalSubscriptions = 0;
828
829                 if( !( current->UDN = getElementValue( UDN ) ) )
830                     fail = 1;
831
832                 if( ( !getSubElement( "serviceType", current_service,
833                                       &serviceType ) ) ||
834                     ( !( current->serviceType =
835                          getElementValue( serviceType ) ) ) )
836                     fail = 1;
837
838                 if( ( !getSubElement( "serviceId", current_service,
839                                       &serviceId ) ) ||
840                     ( !
841                       ( current->serviceId =
842                         getElementValue( serviceId ) ) ) )
843                     fail = 1;
844
845                 if( ( !
846                       ( getSubElement
847                         ( "SCPDURL", current_service, &SCPDURL ) ) )
848                     || ( !( tempDOMString = getElementValue( SCPDURL ) ) )
849                     ||
850                     ( !
851                       ( current->SCPDURL =
852                         resolve_rel_url( URLBase, tempDOMString ) ) ) )
853                     fail = 1;
854
855                 ixmlFreeDOMString( tempDOMString );
856                 tempDOMString = NULL;
857
858                 if( ( !
859                       ( getSubElement
860                         ( "controlURL", current_service, &controlURL ) ) )
861                     ||
862                     ( !( tempDOMString = getElementValue( controlURL ) ) )
863                     ||
864                     ( !
865                       ( current->controlURL =
866                         resolve_rel_url( URLBase, tempDOMString ) ) ) ) {
867                     UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__,
868                         "BAD OR MISSING CONTROL URL" );
869                     UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__,
870                         "CONTROL URL SET TO NULL IN SERVICE INFO" );
871                     current->controlURL = NULL;
872                     fail = 0;
873                 }
874
875                 ixmlFreeDOMString( tempDOMString );
876                 tempDOMString = NULL;
877
878                 if( ( !
879                       ( getSubElement
880                         ( "eventSubURL", current_service, &eventURL ) ) )
881                     || ( !( tempDOMString = getElementValue( eventURL ) ) )
882                     ||
883                     ( !
884                       ( current->eventURL =
885                         resolve_rel_url( URLBase, tempDOMString ) ) ) ) {
886                     UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__,
887                         "BAD OR MISSING EVENT URL" );
888                     UpnpPrintf( UPNP_INFO, GENA, __FILE__, __LINE__,
889                         "EVENT URL SET TO NULL IN SERVICE INFO" );
890                     current->eventURL = NULL;
891                     fail = 0;
892                 }
893
894                 ixmlFreeDOMString( tempDOMString );
895                 tempDOMString = NULL;
896
897                 if( fail ) {
898                     freeServiceList( current );
899
900                     if( previous )
901                         previous->next = NULL;
902                     else
903                         head = NULL;
904
905                     current = previous;
906                 }
907
908             }
909
910             ixmlNodeList_free( serviceNodeList );
911         }
912
913         ( *end ) = current;
914
915         return head;
916     } else
917         return NULL;
918
919 }
920
921 /************************************************************************
922 * Function : getAllServiceList
923 *
924 * Parameters :
925 *       IXML_Node *node ;       XML node information
926 *       char * URLBase ;        provides Base URL to resolve relative URL 
927 *       service_info **out_end ; service added is returned to the output
928 *                               parameter
929 *
930 * Description : Returns pointer to service info after getting the 
931 *               sub-elements of the service info. 
932 *
933 * Return : service_info * ;
934 *
935 * Note :
936 ************************************************************************/
937 service_info *
938 getAllServiceList( IXML_Node * node,
939                    char *URLBase,
940                    service_info ** out_end )
941 {
942     service_info *head = NULL;
943     service_info *end = NULL;
944     service_info *next_end = NULL;
945     IXML_NodeList *deviceList = NULL;
946     IXML_Node *currentDevice = NULL;
947
948     int NumOfDevices = 0;
949     int i = 0;
950
951     ( *out_end ) = NULL;
952
953     deviceList =
954         ixmlElement_getElementsByTagName( ( IXML_Element * ) node,
955                                           "device" );
956     if( deviceList != NULL ) {
957         NumOfDevices = ixmlNodeList_length( deviceList );
958         for( i = 0; i < NumOfDevices; i++ ) {
959             currentDevice = ixmlNodeList_item( deviceList, i );
960             if( head ) {
961                 end->next =
962                     getServiceList( currentDevice, &next_end, URLBase );
963                 end = next_end;
964             } else
965                 head = getServiceList( currentDevice, &end, URLBase );
966
967         }
968
969         ixmlNodeList_free( deviceList );
970     }
971
972     ( *out_end ) = end;
973     return head;
974 }
975
976 /************************************************************************
977 *       Function :      removeServiceTable
978 *
979 *       Parameters :
980 *               IXML_Node *node ;       XML node information
981 *               service_table *in ;     service table from which services will be 
982 *                                                       removed
983 *
984 *       Description :   This function assumes that services for a particular 
985 *               root device are placed linearly in the service table, and in the 
986 *               order in which they are found in the description document
987 *               all services for this root device are removed from the list
988 *
989 *       Return : int ;
990 *
991 *       Note :
992 ************************************************************************/
993 int
994 removeServiceTable( IXML_Node * node,
995                     service_table * in )
996 {
997     IXML_Node *root = NULL;
998     IXML_Node *currentUDN = NULL;
999     DOMString UDN = NULL;
1000     IXML_NodeList *deviceList = NULL;
1001     IXML_Node *currentDevice = NULL;
1002     service_info *current_service = NULL;
1003     service_info *start_search = NULL;
1004     service_info *prev_service = NULL;
1005     int NumOfDevices = 0;
1006     int i = 0;
1007
1008     if( getSubElement( "root", node, &root ) ) {
1009         current_service = in->serviceList;
1010         start_search = in->serviceList;
1011         deviceList =
1012             ixmlElement_getElementsByTagName( ( IXML_Element * ) root,
1013                                               "device" );
1014         if( deviceList != NULL ) {
1015             NumOfDevices = ixmlNodeList_length( deviceList );
1016             for( i = 0; i < NumOfDevices; i++ ) {
1017                 currentDevice = ixmlNodeList_item( deviceList, i );
1018                 if( ( start_search )
1019                     && ( ( getSubElement( "UDN", node, &currentUDN ) )
1020                          && ( UDN = getElementValue( currentUDN ) ) ) ) {
1021                     current_service = start_search;
1022                     //Services are put in the service table in the order in which they appear in the 
1023                     //description document, therefore we go through the list only once to remove a particular
1024                     //root device
1025                     while( ( current_service )
1026                            && ( strcmp( current_service->UDN, UDN ) ) ) {
1027                         current_service = current_service->next;
1028                         prev_service = current_service->next;
1029                     }
1030                     while( ( current_service )
1031                            && ( !strcmp( current_service->UDN, UDN ) ) ) {
1032                         if( prev_service ) {
1033                             prev_service->next = current_service->next;
1034                         } else {
1035                             in->serviceList = current_service->next;
1036                         }
1037                         if( current_service == in->endServiceList )
1038                             in->endServiceList = prev_service;
1039                         start_search = current_service->next;
1040                         freeService( current_service );
1041                         current_service = start_search;
1042                     }
1043                 }
1044             }
1045
1046             ixmlNodeList_free( deviceList );
1047         }
1048     }
1049     return 1;
1050 }
1051
1052 /************************************************************************
1053 *       Function :      addServiceTable
1054 *
1055 *       Parameters :
1056 *               IXML_Node *node ;       XML node information 
1057 *               service_table *in ;     service table that will be initialized with 
1058 *                                                       services
1059 *               const char *DefaultURLBase ; Default base URL on which the URL 
1060 *                                                       will be returned to the service list.
1061 *
1062 *       Description :   Add Service to the table.
1063 *
1064 *       Return : int ;
1065 *
1066 *       Note :
1067 ************************************************************************/
1068 int
1069 addServiceTable( IXML_Node * node,
1070                  service_table * in,
1071                  const char *DefaultURLBase )
1072 {
1073     IXML_Node *root = NULL;
1074     IXML_Node *URLBase = NULL;
1075
1076     service_info *tempEnd = NULL;
1077
1078     if( in->URLBase ) {
1079         free( in->URLBase );
1080         in->URLBase = NULL;
1081     }
1082
1083     if( getSubElement( "root", node, &root ) ) {
1084         if( getSubElement( "URLBase", root, &URLBase ) ) {
1085             in->URLBase = getElementValue( URLBase );
1086         } else {
1087             if( DefaultURLBase ) {
1088                 in->URLBase = ixmlCloneDOMString( DefaultURLBase );
1089             } else {
1090                 in->URLBase = ixmlCloneDOMString( "" );
1091             }
1092         }
1093
1094         if( ( in->endServiceList->next =
1095               getAllServiceList( root, in->URLBase, &tempEnd ) ) ) {
1096             in->endServiceList = tempEnd;
1097             return 1;
1098         }
1099
1100     }
1101
1102     return 0;
1103 }
1104
1105 /************************************************************************
1106  * Function : getServiceTable
1107  *
1108  * Parameters :
1109  *      IXML_Node *node ;       XML node information
1110  *      service_table *out ;    output parameter which will contain the
1111  *                              service list and URL
1112  *      const char *DefaultURLBase ; Default base URL on which the URL
1113  *                              will be returned.
1114  *
1115  * Description : Retrieve service from the table
1116  *
1117  * Return : int ;
1118  *
1119  * Note :
1120 ************************************************************************/
1121 int
1122 getServiceTable( IXML_Node * node,
1123                  service_table * out,
1124                  const char *DefaultURLBase )
1125 {
1126     IXML_Node *root = NULL;
1127     IXML_Node *URLBase = NULL;
1128
1129     if( getSubElement( "root", node, &root ) ) {
1130         if( getSubElement( "URLBase", root, &URLBase ) ) {
1131             out->URLBase = getElementValue( URLBase );
1132         } else {
1133             if( DefaultURLBase ) {
1134                 out->URLBase = ixmlCloneDOMString( DefaultURLBase );
1135             } else {
1136                 out->URLBase = ixmlCloneDOMString( "" );
1137             }
1138         }
1139
1140         if( ( out->serviceList = getAllServiceList(
1141             root, out->URLBase, &out->endServiceList ) ) ) {
1142             return 1;
1143         }
1144
1145     }
1146
1147     return 0;
1148 }
1149
1150 #endif // INCLUDE_DEVICE_APIS