source: trunk/zoo-project/zoo-kernel/service_internal.c @ 631

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

Add readBase64 function, avoid calling it prior to fork . Add dumpMapsValuesToFiles function used to simplify OTB support.

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc
File size: 119.1 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 "service_internal.h"
26#ifdef USE_MS
27#include "service_internal_ms.h"
28#else
29#include "cpl_vsi.h"
30#endif
31
32#ifndef TRUE
33#define TRUE 1
34#endif
35#ifndef FALSE
36#define FALSE -1
37#endif
38
39#ifndef WIN32
40#include <dlfcn.h>
41#endif
42
43#define ERROR_MSG_MAX_LENGTH 1024
44
45#include "mimetypes.h"
46
47/**
48 * Verify if a given language is listed in the lang list defined in the [main]
49 * section of the main.cfg file.
50 *
51 * @param conf the map containing the settings from the main.cfg file
52 * @param str the specific language
53 * @return 1 if the specific language is listed, -1 in other case.
54 */
55int isValidLang(maps* conf,const char *str){
56  map *tmpMap=getMapFromMaps(conf,"main","lang");
57  char *tmp=zStrdup(tmpMap->value);
58  char *pToken=strtok(tmp,",");
59  int res=-1;
60  while(pToken!=NULL){
61    if(strcasecmp(str,pToken)==0){
62      res=1;
63      break;
64    }
65    pToken = strtok(NULL,",");
66  }
67  free(tmp);
68  return res;
69}
70
71/**
72 * Print the HTTP headers based on a map.
73 *
74 * @param m the map containing the headers informations
75 */
76void printHeaders(maps* m){
77  maps *_tmp=getMaps(m,"headers");
78  if(_tmp!=NULL){
79    map* _tmp1=_tmp->content;
80    while(_tmp1!=NULL){
81      printf("%s: %s\r\n",_tmp1->name,_tmp1->value);
82      _tmp1=_tmp1->next;
83    }
84  }
85}
86
87/**
88 * Add a land attribute to a XML node
89 *
90 * @param n the XML node to add the attribute
91 * @param m the map containing the language key to add as xml:lang
92 */
93void addLangAttr(xmlNodePtr n,maps *m){
94  map *tmpLmap=getMapFromMaps(m,"main","language");
95  if(tmpLmap!=NULL)
96    xmlNewProp(n,BAD_CAST "xml:lang",BAD_CAST tmpLmap->value);
97  else
98    xmlNewProp(n,BAD_CAST "xml:lang",BAD_CAST "en-US");
99}
100
101/**
102 * Converts a hex character to its integer value
103 *
104 * @param ch the char to convert
105 * @return the converted char
106 */
107char from_hex(char ch) {
108  return isdigit(ch) ? ch - '0' : tolower(ch) - 'a' + 10;
109}
110
111/**
112 * Converts an integer value to its hec character
113 *
114 * @param code the char to convert
115 * @return the converted char
116 */
117char to_hex(char code) {
118  static char hex[] = "0123456789abcdef";
119  return hex[code & 15];
120}
121
122/**
123 * Get the ongoing status of a running service
124 *
125 * @param conf the maps containing the setting of the main.cfg file
126 * @param pid the service identifier (usid key from the [lenv] section)
127 * @return the reported status char* (MESSAGE|POURCENTAGE)
128 */
129char* _getStatus(maps* conf,int pid){
130  char lid[1024];
131  sprintf(lid,"%d",pid);
132  setMapInMaps(conf,"lenv","lid",lid);
133  semid lockid=getShmLockId(conf,1);
134  if(
135#ifdef WIN32
136     lockid==NULL
137#else
138     lockid<0
139#endif
140     ){
141        char* tmp = (char*) malloc(3*sizeof(char));
142    sprintf(tmp,"%d",ZOO_LOCK_CREATE_FAILED);
143    return tmp;
144  }
145  if(lockShm(lockid)<0){
146    fprintf(stderr,"%s %d\n",__FILE__,__LINE__);
147    fflush(stderr);   
148        char* tmp = (char*) malloc(3*sizeof(char));
149    sprintf(tmp,"%d",ZOO_LOCK_ACQUIRE_FAILED);
150    return tmp;
151  }
152  char *tmp=getStatus(pid);
153  unlockShm(lockid);
154  if(tmp==NULL || strncmp(tmp,"-1",2)==0){
155    removeShmLock(conf,1);
156  }
157  return tmp;
158}
159
160#ifdef WIN32
161
162#include <windows.h>
163#include <fcgi_stdio.h>
164#include <stdio.h>
165#include <conio.h>
166#include <tchar.h>
167
168#define SHMEMSIZE 4096
169
170size_t getKeyValue(maps* conf, char* key, size_t length){
171  if(conf==NULL) {
172    strncpy(key, "700666", length);
173    return strlen(key);
174  }
175 
176  map *tmpMap=getMapFromMaps(conf,"lenv","lid");
177  if(tmpMap==NULL)
178        tmpMap=getMapFromMaps(conf,"lenv","usid");
179
180  if(tmpMap!=NULL){
181        snprintf(key, length, "zoo_sem_%s", tmpMap->value);     
182  }
183  else {
184        strncpy(key, "-1", length); 
185  }
186  return strlen(key);
187}
188
189
190semid getShmLockId(maps* conf, int nsems){
191    semid sem_id;
192    char key[MAX_PATH];
193    getKeyValue(conf, key, MAX_PATH);
194   
195    sem_id = CreateSemaphore( NULL, nsems, nsems+1, key);
196    if(sem_id==NULL){
197#ifdef DEBUG
198      fprintf(stderr,"Semaphore failed to create: %s\n", getLastErrorMessage());
199#endif
200      return NULL;
201    }
202#ifdef DEBUG
203    fprintf(stderr,"%s Accessed !\n",key);
204#endif
205
206    return sem_id;
207}
208
209int removeShmLock(maps* conf, int nsems){
210  semid sem_id=getShmLockId(conf,1);
211  if (CloseHandle(sem_id) == 0) {
212    fprintf(stderr,"Unable to remove semaphore: %s\n", getLastErrorMessage());
213    return -1;
214  }
215#ifdef DEBUG
216  fprintf(stderr,"%d Removed !\n",sem_id);
217#endif
218  return 0;
219}
220
221int lockShm(semid id){
222  DWORD dwWaitResult=WaitForSingleObject(id,INFINITE);
223  switch (dwWaitResult){
224    case WAIT_OBJECT_0:
225      return 0;
226      break;
227    case WAIT_TIMEOUT:
228      return -1;
229      break;
230    default:
231      return -2;
232      break;
233  }
234  return 0;
235}
236
237int unlockShm(semid id){
238  if(!ReleaseSemaphore(id,1,NULL)){
239    return -1;
240  }
241  return 0;
242}
243
244static LPVOID lpvMemG = NULL;      // pointer to shared memory
245static HANDLE hMapObjectG = NULL;  // handle to file mapping
246
247int _updateStatus(maps *conf){
248  LPWSTR lpszTmp;
249  BOOL fInit;
250  char *final_string=NULL;
251  char *s=NULL;
252  map *tmpMap1;
253  map *tmpMap=getMapFromMaps(conf,"lenv","usid");
254  semid lockid=getShmLockId(conf,1);
255  if(lockid==NULL){
256#ifdef DEBUG
257    fprintf(stderr,"Unable to create semaphore on line %d!! \n",__LINE__);
258#endif
259    return ZOO_LOCK_CREATE_FAILED;
260  }
261  if(lockShm(lockid)<0){
262#ifdef DEBUG
263    fprintf(stderr,"Unable to create semaphore on line %d!! \n",__LINE__);
264#endif
265    return ZOO_LOCK_ACQUIRE_FAILED;
266  }
267 
268  if(hMapObjectG==NULL)
269    hMapObjectG = CreateFileMapping( 
270                                    INVALID_HANDLE_VALUE,   // use paging file
271                                    NULL,                   // default security attributes
272                                    PAGE_READWRITE,         // read/write access
273                                    0,                      // size: high 32-bits
274                                    SHMEMSIZE,              // size: low 32-bits
275                                    TEXT(tmpMap->value));   // name of map object
276  if (hMapObjectG == NULL){
277#ifdef DEBUG
278    fprintf(stderr,"Unable to create shared memory segment: %s\n", getLastErrorMessage());
279#endif
280    return -2;
281  }
282  fInit = (GetLastError() != ERROR_ALREADY_EXISTS); 
283  if(lpvMemG==NULL)
284    lpvMemG = MapViewOfFile( 
285                            hMapObjectG,     // object to map view of
286                            FILE_MAP_WRITE, // read/write access
287                            0,              // high offset:  map from
288                            0,              // low offset:   beginning
289                            0);             // default: map entire file
290  if (lpvMemG == NULL){
291#ifdef DEBUG
292    fprintf(stderr,"Unable to create or access the shared memory segment %s !! \n",tmpMap->value);
293#endif
294    return -1;
295  } 
296  memset(lpvMemG, '\0', SHMEMSIZE);
297  tmpMap=getMapFromMaps(conf,"lenv","status");
298  tmpMap1=NULL;
299  tmpMap1=getMapFromMaps(conf,"lenv","message");
300  lpszTmp = (LPWSTR) lpvMemG;
301  final_string=(char*)malloc((strlen(tmpMap1->value)+strlen(tmpMap->value)+2)*sizeof(char));
302  sprintf(final_string,"%s|%s",tmpMap->value,tmpMap1->value);
303  for(s=final_string;*s!='\0';*s++){
304    *lpszTmp++ = *s;
305  }
306  *lpszTmp++ = '\0';
307  free(final_string);
308  unlockShm(lockid);
309  return 0;
310}
311
312char* getStatus(int pid){
313  char *lpszBuf=(char*) malloc(SHMEMSIZE*sizeof(char));
314  int i=0;
315  LPWSTR lpszTmp=NULL;
316  LPVOID lpvMem = NULL;
317  HANDLE hMapObject = NULL;
318  BOOL fIgnore,fInit;
319  char tmp[1024];
320  sprintf(tmp,"%d",pid);
321  if(hMapObject==NULL)
322    hMapObject = CreateFileMapping( 
323                                   INVALID_HANDLE_VALUE,   // use paging file
324                                   NULL,                   // default security attributes
325                                   PAGE_READWRITE,         // read/write access
326                                   0,                      // size: high 32-bits
327                                   4096,                   // size: low 32-bits
328                                   TEXT(tmp));   // name of map object
329  if (hMapObject == NULL){
330#ifdef DEBUG
331    fprintf(stderr,"ERROR on line %d\n",__LINE__);
332#endif
333    return "-1";
334  }
335  if((GetLastError() != ERROR_ALREADY_EXISTS)){
336#ifdef DEBUG
337    fprintf(stderr,"ERROR on line %d\n",__LINE__);
338    fprintf(stderr,"READING STRING S %s\n", getLastErrorMessage());
339#endif
340    fIgnore = UnmapViewOfFile(lpvMem); 
341    fIgnore = CloseHandle(hMapObject);
342    return "-1";
343  }
344  fInit=TRUE;
345  if(lpvMem==NULL)
346    lpvMem = MapViewOfFile( 
347                           hMapObject,     // object to map view of
348                           FILE_MAP_READ,  // read/write access
349                           0,              // high offset:  map from
350                           0,              // low offset:   beginning
351                           0);             // default: map entire file
352  if (lpvMem == NULL){
353#ifdef DEBUG
354    fprintf(stderr,"READING STRING S %d\n",__LINE__);
355    fprintf(stderr,"READING STRING S %s\n", getLastErrorMessage());
356#endif
357    return "-1"; 
358  }
359  lpszTmp = (LPWSTR) lpvMem;
360  while (*lpszTmp){
361    lpszBuf[i] = (char)*lpszTmp;
362    *lpszTmp++; 
363    lpszBuf[i+1] = '\0'; 
364    i++;
365  }
366  return (char*)lpszBuf;
367}
368
369void unhandleStatus(maps *conf){
370  BOOL fIgnore;
371  fIgnore = UnmapViewOfFile(lpvMemG); 
372  fIgnore = CloseHandle(hMapObjectG);
373}
374
375#else
376/**
377 * Number of time to try to access a semaphores set
378 * @see getShmLockId
379 */
380#define MAX_RETRIES 10
381
382#ifndef __APPLE__
383/**
384 * arg for semctl system calls.
385 */
386union semun {
387  int val; //!< value for SETVAL
388  struct semid_ds *buf; //!< buffer for IPC_STAT & IPC_SET
389  ushort *array; //!< array for GETALL & SETALL
390};
391#endif
392
393/**
394 * Set in the pre-allocated key the zoo_sem_[SID] string
395 * where [SID] is the lid (if any) or usid value from the [lenv] section.
396 *
397 * @param conf the map containing the setting of the main.cfg file
398 */
399int getKeyValue(maps* conf){
400  if(conf==NULL)
401     return 700666;
402  map *tmpMap=getMapFromMaps(conf,"lenv","lid");
403  if(tmpMap==NULL)
404    tmpMap=getMapFromMaps(conf,"lenv","usid");
405  int key=-1;
406  if(tmpMap!=NULL)
407    key=atoi(tmpMap->value);
408  return key;
409}
410
411/**
412 * Try to create or access a semaphore set.
413 *
414 * @see getKeyValue
415 * @param conf the map containing the setting of the main.cfg file
416 * @param nsems number of semaphores
417 * @return a semaphores set indentifier on success, -1 in other case
418 */
419int getShmLockId(maps* conf, int nsems){
420    int i;
421    union semun arg;
422    struct semid_ds buf;
423    struct sembuf sb;
424    semid sem_id;
425    int key=getKeyValue(conf);
426   
427    sem_id = semget(key, nsems, IPC_CREAT | IPC_EXCL | 0666);
428
429    if (sem_id >= 0) { /* we got it first */
430        sb.sem_op = 1; 
431        sb.sem_flg = 0;
432        arg.val=1;
433        for(sb.sem_num = 0; sb.sem_num < nsems; sb.sem_num++) { 
434            /* do a semop() to "free" the semaphores. */
435            /* this sets the sem_otime field, as needed below. */
436            if (semop(sem_id, &sb, 1) == -1) {
437                int e = errno;
438                semctl(sem_id, 0, IPC_RMID); /* clean up */
439                errno = e;
440                return -1; /* error, check errno */
441            }
442        }
443    } else if (errno == EEXIST) { /* someone else got it first */
444        int ready = 0;
445
446        sem_id = semget(key, nsems, 0); /* get the id */
447        if (sem_id < 0) return sem_id; /* error, check errno */
448
449        /* wait for other process to initialize the semaphore: */
450        arg.buf = &buf;
451        for(i = 0; i < MAX_RETRIES && !ready; i++) {
452            semctl(sem_id, nsems-1, IPC_STAT, arg);
453            if (arg.buf->sem_otime != 0) {
454#ifdef DEBUG
455              fprintf(stderr,"Semaphore acquired ...\n");
456#endif
457              ready = 1;
458            } else {
459#ifdef DEBUG
460              fprintf(stderr,"Retry to access the semaphore later ...\n");
461#endif
462              sleep(1);
463            }
464        }
465        errno = ZOO_LOCK_ACQUIRE_FAILED;
466        if (!ready) {
467#ifdef DEBUG
468          fprintf(stderr,"Unable to access the semaphore ...\n");
469#endif
470          errno = ETIME;
471          return -1;
472        }
473    } else {
474        return sem_id; /* error, check errno */
475    }
476#ifdef DEBUG
477    fprintf(stderr,"%d Created !\n",sem_id);
478#endif
479    return sem_id;
480}
481
482/**
483 * Try to remove a semaphore set.
484 *
485 * @param conf the map containing the setting of the main.cfg file
486 * @param nsems number of semaphores
487 * @return 0 if the semaphore can be removed, -1 in other case.
488 */
489int removeShmLock(maps* conf, int nsems){
490  union semun arg;
491  int sem_id=getShmLockId(conf,nsems);
492  if (semctl(sem_id, 0, IPC_RMID, arg) == -1) {
493    perror("semctl");
494    return -1;
495  }
496  return 0;
497}
498
499/**
500 * Lock a semaphore set.
501 *
502 * @param id the semaphores set indetifier
503 * @return 0 if the semaphore can be locked, -1 in other case.
504 */
505int lockShm(int id){
506  struct sembuf sb;
507  sb.sem_num = 0;
508  sb.sem_op = -1;  /* set to allocate resource */
509  sb.sem_flg = SEM_UNDO;
510  if (semop(id, &sb, 1) == -1){
511    perror("semop");
512    return -1;
513  }
514  return 0;
515}
516
517/**
518 * unLock a semaphore set.
519 *
520 * @param id the semaphores set indetifier
521 * @return 0 if the semaphore can be locked, -1 in other case.
522 */
523int unlockShm(int id){
524  struct sembuf sb;
525  sb.sem_num = 0;
526  sb.sem_op = 1;  /* free resource */
527  sb.sem_flg = SEM_UNDO;
528  if (semop(id, &sb, 1) == -1) {
529    perror("semop");
530    return -1;
531  }
532  return 0;
533}
534
535/**
536 * Stop handling status repport.
537 *
538 * @param conf the map containing the setting of the main.cfg file
539 */
540void unhandleStatus(maps *conf){
541  int shmid;
542  key_t key;
543  void *shm;
544  struct shmid_ds shmids;
545  map *tmpMap=getMapFromMaps(conf,"lenv","usid");
546  if(tmpMap!=NULL){
547    key=atoi(tmpMap->value);
548    if ((shmid = shmget(key, SHMSZ, IPC_CREAT | 0666)) < 0) {
549#ifdef DEBUG
550      fprintf(stderr,"shmget failed to update value\n");
551#endif
552    }else{
553      if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
554#ifdef DEBUG
555        fprintf(stderr,"shmat failed to update value\n");
556#endif
557      }else{
558        shmdt(shm);
559        shmctl(shmid,IPC_RMID,&shmids);
560      }
561    }
562  }
563}
564
565/**
566 * Update the current of the running service.
567 *
568 * @see getKeyValue, getShmLockId, lockShm
569 * @param conf the map containing the setting of the main.cfg file
570 * @return 0 on success, -2 if shmget failed, -1 if shmat failed
571 */
572int _updateStatus(maps *conf){
573  int shmid;
574  char *shm,*s,*s1;
575  map *tmpMap=NULL;
576  key_t key=getKeyValue(conf);
577  if(key!=-1){
578    semid lockid=getShmLockId(conf,1);
579    if(lockid<0)
580      return ZOO_LOCK_CREATE_FAILED;
581    if(lockShm(lockid)<0){
582      return ZOO_LOCK_ACQUIRE_FAILED;
583    }
584    if ((shmid = shmget(key, SHMSZ, IPC_CREAT | 0666)) < 0) {
585#ifdef DEBUG
586      fprintf(stderr,"shmget failed to create new Shared memory segment\n");
587#endif
588      unlockShm(lockid);
589      return -2;
590    }else{
591      if ((shm = (char*) shmat(shmid, NULL, 0)) == (char *) -1) {
592#ifdef DEBUG
593        fprintf(stderr,"shmat failed to update value\n");
594#endif
595        unlockShm(lockid);
596        return -1;
597      }
598      else{
599        tmpMap=getMapFromMaps(conf,"lenv","status");
600        s1=shm;
601        for(s=tmpMap->value;*s!=NULL && *s!=0;s++){
602          *s1++=*s;
603        }
604        *s1++='|';
605        tmpMap=getMapFromMaps(conf,"lenv","message");
606        if(tmpMap!=NULL)
607          for(s=tmpMap->value;*s!=NULL && *s!=0;s++){
608            *s1++=*s;
609        }
610        *s1=NULL;
611        shmdt((void *)shm);
612        unlockShm(lockid);
613      }
614    }
615  }
616  return 0;
617}
618
619/**
620 * Update the current of the running service.
621 *
622 * @see getKeyValue, getShmLockId, lockShm
623 * @param pid the semaphores
624 * @return 0 on success, -2 if shmget failed, -1 if shmat failed
625 */
626char* getStatus(int pid){
627  int shmid;
628  key_t key;
629  void *shm;
630  key=pid;
631  if ((shmid = shmget(key, SHMSZ, 0666)) < 0) {
632#ifdef DEBUG
633    fprintf(stderr,"shmget failed in getStatus\n");
634#endif
635  }else{
636    if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
637#ifdef DEBUG
638      fprintf(stderr,"shmat failed in getStatus\n");
639#endif
640    }else{
641      char *ret=strdup((char*)shm);
642      shmdt((void *)shm);
643      return ret;
644    }
645  }
646  return (char*)"-1";
647}
648
649#endif
650
651
652/**
653 * URLEncode an url
654 *
655 * @param str the url to encode
656 * @return a url-encoded version of str
657 * @warning be sure to free() the returned string after use
658 */
659char *url_encode(char *str) {
660  char *pstr = str, *buf = (char*) malloc(strlen(str) * 3 + 1), *pbuf = buf;
661  while (*pstr) {
662    if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') 
663      *pbuf++ = *pstr;
664    else if (*pstr == ' ') 
665      *pbuf++ = '+';
666    else 
667      *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), *pbuf++ = to_hex(*pstr & 15);
668    pstr++;
669  }
670  *pbuf = '\0';
671  return buf;
672}
673
674/**
675 * Decode an URLEncoded url
676 *
677 * @param str the URLEncoded url to decode
678 * @return a url-decoded version of str
679 * @warning be sure to free() the returned string after use
680 */
681char *url_decode(char *str) {
682  char *pstr = str, *buf = (char*) malloc(strlen(str) + 1), *pbuf = buf;
683  while (*pstr) {
684    if (*pstr == '%') {
685      if (pstr[1] && pstr[2]) {
686        *pbuf++ = from_hex(pstr[1]) << 4 | from_hex(pstr[2]);
687        pstr += 2;
688      }
689    } else if (*pstr == '+') { 
690      *pbuf++ = ' ';
691    } else {
692      *pbuf++ = *pstr;
693    }
694    pstr++;
695  }
696  *pbuf = '\0';
697  return buf;
698}
699
700/**
701 * Replace the first letter by its upper case version in a new char array
702 *
703 * @param tmp the char*
704 * @return a new char* with first letter in upper case
705 * @warning be sure to free() the returned string after use
706 */
707char *zCapitalize1(char *tmp){
708  char *res=zStrdup(tmp);
709  if(res[0]>=97 && res[0]<=122)
710    res[0]-=32;
711  return res;
712}
713
714/**
715 * Replace all letters by their upper case version in a new char array
716 *
717 * @param tmp the char*
718 * @return a new char* with first letter in upper case
719 * @warning be sure to free() the returned string after use
720 */
721char *zCapitalize(char *tmp){
722  int i=0;
723  char *res=zStrdup(tmp);
724  for(i=0;i<strlen(res);i++)
725    if(res[i]>=97 && res[i]<=122)
726      res[i]-=32;
727  return res;
728}
729
730/**
731 * Search for an existing XML namespace in usedNS.
732 *
733 * @param name the name of the XML namespace to search
734 * @return the index of the XML namespace found or -1 if not found.
735 */
736int zooXmlSearchForNs(const char* name){
737  int i;
738  int res=-1;
739  for(i=0;i<nbNs;i++)
740    if(strncasecmp(name,nsName[i],strlen(nsName[i]))==0){
741      res=i;
742      break;
743    }
744  return res;
745}
746
747/**
748 * Add an XML namespace to the usedNS if it was not already used.
749 *
750 * @param nr the xmlNodePtr to attach the XML namspace (can be NULL)
751 * @param url the url of the XML namespace to add
752 * @param name the name of the XML namespace to add
753 * @return the index of the XML namespace added.
754 */
755int zooXmlAddNs(xmlNodePtr nr,const char* url,const char* name){
756#ifdef DEBUG
757  fprintf(stderr,"zooXmlAddNs %d %s \n",nbNs,name);
758#endif
759  int currId=-1;
760  if(nbNs==0){
761    nbNs++;
762    currId=0;
763    nsName[currId]=strdup(name);
764    usedNs[currId]=xmlNewNs(nr,BAD_CAST url,BAD_CAST name);
765  }else{
766    currId=zooXmlSearchForNs(name);
767    if(currId<0){
768      nbNs++;
769      currId=nbNs-1;
770      nsName[currId]=strdup(name);
771      usedNs[currId]=xmlNewNs(nr,BAD_CAST url,BAD_CAST name);
772    }
773  }
774  return currId;
775}
776
777/**
778 * Free allocated memory to store used XML namespace.
779 */
780void zooXmlCleanupNs(){
781  int j;
782#ifdef DEBUG
783  fprintf(stderr,"zooXmlCleanup %d\n",nbNs);
784#endif
785  for(j=nbNs-1;j>=0;j--){
786#ifdef DEBUG
787    fprintf(stderr,"zooXmlCleanup %d\n",j);
788#endif
789    if(j==0)
790      xmlFreeNs(usedNs[j]);
791    free(nsName[j]);
792    nbNs--;
793  }
794  nbNs=0;
795}
796
797/**
798 * Add a XML document to the iDocs.
799 *
800 * @param value the string containing the XML document
801 * @return the index of the XML document added.
802 */
803int zooXmlAddDoc(const char* value){
804  int currId=0;
805  nbDocs++;
806  currId=nbDocs-1;
807  iDocs[currId]=xmlParseMemory(value,strlen(value));
808  return currId;
809}
810
811/**
812 * Free allocated memort to store XML documents
813 */
814void zooXmlCleanupDocs(){
815  int j;
816  for(j=nbDocs-1;j>=0;j--){
817    xmlFreeDoc(iDocs[j]);
818  }
819  nbDocs=0;
820}
821
822/**
823 * Generate a SOAP Envelope node when required (if the isSoap key of the [main]
824 * section is set to true).
825 *
826 * @param conf the conf maps containing the main.cfg settings
827 * @param n the node used as children of the generated soap:Envelope
828 * @return the generated soap:Envelope (if isSoap=true) or the input node n
829 *  (when isSoap=false)
830 */
831xmlNodePtr soapEnvelope(maps* conf,xmlNodePtr n){
832  map* soap=getMapFromMaps(conf,"main","isSoap");
833  if(soap!=NULL && strcasecmp(soap->value,"true")==0){
834    int lNbNs=nbNs;
835    nsName[lNbNs]=strdup("soap");
836    usedNs[lNbNs]=xmlNewNs(NULL,BAD_CAST "http://www.w3.org/2003/05/soap-envelope",BAD_CAST "soap");
837    nbNs++;
838    xmlNodePtr nr = xmlNewNode(usedNs[lNbNs], BAD_CAST "Envelope");
839    nsName[nbNs]=strdup("soap");
840    usedNs[nbNs]=xmlNewNs(nr,BAD_CAST "http://www.w3.org/2003/05/soap-envelope",BAD_CAST "soap");
841    nbNs++;
842    nsName[nbNs]=strdup("xsi");
843    usedNs[nbNs]=xmlNewNs(nr,BAD_CAST "http://www.w3.org/2001/XMLSchema-instance",BAD_CAST "xsi");
844    nbNs++;
845    xmlNsPtr ns_xsi=usedNs[nbNs-1];
846    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");
847    xmlNodePtr nr1 = xmlNewNode(usedNs[lNbNs], BAD_CAST "Body");
848    xmlAddChild(nr1,n);
849    xmlAddChild(nr,nr1);
850    return nr;
851  }else
852    return n;
853}
854
855/**
856 * Generate a WPS header.
857 *
858 * @param doc the document to add the header
859 * @param m the conf maps containing the main.cfg settings
860 * @param req the request type (GetCapabilities,DescribeProcess,Execute)
861 * @param rname the root node name
862 * @return the generated wps:rname xmlNodePtr (can be wps: Capabilities,
863 *  wps:ProcessDescriptions,wps:ExecuteResponse)
864 */
865xmlNodePtr printWPSHeader(xmlDocPtr doc,maps* m,const char* req,const char* rname){
866
867  xmlNsPtr ns,ns_xsi;
868  xmlNodePtr n;
869
870  int wpsId=zooXmlAddNs(NULL,"http://schemas.opengis.net/wps/1.0.0","wps");
871  ns=usedNs[wpsId];
872  n = xmlNewNode(ns, BAD_CAST rname);
873  zooXmlAddNs(n,"http://www.opengis.net/ows/1.1","ows");
874  xmlNewNs(n,BAD_CAST "http://www.opengis.net/wps/1.0.0",BAD_CAST "wps");
875  zooXmlAddNs(n,"http://www.w3.org/1999/xlink","xlink");
876  int xsiId=zooXmlAddNs(n,"http://www.w3.org/2001/XMLSchema-instance","xsi");
877  ns_xsi=usedNs[xsiId];
878 
879  char *tmp=(char*) malloc((86+strlen(req)+1)*sizeof(char));
880  sprintf(tmp,"http://www.opengis.net/wps/1.0.0 http://schemas.opengis.net/wps/1.0.0/wps%s_response.xsd",req);
881  xmlNewNsProp(n,ns_xsi,BAD_CAST "schemaLocation",BAD_CAST tmp);
882  free(tmp);
883  xmlNewProp(n,BAD_CAST "service",BAD_CAST "WPS");
884  xmlNewProp(n,BAD_CAST "version",BAD_CAST "1.0.0");
885  addLangAttr(n,m);
886  xmlNodePtr fn=soapEnvelope(m,n);
887  xmlDocSetRootElement(doc, fn);
888  return n;
889}
890
891/**
892 * Generate a Capabilities header.
893 *
894 * @param doc the document to add the header
895 * @param m the conf maps containing the main.cfg settings
896 * @return the generated wps:ProcessOfferings xmlNodePtr
897 */
898xmlNodePtr printGetCapabilitiesHeader(xmlDocPtr doc,maps* m){
899
900  xmlNsPtr ns,ns_ows,ns_xlink;
901  xmlNodePtr n,nc,nc1,nc2,nc3,nc4,nc5,nc6;
902  n = printWPSHeader(doc,m,"GetCapabilities","Capabilities");
903  maps* toto1=getMaps(m,"main");
904  char tmp[256];
905
906  int wpsId=zooXmlAddNs(NULL,"http://www.opengis.net/wps/1.0.0","wps");
907  ns=usedNs[wpsId];
908  int xlinkId=zooXmlAddNs(NULL,"http://www.w3.org/1999/xlink","xlink");
909  ns_xlink=usedNs[xlinkId];
910  int owsId=zooXmlAddNs(NULL,"http://www.opengis.net/ows/1.1","ows");
911  ns_ows=usedNs[owsId];
912
913  nc = xmlNewNode(ns_ows, BAD_CAST "ServiceIdentification");
914  maps* tmp4=getMaps(m,"identification");
915  if(tmp4!=NULL){
916    map* tmp2=tmp4->content;
917    const char *orderedFields[5];
918    orderedFields[0]="Title";
919    orderedFields[1]="Abstract";
920    orderedFields[2]="Keywords";
921    orderedFields[3]="Fees";
922    orderedFields[4]="AccessConstraints";
923    int oI=0;
924    for(oI=0;oI<5;oI++)
925      if((tmp2=getMap(tmp4->content,orderedFields[oI]))!=NULL){
926        if(strcasecmp(tmp2->name,"abstract")==0 ||
927           strcasecmp(tmp2->name,"title")==0 ||
928           strcasecmp(tmp2->name,"accessConstraints")==0 ||
929           strcasecmp(tmp2->name,"fees")==0){
930          tmp2->name[0]=toupper(tmp2->name[0]);
931          nc1 = xmlNewNode(ns_ows, BAD_CAST tmp2->name);
932          xmlAddChild(nc1,xmlNewText(BAD_CAST tmp2->value));
933          xmlAddChild(nc,nc1);
934        }
935        else
936          if(strcmp(tmp2->name,"keywords")==0){
937            nc1 = xmlNewNode(ns_ows, BAD_CAST "Keywords");
938            char *toto=tmp2->value;
939            char buff[256];
940            int i=0;
941            int j=0;
942            while(toto[i]){
943              if(toto[i]!=',' && toto[i]!=0){
944                buff[j]=toto[i];
945                buff[j+1]=0;
946                j++;
947              }
948              else{
949                nc2 = xmlNewNode(ns_ows, BAD_CAST "Keyword");
950                xmlAddChild(nc2,xmlNewText(BAD_CAST buff));           
951                xmlAddChild(nc1,nc2);
952                j=0;
953              }
954              i++;
955            }
956            if(strlen(buff)>0){
957              nc2 = xmlNewNode(ns_ows, BAD_CAST "Keyword");
958              xmlAddChild(nc2,xmlNewText(BAD_CAST buff));             
959              xmlAddChild(nc1,nc2);
960            }
961            xmlAddChild(nc,nc1);
962            nc2 = xmlNewNode(ns_ows, BAD_CAST "ServiceType");
963            xmlAddChild(nc2,xmlNewText(BAD_CAST "WPS"));
964            xmlAddChild(nc,nc2);
965            nc2 = xmlNewNode(ns_ows, BAD_CAST "ServiceTypeVersion");
966            xmlAddChild(nc2,xmlNewText(BAD_CAST "1.0.0"));
967            xmlAddChild(nc,nc2);
968          }
969        tmp2=tmp2->next;
970      }
971  }
972  else{
973    fprintf(stderr,"TMP4 NOT FOUND !!");
974    return NULL;
975  }
976  xmlAddChild(n,nc);
977
978  nc = xmlNewNode(ns_ows, BAD_CAST "ServiceProvider");
979  nc3 = xmlNewNode(ns_ows, BAD_CAST "ServiceContact");
980  nc4 = xmlNewNode(ns_ows, BAD_CAST "ContactInfo");
981  nc5 = xmlNewNode(ns_ows, BAD_CAST "Phone");
982  nc6 = xmlNewNode(ns_ows, BAD_CAST "Address");
983  tmp4=getMaps(m,"provider");
984  if(tmp4!=NULL){
985    map* tmp2=tmp4->content;
986    const char *tmpAddress[6];
987    tmpAddress[0]="addressDeliveryPoint";
988    tmpAddress[1]="addressCity";
989    tmpAddress[2]="addressAdministrativeArea";
990    tmpAddress[3]="addressPostalCode";
991    tmpAddress[4]="addressCountry";
992    tmpAddress[5]="addressElectronicMailAddress";
993    const char *tmpPhone[2];
994    tmpPhone[0]="phoneVoice";
995    tmpPhone[1]="phoneFacsimile";
996    const char *orderedFields[12];
997    orderedFields[0]="providerName";
998    orderedFields[1]="providerSite";
999    orderedFields[2]="individualName";
1000    orderedFields[3]="positionName";
1001    orderedFields[4]=tmpPhone[0];
1002    orderedFields[5]=tmpPhone[1];
1003    orderedFields[6]=tmpAddress[0];
1004    orderedFields[7]=tmpAddress[1];
1005    orderedFields[8]=tmpAddress[2];
1006    orderedFields[9]=tmpAddress[3];
1007    orderedFields[10]=tmpAddress[4];
1008    orderedFields[11]=tmpAddress[5];
1009    int oI=0;
1010    for(oI=0;oI<12;oI++)
1011      if((tmp2=getMap(tmp4->content,orderedFields[oI]))!=NULL){
1012        if(strcmp(tmp2->name,"keywords")!=0 &&
1013           strcmp(tmp2->name,"serverAddress")!=0 &&
1014           strcmp(tmp2->name,"lang")!=0){
1015          tmp2->name[0]=toupper(tmp2->name[0]);
1016          if(strcmp(tmp2->name,"ProviderName")==0){
1017            nc1 = xmlNewNode(ns_ows, BAD_CAST tmp2->name);
1018            xmlAddChild(nc1,xmlNewText(BAD_CAST tmp2->value));
1019            xmlAddChild(nc,nc1);
1020          }
1021          else{
1022            if(strcmp(tmp2->name,"ProviderSite")==0){
1023              nc1 = xmlNewNode(ns_ows, BAD_CAST tmp2->name);
1024              xmlNewNsProp(nc1,ns_xlink,BAD_CAST "href",BAD_CAST tmp2->value);
1025              xmlAddChild(nc,nc1);
1026            } 
1027            else 
1028              if(strcmp(tmp2->name,"IndividualName")==0 || 
1029                 strcmp(tmp2->name,"PositionName")==0){
1030                nc1 = xmlNewNode(ns_ows, BAD_CAST tmp2->name);
1031                xmlAddChild(nc1,xmlNewText(BAD_CAST tmp2->value));
1032                xmlAddChild(nc3,nc1);
1033              } 
1034              else 
1035                if(strncmp(tmp2->name,"Phone",5)==0){
1036                  int j;
1037                  for(j=0;j<2;j++)
1038                    if(strcasecmp(tmp2->name,tmpPhone[j])==0){
1039                      char *tmp4=tmp2->name;
1040                      nc1 = xmlNewNode(ns_ows, BAD_CAST tmp4+5);
1041                      xmlAddChild(nc1,xmlNewText(BAD_CAST tmp2->value));
1042                      xmlAddChild(nc5,nc1);
1043                    }
1044                }
1045                else 
1046                  if(strncmp(tmp2->name,"Address",7)==0){
1047                    int j;
1048                    for(j=0;j<6;j++)
1049                      if(strcasecmp(tmp2->name,tmpAddress[j])==0){
1050                        char *tmp4=tmp2->name;
1051                        nc1 = xmlNewNode(ns_ows, BAD_CAST tmp4+7);
1052                        xmlAddChild(nc1,xmlNewText(BAD_CAST tmp2->value));
1053                        xmlAddChild(nc6,nc1);
1054                      }
1055                  }
1056          }
1057        }
1058        else
1059          if(strcmp(tmp2->name,"keywords")==0){
1060            nc1 = xmlNewNode(ns_ows, BAD_CAST "Keywords");
1061            char *toto=tmp2->value;
1062            char buff[256];
1063            int i=0;
1064            int j=0;
1065            while(toto[i]){
1066              if(toto[i]!=',' && toto[i]!=0){
1067                buff[j]=toto[i];
1068                buff[j+1]=0;
1069                j++;
1070              }
1071              else{
1072                nc2 = xmlNewNode(ns_ows, BAD_CAST "Keyword");
1073                xmlAddChild(nc2,xmlNewText(BAD_CAST buff));           
1074                xmlAddChild(nc1,nc2);
1075                j=0;
1076              }
1077              i++;
1078            }
1079            if(strlen(buff)>0){
1080              nc2 = xmlNewNode(ns_ows, BAD_CAST "Keyword");
1081              xmlAddChild(nc2,xmlNewText(BAD_CAST buff));             
1082              xmlAddChild(nc1,nc2);
1083            }
1084            xmlAddChild(nc,nc1);
1085          }
1086        tmp2=tmp2->next;
1087      }
1088  }
1089  else{
1090    fprintf(stderr,"TMP4 NOT FOUND !!");
1091  }
1092  xmlAddChild(nc4,nc5);
1093  xmlAddChild(nc4,nc6);
1094  xmlAddChild(nc3,nc4);
1095  xmlAddChild(nc,nc3);
1096  xmlAddChild(n,nc);
1097
1098
1099  nc = xmlNewNode(ns_ows, BAD_CAST "OperationsMetadata");
1100  char *tmp2[3];
1101  tmp2[0]=strdup("GetCapabilities");
1102  tmp2[1]=strdup("DescribeProcess");
1103  tmp2[2]=strdup("Execute");
1104  int j=0;
1105
1106  if(toto1!=NULL){
1107    map* tmp=getMap(toto1->content,"serverAddress");
1108    if(tmp!=NULL){
1109      SERVICE_URL = strdup(tmp->value);
1110    }
1111    else
1112      SERVICE_URL = strdup("not_defined");
1113  }
1114  else
1115    SERVICE_URL = strdup("not_defined");
1116
1117  for(j=0;j<3;j++){
1118    nc1 = xmlNewNode(ns_ows, BAD_CAST "Operation");
1119    xmlNewProp(nc1,BAD_CAST "name",BAD_CAST tmp2[j]);
1120    nc2 = xmlNewNode(ns_ows, BAD_CAST "DCP");
1121    nc3 = xmlNewNode(ns_ows, BAD_CAST "HTTP");
1122    nc4 = xmlNewNode(ns_ows, BAD_CAST "Get");
1123    sprintf(tmp,"%s",SERVICE_URL);
1124    xmlNewNsProp(nc4,ns_xlink,BAD_CAST "href",BAD_CAST tmp);
1125    xmlAddChild(nc3,nc4);
1126    nc4 = xmlNewNode(ns_ows, BAD_CAST "Post");
1127    xmlNewNsProp(nc4,ns_xlink,BAD_CAST "href",BAD_CAST tmp);
1128    xmlAddChild(nc3,nc4);
1129    xmlAddChild(nc2,nc3);
1130    xmlAddChild(nc1,nc2);   
1131    xmlAddChild(nc,nc1);   
1132  }
1133  for(j=2;j>=0;j--)
1134    free(tmp2[j]);
1135  xmlAddChild(n,nc);
1136
1137  nc = xmlNewNode(ns, BAD_CAST "ProcessOfferings");
1138  xmlAddChild(n,nc);
1139
1140  nc1 = xmlNewNode(ns, BAD_CAST "Languages");
1141  nc2 = xmlNewNode(ns, BAD_CAST "Default");
1142  nc3 = xmlNewNode(ns, BAD_CAST "Supported");
1143 
1144  toto1=getMaps(m,"main");
1145  if(toto1!=NULL){
1146    map* tmp1=getMap(toto1->content,"lang");
1147    char *toto=tmp1->value;
1148    char buff[256];
1149    int i=0;
1150    int j=0;
1151    int dcount=0;
1152    while(toto[i]){
1153      if(toto[i]!=',' && toto[i]!=0){
1154        buff[j]=toto[i];
1155        buff[j+1]=0;
1156        j++;
1157      }
1158      else{
1159        nc4 = xmlNewNode(ns_ows, BAD_CAST "Language");
1160        xmlAddChild(nc4,xmlNewText(BAD_CAST buff));
1161        if(dcount==0){
1162          xmlAddChild(nc2,nc4);
1163          xmlAddChild(nc1,nc2);
1164          dcount++;
1165        }
1166        nc4 = xmlNewNode(ns_ows, BAD_CAST "Language");
1167        xmlAddChild(nc4,xmlNewText(BAD_CAST buff));
1168        xmlAddChild(nc3,nc4);
1169        j=0;
1170        buff[j]=0;
1171      }
1172      i++;
1173    }
1174    if(strlen(buff)>0){
1175      nc4 = xmlNewNode(ns_ows, BAD_CAST "Language");
1176      xmlAddChild(nc4,xmlNewText(BAD_CAST buff));             
1177      xmlAddChild(nc3,nc4);
1178    }
1179  }
1180  xmlAddChild(nc1,nc3);
1181  xmlAddChild(n,nc1);
1182 
1183  free(SERVICE_URL);
1184  return nc;
1185}
1186
1187/**
1188 * Add prefix to the service name.
1189 *
1190 * @param conf the conf maps containing the main.cfg settings
1191 * @param level the map containing the level information
1192 * @param serv the service structure created from the zcfg file
1193 */
1194void addPrefix(maps* conf,map* level,service* serv){
1195  if(level!=NULL){
1196    char key[25];
1197    char* prefix=NULL;
1198    int clevel=atoi(level->value);
1199    int cl=0;
1200    for(cl=0;cl<clevel;cl++){
1201      sprintf(key,"sprefix_%d",cl);
1202      map* tmp2=getMapFromMaps(conf,"lenv",key);
1203      if(tmp2!=NULL){
1204        if(prefix==NULL)
1205          prefix=zStrdup(tmp2->value);
1206        else{
1207          int plen=strlen(prefix);
1208          prefix=(char*)realloc(prefix,(plen+strlen(tmp2->value)+2)*sizeof(char));
1209          memcpy(prefix+plen,tmp2->value,strlen(tmp2->value)*sizeof(char));
1210          prefix[plen+strlen(tmp2->value)]=0;
1211        }
1212      }
1213    }
1214    if(prefix!=NULL){
1215      char* tmp0=strdup(serv->name);
1216      free(serv->name);
1217      serv->name=(char*)malloc((strlen(prefix)+strlen(tmp0)+1)*sizeof(char));
1218      sprintf(serv->name,"%s%s",prefix,tmp0);
1219      free(tmp0);
1220      free(prefix);
1221      prefix=NULL;
1222    }
1223  }
1224}
1225
1226/**
1227 * Generate a wps:Process node for a servie and add it to a given node.
1228 *
1229 * @param m the conf maps containing the main.cfg settings
1230 * @param registry the profile registry if any
1231 * @param nc the XML node to add the Process node
1232 * @param serv the service structure created from the zcfg file
1233 * @return the generated wps:ProcessOfferings xmlNodePtr
1234 */
1235void printGetCapabilitiesForProcess(maps* m,xmlNodePtr nc,service* serv){
1236  xmlNsPtr ns,ns_ows,ns_xlink;
1237  xmlNodePtr n=NULL,nc1,nc2;
1238  /**
1239   * Initialize or get existing namspaces
1240   */
1241  int wpsId=zooXmlAddNs(NULL,"http://www.opengis.net/wps/1.0.0","wps");
1242  ns=usedNs[wpsId];
1243  int owsId=zooXmlAddNs(NULL,"http://www.opengis.net/ows/1.1","ows");
1244  ns_ows=usedNs[owsId];
1245  int xlinkId=zooXmlAddNs(n,"http://www.w3.org/1999/xlink","xlink");
1246  ns_xlink=usedNs[xlinkId];
1247
1248  map* tmp1;
1249  if(serv->content!=NULL){
1250    nc1 = xmlNewNode(ns, BAD_CAST "Process");
1251    tmp1=getMap(serv->content,"processVersion");
1252    if(tmp1!=NULL)
1253      xmlNewNsProp(nc1,ns,BAD_CAST "processVersion",BAD_CAST tmp1->value);
1254    else
1255      xmlNewNsProp(nc1,ns,BAD_CAST "processVersion",BAD_CAST "1");
1256    map* tmp3=getMapFromMaps(m,"lenv","level");
1257    addPrefix(m,tmp3,serv);
1258    printDescription(nc1,ns_ows,serv->name,serv->content);
1259    tmp1=serv->metadata;
1260    while(tmp1!=NULL){
1261      nc2 = xmlNewNode(ns_ows, BAD_CAST "Metadata");
1262      xmlNewNsProp(nc2,ns_xlink,BAD_CAST tmp1->name,BAD_CAST tmp1->value);
1263      xmlAddChild(nc1,nc2);
1264      tmp1=tmp1->next;
1265    }
1266    xmlAddChild(nc,nc1);
1267  }
1268}
1269
1270/**
1271 * Generate a ProcessDescription node for a servie and add it to a given node.
1272 *
1273 * @param m the conf maps containing the main.cfg settings
1274 * @param nc the XML node to add the Process node
1275 * @param serv the servive structure created from the zcfg file
1276 * @return the generated wps:ProcessOfferings xmlNodePtr
1277 */
1278void printDescribeProcessForProcess(maps* m,xmlNodePtr nc,service* serv){
1279  xmlNsPtr ns,ns_ows,ns_xlink;
1280  xmlNodePtr n,nc1;
1281
1282  n=nc;
1283 
1284  int wpsId=zooXmlAddNs(NULL,"http://schemas.opengis.net/wps/1.0.0","wps");
1285  ns=usedNs[wpsId];
1286  int owsId=zooXmlAddNs(NULL,"http://www.opengis.net/ows/1.1","ows");
1287  ns_ows=usedNs[owsId];
1288  int xlinkId=zooXmlAddNs(NULL,"http://www.w3.org/1999/xlink","xlink");
1289  ns_xlink=usedNs[xlinkId];
1290
1291  nc = xmlNewNode(NULL, BAD_CAST "ProcessDescription");
1292  const char *tmp4[3];
1293  tmp4[0]="processVersion";
1294  tmp4[1]="storeSupported";
1295  tmp4[2]="statusSupported";
1296  int j=0;
1297  map* tmp1=NULL;
1298  for(j=0;j<3;j++){
1299    tmp1=getMap(serv->content,tmp4[j]);
1300    if(tmp1!=NULL){
1301      if(j==0)
1302        xmlNewNsProp(nc,ns,BAD_CAST "processVersion",BAD_CAST tmp1->value);     
1303      else
1304        xmlNewProp(nc,BAD_CAST tmp4[j],BAD_CAST tmp1->value);     
1305    }
1306    else{
1307      if(j>0)
1308        xmlNewProp(nc,BAD_CAST tmp4[j],BAD_CAST "true");
1309      else
1310        xmlNewNsProp(nc,ns,BAD_CAST "processVersion",BAD_CAST "1");
1311    }
1312  }
1313 
1314  tmp1=getMapFromMaps(m,"lenv","level");
1315  addPrefix(m,tmp1,serv);
1316  printDescription(nc,ns_ows,serv->name,serv->content);
1317
1318  tmp1=serv->metadata;
1319  while(tmp1!=NULL){
1320    nc1 = xmlNewNode(ns_ows, BAD_CAST "Metadata");
1321    xmlNewNsProp(nc1,ns_xlink,BAD_CAST tmp1->name,BAD_CAST tmp1->value);
1322    xmlAddChild(nc,nc1);
1323    tmp1=tmp1->next;
1324  }
1325
1326  tmp1=getMap(serv->content,"Profile");
1327  if(tmp1!=NULL){
1328    nc1 = xmlNewNode(ns, BAD_CAST "Profile");
1329    xmlAddChild(nc1,xmlNewText(BAD_CAST tmp1->value));
1330    xmlAddChild(nc,nc1);
1331  }
1332
1333  if(serv->inputs!=NULL){
1334    nc1 = xmlNewNode(NULL, BAD_CAST "DataInputs");
1335    elements* e=serv->inputs;
1336    printFullDescription(1,e,"Input",ns_ows,nc1);
1337    xmlAddChild(nc,nc1);
1338  }
1339
1340  nc1 = xmlNewNode(NULL, BAD_CAST "ProcessOutputs");
1341  elements* e=serv->outputs;
1342  printFullDescription(0,e,"Output",ns_ows,nc1);
1343  xmlAddChild(nc,nc1);
1344
1345  xmlAddChild(n,nc);
1346
1347}
1348
1349/**
1350 * Generate the required XML tree for the detailled metadata informations of
1351 * inputs or outputs
1352 *
1353 * @param in 1 in case of inputs, 0 for outputs
1354 * @param elem the elements structure containing the metadata informations
1355 * @param type the name ("Input" or "Output") of the XML node to create
1356 * @param ns_ows the ows XML namespace
1357 * @param nc1 the XML node to use to add the created tree
1358 */
1359void printFullDescription(int in,elements *elem,const char* type,xmlNsPtr ns_ows,xmlNodePtr nc1){
1360  const char *orderedFields[13];
1361  orderedFields[0]="mimeType";
1362  orderedFields[1]="encoding";
1363  orderedFields[2]="schema";
1364  orderedFields[3]="dataType";
1365  orderedFields[4]="uom";
1366  orderedFields[5]="CRS";
1367  orderedFields[6]="value";
1368  orderedFields[7]="AllowedValues";
1369  orderedFields[8]="range";
1370  orderedFields[9]="rangeMin";
1371  orderedFields[10]="rangeMax";
1372  orderedFields[11]="rangeClosure";
1373  orderedFields[12]="rangeSpace";
1374
1375  xmlNodePtr nc2,nc3,nc4,nc5,nc6,nc7,nc8,nc9;
1376  elements* e=elem;
1377
1378  map* tmp1=NULL;
1379  while(e!=NULL){
1380    int default1=0;
1381    int isAnyValue=1;
1382    nc2 = xmlNewNode(NULL, BAD_CAST type);
1383    if(strncmp(type,"Input",5)==0){
1384      tmp1=getMap(e->content,"minOccurs");
1385      if(tmp1!=NULL){
1386        xmlNewProp(nc2,BAD_CAST tmp1->name,BAD_CAST tmp1->value);
1387      }else
1388        xmlNewProp(nc2,BAD_CAST "minOccurs",BAD_CAST "0");
1389      tmp1=getMap(e->content,"maxOccurs");
1390      if(tmp1!=NULL){
1391        if(strcasecmp(tmp1->value,"unbounded")!=0)
1392          xmlNewProp(nc2,BAD_CAST tmp1->name,BAD_CAST tmp1->value);
1393        else
1394          xmlNewProp(nc2,BAD_CAST "maxOccurs",BAD_CAST "1000");
1395      }else
1396        xmlNewProp(nc2,BAD_CAST "maxOccurs",BAD_CAST "1");
1397      if((tmp1=getMap(e->content,"maximumMegabytes"))!=NULL){
1398        xmlNewProp(nc2,BAD_CAST "maximumMegabytes",BAD_CAST tmp1->value);
1399      }
1400    }
1401
1402    printDescription(nc2,ns_ows,e->name,e->content);
1403
1404    /**
1405     * Build the (Literal/Complex/BoundingBox)Data node
1406     */
1407    if(strncmp(type,"Output",6)==0){
1408      if(strncasecmp(e->format,"LITERALDATA",strlen(e->format))==0)
1409        nc3 = xmlNewNode(NULL, BAD_CAST "LiteralOutput");
1410      else if(strncasecmp(e->format,"COMPLEXDATA",strlen(e->format))==0)
1411        nc3 = xmlNewNode(NULL, BAD_CAST "ComplexOutput");
1412      else if(strncasecmp(e->format,"BOUNDINGBOXDATA",strlen(e->format))==0)
1413        nc3 = xmlNewNode(NULL, BAD_CAST "BoundingBoxOutput");
1414      else
1415        nc3 = xmlNewNode(NULL, BAD_CAST e->format);
1416    }else{
1417      if(strncasecmp(e->format,"LITERALDATA",strlen(e->format))==0){
1418        nc3 = xmlNewNode(NULL, BAD_CAST "LiteralData");
1419      }
1420      else if(strncasecmp(e->format,"COMPLEXDATA",strlen(e->format))==0)
1421        nc3 = xmlNewNode(NULL, BAD_CAST "ComplexData");
1422      else if(strncasecmp(e->format,"BOUNDINGBOXDATA",strlen(e->format))==0)
1423        nc3 = xmlNewNode(NULL, BAD_CAST "BoundingBoxData");
1424      else
1425        nc3 = xmlNewNode(NULL, BAD_CAST e->format);
1426    }
1427
1428    iotype* _tmp0=NULL;
1429    iotype* _tmp=e->defaults;
1430    int datatype=0;
1431    bool hasUOM=false;
1432    bool hasUOM1=false;
1433    if(_tmp!=NULL){
1434      if(strcmp(e->format,"LiteralOutput")==0 ||
1435         strcmp(e->format,"LiteralData")==0){
1436        datatype=1;
1437        nc4 = xmlNewNode(NULL, BAD_CAST "UOMs");
1438        nc5 = xmlNewNode(NULL, BAD_CAST "Default");
1439      }
1440      else if(strcmp(e->format,"BoundingBoxOutput")==0 ||
1441              strcmp(e->format,"BoundingBoxData")==0){
1442        datatype=2;
1443        nc5 = xmlNewNode(NULL, BAD_CAST "Default");
1444      }
1445      else{
1446        nc4 = xmlNewNode(NULL, BAD_CAST "Default");
1447        nc5 = xmlNewNode(NULL, BAD_CAST "Format");
1448      }
1449     
1450      tmp1=_tmp->content;
1451
1452      if((tmp1=getMap(_tmp->content,"DataType"))!=NULL){
1453        nc8 = xmlNewNode(ns_ows, BAD_CAST "DataType");
1454        xmlAddChild(nc8,xmlNewText(BAD_CAST tmp1->value));
1455        char tmp[1024];
1456        sprintf(tmp,"http://www.w3.org/TR/xmlschema-2/#%s",tmp1->value);
1457        xmlNewNsProp(nc8,ns_ows,BAD_CAST "reference",BAD_CAST tmp);
1458        xmlAddChild(nc3,nc8);
1459        datatype=1;
1460      }
1461
1462      if(strncmp(type,"Input",5)==0){
1463
1464        if((tmp1=getMap(_tmp->content,"AllowedValues"))!=NULL){
1465          nc6 = xmlNewNode(ns_ows, BAD_CAST "AllowedValues");
1466          char *token,*saveptr1;
1467          token=strtok_r(tmp1->value,",",&saveptr1);
1468          while(token!=NULL){
1469            nc7 = xmlNewNode(ns_ows, BAD_CAST "Value");
1470            char *tmps=strdup(token);
1471            tmps[strlen(tmps)]=0;
1472            xmlAddChild(nc7,xmlNewText(BAD_CAST tmps));
1473            free(tmps);
1474            xmlAddChild(nc6,nc7);
1475            token=strtok_r(NULL,",",&saveptr1);
1476          }
1477          if(getMap(_tmp->content,"range")!=NULL ||
1478             getMap(_tmp->content,"rangeMin")!=NULL ||
1479             getMap(_tmp->content,"rangeMax")!=NULL ||
1480             getMap(_tmp->content,"rangeClosure")!=NULL )
1481            goto doRange;
1482          xmlAddChild(nc3,nc6);
1483          isAnyValue=-1;
1484        }
1485
1486        tmp1=getMap(_tmp->content,"range");
1487        if(tmp1==NULL)
1488          tmp1=getMap(_tmp->content,"rangeMin");
1489        if(tmp1==NULL)
1490          tmp1=getMap(_tmp->content,"rangeMax");
1491       
1492        if(tmp1!=NULL && isAnyValue==1){
1493          nc6 = xmlNewNode(ns_ows, BAD_CAST "AllowedValues");
1494        doRange:
1495         
1496          /**
1497           * Range: Table 46 OGC Web Services Common Standard
1498           */
1499          nc8 = xmlNewNode(ns_ows, BAD_CAST "Range");
1500         
1501          map* tmp0=getMap(tmp1,"range");
1502          if(tmp0!=NULL){
1503            char* pToken;
1504            char* orig=zStrdup(tmp0->value);
1505            /**
1506             * RangeClosure: Table 47 OGC Web Services Common Standard
1507             */
1508            const char *tmp="closed";
1509            if(orig[0]=='[' && orig[strlen(orig)-1]=='[')
1510              tmp="closed-open";
1511            else
1512              if(orig[0]==']' && orig[strlen(orig)-1]==']')
1513                tmp="open-closed";
1514              else
1515                if(orig[0]==']' && orig[strlen(orig)-1]=='[')
1516                  tmp="open";
1517            xmlNewNsProp(nc8,ns_ows,BAD_CAST "rangeClosure",BAD_CAST tmp);
1518            pToken=strtok(orig,",");
1519            int nci0=0;
1520            while(pToken!=NULL){
1521              char *tmpStr=(char*) malloc((strlen(pToken))*sizeof(char));
1522              if(nci0==0){
1523                nc7 = xmlNewNode(ns_ows, BAD_CAST "MinimumValue");
1524                strncpy( tmpStr, pToken+1, strlen(pToken)-1 );
1525                tmpStr[strlen(pToken)-1] = '\0';
1526              }else{
1527                nc7 = xmlNewNode(ns_ows, BAD_CAST "MaximumValue");
1528                const char* bkt;
1529                if ( ( bkt = strchr(pToken, '[') ) != NULL || ( bkt = strchr(pToken, ']') ) != NULL ){
1530                  strncpy( tmpStr, pToken, bkt - pToken );
1531                  tmpStr[bkt - pToken] = '\0';
1532                }
1533              }
1534              xmlAddChild(nc7,xmlNewText(BAD_CAST tmpStr));
1535              free(tmpStr);
1536              xmlAddChild(nc8,nc7);
1537              nci0++;
1538              pToken = strtok(NULL,",");
1539            }               
1540            if(getMap(tmp1,"rangeSpacing")==NULL){
1541              nc7 = xmlNewNode(ns_ows, BAD_CAST "Spacing");
1542              xmlAddChild(nc7,xmlNewText(BAD_CAST "1"));
1543              xmlAddChild(nc8,nc7);
1544            }
1545            free(orig);
1546          }else{
1547           
1548            tmp0=getMap(tmp1,"rangeMin");
1549            if(tmp0!=NULL){
1550              nc7 = xmlNewNode(ns_ows, BAD_CAST "MinimumValue");
1551              xmlAddChild(nc7,xmlNewText(BAD_CAST tmp0->value));
1552              xmlAddChild(nc8,nc7);
1553            }else{
1554              nc7 = xmlNewNode(ns_ows, BAD_CAST "MinimumValue");
1555              xmlAddChild(nc8,nc7);
1556            }
1557            tmp0=getMap(tmp1,"rangeMax");
1558            if(tmp0!=NULL){
1559              nc7 = xmlNewNode(ns_ows, BAD_CAST "MaximumValue");
1560              xmlAddChild(nc7,xmlNewText(BAD_CAST tmp0->value));
1561              xmlAddChild(nc8,nc7);
1562            }else{
1563              nc7 = xmlNewNode(ns_ows, BAD_CAST "MaximumValue");
1564              xmlAddChild(nc8,nc7);
1565            }
1566            tmp0=getMap(tmp1,"rangeSpacing");
1567            if(tmp0!=NULL){
1568              nc7 = xmlNewNode(ns_ows, BAD_CAST "Spacing");
1569              xmlAddChild(nc7,xmlNewText(BAD_CAST tmp0->value));
1570              xmlAddChild(nc8,nc7);
1571            }
1572            tmp0=getMap(tmp1,"rangeClosure");
1573            if(tmp0!=NULL){
1574              const char *tmp="closed";
1575              if(strcasecmp(tmp0->value,"co")==0)
1576                tmp="closed-open";
1577              else
1578                if(strcasecmp(tmp0->value,"oc")==0)
1579                  tmp="open-closed";
1580                else
1581                  if(strcasecmp(tmp0->value,"o")==0)
1582                    tmp="open";
1583              xmlNewNsProp(nc8,ns_ows,BAD_CAST "rangeClosure",BAD_CAST tmp);
1584            }else
1585              xmlNewNsProp(nc8,ns_ows,BAD_CAST "rangeClosure",BAD_CAST "closed");
1586          }
1587          if(_tmp0==NULL){
1588            xmlAddChild(nc6,nc8);
1589            _tmp0=e->supported;
1590            if(_tmp0!=NULL &&
1591               (getMap(_tmp0->content,"range")!=NULL ||
1592                getMap(_tmp0->content,"rangeMin")!=NULL ||
1593                getMap(_tmp0->content,"rangeMax")!=NULL ||
1594                getMap(_tmp0->content,"rangeClosure")!=NULL )){
1595              tmp1=_tmp0->content;
1596              goto doRange;
1597            }
1598          }else{
1599            _tmp0=_tmp0->next;
1600            if(_tmp0!=NULL){
1601              xmlAddChild(nc6,nc8);
1602              if(getMap(_tmp0->content,"range")!=NULL ||
1603                 getMap(_tmp0->content,"rangeMin")!=NULL ||
1604                 getMap(_tmp0->content,"rangeMax")!=NULL ||
1605                 getMap(_tmp0->content,"rangeClosure")!=NULL ){
1606                tmp1=_tmp0->content;
1607                goto doRange;
1608              }
1609            }
1610          }
1611          xmlAddChild(nc6,nc8);
1612          xmlAddChild(nc3,nc6);
1613          isAnyValue=-1;
1614        }
1615       
1616      }
1617     
1618      int oI=0;
1619      for(oI=0;oI<13;oI++)
1620        if((tmp1=getMap(_tmp->content,orderedFields[oI]))!=NULL){
1621#ifdef DEBUG
1622          printf("DATATYPE DEFAULT ? %s\n",tmp1->name);
1623#endif
1624          if(strcmp(tmp1->name,"asReference")!=0 &&
1625             strncasecmp(tmp1->name,"DataType",8)!=0 &&
1626             strcasecmp(tmp1->name,"extension")!=0 &&
1627             strcasecmp(tmp1->name,"value")!=0 &&
1628             strcasecmp(tmp1->name,"AllowedValues")!=0 &&
1629             strncasecmp(tmp1->name,"range",5)!=0){
1630            if(datatype!=1){
1631              char *tmp2=zCapitalize1(tmp1->name);
1632              nc9 = xmlNewNode(NULL, BAD_CAST tmp2);
1633              free(tmp2);
1634            }
1635            else{
1636              char *tmp2=zCapitalize(tmp1->name);
1637              nc9 = xmlNewNode(ns_ows, BAD_CAST tmp2);
1638              free(tmp2);
1639            }
1640            xmlAddChild(nc9,xmlNewText(BAD_CAST tmp1->value));
1641            xmlAddChild(nc5,nc9);
1642            if(strcasecmp(tmp1->name,"uom")==0)
1643              hasUOM1=true;
1644            hasUOM=true;
1645          }else 
1646         
1647            tmp1=tmp1->next;
1648        }
1649   
1650   
1651      if(datatype!=2){
1652        if(hasUOM==true){
1653          xmlAddChild(nc4,nc5);
1654          xmlAddChild(nc3,nc4);
1655        }else{
1656          if(hasUOM1==false){
1657            xmlFreeNode(nc5);
1658            if(datatype==1)
1659              xmlFreeNode(nc4);
1660          }
1661        }
1662      }else{
1663        xmlAddChild(nc3,nc5);
1664      }
1665     
1666      if(datatype!=1 && default1<0){
1667        xmlFreeNode(nc5);
1668        if(datatype!=2)
1669          xmlFreeNode(nc4);
1670      }
1671
1672      map* metadata=e->metadata;
1673      xmlNodePtr n=NULL;
1674      int xlinkId=zooXmlAddNs(n,"http://www.w3.org/1999/xlink","xlink");
1675      xmlNsPtr ns_xlink=usedNs[xlinkId];
1676
1677      while(metadata!=NULL){
1678        nc6=xmlNewNode(ns_ows, BAD_CAST "Metadata");
1679        xmlNewNsProp(nc6,ns_xlink,BAD_CAST metadata->name,BAD_CAST metadata->value);
1680        xmlAddChild(nc2,nc6);
1681        metadata=metadata->next;
1682      }
1683
1684    }
1685
1686    _tmp=e->supported;
1687    if(_tmp==NULL && datatype!=1)
1688      _tmp=e->defaults;
1689
1690    int hasSupported=-1;
1691
1692    while(_tmp!=NULL){
1693      if(hasSupported<0){
1694        if(datatype==0){
1695          nc4 = xmlNewNode(NULL, BAD_CAST "Supported");
1696          nc5 = xmlNewNode(NULL, BAD_CAST "Format");
1697        }
1698        else
1699          nc5 = xmlNewNode(NULL, BAD_CAST "Supported");
1700        hasSupported=0;
1701      }else
1702        if(datatype==0)
1703          nc5 = xmlNewNode(NULL, BAD_CAST "Format");
1704      tmp1=_tmp->content;
1705      int oI=0;
1706      for(oI=0;oI<6;oI++)
1707        if((tmp1=getMap(_tmp->content,orderedFields[oI]))!=NULL){
1708#ifdef DEBUG
1709          printf("DATATYPE SUPPORTED ? %s\n",tmp1->name);
1710#endif
1711          if(strcmp(tmp1->name,"asReference")!=0 && 
1712             strcmp(tmp1->name,"value")!=0 && 
1713             strcmp(tmp1->name,"DataType")!=0 &&
1714             strcasecmp(tmp1->name,"extension")!=0){
1715            if(datatype!=1){
1716              char *tmp2=zCapitalize1(tmp1->name);
1717              nc6 = xmlNewNode(NULL, BAD_CAST tmp2);
1718              free(tmp2);
1719            }
1720            else{
1721              char *tmp2=zCapitalize(tmp1->name);
1722              nc6 = xmlNewNode(ns_ows, BAD_CAST tmp2);
1723              free(tmp2);
1724            }
1725            if(datatype==2){
1726              char *tmpv,*tmps;
1727              tmps=strtok_r(tmp1->value,",",&tmpv);
1728              while(tmps){
1729                xmlAddChild(nc6,xmlNewText(BAD_CAST tmps));
1730                tmps=strtok_r(NULL,",",&tmpv);
1731                if(tmps){
1732                  char *tmp2=zCapitalize1(tmp1->name);
1733                  nc6 = xmlNewNode(NULL, BAD_CAST tmp2);
1734                  free(tmp2);
1735                }
1736              }
1737            }
1738            else{
1739              xmlAddChild(nc6,xmlNewText(BAD_CAST tmp1->value));
1740            }
1741            xmlAddChild(nc5,nc6);
1742          }
1743          tmp1=tmp1->next;
1744        }
1745      if(hasSupported<=0){
1746        if(datatype==0){
1747          xmlAddChild(nc4,nc5);
1748          xmlAddChild(nc3,nc4);
1749        }else{
1750          if(datatype!=1)
1751            xmlAddChild(nc3,nc5);
1752        }
1753        hasSupported=1;
1754      }
1755      else
1756        if(datatype==0){
1757          xmlAddChild(nc4,nc5);
1758          xmlAddChild(nc3,nc4);
1759        }
1760        else
1761          if(datatype!=1)
1762            xmlAddChild(nc3,nc5);
1763
1764      _tmp=_tmp->next;
1765    }
1766
1767    if(hasSupported==0){
1768      if(datatype==0)
1769        xmlFreeNode(nc4);
1770      xmlFreeNode(nc5);
1771    }
1772
1773    _tmp=e->defaults;
1774    if(datatype==1 && hasUOM1==true){
1775      xmlAddChild(nc4,nc5);
1776      xmlAddChild(nc3,nc4);
1777    }
1778
1779    if(in>0 && datatype==1 &&
1780       getMap(_tmp->content,"AllowedValues")==NULL &&
1781       getMap(_tmp->content,"range")==NULL &&
1782       getMap(_tmp->content,"rangeMin")==NULL &&
1783       getMap(_tmp->content,"rangeMax")==NULL &&
1784       getMap(_tmp->content,"rangeClosure")==NULL ){
1785      tmp1=getMap(_tmp->content,"dataType");
1786      if(tmp1!=NULL && strcasecmp(tmp1->value,"boolean")==0){
1787        nc6 = xmlNewNode(ns_ows, BAD_CAST "AllowedValues");
1788        nc7 = xmlNewNode(ns_ows, BAD_CAST "Value");
1789        xmlAddChild(nc7,xmlNewText(BAD_CAST "true"));
1790        xmlAddChild(nc6,nc7);
1791        nc7 = xmlNewNode(ns_ows, BAD_CAST "Value");
1792        xmlAddChild(nc7,xmlNewText(BAD_CAST "false"));
1793        xmlAddChild(nc6,nc7);
1794        xmlAddChild(nc3,nc6);
1795      }
1796      else
1797        xmlAddChild(nc3,xmlNewNode(ns_ows, BAD_CAST "AnyValue"));
1798    }
1799   
1800    if(_tmp!=NULL && (tmp1=getMap(_tmp->content,"value"))!=NULL){
1801      nc7 = xmlNewNode(NULL, BAD_CAST "DefaultValue");
1802      xmlAddChild(nc7,xmlNewText(BAD_CAST tmp1->value));
1803      xmlAddChild(nc3,nc7);
1804    }
1805   
1806    xmlAddChild(nc2,nc3);
1807   
1808    xmlAddChild(nc1,nc2);
1809   
1810    e=e->next;
1811  }
1812}
1813
1814/**
1815 * Generate a wps:Execute XML document.
1816 *
1817 * @param m the conf maps containing the main.cfg settings
1818 * @param request the map representing the HTTP request
1819 * @param pid the process identifier linked to a service
1820 * @param serv the serv structure created from the zcfg file
1821 * @param service the service name
1822 * @param status the status returned by the service
1823 * @param inputs the inputs provided
1824 * @param outputs the outputs generated by the service
1825 */
1826void printProcessResponse(maps* m,map* request, int pid,service* serv,const char* service,int status,maps* inputs,maps* outputs){
1827  xmlNsPtr ns,ns_ows,ns_xlink;
1828  xmlNodePtr nr,n,nc,nc1=NULL,nc3;
1829  xmlDocPtr doc;
1830  time_t time1; 
1831  time(&time1);
1832  nr=NULL;
1833  doc = xmlNewDoc(BAD_CAST "1.0");
1834  n = printWPSHeader(doc,m,"Execute","ExecuteResponse");
1835  int wpsId=zooXmlAddNs(NULL,"http://www.opengis.net/wps/1.0.0","wps");
1836  ns=usedNs[wpsId];
1837  int owsId=zooXmlAddNs(NULL,"http://www.opengis.net/ows/1.1","ows");
1838  ns_ows=usedNs[owsId];
1839  int xlinkId=zooXmlAddNs(NULL,"http://www.w3.org/1999/xlink","xlink");
1840  ns_xlink=usedNs[xlinkId];
1841
1842  char tmp[256];
1843  char url[1024];
1844  char stored_path[1024];
1845  memset(tmp,0,256);
1846  memset(url,0,1024);
1847  memset(stored_path,0,1024);
1848  maps* tmp_maps=getMaps(m,"main");
1849  if(tmp_maps!=NULL){
1850    map* tmpm1=getMap(tmp_maps->content,"serverAddress");
1851    /**
1852     * Check if the ZOO Service GetStatus is available in the local directory.
1853     * If yes, then it uses a reference to an URL which the client can access
1854     * to get information on the status of a running Service (using the
1855     * percentCompleted attribute).
1856     * Else fallback to the initial method using the xml file to write in ...
1857     */
1858    char ntmp[1024];
1859#ifndef WIN32
1860    getcwd(ntmp,1024);
1861#else
1862    _getcwd(ntmp,1024);
1863#endif
1864    struct stat myFileInfo;
1865    int statRes;
1866    char file_path[1024];
1867    sprintf(file_path,"%s/GetStatus.zcfg",ntmp);
1868    statRes=stat(file_path,&myFileInfo);
1869    if(statRes==0){
1870      char currentSid[128];
1871      map* tmpm=getMap(tmp_maps->content,"rewriteUrl");
1872      map *tmp_lenv=NULL;
1873      tmp_lenv=getMapFromMaps(m,"lenv","usid");
1874      if(tmp_lenv==NULL)
1875        sprintf(currentSid,"%i",pid);
1876      else
1877        sprintf(currentSid,"%s",tmp_lenv->value);
1878      if(tmpm==NULL || strcasecmp(tmpm->value,"false")==0){
1879        sprintf(url,"%s?request=Execute&service=WPS&version=1.0.0&Identifier=GetStatus&DataInputs=sid=%s&RawDataOutput=Result",tmpm1->value,currentSid);
1880      }else{
1881        if(strlen(tmpm->value)>0)
1882          if(strcasecmp(tmpm->value,"true")!=0)
1883            sprintf(url,"%s/%s/GetStatus/%s",tmpm1->value,tmpm->value,currentSid);
1884          else
1885            sprintf(url,"%s/GetStatus/%s",tmpm1->value,currentSid);
1886        else
1887          sprintf(url,"%s/?request=Execute&service=WPS&version=1.0.0&Identifier=GetStatus&DataInputs=sid=%s&RawDataOutput=Result",tmpm1->value,currentSid);
1888      }
1889    }else{
1890      int lpid;
1891      map* tmpm2=getMapFromMaps(m,"lenv","usid");
1892      lpid=atoi(tmpm2->value);
1893      tmpm2=getMap(tmp_maps->content,"tmpUrl");
1894      if(tmpm1!=NULL && tmpm2!=NULL){
1895        if( strncasecmp( tmpm2->value, "http://", 7) == 0 ||
1896            strncasecmp( tmpm2->value, "https://", 8 ) == 0 ){
1897          sprintf(url,"%s/%s_%i.xml",tmpm2->value,service,lpid);
1898        }else
1899          sprintf(url,"%s/%s/%s_%i.xml",tmpm1->value,tmpm2->value,service,lpid);
1900      }
1901    }
1902    if(tmpm1!=NULL)
1903      sprintf(tmp,"%s",tmpm1->value);
1904    int lpid;
1905    tmpm1=getMapFromMaps(m,"lenv","usid");
1906    lpid=atoi(tmpm1->value);
1907    tmpm1=getMapFromMaps(m,"main","TmpPath");
1908    sprintf(stored_path,"%s/%s_%i.xml",tmpm1->value,service,lpid);
1909  }
1910
1911
1912
1913  xmlNewProp(n,BAD_CAST "serviceInstance",BAD_CAST tmp);
1914  map* test=getMap(request,"storeExecuteResponse");
1915  bool hasStoredExecuteResponse=false;
1916  if(test!=NULL && strcasecmp(test->value,"true")==0){
1917    xmlNewProp(n,BAD_CAST "statusLocation",BAD_CAST url);
1918    hasStoredExecuteResponse=true;
1919  }
1920
1921  nc = xmlNewNode(ns, BAD_CAST "Process");
1922  map* tmp2=getMap(serv->content,"processVersion");
1923  if(tmp2!=NULL)
1924    xmlNewNsProp(nc,ns,BAD_CAST "processVersion",BAD_CAST tmp2->value);
1925 
1926  map* tmpI=getMapFromMaps(m,"lenv","oIdentifier");
1927  printDescription(nc,ns_ows,tmpI->value,serv->content);
1928
1929  xmlAddChild(n,nc);
1930
1931  nc = xmlNewNode(ns, BAD_CAST "Status");
1932  const struct tm *tm;
1933  size_t len;
1934  time_t now;
1935  char *tmp1;
1936  map *tmpStatus;
1937 
1938  now = time ( NULL );
1939  tm = localtime ( &now );
1940
1941  tmp1 = (char*)malloc((TIME_SIZE+1)*sizeof(char));
1942
1943  len = strftime ( tmp1, TIME_SIZE, "%Y-%m-%dT%I:%M:%SZ", tm );
1944
1945  xmlNewProp(nc,BAD_CAST "creationTime",BAD_CAST tmp1);
1946
1947  char sMsg[2048];
1948  switch(status){
1949  case SERVICE_SUCCEEDED:
1950    nc1 = xmlNewNode(ns, BAD_CAST "ProcessSucceeded");
1951    sprintf(sMsg,_("The service \"%s\" ran successfully."),serv->name);
1952    nc3=xmlNewText(BAD_CAST sMsg);
1953    xmlAddChild(nc1,nc3);
1954    break;
1955  case SERVICE_STARTED:
1956    nc1 = xmlNewNode(ns, BAD_CAST "ProcessStarted");
1957    tmpStatus=getMapFromMaps(m,"lenv","status");
1958    xmlNewProp(nc1,BAD_CAST "percentCompleted",BAD_CAST tmpStatus->value);
1959    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);
1960    nc3=xmlNewText(BAD_CAST sMsg);
1961    xmlAddChild(nc1,nc3);
1962    break;
1963  case SERVICE_ACCEPTED:
1964    nc1 = xmlNewNode(ns, BAD_CAST "ProcessAccepted");
1965    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);
1966    nc3=xmlNewText(BAD_CAST sMsg);
1967    xmlAddChild(nc1,nc3);
1968    break;
1969  case SERVICE_FAILED:
1970    nc1 = xmlNewNode(ns, BAD_CAST "ProcessFailed");
1971    map *errorMap;
1972    map *te;
1973    te=getMapFromMaps(m,"lenv","code");
1974    if(te!=NULL)
1975      errorMap=createMap("code",te->value);
1976    else
1977      errorMap=createMap("code","NoApplicableCode");
1978    te=getMapFromMaps(m,"lenv","message");
1979    if(te!=NULL)
1980      addToMap(errorMap,"text",_ss(te->value));
1981    else
1982      addToMap(errorMap,"text",_("No more information available"));
1983    nc3=createExceptionReportNode(m,errorMap,0);
1984    freeMap(&errorMap);
1985    free(errorMap);
1986    xmlAddChild(nc1,nc3);
1987    break;
1988  default :
1989    printf(_("error code not know : %i\n"),status);
1990    //exit(1);
1991    break;
1992  }
1993  xmlAddChild(nc,nc1);
1994  xmlAddChild(n,nc);
1995  free(tmp1);
1996
1997#ifdef DEBUG
1998  fprintf(stderr,"printProcessResponse 1 161\n");
1999#endif
2000
2001  map* lineage=getMap(request,"lineage");
2002  if(lineage!=NULL && strcasecmp(lineage->value,"true")==0){
2003    nc = xmlNewNode(ns, BAD_CAST "DataInputs");
2004    maps* mcursor=inputs;
2005    elements* scursor=NULL;
2006    while(mcursor!=NULL /*&& scursor!=NULL*/){
2007      scursor=getElements(serv->inputs,mcursor->name);
2008      printIOType(doc,nc,ns,ns_ows,ns_xlink,scursor,mcursor,"Input");
2009      mcursor=mcursor->next;
2010    }
2011    xmlAddChild(n,nc);
2012   
2013#ifdef DEBUG
2014    fprintf(stderr,"printProcessResponse 1 177\n");
2015#endif
2016
2017    nc = xmlNewNode(ns, BAD_CAST "OutputDefinitions");
2018    mcursor=outputs;
2019    scursor=NULL;
2020    while(mcursor!=NULL){
2021      scursor=getElements(serv->outputs,mcursor->name);
2022      printOutputDefinitions(doc,nc,ns,ns_ows,scursor,mcursor,"Output");
2023      mcursor=mcursor->next;
2024    }
2025    xmlAddChild(n,nc);
2026  }
2027#ifdef DEBUG
2028  fprintf(stderr,"printProcessResponse 1 190\n");
2029#endif
2030
2031  /**
2032   * Display the process output only when requested !
2033   */
2034  if(status==SERVICE_SUCCEEDED){
2035    nc = xmlNewNode(ns, BAD_CAST "ProcessOutputs");
2036    maps* mcursor=outputs;
2037    elements* scursor=serv->outputs;
2038    map* testResponse=getMap(request,"RawDataOutput");
2039    if(testResponse==NULL)
2040      testResponse=getMap(request,"ResponseDocument");
2041    while(mcursor!=NULL){
2042      map* tmp0=getMap(mcursor->content,"inRequest");
2043      scursor=getElements(serv->outputs,mcursor->name);
2044      if(scursor!=NULL){
2045        if(testResponse==NULL || tmp0==NULL)
2046          printIOType(doc,nc,ns,ns_ows,ns_xlink,scursor,mcursor,"Output");
2047        else
2048          if(tmp0!=NULL && strncmp(tmp0->value,"true",4)==0)
2049            printIOType(doc,nc,ns,ns_ows,ns_xlink,scursor,mcursor,"Output");
2050      }else
2051        /**
2052         * In case there was no definition found in the ZCFG file but
2053         * present in the service code
2054         */
2055        printIOType(doc,nc,ns,ns_ows,ns_xlink,scursor,mcursor,"Output");
2056      mcursor=mcursor->next;
2057    }
2058    xmlAddChild(n,nc);
2059  }
2060
2061  if(hasStoredExecuteResponse==true && status!=SERVICE_STARTED){
2062    semid lid=getShmLockId(m,1);
2063    if(lid<0){
2064      /* If the lock failed */
2065      errorException(m,_("Lock failed."),"InternalError",NULL);
2066      xmlFreeDoc(doc);
2067      xmlCleanupParser();
2068      zooXmlCleanupNs();
2069      return;
2070    }
2071    else{
2072#ifdef DEBUG
2073      fprintf(stderr,"LOCK %s %d !\n",__FILE__,__LINE__);
2074#endif
2075      lockShm(lid);
2076      /* We need to write the ExecuteResponse Document somewhere */
2077      FILE* output=fopen(stored_path,"w");
2078      if(output==NULL){
2079        /* If the file cannot be created return an ExceptionReport */
2080        char tmpMsg[1024];
2081        sprintf(tmpMsg,_("Unable to create the file \"%s\" for storing the ExecuteResponse."),stored_path);
2082
2083        errorException(m,tmpMsg,"InternalError",NULL);
2084        xmlFreeDoc(doc);
2085        xmlCleanupParser();
2086        zooXmlCleanupNs();
2087        unlockShm(lid);
2088        return;
2089      }
2090      xmlChar *xmlbuff;
2091      int buffersize;
2092      xmlDocDumpFormatMemoryEnc(doc, &xmlbuff, &buffersize, "UTF-8", 1);
2093      fwrite(xmlbuff,1,xmlStrlen(xmlbuff)*sizeof(char),output);
2094      xmlFree(xmlbuff);
2095      fclose(output);
2096#ifdef DEBUG
2097      fprintf(stderr,"UNLOCK %s %d !\n",__FILE__,__LINE__);
2098#endif
2099      unlockShm(lid);
2100      map* test1=getMap(request,"status");
2101      if(test1==NULL || strcasecmp(test1->value,"true")!=0){
2102        removeShmLock(m,1);
2103      }
2104    }
2105  }
2106  printDocument(m,doc,pid);
2107
2108  xmlCleanupParser();
2109  zooXmlCleanupNs();
2110}
2111
2112/**
2113 * Print a XML document.
2114 *
2115 * @param m the conf maps containing the main.cfg settings
2116 * @param doc the XML document
2117 * @param pid the process identifier linked to a service
2118 */
2119void printDocument(maps* m, xmlDocPtr doc,int pid){
2120  char *encoding=getEncoding(m);
2121  if(pid==getpid()){
2122    printHeaders(m);
2123    printf("Content-Type: text/xml; charset=%s\r\nStatus: 200 OK\r\n\r\n",encoding);
2124  }
2125  fflush(stdout);
2126  xmlChar *xmlbuff;
2127  int buffersize;
2128  /*
2129   * Dump the document to a buffer and print it on stdout
2130   * for demonstration purposes.
2131   */
2132  xmlDocDumpFormatMemoryEnc(doc, &xmlbuff, &buffersize, encoding, 1);
2133  printf("%s",xmlbuff);
2134  fflush(stdout);
2135  /*
2136   * Free associated memory.
2137   */
2138  xmlFree(xmlbuff);
2139  xmlFreeDoc(doc);
2140  xmlCleanupParser();
2141  zooXmlCleanupNs();
2142}
2143
2144/**
2145 * Print a XML document.
2146 *
2147 * @param doc the XML document (unused)
2148 * @param nc the XML node to add the output definition
2149 * @param ns_wps the wps XML namespace
2150 * @param ns_ows the ows XML namespace
2151 * @param e the output elements
2152 * @param m the conf maps containing the main.cfg settings
2153 * @param type the type (unused)
2154 */
2155void printOutputDefinitions(xmlDocPtr doc,xmlNodePtr nc,xmlNsPtr ns_wps,xmlNsPtr ns_ows,elements* e,maps* m,const char* type){
2156  xmlNodePtr nc1;
2157  nc1=xmlNewNode(ns_wps, BAD_CAST type);
2158  map *tmp=NULL; 
2159  if(e!=NULL && e->defaults!=NULL)
2160    tmp=e->defaults->content;
2161  else{
2162    /*
2163    dumpElements(e);
2164    */
2165    return;
2166  }
2167  while(tmp!=NULL){
2168    if(strncasecmp(tmp->name,"MIMETYPE",strlen(tmp->name))==0
2169       || strncasecmp(tmp->name,"ENCODING",strlen(tmp->name))==0
2170       || strncasecmp(tmp->name,"SCHEMA",strlen(tmp->name))==0
2171       || strncasecmp(tmp->name,"UOM",strlen(tmp->name))==0)
2172    xmlNewProp(nc1,BAD_CAST tmp->name,BAD_CAST tmp->value);
2173    tmp=tmp->next;
2174  }
2175  tmp=getMap(e->defaults->content,"asReference");
2176  if(tmp==NULL)
2177    xmlNewProp(nc1,BAD_CAST "asReference",BAD_CAST "false");
2178
2179  tmp=e->content;
2180
2181  printDescription(nc1,ns_ows,m->name,e->content);
2182
2183  xmlAddChild(nc,nc1);
2184
2185}
2186
2187/**
2188 * Generate XML nodes describing inputs or outputs metadata.
2189 *
2190 * @param doc the XML document
2191 * @param nc the XML node to add the definition
2192 * @param ns_wps the wps namespace
2193 * @param ns_ows the ows namespace
2194 * @param ns_xlink the xlink namespace
2195 * @param e the output elements
2196 * @param m the conf maps containing the main.cfg settings
2197 * @param type the type
2198 */
2199void printIOType(xmlDocPtr doc,xmlNodePtr nc,xmlNsPtr ns_wps,xmlNsPtr ns_ows,xmlNsPtr ns_xlink,elements* e,maps* m,const char* type){
2200
2201  xmlNodePtr nc1,nc2,nc3;
2202  nc1=xmlNewNode(ns_wps, BAD_CAST type);
2203  map *tmp=NULL;
2204  if(e!=NULL)
2205    tmp=e->content;
2206  else
2207    tmp=m->content;
2208
2209  nc2=xmlNewNode(ns_ows, BAD_CAST "Identifier");
2210  if(e!=NULL)
2211    nc3=xmlNewText(BAD_CAST e->name);
2212  else
2213    nc3=xmlNewText(BAD_CAST m->name);
2214
2215  xmlAddChild(nc2,nc3);
2216  xmlAddChild(nc1,nc2);
2217  xmlAddChild(nc,nc1);
2218  if(e!=NULL)
2219    tmp=getMap(e->content,"Title");
2220  else
2221    tmp=getMap(m->content,"Title");
2222 
2223  if(tmp!=NULL){
2224    nc2=xmlNewNode(ns_ows, BAD_CAST tmp->name);
2225    nc3=xmlNewText(BAD_CAST _ss(tmp->value));
2226    xmlAddChild(nc2,nc3); 
2227    xmlAddChild(nc1,nc2);
2228  }
2229
2230  if(e!=NULL)
2231    tmp=getMap(e->content,"Abstract");
2232  else
2233    tmp=getMap(m->content,"Abstract");
2234
2235  if(tmp!=NULL){
2236    nc2=xmlNewNode(ns_ows, BAD_CAST tmp->name);
2237    nc3=xmlNewText(BAD_CAST _ss(tmp->value));
2238    xmlAddChild(nc2,nc3); 
2239    xmlAddChild(nc1,nc2);
2240    xmlAddChild(nc,nc1);
2241  }
2242
2243  /**
2244   * IO type Reference or full Data ?
2245   */
2246  map *tmpMap=getMap(m->content,"Reference");
2247  if(tmpMap==NULL){
2248    nc2=xmlNewNode(ns_wps, BAD_CAST "Data");
2249    if(e!=NULL){
2250      if(strncasecmp(e->format,"LiteralOutput",strlen(e->format))==0)
2251         nc3=xmlNewNode(ns_wps, BAD_CAST "LiteralData");
2252      else
2253        if(strncasecmp(e->format,"ComplexOutput",strlen(e->format))==0)
2254                   nc3=xmlNewNode(ns_wps, BAD_CAST "ComplexData");
2255          else if(strncasecmp(e->format,"BoundingBoxOutput",strlen(e->format))==0)
2256            nc3=xmlNewNode(ns_wps, BAD_CAST "BoundingBoxData");
2257          else
2258            nc3=xmlNewNode(ns_wps, BAD_CAST e->format);
2259    }
2260    else {
2261      map* tmpV=getMapFromMaps(m,"format","value");
2262      if(tmpV!=NULL)
2263            nc3=xmlNewNode(ns_wps, BAD_CAST tmpV->value);
2264      else
2265            nc3=xmlNewNode(ns_wps, BAD_CAST "LiteralData");
2266    } 
2267    tmp=m->content;
2268
2269    while(tmp!=NULL){
2270      if(strcasecmp(tmp->name,"mimeType")==0 ||
2271             strcasecmp(tmp->name,"encoding")==0 ||
2272             strcasecmp(tmp->name,"schema")==0 ||
2273             strcasecmp(tmp->name,"datatype")==0 ||
2274             strcasecmp(tmp->name,"uom")==0) {
2275
2276            xmlNewProp(nc3,BAD_CAST tmp->name,BAD_CAST tmp->value);
2277      }
2278      tmp=tmp->next;
2279      xmlAddChild(nc2,nc3);
2280    }
2281    if(e!=NULL && e->format!=NULL && strcasecmp(e->format,"BoundingBoxData")==0) {
2282      map* bb=getMap(m->content,"value");
2283      if(bb!=NULL) {
2284            map* tmpRes=parseBoundingBox(bb->value);
2285            printBoundingBox(ns_ows,nc3,tmpRes);
2286            freeMap(&tmpRes);
2287            free(tmpRes);
2288      }
2289    }
2290        else {
2291      if(e!=NULL)
2292            tmp=getMap(e->defaults->content,"mimeType");
2293      else
2294            tmp=NULL;
2295       
2296        map* tmp1=getMap(m->content,"encoding");
2297        map* tmp2=getMap(m->content,"mimeType");
2298        map* tmp3=getMap(m->content,"value");
2299        int hasValue=1;
2300        if(tmp3==NULL){
2301              tmp3=createMap("value","");
2302              hasValue=-1;
2303        }
2304
2305       if( ( tmp1 != NULL && strncmp(tmp1->value,"base64",6) == 0 )  // if encoding is base64
2306                ||                                                           // or if
2307                ( tmp2 != NULL && ( strstr(tmp2->value,"text") == NULL //  mime type is not text
2308                                    &&                                   //  nor
2309                                                            strstr(tmp2->value,"xml") == NULL  //  xml
2310                                                                &&                                          // nor
2311                                                                strstr(tmp2->value,"javascript") == NULL  // javascript
2312                                                                &&
2313                                                                strstr(tmp2->value,"json") == NULL
2314                                                                &&
2315                                                                strstr(tmp2->value,"ecmascript") == NULL
2316                                                                &&
2317                                                                // include for backwards compatibility,
2318                                                                // although correct mime type is ...kml+xml:
2319                                                                strstr(tmp2->value,"google-earth.kml") == NULL                                                         
2320                                                          )
2321                )
2322                  ) {                                                      // then     
2323              map* rs=getMap(m->content,"size");                       // obtain size
2324              bool isSized=true;
2325              if(rs==NULL){
2326                char tmp1[1024];
2327                sprintf(tmp1,"%ld",strlen(tmp3->value));
2328                rs=createMap("size",tmp1);
2329                isSized=false;
2330              }
2331
2332            xmlAddChild(nc3,xmlNewText(BAD_CAST base64(tmp3->value, atoi(rs->value))));  // base 64 encode in XML
2333               
2334            if(tmp1==NULL || (tmp1!=NULL && strncmp(tmp1->value,"base64",6)!=0)) {
2335               xmlAttrPtr ap = xmlHasProp(nc3, BAD_CAST "encoding");
2336               if (ap != NULL) {
2337                  xmlRemoveProp(ap);
2338               }                       
2339               xmlNewProp(nc3,BAD_CAST "encoding",BAD_CAST "base64");
2340                }
2341               
2342            if(!isSized){
2343              freeMap(&rs);
2344              free(rs);
2345            }
2346      }
2347      else if (tmp2!=NULL) {                                 // else (text-based format)
2348            if(strstr(tmp2->value, "javascript") != NULL ||      //    if javascript put code in CDATA block
2349               strstr(tmp2->value, "json") != NULL ||            //    (will not be parsed by XML reader)
2350               strstr(tmp2->value, "ecmascript") != NULL
2351                  ) {
2352               xmlAddChild(nc3,xmlNewCDataBlock(doc,BAD_CAST tmp3->value,strlen(tmp3->value)));
2353                }   
2354            else {                                                     // else
2355               if (strstr(tmp2->value, "xml") != NULL ||                 // if XML-based format
2356                           // include for backwards compatibility,
2357                           // although correct mime type is ...kml+xml:           
2358                   strstr(tmp2->value, "google-earth.kml") != NULL
2359                          ) { 
2360                         
2361                  int li=zooXmlAddDoc(tmp3->value);
2362                  xmlDocPtr doc = iDocs[li];
2363                  xmlNodePtr ir = xmlDocGetRootElement(doc);
2364                  xmlAddChild(nc3,ir);
2365               }
2366               else                                                     // else
2367                  xmlAddChild(nc3,xmlNewText(BAD_CAST tmp3->value));    //   add text node
2368            }
2369            xmlAddChild(nc2,nc3);
2370      }
2371      else {
2372            xmlAddChild(nc3,xmlNewText(BAD_CAST tmp3->value));
2373      }
2374         
2375      if(hasValue<0) {
2376            freeMap(&tmp3);
2377            free(tmp3);
2378      }
2379    }
2380  }
2381  else { // Reference
2382    tmpMap=getMap(m->content,"Reference");
2383    nc3=nc2=xmlNewNode(ns_wps, BAD_CAST "Reference");
2384    if(strcasecmp(type,"Output")==0)
2385      xmlNewProp(nc3,BAD_CAST "href",BAD_CAST tmpMap->value);
2386    else
2387      xmlNewNsProp(nc3,ns_xlink,BAD_CAST "href",BAD_CAST tmpMap->value);
2388   
2389        tmp=m->content;
2390    while(tmp!=NULL) {
2391      if(strcasecmp(tmp->name,"mimeType")==0 ||
2392             strcasecmp(tmp->name,"encoding")==0 ||
2393             strcasecmp(tmp->name,"schema")==0 ||
2394             strcasecmp(tmp->name,"datatype")==0 ||
2395             strcasecmp(tmp->name,"uom")==0){
2396
2397            if(strcasecmp(tmp->name,"datatype")==0)
2398              xmlNewProp(nc3,BAD_CAST "mimeType",BAD_CAST "text/plain");
2399            else
2400              xmlNewProp(nc3,BAD_CAST tmp->name,BAD_CAST tmp->value);
2401      }
2402      tmp=tmp->next;
2403      xmlAddChild(nc2,nc3);
2404    }
2405  }
2406  xmlAddChild(nc1,nc2);
2407  xmlAddChild(nc,nc1);
2408}
2409
2410/**
2411 * Create XML node with basic ows metadata informations (Identifier,Title,Abstract)
2412 *
2413 * @param root the root XML node to add the description
2414 * @param ns_ows the ows XML namespace
2415 * @param identifier the identifier to use
2416 * @param amap the map containing the ows metadata informations
2417 */
2418void printDescription(xmlNodePtr root,xmlNsPtr ns_ows,const char* identifier,map* amap){
2419  xmlNodePtr nc2 = xmlNewNode(ns_ows, BAD_CAST "Identifier");
2420 
2421  xmlAddChild(nc2,xmlNewText(BAD_CAST identifier));
2422  xmlAddChild(root,nc2);
2423  map* tmp=amap;
2424  const char *tmp2[2];
2425  tmp2[0]="Title";
2426  tmp2[1]="Abstract";
2427  int j=0;
2428  for(j=0;j<2;j++){
2429    map* tmp1=getMap(tmp,tmp2[j]);
2430    if(tmp1!=NULL){
2431      nc2 = xmlNewNode(ns_ows, BAD_CAST tmp2[j]);
2432      xmlAddChild(nc2,xmlNewText(BAD_CAST _ss(tmp1->value)));
2433      xmlAddChild(root,nc2);
2434    }
2435  }
2436}
2437
2438/**
2439 * Access the value of the encoding key in a maps
2440 *
2441 * @param m the maps to search for the encoding key
2442 * @return the value of the encoding key in a maps if encoding key exists,
2443 *  "UTF-8" in other case.
2444 */
2445char* getEncoding(maps* m){
2446  if(m!=NULL){
2447    map* tmp=getMap(m->content,"encoding");
2448    if(tmp!=NULL){
2449      return tmp->value;
2450    }
2451    else
2452      return (char*)"UTF-8";
2453  }
2454  else
2455    return (char*)"UTF-8"; 
2456}
2457
2458/**
2459 * Access the value of the version key in a maps
2460 *
2461 * @param m the maps to search for the version key
2462 * @return the value of the version key in a maps if encoding key exists,
2463 *  "1.0.0" in other case.
2464 */
2465char* getVersion(maps* m){
2466  if(m!=NULL){
2467    map* tmp=getMap(m->content,"version");
2468    if(tmp!=NULL){
2469      return tmp->value;
2470    }
2471    else
2472      return (char*)"1.0.0";
2473  }
2474  else
2475    return (char*)"1.0.0";
2476}
2477
2478/**
2479 * Print an OWS ExceptionReport Document and HTTP headers (when required)
2480 * depending on the code.
2481 * Set hasPrinted value to true in the [lenv] section.
2482 *
2483 * @param m the maps containing the settings of the main.cfg file
2484 * @param s the map containing the text,code,locator keys
2485 */
2486void printExceptionReportResponse(maps* m,map* s){
2487  if(getMapFromMaps(m,"lenv","hasPrinted")!=NULL)
2488    return;
2489  int buffersize;
2490  xmlDocPtr doc;
2491  xmlChar *xmlbuff;
2492  xmlNodePtr n;
2493
2494  zooXmlCleanupNs();
2495  doc = xmlNewDoc(BAD_CAST "1.0");
2496  maps* tmpMap=getMaps(m,"main");
2497  char *encoding=getEncoding(tmpMap);
2498  const char *exceptionCode;
2499 
2500  map* tmp=getMap(s,"code");
2501  if(tmp!=NULL){
2502    if(strcmp(tmp->value,"OperationNotSupported")==0 ||
2503       strcmp(tmp->value,"NoApplicableCode")==0)
2504      exceptionCode="501 Not Implemented";
2505    else
2506      if(strcmp(tmp->value,"MissingParameterValue")==0 ||
2507         strcmp(tmp->value,"InvalidUpdateSequence")==0 ||
2508         strcmp(tmp->value,"OptionNotSupported")==0 ||
2509         strcmp(tmp->value,"VersionNegotiationFailed")==0 ||
2510         strcmp(tmp->value,"InvalidParameterValue")==0)
2511        exceptionCode="400 Bad request";
2512      else
2513        exceptionCode="501 Internal Server Error";
2514  }
2515  else
2516    exceptionCode="501 Internal Server Error";
2517
2518  if(m!=NULL){
2519    map *tmpSid=getMapFromMaps(m,"lenv","sid");
2520    if(tmpSid!=NULL){
2521      if( getpid()==atoi(tmpSid->value) ){
2522        printHeaders(m);
2523        printf("Content-Type: text/xml; charset=%s\r\nStatus: %s\r\n\r\n",encoding,exceptionCode);
2524      }
2525    }
2526    else{
2527      printHeaders(m);
2528      printf("Content-Type: text/xml; charset=%s\r\nStatus: %s\r\n\r\n",encoding,exceptionCode);
2529    }
2530  }else{
2531    printf("Content-Type: text/xml; charset=%s\r\nStatus: %s\r\n\r\n",encoding,exceptionCode);
2532  }
2533  n=createExceptionReportNode(m,s,1);
2534  xmlDocSetRootElement(doc, n);
2535  xmlDocDumpFormatMemoryEnc(doc, &xmlbuff, &buffersize, encoding, 1);
2536  printf("%s",xmlbuff);
2537  fflush(stdout);
2538  xmlFreeDoc(doc);
2539  xmlFree(xmlbuff);
2540  xmlCleanupParser();
2541  zooXmlCleanupNs();
2542  if(m!=NULL)
2543    setMapInMaps(m,"lenv","hasPrinted","true");
2544}
2545
2546/**
2547 * Create an OWS ExceptionReport Node.
2548 *
2549 * @param m the conf maps
2550 * @param s the map containing the text,code,locator keys
2551 * @param use_ns (0/1) choose if you want to generate an ExceptionReport or
2552 *  ows:ExceptionReport node respectively
2553 * @return the ExceptionReport/ows:ExceptionReport node
2554 */
2555xmlNodePtr createExceptionReportNode(maps* m,map* s,int use_ns){
2556 
2557  xmlNsPtr ns,ns_xsi;
2558  xmlNodePtr n,nc,nc1;
2559
2560  int nsid=zooXmlAddNs(NULL,"http://www.opengis.net/ows","ows");
2561  ns=usedNs[nsid];
2562  if(use_ns==0){
2563    ns=NULL;
2564  }
2565  n = xmlNewNode(ns, BAD_CAST "ExceptionReport");
2566  if(use_ns==1){
2567    xmlNewNs(n,BAD_CAST "http://www.opengis.net/ows/1.1",BAD_CAST"ows");
2568    int xsiId=zooXmlAddNs(n,"http://www.w3.org/2001/XMLSchema-instance","xsi");
2569    ns_xsi=usedNs[xsiId];
2570    xmlNewNsProp(n,ns_xsi,BAD_CAST "schemaLocation",BAD_CAST "http://www.opengis.net/ows/1.1 http://schemas.opengis.net/ows/1.1.0/owsExceptionReport.xsd");
2571  }
2572
2573
2574  addLangAttr(n,m);
2575  xmlNewProp(n,BAD_CAST "version",BAD_CAST "1.1.0");
2576 
2577  int length=1;
2578  int cnt=0;
2579  map* len=getMap(s,"length");
2580  if(len!=NULL)
2581    length=atoi(len->value);
2582  for(cnt=0;cnt<length;cnt++){
2583    nc = xmlNewNode(ns, BAD_CAST "Exception");
2584   
2585    map* tmp=getMapArray(s,"code",cnt);
2586    if(tmp==NULL)
2587      tmp=getMap(s,"code");
2588    if(tmp!=NULL)
2589      xmlNewProp(nc,BAD_CAST "exceptionCode",BAD_CAST tmp->value);
2590    else
2591      xmlNewProp(nc,BAD_CAST "exceptionCode",BAD_CAST "NoApplicableCode");
2592   
2593    tmp=getMapArray(s,"locator",cnt);
2594    if(tmp==NULL)
2595      tmp=getMap(s,"locator");
2596    if(tmp!=NULL && strcasecmp(tmp->value,"NULL")!=0)
2597      xmlNewProp(nc,BAD_CAST "locator",BAD_CAST tmp->value);
2598
2599    tmp=getMapArray(s,"text",cnt);
2600    nc1 = xmlNewNode(ns, BAD_CAST "ExceptionText");
2601    if(tmp!=NULL){
2602      xmlNodePtr txt=xmlNewText(BAD_CAST tmp->value);
2603      xmlAddChild(nc1,txt);
2604    }
2605    else{
2606      xmlNodeSetContent(nc1, BAD_CAST _("No debug message available"));
2607    }
2608    xmlAddChild(nc,nc1);
2609    xmlAddChild(n,nc);
2610  }
2611  return n;
2612}
2613
2614/**
2615 * Print an OWS ExceptionReport.
2616 *
2617 * @param m the conf maps
2618 * @param message the error message
2619 * @param errorcode the error code
2620 * @param locator the potential locator
2621 */
2622int errorException(maps *m, const char *message, const char *errorcode, const char *locator) 
2623{
2624  map* errormap = createMap("text", message);
2625  addToMap(errormap,"code", errorcode);
2626  if(locator!=NULL)
2627    addToMap(errormap,"locator", locator);
2628  else
2629    addToMap(errormap,"locator", "NULL");
2630  printExceptionReportResponse(m,errormap);
2631  freeMap(&errormap);
2632  free(errormap);
2633  return -1;
2634}
2635
2636/**
2637 * Read a file generated by a service.
2638 *
2639 * @param m the conf maps
2640 * @param content the output item
2641 * @param filename the file to read
2642 */
2643void readGeneratedFile(maps* m,map* content,char* filename){
2644  FILE * file=fopen(filename,"rb");
2645  if(file==NULL){
2646    fprintf(stderr,"Failed to open file %s for reading purpose.\n",filename);
2647    setMapInMaps(m,"lenv","message","Unable to read produced file. Please try again later");
2648    return ;
2649  }
2650  fseek(file, 0, SEEK_END);
2651  long count = ftell(file);
2652  rewind(file);
2653  struct stat file_status; 
2654  stat(filename, &file_status);
2655  map* tmpMap1=getMap(content,"value");
2656  if(tmpMap1==NULL){
2657    addToMap(content,"value","");
2658    tmpMap1=getMap(content,"value");
2659  }
2660  free(tmpMap1->value);
2661  tmpMap1->value=(char*) malloc((count+1)*sizeof(char)); 
2662  fread(tmpMap1->value,1,count*sizeof(char),file);
2663  fclose(file);
2664  char rsize[100];
2665  sprintf(rsize,"%ld",count*sizeof(char));
2666  addToMap(tmpMap1,"size",rsize);
2667}
2668
2669/**
2670 * Generate the output response (RawDataOutput or ResponseDocument)
2671 *
2672 * @param s the service structure containing the metadata informations
2673 * @param request_inputs the inputs provided to the service for execution
2674 * @param request_outputs the outputs updated by the service execution
2675 * @param request_inputs1 the map containing the HTTP request
2676 * @param cpid the process identifier attached to a service execution
2677 * @param m the conf maps containing the main.cfg settings
2678 * @param res the value returned by the service execution
2679 */
2680void outputResponse(service* s,maps* request_inputs,maps* request_outputs,
2681                    map* request_inputs1,int cpid,maps* m,int res){
2682#ifdef DEBUG
2683  dumpMaps(request_inputs);
2684  dumpMaps(request_outputs);
2685  fprintf(stderr,"printProcessResponse\n");
2686#endif
2687  map* toto=getMap(request_inputs1,"RawDataOutput");
2688  int asRaw=0;
2689  if(toto!=NULL)
2690    asRaw=1;
2691 
2692  maps* tmpSess=getMaps(m,"senv");
2693  if(tmpSess!=NULL){
2694    map *_tmp=getMapFromMaps(m,"lenv","cookie");
2695    char* sessId=NULL;
2696    if(_tmp!=NULL){
2697      printf("Set-Cookie: %s; HttpOnly\r\n",_tmp->value);
2698      printf("P3P: CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"\r\n");
2699      char session_file_path[100];
2700      char *tmp1=strtok(_tmp->value,";");
2701      if(tmp1!=NULL)
2702        sprintf(session_file_path,"%s",strstr(tmp1,"=")+1);
2703      else
2704        sprintf(session_file_path,"%s",strstr(_tmp->value,"=")+1);
2705      sessId=strdup(session_file_path);
2706    }else{
2707      maps* t=getMaps(m,"senv");
2708      map*p=t->content;
2709      while(p!=NULL){
2710        if(strstr(p->name,"ID")!=NULL){
2711          sessId=strdup(p->value);
2712          break;
2713        }
2714        p=p->next;
2715      }
2716    }
2717    char session_file_path[1024];
2718    map *tmpPath=getMapFromMaps(m,"main","sessPath");
2719    if(tmpPath==NULL)
2720      tmpPath=getMapFromMaps(m,"main","tmpPath");
2721    sprintf(session_file_path,"%s/sess_%s.cfg",tmpPath->value,sessId);
2722    FILE* teste=fopen(session_file_path,"w");
2723    if(teste==NULL){
2724      char tmpMsg[1024];
2725      sprintf(tmpMsg,_("Unable to create the file \"%s\" for storing the session maps."),session_file_path);
2726      errorException(m,tmpMsg,"InternalError",NULL);
2727
2728      return;
2729    }
2730    else{
2731      fclose(teste);
2732      dumpMapsToFile(tmpSess,session_file_path);
2733    }
2734  }
2735 
2736  if(res==SERVICE_FAILED){
2737    map *lenv;
2738    lenv=getMapFromMaps(m,"lenv","message");
2739    char *tmp0;
2740    if(lenv!=NULL){
2741      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));
2742      sprintf(tmp0,_("Unable to run the Service. The message returned back by the Service was the following: %s"),lenv->value);
2743    }
2744    else{
2745      tmp0=(char*)malloc((strlen(_("Unable to run the Service. No more information was returned back by the Service."))+1)*sizeof(char));
2746      sprintf(tmp0,"%s",_("Unable to run the Service. No more information was returned back by the Service."));
2747    }
2748    errorException(m,tmp0,"InternalError",NULL);
2749    free(tmp0);
2750    return;
2751  }
2752
2753
2754  map *tmp1=getMapFromMaps(m,"main","tmpPath");
2755  if(asRaw==0){
2756#ifdef DEBUG
2757    fprintf(stderr,"REQUEST_OUTPUTS FINAL\n");
2758    dumpMaps(request_outputs);
2759#endif
2760    maps* tmpI=request_outputs;
2761
2762    while(tmpI!=NULL){
2763#ifdef USE_MS
2764      map* testMap=getMap(tmpI->content,"useMapserver");       
2765#endif
2766      toto=getMap(tmpI->content,"asReference");
2767#ifdef USE_MS
2768      if(toto!=NULL && strcasecmp(toto->value,"true")==0 && testMap==NULL)
2769#else
2770      if(toto!=NULL && strcasecmp(toto->value,"true")==0)
2771#endif
2772        {
2773          elements* in=getElements(s->outputs,tmpI->name);
2774          char *format=NULL;
2775          if(in!=NULL){
2776            format=strdup(in->format);
2777          }else
2778            format=strdup("LiteralData");
2779          if(strcasecmp(format,"BoundingBoxData")==0){
2780            addToMap(tmpI->content,"extension","xml");
2781            addToMap(tmpI->content,"mimeType","text/xml");
2782            addToMap(tmpI->content,"encoding","UTF-8");
2783            addToMap(tmpI->content,"schema","http://schemas.opengis.net/ows/1.1.0/owsCommon.xsd");
2784          }
2785
2786          map *gfile=getMap(tmpI->content,"generated_file");
2787          char *file_name;
2788          if(gfile!=NULL){
2789            gfile=getMap(tmpI->content,"expected_generated_file");
2790            if(gfile==NULL){
2791              gfile=getMap(tmpI->content,"generated_file");
2792            }
2793            readGeneratedFile(m,tmpI->content,gfile->value);       
2794            file_name=(char*)malloc((strlen(gfile->value)+strlen(tmp1->value)+1)*sizeof(char));
2795            for(int i=0;i<strlen(gfile->value);i++)
2796              file_name[i]=gfile->value[i+strlen(tmp1->value)];
2797          }
2798          else{
2799            map *ext=getMap(tmpI->content,"extension");
2800            char *file_path;
2801            char file_ext[32];
2802
2803            if( ext != NULL && ext->value != NULL) {
2804              strncpy(file_ext, ext->value, 32);
2805            }
2806            else {
2807              // Obtain default file extension (see mimetypes.h).             
2808              // If the MIME type is not recognized, txt is used as the default extension
2809              map* mtype=getMap(tmpI->content,"mimeType");
2810              getFileExtension(mtype != NULL ? mtype->value : NULL, file_ext, 32);
2811            }
2812               
2813            file_name=(char*)malloc((strlen(s->name)+strlen(file_ext)+strlen(tmpI->name)+1024)*sizeof(char));
2814            int cpid0=cpid+time(NULL);     
2815            sprintf(file_name,"%s_%s_%i.%s",s->name,tmpI->name,cpid0,file_ext);
2816            file_path=(char*)malloc((strlen(tmp1->value)+strlen(file_name)+2)*sizeof(char));
2817            sprintf(file_path,"%s/%s",tmp1->value,file_name);
2818   
2819                FILE *ofile=fopen(file_path,"wb");
2820            if(ofile==NULL){
2821              char tmpMsg[1024];
2822              sprintf(tmpMsg,_("Unable to create the file \"%s\" for storing the %s final result."),file_name,tmpI->name);
2823              errorException(m,tmpMsg,"InternalError",NULL);
2824              free(file_name);
2825              free(file_path);
2826              return;
2827            }
2828            free(file_path);
2829
2830            toto=getMap(tmpI->content,"value");
2831            if(strcasecmp(format,"BoundingBoxData")!=0){
2832              map* size=getMap(tmpI->content,"size");
2833              if(size!=NULL && toto!=NULL)
2834                fwrite(toto->value,1,atoi(size->value)*sizeof(char),ofile);
2835              else
2836                if(toto!=NULL && toto->value!=NULL)
2837                  fwrite(toto->value,1,strlen(toto->value)*sizeof(char),ofile);
2838            }else{
2839              printBoundingBoxDocument(m,tmpI,ofile);
2840            }
2841            fclose(ofile);
2842
2843          }
2844          map *tmp2=getMapFromMaps(m,"main","tmpUrl");
2845          map *tmp3=getMapFromMaps(m,"main","serverAddress");
2846          char *file_url;
2847          if(strncasecmp(tmp2->value,"http://",7)==0 ||
2848             strncasecmp(tmp2->value,"https://",8)==0){
2849            file_url=(char*)malloc((strlen(tmp2->value)+strlen(file_name)+2)*sizeof(char));
2850            sprintf(file_url,"%s/%s",tmp2->value,file_name);
2851          }else{
2852            file_url=(char*)malloc((strlen(tmp3->value)+strlen(tmp2->value)+strlen(file_name)+3)*sizeof(char));
2853            sprintf(file_url,"%s/%s/%s",tmp3->value,tmp2->value,file_name);
2854          }
2855          addToMap(tmpI->content,"Reference",file_url);
2856          free(format);
2857          free(file_name);
2858          free(file_url);       
2859         
2860        }
2861#ifdef USE_MS
2862      else{
2863        if(testMap!=NULL){
2864          setReferenceUrl(m,tmpI);
2865        }
2866      }
2867#endif
2868      tmpI=tmpI->next;
2869    }
2870    map *r_inputs=getMap(s->content,"serviceProvider");
2871#ifdef DEBUG
2872    fprintf(stderr,"SERVICE : %s\n",r_inputs->value);
2873    dumpMaps(m);
2874#endif
2875    printProcessResponse(m,request_inputs1,cpid,
2876                //       s,r_inputs->value,res,
2877                         s, s->name,res,  // replace serviceProvider with serviceName in stored response file name
2878                         request_inputs,
2879                         request_outputs);
2880  }
2881  else{
2882    /**
2883     * We get the requested output or fallback to the first one if the
2884     * requested one is not present in the resulting outputs maps.
2885     */
2886    maps* tmpI=NULL;
2887    map* tmpIV=getMap(request_inputs1,"RawDataOutput");
2888    if(tmpIV!=NULL){
2889      tmpI=getMaps(request_outputs,tmpIV->value);
2890    }
2891    if(tmpI==NULL)
2892      tmpI=request_outputs;
2893    elements* e=getElements(s->outputs,tmpI->name);
2894    if(e!=NULL && strcasecmp(e->format,"BoundingBoxData")==0){
2895      printBoundingBoxDocument(m,tmpI,NULL);
2896    }else{
2897      map *gfile=getMap(tmpI->content,"generated_file");
2898      if(gfile!=NULL){
2899        gfile=getMap(tmpI->content,"expected_generated_file");
2900        if(gfile==NULL){
2901          gfile=getMap(tmpI->content,"generated_file");
2902        }
2903        readGeneratedFile(m,tmpI->content,gfile->value);
2904      }
2905      toto=getMap(tmpI->content,"value");
2906      if(toto==NULL){
2907        char tmpMsg[1024];
2908        sprintf(tmpMsg,_("Wrong RawDataOutput parameter: unable to fetch any result for the given parameter name: \"%s\"."),tmpI->name);
2909        errorException(m,tmpMsg,"InvalidParameterValue","RawDataOutput");
2910        return;
2911      }
2912      map* fname=getMapFromMaps(tmpI,tmpI->name,"filename");
2913      if(fname!=NULL)
2914        printf("Content-Disposition: attachment; filename=\"%s\"\r\n",fname->value);
2915      map* rs=getMapFromMaps(tmpI,tmpI->name,"size");
2916      if(rs!=NULL)
2917        printf("Content-Length: %s\r\n",rs->value);
2918      printHeaders(m);
2919      char mime[1024];
2920      map* mi=getMap(tmpI->content,"mimeType");
2921#ifdef DEBUG
2922      fprintf(stderr,"SERVICE OUTPUTS\n");
2923      dumpMaps(request_outputs);
2924      fprintf(stderr,"SERVICE OUTPUTS\n");
2925#endif
2926      map* en=getMap(tmpI->content,"encoding");
2927      if(mi!=NULL && en!=NULL)
2928        sprintf(mime,
2929                "Content-Type: %s; charset=%s\r\nStatus: 200 OK\r\n\r\n",
2930                mi->value,en->value);
2931      else
2932        if(mi!=NULL)
2933          sprintf(mime,
2934                  "Content-Type: %s; charset=UTF-8\r\nStatus: 200 OK\r\n\r\n",
2935                  mi->value);
2936        else
2937          sprintf(mime,"Content-Type: text/plain; charset=utf-8\r\nStatus: 200 OK\r\n\r\n");
2938      printf("%s",mime);
2939      if(rs!=NULL)
2940        fwrite(toto->value,1,atoi(rs->value),stdout);
2941      else
2942        fwrite(toto->value,1,strlen(toto->value),stdout);
2943#ifdef DEBUG
2944      dumpMap(toto);
2945#endif
2946    }
2947  }
2948}
2949
2950/**
2951 * Write a file from value and length
2952 *
2953 * @param fname the file name
2954 * @param val the value
2955 * @param length the value length
2956 */
2957int writeFile(char* fname,char* val,int length){
2958  FILE* of=fopen(fname,"wb");
2959  if(of==NULL){
2960    return -1;
2961  }
2962  size_t ret=fwrite(val,sizeof(char),length,of);
2963  if(ret<length){
2964    fprintf(stderr,"Write error occured!\n");
2965    fclose(of);
2966    return -1;
2967  }
2968  fclose(of);
2969  return 1;
2970}
2971
2972/**
2973 * Dump all values in a maps as files
2974 *
2975 * @param main_conf the maps containing the settings of the main.cfg file
2976 * @param in the maps containing values to dump as files
2977 */
2978void dumpMapsValuesToFiles(maps** main_conf,maps** in){
2979  map* tmpPath=getMapFromMaps(*main_conf,"main","tmpPath");
2980  map* tmpSid=getMapFromMaps(*main_conf,"lenv","sid");
2981  maps* inputs=*in;
2982  int length=0;
2983  while(inputs!=NULL){
2984    if(getMap(inputs->content,"mimeType")!=NULL &&
2985       getMap(inputs->content,"cache_file")==NULL){
2986      map* cMap=inputs->content;
2987      if(getMap(cMap,"length")!=NULL){
2988        map* tmpLength=getMap(cMap,"length");
2989        int len=atoi(tmpLength->value);
2990        int k=0;
2991        for(k=0;k<len;k++){
2992          map* cMimeType=getMapArray(cMap,"mimeType",k);
2993          map* cValue=getMapArray(cMap,"value",k);
2994          map* cSize=getMapArray(cMap,"size",k);
2995          char file_ext[32];
2996          getFileExtension(cMimeType != NULL ? cMimeType->value : NULL, file_ext, 32);
2997          char* val=(char*)malloc((strlen(tmpPath->value)+strlen(inputs->name)+strlen(tmpSid->value)+strlen(file_ext)+16)*sizeof(char));
2998          sprintf(val,"%s/Input_%s_%s_%d.%s",tmpPath->value,inputs->name,tmpSid->value,k,file_ext);
2999          length=0;
3000          if(cSize!=NULL){
3001            length=atoi(cSize->value);
3002          }
3003          writeFile(val,cValue->value,length);
3004          setMapArray(cMap,"cache_file",k,val);
3005          free(val);
3006        }
3007      }else{
3008        int length=0;
3009        map* cMimeType=getMap(cMap,"mimeType");
3010        map* cValue=getMap(cMap,"value");
3011        map* cSize=getMap(cMap,"size");
3012        char file_ext[32];
3013        getFileExtension(cMimeType != NULL ? cMimeType->value : NULL, file_ext, 32);
3014        char *val=(char*)malloc((strlen(tmpPath->value)+strlen(inputs->name)+strlen(tmpSid->value)+strlen(file_ext)+16)*sizeof(char));
3015        sprintf(val,"%s/Input_%s_%s_%d.%s",tmpPath->value,inputs->name,tmpSid->value,0,file_ext);
3016        if(cSize!=NULL){
3017          length=atoi(cSize->value);
3018        }
3019        writeFile(val,cValue->value,length);
3020        addToMap(cMap,"cache_file",val);
3021        free(val);
3022      }
3023    }
3024    inputs=inputs->next;
3025  }
3026}
3027
3028/**
3029 * Base64 encoding of a char*
3030 *
3031 * @param input the value to encode
3032 * @param length the value length
3033 * @return the buffer containing the base64 value
3034 * @warning make sure to free the returned value
3035 */
3036char *base64(const char *input, int length)
3037{
3038  BIO *bmem, *b64;
3039  BUF_MEM *bptr;
3040
3041  b64 = BIO_new(BIO_f_base64());
3042  BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
3043  bmem = BIO_new(BIO_s_mem());
3044  b64 = BIO_push(b64, bmem);
3045  BIO_write(b64, input, length+1);
3046  BIO_flush(b64);
3047  BIO_get_mem_ptr(b64, &bptr);
3048
3049  char *buff = (char *)malloc((bptr->length+1)*sizeof(char));
3050  memcpy(buff, bptr->data, bptr->length);
3051  buff[bptr->length-1] = 0;
3052
3053  BIO_free_all(b64);
3054
3055  return buff;
3056}
3057
3058/**
3059 * Base64 decoding of a char*
3060 *
3061 * @param input the value to decode
3062 * @param length the value length
3063 * @param red the value length
3064 * @return the buffer containing the base64 value
3065 * @warning make sure to free the returned value
3066 */
3067char *base64d(const char *input, int length,int* red)
3068{
3069  BIO *b64, *bmem;
3070
3071  char *buffer = (char *)malloc(length);
3072  if(buffer){
3073    memset(buffer, 0, length);
3074    b64 = BIO_new(BIO_f_base64());
3075    if(b64){
3076      bmem = BIO_new_mem_buf((unsigned char*)input,length);
3077      bmem = BIO_push(b64, bmem);
3078      *red=BIO_read(bmem, buffer, length);
3079      buffer[length-1]=0;
3080      BIO_free_all(bmem);
3081    }
3082  }
3083  return buffer;
3084}
3085
3086/**
3087 * Read Base64 value and split it value by lines of 64 char.
3088 *
3089 * @param in the map containing the value to split
3090 */
3091void readBase64(map **in){
3092  char *res = NULL;
3093  char *curs = (*in)->value;
3094  int i = 0;
3095  for (i = 0; i <= strlen ((*in)->value) / 64;
3096       i++)
3097    {
3098      if (res == NULL)
3099        res =
3100          (char *) malloc (65 * sizeof (char));
3101      else
3102        res =
3103          (char *) realloc (res,
3104                            (((i + 1) * 65) +
3105                             i) * sizeof (char));
3106      int csize = i * 65;
3107      strncpy (res + csize, curs, 64);
3108      if (i == strlen ((*in)->value) / 64)
3109        strcat (res, "\n\0");
3110      else
3111        {
3112          strncpy (res + (((i + 1) * 64) + i),
3113                   "\n\0", 2);
3114          curs += 64;
3115        }
3116    }
3117  free ((*in)->value);
3118  (*in)->value = zStrdup (res);
3119  free (res);
3120}
3121
3122/**
3123 * Make sure that each value encoded in base64 in a maps is decoded.
3124 *
3125 * @param in the maps containing the values
3126 * @see readBase64
3127 */
3128void ensureDecodedBase64(maps **in){
3129  maps* cursor=*in;
3130  while(cursor!=NULL){
3131    map *tmp=getMap(cursor->content,"encoding");
3132    if(tmp!=NULL && strncasecmp(tmp->value,"base64",6)==0){
3133      tmp=getMap(cursor->content,"value");
3134      readBase64(&tmp);
3135      addToMap(cursor->content,"base64_value",tmp->value);
3136      int size=0;
3137      char *s=strdup(tmp->value);
3138      free(tmp->value);
3139      tmp->value=base64d(s,strlen(s),&size);
3140      free(s);
3141      char sizes[1024];
3142      sprintf(sizes,"%d",size);
3143      addToMap(cursor->content,"size",sizes);
3144    }
3145    map* length=getMap(cursor->content,"length");
3146    if(length!=NULL){
3147      int len=atoi(length->value);
3148      for(int i=1;i<len;i++){
3149        tmp=getMapArray(cursor->content,"encoding",i);
3150        if(tmp!=NULL && strncasecmp(tmp->value,"base64",6)==0){
3151          char key[17];
3152          sprintf(key,"base64_value_%d",i);
3153          tmp=getMapArray(cursor->content,"value",i);
3154          readBase64(&tmp);
3155          addToMap(cursor->content,key,tmp->value);
3156          int size=0;
3157          char *s=strdup(tmp->value);
3158          free(tmp->value);
3159          tmp->value=base64d(s,strlen(s),&size);
3160          free(s);
3161          char sizes[1024];
3162          sprintf(sizes,"%d",size);
3163          sprintf(key,"size_%d",i);
3164          addToMap(cursor->content,key,sizes);
3165        }
3166      }
3167    }
3168    cursor=cursor->next;
3169  }
3170}
3171
3172/**
3173 * Add the default values defined in the zcfg to a maps.
3174 *
3175 * @param out the maps containing the inputs or outputs given in the initial
3176 *  HTTP request
3177 * @param in the description of all inputs or outputs available for a service
3178 * @param m the maps containing the settings of the main.cfg file
3179 * @param type 0 for inputs and 1 for outputs
3180 * @param err the map to store potential missing mandatory input parameters or
3181 *  wrong output names depending on the type.
3182 * @return "" if no error was detected, the name of last input or output causing
3183 *  an error.
3184 */
3185char* addDefaultValues(maps** out,elements* in,maps* m,int type,map** err){
3186  map *res=*err;
3187  elements* tmpInputs=in;
3188  maps* out1=*out;
3189  char *result=NULL;
3190  int nb=0;
3191  if(type==1){
3192    while(out1!=NULL){
3193      if(getElements(in,out1->name)==NULL){
3194        if(res==NULL){
3195          res=createMap("value",out1->name);
3196        }else{
3197          setMapArray(res,"value",nb,out1->name);
3198        }
3199        nb++;
3200        result=out1->name;
3201      }
3202      out1=out1->next;
3203    }
3204    if(res!=NULL){
3205      *err=res;
3206      return result;
3207    }
3208    out1=*out;
3209  }
3210  while(tmpInputs!=NULL){
3211    maps *tmpMaps=getMaps(out1,tmpInputs->name);
3212    if(tmpMaps==NULL){
3213      maps* tmpMaps2=(maps*)malloc(MAPS_SIZE);
3214      tmpMaps2->name=strdup(tmpInputs->name);
3215      tmpMaps2->content=NULL;
3216      tmpMaps2->next=NULL;
3217     
3218      if(type==0){
3219        map* tmpMapMinO=getMap(tmpInputs->content,"minOccurs");
3220        if(tmpMapMinO!=NULL){
3221          if(atoi(tmpMapMinO->value)>=1){
3222            freeMaps(&tmpMaps2);
3223            free(tmpMaps2);
3224            if(res==NULL){
3225              res=createMap("value",tmpInputs->name);
3226            }else{
3227              setMapArray(res,"value",nb,tmpInputs->name);
3228            }
3229            nb++;
3230            result=tmpInputs->name;
3231          }
3232          else{
3233            if(tmpMaps2->content==NULL)
3234              tmpMaps2->content=createMap("minOccurs",tmpMapMinO->value);
3235            else
3236              addToMap(tmpMaps2->content,"minOccurs",tmpMapMinO->value);
3237          }
3238        }
3239        if(res==NULL){
3240          map* tmpMaxO=getMap(tmpInputs->content,"maxOccurs");
3241          if(tmpMaxO!=NULL){
3242            if(tmpMaps2->content==NULL)
3243              tmpMaps2->content=createMap("maxOccurs",tmpMaxO->value);
3244            else
3245              addToMap(tmpMaps2->content,"maxOccurs",tmpMaxO->value);
3246          }
3247          map* tmpMaxMB=getMap(tmpInputs->content,"maximumMegabytes");
3248          if(tmpMaxMB!=NULL){
3249            if(tmpMaps2->content==NULL)
3250              tmpMaps2->content=createMap("maximumMegabytes",tmpMaxMB->value);
3251            else
3252              addToMap(tmpMaps2->content,"maximumMegabytes",tmpMaxMB->value);
3253          }
3254        }
3255      }
3256
3257      if(res==NULL){
3258        iotype* tmpIoType=tmpInputs->defaults;
3259        if(tmpIoType!=NULL){
3260          map* tmpm=tmpIoType->content;
3261          while(tmpm!=NULL){
3262            if(tmpMaps2->content==NULL)
3263              tmpMaps2->content=createMap(tmpm->name,tmpm->value);
3264            else
3265              addToMap(tmpMaps2->content,tmpm->name,tmpm->value);
3266            tmpm=tmpm->next;
3267          }
3268        }
3269        addToMap(tmpMaps2->content,"inRequest","false");
3270        if(type==0){
3271          map *tmpMap=getMap(tmpMaps2->content,"value");
3272          if(tmpMap==NULL)
3273            addToMap(tmpMaps2->content,"value","NULL");
3274        }
3275        if(out1==NULL){
3276          *out=dupMaps(&tmpMaps2);
3277          out1=*out;
3278        }
3279        else
3280          addMapsToMaps(&out1,tmpMaps2);
3281        freeMap(&tmpMaps2->content);
3282        free(tmpMaps2->content);
3283        tmpMaps2->content=NULL;
3284        freeMaps(&tmpMaps2);
3285        free(tmpMaps2);
3286        tmpMaps2=NULL;
3287      }
3288    }
3289    else{
3290      iotype* tmpIoType=getIoTypeFromElement(tmpInputs,tmpInputs->name,
3291                                             tmpMaps->content);
3292      if(type==0) {
3293        /**
3294         * In case of an Input maps, then add the minOccurs and maxOccurs to the
3295         * content map.
3296         */
3297        map* tmpMap1=getMap(tmpInputs->content,"minOccurs");
3298        if(tmpMap1!=NULL){
3299          if(tmpMaps->content==NULL)
3300            tmpMaps->content=createMap("minOccurs",tmpMap1->value);
3301          else
3302            addToMap(tmpMaps->content,"minOccurs",tmpMap1->value);
3303        }
3304        map* tmpMaxO=getMap(tmpInputs->content,"maxOccurs");
3305        if(tmpMaxO!=NULL){
3306          if(tmpMaps->content==NULL)
3307            tmpMaps->content=createMap("maxOccurs",tmpMaxO->value);
3308          else
3309            addToMap(tmpMaps->content,"maxOccurs",tmpMaxO->value);
3310        }
3311        map* tmpMaxMB=getMap(tmpInputs->content,"maximumMegabytes");
3312        if(tmpMaxMB!=NULL){
3313          if(tmpMaps->content==NULL)
3314            tmpMaps->content=createMap("maximumMegabytes",tmpMaxMB->value);
3315          else
3316            addToMap(tmpMaps->content,"maximumMegabytes",tmpMaxMB->value);
3317        }
3318        /**
3319         * Parsing BoundingBoxData, fill the following map and then add it to
3320         * the content map of the Input maps:
3321         * lowerCorner, upperCorner, srs and dimensions
3322         * cf. parseBoundingBox
3323         */
3324        if(tmpInputs->format!=NULL && strcasecmp(tmpInputs->format,"BoundingBoxData")==0){
3325          maps* tmpI=getMaps(*out,tmpInputs->name);
3326          if(tmpI!=NULL){
3327            map* tmpV=getMap(tmpI->content,"value");
3328            if(tmpV!=NULL){
3329              char *tmpVS=strdup(tmpV->value);
3330              map* tmp=parseBoundingBox(tmpVS);
3331              free(tmpVS);
3332              map* tmpC=tmp;
3333              while(tmpC!=NULL){
3334                addToMap(tmpMaps->content,tmpC->name,tmpC->value);
3335                tmpC=tmpC->next;
3336              }
3337              freeMap(&tmp);
3338              free(tmp);
3339            }
3340          }
3341        }
3342      }
3343
3344      if(tmpIoType!=NULL){
3345        map* tmpContent=tmpIoType->content;
3346        map* cval=NULL;
3347        int hasPassed=-1;
3348        while(tmpContent!=NULL){
3349          if((cval=getMap(tmpMaps->content,tmpContent->name))==NULL){
3350#ifdef DEBUG
3351            fprintf(stderr,"addDefaultValues %s => %s\n",tmpContent->name,tmpContent->value);
3352#endif
3353            if(tmpMaps->content==NULL)
3354              tmpMaps->content=createMap(tmpContent->name,tmpContent->value);
3355            else
3356              addToMap(tmpMaps->content,tmpContent->name,tmpContent->value);
3357           
3358            if(hasPassed<0 && type==0 && getMap(tmpMaps->content,"isArray")!=NULL){
3359              map* length=getMap(tmpMaps->content,"length");
3360              int i;
3361              char *tcn=strdup(tmpContent->name);
3362              for(i=1;i<atoi(length->value);i++){
3363#ifdef DEBUG
3364                dumpMap(tmpMaps->content);
3365                fprintf(stderr,"addDefaultValues %s_%d => %s\n",tcn,i,tmpContent->value);
3366#endif
3367                int len=strlen((char*) tcn);
3368                char *tmp1=(char *)malloc((len+10)*sizeof(char));
3369                sprintf(tmp1,"%s_%d",tcn,i);
3370#ifdef DEBUG
3371                fprintf(stderr,"addDefaultValues %s => %s\n",tmp1,tmpContent->value);
3372#endif
3373                addToMap(tmpMaps->content,tmp1,tmpContent->value);
3374                free(tmp1);
3375                hasPassed=1;
3376              }
3377              free(tcn);
3378            }
3379          }
3380          tmpContent=tmpContent->next;
3381        }
3382#ifdef USE_MS
3383        /**
3384         * check for useMapServer presence
3385         */
3386        map* tmpCheck=getMap(tmpIoType->content,"useMapServer");
3387        if(tmpCheck!=NULL){
3388          // Get the default value
3389          tmpIoType=getIoTypeFromElement(tmpInputs,tmpInputs->name,NULL);
3390          tmpCheck=getMap(tmpMaps->content,"mimeType");
3391          addToMap(tmpMaps->content,"requestedMimeType",tmpCheck->value);
3392          map* cursor=tmpIoType->content;
3393          while(cursor!=NULL){
3394            addToMap(tmpMaps->content,cursor->name,cursor->value);
3395            cursor=cursor->next;
3396          }
3397         
3398          cursor=tmpInputs->content;
3399          while(cursor!=NULL){
3400            if(strcasecmp(cursor->name,"Title")==0 ||
3401               strcasecmp(cursor->name,"Abstract")==0)
3402              addToMap(tmpMaps->content,cursor->name,cursor->value);
3403           cursor=cursor->next;
3404          }
3405        }
3406#endif
3407      }
3408      if(tmpMaps->content==NULL)
3409        tmpMaps->content=createMap("inRequest","true");
3410      else
3411        addToMap(tmpMaps->content,"inRequest","true");
3412
3413    }
3414    tmpInputs=tmpInputs->next;
3415  }
3416  if(res!=NULL){
3417    *err=res;
3418    return result;
3419  }
3420  return "";
3421}
3422
3423/**
3424 * Parse a BoundingBox string
3425 *
3426 * [OGC 06-121r3](http://portal.opengeospatial.org/files/?artifact_id=20040):
3427 *  10.2 Bounding box
3428 *
3429 *
3430 * Value is provided as : lowerCorner,upperCorner,crs,dimension
3431 * Exemple : 189000,834000,285000,962000,urn:ogc:def:crs:OGC:1.3:CRS84
3432 *
3433 * A map to store boundingbox informations should contain:
3434 *  - lowerCorner : double,double (minimum within this bounding box)
3435 *  - upperCorner : double,double (maximum within this bounding box)
3436 *  - crs : URI (Reference to definition of the CRS)
3437 *  - dimensions : int
3438 *
3439 * Note : support only 2D bounding box.
3440 *
3441 * @param value the char* containing the KVP bouding box
3442 * @return a map containing all the bounding box keys
3443 */
3444map* parseBoundingBox(const char* value){
3445  map *res=NULL;
3446  if(value!=NULL){
3447    char *cv,*cvp;
3448    cv=strtok_r((char*) value,",",&cvp);
3449    int cnt=0;
3450    int icnt=0;
3451    char *currentValue=NULL;
3452    while(cv){
3453      if(cnt<2)
3454        if(currentValue!=NULL){
3455          char *finalValue=(char*)malloc((strlen(currentValue)+strlen(cv)+1)*sizeof(char));
3456          sprintf(finalValue,"%s%s",currentValue,cv);
3457          switch(cnt){
3458          case 0:
3459            res=createMap("lowerCorner",finalValue);
3460            break;
3461          case 1:
3462            addToMap(res,"upperCorner",finalValue);
3463            icnt=-1;
3464            break;
3465          }
3466          cnt++;
3467          free(currentValue);
3468          currentValue=NULL;
3469          free(finalValue);
3470        }
3471        else{
3472          currentValue=(char*)malloc((strlen(cv)+2)*sizeof(char));
3473          sprintf(currentValue,"%s ",cv);
3474        }
3475      else
3476        if(cnt==2){
3477          addToMap(res,"crs",cv);
3478          cnt++;
3479        }
3480        else
3481          addToMap(res,"dimensions",cv);
3482      icnt++;
3483      cv=strtok_r(NULL,",",&cvp);
3484    }
3485  }
3486  return res;
3487}
3488
3489/**
3490 * Create required XML nodes for boundingbox and update the current XML node
3491 *
3492 * @param ns_ows the ows XML namespace
3493 * @param n the XML node to update
3494 * @param boundingbox the map containing the boundingbox definition
3495 */
3496void printBoundingBox(xmlNsPtr ns_ows,xmlNodePtr n,map* boundingbox){
3497
3498  xmlNodePtr lw=NULL,uc=NULL;
3499
3500  map* tmp=getMap(boundingbox,"value");
3501
3502  tmp=getMap(boundingbox,"lowerCorner");
3503  if(tmp!=NULL){
3504    lw=xmlNewNode(ns_ows,BAD_CAST "LowerCorner");
3505    xmlAddChild(lw,xmlNewText(BAD_CAST tmp->value));
3506  }
3507
3508  tmp=getMap(boundingbox,"upperCorner");
3509  if(tmp!=NULL){
3510    uc=xmlNewNode(ns_ows,BAD_CAST "UpperCorner");
3511    xmlAddChild(uc,xmlNewText(BAD_CAST tmp->value));
3512  }
3513
3514  tmp=getMap(boundingbox,"crs");
3515  if(tmp!=NULL)
3516    xmlNewProp(n,BAD_CAST "crs",BAD_CAST tmp->value);
3517
3518  tmp=getMap(boundingbox,"dimensions");
3519  if(tmp!=NULL)
3520    xmlNewProp(n,BAD_CAST "dimensions",BAD_CAST tmp->value);
3521
3522  xmlAddChild(n,lw);
3523  xmlAddChild(n,uc);
3524
3525}
3526
3527/**
3528 * Print an ows:BoundingBox XML document
3529 *
3530 * @param m the maps containing the settings of the main.cfg file
3531 * @param boundingbox the maps containing the boundingbox definition
3532 * @param file the file to print the BoundingBox (if NULL then print on stdout)
3533 * @see parseBoundingBox, printBoundingBox
3534 */
3535void printBoundingBoxDocument(maps* m,maps* boundingbox,FILE* file){
3536  if(file==NULL)
3537    rewind(stdout);
3538  xmlNodePtr n;
3539  xmlDocPtr doc;
3540  xmlNsPtr ns_ows,ns_xsi;
3541  xmlChar *xmlbuff;
3542  int buffersize;
3543  char *encoding=getEncoding(m);
3544  map *tmp;
3545  if(file==NULL){
3546    int pid=0;
3547    tmp=getMapFromMaps(m,"lenv","sid");
3548    if(tmp!=NULL)
3549      pid=atoi(tmp->value);
3550    if(pid==getpid()){
3551      printf("Content-Type: text/xml; charset=%s\r\nStatus: 200 OK\r\n\r\n",encoding);
3552    }
3553    fflush(stdout);
3554  }
3555
3556  doc = xmlNewDoc(BAD_CAST "1.0");
3557  int owsId=zooXmlAddNs(NULL,"http://www.opengis.net/ows/1.1","ows");
3558  ns_ows=usedNs[owsId];
3559  n = xmlNewNode(ns_ows, BAD_CAST "BoundingBox");
3560  xmlNewNs(n,BAD_CAST "http://www.opengis.net/ows/1.1",BAD_CAST "ows");
3561  int xsiId=zooXmlAddNs(n,"http://www.w3.org/2001/XMLSchema-instance","xsi");
3562  ns_xsi=usedNs[xsiId];
3563  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");
3564  map *tmp1=getMap(boundingbox->content,"value");
3565  tmp=parseBoundingBox(tmp1->value);
3566  printBoundingBox(ns_ows,n,tmp);
3567  xmlDocSetRootElement(doc, n);
3568
3569  xmlDocDumpFormatMemoryEnc(doc, &xmlbuff, &buffersize, encoding, 1);
3570  if(file==NULL)
3571    printf("%s",xmlbuff);
3572  else{
3573    fprintf(file,"%s",xmlbuff);
3574  }
3575
3576  if(tmp!=NULL){
3577    freeMap(&tmp);
3578    free(tmp);
3579  }
3580  xmlFree(xmlbuff);
3581  xmlFreeDoc(doc);
3582  xmlCleanupParser();
3583  zooXmlCleanupNs();
3584 
3585}
3586
3587/**
3588 * Compute md5
3589 *
3590 * @param url the char*
3591 * @return a char* representing the md5 of the url
3592 * @warning make sure to free ressources returned by this function
3593 */
3594char* getMd5(char* url){
3595  EVP_MD_CTX md5ctx;
3596  char* fresult=(char*)malloc((EVP_MAX_MD_SIZE+1)*sizeof(char));
3597  unsigned char result[EVP_MAX_MD_SIZE];
3598  unsigned int len;
3599  EVP_DigestInit(&md5ctx, EVP_md5());
3600  EVP_DigestUpdate(&md5ctx, url, strlen(url));
3601  EVP_DigestFinal_ex(&md5ctx,result,&len);
3602  EVP_MD_CTX_cleanup(&md5ctx);
3603  int i;
3604  for(i = 0; i < len; i++){
3605    if(i>0){
3606      char *tmp=strdup(fresult);
3607      sprintf(fresult,"%s%02x", tmp,result[i]);
3608      free(tmp);
3609    }
3610    else
3611      sprintf(fresult,"%02x",result[i]);
3612  }
3613  return fresult;
3614}
3615
3616/**
3617 * Cache a file for a given request.
3618 * For each cached file, the are two files stored, a .zca and a .zcm containing
3619 * the downloaded content and the mimeType respectively.
3620 *
3621 * @param conf the maps containing the settings of the main.cfg file
3622 * @param request the url used too fetch the content
3623 * @param content the downloaded content
3624 * @param mimeType the content mimeType
3625 * @param length the content size
3626 * @param filepath a buffer for storing the path of the cached file; may be NULL
3627 * @param max_path the size of the allocated filepath buffer 
3628 */
3629void addToCache(maps* conf,char* request,char* content,char* mimeType,int length, 
3630                char* filepath, size_t max_path){
3631  map* tmp=getMapFromMaps(conf,"main","cacheDir");
3632  if(tmp!=NULL){
3633    char* md5str=getMd5(request);
3634    char* fname=(char*)malloc(sizeof(char)*(strlen(tmp->value)+strlen(md5str)+6));
3635    sprintf(fname,"%s/%s.zca",tmp->value,md5str);
3636#ifdef DEBUG
3637    fprintf(stderr,"Cache list : %s\n",fname);
3638    fflush(stderr);
3639#endif
3640    FILE* fo=fopen(fname,"w+");
3641    if(fo==NULL){
3642#ifdef DEBUG
3643      fprintf (stderr, "Failed to open %s for writing: %s\n",fname, strerror(errno));
3644#endif
3645      filepath = NULL; 
3646      return;
3647    }
3648    fwrite(content,sizeof(char),length,fo);
3649    fclose(fo);
3650       
3651        if (filepath != NULL) {
3652                strncpy(filepath, fname, max_path);
3653        }       
3654
3655    sprintf(fname,"%s/%s.zcm",tmp->value,md5str);
3656    fo=fopen(fname,"w+");
3657#ifdef DEBUG
3658    fprintf(stderr,"MIMETYPE: %s\n",mimeType);
3659#endif
3660    fwrite(mimeType,sizeof(char),strlen(mimeType),fo);
3661    fclose(fo);
3662
3663    free(md5str);
3664    free(fname);
3665  }
3666  else {
3667          filepath = NULL;
3668  }       
3669}
3670
3671/**
3672 * Verify if a url is available in the cache
3673 *
3674 * @param conf the maps containing the settings of the main.cfg file
3675 * @param request the url
3676 * @return the full name of the cached file if any, NULL in other case
3677 * @warning make sure to free ressources returned by this function (if not NULL)
3678 */
3679char* isInCache(maps* conf,char* request){
3680  map* tmpM=getMapFromMaps(conf,"main","cacheDir");
3681  if(tmpM!=NULL){
3682    char* md5str=getMd5(request);
3683#ifdef DEBUG
3684    fprintf(stderr,"MD5STR : (%s)\n\n",md5str);
3685#endif
3686    char* fname=(char*)malloc(sizeof(char)*(strlen(tmpM->value)+strlen(md5str)+6));
3687    sprintf(fname,"%s/%s.zca",tmpM->value,md5str);
3688    struct stat f_status;
3689    int s=stat(fname, &f_status);
3690    if(s==0 && f_status.st_size>0){
3691      free(md5str);
3692      return fname;
3693    }
3694    free(md5str);
3695    free(fname);
3696  }
3697  return NULL;
3698}
3699
3700/**
3701 * Effectively run all the HTTP requests in the queue
3702 *
3703 * @param m the maps containing the settings of the main.cfg file
3704 * @param inputs the maps containing the inputs (defined in the requests+added
3705 *  per default based on the zcfg file)
3706 * @param hInternet the HINTERNET pointer
3707 * @return 0 on success
3708 */
3709int runHttpRequests(maps** m,maps** inputs,HINTERNET* hInternet){
3710  if(hInternet->nb>0){
3711    processDownloads(hInternet);
3712    maps* content=*inputs;
3713    map* tmp1;
3714    int index=0;
3715    char sindex[5];
3716    while(content!=NULL){
3717     
3718      map* length=getMap(content->content,"length");
3719      int shouldClean=-1;
3720      if(length==NULL){
3721        length=createMap("length","1");
3722        shouldClean=1;
3723      }
3724      for(int i=0;i<atoi(length->value);i++){
3725        char* fcontent;
3726        char *mimeType=NULL;
3727        int fsize=0;
3728        char cname[15];
3729        char vname[11];
3730        char vname1[11];
3731        char sname[9];
3732        char mname[15];
3733        char icname[14];
3734        char xname[16];
3735        char oname[12];
3736        if(index>0)
3737          sprintf(vname1,"value_%d",index);
3738        else
3739          sprintf(vname1,"value");
3740
3741        if(i>0){
3742          tmp1=getMap(content->content,cname);
3743          sprintf(cname,"cache_file_%d",i);
3744          sprintf(vname,"value_%d",i);
3745          sprintf(sname,"size_%d",i);
3746          sprintf(mname,"mimeType_%d",i);
3747          sprintf(icname,"isCached_%d",i);
3748          sprintf(xname,"Reference_%d",i);
3749          sprintf(oname,"Order_%d",i);
3750        }else{
3751          sprintf(cname,"cache_file");
3752          sprintf(vname,"value");
3753          sprintf(sname,"size");
3754          sprintf(mname,"mimeType");
3755          sprintf(icname,"isCached");
3756          sprintf(xname,"Reference");
3757          sprintf(oname,"Order");
3758        }
3759
3760        map* tmap=getMap(content->content,oname);
3761        sprintf(sindex,"%d",index+1);
3762        if((tmp1=getMap(content->content,xname))!=NULL && tmap!=NULL && strcasecmp(tmap->value,sindex)==0){
3763
3764          if(getMap(content->content,icname)==NULL){
3765           
3766            fcontent=(char*)malloc((hInternet->ihandle[index].nDataLen+1)*sizeof(char));
3767            if(fcontent == NULL){
3768              return errorException(*m, _("Unable to allocate memory."), "InternalError",NULL);
3769            }
3770            size_t dwRead;
3771            InternetReadFile(hInternet->ihandle[index], 
3772                             (LPVOID)fcontent, 
3773                             hInternet->ihandle[index].nDataLen, 
3774                             &dwRead);
3775            fcontent[hInternet->ihandle[index].nDataLen]=0;
3776            fsize=hInternet->ihandle[index].nDataLen;
3777            if(hInternet->ihandle[index].mimeType==NULL)
3778              mimeType=strdup("none");
3779            else
3780              mimeType=strdup(hInternet->ihandle[index].mimeType);           
3781           
3782            map* tmpMap=getMapOrFill(&content->content,vname,"");
3783            free(tmpMap->value);
3784            tmpMap->value=(char*)malloc((fsize+1)*sizeof(char));
3785            if(tmpMap->value==NULL){
3786              return errorException(*m, _("Unable to allocate memory."), "InternalError",NULL);
3787            }
3788            memcpy(tmpMap->value,fcontent,(fsize+1)*sizeof(char));
3789           
3790            char ltmp1[256];
3791            sprintf(ltmp1,"%d",fsize);
3792            map* tmp=getMapFromMaps(*m,"main","cacheDir");
3793            if(tmp!=NULL){
3794              char* md5str=getMd5(tmp1->value);
3795              char* fname=(char*)malloc(sizeof(char)*(strlen(tmp->value)+strlen(md5str)+6));
3796              sprintf(fname,"%s/%s.zca",tmp->value,md5str);
3797              addToMap(content->content,cname,fname);
3798              free(fname);
3799            }
3800            addToMap(content->content,sname,ltmp1);
3801            addToMap(content->content,mname,mimeType);
3802            addToCache(*m,tmp1->value,fcontent,mimeType,fsize, NULL, 0);
3803            free(fcontent);
3804            free(mimeType);
3805            index++;
3806
3807          }
3808        }
3809      }
3810      if(shouldClean>0){
3811        freeMap(&length);
3812        free(length);
3813      }
3814     
3815      content=content->next;
3816    }
3817   
3818  }
3819  return 0;
3820}
3821
3822/**
3823 * Add a request in the download queue
3824 *
3825 * @param m the maps containing the settings of the main.cfg file
3826 * @param url the url to add to the queue
3827 */
3828void addRequestToQueue(maps** m,HINTERNET* hInternet,const char* url,bool req){
3829  hInternet->waitingRequests[hInternet->nb]=strdup(url);
3830  hInternet->ihandle[hInternet->nb].header=NULL;
3831  if(req)
3832    InternetOpenUrl(hInternet,hInternet->waitingRequests[hInternet->nb],NULL,0,INTERNET_FLAG_NO_CACHE_WRITE,0);
3833  maps *oreq=getMaps(*m,"orequests");
3834  if(oreq==NULL){
3835    oreq=(maps*)malloc(MAPS_SIZE);
3836    oreq->name=zStrdup("orequests");
3837    oreq->content=createMap("value",url);
3838    oreq->next=NULL;
3839    addMapsToMaps(m,oreq);
3840    freeMaps(&oreq);
3841    free(oreq);
3842  }else{
3843    setMapArray(oreq->content,"value",hInternet->nb-1,url);
3844  }
3845}
3846
3847/**
3848 * Try to load file from cache or download a remote file if not in cache
3849 *
3850 * @param m the maps containing the settings of the main.cfg file
3851 * @param content the map to update
3852 * @param hInternet the HINTERNET pointer
3853 * @param url the url to fetch
3854 * @return 0
3855 */
3856int loadRemoteFile(maps** m,map** content,HINTERNET* hInternet,char *url){
3857  char* fcontent;
3858  char* cached=isInCache(*m,url);
3859  char *mimeType=NULL;
3860  int fsize=0;
3861
3862  map* t=getMap(*content,"xlink:href");
3863  if(t==NULL){
3864    t=getMap((*content),"href");
3865    addToMap(*content,"xlink:href",url);
3866  }
3867
3868  if(cached!=NULL){
3869
3870    struct stat f_status;
3871    int s=stat(cached, &f_status);
3872    if(s==0){
3873      fcontent=(char*)malloc(sizeof(char)*(f_status.st_size+1));
3874      FILE* f=fopen(cached,"rb");
3875      fread(fcontent,f_status.st_size,1,f);
3876      fsize=f_status.st_size;
3877      fcontent[fsize]=0;
3878      fclose(f);
3879      addToMap(*content,"cache_file",cached);
3880    }
3881    cached[strlen(cached)-1]='m';
3882    s=stat(cached, &f_status);
3883    if(s==0){
3884      mimeType=(char*)malloc(sizeof(char)*(f_status.st_size+1));
3885      FILE* f=fopen(cached,"rb");
3886      fread(mimeType,f_status.st_size,1,f);
3887      mimeType[f_status.st_size]=0;
3888      fclose(f);
3889    }
3890
3891  }else{   
3892    addRequestToQueue(m,hInternet,url,true);
3893    return 0;
3894  }
3895  if(fsize==0){
3896    return errorException(*m, _("Unable to download the file."), "InternalError",NULL);
3897  }
3898  if(mimeType!=NULL){
3899    addToMap(*content,"fmimeType",mimeType);
3900  }
3901
3902  map* tmpMap=getMapOrFill(content,"value","");
3903   
3904  free(tmpMap->value);
3905
3906  tmpMap->value=(char*)malloc((fsize+1)*sizeof(char));
3907  if(tmpMap->value==NULL)
3908    return errorException(*m, _("Unable to allocate memory."), "InternalError",NULL);
3909  memcpy(tmpMap->value,fcontent,(fsize+1)*sizeof(char));
3910
3911  char ltmp1[256];
3912  sprintf(ltmp1,"%d",fsize);
3913  addToMap(*content,"size",ltmp1);
3914  if(cached==NULL){
3915    addToCache(*m,url,fcontent,mimeType,fsize, NULL, 0);
3916  }
3917  else{
3918    addToMap(*content,"isCached","true");
3919    map* tmp=getMapFromMaps(*m,"main","cacheDir");
3920    if(tmp!=NULL){
3921      map *c=getMap((*content),"xlink:href");
3922      char* md5str=getMd5(c->value);
3923      char* fname=(char*)malloc(sizeof(char)*(strlen(tmp->value)+strlen(md5str)+6));
3924      sprintf(fname,"%s/%s.zca",tmp->value,md5str);
3925      addToMap(*content,"cache_file",fname);
3926      free(fname);
3927    }
3928  }
3929  free(fcontent);
3930  free(mimeType);
3931  free(cached);
3932  return 0;
3933}
3934
3935/**
3936 * Read a file using the GDAL VSI API
3937 *
3938 * @param conf the maps containing the settings of the main.cfg file
3939 * @param dataSource the datasource name to read
3940 * @warning make sure to free ressources returned by this function
3941 */
3942char *readVSIFile(maps* conf,const char* dataSource){
3943    VSILFILE * fichier=VSIFOpenL(dataSource,"rb");
3944    VSIStatBufL file_status;
3945    VSIStatL(dataSource, &file_status);
3946    if(fichier==NULL){
3947      char tmp[1024];
3948      sprintf(tmp,"Failed to open file %s for reading purpose. File seems empty %lld.",
3949              dataSource,file_status.st_size);
3950      setMapInMaps(conf,"lenv","message",tmp);
3951      return NULL;
3952    }
3953    char *res1=(char *)malloc(file_status.st_size*sizeof(char));
3954    VSIFReadL(res1,1,file_status.st_size*sizeof(char),fichier);
3955    res1[file_status.st_size-1]=0;
3956    VSIFCloseL(fichier);
3957    VSIUnlink(dataSource);
3958    return res1;
3959}
3960
3961/**
3962 * Extract the service identifier from the full service identifier
3963 * ie:
3964 *  - Full service name: OTB.BandMath
3965 *  - Service name: BandMath
3966 *
3967 * @param conf the maps containing the settings of the main.cfg file
3968 * @param conf_dir the full path to the ZOO-Kernel directory
3969 * @param identifier the full service name (potentialy including a prefix, ie:
3970 *  Prefix.MyService)
3971 * @param buffer the resulting service identifier (without any prefix)
3972 */
3973void parseIdentifier(maps* conf,char* conf_dir,char *identifier,char* buffer){
3974  setMapInMaps(conf,"lenv","oIdentifier",identifier);
3975  char *lid=zStrdup(identifier);
3976  char *saveptr1;
3977  char *tmps1=strtok_r(lid,".",&saveptr1);
3978  int level=0;
3979  char key[25];
3980  char levels[18];
3981  while(tmps1!=NULL){
3982    char *test=zStrdup(tmps1);
3983    char* tmps2=(char*)malloc((strlen(test)+2)*sizeof(char));
3984    sprintf(key,"sprefix_%d",level);
3985    sprintf(tmps2,"%s.",test);
3986    sprintf(levels,"%d",level);
3987    setMapInMaps(conf,"lenv","level",levels);
3988    setMapInMaps(conf,"lenv",key,tmps2);
3989    free(tmps2);
3990    free(test);
3991    level++;
3992    tmps1=strtok_r(NULL,".",&saveptr1);
3993  }
3994  int i=0;
3995  sprintf(buffer,"%s",conf_dir);
3996  for(i=0;i<level;i++){
3997    char *tmp0=zStrdup(buffer);
3998    sprintf(key,"sprefix_%d",i);
3999    map* tmp00=getMapFromMaps(conf,"lenv",key);
4000    if(tmp00!=NULL)
4001      sprintf(buffer,"%s/%s",tmp0,tmp00->value);
4002    free(tmp0);
4003    buffer[strlen(buffer)-1]=0;
4004    if(i+1<level){ 
4005      #ifdef IGNORE_METAPATH
4006        map* tmpMap = createMap("metapath", "");
4007      #else 
4008        map* tmpMap=getMapFromMaps(conf,"lenv","metapath");
4009      #endif     
4010      if(tmpMap==NULL || strlen(tmpMap->value)==0){
4011        char *tmp01=zStrdup(tmp00->value);
4012        tmp01[strlen(tmp01)-1]=0;
4013        setMapInMaps(conf,"lenv","metapath",tmp01);
4014        free(tmp01);
4015        tmp01=NULL;
4016      }
4017      else{
4018        if(tmp00!=NULL && tmpMap!=NULL){
4019          char *tmp00s=zStrdup(tmp00->value);
4020          tmp00s[strlen(tmp00s)-1]=0;
4021          char *value=(char*)malloc((strlen(tmp00s)+strlen(tmpMap->value)+2)*sizeof(char));
4022          sprintf(value,"%s/%s",tmpMap->value,tmp00s);
4023          setMapInMaps(conf,"lenv","metapath",value);
4024          free(value);
4025          free(tmp00s);
4026          value=NULL;
4027        }
4028      }
4029    }else{
4030      char *tmp01=zStrdup(tmp00->value);
4031      tmp01[strlen(tmp01)-1]=0;
4032      setMapInMaps(conf,"lenv","Identifier",tmp01);
4033      free(tmp01);
4034    }
4035  }
4036  char *tmp0=zStrdup(buffer);
4037  sprintf(buffer,"%s.zcfg",tmp0);
4038  free(tmp0);
4039  free(lid);
4040}
4041
4042/**
4043 * Update the status of an ongoing service
4044 *
4045 * @param conf the maps containing the settings of the main.cfg file
4046 * @param percentCompleted percentage of completude of execution of the service
4047 * @param message information about the current step executed
4048 * @return the value of _updateStatus
4049 * @see _updateStatus
4050 */
4051int updateStatus( maps* conf, const int percentCompleted, const char* message ){
4052  char tmp[4];
4053  snprintf(tmp,4,"%d",percentCompleted);
4054  setMapInMaps( conf, "lenv", "status", tmp );
4055  setMapInMaps( conf, "lenv", "message", message);
4056  return _updateStatus( conf );
4057}
4058
4059/**
4060 * Access an input value
4061 *
4062 * @param inputs the maps to search for the input value
4063 * @param parameterName the input name to fetch the value
4064 * @param numberOfBytes the resulting size of the value to add (for binary
4065 *  values), -1 for basic char* data
4066 * @return a pointer to the input value if found, NULL in other case.
4067 */
4068char* getInputValue( maps* inputs, const char* parameterName, size_t* numberOfBytes){
4069  map* res=getMapFromMaps(inputs,parameterName,"value");
4070  if(res!=NULL){
4071    map* size=getMapFromMaps(inputs,parameterName,"size");
4072    if(size!=NULL){
4073      *numberOfBytes=(size_t)atoi(size->value);
4074      return res->value;
4075    }else{
4076      *numberOfBytes=strlen(res->value);
4077      return res->value;
4078    }
4079  }
4080  return NULL;
4081}
4082
4083/**
4084 * Set an output value
4085 *
4086 * @param outputs the maps to define the output value
4087 * @param parameterName the output name to set the value
4088 * @param data the value to set
4089 * @param numberOfBytes size of the value to add (for binary values), -1 for
4090 *  basic char* data
4091 * @return 0
4092 */
4093int  setOutputValue( maps* outputs, const char* parameterName, char* data, size_t numberOfBytes ){
4094  if(numberOfBytes==-1){
4095    setMapInMaps(outputs,parameterName,"value",data);
4096  }else{
4097    char size[1024];
4098    map* tmp=getMapFromMaps(outputs,parameterName,"value");
4099    if(tmp==NULL){
4100      setMapInMaps(outputs,parameterName,"value","");
4101      tmp=getMapFromMaps(outputs,parameterName,"value");
4102    }
4103    free(tmp->value);
4104    tmp->value=(char*) malloc((numberOfBytes+1)*sizeof(char));
4105    memcpy(tmp->value,data,numberOfBytes);
4106    sprintf(size,"%lu",numberOfBytes);
4107    setMapInMaps(outputs,parameterName,"size",size);
4108  }
4109  return 0;
4110}
4111
4112/**
4113 * Verify if a parameter value is valid.
4114 *
4115 * @param request the request map
4116 * @param res the error map potentially generated
4117 * @param toCheck the parameter to use
4118 * @param avalues the acceptable values (or null if testing only for presence)
4119 * @param mandatory verify the presence of the parameter if mandatory > 0
4120 */
4121void checkValidValue(map* request,map** res,const char* toCheck,const char** avalues,int mandatory){
4122  map* lres=*res;
4123  map* r_inputs = getMap (request,toCheck);
4124  if (r_inputs == NULL){
4125    if(mandatory>0){
4126      char *replace=_("Mandatory parameter <%s> was not specified");
4127      char *message=(char*)malloc((strlen(replace)+strlen(toCheck)+1)*sizeof(char));
4128      sprintf(message,replace,toCheck);
4129      if(lres==NULL){
4130        lres=createMap("code","MissingParameterValue");
4131        addToMap(lres,"text",message);
4132        addToMap(lres,"locator",toCheck);       
4133      }else{
4134        int length=1;
4135        map* len=getMap(lres,"length");
4136        if(len!=NULL){
4137          length=atoi(len->value);
4138        }
4139        setMapArray(lres,"text",length,message);
4140        setMapArray(lres,"locator",length,toCheck);
4141        setMapArray(lres,"code",length,"MissingParameter");
4142      }
4143      free(message);
4144    }
4145  }else{
4146    if(avalues==NULL)
4147      return;
4148    int nb=0;
4149    int hasValidValue=-1;
4150    while(avalues[nb]!=NULL){
4151      if(strcasecmp(avalues[nb],r_inputs->value)==0){
4152        hasValidValue=1;
4153        break;
4154      }
4155      nb++;
4156    }
4157    if(hasValidValue<0){
4158      char *replace=_("The value <%s> was not recognized, %s %s the only acceptable value.");
4159      nb=0;
4160      char *vvalues=NULL;
4161      char* num=_("is");
4162      while(avalues[nb]!=NULL){
4163        char *tvalues;
4164        if(vvalues==NULL){
4165          vvalues=(char*)malloc((strlen(avalues[nb])+3)*sizeof(char));
4166          sprintf(vvalues,"%s",avalues[nb]);
4167        }
4168        else{
4169          tvalues=zStrdup(vvalues);
4170          vvalues=(char*)realloc(vvalues,(strlen(tvalues)+strlen(avalues[nb])+3)*sizeof(char));
4171          sprintf(vvalues,"%s, %s",tvalues,avalues[nb]);
4172          free(tvalues);
4173          num=_("are");
4174        }
4175        nb++;
4176      }
4177      char *message=(char*)malloc((strlen(replace)+strlen(num)+strlen(vvalues)+strlen(toCheck)+1)*sizeof(char));
4178      sprintf(message,replace,toCheck,vvalues,num);
4179      if(lres==NULL){
4180        lres=createMap("code","InvalidParameterValue");
4181        addToMap(lres,"text",message);
4182        addToMap(lres,"locator",toCheck);       
4183      }else{
4184        int length=1;
4185        map* len=getMap(lres,"length");
4186        if(len!=NULL){
4187          length=atoi(len->value);
4188        }
4189        setMapArray(lres,"text",length,message);
4190        setMapArray(lres,"locator",length,toCheck);
4191        setMapArray(lres,"code",length,"InvalidParameterValue");
4192      }
4193    }
4194  }
4195  if(lres!=NULL){
4196    *res=lres;
4197  }
4198}
4199
4200/**
4201 * Access the last error message returned by the OS when trying to dynamically
4202 * load a shared library.
4203 *
4204 * @return the last error message
4205 * @warning The character string returned from getLastErrorMessage resides
4206 * in a static buffer. The application should not write to this
4207 * buffer or attempt to free() it.
4208 */ 
4209char* getLastErrorMessage() {                                             
4210#ifdef WIN32
4211  LPVOID lpMsgBuf;
4212  DWORD errCode = GetLastError();
4213  static char msg[ERROR_MSG_MAX_LENGTH];
4214  size_t i;
4215 
4216  DWORD length = FormatMessage(
4217                               FORMAT_MESSAGE_ALLOCATE_BUFFER | 
4218                               FORMAT_MESSAGE_FROM_SYSTEM |
4219                               FORMAT_MESSAGE_IGNORE_INSERTS,
4220                               NULL,
4221                               errCode,
4222                               MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
4223                               (LPTSTR) &lpMsgBuf,
4224                               0, NULL );       
4225 
4226#ifdef UNICODE         
4227  wcstombs_s( &i, msg, ERROR_MSG_MAX_LENGTH,
4228              (wchar_t*) lpMsgBuf, _TRUNCATE );
4229#else
4230  strcpy_s( msg, ERROR_MSG_MAX_LENGTH,
4231            (char *) lpMsgBuf );               
4232#endif 
4233  LocalFree(lpMsgBuf);
4234 
4235  return msg;
4236#else
4237  return dlerror();
4238#endif
4239}
4240
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