source: branches/branch-1.5/zoo-project/zoo-kernel/response_print.c @ 973

Last change on this file since 973 was 725, checked in by djay, 10 years ago

Fix issue with rst files displayed from Trac. Fix strings to be translated. Always use the same string in all messages.

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