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

Last change on this file since 676 was 676, checked in by djay, 9 years ago

Move createRegistry function to server_internal. Add the utils/registry service.

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