~ubuntu-branches/ubuntu/hoary/liferea/hoary

« back to all changes in this revision

Viewing changes to src/favicon.c

  • Committer: Bazaar Package Importer
  • Author(s): David Moreno Garza
  • Date: 2005-01-30 23:35:05 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20050130233505-bo2qi2x3r9u9i5c2
Tags: 0.9.0b-1
* New upstream release (Closes: #292705).
* Remembers now the sorting order after an upgrade (Closes: #281715).
* Shows date info on the condensed view (Closes: #276040).
* Taking every information item on OPML feeds (Closes: #254148).
* Corrected hang on kicker restart (Closes: #281622).
* Removed filter unread headlines feature (Closes: #279064).

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/**
2
 
 * @file ico2xpm.c -- Convert icons to pixmaps
3
 
 * Copyright (C) 1998 Philippe Martin
4
 
 * Modified by Brion Vibber
 
2
 * @file favicon.c Liferea favicon handling
5
3
 * 
6
 
 * Modified to be suitable for Liferea
7
 
 * Copyright (C) 2003 Lars Lindner <lars.lindner@gmx.net>
 
4
 * Copyright (C) 2004 Nathan J. Conrad <t98502@users.sourceforge.net>
8
5
 *
9
6
 * This program is free software; you can redistribute it and/or modify
10
7
 * it under the terms of the GNU General Public License as published by
26
23
#endif
27
24
 
28
25
#include <glib.h>
 
26
#include <sys/types.h>
29
27
#include <sys/stat.h>
30
28
#include <unistd.h>
31
29
#include <stdio.h>
32
30
#include <string.h>
 
31
#include <time.h>
33
32
 
34
33
#include "favicon.h"
35
34
#include "support.h"
36
35
#include "feed.h"
37
36
#include "common.h"
38
37
#include "update.h"
39
 
#include "net/netio.h"
40
38
#include "debug.h"
41
 
 
42
 
#ifdef STDC_HEADERS
43
 
#include <stdlib.h>
44
 
#endif
45
 
 
46
 
/* The maximum number of icons we'll try to handle in any one file */
47
 
#define MAXICONS 32
48
 
 
49
 
/* Header of a single icon image in an icon file */
50
 
typedef struct IconDirectoryEntry {
51
 
        unsigned char  bWidth;
52
 
        unsigned char  bHeight;
53
 
        unsigned char  bColorCount;
54
 
        unsigned char  bReserved;
55
 
        unsigned short  wPlanes;
56
 
        unsigned short  wBitCount;
57
 
        unsigned long  dwBytesInRes;
58
 
        unsigned long  dwImageOffset;
59
 
} ICONDIRENTRY;
60
 
 
61
 
/* Header of an icon file */
62
 
typedef struct ICONDIR {
63
 
         unsigned short          idReserved;
64
 
         unsigned short          idType;
65
 
         unsigned short          idCount;
66
 
/*    ICONDIRENTRY  idEntries[1];*/
67
 
         ICONDIRENTRY  idEntries[MAXICONS];
68
 
} ICONHEADER;
69
 
 
70
 
/* Bitmap header - this is on the images themselves */
71
 
typedef struct tagBITMAPINFOHEADER{
72
 
        unsigned long   biSize;
73
 
        long            biWidth;
74
 
        long            biHeight;
75
 
        unsigned short  biPlanes;
76
 
        unsigned short  biBitCount;
77
 
        unsigned long   biCompression;
78
 
        unsigned long   biSizeImage;
79
 
        long            biXPelsPerMeter;
80
 
        long            biYPelsPerMeter;
81
 
        unsigned long   biClrUsed;
82
 
        unsigned long   biClrImportant;
83
 
} BITMAPINFOHEADER;
84
 
 
85
 
/* Magic number for an icon file */
86
 
/* This is the the idReserved and idType fields of the header */
87
 
static char ico_magic_number[4] = {0, 0, 1, 0};
88
 
 
89
 
static int do_verbose = 0;
90
 
 
91
 
/* void convert __P((void)); */
92
 
 
93
 
/* For keeping track of which icon image we're on */
94
 
static unsigned short whichimage = 0;
95
 
 
96
 
/*
97
 
 * Conversion
98
 
 */
99
 
 
100
 
#define XPM_HEAD "/* XPM */\n\
101
 
static char *pixmap[] = {\n\
102
 
/* width height ncols cpp */\n\
103
 
\"%d %d %d 2\",\n  /* Colors */\n"
104
 
 
105
 
/* The smallest number of double words containing c bytes */
106
 
#define DWORD_ALIGN_BYTES(b) (((b) / 4) + (((b) % 4 > 0) ? 1 : 0))
107
 
 
108
 
/* The smallest number of double words containing c bits */
109
 
#define DWORD_ALIGN_BITS(b) (((b) / 32) + (((b) % 32 > 0) ? 1 : 0))
110
 
 
111
 
/* The different possible number of colors */
112
 
#define LOW_COLOR 16
113
 
#define HIGH_COLOR 0
114
 
/*#define NCOLORS (color_level == LOW_COLOR ? 16 : 256)*/
115
 
#define NCOLORS ncolors
116
 
 
117
 
/* The color index of a pixel in the icon colormap */
118
 
#define PIXEL_INDEX(x,y) \
119
 
     (color_level == LOW_COLOR \
120
 
      ? ((x) % 2 == 0 \
121
 
         ? (image [bytes_per_line * (height - 1 - (y)) / 2 + (x) / 2] & 0xF0) >> 4 \
122
 
         : image [bytes_per_line * (height - 1 - (y)) / 2 + (x) / 2] & 0x0F) \
123
 
      : image [bytes_per_line * (height - 1 - (y)) + (x)])
124
 
     
125
 
/* The color index of a pixel in the (reduced) pixmap colormap */
126
 
#define PIXEL_REDUCED_INDEX(x,y) \
127
 
     (reduced_colormap_index [PIXEL_INDEX((x),(y))])
128
 
  
129
 
/* The RGB value of a colormap entry */
130
 
#define INDEX_VALUE(index,c) (colormap[(c) + (index) * 4])
131
 
#define INDEX_R_VALUE(index) (INDEX_VALUE((index), 2))
132
 
#define INDEX_G_VALUE(index) (INDEX_VALUE((index), 1))
133
 
#define INDEX_B_VALUE(index) (INDEX_VALUE((index), 0))
134
 
  
135
 
/* The transparency of a pixel */
136
 
#define MASK_BYTE(x,y) (bytes_per_mask_line * (height - 1 - (y)) + (x) / 8)
137
 
#define MASK_BIT(x,y) (7 - (x) % 8)
138
 
#define IS_TRANSPARENT(x,y) \
139
 
     (mask[MASK_BYTE((x),(y))] & (1 << MASK_BIT((x),(y))))
140
 
 
141
 
static FILE *xpm_stream; 
142
 
 
143
 
/* Values read from icon file */
144
 
static ICONHEADER iconheader;
145
 
static BITMAPINFOHEADER bitmapinfoheader;
146
 
/*static unsigned char magic_number [sizeof(ico_magic_number)];*/
147
 
static unsigned char *magic_number;
148
 
static unsigned char color_level;
149
 
static unsigned char colormap[256 * 4];
150
 
static unsigned char image[256 * 256];
151
 
static unsigned char mask[256 * 32];
152
 
 
153
 
/* Different variables computed from the read ones */
154
 
static unsigned ncolors;
155
 
static unsigned char width;
156
 
static unsigned char height;
157
 
static unsigned char bytes_per_line;
158
 
static unsigned char bytes_per_mask_line;
159
 
static int image_length;
160
 
static int mask_length;
161
 
static int i, x, y;
162
 
 
163
 
/* Variables for the reduced colormap */
164
 
static int color_used[256];
165
 
static int nb_color_used;
166
 
static unsigned char reduced_colormap_index [256];
167
 
 
168
 
/* Does the icon have transparent pixels ? */
169
 
static int have_transparent_pixels;
170
 
 
171
 
 
172
 
/* function reads the data of a MS Windows .ICO file referenced by 
173
 
   icondata with length datalen, converts the image into XPM 
174
 
   format and saves the result in the file outputfile. If the 
175
 
   conversion is successful TRUE is returned. */
176
 
static gboolean
177
 
convert_favicon_to_XPM(gchar *outputfile, unsigned char *icondata, int datalen)
178
 
{
179
 
  int offset = 0;
180
 
 
181
 
  /* Check the magic number & header */
182
 
  /*fread (magic_number, 1, sizeof(ico_magic_number), ico_stream);*/
183
 
  //fread (&iconheader, 1, 6/*sizeof(unsigned short)*3*/, ico_stream);
184
 
  memcpy(&iconheader, icondata, 6);
185
 
  offset += 6;
186
 
  magic_number = (unsigned char *)&iconheader;
187
 
  for (i = 0 ; i < sizeof(ico_magic_number) ; i ++)
188
 
    {    
189
 
      if (magic_number [i] != ico_magic_number [i])
190
 
        {
191
 
          g_warning("favicon.ico data is not a recognized icon file.\n");
192
 
          return FALSE;
193
 
        }
194
 
    }
195
 
  
196
 
  /* Output some stats */
197
 
  if (do_verbose)
198
 
    g_print("favicon.ico data contains %d icon images\n", GUINT16_FROM_LE(iconheader.idCount));
199
 
 
200
 
  /* Read in the rest of the icon directory entries */
201
 
  //fread(&iconheader.idEntries[0],iconheader.idCount,
202
 
  //  /*sizeof(ICONDIRENTRY)*/16,ico_stream);
203
 
  memcpy(&iconheader.idEntries[0], icondata + offset, GUINT16_FROM_LE(iconheader.idCount)*16);
204
 
  offset += GUINT16_FROM_LE(iconheader.idCount)*16;
205
 
  
206
 
  /* Cycle through each icon image */
207
 
  for(whichimage = 0; whichimage < GUINT16_FROM_LE(iconheader.idCount); whichimage++) {
208
 
    // * For debugging
209
 
    if(do_verbose) {
210
 
      g_print("(%d) identry: %d %d %d %d %d %d %d %d\n",
211
 
        whichimage,
212
 
        (int)iconheader.idEntries[whichimage].bWidth,
213
 
        (int)iconheader.idEntries[whichimage].bHeight,
214
 
        (int)iconheader.idEntries[whichimage].bColorCount,
215
 
        (int)iconheader.idEntries[whichimage].bReserved,
216
 
        (int)GUINT16_FROM_LE(iconheader.idEntries[whichimage].wPlanes),
217
 
        (int)GUINT16_FROM_LE(iconheader.idEntries[whichimage].wBitCount),
218
 
        (int)GULONG_FROM_LE(iconheader.idEntries[whichimage].dwBytesInRes),
219
 
        (int)GULONG_FROM_LE(iconheader.idEntries[whichimage].dwImageOffset));
220
 
    }
221
 
    //*/
222
 
    
223
 
    /* Update the output file name */
224
 
    
225
 
 
226
 
    /* Read the icon size */
227
 
    width = iconheader.idEntries[whichimage].bWidth;
228
 
    height = iconheader.idEntries[whichimage].bWidth;
229
 
 
230
 
    /* Determine the number of bytes defining a line of the icon. */
231
 
    bytes_per_line = 4 * DWORD_ALIGN_BYTES (width);
232
 
    bytes_per_mask_line = 4 * DWORD_ALIGN_BITS (width);
233
 
 
234
 
    /* Let's surf on over to the bitmap image & read the BMIH. */
235
 
    //fseek (ico_stream, GULONG_FROM_LEiconheader.idEntries[whichimage].dwImageOffset),SEEK_SET);
236
 
    //fread (&bitmapinfoheader, 1, sizeof(bitmapinfoheader), ico_stream);
237
 
    offset = GULONG_FROM_LE(iconheader.idEntries[whichimage].dwImageOffset);
238
 
    memcpy(&bitmapinfoheader, icondata + offset, sizeof(bitmapinfoheader));
239
 
 
240
 
    // * For debugging
241
 
    if(do_verbose) {
242
 
      g_print("(%d) bmih: %d %d %d %d %d %d %d %d %d %d %d\n",
243
 
        whichimage,
244
 
        (int)GULONG_FROM_LE(bitmapinfoheader.biSize),
245
 
        (int)GLONG_FROM_LE(bitmapinfoheader.biWidth),
246
 
        (int)GLONG_FROM_LE(bitmapinfoheader.biHeight),
247
 
        (int)GUINT16_FROM_LE(bitmapinfoheader.biPlanes),
248
 
        (int)GUINT16_FROM_LE(bitmapinfoheader.biBitCount),
249
 
        (int)GULONG_FROM_LE(bitmapinfoheader.biCompression),
250
 
        (int)GULONG_FROM_LE(bitmapinfoheader.biSizeImage),
251
 
        (int)GLONG_FROM_LE(bitmapinfoheader.biXPelsPerMeter),
252
 
        (int)GLONG_FROM_LE(bitmapinfoheader.biYPelsPerMeter),
253
 
        (int)GULONG_FROM_LE(bitmapinfoheader.biClrUsed),
254
 
        (int)GULONG_FROM_LE(bitmapinfoheader.biClrImportant));
255
 
    }//*/
256
 
    
257
 
    /* Read the number of colors.
258
 
     * TODO: add support for monochrome, 24-bit icons
259
 
     */
260
 
    switch(GUINT16_FROM_LE(bitmapinfoheader.biPlanes)
261
 
         * GUINT16_FROM_LE(bitmapinfoheader.biBitCount)) {
262
 
      case 4: /* 2^4 = 14 */ color_level = LOW_COLOR; break;
263
 
      case 8: /* 2^8 = 256 */ color_level = HIGH_COLOR; break;
264
 
      default:
265
 
        g_warning("Unsupported number of colors in favicon.ico image! Skipping. (%d planes, %d bpp)\n",
266
 
          (int)GUINT16_FROM_LE(bitmapinfoheader.biPlanes),
267
 
          (int)GUINT16_FROM_LE(bitmapinfoheader.biBitCount));
268
 
        continue;
269
 
    }
270
 
    
271
 
    /* Read the colormap */
272
 
    if(GULONG_FROM_LE(bitmapinfoheader.biClrImportant) != 0)
273
 
      ncolors = GULONG_FROM_LE(bitmapinfoheader.biClrImportant);
274
 
    else if(GULONG_FROM_LE(bitmapinfoheader.biClrUsed) != 0)
275
 
      ncolors = GULONG_FROM_LE(bitmapinfoheader.biClrUsed);
276
 
    else
277
 
      ncolors = 1 << (GUINT16_FROM_LE(bitmapinfoheader.biPlanes)*GUINT16_FROM_LE(bitmapinfoheader.biBitCount));
278
 
 
279
 
    /*fseek (ico_stream, iconheader.idEntries[whichimage].dwImageOffset
280
 
      + bitmapinfoheader.biSize, SEEK_SET);
281
 
    fread (colormap, 1,ncolors * 4, ico_stream);*/
282
 
    offset += GULONG_FROM_LE(bitmapinfoheader.biSize);
283
 
    memcpy(&colormap, icondata + offset, ncolors*4);
284
 
    offset += ncolors*4;
285
 
 
286
 
    /* Read the image */
287
 
    if (color_level == LOW_COLOR)
288
 
        image_length = bytes_per_line * height / 2;
289
 
    else
290
 
        image_length = bytes_per_line * height;
291
 
    /*fread (image, 1, image_length, ico_stream);*/
292
 
    memcpy(&image, icondata + offset, image_length);
293
 
    offset += image_length;
294
 
 
295
 
    /* Read the mask */
296
 
    mask_length = bytes_per_mask_line * height;
297
 
    /*fread (mask, 1, mask_length, ico_stream);*/
298
 
    memcpy(&mask, icondata + offset, mask_length);
299
 
    offset += mask_length;
300
 
 
301
 
    /* Read error / prematured EOF  occured ? */
302
 
    if((mask + mask_length) > (icondata + datalen))
303
 
      g_warning("Premature end of favicon.ico data.\n");
304
 
    /*if (ferror (ico_stream))
305
 
      fprintf (stderr, "%s: %s: Read error.\n",
306
 
             program_name, input_file);*/
307
 
    /*if (feof (ico_stream) || ferror (ico_stream))
308
 
      {
309
 
        fclose (ico_stream);
310
 
        return;
311
 
      }*/
312
 
 
313
 
    /* Reduce the number of colors */
314
 
    for (i = 0 ; i < ncolors ; i++)
315
 
      color_used [i] = 0;
316
 
  
317
 
    for (y = 0 ; y <height ; y++)
318
 
      for (x = 0 ; x < width ; x++)
319
 
        color_used [PIXEL_INDEX(x,y)] = 1;
320
 
  
321
 
    nb_color_used = 0;
322
 
    for (i = 0 ; i < ncolors ; i++)
323
 
      if (color_used [i])
324
 
        reduced_colormap_index[i] = nb_color_used ++;
325
 
 
326
 
    /* Check for at least one transparent pixel */
327
 
    have_transparent_pixels = 0;
328
 
    for (y=0; y<height && have_transparent_pixels == 0 ; y++)
329
 
      for (x=0; x<width; x++)
330
 
        if (IS_TRANSPARENT(x,y))
331
 
          {
332
 
            have_transparent_pixels = 1;
333
 
            break;
334
 
          }
335
 
  
336
 
    /*
337
 
     * Write the pixmap file
338
 
     */
339
 
    if ((xpm_stream = fopen (outputfile, "w")) == NULL)
340
 
      {
341
 
        perror (outputfile);    // FIXME: use glib
342
 
        return FALSE;
343
 
      }
344
 
 
345
 
    /* Write the header */
346
 
    fprintf (xpm_stream, XPM_HEAD, 
347
 
             width, height, 
348
 
             nb_color_used + have_transparent_pixels);
349
 
 
350
 
    /* Write the colors */
351
 
    x = 0;
352
 
    for (i=0; i<NCOLORS; i++)
353
 
      {
354
 
        if (color_used [i])
355
 
          {
356
 
            fprintf (xpm_stream, "  \"%.2X c #%.2X%.2X%.2X\",\n", x++, 
357
 
                    INDEX_R_VALUE(i), INDEX_G_VALUE(i), INDEX_B_VALUE(i));
358
 
          }
359
 
      }
360
 
    if (have_transparent_pixels)
361
 
      fprintf (xpm_stream, "  \".. s None c None\",\n");
362
 
 
363
 
    /* Write the image */
364
 
    for (y=0; y<height; y++)
365
 
      {
366
 
        fprintf (xpm_stream, "  \"");
367
 
        for (x=0; x<width; x++)
368
 
          {
369
 
            if (IS_TRANSPARENT(x,y))
370
 
              fprintf (xpm_stream, "..");
371
 
            else
372
 
              fprintf (xpm_stream, "%.2X", PIXEL_REDUCED_INDEX(x,y));
373
 
          }
374
 
        fprintf (xpm_stream, "\",\n");
375
 
      }
376
 
    fprintf (xpm_stream, "};\n");
377
 
 
378
 
    /* Write error occured ? */
379
 
    if (ferror (xpm_stream))
380
 
        g_warning("Error writing %s.\n", outputfile);
381
 
  
382
 
    fclose (xpm_stream);
383
 
  
384
 
    /* Write info about xpm file written */
385
 
    if (do_verbose)
386
 
        g_print("Wrote %s %dx%dx%d (%d)\n",
387
 
               outputfile, width, height,
388
 
               nb_color_used, NCOLORS);
389
 
        
390
 
    /* we intentionally return after the first retrieved pixmap */       
391
 
    return TRUE;
392
 
  }
393
 
  return FALSE;
394
 
}
395
 
 
396
 
/* Liferea specific wrapper functions */
 
39
#include "html.h"
 
40
#include "ui_feedlist.h"
 
41
#include "ui_mainwindow.h"
 
42
#include "ui_feed.h"
397
43
 
398
44
void favicon_load(feedPtr fp) {
 
45
        struct stat     statinfo;
 
46
        GTimeVal        now;
399
47
        gchar           *filename;
400
48
        GdkPixbuf       *pixbuf;
401
 
        GError *error = NULL;
 
49
        GError          *error = NULL;
402
50
        
403
51
        /* try to load a saved favicon */
404
 
        filename = common_create_cache_filename("cache" G_DIR_SEPARATOR_S "favicons",fp->id, "xpm");
405
 
 
406
 
        if(g_file_test(filename, G_FILE_TEST_EXISTS)) {
407
 
                /* remove path, because create_pixbuf allows no absolute pathnames */
408
 
                pixbuf = gdk_pixbuf_new_from_file (filename, &error);
409
 
                if (pixbuf) {
 
52
        filename = common_create_cache_filename("cache" G_DIR_SEPARATOR_S "favicons", feed_get_id(fp), "png");
 
53
        
 
54
        if(0 == stat((const char*)filename, &statinfo)) {
 
55
                pixbuf = gdk_pixbuf_new_from_file(filename, &error);
 
56
                if(pixbuf != NULL) {
 
57
                        if(fp->icon != NULL)
 
58
                                g_object_unref(fp->icon);
410
59
                        fp->icon = gdk_pixbuf_scale_simple(pixbuf, 16, 16, GDK_INTERP_BILINEAR);
411
60
                        g_object_unref(pixbuf);
412
61
                } else { /* Error */
413
 
                        fprintf (stderr, "Failed to load pixbuf file: %s: %s\n",
414
 
                                    filename, error->message);
415
 
                        g_error_free (error);
 
62
                        fprintf(stderr, "Failed to load pixbuf file: %s: %s\n",
 
63
                                filename, error->message);
 
64
                        g_error_free(error);
416
65
                }
417
66
                
 
67
                /* check creation date and update favicon if older than one month */
 
68
                g_get_current_time(&now);
 
69
                if(now.tv_sec > statinfo.st_mtime + 60*60*24*31) {
 
70
                        debug1(DEBUG_UPDATE, "updating favicon %s\n", filename);
 
71
                        favicon_download(fp);
 
72
                }
418
73
        }
419
 
        g_free(filename);
 
74
        g_free(filename);       
420
75
}
421
76
 
422
77
void favicon_remove(feedPtr fp) {
423
78
        gchar           *filename;
424
79
        
425
80
        /* try to load a saved favicon */
426
 
        filename = common_create_cache_filename( "cache" G_DIR_SEPARATOR_S "favicons", fp->id, "xpm");
 
81
        filename = common_create_cache_filename( "cache" G_DIR_SEPARATOR_S "favicons", feed_get_id(fp), "png");
427
82
        if(g_file_test(filename, G_FILE_TEST_EXISTS)) {
428
 
                if(0 != unlink(filename)) {
429
 
                        g_warning(_("Could not delete icon file %s! Please remove manually!"), filename);
430
 
                }       
 
83
                if(0 != unlink(filename))
 
84
                        /* What can we do? The file probably doesn't exist. Or permissions are wrong. Oh well.... */;
431
85
        }
432
86
        g_free(filename);
433
87
}
434
88
 
435
 
void favicon_download(feedPtr fp) {
436
 
        unsigned char           *icodata;
437
 
        gchar                   *baseurl;
 
89
/*
 
90
 * This code tries to download a series of files. If there are no
 
91
 * favicons, this will make four downloads, two of which will be 404
 
92
 * errors. Hopefully this will not cause any webservers pain because
 
93
 * this code should be run only once a month per feed.
 
94
 *
 
95
 * Flag states: (stored in request->flags)
 
96
 *
 
97
 * 0 <-- downloading HTML of the feed url
 
98
 * 1 <-- downloading favicon from the feed url HTML
 
99
 * 2 <-- downloading HTML of root of webserver
 
100
 * 3 <-- downloading favicon from the root HTML
 
101
 * 4 <-- downloading favicon from directory of RSS feed
 
102
 * 5 <-- downloading favicon from root of webserver
 
103
 */
 
104
 
 
105
static void favicon_download_request_favicon_cb(struct request *request);
 
106
static void favicon_download_html(feedPtr fp, int phase);
 
107
 
 
108
static void favicon_download_5(feedPtr fp) {
 
109
        gchar *baseurl, *tmp;
 
110
        struct request *request;
 
111
        
 
112
        baseurl = g_strdup(feed_get_source(fp));
 
113
        if(NULL != (tmp = strstr(baseurl, "://"))) {
 
114
                tmp += 3;
 
115
                if(NULL != (tmp = strchr(tmp, '/'))) {
 
116
                        *tmp = 0;
 
117
                        request = download_request_new(NULL);
 
118
                        request->source = g_strdup_printf("%s/favicon.ico", baseurl);
 
119
                        
 
120
                        request->callback = &favicon_download_request_favicon_cb;
 
121
                        request->user_data = fp;
 
122
                        request->flags = 5;
 
123
                        fp->otherRequests = g_slist_append(fp->otherRequests, request);
 
124
                        
 
125
                        debug1(DEBUG_UPDATE, "trying to download server root favicon.ico for \"%s\"\n", request->source);
 
126
                        
 
127
                        download_queue(request);
 
128
                }
 
129
        }
 
130
        g_free(baseurl);
 
131
}
 
132
 
 
133
static void favicon_download_4(feedPtr fp) {
 
134
        gchar *baseurl, *tmp;
 
135
        struct request *request;
 
136
        
 
137
        baseurl = g_strdup(feed_get_source(fp));
 
138
        if(NULL != (tmp = strstr(baseurl, "://"))) {
 
139
                tmp += 3;
 
140
                if(NULL != (tmp = strrchr(tmp, '/'))) {
 
141
                        *tmp = 0;
 
142
                        
 
143
                        request = download_request_new(NULL);
 
144
                        request->source = g_strdup_printf("%s/favicon.ico", baseurl);
 
145
                        request->callback = &favicon_download_request_favicon_cb;
 
146
                        request->user_data = fp;
 
147
                        request->flags = 4;
 
148
                        fp->otherRequests = g_slist_append(fp->otherRequests, request);
 
149
                        
 
150
                        debug1(DEBUG_UPDATE, "trying to download favicon.ico for \"%s\"\n", request->source);
 
151
                        
 
152
                        download_queue(request);
 
153
                }
 
154
        }
 
155
        g_free(baseurl);
 
156
}
 
157
 
 
158
static void favicon_download_request_favicon_cb(struct request *request) {
 
159
        feedPtr         fp = (feedPtr)request->user_data;
 
160
        gchar           *tmp;
 
161
        gboolean        success = FALSE;
 
162
        
 
163
        debug2(DEBUG_UPDATE, "icon download processing (%s, %d bytes)", request->source, request->size);
 
164
        fp->otherRequests = g_slist_remove(fp->otherRequests, request);
 
165
        
 
166
        if(NULL != request->data && request->size > 0) {
 
167
                GdkPixbufLoader *loader = gdk_pixbuf_loader_new();
 
168
                GdkPixbuf *pixbuf;
 
169
                tmp = common_create_cache_filename("cache" G_DIR_SEPARATOR_S "favicons", feed_get_id(fp), "png");
 
170
                
 
171
                if(gdk_pixbuf_loader_write(loader, request->data, request->size, NULL)) {
 
172
                        if(NULL != (pixbuf = gdk_pixbuf_loader_get_pixbuf(loader))) {
 
173
                                debug1(DEBUG_UPDATE, "saving icon as %s", tmp);
 
174
                                if(FALSE == (gdk_pixbuf_save(pixbuf, tmp, "png", NULL, NULL))) {
 
175
                                        g_warning("favicon saving error!");
 
176
                                }
 
177
                                success = TRUE;
 
178
                                favicon_load(fp);
 
179
                        }
 
180
                }
 
181
                gdk_pixbuf_loader_close(loader, NULL);
 
182
                g_object_unref(loader);
 
183
                g_free(tmp);
 
184
                ui_feed_update(fp);
 
185
        }
 
186
        
 
187
        if(!success) {
 
188
                if(request->flags == 1)
 
189
                        favicon_download_html(fp, 2);
 
190
                else if(request->flags == 3) {
 
191
                        favicon_download_4(fp);
 
192
                } else if(request->flags == 4) {
 
193
                        favicon_download_5(fp);
 
194
                }
 
195
        }
 
196
}
 
197
 
 
198
static void favicon_download_html_request_cb(struct request *request) {
 
199
        gchar *iconUri;
 
200
        struct request *request2 = NULL;
 
201
        feedPtr fp = (feedPtr)request->user_data;
 
202
        
 
203
        fp->otherRequests = g_slist_remove(fp->otherRequests, request);
 
204
                
 
205
        if (request->size > 0 && request->data != NULL) {
 
206
                iconUri = html_discover_favicon(request->data, request->source);
 
207
                if (iconUri != NULL) {
 
208
                        request2 = download_request_new(NULL);
 
209
                        request2->source = iconUri;
 
210
                        request2->callback = &favicon_download_request_favicon_cb;
 
211
                        request2->user_data = fp;
 
212
                        request2->flags++;
 
213
                        fp->otherRequests = g_slist_append(fp->otherRequests, request2);
 
214
                        download_queue(request2);
 
215
                }
 
216
        }
 
217
        if (request2 == NULL) {
 
218
                if (request->flags == 0)
 
219
                        favicon_download_html((feedPtr)request->user_data, 2);
 
220
                else /* flags == 2 */
 
221
                        favicon_download_4((feedPtr)fp);
 
222
        }
 
223
}
 
224
 
 
225
static void favicon_download_html(feedPtr fp, int phase) {
 
226
        gchar                   *htmlurl;
438
227
        gchar                   *tmp;
439
 
        struct feed_request     *request;
 
228
        struct request  *request;
440
229
        
441
230
        /* try to download favicon */
442
 
        baseurl = g_strdup(fp->source);
443
 
        if(NULL != (tmp = strstr(baseurl, "://"))) {
444
 
                tmp += 3;
445
 
                if(NULL != (tmp = strchr(tmp, '/'))) {
446
 
                        *tmp = 0;
447
 
                        
448
 
                        request = update_request_new(NULL);
449
 
                        request->feedurl = g_strdup_printf("%s/favicon.ico", baseurl);
450
 
                        debug1(DEBUG_UPDATE, "trying to download favicon.ico for \"%s\"\n", request->feedurl);
451
 
                        icodata = downloadURL(request);
452
 
                        update_request_free(request);
453
 
                        
454
 
                        if(NULL != icodata) {
455
 
                                tmp = common_create_cache_filename("cache" G_DIR_SEPARATOR_S "favicons", fp->id, "xpm");
456
 
                                        convert_favicon_to_XPM(tmp, icodata, 10000000);
457
 
                                        favicon_load(fp);
458
 
                                        g_free(tmp);
459
 
                                        g_free(icodata);
 
231
        if (phase == 0) {
 
232
                htmlurl = g_strdup(feed_get_html_url(fp));
 
233
        } else {
 
234
                htmlurl = g_strdup(feed_get_source(fp));
 
235
                if(NULL != (tmp = strstr(htmlurl, "://"))) {
 
236
                        tmp += 3;
 
237
                        /* first we try to download a favicon inside the current web path
 
238
                           if the download fails the callback will try to strip parts of
 
239
                           the URL to download a root favicon. */
 
240
                        if(NULL != (tmp = strrchr(tmp, '/'))) {
 
241
                                *tmp = 0;
460
242
                        }
461
243
                }
462
244
        }
463
 
        g_free(baseurl);
464
 
}
465
 
 
 
245
        
 
246
        request = download_request_new(NULL);
 
247
        request->source = htmlurl;
 
248
        request->callback = &favicon_download_html_request_cb;
 
249
        request->user_data = fp;
 
250
        request->flags = phase;
 
251
        fp->otherRequests = g_slist_append(fp->otherRequests, request); 
 
252
        download_queue(request);
 
253
        
 
254
        debug_exit("favicon_download");
 
255
}
 
256
 
 
257
void favicon_download(feedPtr fp) {
 
258
        
 
259
        if(FST_VFOLDER == feed_get_type(fp))
 
260
                return;
 
261
                
 
262
        debug_enter("favicon_download");
 
263
        debug1(DEBUG_UPDATE, "trying to download favicon.ico for \"%s\"\n", feed_get_title(fp));
 
264
        
 
265
        ui_mainwindow_set_status_bar(_("Updating feed icon for \"%s\""),
 
266
                                             feed_get_title(fp));
 
267
 
 
268
        g_get_current_time(&fp->lastFaviconPoll);
 
269
        
 
270
        if(feed_get_html_url(fp) != NULL) {
 
271
                favicon_download_html(fp, 0);
 
272
        } else {
 
273
                favicon_download_html(fp, 2);
 
274
        }
 
275
        
 
276
        debug_exit("favicon_download");
 
277
}