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

Last change on this file since 620 was 620, checked in by djay, 9 years ago

Small fix for CDATA content. ExceptionReport? if lock failed.

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