source: trunk/zoo-project/zoo-kernel/response_print.c @ 686

Last change on this file since 686 was 682, checked in by djay, 10 years ago

Fix GetResult? and POST asynchronous requests on Windows. Prevent CONTENT_TYPE=text/xml before creating the process using CreateProcess?. Revert modifications made r587 for using url_decode directly inside zoo_loader.c, the url_decode call should be in kvpParseInputs (from request_parser.c), indeed, there should not be any decoding required in other cases than Execute requests. Fix issue in mapsFromPyDict, small changes in mapFromPyDict to fix parsing result value (only) for Python 3.

  • Property svn:keywords set to Id
File size: 82.7 KB
Line 
1/*
2 * Author : Gérald FENOY
3 *
4 * Copyright (c) 2009-2015 GeoLabs SARL
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
24
25#include "response_print.h"
26#include "request_parser.h"
27#include "server_internal.h"
28#include "service_internal.h"
29#ifdef USE_MS
30#include "service_internal_ms.h"
31#else
32#include "cpl_vsi.h"
33#endif
34
35#ifndef TRUE
36#define TRUE 1
37#endif
38#ifndef FALSE
39#define FALSE -1
40#endif
41
42#ifndef WIN32
43#include <dlfcn.h>
44#endif
45
46#include "mimetypes.h"
47
48
49/**
50 * Add prefix to the service name.
51 *
52 * @param conf the conf maps containing the main.cfg settings
53 * @param level the map containing the level information
54 * @param serv the service structure created from the zcfg file
55 */
56void addPrefix(maps* conf,map* level,service* serv){
57  if(level!=NULL){
58    char key[25];
59    char* prefix=NULL;
60    int clevel=atoi(level->value);
61    int cl=0;
62    for(cl=0;cl<clevel;cl++){
63      sprintf(key,"sprefix_%d",cl);
64      map* tmp2=getMapFromMaps(conf,"lenv",key);
65      if(tmp2!=NULL){
66        if(prefix==NULL)
67          prefix=zStrdup(tmp2->value);
68        else{
69          int plen=strlen(prefix);
70          prefix=(char*)realloc(prefix,(plen+strlen(tmp2->value)+2)*sizeof(char));
71          memcpy(prefix+plen,tmp2->value,strlen(tmp2->value)*sizeof(char));
72          prefix[plen+strlen(tmp2->value)]=0;
73        }
74      }
75    }
76    if(prefix!=NULL){
77      char* tmp0=strdup(serv->name);
78      free(serv->name);
79      serv->name=(char*)malloc((strlen(prefix)+strlen(tmp0)+1)*sizeof(char));
80      sprintf(serv->name,"%s%s",prefix,tmp0);
81      free(tmp0);
82      free(prefix);
83      prefix=NULL;
84    }
85  }
86}
87
88/**
89 * Print the HTTP headers based on a map.
90 *
91 * @param m the map containing the headers informations
92 */
93void printHeaders(maps* m){
94  maps *_tmp=getMaps(m,"headers");
95  if(_tmp!=NULL){
96    map* _tmp1=_tmp->content;
97    while(_tmp1!=NULL){
98      printf("%s: %s\r\n",_tmp1->name,_tmp1->value);
99      _tmp1=_tmp1->next;
100    }
101  }
102}
103
104/**
105 * Add a land attribute to a XML node
106 *
107 * @param n the XML node to add the attribute
108 * @param m the map containing the language key to add as xml:lang
109 */
110void addLangAttr(xmlNodePtr n,maps *m){
111  map *tmpLmap=getMapFromMaps(m,"main","language");
112  if(tmpLmap!=NULL)
113    xmlNewProp(n,BAD_CAST "xml:lang",BAD_CAST tmpLmap->value);
114  else
115    xmlNewProp(n,BAD_CAST "xml:lang",BAD_CAST "en-US");
116}
117
118/**
119 * Replace the first letter by its upper case version in a new char array
120 *
121 * @param tmp the char*
122 * @return a new char* with first letter in upper case
123 * @warning be sure to free() the returned string after use
124 */
125char *zCapitalize1(char *tmp){
126  char *res=zStrdup(tmp);
127  if(res[0]>=97 && res[0]<=122)
128    res[0]-=32;
129  return res;
130}
131
132/**
133 * Replace all letters by their upper case version in a new char array
134 *
135 * @param tmp the char*
136 * @return a new char* with first letter in upper case
137 * @warning be sure to free() the returned string after use
138 */
139char *zCapitalize(char *tmp){
140  int i=0;
141  char *res=zStrdup(tmp);
142  for(i=0;i<strlen(res);i++)
143    if(res[i]>=97 && res[i]<=122)
144      res[i]-=32;
145  return res;
146}
147
148/**
149 * Search for an existing XML namespace in usedNS.
150 *
151 * @param name the name of the XML namespace to search
152 * @return the index of the XML namespace found or -1 if not found.
153 */
154int zooXmlSearchForNs(const char* name){
155  int i;
156  int res=-1;
157  for(i=0;i<nbNs;i++)
158    if(strncasecmp(name,nsName[i],strlen(nsName[i]))==0){
159      res=i;
160      break;
161    }
162  return res;
163}
164
165/**
166 * Add an XML namespace to the usedNS if it was not already used.
167 *
168 * @param nr the xmlNodePtr to attach the XML namspace (can be NULL)
169 * @param url the url of the XML namespace to add
170 * @param name the name of the XML namespace to add
171 * @return the index of the XML namespace added.
172 */
173int zooXmlAddNs(xmlNodePtr nr,const char* url,const char* name){
174#ifdef DEBUG
175  fprintf(stderr,"zooXmlAddNs %d %s \n",nbNs,name);
176#endif
177  int currId=-1;
178  if(nbNs==0){
179    nbNs++;
180    currId=0;
181    nsName[currId]=strdup(name);
182    usedNs[currId]=xmlNewNs(nr,BAD_CAST url,BAD_CAST name);
183  }else{
184    currId=zooXmlSearchForNs(name);
185    if(currId<0){
186      nbNs++;
187      currId=nbNs-1;
188      nsName[currId]=strdup(name);
189      usedNs[currId]=xmlNewNs(nr,BAD_CAST url,BAD_CAST name);
190    }
191  }
192  return currId;
193}
194
195/**
196 * Free allocated memory to store used XML namespace.
197 */
198void zooXmlCleanupNs(){
199  int j;
200#ifdef DEBUG
201  fprintf(stderr,"zooXmlCleanup %d\n",nbNs);
202#endif
203  for(j=nbNs-1;j>=0;j--){
204#ifdef DEBUG
205    fprintf(stderr,"zooXmlCleanup %d\n",j);
206#endif
207    if(j==0)
208      xmlFreeNs(usedNs[j]);
209    free(nsName[j]);
210    nbNs--;
211  }
212  nbNs=0;
213}
214
215/**
216 * Add a XML document to the iDocs.
217 *
218 * @param value the string containing the XML document
219 * @return the index of the XML document added.
220 */
221int zooXmlAddDoc(const char* value){
222  int currId=0;
223  nbDocs++;
224  currId=nbDocs-1;
225  iDocs[currId]=xmlParseMemory(value,strlen(value));
226  return currId;
227}
228
229/**
230 * Free allocated memort to store XML documents
231 */
232void zooXmlCleanupDocs(){
233  int j;
234  for(j=nbDocs-1;j>=0;j--){
235    xmlFreeDoc(iDocs[j]);
236  }
237  nbDocs=0;
238}
239
240/**
241 * Generate a SOAP Envelope node when required (if the isSoap key of the [main]
242 * section is set to true).
243 *
244 * @param conf the conf maps containing the main.cfg settings
245 * @param n the node used as children of the generated soap:Envelope
246 * @return the generated soap:Envelope (if isSoap=true) or the input node n
247 *  (when isSoap=false)
248 */
249xmlNodePtr soapEnvelope(maps* conf,xmlNodePtr n){
250  map* soap=getMapFromMaps(conf,"main","isSoap");
251  if(soap!=NULL && strcasecmp(soap->value,"true")==0){
252    int lNbNs=nbNs;
253    nsName[lNbNs]=strdup("soap");
254    usedNs[lNbNs]=xmlNewNs(NULL,BAD_CAST "http://www.w3.org/2003/05/soap-envelope",BAD_CAST "soap");
255    nbNs++;
256    xmlNodePtr nr = xmlNewNode(usedNs[lNbNs], BAD_CAST "Envelope");
257    nsName[nbNs]=strdup("soap");
258    usedNs[nbNs]=xmlNewNs(nr,BAD_CAST "http://www.w3.org/2003/05/soap-envelope",BAD_CAST "soap");
259    nbNs++;
260    nsName[nbNs]=strdup("xsi");
261    usedNs[nbNs]=xmlNewNs(nr,BAD_CAST "http://www.w3.org/2001/XMLSchema-instance",BAD_CAST "xsi");
262    nbNs++;
263    xmlNsPtr ns_xsi=usedNs[nbNs-1];
264    xmlNewNsProp(nr,ns_xsi,BAD_CAST "schemaLocation",BAD_CAST "http://www.w3.org/2003/05/soap-envelope http://www.w3.org/2003/05/soap-envelope");
265    xmlNodePtr nr1 = xmlNewNode(usedNs[lNbNs], BAD_CAST "Body");
266    xmlAddChild(nr1,n);
267    xmlAddChild(nr,nr1);
268    return nr;
269  }else
270    return n;
271}
272
273/**
274 * Generate a WPS header.
275 *
276 * @param doc the document to add the header
277 * @param m the conf maps containing the main.cfg settings
278 * @param req the request type (GetCapabilities,DescribeProcess,Execute)
279 * @param rname the root node name
280 * @return the generated wps:rname xmlNodePtr (can be wps: Capabilities,
281 *  wps:ProcessDescriptions,wps:ExecuteResponse)
282 */
283xmlNodePtr printWPSHeader(xmlDocPtr doc,maps* m,const char* req,const char* rname,const char* version,int reqId){
284
285  xmlNsPtr ns,ns_xsi;
286  xmlNodePtr n;
287
288  int vid=getVersionId(version);
289
290  int wpsId=zooXmlAddNs(NULL,schemas[vid][2],"wps");
291  ns=usedNs[wpsId];
292  n = xmlNewNode(ns, BAD_CAST rname);
293  zooXmlAddNs(n,schemas[vid][1],"ows");
294  xmlNewNs(n,BAD_CAST schemas[vid][2],BAD_CAST "wps");
295  zooXmlAddNs(n,"http://www.w3.org/1999/xlink","xlink");
296  int xsiId=zooXmlAddNs(n,"http://www.w3.org/2001/XMLSchema-instance","xsi");
297  ns_xsi=usedNs[xsiId];
298  char *tmp=(char*) malloc((86+strlen(req)+1)*sizeof(char));
299  sprintf(tmp,schemas[vid][4],schemas[vid][2],schemas[vid][3],req);
300  xmlNewNsProp(n,ns_xsi,BAD_CAST "schemaLocation",BAD_CAST tmp);
301  free(tmp);
302  if(vid==0 || reqId==0){
303    xmlNewProp(n,BAD_CAST "service",BAD_CAST "WPS");
304    xmlNewProp(n,BAD_CAST "version",BAD_CAST schemas[vid][0]);
305  }
306  if(vid==0)
307    addLangAttr(n,m);
308  xmlNodePtr fn=soapEnvelope(m,n);
309  xmlDocSetRootElement(doc, fn);
310  return n;
311}
312
313void addLanguageNodes(maps* conf,xmlNodePtr n,xmlNsPtr ns,xmlNsPtr ns_ows){
314  xmlNodePtr nc1,nc2,nc3,nc4;
315  map* version=getMapFromMaps(conf,"main","rversion");
316  int vid=getVersionId(version->value);
317  if(vid==1)
318    nc1 = xmlNewNode(ns_ows, BAD_CAST "Languages");
319  else{
320    nc1 = xmlNewNode(ns, BAD_CAST "Languages");
321    nc2 = xmlNewNode(ns, BAD_CAST "Default");
322    nc3 = xmlNewNode(ns, BAD_CAST "Supported");
323  }
324
325  maps* tmp=getMaps(conf,"main");
326  if(tmp!=NULL){
327    map* tmp1=getMap(tmp->content,"lang");
328    char *toto=tmp1->value;
329    char buff[256];
330    int i=0;
331    int j=0;
332    int dcount=0;
333    while(toto[i]){
334      if(toto[i]!=',' && toto[i]!=0){
335        buff[j]=toto[i];
336        buff[j+1]=0;
337        j++;
338      }
339      else{
340        nc4 = xmlNewNode(ns_ows, BAD_CAST "Language");
341        xmlAddChild(nc4,xmlNewText(BAD_CAST buff));
342        if(dcount==0){
343          if(vid==0){
344            xmlAddChild(nc2,nc4);
345            xmlAddChild(nc1,nc2);
346          }
347          dcount++;
348        }
349        nc4 = xmlNewNode(ns_ows, BAD_CAST "Language");
350        xmlAddChild(nc4,xmlNewText(BAD_CAST buff));
351        if(vid==0)
352          xmlAddChild(nc3,nc4);
353        else
354          xmlAddChild(nc1,nc4);
355        j=0;
356        buff[j]=0;
357      }
358      i++;
359    }
360    if(strlen(buff)>0){
361      nc4 = xmlNewNode(ns_ows, BAD_CAST "Language");
362      xmlAddChild(nc4,xmlNewText(BAD_CAST buff));             
363        if(vid==0)
364          xmlAddChild(nc3,nc4);
365        else
366          xmlAddChild(nc1,nc4);
367    }
368  }
369  if(vid==0)
370    xmlAddChild(nc1,nc3);
371  xmlAddChild(n,nc1);
372}
373
374/**
375 * Generate a Capabilities header.
376 *
377 * @param doc the document to add the header
378 * @param m the conf maps containing the main.cfg settings
379 * @return the generated wps:ProcessOfferings xmlNodePtr
380 */
381xmlNodePtr printGetCapabilitiesHeader(xmlDocPtr doc,maps* m,const char* version="1.0.0"){
382
383  xmlNsPtr ns,ns_ows,ns_xlink;
384  xmlNodePtr n,nc,nc1,nc2,nc3,nc4,nc5,nc6;
385  n = printWPSHeader(doc,m,"GetCapabilities","Capabilities",version,0);
386  maps* toto1=getMaps(m,"main");
387  char tmp[256];
388  map* v=getMapFromMaps(m,"main","rversion");
389  int vid=getVersionId(v->value);
390
391  int wpsId=zooXmlAddNs(NULL,schemas[vid][2],"wps");
392  ns=usedNs[wpsId];
393  int xlinkId=zooXmlAddNs(NULL,"http://www.w3.org/1999/xlink","xlink");
394  ns_xlink=usedNs[xlinkId];
395  int owsId=zooXmlAddNs(NULL,schemas[vid][1],"ows");
396  ns_ows=usedNs[owsId];
397
398  nc = xmlNewNode(ns_ows, BAD_CAST "ServiceIdentification");
399  maps* tmp4=getMaps(m,"identification");
400  if(tmp4!=NULL){
401    map* tmp2=tmp4->content;
402    const char *orderedFields[5];
403    orderedFields[0]="Title";
404    orderedFields[1]="Abstract";
405    orderedFields[2]="Keywords";
406    orderedFields[3]="Fees";
407    orderedFields[4]="AccessConstraints";
408    int oI=0;
409    for(oI=0;oI<5;oI++)
410      if((tmp2=getMap(tmp4->content,orderedFields[oI]))!=NULL){
411        if(strcasecmp(tmp2->name,"abstract")==0 ||
412           strcasecmp(tmp2->name,"title")==0 ||
413           strcasecmp(tmp2->name,"accessConstraints")==0 ||
414           strcasecmp(tmp2->name,"fees")==0){
415          tmp2->name[0]=toupper(tmp2->name[0]);
416          nc1 = xmlNewNode(ns_ows, BAD_CAST tmp2->name);
417          xmlAddChild(nc1,xmlNewText(BAD_CAST tmp2->value));
418          xmlAddChild(nc,nc1);
419        }
420        else
421          if(strcmp(tmp2->name,"keywords")==0){
422            nc1 = xmlNewNode(ns_ows, BAD_CAST "Keywords");
423            char *toto=tmp2->value;
424            char buff[256];
425            int i=0;
426            int j=0;
427            while(toto[i]){
428              if(toto[i]!=',' && toto[i]!=0){
429                buff[j]=toto[i];
430                buff[j+1]=0;
431                j++;
432              }
433              else{
434                nc2 = xmlNewNode(ns_ows, BAD_CAST "Keyword");
435                xmlAddChild(nc2,xmlNewText(BAD_CAST buff));           
436                xmlAddChild(nc1,nc2);
437                j=0;
438              }
439              i++;
440            }
441            if(strlen(buff)>0){
442              nc2 = xmlNewNode(ns_ows, BAD_CAST "Keyword");
443              xmlAddChild(nc2,xmlNewText(BAD_CAST buff));             
444              xmlAddChild(nc1,nc2);
445            }
446            xmlAddChild(nc,nc1);
447            nc2 = xmlNewNode(ns_ows, BAD_CAST "ServiceType");
448            xmlAddChild(nc2,xmlNewText(BAD_CAST "WPS"));
449            xmlAddChild(nc,nc2);
450            nc2 = xmlNewNode(ns_ows, BAD_CAST "ServiceTypeVersion");
451            map* tmpv=getMapFromMaps(m,"main","rversion");
452            xmlAddChild(nc2,xmlNewText(BAD_CAST tmpv->value));
453            xmlAddChild(nc,nc2);
454          }
455        tmp2=tmp2->next;
456      }
457  }
458  else{
459    fprintf(stderr,"TMP4 NOT FOUND !!");
460    return NULL;
461  }
462  xmlAddChild(n,nc);
463
464  nc = xmlNewNode(ns_ows, BAD_CAST "ServiceProvider");
465  nc3 = xmlNewNode(ns_ows, BAD_CAST "ServiceContact");
466  nc4 = xmlNewNode(ns_ows, BAD_CAST "ContactInfo");
467  nc5 = xmlNewNode(ns_ows, BAD_CAST "Phone");
468  nc6 = xmlNewNode(ns_ows, BAD_CAST "Address");
469  tmp4=getMaps(m,"provider");
470  if(tmp4!=NULL){
471    map* tmp2=tmp4->content;
472    const char *tmpAddress[6];
473    tmpAddress[0]="addressDeliveryPoint";
474    tmpAddress[1]="addressCity";
475    tmpAddress[2]="addressAdministrativeArea";
476    tmpAddress[3]="addressPostalCode";
477    tmpAddress[4]="addressCountry";
478    tmpAddress[5]="addressElectronicMailAddress";
479    const char *tmpPhone[2];
480    tmpPhone[0]="phoneVoice";
481    tmpPhone[1]="phoneFacsimile";
482    const char *orderedFields[12];
483    orderedFields[0]="providerName";
484    orderedFields[1]="providerSite";
485    orderedFields[2]="individualName";
486    orderedFields[3]="positionName";
487    orderedFields[4]=tmpPhone[0];
488    orderedFields[5]=tmpPhone[1];
489    orderedFields[6]=tmpAddress[0];
490    orderedFields[7]=tmpAddress[1];
491    orderedFields[8]=tmpAddress[2];
492    orderedFields[9]=tmpAddress[3];
493    orderedFields[10]=tmpAddress[4];
494    orderedFields[11]=tmpAddress[5];
495    int oI=0;
496    for(oI=0;oI<12;oI++)
497      if((tmp2=getMap(tmp4->content,orderedFields[oI]))!=NULL){
498        if(strcmp(tmp2->name,"keywords")!=0 &&
499           strcmp(tmp2->name,"serverAddress")!=0 &&
500           strcmp(tmp2->name,"lang")!=0){
501          tmp2->name[0]=toupper(tmp2->name[0]);
502          if(strcmp(tmp2->name,"ProviderName")==0){
503            nc1 = xmlNewNode(ns_ows, BAD_CAST tmp2->name);
504            xmlAddChild(nc1,xmlNewText(BAD_CAST tmp2->value));
505            xmlAddChild(nc,nc1);
506          }
507          else{
508            if(strcmp(tmp2->name,"ProviderSite")==0){
509              nc1 = xmlNewNode(ns_ows, BAD_CAST tmp2->name);
510              xmlNewNsProp(nc1,ns_xlink,BAD_CAST "href",BAD_CAST tmp2->value);
511              xmlAddChild(nc,nc1);
512            } 
513            else 
514              if(strcmp(tmp2->name,"IndividualName")==0 || 
515                 strcmp(tmp2->name,"PositionName")==0){
516                nc1 = xmlNewNode(ns_ows, BAD_CAST tmp2->name);
517                xmlAddChild(nc1,xmlNewText(BAD_CAST tmp2->value));
518                xmlAddChild(nc3,nc1);
519              } 
520              else 
521                if(strncmp(tmp2->name,"Phone",5)==0){
522                  int j;
523                  for(j=0;j<2;j++)
524                    if(strcasecmp(tmp2->name,tmpPhone[j])==0){
525                      char *tmp4=tmp2->name;
526                      nc1 = xmlNewNode(ns_ows, BAD_CAST tmp4+5);
527                      xmlAddChild(nc1,xmlNewText(BAD_CAST tmp2->value));
528                      xmlAddChild(nc5,nc1);
529                    }
530                }
531                else 
532                  if(strncmp(tmp2->name,"Address",7)==0){
533                    int j;
534                    for(j=0;j<6;j++)
535                      if(strcasecmp(tmp2->name,tmpAddress[j])==0){
536                        char *tmp4=tmp2->name;
537                        nc1 = xmlNewNode(ns_ows, BAD_CAST tmp4+7);
538                        xmlAddChild(nc1,xmlNewText(BAD_CAST tmp2->value));
539                        xmlAddChild(nc6,nc1);
540                      }
541                  }
542          }
543        }
544        else
545          if(strcmp(tmp2->name,"keywords")==0){
546            nc1 = xmlNewNode(ns_ows, BAD_CAST "Keywords");
547            char *toto=tmp2->value;
548            char buff[256];
549            int i=0;
550            int j=0;
551            while(toto[i]){
552              if(toto[i]!=',' && toto[i]!=0){
553                buff[j]=toto[i];
554                buff[j+1]=0;
555                j++;
556              }
557              else{
558                nc2 = xmlNewNode(ns_ows, BAD_CAST "Keyword");
559                xmlAddChild(nc2,xmlNewText(BAD_CAST buff));           
560                xmlAddChild(nc1,nc2);
561                j=0;
562              }
563              i++;
564            }
565            if(strlen(buff)>0){
566              nc2 = xmlNewNode(ns_ows, BAD_CAST "Keyword");
567              xmlAddChild(nc2,xmlNewText(BAD_CAST buff));             
568              xmlAddChild(nc1,nc2);
569            }
570            xmlAddChild(nc,nc1);
571          }
572        tmp2=tmp2->next;
573      }
574  }
575  else{
576    fprintf(stderr,"TMP4 NOT FOUND !!");
577  }
578  xmlAddChild(nc4,nc5);
579  xmlAddChild(nc4,nc6);
580  xmlAddChild(nc3,nc4);
581  xmlAddChild(nc,nc3);
582  xmlAddChild(n,nc);
583
584
585  nc = xmlNewNode(ns_ows, BAD_CAST "OperationsMetadata");
586
587  int j=0;
588
589  if(toto1!=NULL){
590    map* tmp=getMap(toto1->content,"serverAddress");
591    if(tmp!=NULL){
592      SERVICE_URL = strdup(tmp->value);
593    }
594    else
595      SERVICE_URL = strdup("not_defined");
596  }
597  else
598    SERVICE_URL = strdup("not_defined");
599
600  for(j=0;j<nbSupportedRequests;j++){
601    if(requests[vid][j]==NULL)
602      break;
603    else{
604      nc1 = xmlNewNode(ns_ows, BAD_CAST "Operation");
605      xmlNewProp(nc1,BAD_CAST "name",BAD_CAST requests[vid][j]);
606      nc2 = xmlNewNode(ns_ows, BAD_CAST "DCP");
607      nc3 = xmlNewNode(ns_ows, BAD_CAST "HTTP");
608      if(vid!=1 || j!=2){
609        nc4 = xmlNewNode(ns_ows, BAD_CAST "Get");
610        xmlNewNsProp(nc4,ns_xlink,BAD_CAST "href",BAD_CAST SERVICE_URL);
611        xmlAddChild(nc3,nc4);
612      }
613      nc4 = xmlNewNode(ns_ows, BAD_CAST "Post");
614      xmlNewNsProp(nc4,ns_xlink,BAD_CAST "href",BAD_CAST SERVICE_URL);
615      xmlAddChild(nc3,nc4);
616      xmlAddChild(nc2,nc3);
617      xmlAddChild(nc1,nc2);
618      xmlAddChild(nc,nc1);
619    }
620  }
621  xmlAddChild(n,nc);
622
623  if(vid==1)
624    addLanguageNodes(m,n,ns,ns_ows);
625  free(SERVICE_URL);
626
627  nc = xmlNewNode(ns, BAD_CAST root_nodes[vid][0]);
628  xmlAddChild(n,nc);
629
630  if(vid==0)
631    addLanguageNodes(m,n,ns,ns_ows);
632
633  return nc;
634}
635
636/**
637 * Generate a wps:Process node for a servie and add it to a given node.
638 *
639 * @param reg the profiles registry
640 * @param m the conf maps containing the main.cfg settings
641 * @param registry the profile registry if any
642 * @param nc the XML node to add the Process node
643 * @param serv the service structure created from the zcfg file
644 * @return the generated wps:ProcessOfferings xmlNodePtr
645 */
646void printGetCapabilitiesForProcess(registry *reg, maps* m,xmlNodePtr nc,service* serv){
647  xmlNsPtr ns,ns_ows,ns_xml,ns_xlink;
648  xmlNodePtr n=NULL,nc1,nc2;
649  map* version=getMapFromMaps(m,"main","rversion");
650  int vid=getVersionId(version->value);
651  // Initialize or get existing namespaces
652  int wpsId=zooXmlAddNs(NULL,schemas[vid][2],"wps");
653  ns=usedNs[wpsId];
654  int owsId=zooXmlAddNs(NULL,schemas[vid][1],"ows");
655  ns_ows=usedNs[owsId];
656  int xmlId=zooXmlAddNs(NULL,"http://www.w3.org/XML/1998/namespace","xml");
657  ns_xml=usedNs[xmlId];
658  int xlinkId=zooXmlAddNs(n,"http://www.w3.org/1999/xlink","xlink");
659  ns_xlink=usedNs[xlinkId];
660  map* tmp1;
661  if(serv->content!=NULL){
662    nc1 = xmlNewNode(ns, BAD_CAST capabilities[vid][0]);
663    int i=1;
664    int limit=3;
665    if(vid==1){
666      ns=NULL;
667      limit=7;
668    }
669    for(;i<limit;i+=2){
670      if(capabilities[vid][i]==NULL)
671        break;
672      else{
673        tmp1=getMap(serv->content,capabilities[vid][i]);
674        if(tmp1!=NULL){
675          if(vid==1 && i==1 && strlen(tmp1->value)<5){
676            char *val=(char*)malloc((strlen(tmp1->value)+5)*sizeof(char));
677            sprintf(val,"%s.0.0",tmp1->value);
678            xmlNewNsProp(nc1,ns,BAD_CAST capabilities[vid][i],BAD_CAST val);
679            free(val);
680          }
681          else
682            xmlNewNsProp(nc1,ns,BAD_CAST capabilities[vid][i],BAD_CAST tmp1->value);
683        }
684        else
685          xmlNewNsProp(nc1,ns,BAD_CAST capabilities[vid][i],BAD_CAST capabilities[vid][i+1]);
686      }
687    }
688    map* tmp3=getMapFromMaps(m,"lenv","level");
689    addPrefix(m,tmp3,serv);
690    printDescription(nc1,ns_ows,serv->name,serv->content,vid);
691    tmp1=serv->metadata;
692    while(tmp1!=NULL){
693      nc2 = xmlNewNode(ns_ows, BAD_CAST "Metadata");
694      xmlNewNsProp(nc2,ns_xlink,BAD_CAST tmp1->name,BAD_CAST tmp1->value);
695      xmlAddChild(nc1,nc2);
696      tmp1=tmp1->next;
697    }
698
699    xmlAddChild(nc,nc1);
700  }
701}
702
703/**
704 * Attach attributes to a ProcessDescription or a ProcessOffering node.
705 *
706 * @param n the XML node to attach the attributes to
707 * @param ns the XML namespace to create the attributes
708 * @param content the servive main content created from the zcfg file
709 * @param vid the version identifier (0 for 1.0.0 and 1 for 2.0.0)
710 */
711void attachAttributes(xmlNodePtr n,xmlNsPtr ns,map* content,int vid){
712  int limit=(vid==1?7:3);
713  for(int i=1;i<limit;i+=2){
714    map* tmp1=getMap(content,capabilities[vid][i]);
715    if(tmp1!=NULL){
716      if(vid==1 && i==1 && strlen(tmp1->value)<5){
717        char *val=(char*)malloc((strlen(tmp1->value)+5)*sizeof(char));
718        sprintf(val,"%s.0.0",tmp1->value);
719        xmlNewNsProp(n,ns,BAD_CAST capabilities[vid][i],BAD_CAST val);
720        free(val);
721      }
722      else
723        xmlNewNsProp(n,ns,BAD_CAST capabilities[vid][i],BAD_CAST tmp1->value);
724    }
725    else
726      xmlNewNsProp(n,ns,BAD_CAST capabilities[vid][i],BAD_CAST capabilities[vid][i+1]);
727  }
728}
729
730/**
731 * Add the ows:Metadata nodes relative to the profile registry
732 *
733 * @param n the XML node to add the ows:Metadata
734 * @param ns_ows the ows XML namespace
735 * @param ns_xlink the ows xlink namespace
736 * @param reg the profile registry
737 * @param main_conf the map containing the main configuration content
738 * @param serv the service
739 */
740void addInheritedMetadata(xmlNodePtr n,xmlNsPtr ns_ows,xmlNsPtr ns_xlink,registry* reg,maps* main_conf,service* serv){
741  int vid=1;
742  map* tmp1=getMap(serv->content,"extend");
743  if(tmp1==NULL)
744    tmp1=getMap(serv->content,"concept");
745  if(tmp1!=NULL){
746    map* level=getMap(serv->content,"level");
747    if(level!=NULL){
748      xmlNodePtr nc1 = xmlNewNode(ns_ows, BAD_CAST "Metadata");
749      char* ckey=level->value;
750      if(strncasecmp(level->value,"profile",7)==0)
751        ckey="generic";
752      if(strncasecmp(level->value,"generic",7)==0)
753        ckey="concept";
754      service* inherited=getServiceFromRegistry(reg,ckey,tmp1->value);
755      if(inherited!=NULL){
756        addInheritedMetadata(n,ns_ows,ns_xlink,reg,main_conf,inherited);
757      }
758      char cschema[71];
759      sprintf(cschema,"%s%s",schemas[vid][7],ckey);
760      map* regUrl=getMapFromMaps(main_conf,"main","registryUrl");
761      map* regExt=getMapFromMaps(main_conf,"main","registryExt");
762      char* registryUrl=(char*)malloc((strlen(regUrl->value)+strlen(ckey)+
763                                       (regExt!=NULL?strlen(regExt->value)+1:0)+
764                                       strlen(tmp1->value)+2)*sizeof(char));
765      if(regExt!=NULL)
766        sprintf(registryUrl,"%s%s/%s.%s",regUrl->value,ckey,tmp1->value,regExt->value);
767      else
768        sprintf(registryUrl,"%s%s/%s",regUrl->value,ckey,tmp1->value);
769      xmlNewNsProp(nc1,ns_xlink,BAD_CAST "role",BAD_CAST cschema);
770      xmlNewNsProp(nc1,ns_xlink,BAD_CAST "href",BAD_CAST registryUrl);
771      free(registryUrl);
772      xmlAddChild(n,nc1);
773    }
774  }
775}
776
777/**
778 * Generate a ProcessDescription node for a servie and add it to a given node.
779 *
780 * @param reg the profile registry
781 * @param m the conf maps containing the main.cfg settings
782 * @param nc the XML node to add the Process node
783 * @param serv the servive structure created from the zcfg file
784 * @return the generated wps:ProcessOfferings xmlNodePtr
785 */
786void printDescribeProcessForProcess(registry *reg, maps* m,xmlNodePtr nc,service* serv){
787  xmlNsPtr ns,ns_ows,ns_xlink;
788  xmlNodePtr n,nc1,nc2;
789  map* version=getMapFromMaps(m,"main","rversion");
790  int vid=getVersionId(version->value);
791
792  n=nc;
793 
794  int wpsId=zooXmlAddNs(NULL,schemas[vid][3],"wps");
795  ns=usedNs[wpsId];
796  int owsId=zooXmlAddNs(NULL,schemas[vid][1],"ows");
797  ns_ows=usedNs[owsId];
798  int xlinkId=zooXmlAddNs(NULL,"http://www.w3.org/1999/xlink","xlink");
799  ns_xlink=usedNs[xlinkId];
800  map* tmp1=NULL;
801
802  if(vid==0){
803    nc = xmlNewNode(NULL, BAD_CAST "ProcessDescription");
804    attachAttributes(nc,ns,serv->content,vid);
805  }
806  else{
807    nc2 = xmlNewNode(ns, BAD_CAST "ProcessOffering");
808    // In case mode was defined in the ZCFG file then restrict the
809    // jobControlOptions value to this value. The dismiss is always
810    // supported whatever you can set in the ZCFG file.
811    // cf. http://docs.opengeospatial.org/is/14-065/14-065.html#47 (Table 30)
812    map* mode=getMap(serv->content,"mode");
813    if(mode!=NULL){
814      if( strncasecmp(mode->value,"sync",strlen(mode->value))==0 ||
815          strncasecmp(mode->value,"async",strlen(mode->value))==0 ){
816        char toReplace[22];
817        sprintf(toReplace,"%s-execute dismiss",mode->value);
818        addToMap(serv->content,capabilities[vid][3],toReplace);
819      }
820    }
821    attachAttributes(nc2,NULL,serv->content,vid);
822    map* level=getMap(serv->content,"level");
823    if(level!=NULL && strcasecmp(level->value,"generic")==0)
824      nc = xmlNewNode(ns, BAD_CAST "GenericProcess");
825    else
826      nc = xmlNewNode(ns, BAD_CAST "Process");
827  }
828 
829  tmp1=getMapFromMaps(m,"lenv","level");
830  addPrefix(m,tmp1,serv);
831  printDescription(nc,ns_ows,serv->name,serv->content,vid);
832
833  if(vid==0){
834    tmp1=serv->metadata;
835    while(tmp1!=NULL){
836      nc1 = xmlNewNode(ns_ows, BAD_CAST "Metadata");
837      xmlNewNsProp(nc1,ns_xlink,BAD_CAST tmp1->name,BAD_CAST tmp1->value);
838      xmlAddChild(nc,nc1);
839      tmp1=tmp1->next;
840    }
841    tmp1=getMap(serv->content,"Profile");
842    if(tmp1!=NULL && vid==0){
843      nc1 = xmlNewNode(ns, BAD_CAST "Profile");
844      xmlAddChild(nc1,xmlNewText(BAD_CAST tmp1->value));
845      xmlAddChild(nc,nc1);
846    }
847  }else{
848    addInheritedMetadata(nc,ns_ows,ns_xlink,reg,m,serv);
849  }
850
851  if(serv->inputs!=NULL){
852    elements* e=serv->inputs;
853    if(vid==0){
854      nc1 = xmlNewNode(NULL, BAD_CAST "DataInputs");
855      printFullDescription(1,e,"Input",ns,ns_ows,nc1,vid);
856      xmlAddChild(nc,nc1);
857    }
858    else{
859      printFullDescription(1,e,"wps:Input",ns,ns_ows,nc,vid);
860    }
861  }
862
863  elements* e=serv->outputs;
864  if(vid==0){
865    nc1 = xmlNewNode(NULL, BAD_CAST "ProcessOutputs");
866    printFullDescription(0,e,"Output",ns,ns_ows,nc1,vid);
867    xmlAddChild(nc,nc1);
868  }
869  else{
870    printFullDescription(0,e,"wps:Output",ns,ns_ows,nc,vid);
871  }
872  if(vid==0)
873    xmlAddChild(n,nc);
874  else{
875    xmlAddChild(nc2,nc);
876    xmlAddChild(n,nc2);
877  }
878
879}
880
881/**
882 * Generate the required XML tree for the detailled metadata informations of
883 * inputs or outputs
884 *
885 * @param in 1 in case of inputs, 0 for outputs
886 * @param elem the elements structure containing the metadata informations
887 * @param type the name ("Input" or "Output") of the XML node to create
888 * @param ns_ows the ows XML namespace
889 * @param ns_ows the ows XML namespace
890 * @param nc1 the XML node to use to add the created tree
891 * @param vid the WPS version id (0 for 1.0.0, 1 for 2.0.0)
892 */
893void printFullDescription(int in,elements *elem,const char* type,xmlNsPtr ns,xmlNsPtr ns_ows,xmlNodePtr nc1,int vid){
894  xmlNsPtr ns1=NULL;
895  if(vid==1)
896    ns1=ns;
897
898  xmlNodePtr nc2,nc3,nc4,nc5,nc6,nc7,nc8,nc9;
899  elements* e=elem;
900  nc9=NULL;
901  map* tmp1=NULL;
902  while(e!=NULL){
903    int default1=0;
904    int isAnyValue=1;
905    nc2 = xmlNewNode(NULL, BAD_CAST type);
906    if(strstr(type,"Input")!=NULL){
907      tmp1=getMap(e->content,"minOccurs");
908      if(tmp1!=NULL){
909        xmlNewProp(nc2,BAD_CAST tmp1->name,BAD_CAST tmp1->value);
910      }else
911        xmlNewProp(nc2,BAD_CAST "minOccurs",BAD_CAST "0");
912      tmp1=getMap(e->content,"maxOccurs");
913      if(tmp1!=NULL){
914        if(strcasecmp(tmp1->value,"unbounded")!=0)
915          xmlNewProp(nc2,BAD_CAST tmp1->name,BAD_CAST tmp1->value);
916        else
917          xmlNewProp(nc2,BAD_CAST "maxOccurs",BAD_CAST "1000");
918      }else
919        xmlNewProp(nc2,BAD_CAST "maxOccurs",BAD_CAST "1");
920      if((tmp1=getMap(e->content,"maximumMegabytes"))!=NULL){
921        xmlNewProp(nc2,BAD_CAST "maximumMegabytes",BAD_CAST tmp1->value);
922      }
923    }
924
925    printDescription(nc2,ns_ows,e->name,e->content,vid);
926
927    if(e->format!=NULL){
928      const char orderedFields[13][14]={
929        "mimeType",
930        "encoding",
931        "schema",
932        "dataType",
933        "uom",
934        "CRS",
935        "AllowedValues",
936        "range",
937        "rangeMin",
938        "rangeMax",
939        "rangeClosure",
940        "rangeSpace"
941      };
942
943      //Build the (Literal/Complex/BoundingBox)Data node
944      if(strncmp(type,"Output",6)==0){
945        if(strncasecmp(e->format,"LITERALDATA",strlen(e->format))==0)
946          nc3 = xmlNewNode(ns1, BAD_CAST "LiteralOutput");
947        else if(strncasecmp(e->format,"COMPLEXDATA",strlen(e->format))==0)
948          nc3 = xmlNewNode(ns1, BAD_CAST "ComplexOutput");
949        else if(strncasecmp(e->format,"BOUNDINGBOXDATA",strlen(e->format))==0)
950          nc3 = xmlNewNode(ns1, BAD_CAST "BoundingBoxOutput");
951        else
952          nc3 = xmlNewNode(ns1, BAD_CAST e->format);
953      }else{
954        if(strncasecmp(e->format,"LITERALDATA",strlen(e->format))==0 ||
955           strncasecmp(e->format,"LITERALOUTPUT",strlen(e->format))==0){
956          nc3 = xmlNewNode(ns1, BAD_CAST "LiteralData");
957        }
958        else if(strncasecmp(e->format,"COMPLEXDATA",strlen(e->format))==0)
959          nc3 = xmlNewNode(ns1, BAD_CAST "ComplexData");
960        else if(strncasecmp(e->format,"BOUNDINGBOXDATA",strlen(e->format))==0)
961          nc3 = xmlNewNode(ns1, BAD_CAST "BoundingBoxData");
962        else
963          nc3 = xmlNewNode(ns1, BAD_CAST e->format);
964      }
965
966      iotype* _tmp0=NULL;
967      iotype* _tmp=e->defaults;
968      int datatype=0;
969      bool hasUOM=false;
970      bool hasUOM1=false;
971      if(_tmp!=NULL){
972        if(strcmp(e->format,"LiteralOutput")==0 ||
973           strcmp(e->format,"LiteralData")==0){
974          datatype=1;
975          if(vid==1){
976            nc4 = xmlNewNode(ns1, BAD_CAST "Format");
977            xmlNewProp(nc4,BAD_CAST "mimeType",BAD_CAST "text/plain");
978            xmlNewProp(nc4,BAD_CAST "default",BAD_CAST "true");
979            xmlAddChild(nc3,nc4);
980            nc5 = xmlNewNode(NULL, BAD_CAST "LiteralDataDomain");
981            xmlNewProp(nc5,BAD_CAST "default",BAD_CAST "true");
982          }
983          else{
984            nc4 = xmlNewNode(NULL, BAD_CAST "UOMs");
985            nc5 = xmlNewNode(NULL, BAD_CAST "Default");
986          }
987        }
988        else if(strcmp(e->format,"BoundingBoxOutput")==0 ||
989                strcmp(e->format,"BoundingBoxData")==0){
990          datatype=2;
991          nc5 = xmlNewNode(NULL, BAD_CAST "Default");
992        }
993        else{
994          if(vid==0)
995            nc4 = xmlNewNode(NULL, BAD_CAST "Default");
996          nc5 = xmlNewNode(ns1, BAD_CAST "Format");
997          if(vid==1){
998            xmlNewProp(nc5,BAD_CAST "default",BAD_CAST "true");
999            int oI=0;
1000            for(oI=0;oI<3;oI++)
1001              if((tmp1=getMap(_tmp->content,orderedFields[oI]))!=NULL){
1002                xmlNewProp(nc5,BAD_CAST orderedFields[oI],BAD_CAST tmp1->value);
1003              }
1004          }
1005        }
1006     
1007        tmp1=_tmp->content;
1008
1009        if(vid==0)
1010          if((tmp1=getMap(_tmp->content,"DataType"))!=NULL){
1011            nc8 = xmlNewNode(ns_ows, BAD_CAST "DataType");
1012            xmlAddChild(nc8,xmlNewText(BAD_CAST tmp1->value));
1013            char tmp[1024];
1014            sprintf(tmp,"http://www.w3.org/TR/xmlschema-2/#%s",tmp1->value);
1015            xmlNewNsProp(nc8,ns_ows,BAD_CAST "reference",BAD_CAST tmp);
1016            if(vid==0)
1017              xmlAddChild(nc3,nc8);
1018            else
1019              xmlAddChild(nc5,nc8);
1020            datatype=1;
1021          }
1022
1023        bool isInput=false;
1024        if(strncmp(type,"Input",5)==0 || strncmp(type,"wps:Input",9)==0){
1025          isInput=true;
1026          if((tmp1=getMap(_tmp->content,"AllowedValues"))!=NULL){
1027            nc6 = xmlNewNode(ns_ows, BAD_CAST "AllowedValues");
1028            char *token,*saveptr1;
1029            token=strtok_r(tmp1->value,",",&saveptr1);
1030            while(token!=NULL){
1031              nc7 = xmlNewNode(ns_ows, BAD_CAST "Value");
1032              char *tmps=strdup(token);
1033              tmps[strlen(tmps)]=0;
1034              xmlAddChild(nc7,xmlNewText(BAD_CAST tmps));
1035              free(tmps);
1036              xmlAddChild(nc6,nc7);
1037              token=strtok_r(NULL,",",&saveptr1);
1038            }
1039            if(getMap(_tmp->content,"range")!=NULL ||
1040               getMap(_tmp->content,"rangeMin")!=NULL ||
1041               getMap(_tmp->content,"rangeMax")!=NULL ||
1042               getMap(_tmp->content,"rangeClosure")!=NULL )
1043              goto doRange;
1044            if(vid==0)
1045              xmlAddChild(nc3,nc6);
1046            else
1047              xmlAddChild(nc5,nc6);
1048            isAnyValue=-1;
1049          }
1050
1051          tmp1=getMap(_tmp->content,"range");
1052          if(tmp1==NULL)
1053            tmp1=getMap(_tmp->content,"rangeMin");
1054          if(tmp1==NULL)
1055            tmp1=getMap(_tmp->content,"rangeMax");
1056       
1057          if(tmp1!=NULL && isAnyValue==1){
1058            nc6 = xmlNewNode(ns_ows, BAD_CAST "AllowedValues");
1059          doRange:
1060         
1061            /**
1062             * Range: Table 46 OGC Web Services Common Standard
1063             */
1064            nc8 = xmlNewNode(ns_ows, BAD_CAST "Range");
1065         
1066            map* tmp0=getMap(tmp1,"range");
1067            if(tmp0!=NULL){
1068              char* pToken;
1069              char* orig=zStrdup(tmp0->value);
1070              /**
1071               * RangeClosure: Table 47 OGC Web Services Common Standard
1072               */
1073              const char *tmp="closed";
1074              if(orig[0]=='[' && orig[strlen(orig)-1]=='[')
1075                tmp="closed-open";
1076              else
1077                if(orig[0]==']' && orig[strlen(orig)-1]==']')
1078                  tmp="open-closed";
1079                else
1080                  if(orig[0]==']' && orig[strlen(orig)-1]=='[')
1081                    tmp="open";
1082              xmlNewNsProp(nc8,ns_ows,BAD_CAST "rangeClosure",BAD_CAST tmp);
1083              pToken=strtok(orig,",");
1084              int nci0=0;
1085              while(pToken!=NULL){
1086                char *tmpStr=(char*) malloc((strlen(pToken))*sizeof(char));
1087                if(nci0==0){
1088                  nc7 = xmlNewNode(ns_ows, BAD_CAST "MinimumValue");
1089                  strncpy( tmpStr, pToken+1, strlen(pToken)-1 );
1090                  tmpStr[strlen(pToken)-1] = '\0';
1091                }else{
1092                  nc7 = xmlNewNode(ns_ows, BAD_CAST "MaximumValue");
1093                  const char* bkt;
1094                  if ( ( bkt = strchr(pToken, '[') ) != NULL || ( bkt = strchr(pToken, ']') ) != NULL ){
1095                    strncpy( tmpStr, pToken, bkt - pToken );
1096                    tmpStr[bkt - pToken] = '\0';
1097                  }
1098                }
1099                xmlAddChild(nc7,xmlNewText(BAD_CAST tmpStr));
1100                free(tmpStr);
1101                xmlAddChild(nc8,nc7);
1102                nci0++;
1103                pToken = strtok(NULL,",");
1104              }             
1105              if(getMap(tmp1,"rangeSpacing")==NULL){
1106                nc7 = xmlNewNode(ns_ows, BAD_CAST "Spacing");
1107                xmlAddChild(nc7,xmlNewText(BAD_CAST "1"));
1108                xmlAddChild(nc8,nc7);
1109              }
1110              free(orig);
1111            }else{
1112           
1113              tmp0=getMap(tmp1,"rangeMin");
1114              if(tmp0!=NULL){
1115                nc7 = xmlNewNode(ns_ows, BAD_CAST "MinimumValue");
1116                xmlAddChild(nc7,xmlNewText(BAD_CAST tmp0->value));
1117                xmlAddChild(nc8,nc7);
1118              }else{
1119                nc7 = xmlNewNode(ns_ows, BAD_CAST "MinimumValue");
1120                xmlAddChild(nc8,nc7);
1121              }
1122              tmp0=getMap(tmp1,"rangeMax");
1123              if(tmp0!=NULL){
1124                nc7 = xmlNewNode(ns_ows, BAD_CAST "MaximumValue");
1125                xmlAddChild(nc7,xmlNewText(BAD_CAST tmp0->value));
1126                xmlAddChild(nc8,nc7);
1127              }else{
1128                nc7 = xmlNewNode(ns_ows, BAD_CAST "MaximumValue");
1129                xmlAddChild(nc8,nc7);
1130              }
1131              tmp0=getMap(tmp1,"rangeSpacing");
1132              if(tmp0!=NULL){
1133                nc7 = xmlNewNode(ns_ows, BAD_CAST "Spacing");
1134                xmlAddChild(nc7,xmlNewText(BAD_CAST tmp0->value));
1135                xmlAddChild(nc8,nc7);
1136              }
1137              tmp0=getMap(tmp1,"rangeClosure");
1138              if(tmp0!=NULL){
1139                const char *tmp="closed";
1140                if(strcasecmp(tmp0->value,"co")==0)
1141                  tmp="closed-open";
1142                else
1143                  if(strcasecmp(tmp0->value,"oc")==0)
1144                    tmp="open-closed";
1145                  else
1146                    if(strcasecmp(tmp0->value,"o")==0)
1147                      tmp="open";
1148                xmlNewNsProp(nc8,ns_ows,BAD_CAST "rangeClosure",BAD_CAST tmp);
1149              }else
1150                xmlNewNsProp(nc8,ns_ows,BAD_CAST "rangeClosure",BAD_CAST "closed");
1151            }
1152            if(_tmp0==NULL){
1153              xmlAddChild(nc6,nc8);
1154              _tmp0=e->supported;
1155              if(_tmp0!=NULL &&
1156                 (getMap(_tmp0->content,"range")!=NULL ||
1157                  getMap(_tmp0->content,"rangeMin")!=NULL ||
1158                  getMap(_tmp0->content,"rangeMax")!=NULL ||
1159                  getMap(_tmp0->content,"rangeClosure")!=NULL )){
1160                tmp1=_tmp0->content;
1161                goto doRange;
1162              }
1163            }else{
1164              _tmp0=_tmp0->next;
1165              if(_tmp0!=NULL){
1166                xmlAddChild(nc6,nc8);
1167                if(getMap(_tmp0->content,"range")!=NULL ||
1168                   getMap(_tmp0->content,"rangeMin")!=NULL ||
1169                   getMap(_tmp0->content,"rangeMax")!=NULL ||
1170                   getMap(_tmp0->content,"rangeClosure")!=NULL ){
1171                  tmp1=_tmp0->content;
1172                  goto doRange;
1173                }
1174              }
1175            }
1176            xmlAddChild(nc6,nc8);
1177            if(vid==0)
1178              xmlAddChild(nc3,nc6);
1179            else
1180              xmlAddChild(nc5,nc6);
1181            isAnyValue=-1;
1182          }
1183       
1184        }
1185     
1186        int oI=0;
1187        /*if(vid==0)*/ {
1188          for(oI=0;oI<13;oI++)
1189            if((tmp1=getMap(_tmp->content,orderedFields[oI]))!=NULL){
1190#ifdef DEBUG
1191              printf("DATATYPE DEFAULT ? %s\n",tmp1->name);
1192#endif
1193              if(strcmp(tmp1->name,"asReference")!=0 &&
1194                 strncasecmp(tmp1->name,"DataType",8)!=0 &&
1195                 strcasecmp(tmp1->name,"extension")!=0 &&
1196                 strcasecmp(tmp1->name,"value")!=0 &&
1197                 strcasecmp(tmp1->name,"AllowedValues")!=0 &&
1198                 strncasecmp(tmp1->name,"range",5)!=0){
1199                if(datatype!=1){
1200                  char *tmp2=zCapitalize1(tmp1->name);
1201                  nc9 = xmlNewNode(NULL, BAD_CAST tmp2);
1202                  free(tmp2);
1203                }
1204                else{
1205                  char *tmp2=zCapitalize(tmp1->name);
1206                  nc9 = xmlNewNode(ns_ows, BAD_CAST tmp2);
1207                  free(tmp2);
1208                }
1209                xmlAddChild(nc9,xmlNewText(BAD_CAST tmp1->value));
1210                if(vid==0 || oI>=3){
1211                  if(vid==0 || oI!=4)
1212                    xmlAddChild(nc5,nc9);
1213                  if(oI==4 && vid==1){
1214                    xmlNewProp(nc9,BAD_CAST "default",BAD_CAST "true");
1215                  }
1216                }
1217                else
1218                  xmlFree(nc9);
1219                if(strcasecmp(tmp1->name,"uom")==0)
1220                  hasUOM1=true;
1221                hasUOM=true;
1222              }else       
1223                tmp1=tmp1->next;
1224            }
1225        }
1226   
1227        if(datatype!=2){
1228          if(hasUOM==true){
1229            if(vid==0){
1230              xmlAddChild(nc4,nc5);
1231              xmlAddChild(nc3,nc4);
1232            }
1233            else{
1234              xmlAddChild(nc3,nc5);
1235            }
1236          }else{
1237            if(hasUOM1==false && vid==0){
1238              xmlFreeNode(nc5);
1239              if(datatype==1)
1240                xmlFreeNode(nc4);
1241            }
1242            else
1243              xmlAddChild(nc3,nc5);
1244          }
1245        }else{
1246          xmlAddChild(nc3,nc5);
1247        }
1248     
1249        if(datatype!=1 && default1<0){
1250          xmlFreeNode(nc5);
1251          if(datatype!=2)
1252            xmlFreeNode(nc4);
1253        }
1254
1255
1256        if((isInput || vid==1) && datatype==1 &&
1257           getMap(_tmp->content,"AllowedValues")==NULL &&
1258           getMap(_tmp->content,"range")==NULL &&
1259           getMap(_tmp->content,"rangeMin")==NULL &&
1260           getMap(_tmp->content,"rangeMax")==NULL &&
1261           getMap(_tmp->content,"rangeClosure")==NULL ){
1262          tmp1=getMap(_tmp->content,"dataType");
1263          // We were tempted to define default value for boolean as {true,false}
1264          if(tmp1!=NULL && strcasecmp(tmp1->value,"boolean")==0){
1265            nc6 = xmlNewNode(ns_ows, BAD_CAST "AllowedValues");
1266            nc7 = xmlNewNode(ns_ows, BAD_CAST "Value");
1267            xmlAddChild(nc7,xmlNewText(BAD_CAST "true"));
1268            xmlAddChild(nc6,nc7);
1269            nc7 = xmlNewNode(ns_ows, BAD_CAST "Value");
1270            xmlAddChild(nc7,xmlNewText(BAD_CAST "false"));
1271            xmlAddChild(nc6,nc7);
1272            if(vid==0)
1273              xmlAddChild(nc3,nc6);
1274            else
1275              xmlAddChild(nc5,nc6);
1276          }
1277          else
1278            if(vid==0)
1279              xmlAddChild(nc3,xmlNewNode(ns_ows, BAD_CAST "AnyValue"));
1280            else
1281              xmlAddChild(nc5,xmlNewNode(ns_ows, BAD_CAST "AnyValue"));
1282        }
1283
1284        if(vid==1){
1285          if((tmp1=getMap(_tmp->content,"DataType"))!=NULL){
1286            nc8 = xmlNewNode(ns_ows, BAD_CAST "DataType");
1287            xmlAddChild(nc8,xmlNewText(BAD_CAST tmp1->value));
1288            char tmp[1024];
1289            sprintf(tmp,"http://www.w3.org/TR/xmlschema-2/#%s",tmp1->value);
1290            xmlNewNsProp(nc8,ns_ows,BAD_CAST "reference",BAD_CAST tmp);
1291            if(vid==0)
1292              xmlAddChild(nc3,nc8);
1293            else
1294              xmlAddChild(nc5,nc8);
1295            datatype=1;
1296          }
1297          if(hasUOM==true){
1298            tmp1=getMap(_tmp->content,"uom");
1299            if(tmp1!=NULL){
1300              char *tmp2=zCapitalize(tmp1->name);
1301              nc9 = xmlNewNode(ns_ows, BAD_CAST tmp2);
1302              free(tmp2);
1303              //xmlNewProp(nc9, BAD_CAST "default", BAD_CAST "true");
1304              xmlAddChild(nc9,xmlNewText(BAD_CAST tmp1->value));
1305              xmlAddChild(nc5,nc9);
1306              /*struct iotype * _ltmp=e->supported;
1307                while(_ltmp!=NULL){
1308                tmp1=getMap(_ltmp->content,"uom");
1309                if(tmp1!=NULL){
1310                char *tmp2=zCapitalize(tmp1->name);
1311                nc9 = xmlNewNode(ns_ows, BAD_CAST tmp2);
1312                free(tmp2);
1313                xmlAddChild(nc9,xmlNewText(BAD_CAST tmp1->value));
1314                xmlAddChild(nc5,nc9);
1315                }
1316                _ltmp=_ltmp->next;
1317                }*/
1318           
1319            }
1320          }
1321          if(e->defaults!=NULL && (tmp1=getMap(e->defaults->content,"value"))!=NULL){
1322            nc7 = xmlNewNode(ns_ows, BAD_CAST "DefaultValue");
1323            xmlAddChild(nc7,xmlNewText(BAD_CAST tmp1->value));
1324            xmlAddChild(nc5,nc7);
1325          }
1326        }
1327
1328        map* metadata=e->metadata;
1329        xmlNodePtr n=NULL;
1330        int xlinkId=zooXmlAddNs(n,"http://www.w3.org/1999/xlink","xlink");
1331        xmlNsPtr ns_xlink=usedNs[xlinkId];
1332
1333        while(metadata!=NULL){
1334          nc6=xmlNewNode(ns_ows, BAD_CAST "Metadata");
1335          xmlNewNsProp(nc6,ns_xlink,BAD_CAST metadata->name,BAD_CAST metadata->value);
1336          xmlAddChild(nc2,nc6);
1337          metadata=metadata->next;
1338        }
1339
1340      }
1341
1342      _tmp=e->supported;
1343      if(_tmp==NULL && datatype!=1)
1344        _tmp=e->defaults;
1345
1346      int hasSupported=-1;
1347
1348      while(_tmp!=NULL){
1349        if(hasSupported<0){
1350          if(datatype==0){
1351            if(vid==0)
1352              nc4 = xmlNewNode(NULL, BAD_CAST "Supported");
1353            nc5 = xmlNewNode(ns1, BAD_CAST "Format");
1354            if(vid==1){
1355              int oI=0;
1356              for(oI=0;oI<3;oI++)
1357                if((tmp1=getMap(_tmp->content,orderedFields[oI]))!=NULL){
1358                  xmlNewProp(nc5,BAD_CAST orderedFields[oI],BAD_CAST tmp1->value);
1359                }
1360            }
1361          }
1362          else
1363            if(vid==0)
1364              nc5 = xmlNewNode(NULL, BAD_CAST "Supported");
1365          hasSupported=0;
1366        }else
1367          if(datatype==0){
1368            nc5 = xmlNewNode(ns1, BAD_CAST "Format");
1369            if(vid==1){
1370              int oI=0;
1371              for(oI=0;oI<3;oI++)
1372                if((tmp1=getMap(_tmp->content,orderedFields[oI]))!=NULL){
1373                  xmlNewProp(nc5,BAD_CAST orderedFields[oI],BAD_CAST tmp1->value);
1374                }
1375            }
1376          }
1377        tmp1=_tmp->content;
1378        int oI=0;
1379        for(oI=0;oI<6;oI++)
1380          if((tmp1=getMap(_tmp->content,orderedFields[oI]))!=NULL){
1381#ifdef DEBUG
1382            printf("DATATYPE SUPPORTED ? %s\n",tmp1->name);
1383#endif
1384            if(strcmp(tmp1->name,"asReference")!=0 && 
1385               strcmp(tmp1->name,"value")!=0 && 
1386               strcmp(tmp1->name,"DataType")!=0 &&
1387               strcasecmp(tmp1->name,"extension")!=0){
1388              if(datatype!=1){
1389                char *tmp2=zCapitalize1(tmp1->name);
1390                nc6 = xmlNewNode(NULL, BAD_CAST tmp2);
1391                free(tmp2);
1392              }
1393              else{
1394                char *tmp2=zCapitalize(tmp1->name);
1395                nc6 = xmlNewNode(ns_ows, BAD_CAST tmp2);
1396                free(tmp2);
1397              }
1398              if(datatype==2){
1399                char *tmpv,*tmps;
1400                tmps=strtok_r(tmp1->value,",",&tmpv);
1401                while(tmps){
1402                  xmlAddChild(nc6,xmlNewText(BAD_CAST tmps));
1403                  tmps=strtok_r(NULL,",",&tmpv);
1404                  if(tmps){
1405                    char *tmp2=zCapitalize1(tmp1->name);
1406                    nc6 = xmlNewNode(NULL, BAD_CAST tmp2);
1407                    free(tmp2);
1408                  }
1409                }
1410              }
1411              else{
1412                xmlAddChild(nc6,xmlNewText(BAD_CAST tmp1->value));
1413              }
1414              if(vid==0 || oI>=3){
1415                if(vid==0 || oI!=4)
1416                  xmlAddChild(nc5,nc6);
1417                else
1418                  xmlFree(nc6);
1419              }
1420              else
1421                xmlFree(nc6);
1422            }
1423            tmp1=tmp1->next;
1424          }
1425        if(hasSupported<=0){
1426          if(datatype==0){
1427            if(vid==0){
1428              xmlAddChild(nc4,nc5);
1429              xmlAddChild(nc3,nc4);
1430            }
1431            else{
1432              xmlAddChild(nc3,nc5);
1433            }
1434
1435          }else{
1436            if(datatype!=1)
1437              xmlAddChild(nc3,nc5);
1438          }
1439          hasSupported=1;
1440        }
1441        else
1442          if(datatype==0){
1443            if(vid==0){
1444              xmlAddChild(nc4,nc5);
1445              xmlAddChild(nc3,nc4);
1446            }
1447            else{
1448              xmlAddChild(nc3,nc5);
1449            }
1450          }
1451          else
1452            if(datatype!=1)
1453              xmlAddChild(nc3,nc5);
1454
1455        _tmp=_tmp->next;
1456      }
1457
1458      if(hasSupported==0){
1459        if(datatype==0 && vid!=0)
1460          xmlFreeNode(nc4);
1461        xmlFreeNode(nc5);
1462      }
1463
1464      _tmp=e->defaults;
1465      if(datatype==1 && hasUOM1==true){
1466        if(vid==0){
1467          xmlAddChild(nc4,nc5);
1468          xmlAddChild(nc3,nc4);
1469        }
1470        else{
1471          xmlAddChild(nc3,nc5);
1472        }
1473      }
1474
1475      if(vid==0 && _tmp!=NULL && (tmp1=getMap(_tmp->content,"value"))!=NULL){
1476        nc7 = xmlNewNode(NULL, BAD_CAST "DefaultValue");
1477        xmlAddChild(nc7,xmlNewText(BAD_CAST tmp1->value));
1478        xmlAddChild(nc3,nc7);
1479      }
1480   
1481      xmlAddChild(nc2,nc3);
1482    }
1483   
1484    xmlAddChild(nc1,nc2);
1485   
1486    e=e->next;
1487  }
1488}
1489
1490/**
1491 * Generate a wps:Execute XML document.
1492 *
1493 * @param m the conf maps containing the main.cfg settings
1494 * @param request the map representing the HTTP request
1495 * @param pid the process identifier linked to a service
1496 * @param serv the serv structure created from the zcfg file
1497 * @param service the service name
1498 * @param status the status returned by the service
1499 * @param inputs the inputs provided
1500 * @param outputs the outputs generated by the service
1501 */
1502void printProcessResponse(maps* m,map* request, int pid,service* serv,const char* service,int status,maps* inputs,maps* outputs){
1503  xmlNsPtr ns,ns_ows,ns_xlink;
1504  xmlNodePtr nr,n,nc,nc1=NULL,nc3;
1505  xmlDocPtr doc;
1506  time_t time1; 
1507  time(&time1);
1508  nr=NULL;
1509
1510  doc = xmlNewDoc(BAD_CAST "1.0");
1511  map* version=getMapFromMaps(m,"main","rversion");
1512  int vid=getVersionId(version->value);
1513  n = printWPSHeader(doc,m,"Execute",root_nodes[vid][2],(version!=NULL?version->value:"1.0.0"),2);
1514  int wpsId=zooXmlAddNs(NULL,schemas[vid][2],"wps");
1515  ns=usedNs[wpsId];
1516  int owsId=zooXmlAddNs(NULL,schemas[vid][1],"ows");
1517  ns_ows=usedNs[owsId];
1518  int xlinkId=zooXmlAddNs(NULL,"http://www.w3.org/1999/xlink","xlink");
1519  ns_xlink=usedNs[xlinkId];
1520  bool hasStoredExecuteResponse=false;
1521  char stored_path[1024];
1522  memset(stored_path,0,1024);
1523   
1524  if(vid==0){
1525    char tmp[256];
1526    char url[1024];
1527    memset(tmp,0,256);
1528    memset(url,0,1024);
1529    maps* tmp_maps=getMaps(m,"main");
1530    if(tmp_maps!=NULL){
1531      map* tmpm1=getMap(tmp_maps->content,"serverAddress");
1532      /**
1533       * Check if the ZOO Service GetStatus is available in the local directory.
1534       * If yes, then it uses a reference to an URL which the client can access
1535       * to get information on the status of a running Service (using the
1536       * percentCompleted attribute).
1537       * Else fallback to the initial method using the xml file to write in ...
1538       */
1539      char ntmp[1024];
1540#ifndef WIN32
1541      getcwd(ntmp,1024);
1542#else
1543      _getcwd(ntmp,1024);
1544#endif
1545      struct stat myFileInfo;
1546      int statRes;
1547      char file_path[1024];
1548      sprintf(file_path,"%s/GetStatus.zcfg",ntmp);
1549      statRes=stat(file_path,&myFileInfo);
1550      if(statRes==0){
1551        char currentSid[128];
1552        map* tmpm=getMap(tmp_maps->content,"rewriteUrl");
1553        map *tmp_lenv=NULL;
1554        tmp_lenv=getMapFromMaps(m,"lenv","usid");
1555        if(tmp_lenv==NULL)
1556          sprintf(currentSid,"%i",pid);
1557        else
1558          sprintf(currentSid,"%s",tmp_lenv->value);
1559        if(tmpm==NULL || strcasecmp(tmpm->value,"false")==0){
1560          sprintf(url,"%s?request=Execute&service=WPS&version=1.0.0&Identifier=GetStatus&DataInputs=sid=%s&RawDataOutput=Result",tmpm1->value,currentSid);
1561        }else{
1562          if(strlen(tmpm->value)>0)
1563            if(strcasecmp(tmpm->value,"true")!=0)
1564              sprintf(url,"%s/%s/GetStatus/%s",tmpm1->value,tmpm->value,currentSid);
1565            else
1566              sprintf(url,"%s/GetStatus/%s",tmpm1->value,currentSid);
1567          else
1568            sprintf(url,"%s/?request=Execute&service=WPS&version=1.0.0&Identifier=GetStatus&DataInputs=sid=%s&RawDataOutput=Result",tmpm1->value,currentSid);
1569        }
1570      }else{
1571        int lpid;
1572        map* tmpm2=getMapFromMaps(m,"lenv","usid");
1573        map* tmpm3=getMap(tmp_maps->content,"tmpUrl");
1574        if(tmpm1!=NULL && tmpm3!=NULL){
1575          if( strncasecmp( tmpm3->value, "http://", 7) == 0 ||
1576              strncasecmp( tmpm3->value, "https://", 8 ) == 0 ){
1577            sprintf(url,"%s/%s_%s.xml",tmpm3->value,service,tmpm2->value);
1578          }else
1579            sprintf(url,"%s/%s_%s.xml",tmpm1->value,service,tmpm2->value);
1580        }
1581      }
1582      if(tmpm1!=NULL){
1583        sprintf(tmp,"%s",tmpm1->value);
1584      }
1585      int lpid;
1586      map* tmpm2=getMapFromMaps(m,"lenv","usid");
1587      tmpm1=getMapFromMaps(m,"main","TmpPath");
1588      sprintf(stored_path,"%s/%s_%s.xml",tmpm1->value,service,tmpm2->value);
1589    }
1590
1591    xmlNewProp(n,BAD_CAST "serviceInstance",BAD_CAST tmp);
1592    map* test=getMap(request,"storeExecuteResponse");
1593    if(test!=NULL && strcasecmp(test->value,"true")==0){
1594      xmlNewProp(n,BAD_CAST "statusLocation",BAD_CAST url);
1595      hasStoredExecuteResponse=true;
1596    }
1597
1598    nc = xmlNewNode(ns, BAD_CAST "Process");
1599    map* tmp2=getMap(serv->content,"processVersion");
1600    if(tmp2!=NULL)
1601      xmlNewNsProp(nc,ns,BAD_CAST "processVersion",BAD_CAST tmp2->value);
1602 
1603    map* tmpI=getMapFromMaps(m,"lenv","oIdentifier");
1604    printDescription(nc,ns_ows,tmpI->value,serv->content,0);
1605
1606    xmlAddChild(n,nc);
1607
1608    nc = xmlNewNode(ns, BAD_CAST "Status");
1609    const struct tm *tm;
1610    size_t len;
1611    time_t now;
1612    char *tmp1;
1613    map *tmpStatus;
1614 
1615    now = time ( NULL );
1616    tm = localtime ( &now );
1617
1618    tmp1 = (char*)malloc((TIME_SIZE+1)*sizeof(char));
1619
1620    len = strftime ( tmp1, TIME_SIZE, "%Y-%m-%dT%I:%M:%SZ", tm );
1621
1622    xmlNewProp(nc,BAD_CAST "creationTime",BAD_CAST tmp1);
1623
1624    char sMsg[2048];
1625    switch(status){
1626    case SERVICE_SUCCEEDED:
1627      nc1 = xmlNewNode(ns, BAD_CAST "ProcessSucceeded");
1628      sprintf(sMsg,_("The service \"%s\" ran successfully."),serv->name);
1629      nc3=xmlNewText(BAD_CAST sMsg);
1630      xmlAddChild(nc1,nc3);
1631      break;
1632    case SERVICE_STARTED:
1633      nc1 = xmlNewNode(ns, BAD_CAST "ProcessStarted");
1634      tmpStatus=getMapFromMaps(m,"lenv","status");
1635      xmlNewProp(nc1,BAD_CAST "percentCompleted",BAD_CAST tmpStatus->value);
1636      sprintf(sMsg,_("The ZOO service \"%s\" is currently running. Please reload this document to get the up-to-date status of the service."),serv->name);
1637      nc3=xmlNewText(BAD_CAST sMsg);
1638      xmlAddChild(nc1,nc3);
1639      break;
1640    case SERVICE_ACCEPTED:
1641      nc1 = xmlNewNode(ns, BAD_CAST "ProcessAccepted");
1642      sprintf(sMsg,_("The service \"%s\" was accepted by the ZOO kernel and is running as a background task. Please access the URL in the statusLocation attribute provided in this document to get the up-to-date status and results."),serv->name);
1643      nc3=xmlNewText(BAD_CAST sMsg);
1644      xmlAddChild(nc1,nc3);
1645      break;
1646    case SERVICE_FAILED:
1647      nc1 = xmlNewNode(ns, BAD_CAST "ProcessFailed");
1648      map *errorMap;
1649      map *te;
1650      te=getMapFromMaps(m,"lenv","code");
1651      if(te!=NULL)
1652        errorMap=createMap("code",te->value);
1653      else
1654        errorMap=createMap("code","NoApplicableCode");
1655      te=getMapFromMaps(m,"lenv","message");
1656      if(te!=NULL)
1657        addToMap(errorMap,"text",_ss(te->value));
1658      else
1659        addToMap(errorMap,"text",_("No more information available"));
1660      nc3=createExceptionReportNode(m,errorMap,0);
1661      freeMap(&errorMap);
1662      free(errorMap);
1663      xmlAddChild(nc1,nc3);
1664      break;
1665    default :
1666      printf(_("error code not know : %i\n"),status);
1667      //exit(1);
1668      break;
1669    }
1670    xmlAddChild(nc,nc1);
1671    xmlAddChild(n,nc);
1672    free(tmp1);
1673
1674#ifdef DEBUG
1675    fprintf(stderr,"printProcessResponse %d\n",__LINE__);
1676#endif
1677
1678    map* lineage=getMap(request,"lineage");
1679    if(lineage!=NULL && strcasecmp(lineage->value,"true")==0){
1680      nc = xmlNewNode(ns, BAD_CAST "DataInputs");
1681      maps* mcursor=inputs;
1682      elements* scursor=NULL;
1683      while(mcursor!=NULL /*&& scursor!=NULL*/){
1684        scursor=getElements(serv->inputs,mcursor->name);
1685        printIOType(doc,nc,ns,ns_ows,ns_xlink,scursor,mcursor,"Input",vid);
1686        mcursor=mcursor->next;
1687      }
1688      xmlAddChild(n,nc);
1689
1690      nc = xmlNewNode(ns, BAD_CAST "OutputDefinitions");
1691      mcursor=outputs;
1692      scursor=NULL;
1693      while(mcursor!=NULL){
1694        scursor=getElements(serv->outputs,mcursor->name);
1695        printOutputDefinitions(doc,nc,ns,ns_ows,scursor,mcursor,"Output");
1696        mcursor=mcursor->next;
1697      }
1698      xmlAddChild(n,nc);
1699    }
1700  }
1701
1702  /**
1703   * Display the process output only when requested !
1704   */
1705  if(status==SERVICE_SUCCEEDED){
1706    if(vid==0){
1707      nc = xmlNewNode(ns, BAD_CAST "ProcessOutputs");
1708    }
1709    maps* mcursor=outputs;
1710    elements* scursor=serv->outputs;
1711    map* testResponse=getMap(request,"RawDataOutput");
1712    if(testResponse==NULL)
1713      testResponse=getMap(request,"ResponseDocument");
1714    while(mcursor!=NULL){
1715      map* tmp0=getMap(mcursor->content,"inRequest");
1716      scursor=getElements(serv->outputs,mcursor->name);
1717      if(scursor!=NULL){
1718        if(testResponse==NULL || tmp0==NULL){
1719          if(vid==0)
1720            printIOType(doc,nc,ns,ns_ows,ns_xlink,scursor,mcursor,"Output",vid);
1721          else
1722            printIOType(doc,n,ns,ns_ows,ns_xlink,scursor,mcursor,"Output",vid);
1723        }
1724        else
1725
1726          if(tmp0!=NULL && strncmp(tmp0->value,"true",4)==0){
1727            if(vid==0)
1728              printIOType(doc,nc,ns,ns_ows,ns_xlink,scursor,mcursor,"Output",vid);
1729            else
1730              printIOType(doc,n,ns,ns_ows,ns_xlink,scursor,mcursor,"Output",vid);
1731          }
1732      }else
1733        /**
1734         * In case there was no definition found in the ZCFG file but
1735         * present in the service code
1736         */
1737        if(vid==0)
1738          printIOType(doc,nc,ns,ns_ows,ns_xlink,scursor,mcursor,"Output",vid);
1739        else
1740          printIOType(doc,n,ns,ns_ows,ns_xlink,scursor,mcursor,"Output",vid);
1741      mcursor=mcursor->next;
1742    }
1743    if(vid==0)
1744      xmlAddChild(n,nc);
1745  }
1746 
1747  if(vid==0 && 
1748     hasStoredExecuteResponse==true 
1749     && status!=SERVICE_STARTED
1750#ifndef WIN32
1751     && status!=SERVICE_ACCEPTED
1752#endif
1753     ){
1754#ifndef RELY_ON_DB
1755    semid lid=acquireLock(m);//,1);
1756    if(lid<0){
1757      /* If the lock failed */
1758      errorException(m,_("Lock failed."),"InternalError",NULL);
1759      xmlFreeDoc(doc);
1760      xmlCleanupParser();
1761      zooXmlCleanupNs();
1762      return;
1763    }
1764    else{
1765#endif
1766      /* We need to write the ExecuteResponse Document somewhere */
1767      FILE* output=fopen(stored_path,"w");
1768      if(output==NULL){
1769        /* If the file cannot be created return an ExceptionReport */
1770        char tmpMsg[1024];
1771        sprintf(tmpMsg,_("Unable to create the file \"%s\" for storing the ExecuteResponse."),stored_path);
1772
1773        errorException(m,tmpMsg,"InternalError",NULL);
1774        xmlFreeDoc(doc);
1775        xmlCleanupParser();
1776        zooXmlCleanupNs();
1777#ifndef RELY_ON_DB
1778        unlockShm(lid);
1779#endif
1780        return;
1781      }
1782      xmlChar *xmlbuff;
1783      int buffersize;
1784      xmlDocDumpFormatMemoryEnc(doc, &xmlbuff, &buffersize, "UTF-8", 1);
1785      fwrite(xmlbuff,1,xmlStrlen(xmlbuff)*sizeof(char),output);
1786      xmlFree(xmlbuff);
1787      fclose(output);
1788#ifndef RELY_ON_DB
1789#ifdef DEBUG
1790      fprintf(stderr,"UNLOCK %s %d !\n",__FILE__,__LINE__);
1791#endif
1792      unlockShm(lid);
1793      map* v=getMapFromMaps(m,"lenv","sid");
1794      // Remove the lock when running as a normal task
1795      if(getpid()==atoi(v->value)){
1796        removeShmLock (m, 1);
1797      }
1798    }
1799#endif
1800  }
1801  printDocument(m,doc,pid);
1802
1803  xmlCleanupParser();
1804  zooXmlCleanupNs();
1805}
1806
1807/**
1808 * Print a XML document.
1809 *
1810 * @param m the conf maps containing the main.cfg settings
1811 * @param doc the XML document
1812 * @param pid the process identifier linked to a service
1813 */
1814void printDocument(maps* m, xmlDocPtr doc,int pid){
1815  char *encoding=getEncoding(m);
1816  if(pid==getpid()){
1817    printHeaders(m);
1818    printf("Content-Type: text/xml; charset=%s\r\nStatus: 200 OK\r\n\r\n",encoding);
1819  }
1820  fflush(stdout);
1821  xmlChar *xmlbuff;
1822  int buffersize;
1823  /*
1824   * Dump the document to a buffer and print it on stdout
1825   * for demonstration purposes.
1826   */
1827  xmlDocDumpFormatMemoryEnc(doc, &xmlbuff, &buffersize, encoding, 1);
1828  printf("%s",xmlbuff);
1829  fflush(stdout);
1830  /*
1831   * Free associated memory.
1832   */
1833  xmlFree(xmlbuff);
1834  xmlFreeDoc(doc);
1835  xmlCleanupParser();
1836  zooXmlCleanupNs();
1837}
1838
1839/**
1840 * Print a XML document.
1841 *
1842 * @param doc the XML document (unused)
1843 * @param nc the XML node to add the output definition
1844 * @param ns_wps the wps XML namespace
1845 * @param ns_ows the ows XML namespace
1846 * @param e the output elements
1847 * @param m the conf maps containing the main.cfg settings
1848 * @param type the type (unused)
1849 */
1850void printOutputDefinitions(xmlDocPtr doc,xmlNodePtr nc,xmlNsPtr ns_wps,xmlNsPtr ns_ows,elements* e,maps* m,const char* type){
1851  xmlNodePtr nc1;
1852  nc1=xmlNewNode(ns_wps, BAD_CAST type);
1853  map *tmp=NULL; 
1854  if(e!=NULL && e->defaults!=NULL)
1855    tmp=e->defaults->content;
1856  else{
1857    /*
1858    dumpElements(e);
1859    */
1860    return;
1861  }
1862  while(tmp!=NULL){
1863    if(strncasecmp(tmp->name,"MIMETYPE",strlen(tmp->name))==0
1864       || strncasecmp(tmp->name,"ENCODING",strlen(tmp->name))==0
1865       || strncasecmp(tmp->name,"SCHEMA",strlen(tmp->name))==0
1866       || strncasecmp(tmp->name,"UOM",strlen(tmp->name))==0)
1867    xmlNewProp(nc1,BAD_CAST tmp->name,BAD_CAST tmp->value);
1868    tmp=tmp->next;
1869  }
1870  tmp=getMap(e->defaults->content,"asReference");
1871  if(tmp==NULL)
1872    xmlNewProp(nc1,BAD_CAST "asReference",BAD_CAST "false");
1873
1874  tmp=e->content;
1875
1876  printDescription(nc1,ns_ows,m->name,e->content,0);
1877
1878  xmlAddChild(nc,nc1);
1879
1880}
1881
1882/**
1883 * Generate XML nodes describing inputs or outputs metadata.
1884 *
1885 * @param doc the XML document
1886 * @param nc the XML node to add the definition
1887 * @param ns_wps the wps namespace
1888 * @param ns_ows the ows namespace
1889 * @param ns_xlink the xlink namespace
1890 * @param e the output elements
1891 * @param m the conf maps containing the main.cfg settings
1892 * @param type the type
1893 */
1894void printIOType(xmlDocPtr doc,xmlNodePtr nc,xmlNsPtr ns_wps,xmlNsPtr ns_ows,xmlNsPtr ns_xlink,elements* e,maps* m,const char* type,int vid){
1895
1896  xmlNodePtr nc1,nc2,nc3;
1897  nc1=xmlNewNode(ns_wps, BAD_CAST type);
1898  map *tmp=NULL;
1899  if(e!=NULL)
1900    tmp=e->content;
1901  else
1902    tmp=m->content;
1903
1904  if(vid==0){
1905    nc2=xmlNewNode(ns_ows, BAD_CAST "Identifier");
1906    if(e!=NULL)
1907      nc3=xmlNewText(BAD_CAST e->name);
1908    else
1909      nc3=xmlNewText(BAD_CAST m->name);
1910   
1911    xmlAddChild(nc2,nc3);
1912    xmlAddChild(nc1,nc2);
1913 
1914    xmlAddChild(nc,nc1);
1915
1916    if(e!=NULL)
1917      tmp=getMap(e->content,"Title");
1918    else
1919      tmp=getMap(m->content,"Title");
1920   
1921    if(tmp!=NULL){
1922      nc2=xmlNewNode(ns_ows, BAD_CAST tmp->name);
1923      nc3=xmlNewText(BAD_CAST _ss(tmp->value));
1924      xmlAddChild(nc2,nc3); 
1925      xmlAddChild(nc1,nc2);
1926    }
1927
1928    if(e!=NULL)
1929      tmp=getMap(e->content,"Abstract");
1930    else
1931      tmp=getMap(m->content,"Abstract");
1932
1933    if(tmp!=NULL){
1934      nc2=xmlNewNode(ns_ows, BAD_CAST tmp->name);
1935      nc3=xmlNewText(BAD_CAST _ss(tmp->value));
1936      xmlAddChild(nc2,nc3); 
1937      xmlAddChild(nc1,nc2);
1938      xmlAddChild(nc,nc1);
1939    }
1940  }else{
1941    xmlNewProp(nc1,BAD_CAST "id",BAD_CAST (e!=NULL?e->name:m->name));
1942  }
1943
1944  /**
1945   * IO type Reference or full Data ?
1946   */
1947  map *tmpMap=getMap(m->content,"Reference");
1948  if(tmpMap==NULL){
1949    nc2=xmlNewNode(ns_wps, BAD_CAST "Data");
1950    if(e!=NULL){
1951      if(strncasecmp(e->format,"LiteralOutput",strlen(e->format))==0)
1952        nc3=xmlNewNode(ns_wps, BAD_CAST "LiteralData");
1953      else
1954        if(strncasecmp(e->format,"ComplexOutput",strlen(e->format))==0)
1955          nc3=xmlNewNode(ns_wps, BAD_CAST "ComplexData");
1956        else if(strncasecmp(e->format,"BoundingBoxOutput",strlen(e->format))==0)
1957          nc3=xmlNewNode(ns_wps, BAD_CAST "BoundingBoxData");
1958        else
1959          nc3=xmlNewNode(ns_wps, BAD_CAST e->format);
1960    }
1961    else {
1962      map* tmpV=getMapFromMaps(m,"format","value");
1963      if(tmpV!=NULL)
1964        nc3=xmlNewNode(ns_wps, BAD_CAST tmpV->value);
1965      else
1966        nc3=xmlNewNode(ns_wps, BAD_CAST "LiteralData");
1967    } 
1968    tmp=m->content;
1969
1970    while(tmp!=NULL){
1971      if(strcasecmp(tmp->name,"mimeType")==0 ||
1972         strcasecmp(tmp->name,"encoding")==0 ||
1973         strcasecmp(tmp->name,"schema")==0 ||
1974         strcasecmp(tmp->name,"datatype")==0 ||
1975         strcasecmp(tmp->name,"uom")==0) {
1976       
1977        if(vid==0)
1978          xmlNewProp(nc3,BAD_CAST tmp->name,BAD_CAST tmp->value);
1979        else{
1980          if(strcasecmp(tmp->name,"datatype")==0)
1981            xmlNewProp(nc2,BAD_CAST "mimeType",BAD_CAST "text/plain");
1982          else
1983            if(strcasecmp(tmp->name,"uom")!=0)
1984              xmlNewProp(nc2,BAD_CAST tmp->name,BAD_CAST tmp->value);
1985        }
1986      }
1987      if(vid==0)
1988        xmlAddChild(nc2,nc3);
1989      tmp=tmp->next;
1990    }
1991    if(e!=NULL && e->format!=NULL && strcasecmp(e->format,"BoundingBoxData")==0) {
1992      map* bb=getMap(m->content,"value");
1993      if(bb!=NULL) {
1994        map* tmpRes=parseBoundingBox(bb->value);
1995        printBoundingBox(ns_ows,nc3,tmpRes);
1996        freeMap(&tmpRes);
1997        free(tmpRes);
1998      }
1999    }
2000    else {
2001      if(e!=NULL)
2002        tmp=getMap(e->defaults->content,"mimeType");
2003      else
2004        tmp=NULL;
2005       
2006      map* tmp1=getMap(m->content,"encoding");
2007      map* tmp2=getMap(m->content,"mimeType");
2008      map* tmp3=getMap(m->content,"value");
2009      int hasValue=1;
2010      if(tmp3==NULL){
2011        tmp3=createMap("value","");
2012        hasValue=-1;
2013      }
2014
2015      if( ( tmp1 != NULL && strncmp(tmp1->value,"base64",6) == 0 )     // if encoding is base64
2016          ||                                                           // or if
2017          ( tmp2 != NULL && ( strstr(tmp2->value,"text") == NULL       //  mime type is not text
2018                              &&                                       //  nor
2019                              strstr(tmp2->value,"xml") == NULL        //  xml
2020                              &&                                       // nor
2021                              strstr(tmp2->value,"javascript") == NULL // javascript
2022                              &&
2023                              strstr(tmp2->value,"json") == NULL
2024                              &&
2025                              strstr(tmp2->value,"ecmascript") == NULL
2026                              &&
2027                              // include for backwards compatibility,
2028                              // although correct mime type is ...kml+xml:
2029                              strstr(tmp2->value,"google-earth.kml") == NULL                                                    )
2030            )
2031          ) {                                                    // then       
2032        map* rs=getMap(m->content,"size");                       // obtain size
2033        bool isSized=true;
2034        if(rs==NULL){
2035          char tmp1[1024];
2036          sprintf(tmp1,"%ld",strlen(tmp3->value));
2037          rs=createMap("size",tmp1);
2038          isSized=false;
2039        }
2040         
2041        xmlAddChild((vid==0?nc3:nc2),xmlNewText(BAD_CAST base64(tmp3->value, atoi(rs->value))));  // base 64 encode in XML
2042               
2043        if(tmp1==NULL || (tmp1!=NULL && strncmp(tmp1->value,"base64",6)!=0)) {
2044          xmlAttrPtr ap = xmlHasProp((vid==0?nc3:nc2), BAD_CAST "encoding");
2045          if (ap != NULL) {
2046            xmlRemoveProp(ap);
2047          }                     
2048          xmlNewProp((vid==0?nc3:nc2),BAD_CAST "encoding",BAD_CAST "base64");
2049        }
2050               
2051        if(!isSized){
2052          freeMap(&rs);
2053          free(rs);
2054        }
2055      }
2056      else if (tmp2!=NULL) {                                 // else (text-based format)
2057        if(strstr(tmp2->value, "javascript") != NULL ||      //    if javascript put code in CDATA block
2058           strstr(tmp2->value, "json") != NULL ||            //    (will not be parsed by XML reader)
2059           strstr(tmp2->value, "ecmascript") != NULL
2060           ) {
2061          xmlAddChild((vid==0?nc3:nc2),xmlNewCDataBlock(doc,BAD_CAST tmp3->value,strlen(tmp3->value)));
2062        }   
2063        else {                                                     // else
2064          if (strstr(tmp2->value, "xml") != NULL ||                 // if XML-based format
2065              // include for backwards compatibility,
2066              // although correct mime type is ...kml+xml:                 
2067              strstr(tmp2->value, "google-earth.kml") != NULL
2068              ) { 
2069                         
2070            int li=zooXmlAddDoc(tmp3->value);
2071            xmlDocPtr doc = iDocs[li];
2072            xmlNodePtr ir = xmlDocGetRootElement(doc);
2073            xmlAddChild((vid==0?nc3:nc2),ir);
2074          }
2075          else                                                     // else     
2076            xmlAddChild((vid==0?nc3:nc2),xmlNewText(BAD_CAST tmp3->value));    //   add text node
2077        }
2078        xmlAddChild(nc2,nc3);
2079      }
2080      else {
2081        xmlAddChild((vid==0?nc3:nc2),xmlNewText(BAD_CAST tmp3->value));
2082      }
2083         
2084      if(hasValue<0) {
2085        freeMap(&tmp3);
2086        free(tmp3);
2087      }
2088    }
2089  }
2090  else { // Reference
2091    tmpMap=getMap(m->content,"Reference");
2092    nc3=nc2=xmlNewNode(ns_wps, BAD_CAST "Reference");
2093    if(strcasecmp(type,"Output")==0)
2094      xmlNewProp(nc3,BAD_CAST "href",BAD_CAST tmpMap->value);
2095    else
2096      xmlNewNsProp(nc3,ns_xlink,BAD_CAST "href",BAD_CAST tmpMap->value);
2097   
2098    tmp=m->content;
2099    while(tmp!=NULL) {
2100      if(strcasecmp(tmp->name,"mimeType")==0 ||
2101         strcasecmp(tmp->name,"encoding")==0 ||
2102         strcasecmp(tmp->name,"schema")==0 ||
2103         strcasecmp(tmp->name,"datatype")==0 ||
2104         strcasecmp(tmp->name,"uom")==0){
2105
2106        if(strcasecmp(tmp->name,"datatype")==0)
2107          xmlNewProp(nc3,BAD_CAST "mimeType",BAD_CAST "text/plain");
2108        else
2109          xmlNewProp(nc3,BAD_CAST tmp->name,BAD_CAST tmp->value);
2110      }
2111      tmp=tmp->next;
2112      xmlAddChild(nc2,nc3);
2113    }
2114  }
2115  xmlAddChild(nc1,nc2);
2116  xmlAddChild(nc,nc1);
2117}
2118
2119/**
2120 * Create XML node with basic ows metadata informations (Identifier,Title,Abstract)
2121 *
2122 * @param root the root XML node to add the description
2123 * @param ns_ows the ows XML namespace
2124 * @param identifier the identifier to use
2125 * @param amap the map containing the ows metadata informations
2126 */
2127void printDescription(xmlNodePtr root,xmlNsPtr ns_ows,const char* identifier,map* amap,int vid=0){
2128  xmlNodePtr nc2;
2129  if(vid==0){
2130    nc2 = xmlNewNode(ns_ows, BAD_CAST "Identifier");
2131    xmlAddChild(nc2,xmlNewText(BAD_CAST identifier));
2132    xmlAddChild(root,nc2);
2133  }
2134  map* tmp=amap;
2135  const char *tmp2[2];
2136  tmp2[0]="Title";
2137  tmp2[1]="Abstract";
2138  int j=0;
2139  for(j=0;j<2;j++){
2140    map* tmp1=getMap(tmp,tmp2[j]);
2141    if(tmp1!=NULL){
2142      nc2 = xmlNewNode(ns_ows, BAD_CAST tmp2[j]);
2143      xmlAddChild(nc2,xmlNewText(BAD_CAST _ss(tmp1->value)));
2144      xmlAddChild(root,nc2);
2145    }
2146  }
2147  if(vid==1){
2148    nc2 = xmlNewNode(ns_ows, BAD_CAST "Identifier");
2149    xmlAddChild(nc2,xmlNewText(BAD_CAST identifier));
2150    xmlAddChild(root,nc2);
2151  }
2152}
2153
2154/**
2155 * Print an OWS ExceptionReport Document and HTTP headers (when required)
2156 * depending on the code.
2157 * Set hasPrinted value to true in the [lenv] section.
2158 *
2159 * @param m the maps containing the settings of the main.cfg file
2160 * @param s the map containing the text,code,locator keys
2161 */
2162void printExceptionReportResponse(maps* m,map* s){
2163  if(getMapFromMaps(m,"lenv","hasPrinted")!=NULL)
2164    return;
2165  int buffersize;
2166  xmlDocPtr doc;
2167  xmlChar *xmlbuff;
2168  xmlNodePtr n;
2169
2170  zooXmlCleanupNs();
2171  doc = xmlNewDoc(BAD_CAST "1.0");
2172  maps* tmpMap=getMaps(m,"main");
2173  char *encoding=getEncoding(tmpMap);
2174  const char *exceptionCode;
2175 
2176  map* tmp=getMap(s,"code");
2177  if(tmp!=NULL){
2178    if(strcmp(tmp->value,"OperationNotSupported")==0 ||
2179       strcmp(tmp->value,"NoApplicableCode")==0)
2180      exceptionCode="501 Not Implemented";
2181    else
2182      if(strcmp(tmp->value,"MissingParameterValue")==0 ||
2183         strcmp(tmp->value,"InvalidUpdateSequence")==0 ||
2184         strcmp(tmp->value,"OptionNotSupported")==0 ||
2185         strcmp(tmp->value,"VersionNegotiationFailed")==0 ||
2186         strcmp(tmp->value,"InvalidParameterValue")==0)
2187        exceptionCode="400 Bad request";
2188      else
2189        exceptionCode="501 Internal Server Error";
2190  }
2191  else
2192    exceptionCode="501 Internal Server Error";
2193
2194  if(m!=NULL){
2195    map *tmpSid=getMapFromMaps(m,"lenv","sid");
2196    if(tmpSid!=NULL){
2197      if( getpid()==atoi(tmpSid->value) ){
2198        printHeaders(m);
2199        printf("Content-Type: text/xml; charset=%s\r\nStatus: %s\r\n\r\n",encoding,exceptionCode);
2200      }
2201    }
2202    else{
2203      printHeaders(m);
2204      printf("Content-Type: text/xml; charset=%s\r\nStatus: %s\r\n\r\n",encoding,exceptionCode);
2205    }
2206  }else{
2207    printf("Content-Type: text/xml; charset=%s\r\nStatus: %s\r\n\r\n",encoding,exceptionCode);
2208  }
2209  n=createExceptionReportNode(m,s,1);
2210  xmlDocSetRootElement(doc, n);
2211  xmlDocDumpFormatMemoryEnc(doc, &xmlbuff, &buffersize, encoding, 1);
2212  printf("%s",xmlbuff);
2213  fflush(stdout);
2214  xmlFreeDoc(doc);
2215  xmlFree(xmlbuff);
2216  xmlCleanupParser();
2217  zooXmlCleanupNs();
2218  if(m!=NULL)
2219    setMapInMaps(m,"lenv","hasPrinted","true");
2220}
2221
2222/**
2223 * Create an OWS ExceptionReport Node.
2224 *
2225 * @param m the conf maps
2226 * @param s the map containing the text,code,locator keys
2227 * @param use_ns (0/1) choose if you want to generate an ExceptionReport or
2228 *  ows:ExceptionReport node respectively
2229 * @return the ExceptionReport/ows:ExceptionReport node
2230 */
2231xmlNodePtr createExceptionReportNode(maps* m,map* s,int use_ns){
2232 
2233  xmlNsPtr ns,ns_xsi;
2234  xmlNodePtr n,nc,nc1;
2235
2236  int nsid=zooXmlAddNs(NULL,"http://www.opengis.net/ows","ows");
2237  ns=usedNs[nsid];
2238  if(use_ns==0){
2239    ns=NULL;
2240  }
2241  n = xmlNewNode(ns, BAD_CAST "ExceptionReport");
2242  map* version=getMapFromMaps(m,"main","rversion");
2243  int vid=getVersionId(version->value);
2244  if(vid<0)
2245    vid=0;
2246  if(use_ns==1){
2247    xmlNewNs(n,BAD_CAST schemas[vid][1],BAD_CAST"ows");
2248    int xsiId=zooXmlAddNs(n,"http://www.w3.org/2001/XMLSchema-instance","xsi");
2249    ns_xsi=usedNs[xsiId];
2250    char tmp[1024];
2251    sprintf(tmp,"%s %s",schemas[vid][1],schemas[vid][5]);
2252    xmlNewNsProp(n,ns_xsi,BAD_CAST "schemaLocation",BAD_CAST tmp);
2253  }
2254
2255
2256  addLangAttr(n,m);
2257  xmlNewProp(n,BAD_CAST "version",BAD_CAST schemas[vid][6]);
2258 
2259  int length=1;
2260  int cnt=0;
2261  map* len=getMap(s,"length");
2262  if(len!=NULL)
2263    length=atoi(len->value);
2264  for(cnt=0;cnt<length;cnt++){
2265    nc = xmlNewNode(ns, BAD_CAST "Exception");
2266   
2267    map* tmp=getMapArray(s,"code",cnt);
2268    if(tmp==NULL)
2269      tmp=getMap(s,"code");
2270    if(tmp!=NULL)
2271      xmlNewProp(nc,BAD_CAST "exceptionCode",BAD_CAST tmp->value);
2272    else
2273      xmlNewProp(nc,BAD_CAST "exceptionCode",BAD_CAST "NoApplicableCode");
2274   
2275    tmp=getMapArray(s,"locator",cnt);
2276    if(tmp==NULL)
2277      tmp=getMap(s,"locator");
2278    if(tmp!=NULL && strcasecmp(tmp->value,"NULL")!=0)
2279      xmlNewProp(nc,BAD_CAST "locator",BAD_CAST tmp->value);
2280
2281    tmp=getMapArray(s,"text",cnt);
2282    nc1 = xmlNewNode(ns, BAD_CAST "ExceptionText");
2283    if(tmp!=NULL){
2284      xmlNodePtr txt=xmlNewText(BAD_CAST tmp->value);
2285      xmlAddChild(nc1,txt);
2286    }
2287    else{
2288      xmlNodeSetContent(nc1, BAD_CAST _("No debug message available"));
2289    }
2290    xmlAddChild(nc,nc1);
2291    xmlAddChild(n,nc);
2292  }
2293  return n;
2294}
2295
2296/**
2297 * Print an OWS ExceptionReport.
2298 *
2299 * @param m the conf maps
2300 * @param message the error message
2301 * @param errorcode the error code
2302 * @param locator the potential locator
2303 */
2304int errorException(maps *m, const char *message, const char *errorcode, const char *locator) 
2305{
2306  map* errormap = createMap("text", message);
2307  addToMap(errormap,"code", errorcode);
2308  if(locator!=NULL)
2309    addToMap(errormap,"locator", locator);
2310  else
2311    addToMap(errormap,"locator", "NULL");
2312  printExceptionReportResponse(m,errormap);
2313  freeMap(&errormap);
2314  free(errormap);
2315  return -1;
2316}
2317
2318/**
2319 * Generate the output response (RawDataOutput or ResponseDocument)
2320 *
2321 * @param s the service structure containing the metadata informations
2322 * @param request_inputs the inputs provided to the service for execution
2323 * @param request_outputs the outputs updated by the service execution
2324 * @param request_inputs1 the map containing the HTTP request
2325 * @param cpid the process identifier attached to a service execution
2326 * @param m the conf maps containing the main.cfg settings
2327 * @param res the value returned by the service execution
2328 */
2329void outputResponse(service* s,maps* request_inputs,maps* request_outputs,
2330                    map* request_inputs1,int cpid,maps* m,int res){
2331#ifdef DEBUG
2332  dumpMaps(request_inputs);
2333  dumpMaps(request_outputs);
2334  fprintf(stderr,"printProcessResponse\n");
2335#endif
2336  map* toto=getMap(request_inputs1,"RawDataOutput");
2337  int asRaw=0;
2338  if(toto!=NULL)
2339    asRaw=1;
2340  map* version=getMapFromMaps(m,"main","rversion");
2341  int vid=getVersionId(version->value);
2342
2343  maps* tmpSess=getMaps(m,"senv");
2344  if(tmpSess!=NULL){
2345    map *_tmp=getMapFromMaps(m,"lenv","cookie");
2346    char* sessId=NULL;
2347    if(_tmp!=NULL){
2348      printf("Set-Cookie: %s; HttpOnly\r\n",_tmp->value);
2349      printf("P3P: CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"\r\n");
2350      char session_file_path[100];
2351      char *tmp1=strtok(_tmp->value,";");
2352      if(tmp1!=NULL)
2353        sprintf(session_file_path,"%s",strstr(tmp1,"=")+1);
2354      else
2355        sprintf(session_file_path,"%s",strstr(_tmp->value,"=")+1);
2356      sessId=strdup(session_file_path);
2357    }else{
2358      maps* t=getMaps(m,"senv");
2359      map*p=t->content;
2360      while(p!=NULL){
2361        if(strstr(p->name,"ID")!=NULL){
2362          sessId=strdup(p->value);
2363          break;
2364        }
2365        p=p->next;
2366      }
2367    }
2368    char session_file_path[1024];
2369    map *tmpPath=getMapFromMaps(m,"main","sessPath");
2370    if(tmpPath==NULL)
2371      tmpPath=getMapFromMaps(m,"main","tmpPath");
2372    sprintf(session_file_path,"%s/sess_%s.cfg",tmpPath->value,sessId);
2373    FILE* teste=fopen(session_file_path,"w");
2374    if(teste==NULL){
2375      char tmpMsg[1024];
2376      sprintf(tmpMsg,_("Unable to create the file \"%s\" for storing the session maps."),session_file_path);
2377      errorException(m,tmpMsg,"InternalError",NULL);
2378
2379      return;
2380    }
2381    else{
2382      fclose(teste);
2383      dumpMapsToFile(tmpSess,session_file_path,1);
2384    }
2385  }
2386 
2387  if(res==SERVICE_FAILED){
2388    map *lenv;
2389    lenv=getMapFromMaps(m,"lenv","message");
2390    char *tmp0;
2391    if(lenv!=NULL){
2392      tmp0=(char*)malloc((strlen(lenv->value)+strlen(_("Unable to run the Service. The message returned back by the Service was the following: "))+1)*sizeof(char));
2393      sprintf(tmp0,_("Unable to run the Service. The message returned back by the Service was the following: %s"),lenv->value);
2394    }
2395    else{
2396      tmp0=(char*)malloc((strlen(_("Unable to run the Service. No more information was returned back by the Service."))+1)*sizeof(char));
2397      sprintf(tmp0,"%s",_("Unable to run the Service. No more information was returned back by the Service."));
2398    }
2399    errorException(m,tmp0,"InternalError",NULL);
2400    free(tmp0);
2401    return;
2402  }
2403
2404  if(res==SERVICE_ACCEPTED && vid==1){
2405    map* statusInfo=createMap("Status","Accepted");
2406    map *usid=getMapFromMaps(m,"lenv","usid");
2407    addToMap(statusInfo,"JobID",usid->value);
2408    printStatusInfo(m,statusInfo,"Execute");
2409    freeMap(&statusInfo);
2410    free(statusInfo);
2411    return;
2412  }
2413
2414  map *tmp1=getMapFromMaps(m,"main","tmpPath");
2415  if(asRaw==0){
2416#ifdef DEBUG
2417    fprintf(stderr,"REQUEST_OUTPUTS FINAL\n");
2418    dumpMaps(request_outputs);
2419#endif
2420    maps* tmpI=request_outputs;
2421    map* usid=getMapFromMaps(m,"lenv","usid");
2422    int itn=0;
2423    while(tmpI!=NULL){
2424#ifdef USE_MS
2425      map* testMap=getMap(tmpI->content,"useMapserver");       
2426#endif
2427      map *gfile=getMap(tmpI->content,"generated_file");
2428      char *file_name;
2429      if(gfile!=NULL){
2430        gfile=getMap(tmpI->content,"expected_generated_file");
2431        if(gfile==NULL){
2432          gfile=getMap(tmpI->content,"generated_file");
2433        }
2434        readGeneratedFile(m,tmpI->content,gfile->value);           
2435        file_name=(char*)malloc((strlen(gfile->value)+strlen(tmp1->value)+1)*sizeof(char));
2436        for(int i=0;i<strlen(gfile->value);i++)
2437          file_name[i]=gfile->value[i+strlen(tmp1->value)];
2438      }
2439
2440      toto=getMap(tmpI->content,"asReference");
2441#ifdef USE_MS
2442      if(toto!=NULL && strcasecmp(toto->value,"true")==0 && testMap==NULL)
2443#else
2444      if(toto!=NULL && strcasecmp(toto->value,"true")==0)
2445#endif
2446        {
2447          elements* in=getElements(s->outputs,tmpI->name);
2448          char *format=NULL;
2449          if(in!=NULL && in->format!=NULL){
2450            format=zStrdup(in->format);
2451          }else
2452            format=zStrdup("LiteralData");
2453          if(strcasecmp(format,"BoundingBoxData")==0){
2454            addToMap(tmpI->content,"extension","xml");
2455            addToMap(tmpI->content,"mimeType","text/xml");
2456            addToMap(tmpI->content,"encoding","UTF-8");
2457            addToMap(tmpI->content,"schema","http://schemas.opengis.net/ows/1.1.0/owsCommon.xsd");
2458          }
2459
2460          if(gfile==NULL) {
2461            map *ext=getMap(tmpI->content,"extension");
2462            char *file_path;
2463            char file_ext[32];
2464
2465            if( ext != NULL && ext->value != NULL) {
2466              strncpy(file_ext, ext->value, 32);
2467            }
2468            else {
2469              // Obtain default file extension (see mimetypes.h).             
2470              // If the MIME type is not recognized, txt is used as the default extension
2471              map* mtype=getMap(tmpI->content,"mimeType");
2472              getFileExtension(mtype != NULL ? mtype->value : NULL, file_ext, 32);
2473            }
2474
2475            file_name=(char*)malloc((strlen(s->name)+strlen(usid->value)+strlen(file_ext)+strlen(tmpI->name)+45)*sizeof(char));
2476            sprintf(file_name,"%s_%s_%s_%d.%s",s->name,tmpI->name,usid->value,itn,file_ext);
2477            itn++;
2478            file_path=(char*)malloc((strlen(tmp1->value)+strlen(file_name)+2)*sizeof(char));
2479            sprintf(file_path,"%s/%s",tmp1->value,file_name);
2480
2481            FILE *ofile=fopen(file_path,"wb");
2482            if(ofile==NULL){
2483              char tmpMsg[1024];
2484              sprintf(tmpMsg,_("Unable to create the file \"%s\" for storing the %s final result."),file_name,tmpI->name);
2485              errorException(m,tmpMsg,"InternalError",NULL);
2486              free(file_name);
2487              free(file_path);
2488              return;
2489            }
2490            free(file_path);
2491
2492            toto=getMap(tmpI->content,"value");
2493            if(strcasecmp(format,"BoundingBoxData")!=0){
2494              map* size=getMap(tmpI->content,"size");
2495              if(size!=NULL && toto!=NULL)
2496                fwrite(toto->value,1,(atoi(size->value))*sizeof(char),ofile);
2497              else
2498                if(toto!=NULL && toto->value!=NULL)
2499                  fwrite(toto->value,1,strlen(toto->value)*sizeof(char),ofile);
2500            }else{
2501              printBoundingBoxDocument(m,tmpI,ofile);
2502            }
2503            fclose(ofile);
2504
2505          }
2506
2507          map *tmp2=getMapFromMaps(m,"main","tmpUrl");
2508          map *tmp3=getMapFromMaps(m,"main","serverAddress");
2509          char *file_url;
2510          if(strncasecmp(tmp2->value,"http://",7)==0 ||
2511             strncasecmp(tmp2->value,"https://",8)==0){
2512            file_url=(char*)malloc((strlen(tmp2->value)+strlen(file_name)+2)*sizeof(char));
2513            sprintf(file_url,"%s/%s",tmp2->value,file_name);
2514          }else{
2515            file_url=(char*)malloc((strlen(tmp3->value)+strlen(tmp2->value)+strlen(file_name)+3)*sizeof(char));
2516            sprintf(file_url,"%s/%s/%s",tmp3->value,tmp2->value,file_name);
2517          }
2518
2519          addToMap(tmpI->content,"Reference",file_url);
2520          free(format);
2521          free(file_name);
2522          free(file_url);
2523         
2524        }
2525#ifdef USE_MS
2526      else{
2527        if(testMap!=NULL){
2528          setReferenceUrl(m,tmpI);
2529        }
2530      }
2531#endif
2532      tmpI=tmpI->next;
2533    }
2534#ifdef DEBUG
2535    fprintf(stderr,"SERVICE : %s\n",s->name);
2536    dumpMaps(m);
2537#endif
2538    printProcessResponse(m,request_inputs1,cpid,
2539                         s, s->name,res,  // replace serviceProvider with serviceName in stored response file name
2540                         request_inputs,
2541                         request_outputs);
2542  }
2543  else{
2544    /**
2545     * We get the requested output or fallback to the first one if the
2546     * requested one is not present in the resulting outputs maps.
2547     */
2548    maps* tmpI=NULL;
2549    map* tmpIV=getMap(request_inputs1,"RawDataOutput");
2550    if(tmpIV!=NULL){
2551      tmpI=getMaps(request_outputs,tmpIV->value);
2552    }
2553    if(tmpI==NULL)
2554      tmpI=request_outputs;
2555    elements* e=getElements(s->outputs,tmpI->name);
2556    if(e!=NULL && strcasecmp(e->format,"BoundingBoxData")==0){
2557      printBoundingBoxDocument(m,tmpI,NULL);
2558    }else{
2559      map *gfile=getMap(tmpI->content,"generated_file");
2560      if(gfile!=NULL){
2561        gfile=getMap(tmpI->content,"expected_generated_file");
2562        if(gfile==NULL){
2563          gfile=getMap(tmpI->content,"generated_file");
2564        }
2565        readGeneratedFile(m,tmpI->content,gfile->value);
2566      }
2567      toto=getMap(tmpI->content,"value");
2568      if(toto==NULL){
2569        char tmpMsg[1024];
2570        sprintf(tmpMsg,_("Wrong RawDataOutput parameter: unable to fetch any result for the given parameter name: \"%s\"."),tmpI->name);
2571        errorException(m,tmpMsg,"InvalidParameterValue","RawDataOutput");
2572        return;
2573      }
2574      map* fname=getMapFromMaps(tmpI,tmpI->name,"filename");
2575      if(fname!=NULL)
2576        printf("Content-Disposition: attachment; filename=\"%s\"\r\n",fname->value);
2577      map* rs=getMapFromMaps(tmpI,tmpI->name,"size");
2578      if(rs!=NULL)
2579        printf("Content-Length: %s\r\n",rs->value);
2580      printHeaders(m);
2581      char mime[1024];
2582      map* mi=getMap(tmpI->content,"mimeType");
2583#ifdef DEBUG
2584      fprintf(stderr,"SERVICE OUTPUTS\n");
2585      dumpMaps(request_outputs);
2586      fprintf(stderr,"SERVICE OUTPUTS\n");
2587#endif
2588      map* en=getMap(tmpI->content,"encoding");
2589      if(mi!=NULL && en!=NULL)
2590        sprintf(mime,
2591                "Content-Type: %s; charset=%s\r\nStatus: 200 OK\r\n\r\n",
2592                mi->value,en->value);
2593      else
2594        if(mi!=NULL)
2595          sprintf(mime,
2596                  "Content-Type: %s; charset=UTF-8\r\nStatus: 200 OK\r\n\r\n",
2597                  mi->value);
2598        else
2599          sprintf(mime,"Content-Type: text/plain; charset=utf-8\r\nStatus: 200 OK\r\n\r\n");
2600      printf("%s",mime);
2601      if(rs!=NULL)
2602        fwrite(toto->value,1,atoi(rs->value),stdout);
2603      else
2604        fwrite(toto->value,1,strlen(toto->value),stdout);
2605#ifdef DEBUG
2606      dumpMap(toto);
2607#endif
2608    }
2609  }
2610}
2611
2612/**
2613 * Create required XML nodes for boundingbox and update the current XML node
2614 *
2615 * @param ns_ows the ows XML namespace
2616 * @param n the XML node to update
2617 * @param boundingbox the map containing the boundingbox definition
2618 */
2619void printBoundingBox(xmlNsPtr ns_ows,xmlNodePtr n,map* boundingbox){
2620
2621  xmlNodePtr lw=NULL,uc=NULL;
2622
2623  map* tmp=getMap(boundingbox,"value");
2624
2625  tmp=getMap(boundingbox,"lowerCorner");
2626  if(tmp!=NULL){
2627    lw=xmlNewNode(ns_ows,BAD_CAST "LowerCorner");
2628    xmlAddChild(lw,xmlNewText(BAD_CAST tmp->value));
2629  }
2630
2631  tmp=getMap(boundingbox,"upperCorner");
2632  if(tmp!=NULL){
2633    uc=xmlNewNode(ns_ows,BAD_CAST "UpperCorner");
2634    xmlAddChild(uc,xmlNewText(BAD_CAST tmp->value));
2635  }
2636
2637  tmp=getMap(boundingbox,"crs");
2638  if(tmp!=NULL)
2639    xmlNewProp(n,BAD_CAST "crs",BAD_CAST tmp->value);
2640
2641  tmp=getMap(boundingbox,"dimensions");
2642  if(tmp!=NULL)
2643    xmlNewProp(n,BAD_CAST "dimensions",BAD_CAST tmp->value);
2644
2645  xmlAddChild(n,lw);
2646  xmlAddChild(n,uc);
2647
2648}
2649
2650/**
2651 * Parse a BoundingBox string
2652 *
2653 * [OGC 06-121r3](http://portal.opengeospatial.org/files/?artifact_id=20040):
2654 *  10.2 Bounding box
2655 *
2656 *
2657 * Value is provided as : lowerCorner,upperCorner,crs,dimension
2658 * Exemple : 189000,834000,285000,962000,urn:ogc:def:crs:OGC:1.3:CRS84
2659 *
2660 * A map to store boundingbox informations should contain:
2661 *  - lowerCorner : double,double (minimum within this bounding box)
2662 *  - upperCorner : double,double (maximum within this bounding box)
2663 *  - crs : URI (Reference to definition of the CRS)
2664 *  - dimensions : int
2665 *
2666 * Note : support only 2D bounding box.
2667 *
2668 * @param value the char* containing the KVP bouding box
2669 * @return a map containing all the bounding box keys
2670 */
2671map* parseBoundingBox(const char* value){
2672  map *res=NULL;
2673  if(value!=NULL){
2674    char *cv,*cvp;
2675    cv=strtok_r((char*) value,",",&cvp);
2676    int cnt=0;
2677    int icnt=0;
2678    char *currentValue=NULL;
2679    while(cv){
2680      if(cnt<2)
2681        if(currentValue!=NULL){
2682          char *finalValue=(char*)malloc((strlen(currentValue)+strlen(cv)+1)*sizeof(char));
2683          sprintf(finalValue,"%s%s",currentValue,cv);
2684          switch(cnt){
2685          case 0:
2686            res=createMap("lowerCorner",finalValue);
2687            break;
2688          case 1:
2689            addToMap(res,"upperCorner",finalValue);
2690            icnt=-1;
2691            break;
2692          }
2693          cnt++;
2694          free(currentValue);
2695          currentValue=NULL;
2696          free(finalValue);
2697        }
2698        else{
2699          currentValue=(char*)malloc((strlen(cv)+2)*sizeof(char));
2700          sprintf(currentValue,"%s ",cv);
2701        }
2702      else
2703        if(cnt==2){
2704          addToMap(res,"crs",cv);
2705          cnt++;
2706        }
2707        else
2708          addToMap(res,"dimensions",cv);
2709      icnt++;
2710      cv=strtok_r(NULL,",",&cvp);
2711    }
2712  }
2713  return res;
2714}
2715
2716/**
2717 * Print an ows:BoundingBox XML document
2718 *
2719 * @param m the maps containing the settings of the main.cfg file
2720 * @param boundingbox the maps containing the boundingbox definition
2721 * @param file the file to print the BoundingBox (if NULL then print on stdout)
2722 * @see parseBoundingBox, printBoundingBox
2723 */
2724void printBoundingBoxDocument(maps* m,maps* boundingbox,FILE* file){
2725  if(file==NULL)
2726    rewind(stdout);
2727  xmlNodePtr n;
2728  xmlDocPtr doc;
2729  xmlNsPtr ns_ows,ns_xsi;
2730  xmlChar *xmlbuff;
2731  int buffersize;
2732  char *encoding=getEncoding(m);
2733  map *tmp;
2734  if(file==NULL){
2735    int pid=0;
2736    tmp=getMapFromMaps(m,"lenv","sid");
2737    if(tmp!=NULL)
2738      pid=atoi(tmp->value);
2739    if(pid==getpid()){
2740      printf("Content-Type: text/xml; charset=%s\r\nStatus: 200 OK\r\n\r\n",encoding);
2741    }
2742    fflush(stdout);
2743  }
2744
2745  doc = xmlNewDoc(BAD_CAST "1.0");
2746  int owsId=zooXmlAddNs(NULL,"http://www.opengis.net/ows/1.1","ows");
2747  ns_ows=usedNs[owsId];
2748  n = xmlNewNode(ns_ows, BAD_CAST "BoundingBox");
2749  xmlNewNs(n,BAD_CAST "http://www.opengis.net/ows/1.1",BAD_CAST "ows");
2750  int xsiId=zooXmlAddNs(n,"http://www.w3.org/2001/XMLSchema-instance","xsi");
2751  ns_xsi=usedNs[xsiId];
2752  xmlNewNsProp(n,ns_xsi,BAD_CAST "schemaLocation",BAD_CAST "http://www.opengis.net/ows/1.1 http://schemas.opengis.net/ows/1.1.0/owsCommon.xsd");
2753  map *tmp1=getMap(boundingbox->content,"value");
2754  tmp=parseBoundingBox(tmp1->value);
2755  printBoundingBox(ns_ows,n,tmp);
2756  xmlDocSetRootElement(doc, n);
2757
2758  xmlDocDumpFormatMemoryEnc(doc, &xmlbuff, &buffersize, encoding, 1);
2759  if(file==NULL)
2760    printf("%s",xmlbuff);
2761  else{
2762    fprintf(file,"%s",xmlbuff);
2763  }
2764
2765  if(tmp!=NULL){
2766    freeMap(&tmp);
2767    free(tmp);
2768  }
2769  xmlFree(xmlbuff);
2770  xmlFreeDoc(doc);
2771  xmlCleanupParser();
2772  zooXmlCleanupNs();
2773 
2774}
2775
2776/**
2777 * Print a StatusInfo XML document.
2778 * a statusInfo map should contain the following keys:
2779 *  * JobID corresponding to usid key from the lenv section
2780 *  * Status the current state (Succeeded,Failed,Accepted,Running)
2781 *  * PercentCompleted (optional) the percent completed
2782 *  * Message (optional) any messages the service may wish to share
2783 *
2784 * @param conf the maps containing the settings of the main.cfg file
2785 * @param statusInfo the map containing the statusInfo definition
2786 * @param req the WPS requests (GetResult, GetStatus or Dismiss)
2787 */
2788void printStatusInfo(maps* conf,map* statusInfo,char* req){
2789  rewind(stdout);
2790  xmlNodePtr n,n1;
2791  xmlDocPtr doc;
2792  xmlNsPtr ns;
2793  xmlChar *xmlbuff;
2794  int buffersize;
2795  char *encoding=getEncoding(conf);
2796  map *tmp;
2797  int pid=0;
2798  printf("Content-Type: text/xml; charset=%s\r\nStatus: 200 OK\r\n\r\n",encoding);
2799
2800  map* version=getMapFromMaps(conf,"main","rversion");
2801  int vid=getVersionId(version->value);
2802
2803  doc = xmlNewDoc(BAD_CAST "1.0");
2804  n1=printWPSHeader(doc,conf,req,"StatusInfo",version->value,1);
2805
2806  map* val=getMap(statusInfo,"JobID");
2807  int wpsId=zooXmlAddNs(NULL,schemas[vid][2],"wps");
2808  ns=usedNs[wpsId];
2809  n = xmlNewNode(ns, BAD_CAST "JobID");
2810  xmlAddChild(n,xmlNewText(BAD_CAST val->value));
2811
2812  xmlAddChild(n1,n);
2813
2814  val=getMap(statusInfo,"Status");
2815  n = xmlNewNode(ns, BAD_CAST "Status");
2816  xmlAddChild(n,xmlNewText(BAD_CAST val->value));
2817
2818  xmlAddChild(n1,n);
2819
2820  if(strncasecmp(val->value,"Failed",6)!=0 &&
2821     strncasecmp(val->value,"Succeeded",9)!=0){
2822    val=getMap(statusInfo,"PercentCompleted");
2823    if(val!=NULL){
2824      n = xmlNewNode(ns, BAD_CAST "PercentCompleted");
2825      xmlAddChild(n,xmlNewText(BAD_CAST val->value));
2826      xmlAddChild(n1,n);
2827    }
2828
2829    val=getMap(statusInfo,"Message");
2830    if(val!=NULL){   
2831      xmlAddChild(n1,xmlNewComment(BAD_CAST val->value));
2832    }
2833  }
2834  xmlDocSetRootElement(doc, n1);
2835
2836  xmlDocDumpFormatMemoryEnc(doc, &xmlbuff, &buffersize, encoding, 1);
2837  printf("%s",xmlbuff);
2838
2839  xmlFree(xmlbuff);
2840  xmlFreeDoc(doc);
2841  xmlCleanupParser();
2842  zooXmlCleanupNs();
2843 
2844}
2845
Note: See TracBrowser for help on using the repository browser.

Search

ZOO Sponsors

http://www.zoo-project.org/trac/chrome/site/img/geolabs-logo.pnghttp://www.zoo-project.org/trac/chrome/site/img/neogeo-logo.png http://www.zoo-project.org/trac/chrome/site/img/apptech-logo.png http://www.zoo-project.org/trac/chrome/site/img/3liz-logo.png http://www.zoo-project.org/trac/chrome/site/img/gateway-logo.png

Become a sponsor !

Knowledge partners

http://www.zoo-project.org/trac/chrome/site/img/ocu-logo.png http://www.zoo-project.org/trac/chrome/site/img/gucas-logo.png http://www.zoo-project.org/trac/chrome/site/img/polimi-logo.png http://www.zoo-project.org/trac/chrome/site/img/fem-logo.png http://www.zoo-project.org/trac/chrome/site/img/supsi-logo.png http://www.zoo-project.org/trac/chrome/site/img/cumtb-logo.png

Become a knowledge partner

Related links

http://zoo-project.org/img/ogclogo.png http://zoo-project.org/img/osgeologo.png