~cairo-dock-team/ubuntu/oneiric/cairo-dock/2.3.0-3

« back to all changes in this revision

Viewing changes to src/gldit/cairo-dock-packages.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthieu Baerts (matttbe)
  • Date: 2010-08-09 23:26:12 UTC
  • mto: This revision was merged to the branch mainline in revision 13.
  • Revision ID: james.westby@ubuntu.com-20100809232612-pocdxliaxjdetm37
Tags: upstream-2.2.0~0beta4
ImportĀ upstreamĀ versionĀ 2.2.0~0beta4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**
 
2
* This file is a part of the Cairo-Dock project
 
3
*
 
4
* Copyright : (C) see the 'copyright' file.
 
5
* E-mail    : see the 'copyright' file.
 
6
*
 
7
* This program is free software; you can redistribute it and/or
 
8
* modify it under the terms of the GNU General Public License
 
9
* as published by the Free Software Foundation; either version 3
 
10
* of the License, or (at your option) any later version.
 
11
*
 
12
* This program is distributed in the hope that it will be useful,
 
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
* GNU General Public License for more details.
 
16
* You should have received a copy of the GNU General Public License
 
17
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
18
*/
 
19
 
 
20
#include <string.h>
 
21
#include <unistd.h>
 
22
#define __USE_XOPEN_EXTENDED
 
23
#include <stdlib.h>
 
24
#include <sys/stat.h>
 
25
#define __USE_POSIX
 
26
#include <time.h>
 
27
#include <glib/gstdio.h>
 
28
#include <glib/gi18n.h>
 
29
#include <curl/curl.h>
 
30
 
 
31
#include "../config.h"
 
32
#include "cairo-dock-keyfile-utilities.h"
 
33
//#include "cairo-dock-dock-manager.h"
 
34
//#include "cairo-dock-gui-manager.h"
 
35
#include "cairo-dock-task.h"
 
36
#include "cairo-dock-log.h"
 
37
#include "cairo-dock-internal-system.h"
 
38
#include "cairo-dock-packages.h"
 
39
 
 
40
#define CAIRO_DOCK_DEFAULT_PACKAGES_LIST_FILE "list.conf"
 
41
 
 
42
static gchar *s_cPackageServerAdress = NULL;
 
43
 
 
44
  ////////////////////
 
45
 /// DOWNLOAD API ///
 
46
////////////////////
 
47
 
 
48
gchar *cairo_dock_uncompress_file (const gchar *cArchivePath, const gchar *cExtractTo, const gchar *cRealArchiveName)
 
49
{
 
50
        //\_______________ on cree le repertoire d'extraction.
 
51
        if (!g_file_test (cExtractTo, G_FILE_TEST_EXISTS))
 
52
        {
 
53
                if (g_mkdir (cExtractTo, 7*8*8+7*8+5) != 0)
 
54
                {
 
55
                        cd_warning ("couldn't create directory %s", cExtractTo);
 
56
                        return NULL;
 
57
                }
 
58
        }
 
59
        
 
60
        //\_______________ on construit le chemin local du dossier apres son extraction.
 
61
        gchar *cLocalFileName;
 
62
        if (cRealArchiveName == NULL)
 
63
                cRealArchiveName = cArchivePath;
 
64
        gchar *str = strrchr (cRealArchiveName, '/');
 
65
        if (str != NULL)
 
66
                cLocalFileName = g_strdup (str+1);
 
67
        else
 
68
                cLocalFileName = g_strdup (cRealArchiveName);
 
69
        
 
70
        if (g_str_has_suffix (cLocalFileName, ".tar.gz"))
 
71
                cLocalFileName[strlen(cLocalFileName)-7] = '\0';
 
72
        else if (g_str_has_suffix (cLocalFileName, ".tar.bz2"))
 
73
                cLocalFileName[strlen(cLocalFileName)-8] = '\0';
 
74
        else if (g_str_has_suffix (cLocalFileName, ".tgz"))
 
75
                cLocalFileName[strlen(cLocalFileName)-4] = '\0';
 
76
        g_return_val_if_fail (cLocalFileName != NULL && *cLocalFileName != '\0', NULL);
 
77
        
 
78
        gchar *cResultPath = g_strdup_printf ("%s/%s", cExtractTo, cLocalFileName);
 
79
        g_free (cLocalFileName);
 
80
        
 
81
        //\_______________ on efface un dossier identique prealable.
 
82
        if (g_file_test (cResultPath, G_FILE_TEST_EXISTS))
 
83
        {
 
84
                gchar *cCommand = g_strdup_printf ("rm -rf \"%s\"", cResultPath);
 
85
                int r = system (cCommand);
 
86
                g_free (cCommand);
 
87
        }
 
88
        
 
89
        //\_______________ on decompresse l'archive.
 
90
        gchar *cCommand = g_strdup_printf ("tar xf%c \"%s\" -C \"%s\"", (g_str_has_suffix (cArchivePath, "bz2") ? 'j' : 'z'), cArchivePath, cExtractTo);
 
91
        cd_debug ("tar : %s\n", cCommand);
 
92
        int r = system (cCommand);
 
93
        if (r != 0)
 
94
        {
 
95
                cd_warning ("an error occured while executing '%s'", cCommand);
 
96
                g_free (cResultPath);
 
97
                cResultPath = NULL;
 
98
        }
 
99
        g_free (cCommand);
 
100
        return cResultPath;
 
101
}
 
102
 
 
103
static inline CURL *_init_curl_connection (const gchar *cURL)
 
104
{
 
105
        CURL *handle = curl_easy_init ();
 
106
        curl_easy_setopt (handle, CURLOPT_URL, cURL);
 
107
        if (mySystem.cConnectionProxy != NULL)
 
108
        {
 
109
                curl_easy_setopt (handle, CURLOPT_PROXY, mySystem.cConnectionProxy);
 
110
                if (mySystem.iConnectionPort != 0)
 
111
                        curl_easy_setopt (handle, CURLOPT_PROXYPORT, mySystem.iConnectionPort);
 
112
                if (mySystem.cConnectionUser != NULL && mySystem.
 
113
                        cConnectionPasswd != NULL)
 
114
                {
 
115
                        gchar *cUserPwd = g_strdup_printf ("%s:%s", mySystem.cConnectionUser, mySystem.
 
116
                        cConnectionPasswd);
 
117
                        curl_easy_setopt (handle, CURLOPT_PROXYUSERPWD, cUserPwd);
 
118
                        g_free (cUserPwd);
 
119
                        /*curl_easy_setopt (handle, CURLOPT_PROXYUSERNAME, mySystem.cConnectionUser);
 
120
                        if (mySystem.cConnectionPasswd != NULL)
 
121
                                curl_easy_setopt (handle, CURLOPT_PROXYPASSWORD, mySystem.cConnectionPasswd);*/  // a partir de libcurl 7.19.1, donc apres Jaunty
 
122
                }
 
123
        }
 
124
        curl_easy_setopt (handle, CURLOPT_TIMEOUT, mySystem.iConnectionMaxTime);
 
125
        curl_easy_setopt (handle, CURLOPT_CONNECTTIMEOUT, mySystem.iConnectionTimeout);
 
126
        curl_easy_setopt (handle, CURLOPT_NOSIGNAL, 1);  // With CURLOPT_NOSIGNAL set non-zero, curl will not use any signals; sinon curl se vautre apres le timeout, meme si le download s'est bien passe !
 
127
        return handle;
 
128
}
 
129
 
 
130
static size_t _write_data_to_file (gpointer buffer, size_t size, size_t nmemb, FILE *fd)
 
131
{
 
132
        return fwrite (buffer, size, nmemb, fd);
 
133
}
 
134
gchar *cairo_dock_download_file (const gchar *cServerAdress, const gchar *cDistantFilePath, const gchar *cDistantFileName, const gchar *cExtractTo, GError **erreur)
 
135
{
 
136
        //g_print ("%s (%s, %s, %s, %s)\n", __func__, cServerAdress, cDistantFilePath, cDistantFileName, cExtractTo);
 
137
        //\_______________ On reserve un fichier temporaire.
 
138
        gchar *cTmpFilePath = g_strdup ("/tmp/cairo-dock-net-file.XXXXXX");
 
139
        int fds = mkstemp (cTmpFilePath);
 
140
        if (fds == -1)
 
141
        {
 
142
                g_set_error (erreur, 1, 1, "couldn't create temporary file '%s'", cTmpFilePath);
 
143
                g_free (cTmpFilePath);
 
144
                return NULL;
 
145
        }
 
146
        
 
147
        //\_______________ On lance le download.
 
148
        gchar *cURL = (cServerAdress ? g_strdup_printf ("%s/%s/%s", cServerAdress, cDistantFilePath, cDistantFileName) : g_strdup (cDistantFileName));
 
149
        cd_debug ("cURL : %s\n", cURL);
 
150
        FILE *f = fopen (cTmpFilePath, "wb");
 
151
        g_return_val_if_fail (f, NULL);
 
152
        
 
153
        CURL *handle = _init_curl_connection (cURL);
 
154
        curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, _write_data_to_file);
 
155
        curl_easy_setopt(handle, CURLOPT_WRITEDATA, f);
 
156
        
 
157
        CURLcode r = curl_easy_perform (handle);
 
158
        
 
159
        if (r != CURLE_OK)
 
160
        {
 
161
                cd_warning ("an error occured while downloading '%s'", cURL);
 
162
                g_remove (cTmpFilePath);
 
163
                g_free (cTmpFilePath);
 
164
                cTmpFilePath = NULL;
 
165
        }
 
166
        
 
167
        curl_easy_cleanup (handle);
 
168
        g_free (cURL);
 
169
        fclose (f);
 
170
        
 
171
        //\_______________ On teste que le fichier est non vide.
 
172
        gboolean bOk = (cTmpFilePath != NULL);
 
173
        if (bOk)
 
174
        {
 
175
                struct stat buf;
 
176
                stat (cTmpFilePath, &buf);
 
177
                bOk = (buf.st_size > 0);
 
178
        }
 
179
        if (! bOk)
 
180
        {
 
181
                g_set_error (erreur, 1, 1, "couldn't get distant file %s", cDistantFileName);
 
182
                g_remove (cTmpFilePath);
 
183
                g_free (cTmpFilePath);
 
184
                cTmpFilePath = NULL;
 
185
        }
 
186
        close(fds);
 
187
        
 
188
        //\_______________ On l'extrait si c'est une archive.
 
189
        if (cTmpFilePath != NULL && cExtractTo != NULL)
 
190
        {
 
191
                cd_debug ("uncompressing ...\n");
 
192
                gchar *cPath = cairo_dock_uncompress_file (cTmpFilePath, cExtractTo, cDistantFileName);
 
193
                g_remove (cTmpFilePath);
 
194
                g_free (cTmpFilePath);
 
195
                cTmpFilePath = cPath;
 
196
        }
 
197
        
 
198
        return cTmpFilePath;
 
199
}
 
200
 
 
201
static void _dl_file (gpointer *pSharedMemory)
 
202
{
 
203
        GError *erreur = NULL;
 
204
        pSharedMemory[6] = cairo_dock_download_file (pSharedMemory[0], pSharedMemory[1], pSharedMemory[2], pSharedMemory[3], &erreur);
 
205
        if (erreur != NULL)
 
206
        {
 
207
                cd_warning (erreur->message);
 
208
                g_error_free (erreur);
 
209
        }
 
210
}
 
211
static gboolean _finish_dl (gpointer *pSharedMemory)
 
212
{
 
213
        if (pSharedMemory[6] == NULL)
 
214
                cd_warning ("couldn't get distant file %s", pSharedMemory[2]);
 
215
        
 
216
        GFunc pCallback = pSharedMemory[4];
 
217
        pCallback (pSharedMemory[6], pSharedMemory[5]);
 
218
        return FALSE;
 
219
}
 
220
static void _free_dl (gpointer *pSharedMemory)
 
221
{
 
222
        g_free (pSharedMemory[0]);
 
223
        g_free (pSharedMemory[1]);
 
224
        g_free (pSharedMemory[2]);
 
225
        g_free (pSharedMemory[3]);
 
226
        g_free (pSharedMemory[6]);
 
227
        g_free (pSharedMemory);
 
228
}
 
229
CairoDockTask *cairo_dock_download_file_async (const gchar *cServerAdress, const gchar *cDistantFilePath, const gchar *cDistantFileName, const gchar *cExtractTo, GFunc pCallback, gpointer data)
 
230
{
 
231
        gpointer *pSharedMemory = g_new0 (gpointer, 7);
 
232
        pSharedMemory[0] = g_strdup (cServerAdress);
 
233
        pSharedMemory[1] = g_strdup (cDistantFilePath);
 
234
        pSharedMemory[2] = g_strdup (cDistantFileName);
 
235
        pSharedMemory[3] = g_strdup (cExtractTo);
 
236
        pSharedMemory[4] = pCallback;
 
237
        pSharedMemory[5] = data;
 
238
        CairoDockTask *pTask = cairo_dock_new_task_full (0, (CairoDockGetDataAsyncFunc) _dl_file, (CairoDockUpdateSyncFunc) _finish_dl, (GFreeFunc) _free_dl, pSharedMemory);
 
239
        cairo_dock_launch_task (pTask);
 
240
        return pTask;
 
241
}
 
242
 
 
243
 
 
244
gchar *cairo_dock_get_distant_file_content (const gchar *cServerAdress, const gchar *cDistantFilePath, const gchar *cDistantFileName, GError **erreur)
 
245
{
 
246
        gchar *cURL = g_strdup_printf ("%s/%s/%s", cServerAdress, cDistantFilePath, cDistantFileName);
 
247
        gchar *cContent = cairo_dock_get_url_data (cURL, erreur);
 
248
        g_free (cURL);
 
249
        return cContent;
 
250
}
 
251
 
 
252
static size_t _write_data_to_buffer (gpointer buffer, size_t size, size_t nmemb, GList **list_ptr)
 
253
{
 
254
        GList *pList = *list_ptr;
 
255
        *list_ptr = g_list_prepend (*list_ptr, g_strndup (buffer, size * nmemb));
 
256
        return size * nmemb;
 
257
}
 
258
gchar *cairo_dock_get_url_data (const gchar *cURL, GError **erreur)
 
259
{
 
260
        //\_______________ On lance le download.
 
261
        cd_debug ("getting data from '%s' ...", cURL);
 
262
        CURL *handle = _init_curl_connection (cURL);
 
263
        curl_easy_setopt (handle, CURLOPT_WRITEFUNCTION, (curl_write_callback)_write_data_to_buffer);
 
264
        gpointer *pointer_to_list = g_new0 (gpointer, 1);
 
265
        curl_easy_setopt (handle, CURLOPT_WRITEDATA, pointer_to_list);
 
266
        
 
267
        CURLcode r = curl_easy_perform (handle);
 
268
        
 
269
        if (r != CURLE_OK)
 
270
        {
 
271
                cd_warning ("an error occured while downloading '%s' : %s", cURL, curl_easy_strerror (r));
 
272
                g_free (pointer_to_list);
 
273
                pointer_to_list = NULL;
 
274
        }
 
275
        
 
276
        curl_easy_cleanup (handle);
 
277
        
 
278
        //\_______________ On recupere les donnees.
 
279
        gchar *cContent = NULL;
 
280
        if (pointer_to_list != NULL)
 
281
        {
 
282
                GList *l, *pList = *pointer_to_list;
 
283
                int n = 0;
 
284
                for (l = pList; l != NULL; l = l->next)
 
285
                {
 
286
                        if (l->data != NULL)
 
287
                                n += strlen (l->data);
 
288
                }
 
289
                
 
290
                if (n != 0)
 
291
                {
 
292
                        cContent = g_new0 (char, n+1);
 
293
                        char *ptr = cContent;
 
294
                        for (l = g_list_last (pList); l != NULL; l = l->prev)
 
295
                        {
 
296
                                if (l->data != NULL)
 
297
                                {
 
298
                                        n = strlen (l->data);
 
299
                                        memcpy (ptr, l->data, n);
 
300
                                        ptr += n;
 
301
                                        g_free (l->data);
 
302
                                }
 
303
                        }
 
304
                }
 
305
                g_list_free (pList);
 
306
                g_free (pointer_to_list);
 
307
        }
 
308
        
 
309
        return cContent;
 
310
}
 
311
 
 
312
static void _dl_file_content (gpointer *pSharedMemory)
 
313
{
 
314
        GError *erreur = NULL;
 
315
        pSharedMemory[5] = cairo_dock_get_distant_file_content (pSharedMemory[0], pSharedMemory[1], pSharedMemory[2], &erreur);
 
316
        if (erreur != NULL)
 
317
        {
 
318
                cd_warning (erreur->message);
 
319
                g_error_free (erreur);
 
320
        }
 
321
}
 
322
static gboolean _finish_dl_content (gpointer *pSharedMemory)
 
323
{
 
324
        if (pSharedMemory[5] == NULL)
 
325
                cd_warning ("couldn't get distant file %s", pSharedMemory[2]);
 
326
        
 
327
        GFunc pCallback = pSharedMemory[3];
 
328
        pCallback (pSharedMemory[5], pSharedMemory[4]);
 
329
        return TRUE;
 
330
}
 
331
static void _free_dl_content (gpointer *pSharedMemory)
 
332
{
 
333
        g_free (pSharedMemory[0]);
 
334
        g_free (pSharedMemory[1]);
 
335
        g_free (pSharedMemory[2]);
 
336
        g_free (pSharedMemory[5]);
 
337
        g_free (pSharedMemory);
 
338
}
 
339
CairoDockTask *cairo_dock_get_distant_file_content_async (const gchar *cServerAdress, const gchar *cDistantFilePath, const gchar *cDistantFileName, GFunc pCallback, gpointer data)
 
340
{
 
341
        gpointer *pSharedMemory = g_new0 (gpointer, 6);
 
342
        pSharedMemory[0] = g_strdup (cServerAdress);
 
343
        pSharedMemory[1] = g_strdup (cDistantFilePath);
 
344
        pSharedMemory[2] = g_strdup (cDistantFileName);
 
345
        pSharedMemory[3] = pCallback;
 
346
        pSharedMemory[4] = data;
 
347
        CairoDockTask *pTask = cairo_dock_new_task_full (0, (CairoDockGetDataAsyncFunc) _dl_file_content, (CairoDockUpdateSyncFunc) _finish_dl_content, (GFreeFunc) _free_dl_content, pSharedMemory);
 
348
        cairo_dock_launch_task (pTask);
 
349
        return pTask;
 
350
}
 
351
 
 
352
  ////////////////////
 
353
 /// PACKAGES API ///
 
354
////////////////////
 
355
 
 
356
void cairo_dock_free_package (CairoDockPackage *pPackage)
 
357
{
 
358
        if (pPackage == NULL)
 
359
                return ;
 
360
        g_free (pPackage->cPackagePath);
 
361
        g_free (pPackage->cAuthor);
 
362
        g_free (pPackage->cDisplayedName);
 
363
        g_free (pPackage);
 
364
}
 
365
 
 
366
static inline int _get_rating (const gchar *cPackagesDir, const gchar *cPackageName)
 
367
{
 
368
        gchar *cRatingFile = g_strdup_printf ("%s/.rating/%s", cPackagesDir, cPackageName);
 
369
        int iRating = 0;
 
370
        gsize length = 0;
 
371
        gchar *cContent = NULL;
 
372
        g_file_get_contents (cRatingFile,
 
373
                &cContent,
 
374
                &length,
 
375
                NULL);
 
376
        if (cContent)
 
377
        {
 
378
                iRating = atoi (cContent);
 
379
                g_free (cContent);
 
380
        }
 
381
        g_free (cRatingFile);
 
382
        return iRating; 
 
383
}
 
384
GHashTable *cairo_dock_list_local_packages (const gchar *cPackagesDir, GHashTable *hProvidedTable, gboolean bUpdatePackageValidity, GError **erreur)
 
385
{
 
386
        cd_debug ("%s (%s)", __func__, cPackagesDir);
 
387
        GError *tmp_erreur = NULL;
 
388
        GDir *dir = g_dir_open (cPackagesDir, 0, &tmp_erreur);
 
389
        if (tmp_erreur != NULL)
 
390
        {
 
391
                g_propagate_error (erreur, tmp_erreur);
 
392
                return hProvidedTable;
 
393
        }
 
394
 
 
395
        GHashTable *pPackageTable = (hProvidedTable != NULL ? hProvidedTable : g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) cairo_dock_free_package));
 
396
        
 
397
        CairoDockPackageType iType = (strncmp (cPackagesDir, "/usr", 4) == 0 ?
 
398
                CAIRO_DOCK_LOCAL_PACKAGE :
 
399
                CAIRO_DOCK_USER_PACKAGE);
 
400
        GString *sRatingFile = g_string_new (cPackagesDir);
 
401
        gchar *cPackagePath;
 
402
        CairoDockPackage *pPackage;
 
403
        const gchar *cPackageName;
 
404
        while ((cPackageName = g_dir_read_name (dir)) != NULL)
 
405
        {
 
406
                // on ecarte les fichiers caches.
 
407
                if (*cPackageName == '.')
 
408
                        continue;
 
409
                
 
410
                // on ecarte les non repertoires.
 
411
                cPackagePath = g_strdup_printf ("%s/%s", cPackagesDir, cPackageName);
 
412
                if (! g_file_test (cPackagePath, G_FILE_TEST_IS_DIR))
 
413
                {
 
414
                        g_free (cPackagePath);
 
415
                        continue;
 
416
                }
 
417
                
 
418
                // on insere le package dans la table.
 
419
                pPackage = g_new0 (CairoDockPackage, 1);
 
420
                pPackage->cPackagePath = cPackagePath;
 
421
                pPackage->cDisplayedName = g_strdup (cPackageName);
 
422
                pPackage->iType = iType;
 
423
                pPackage->iRating = _get_rating (cPackagesDir, cPackageName);
 
424
                g_hash_table_insert (pPackageTable, g_strdup (cPackageName), pPackage);  // donc ecrase un package installe ayant le meme nom.
 
425
        }
 
426
        g_dir_close (dir);
 
427
        return pPackageTable;
 
428
}
 
429
 
 
430
static inline int _convert_date (int iDate)
 
431
{
 
432
        int d, m, y;
 
433
        y = iDate / 10000;
 
434
        m = (iDate - y*10000) / 100;
 
435
        d = iDate % 100;
 
436
        return (d + m*30 + y*365);
 
437
}
 
438
static void _cairo_dock_parse_package_list (GKeyFile *pKeyFile, const gchar *cServerAdress, const gchar *cDirectory, GHashTable *pPackageTable)
 
439
{
 
440
        // date courante.
 
441
        time_t epoch = (time_t) time (NULL);
 
442
        struct tm currentTime;
 
443
        localtime_r (&epoch, &currentTime);
 
444
        int day = currentTime.tm_mday;  // dans l'intervalle 1 a 31.
 
445
        int month = currentTime.tm_mon + 1;  // dans l'intervalle 0 a 11.
 
446
        int year = 1900 + currentTime.tm_year;  // tm_year = nombre d'annees Ć©coulees depuis 1900.
 
447
        int now = day + month * 30 + year * 365;
 
448
        
 
449
        // liste des packages.
 
450
        gsize length=0;
 
451
        gchar **pGroupList = g_key_file_get_groups (pKeyFile, &length);
 
452
        g_return_if_fail (pGroupList != NULL);  // rien a charger dans la table, on quitte.
 
453
        
 
454
        // on parcourt la liste.
 
455
        gchar *cPackageName, *cDate, *cDisplayedName, *cName, *cAuthor;
 
456
        CairoDockPackage *pPackage;
 
457
        CairoDockPackageType iType;
 
458
        double fSize;
 
459
        int iCreationDate, iLastModifDate, iLocalDate, iSobriety, iCategory;
 
460
        int last_modif, creation_date;
 
461
        guint i;
 
462
        for (i = 0; i < length; i ++)
 
463
        {
 
464
                cPackageName = pGroupList[i];
 
465
                iCreationDate = g_key_file_get_integer (pKeyFile, cPackageName, "creation", NULL);
 
466
                iLastModifDate = g_key_file_get_integer (pKeyFile, cPackageName, "last modif", NULL);
 
467
                iSobriety = g_key_file_get_integer (pKeyFile, cPackageName, "sobriety", NULL);
 
468
                iCategory = g_key_file_get_integer (pKeyFile, cPackageName, "category", NULL);
 
469
                fSize = g_key_file_get_double (pKeyFile, cPackageName, "size", NULL);
 
470
                cAuthor = g_key_file_get_string (pKeyFile, cPackageName, "author", NULL);
 
471
                if (cAuthor && *cAuthor == '\0')
 
472
                {
 
473
                        g_free (cAuthor);
 
474
                        cAuthor = NULL;
 
475
                }
 
476
                cName = NULL;
 
477
                if (g_key_file_has_key (pKeyFile, cPackageName, "name", NULL))
 
478
                {
 
479
                        cName = g_key_file_get_string (pKeyFile, cPackageName, "name", NULL);
 
480
                }
 
481
                
 
482
                // creation < 30j && pas sur le disque -> new
 
483
                // sinon last modif < 30j && last use < last modif -> updated
 
484
                // sinon -> net
 
485
                
 
486
                // on surcharge les packages locaux en cas de nouvelle version.
 
487
                CairoDockPackage *pSamePackage = g_hash_table_lookup (pPackageTable, cPackageName);
 
488
                if (pSamePackage != NULL)  // le package existe en local.
 
489
                {
 
490
                        // on regarde de quand date cette version locale.
 
491
                        gchar *cVersionFile = g_strdup_printf ("%s/last-modif", pSamePackage->cPackagePath);
 
492
                        gsize length = 0;
 
493
                        gchar *cContent = NULL;
 
494
                        g_file_get_contents (cVersionFile,
 
495
                                &cContent,
 
496
                                &length,
 
497
                                NULL);
 
498
                        if (cContent == NULL)  // le package n'a pas encore de fichier de date
 
499
                        {
 
500
                                // on ne peut pas savoir quand l'utilisateur a mis a jour le package pour la derniere fois;
 
501
                                // on va supposer que l'on ne met pas a jour ses packages tres regulierement, donc il est probable qu'il l'ait fait il y'a au moins 1 mois.
 
502
                                // de cette facon, les packages mis a jour recemment (il y'a moins d'1 mois) apparaitront "updated".
 
503
                                if (month > 1)
 
504
                                        iLocalDate = day + (month - 1) * 1e2 + year * 1e4;
 
505
                                else
 
506
                                        iLocalDate = day + 12 * 1e2 + (year - 1) * 1e4;
 
507
                                cDate = g_strdup_printf ("%d", iLocalDate);
 
508
                                g_file_set_contents (cVersionFile,
 
509
                                        cDate,
 
510
                                        -1,
 
511
                                        NULL);
 
512
                                g_free (cDate);
 
513
                        }
 
514
                        else
 
515
                                iLocalDate = atoi (cContent);
 
516
                        g_free (cContent);
 
517
                        g_free (cVersionFile);
 
518
                        
 
519
                        
 
520
                        if (iLocalDate < iLastModifDate)  // la copie locale est plus ancienne.
 
521
                        {
 
522
                                iType = CAIRO_DOCK_UPDATED_PACKAGE;
 
523
                        }
 
524
                        else  // c'est deja la derniere version disponible, on en reste la.
 
525
                        {
 
526
                                pSamePackage->iSobriety = iSobriety;  // par contre on en profite pour renseigner la sobriete.
 
527
                                g_free (pSamePackage->cDisplayedName);
 
528
                                pSamePackage->cDisplayedName = g_strdup_printf ("%s by %s", cName ? cName : cPackageName, (cAuthor ? cAuthor : "---"));
 
529
                                pSamePackage->cAuthor = cAuthor;
 
530
                                g_free (cName);
 
531
                                g_free (cPackageName);
 
532
                                continue;
 
533
                        }
 
534
                        
 
535
                        pPackage = pSamePackage;
 
536
                        g_free (pPackage->cPackagePath);
 
537
                        g_free (pPackage->cAuthor);
 
538
                        g_free (pPackage->cDisplayedName);
 
539
                }
 
540
                else  // package encore jamais telecharge.
 
541
                {
 
542
                        last_modif = _convert_date (iLastModifDate);
 
543
                        creation_date = _convert_date (iCreationDate);
 
544
                        
 
545
                        if (now - creation_date < 30)  // les packages restent nouveaux pendant 1 mois.
 
546
                                iType = CAIRO_DOCK_NEW_PACKAGE;
 
547
                        else if (now - last_modif < 30)  // les packages restent mis a jour pendant 1 mois.
 
548
                                iType = CAIRO_DOCK_UPDATED_PACKAGE;
 
549
                        else
 
550
                                iType = CAIRO_DOCK_DISTANT_PACKAGE;
 
551
                        
 
552
                        pPackage = g_new0 (CairoDockPackage, 1);
 
553
                        g_hash_table_insert (pPackageTable, cPackageName, pPackage);
 
554
                        pPackage->iRating = g_key_file_get_integer (pKeyFile, cPackageName, "rating", NULL);  // par contre on affiche la note que l'utilisateur avait precedemment etablie.
 
555
                }
 
556
                
 
557
                pPackage->cPackagePath = g_strdup_printf ("%s/%s/%s", cServerAdress, cDirectory, cPackageName);
 
558
                pPackage->iType = iType;
 
559
                pPackage->fSize = fSize;
 
560
                pPackage->cAuthor = cAuthor;
 
561
                pPackage->cDisplayedName = g_strdup_printf ("%s by %s [%.2f MB]", cName ? cName : cPackageName, (cAuthor ? cAuthor : "---"), fSize);
 
562
                pPackage->iSobriety = iSobriety;
 
563
                pPackage->iCategory = iCategory;
 
564
                pPackage->iCreationDate = iCreationDate;
 
565
                pPackage->iLastModifDate = iLastModifDate;
 
566
        }
 
567
        g_free (pGroupList);  // les noms des packages sont desormais dans la hash-table.
 
568
}
 
569
GHashTable *cairo_dock_list_net_packages (const gchar *cServerAdress, const gchar *cDirectory, const gchar *cListFileName, GHashTable *hProvidedTable, GError **erreur)
 
570
{
 
571
        g_return_val_if_fail (cServerAdress != NULL && *cServerAdress != '\0', hProvidedTable);
 
572
        cd_message ("listing net packages on %s/%s ...", cServerAdress, cDirectory);
 
573
        
 
574
        // On recupere la liste des packages distants.
 
575
        GError *tmp_erreur = NULL;
 
576
        gchar *cContent = cairo_dock_get_distant_file_content (cServerAdress, cDirectory, cListFileName, &tmp_erreur);
 
577
        if (tmp_erreur != NULL)
 
578
        {
 
579
                cd_warning ("couldn't retrieve packages on %s (check that your connection is alive, or retry later)", cServerAdress);
 
580
                g_propagate_error (erreur, tmp_erreur);
 
581
                return hProvidedTable;
 
582
        }
 
583
        
 
584
        // on verifie son integrite.
 
585
        if (cContent == NULL || strncmp (cContent, "#!CD", 4) != 0)  // avec une connexion wifi etablie sur un operateur auquel on ne s'est pas logue, il peut nous renvoyer des messages au lieu de juste rien. On filtre ca par un entete dedie.
 
586
        {
 
587
                cd_warning ("empty packages list on %s (check that your connection is alive, or retry later)", cServerAdress);
 
588
                g_set_error (erreur, 1, 1, "empty packages list on %s", cServerAdress);
 
589
                g_free (cContent);
 
590
                return hProvidedTable;
 
591
        }
 
592
        
 
593
        // on charge la liste dans un fichier de cles.
 
594
        GKeyFile *pKeyFile = g_key_file_new ();
 
595
        g_key_file_load_from_data (pKeyFile,
 
596
                cContent,
 
597
                -1,
 
598
                G_KEY_FILE_NONE,
 
599
                &tmp_erreur);
 
600
        g_free (cContent);
 
601
        if (tmp_erreur != NULL)
 
602
        {
 
603
                cd_warning ("invalid list of packages (%s)\n(check that your connection is alive, or retry later)", cServerAdress);
 
604
                g_propagate_error (erreur, tmp_erreur);
 
605
                g_key_file_free (pKeyFile);
 
606
                return hProvidedTable;
 
607
        }
 
608
        
 
609
        // on parse la liste dans une table de hashage.
 
610
        GHashTable *pPackageTable = (hProvidedTable != NULL ? hProvidedTable : g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) cairo_dock_free_package));
 
611
        
 
612
        _cairo_dock_parse_package_list (pKeyFile, cServerAdress, cDirectory, pPackageTable);
 
613
        
 
614
        g_key_file_free (pKeyFile);
 
615
        
 
616
        return pPackageTable;
 
617
}
 
618
 
 
619
GHashTable *cairo_dock_list_packages (const gchar *cSharePackagesDir, const gchar *cUserPackagesDir, const gchar *cDistantPackagesDir)
 
620
{
 
621
        cd_message ("%s (%s, %s, %s)", __func__, cSharePackagesDir, cUserPackagesDir, cDistantPackagesDir);
 
622
        GError *erreur = NULL;
 
623
        GHashTable *pPackageTable = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) cairo_dock_free_package);
 
624
        
 
625
        //\______________ On recupere les packages pre-installes.
 
626
        if (cSharePackagesDir != NULL)
 
627
                pPackageTable = cairo_dock_list_local_packages (cSharePackagesDir, pPackageTable, cDistantPackagesDir != NULL, &erreur);
 
628
        if (erreur != NULL)
 
629
        {
 
630
                cd_warning ("while listing pre-installed packages in '%s' : %s", cSharePackagesDir, erreur->message);
 
631
                g_error_free (erreur);
 
632
                erreur = NULL;
 
633
        }
 
634
        
 
635
        //\______________ On recupere les packages utilisateurs (qui ecrasent donc les precedents).
 
636
        if (cUserPackagesDir != NULL)
 
637
                pPackageTable = cairo_dock_list_local_packages (cUserPackagesDir, pPackageTable, cDistantPackagesDir != NULL, &erreur);
 
638
        if (erreur != NULL)
 
639
        {
 
640
                cd_warning ("while listing user packages in '%s' : %s", cSharePackagesDir, erreur->message);
 
641
                g_error_free (erreur);
 
642
                erreur = NULL;
 
643
        }
 
644
        
 
645
        //\______________ On recupere les packages distants (qui surchargent tous les packages).
 
646
        if (cDistantPackagesDir != NULL && s_cPackageServerAdress)
 
647
        {
 
648
                pPackageTable = cairo_dock_list_net_packages (s_cPackageServerAdress, cDistantPackagesDir, CAIRO_DOCK_DEFAULT_PACKAGES_LIST_FILE, pPackageTable, &erreur);
 
649
                if (erreur != NULL)
 
650
                {
 
651
                        cd_warning ("while listing distant packages in '%s/%s' : %s", s_cPackageServerAdress, cDistantPackagesDir, erreur->message);
 
652
                        g_error_free (erreur);
 
653
                        erreur = NULL;
 
654
                }
 
655
        }
 
656
        
 
657
        return pPackageTable;
 
658
}
 
659
 
 
660
static void _list_packages (gpointer *pSharedMemory)
 
661
{
 
662
        pSharedMemory[5] = cairo_dock_list_packages (pSharedMemory[0], pSharedMemory[1], pSharedMemory[2]);
 
663
}
 
664
static gboolean _finish_list_packages (gpointer *pSharedMemory)
 
665
{
 
666
        if (pSharedMemory[5] == NULL)
 
667
                cd_warning ("couldn't get distant packages in '%s'", pSharedMemory[2]);
 
668
        
 
669
        GFunc pCallback = pSharedMemory[3];
 
670
        pCallback (pSharedMemory[5], pSharedMemory[4]);
 
671
        return TRUE;
 
672
}
 
673
static void _discard_list_packages (gpointer *pSharedMemory)
 
674
{
 
675
        g_free (pSharedMemory[0]);
 
676
        g_free (pSharedMemory[1]);
 
677
        g_free (pSharedMemory[2]);
 
678
        if (pSharedMemory[5] != NULL)
 
679
                g_hash_table_unref (pSharedMemory[5]);
 
680
        g_free (pSharedMemory);
 
681
}
 
682
CairoDockTask *cairo_dock_list_packages_async (const gchar *cSharePackagesDir, const gchar *cUserPackagesDir, const gchar *cDistantPackagesDir, CairoDockGetPackagesFunc pCallback, gpointer data)
 
683
{
 
684
        gpointer *pSharedMemory = g_new0 (gpointer, 6);
 
685
        pSharedMemory[0] = g_strdup (cSharePackagesDir);
 
686
        pSharedMemory[1] = g_strdup (cUserPackagesDir);
 
687
        pSharedMemory[2] = g_strdup (cDistantPackagesDir);
 
688
        pSharedMemory[3] = pCallback;
 
689
        pSharedMemory[4] = data;
 
690
        CairoDockTask *pTask = cairo_dock_new_task_full (0, (CairoDockGetDataAsyncFunc) _list_packages, (CairoDockUpdateSyncFunc) _finish_list_packages, (GFreeFunc) _discard_list_packages, pSharedMemory);
 
691
        cairo_dock_launch_task (pTask);
 
692
        return pTask;
 
693
}
 
694
 
 
695
gchar *cairo_dock_get_package_path (const gchar *cPackageName, const gchar *cSharePackagesDir, const gchar *cUserPackagesDir, const gchar *cDistantPackagesDir, CairoDockPackageType iGivenType)
 
696
{
 
697
        cd_message ("%s (%s, %s, %s)", __func__, cSharePackagesDir, cUserPackagesDir, cDistantPackagesDir);
 
698
        if (cPackageName == NULL || *cPackageName == '\0')
 
699
                return NULL;
 
700
        CairoDockPackageType iType = cairo_dock_extract_package_type_from_name (cPackageName);  // juste au cas ou, mais normalement c'est plutot a l'appelant d'extraire le type de theme.
 
701
        if (iType == CAIRO_DOCK_ANY_PACKAGE)
 
702
                iType = iGivenType;
 
703
        gchar *cPackagePath = NULL;
 
704
        
 
705
        //g_print ("iType : %d\n", iType);
 
706
        if (cUserPackagesDir != NULL && /*iType != CAIRO_DOCK_DISTANT_PACKAGE && iType != CAIRO_DOCK_NEW_PACKAGE && */iType != CAIRO_DOCK_UPDATED_PACKAGE)
 
707
        {
 
708
                cPackagePath = g_strdup_printf ("%s/%s", cUserPackagesDir, cPackageName);
 
709
                
 
710
                if (g_file_test (cPackagePath, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
 
711
                {
 
712
                        return cPackagePath;
 
713
                }
 
714
                
 
715
                g_free (cPackagePath);
 
716
                cPackagePath = NULL;
 
717
        }
 
718
        
 
719
        if (cSharePackagesDir != NULL && iType != CAIRO_DOCK_UPDATED_PACKAGE)
 
720
        {
 
721
                cPackagePath = g_strdup_printf ("%s/%s", cSharePackagesDir, cPackageName);
 
722
                if (g_file_test (cPackagePath, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
 
723
                        return cPackagePath;
 
724
                g_free (cPackagePath);
 
725
                cPackagePath = NULL;
 
726
        }
 
727
        
 
728
        if (cDistantPackagesDir != NULL && s_cPackageServerAdress)
 
729
        {
 
730
                gchar *cDistantFileName = g_strdup_printf ("%s/%s.tar.gz", cPackageName, cPackageName);
 
731
                GError *erreur = NULL;
 
732
                cPackagePath = cairo_dock_download_file (s_cPackageServerAdress, cDistantPackagesDir, cDistantFileName, cUserPackagesDir, &erreur);
 
733
                g_free (cDistantFileName);
 
734
                if (erreur != NULL)
 
735
                {
 
736
                        cd_warning ("couldn't retrieve distant package %s : %s" , cPackageName, erreur->message);
 
737
                        g_error_free (erreur);
 
738
                }
 
739
                else  // on se souvient de la date a laquelle on a mis a jour le package pour la derniere fois.
 
740
                {
 
741
                        gchar *cVersionFile = g_strdup_printf ("%s/last-modif", cPackagePath);
 
742
                        time_t epoch = (time_t) time (NULL);
 
743
                        struct tm currentTime;
 
744
                        localtime_r (&epoch, &currentTime);
 
745
                        int now = (currentTime.tm_mday+1) + (currentTime.tm_mon+1) * 1e2 + (1900+currentTime.tm_year) * 1e4;
 
746
                        gchar *cDate = g_strdup_printf ("%d", now);
 
747
                        g_file_set_contents (cVersionFile,
 
748
                                cDate,
 
749
                                -1,
 
750
                                NULL);
 
751
                        g_free (cDate);
 
752
                        g_free (cVersionFile);
 
753
                }
 
754
        }
 
755
        
 
756
        cd_debug (" ====> cPackagePath : %s", cPackagePath);
 
757
        return cPackagePath;
 
758
}
 
759
 
 
760
 
 
761
CairoDockPackageType cairo_dock_extract_package_type_from_name (const gchar *cPackageName)
 
762
{
 
763
        if (cPackageName == NULL)
 
764
                return CAIRO_DOCK_ANY_PACKAGE;
 
765
        CairoDockPackageType iType = CAIRO_DOCK_ANY_PACKAGE;
 
766
        int l = strlen (cPackageName);
 
767
        if (cPackageName[l-1] == ']')
 
768
        {
 
769
                gchar *str = strrchr (cPackageName, '[');
 
770
                if (str != NULL && g_ascii_isdigit (*(str+1)))
 
771
                {
 
772
                        iType = atoi (str+1);
 
773
                        *str = '\0';
 
774
                }
 
775
        }
 
776
        return iType;
 
777
}
 
778
 
 
779
#define _check_dir(cDirPath) \
 
780
        if (! g_file_test (cDirPath, G_FILE_TEST_IS_DIR)) {\
 
781
                if (g_mkdir (cDirPath, 7*8*8+7*8+7) != 0) {\
 
782
                        cd_warning ("couldn't create directory %s", cDirPath);\
 
783
                        g_free (cDirPath);\
 
784
                        cDirPath = NULL; } }
 
785
 
 
786
void cairo_dock_init_package_manager (gchar *cPackageServerAdress)
 
787
{
 
788
        s_cPackageServerAdress = cPackageServerAdress;
 
789
        
 
790
        //\___________________ On initialise le gestionnaire de download.
 
791
        curl_global_init (CURL_GLOBAL_DEFAULT);
 
792
}