Fix memleaks and a typo
[scilab.git] / scilab / modules / fileio / src / c / dlManager.c
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) 2012-2013 - S/E - Sylvestre LEDRU
4  *
5  * This file must be used under the terms of the CeCILL.
6  * This source file is licensed as described in the file COPYING, which
7  * you should have received as part of this distribution.  The terms
8  * are also available at
9  * http://www.cecill.info/licences/Licence_CeCILL_V2.1-en.txt
10  *
11  */
12
13 #ifndef _MSC_VER
14 #define _GNU_SOURCE             /* basename crashes this extension otherwise */
15 #endif
16 #include "MALLOC.h"
17 #include <curl/curl.h>
18 #include <libxml/uri.h>
19 #include <string.h>
20 #include "dlManager.h"
21 #include "Scierror.h"
22 #include "SCIHOME.h"
23 #include "PATH_MAX.h"
24 #include "isdir.h"
25 #include "charEncoding.h"
26 #include "localization.h"
27 #include "getos.h"
28 #include "machine.h"
29 #include "scicurdir.h"
30 #include "splitpath.h"
31 #include "getScilabPreference.h"
32 #include "stricmp.h"
33 #include "freeArrayOfString.h"
34 /* ==================================================================== */
35 #ifndef HAVE_BASENAME
36 static char *Curl_basename(char *path);
37 #define basename(x)  Curl_basename((x))
38 #endif
39 /* ==================================================================== */
40 static char errorBuffer[CURL_ERROR_SIZE];
41 /* ==================================================================== */
42 static int getProxyValues(char **proxyHost, long *proxyPort, char **proxyUserPwd);
43 /* ==================================================================== */
44 typedef struct __INPUTSTRING__
45 {
46     char *ptr;
47     size_t len;
48 } inputString;
49 /* ==================================================================== */
50 static void init_string(inputString *s)
51 {
52     s->len = 0;
53     s->ptr = (char*)CALLOC(s->len + 1, sizeof(char));
54     if (s->ptr == NULL)
55     {
56         Scierror(999, "Internal error: calloc() failed.\n");
57         return;
58     }
59 }
60 /* ==================================================================== */
61 static void free_string(inputString *s)
62 {
63     if (s->len && s->ptr)
64     {
65         FREE(s->ptr);
66         s->ptr = NULL;
67     }
68 }
69 /* ==================================================================== */
70 static size_t writefunc(void *ptr, size_t size, size_t nmemb, inputString *s)
71 {
72     size_t new_len = s->len + size * nmemb;
73
74     s->ptr = (char*)REALLOC(s->ptr, new_len + 1);
75     if (s->ptr == NULL)
76     {
77         Scierror(999, "Internal error: realloc() failed.\n");
78         return 0;
79     }
80     memcpy(s->ptr + s->len, ptr, size * nmemb);
81     s->ptr[new_len] = '\0';
82     s->len = new_len;
83
84     return size * nmemb;
85 }
86 /* ==================================================================== */
87 static char *getFileNameFromURL(char *url)
88 {
89     char *filename = NULL;
90     xmlURIPtr c = xmlParseURI(url);
91
92     if (c == NULL)
93     {
94         Scierror(999, _("Could not parse the URL.\n"));
95         return NULL;
96     }
97
98     if (c->path == NULL || strstr(c->path, "/") == 0 || strcmp(c->path, "/") == 0)
99     {
100         filename = (char *)MALLOC((strlen(DEFAULT_FILENAME) + 1) * sizeof(char));
101         strcpy(filename, DEFAULT_FILENAME);
102     }
103     else
104     {
105         char bname[PATH_MAX] = {0};
106         strncpy(bname, basename(c->path), sizeof(bname));
107         filename = (char *)MALLOC((strlen(bname) + 1) * sizeof(char));
108         strcpy(filename, bname);
109     }
110     return filename;
111
112 }
113 /* ==================================================================== */
114 int getProxyValues(char **proxyHost, long *proxyPort, char **proxyUserPwd)
115 {
116     const char * attrs[] = {"enabled", "host", "port", "user", "password"};
117     const unsigned int N = sizeof(attrs) / sizeof(char*);
118     char ** values = getPrefAttributesValues("//web/body/proxy", attrs, N);
119
120     if (!values)
121     {
122         return 0;
123     }
124
125     if (stricmp(values[0]/*enabled*/, "true") == 0)
126     {
127         const unsigned int ulen = (const unsigned int)strlen(values[3]);
128         const unsigned int plen = (const unsigned int)strlen(values[4]);
129
130         *proxyHost = values[1]; //host;
131         *proxyPort = strtol(values[2], NULL, 10); //port;
132         FREE(values[2]);
133
134         if (plen == 0)
135         {
136             *proxyUserPwd = values[3]; //user
137         }
138         else
139         {
140             *proxyUserPwd = (char *)MALLOC((ulen + 1 + plen + 1) * sizeof(char *));
141             sprintf(*proxyUserPwd, "%s:%s", values[3]/*user*/, values[4]/*password*/);
142             (*proxyUserPwd)[ulen + 1 + plen] = '\0';
143             FREE(values[3]);
144         }
145
146         FREE(values[4]);
147         FREE(values);
148     }
149     else
150     {
151         freeArrayOfString(values, N);
152         return 0;
153     }
154
155     return 1;
156 }
157 /* ==================================================================== */
158 char *downloadFile(char *url, char *dest, char *username, char *password, char **content)
159 {
160     CURL *curl;
161     CURLcode res;
162     char *filename = NULL;
163     FILE *file;
164     inputString buffer;
165     char *destdir = NULL;
166     char *destfile = NULL;
167
168     curl = curl_easy_init();
169     if (curl == NULL)
170     {
171         Scierror(999, "Failed opening the curl handle.\n");
172         return NULL;
173     }
174
175     init_string(&buffer);
176
177     res = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
178     if (res != CURLE_OK)
179     {
180         Scierror(999, "Failed to set error buffer [%d]\n", res);
181         return NULL;
182     }
183
184     // Get destination directory and filename
185     if (dest != NULL)
186     {
187         // Destination is specified in argument
188         char* pathdrive = (char*)MALLOC(sizeof(char) * (PATH_MAX + 1));
189         char* pathdir = (char*)MALLOC(sizeof(char) * (PATH_MAX + 1));
190         char* pathfile = (char*)MALLOC(sizeof(char) * (PATH_MAX + 1));
191         char* pathext = (char*)MALLOC(sizeof(char) * (PATH_MAX + 1));
192
193         splitpath(dest, TRUE, pathdrive, pathdir, pathfile, pathext);
194
195         if (!isdir(dest))
196         {
197             // Destination is a file
198             destdir = (char *)MALLOC((strlen(pathdrive) + strlen(pathdir) + 1) * sizeof(char));
199             strcpy(destdir, pathdrive);
200             strcat(destdir, pathdir);
201
202             // Get filename
203             destfile = (char *)MALLOC((strlen(pathfile) + strlen(pathext) + 1) * sizeof(char));
204             strcpy(destfile, pathfile);
205             strcat(destfile, pathext);
206         }
207         else
208         {
209             // Destination is a directory
210             destdir = (char *)MALLOC((strlen(pathdrive) + strlen(pathdir) + strlen(pathfile) + strlen(pathext) + strlen(DIR_SEPARATOR) + 1) * sizeof(char));
211             strcpy(destdir, pathdrive);
212             strcat(destdir, pathdir);
213             strcat(destdir, pathfile);
214             strcat(destdir, pathext);
215             strcat(destdir, DIR_SEPARATOR);
216
217             // Retrieve filename from URL
218             destfile = getFileNameFromURL(url);
219         }
220
221         FREE(pathdrive);
222         FREE(pathdir);
223         FREE(pathfile);
224         FREE(pathext);
225     }
226     else
227     {
228         // Destination is not specified in argument
229         // Destination directory is current dir
230         int err = 0;
231         char *currentdir;
232         currentdir = scigetcwd(&err);
233         if (!err)
234         {
235             destdir = (char *)MALLOC((strlen(currentdir) + strlen(DIR_SEPARATOR) + 1) * sizeof(char));
236             strcpy(destdir, currentdir);
237             strcat(destdir, DIR_SEPARATOR);
238             FREE(currentdir);
239         }
240         else
241         {
242             Scierror(999, _("Failed getting current dir, error code: %d\n"), err);
243             return NULL;
244         }
245
246         // Destination filename retrieved from URL
247         destfile = getFileNameFromURL(url);
248     }
249
250     if (destfile == NULL)
251     {
252         return NULL;
253     }
254
255     // Build file path
256     filename = (char *)MALLOC((strlen(destdir) + strlen(destfile) + 1) * sizeof(char));
257     strcpy(filename, destdir);
258     strcat(filename, destfile);
259     FREE(destdir);
260     FREE(destfile);
261
262     res = curl_easy_setopt(curl, CURLOPT_URL, url);
263     if (res != CURLE_OK)
264     {
265         Scierror(999, _("Failed to set URL [%s]\n"), errorBuffer);
266         FREE(filename);
267         return NULL;
268     }
269
270     //Set authentication variables
271     if (username != NULL)
272     {
273         char * userpass;
274         int uplen = (int)strlen(username);
275         if (password != NULL)
276         {
277             uplen = uplen + (int)strlen(password);
278         }
279
280         userpass = (char *)MALLOC((uplen + 2) * sizeof(char));
281
282         strcpy(userpass, username);
283         strcat(userpass, ":");
284         if (password != NULL)
285         {
286             strcat(userpass, password);
287         }
288
289         res = curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
290         if (res != CURLE_OK)
291         {
292             FREE(filename);
293             FREE(userpass);
294             Scierror(999, "Failed to set httpauth type to ANY [%s]\n", errorBuffer);
295             return NULL;
296         }
297
298         res = curl_easy_setopt(curl, CURLOPT_USERPWD, userpass);
299         if (res != CURLE_OK)
300         {
301             FREE(filename);
302             Scierror(999, _("Failed to set user:pwd [%s]\n"), errorBuffer);
303             return NULL;
304         }
305     } /* end authentication section */
306
307     {
308         //Set proxy variables
309         char *proxyHost = NULL;
310         char *proxyUserPwd = NULL;
311         long proxyPort = 1080;
312         int proxySet = 0;
313
314         proxySet = getProxyValues(&proxyHost, &proxyPort, &proxyUserPwd);
315
316         if (proxySet == 1)
317         {
318             res = curl_easy_setopt(curl, CURLOPT_PROXY, proxyHost);
319             if (res != CURLE_OK)
320             {
321                 FREE(proxyHost);
322                 FREE(proxyUserPwd);
323                 FREE(filename);
324                 Scierror(999, _("Failed to set proxy host [%s]\n"), errorBuffer);
325                 return NULL;
326             }
327
328             res = curl_easy_setopt(curl, CURLOPT_PROXYPORT, proxyPort);
329             if (res != CURLE_OK)
330             {
331                 FREE(proxyHost);
332                 FREE(proxyUserPwd);
333                 FREE(filename);
334                 Scierror(999, _("Failed to set proxy port [%s]\n"), errorBuffer);
335                 return NULL;
336             }
337             if (proxyUserPwd != NULL)
338             {
339                 res = curl_easy_setopt(curl, CURLOPT_PROXYUSERPWD, proxyUserPwd);
340                 if (res != CURLE_OK)
341                 {
342                     FREE(proxyHost);
343                     FREE(proxyUserPwd);
344                     FREE(filename);
345                     Scierror(999, _("Failed to set proxy user:password [%s]\n"), errorBuffer);
346                     return NULL;
347                 }
348             }
349
350             FREE(proxyHost);
351             FREE(proxyUserPwd);
352         }
353     } /* end of the set of the proxy */
354
355     res = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
356     if (res != CURLE_OK)
357     {
358         FREE(filename);
359         Scierror(999, _("Failed to set write function [%s]\n"), errorBuffer);
360         return NULL;
361     }
362
363     //Get data to be written to the variable
364     res = curl_easy_setopt(curl, CURLOPT_WRITEDATA, &buffer);
365     if (res != CURLE_OK)
366     {
367         FREE(filename);
368         free_string(&buffer);
369         Scierror(999, _("Failed to set write data [%s]\n"), errorBuffer);
370         return NULL;
371     }
372
373     // Follow redirects
374     res = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
375     if (res != CURLE_OK)
376     {
377         FREE(filename);
378         free_string(&buffer);
379         Scierror(999, _("Failed to set 'Follow Location' [%s]\n"), errorBuffer);
380         return NULL;
381     }
382
383     res = curl_easy_perform(curl);
384     if (res != 0)
385     {
386         FREE(filename);
387         free_string(&buffer);
388         Scierror(999, _("Transfer did not complete successfully: %s\n"), errorBuffer);
389         return NULL;
390     }
391
392     wcfopen(file, (char*)filename, "wb");
393     if (file == NULL)
394     {
395         Scierror(999, _("Failed opening '%s' for writing.\n"), filename);
396         FREE(filename);
397         return NULL;
398     }
399
400     /* Write the file */
401     fwrite(buffer.ptr, sizeof(char), buffer.len, file);
402
403     /* Create the variable which contains the output argument */
404     *content = buffer.ptr;
405
406     /* always cleanup */
407     curl_easy_cleanup(curl);
408
409     fclose(file);
410     return filename;
411 }
412 /* ==================================================================== */
413 static char *Curl_basename(char *path)
414 {
415     char *s1 = NULL;
416     char *s2 = NULL;
417
418     s1 = strrchr(path, '/');
419     s2 = strrchr(path, '\\');
420
421     if (s1 && s2)
422     {
423         path = (s1 > s2 ? s1 : s2) + 1;
424     }
425     else if (s1)
426     {
427         path = s1 + 1;
428     }
429     else if (s2)
430     {
431         path = s2 + 1;
432     }
433     return path;
434 }
435 /* ==================================================================== */