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

Last change on this file since 587 was 587, checked in by knut, 9 years ago

Implemented asynchronous HTTP POST Execute requests on Windows platform (via caching). Fixed bug that caused only the last output variable in a HTTP POST Execute request to be returned. Modified the addToCache function so that the path of the cached file can be retrieved. Changed the parsing of KVPs in zoo_loader.c so that keys with missing values (e.g. "metapath=") are assigned the empty string instead of NULL (avoids segmentation fault in some situations). Added conditional definition of ZEND_DEBUG in service_internal_php.c. Deallocation of memory in function createProcess. In zoo_loader.c, applied url_decode to CGI form string (WIN32 only, but should check if this should apply to other platforms as well).

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