source: branches/prototype-v0/zoo-project/zoo-kernel/ulinet.c @ 821

Last change on this file since 821 was 821, checked in by djay, 7 years ago

Create branch for testing purpose

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc
File size: 18.0 KB
Line 
1/*
2 *  ulinet.c
3 *
4 * Author : Gérald FENOY
5 *
6 * Copyright (c) 2008-2015 GeoLabs SARL
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24 * THE SOFTWARE.
25 *
26 */
27
28#define _ULINET
29#define MAX_WAIT_MSECS 180*1000 /* Wait max. 180 seconds */
30#include "ulinet.h"
31#include <assert.h>
32#include <ctype.h>
33
34/**
35 * Write the downloaded content to a _HINTERNET structure
36 *
37 * @param buffer the buffer to read
38 * @param size size of each member
39 * @param nmemb number of element to read
40 * @param data the _HINTERNET structure to write in
41 * @return the size red, -1 if buffer is NULL
42 */
43size_t write_data_into(void *buffer, size_t size, size_t nmemb, void *data){
44  size_t realsize = size * nmemb;
45  _HINTERNET *psInternet;
46  if(buffer==NULL){
47    buffer=NULL;
48    return -1;
49  }
50  psInternet=(_HINTERNET *)data;
51  if(psInternet->pabyData){
52    psInternet->pabyData=(unsigned char*)realloc(psInternet->pabyData,psInternet->nDataLen+realsize+1);
53    psInternet->nDataAlloc+=psInternet->nDataLen+realsize+1;
54  }
55  else{
56    psInternet->pabyData=(unsigned char*)malloc(psInternet->nDataLen+realsize+1);
57    psInternet->nDataAlloc=realsize+1;
58  }
59
60  if (psInternet->pabyData) {
61    memcpy( psInternet->pabyData + psInternet->nDataLen, buffer, realsize);
62    psInternet->nDataLen += realsize;
63    psInternet->pabyData[psInternet->nDataLen] = 0;
64  }
65
66  buffer=NULL;
67  return realsize;
68}
69
70/**
71 * In case of presence of "Set-Cookie" in the headers red, store the cookie
72 * identifier in CCookie
73 *
74 * @param buffer the buffer to read
75 * @param size size of each member
76 * @param nmemb number of element to read
77 * @param data the _HINTERNET structure to write in
78 * @return the size red, -1 if buffer is NULL
79 * @see CCookie
80 */
81size_t header_write_data(void *buffer, size_t size, size_t nmemb, void *data){
82  if(strncmp("Set-Cookie: ",(char*)buffer,12)==0){
83    int i;
84    char env[256];
85    char path[256];
86    char domain[256];
87    char* tmp;
88    for(i=0;i<12;i++)
89#ifndef WIN32
90      buffer++;
91#else
92        ;
93#endif
94    sscanf((char*)buffer,"%s; path=%s; domain=%s",env,path,domain);
95    _HINTERNET *psInternet=(_HINTERNET *)data;
96    tmp=strcat(env,CCookie[psInternet->id][0]);
97#ifdef MSG_LAF_OUT
98    printf("\n**Cookie env : [%s] , path : [%s], domain : [%s]**\n",env,path,domain);
99    printf("buffer : %d (%s) (%s) (%s)\n",(buffer==NULL),buffer,tmp,CCookie);
100#endif
101    strcpy(CCookie[psInternet->id][0],tmp);
102  }
103  return size * nmemb;//write_data_into(buffer,size,nmemb,data,HEADER);
104};
105
106/**
107 * Define the proxy to use for a CURL handler
108 *
109 * @param handle the CURL handler
110 * @param host the proxy host (including http://)
111 * @param port the proxy port
112 */
113void setProxy(CURL* handle,char* host,long port){
114  char* proxyDef=(char*)malloc((strlen(host)+10+2)*sizeof(char));
115  sprintf(proxyDef,"%s:%ld",host,port);
116  curl_easy_setopt(handle,CURLOPT_PROXY,proxyDef);
117  free(proxyDef);
118}
119
120/**
121 * MACOSX
122 */
123#if defined(macintosh) || (defined(__MACH__) && defined(__APPLE__))
124
125
126char* CFStringToCString(CFStringRef dest,char *buffer){
127  CFStringEncoding encoding = kCFStringEncodingUTF8;
128  Boolean bool2 = CFStringGetCString(dest,buffer,1024,encoding);
129  if(bool2){
130    printf("Loaded into local_buffer");
131    return buffer;
132  }
133  return NULL;
134}
135
136OSStatus setProxiesForProtcol(CURL* handle,const char *proto){
137  OSStatus              err;
138  CFDictionaryRef proxyDict;
139  CFArrayRef            proxies;
140 
141  CFStringRef key_enabled = NULL;
142  CFStringRef key_host = NULL;
143  CFStringRef key_port = NULL;
144 
145  bool proxy_enabled;
146  char *proxy_host;
147  long proxy_port;
148 
149  proxyDict = NULL;
150  proxies = NULL;
151
152  err = noErr;
153  proxyDict = SCDynamicStoreCopyProxies(NULL);
154
155  if(strncmp(proto,"http",4)==0){
156      key_enabled=kSCPropNetProxiesHTTPEnable;
157      key_host=kSCPropNetProxiesHTTPProxy;
158      key_port=kSCPropNetProxiesHTTPPort;
159  }
160  else
161    if(strncmp(proto,"https",5)==0){
162      key_enabled=kSCPropNetProxiesHTTPSEnable;
163      key_host=kSCPropNetProxiesHTTPSProxy;
164      key_port=kSCPropNetProxiesHTTPSPort;
165    }
166
167  CFNumberGetValue(CFDictionaryGetValue(proxyDict,key_enabled),kCFNumberIntType,&proxy_enabled);
168  if(proxy_enabled){
169    CFNumberGetValue(CFDictionaryGetValue(proxyDict,key_port),CFNumberGetType(CFDictionaryGetValue(proxyDict,key_port)),&proxy_port);
170    char buffer[1024];
171    CFStringToCString(CFDictionaryGetValue(proxyDict,key_host),buffer);
172    proxy_host=buffer;
173
174#ifdef MSG_LAF_VERBOSE
175    printf("\n**[PROXY SETTINGS DETECTION %s (%d) %s:%li (%s)]**\n",proto,proxy_enabled,(char*)proxy_host,proxy_port,buffer);
176#endif
177
178    if (proxyDict == NULL) {
179      err = coreFoundationUnknownErr;
180    }
181
182    setProxy(handle,proxy_host,proxy_port);
183  }
184  return err;
185}
186#else
187/**
188 * Should autodetect the proxy configuration (do nothing on linux)
189 *
190 * @param handle a CURL handle
191 * @param proto the protocol requiring the use of a proxy
192 */
193int setProxiesForProtcol(CURL* handle,const char *proto){
194#ifdef MSG_LAF_VERBOSE
195  fprintf( stderr, "setProxiesForProtocol (do nothing) ...\n" );
196#endif
197  return 0;
198}
199#endif
200
201/**
202 * Create a HINTERNET
203 *
204 * @param lpszAgent the HTPP User-Agent to use to send requests
205 * @param  dwAccessType type of access required
206 * @param  lpszProxyName the name of the proxy server(s) to use
207 * @param  lpszProxyBypass ip address or host names which should not be routed
208 *  through the proxy
209 * @param  dwFlags Options (INTERNET_FLAG_ASYNC,INTERNET_FLAG_FROM_CACHE,INTERNET_FLAG_OFFLINE)
210 * @return the created HINTERNET
211 */
212HINTERNET InternetOpen(char* lpszAgent,int dwAccessType,char* lpszProxyName,char* lpszProxyBypass,int dwFlags){
213  HINTERNET ret;
214  ret.handle=curl_multi_init();
215  ret.agent=strdup(lpszAgent);
216  ret.nb=0;
217  ret.ihandle[ret.nb].header=NULL;
218  return ret;
219}
220
221/**
222 * Add missing headers to an existing _HINTERNET
223 *
224 *
225 * @param handle the _HINTERNET pointer
226 * @param key the header parameter name
227 * @param value the header parameter value
228 * @return 0 if the operation succeeded, -1 in other case.
229 */
230int AddMissingHeaderEntry(_HINTERNET* handle,const char* key,const char* value){
231  int length=strlen(key)+strlen(value)+3;
232  char *entry=(char*)malloc((length)*sizeof(char));
233  if(entry==NULL)
234    return -1;
235  snprintf (entry, length, "%s: %s", key, value);
236  handle->header = curl_slist_append (handle->header, entry);
237  free(entry);
238  return 0;
239}
240
241/**
242 * Verify if a host is protected (appear in [security] > hosts)
243 *
244 * @param protectedHosts string containing all the protected hosts (coma separated)
245 * @param url string used to extract the host from
246 * @return 1 if the host is listed as protected, 0 in other case
247 */
248int isProtectedHost(const char* protectedHosts,const char* url){
249  char *token, *saveptr;
250  token = strtok_r (url, "//", &saveptr);
251  int cnt=0;
252  char* host;
253  while(token!=NULL && cnt<=1){
254    fprintf(stderr,"%s %d %s \n",__FILE__,__LINE__,token);
255    if(cnt==1)
256      fprintf(stderr,"%s %d %s \n",__FILE__,__LINE__,strstr(protectedHosts,token));
257    fflush(stderr);
258    if(cnt==1 && strstr(protectedHosts,token)!=NULL){
259      fprintf(stderr,"%s %d %s \n",__FILE__,__LINE__,strstr(protectedHosts,token));
260      return 1;
261    }
262    token = strtok_r (NULL, "/", &saveptr);
263    cnt+=1;
264  }
265  return 0;
266}
267
268/**
269 * Add headers defined in [security] > attributes to an existing HINTERNET
270 * @see isProtectedHost, AddMissingHeaderEntry
271 *
272 * @param handle the _HINTERNET pointer
273 * @param conf the header parameter name
274 * @param value the header parameter value
275 * @return 0 if the operation succeeded, -1 in other case.
276 */
277void AddHeaderEntries(HINTERNET* handle,maps* conf){
278  map* passThrough=getMapFromMaps(conf,"security","attributes");
279  map* targetHosts=getMapFromMaps(conf,"security","hosts");
280  char* passedHeader[10];
281  int cnt=0;
282  if(passThrough!=NULL && targetHosts!=NULL){
283    char *tmp=zStrdup(passThrough->value);
284    char *token, *saveptr;
285    token = strtok_r (tmp, ",", &saveptr);
286    int i;
287    for(i=0;i<handle->nb;i++){
288      if(targetHosts->value[0]=='*' || isProtectedHost(targetHosts->value,handle->ihandle[i].url)==1){
289        while (token != NULL){
290          int length=strlen(token)+6;
291          char* tmp1=(char*)malloc(length*sizeof(char));
292          snprintf(tmp1,6,"HTTP_");
293          int j;
294          for(j=0;token[j]!='\0';j++){
295            if(token[j]!='-')
296              tmp1[5+j]=toupper(token[i]);
297            else
298              tmp1[5+j]='_';
299            tmp1[5+j+1]='\0';
300          }
301          fprintf(stderr,"%s %d %s \n",__FILE__,__LINE__,tmp1);
302          map* tmpMap = getMapFromMaps(conf,"renv",tmp1);
303          if(tmpMap!=NULL)         
304            AddMissingHeaderEntry(&handle->ihandle[i],token,tmpMap->value);
305          free(tmp1);
306          if(handle->ihandle[i].header!=NULL)
307            curl_easy_setopt(handle->ihandle[i].handle,CURLOPT_HTTPHEADER,handle->ihandle[i].header);
308          cnt+=1;
309          token = strtok_r (NULL, ",", &saveptr);
310        }
311      }
312    }
313    free(tmp);
314  }
315}
316
317/**
318 * Close a HINTERNET connection and free allocated resources
319 *
320 * @param handle0 the HINTERNET connection to close
321 */
322void InternetCloseHandle(HINTERNET* handle0){
323  int i=0;
324  for(i=0;i<handle0->nb;i++){
325    _HINTERNET handle=handle0->ihandle[i];
326    if(handle.hasCacheFile>0){
327      fclose(handle.file);
328      unlink(handle.filename);
329    }
330    else{
331      handle.pabyData = NULL;
332      handle.nDataAlloc = handle.nDataLen = 0;
333    }
334    if(handle0->ihandle[i].header!=NULL){
335      curl_slist_free_all(handle0->ihandle[i].header);
336      handle0->ihandle[i].header=NULL;
337    }
338    if(handle.post!=NULL)
339      free(handle.post);
340    if(handle.url!=NULL)
341      free(handle.url);
342    free(handle.mimeType);
343    handle.mimeType = NULL;
344  }
345  if(handle0->handle)
346    curl_multi_cleanup(handle0->handle);
347  free(handle0->agent);
348  for(i=handle0->nb-1;i>=0;i--){
349    free(handle0->waitingRequests[i]);
350  }
351}
352
353/**
354 * Create a new element in the download queue
355 *
356 * @param hInternet the HINTERNET connection to add the download link
357 * @param lpszUrl the url to download
358 * @param lpszHeaders the additional headers to be sent to the HTTP server
359 * @param dwHeadersLength the size of the additional headers
360 * @param dwFlags desired download mode (INTERNET_FLAG_NO_CACHE_WRITE for not using cache file)
361 * @param dwContext not used
362 */
363HINTERNET InternetOpenUrl(HINTERNET* hInternet,LPCTSTR lpszUrl,LPCTSTR lpszHeaders,size_t dwHeadersLength,size_t dwFlags,size_t dwContext){
364
365  char filename[255];
366  struct MemoryStruct header;
367
368  hInternet->ihandle[hInternet->nb].handle=curl_easy_init( );
369  hInternet->ihandle[hInternet->nb].hasCacheFile=0;
370  hInternet->ihandle[hInternet->nb].nDataAlloc = 0;
371  hInternet->ihandle[hInternet->nb].url = NULL;
372  hInternet->ihandle[hInternet->nb].mimeType = NULL;
373  hInternet->ihandle[hInternet->nb].nDataLen = 0;
374  hInternet->ihandle[hInternet->nb].id = hInternet->nb;
375  hInternet->ihandle[hInternet->nb].nDataAlloc = 0;
376  hInternet->ihandle[hInternet->nb].pabyData = NULL;
377  hInternet->ihandle[hInternet->nb].post = NULL;
378
379  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_COOKIEFILE, "ALL");
380#ifndef TIGER
381  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_COOKIELIST, "ALL");
382#endif
383  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_USERAGENT, hInternet->agent);
384 
385  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_FOLLOWLOCATION,1);
386  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_MAXREDIRS,3);
387 
388  header.memory=NULL;
389  header.size = 0;
390
391  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_HEADERFUNCTION, header_write_data);
392  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_WRITEHEADER, (void *)&header);
393
394#ifdef MSG_LAF_VERBOSE
395  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_VERBOSE, 1);
396#endif
397
398     
399  switch(dwFlags)
400    {
401    case INTERNET_FLAG_NO_CACHE_WRITE:
402      hInternet->ihandle[hInternet->nb].hasCacheFile=-1;
403      curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_WRITEFUNCTION, write_data_into);
404      curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_WRITEDATA, (void*)&hInternet->ihandle[hInternet->nb]);
405      break;
406    default:
407      sprintf(hInternet->ihandle[hInternet->nb].filename,"/tmp/ZOO_Cache%d",(int)time(NULL));
408      hInternet->ihandle[hInternet->nb].filename[24]=0;
409#ifdef MSG_LAF_VERBOSE
410      fprintf(stderr,"file=%s",hInternet->ihandle[hInternet->nb].filename);
411#endif
412      hInternet->ihandle[hInternet->nb].filename=filename;
413      hInternet->ihandle[hInternet->nb].file=fopen(hInternet->ihandle[hInternet->nb].filename,"w+");
414   
415      hInternet->ihandle[hInternet->nb].hasCacheFile=1;
416      curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_WRITEFUNCTION, NULL);
417      curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle, CURLOPT_WRITEDATA, hInternet->ihandle[hInternet->nb].file);
418      hInternet->ihandle[hInternet->nb].nDataLen=0;
419      break;
420    }
421#ifdef ULINET_DEBUG
422  fprintf(stderr,"URL (%s)\nBODY (%s)\n",lpszUrl,lpszHeaders);
423#endif
424  if(lpszHeaders!=NULL && strlen(lpszHeaders)>0){
425#ifdef MSG_LAF_VERBOSE
426    fprintf(stderr,"FROM ULINET !!");
427    fprintf(stderr,"HEADER : [%s] %d\n",lpszHeaders,dwHeadersLength);
428#endif
429    curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_POST,1);
430#ifdef ULINET_DEBUG
431    fprintf(stderr,"** (%s) %d **\n",lpszHeaders,dwHeadersLength);
432    curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_VERBOSE,1);
433#endif
434    hInternet->ihandle[hInternet->nb].post=strdup(lpszHeaders);
435    curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_POSTFIELDS,hInternet->ihandle[hInternet->nb].post);
436    curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_POSTFIELDSIZE,(long)dwHeadersLength);
437  }
438  if(hInternet->ihandle[hInternet->nb].header!=NULL)
439    curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_HTTPHEADER,hInternet->ihandle[hInternet->nb].header);
440
441  curl_easy_setopt(hInternet->ihandle[hInternet->nb].handle,CURLOPT_URL,lpszUrl);
442  hInternet->ihandle[hInternet->nb].url = zStrdup(lpszUrl);
443
444  curl_multi_add_handle(hInternet->handle,hInternet->ihandle[hInternet->nb].handle);
445 
446  hInternet->ihandle[hInternet->nb].header=NULL;
447  ++hInternet->nb;
448
449#ifdef ULINET_DEBUG
450  fprintf(stderr,"DEBUG MIMETYPE: %s\n",hInternet.mimeType);
451  fflush(stderr);
452#endif
453  return *hInternet;
454};
455
456/**
457 * Download all opened urls in the queue
458 *
459 * @param hInternet the HINTERNET structure containing the queue
460 * @return 0
461 */
462int processDownloads(HINTERNET* hInternet){
463  int still_running=0;
464  int msgs_left=0;
465  int i=0;
466  do{
467    curl_multi_perform(hInternet->handle, &still_running);
468  }while(still_running); 
469  for(i=0;i<hInternet->nb;i++){
470    char *tmp;
471    curl_easy_getinfo(hInternet->ihandle[i].handle,CURLINFO_CONTENT_TYPE,&tmp);
472    if(tmp!=NULL)
473      hInternet->ihandle[i].mimeType=strdup(tmp);
474    curl_easy_getinfo(hInternet->ihandle[i].handle,CURLINFO_RESPONSE_CODE,&hInternet->ihandle[i].code);
475    curl_multi_remove_handle(hInternet->handle, hInternet->ihandle[i].handle);
476    curl_easy_cleanup(hInternet->ihandle[i].handle);
477  }
478  return 0;
479}
480
481/**
482 * Initialize the CCookie for a specific index (hInternet.nb)
483 *
484 * @param hInternet the HINTERNET structure to know the CCookie index to reset
485 * @return 1
486 * @see HINTERNET
487 */
488int freeCookieList(HINTERNET hInternet){
489  memset(&CCookie[hInternet.nb][0],0,1024);
490#ifndef TIGER
491  curl_easy_setopt(hInternet.ihandle[hInternet.nb].handle, CURLOPT_COOKIELIST, "ALL");
492#endif
493  return 1;
494}
495
496/**
497 * Copy a downloaded content
498 *
499 * @param hInternet the _HINTERNET structure
500 * @param lpBuffer the memory space to copy the downloaded content
501 * @param dwNumberOfBytesToRead the size of lpBuffer
502 * @param lpdwNumberOfBytesRead number of bytes red
503 * @return 1 on success, 0 if failure
504 */
505int InternetReadFile(_HINTERNET hInternet,LPVOID lpBuffer,int dwNumberOfBytesToRead, size_t *lpdwNumberOfBytesRead){
506  int dwDataSize;
507
508  if(hInternet.hasCacheFile>0){
509    fseek (hInternet.file , 0 , SEEK_END);
510    dwDataSize=ftell(hInternet.file); //taille du ficher
511    rewind (hInternet.file);
512  }
513  else{
514    memset(lpBuffer,0,hInternet.nDataLen+1);
515    memcpy(lpBuffer, hInternet.pabyData, hInternet.nDataLen );
516    dwDataSize=hInternet.nDataLen;
517    free( hInternet.pabyData );
518    hInternet.pabyData=NULL;
519  }
520
521  if( dwNumberOfBytesToRead /* buffer size */ < dwDataSize )
522    return 0;
523
524#ifdef MSG_LAF_VERBOSE
525  printf("\nfile size : %dko\n",dwDataSize/1024);
526#endif
527
528  if(hInternet.hasCacheFile>0){
529    *lpdwNumberOfBytesRead = fread(lpBuffer,1,dwDataSize,hInternet.file); 
530  }
531  else{
532    *lpdwNumberOfBytesRead = hInternet.nDataLen;
533    free( hInternet.pabyData );
534    hInternet.pabyData = NULL;
535    hInternet.nDataAlloc = hInternet.nDataLen = 0;
536  }
537
538  CCookie[hInternet.id][0]=0;
539
540  if( *lpdwNumberOfBytesRead < dwDataSize )
541      return 0;
542  else
543      return 1; // TRUE
544}
545
546
547/**
548 * Use basic authentication for accessing a resource
549 *
550 * @param hInternet the _HINTERNET structure
551 * @param login the login to use to authenticate
552 * @param passwd the password to use to authenticate
553 */
554int setBasicAuth(HINTERNET hInternet,char* login,char* passwd){
555  char *tmp;
556  tmp=(char*)malloc((strlen(login)+strlen(passwd)+2)*sizeof(char));
557  sprintf(tmp,"%s:%s",login,passwd);
558  if(curl_easy_setopt(hInternet.ihandle[hInternet.nb].handle,CURLOPT_USERPWD,tmp)==CURLE_OUT_OF_MEMORY){
559    free(tmp);
560    return -1;
561  }
562  curl_easy_setopt(hInternet.ihandle[hInternet.nb].handle, CURLOPT_HTTPAUTH,CURLAUTH_ANY);
563  free(tmp);
564  return 0;
565}
Note: See TracBrowser for help on using the repository browser.

Search

Context Navigation

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