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

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

Altered the path of stored response files from [tmpPath]/[serviceProvider]_[cpid].xml to [tmpPath]/[serviceName]_[cpid].xml. Added support for a new parameter, libPath, in the [main] block of main.cfg. The libPath parameter is interpreted as the absolute path of the directory containing library files. If the libPath parameter is set, it will override the metapath parameter such that library files are loaded from [libPath]/[serviceProvider] instead of [CWD]/[metapath]/[serviceProvider]. Added the option to disable the metapath parameter (for security reasons) at compile time: If the Zoo kernel is compiled with the preprocessor directive IGNORE_METAPATH, the metapath will be set to the empty string. Note however, that the libPath and IGNORE_METAPATH options so far only work for C and PHP; the functions for loading libraries written in other languages should be modified correspondingly before the documentation is updated. See also ticket no. 112 (http://www.zoo-project.org/trac/ticket/112). Fixed some spelling errors and modified the language in some of the messages returned by the Zoo kernel.

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