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

Last change on this file since 589 was 587, checked in by knut, 10 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