~ubuntu-branches/debian/experimental/gupnp/experimental

« back to all changes in this revision

Viewing changes to libgupnp/xdgmime/xdgmime.c

  • Committer: Bazaar Package Importer
  • Author(s): Ross Burton
  • Date: 2008-06-30 09:32:18 UTC
  • mfrom: (1.2.1 upstream) (2.1.5 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080630093218-vmb4elru8cn18579
Tags: 0.12.1-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- mode: C; c-file-style: "gnu" -*- */
2
 
/* xdgmime.c: XDG Mime Spec mime resolver.  Based on version 0.11 of the spec.
3
 
 *
4
 
 * More info can be found at http://www.freedesktop.org/standards/
5
 
 * 
6
 
 * Copyright (C) 2003,2004  Red Hat, Inc.
7
 
 * Copyright (C) 2003,2004  Jonathan Blandford <jrb@alum.mit.edu>
8
 
 *
9
 
 * Licensed under the Academic Free License version 2.0
10
 
 * Or under the following terms:
11
 
 * 
12
 
 * This library is free software; you can redistribute it and/or
13
 
 * modify it under the terms of the GNU Lesser General Public
14
 
 * License as published by the Free Software Foundation; either
15
 
 * version 2 of the License, or (at your option) any later version.
16
 
 *
17
 
 * This library is distributed in the hope that it will be useful,
18
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20
 
 * Lesser General Public License for more details.
21
 
 *
22
 
 * You should have received a copy of the GNU Lesser General Public
23
 
 * License along with this library; if not, write to the
24
 
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25
 
 * Boston, MA 02111-1307, USA.
26
 
 */
27
 
 
28
 
#ifdef HAVE_CONFIG_H
29
 
#include <config.h>
30
 
#endif
31
 
 
32
 
#include "xdgmime.h"
33
 
#include "xdgmimeint.h"
34
 
#include "xdgmimeglob.h"
35
 
#include "xdgmimemagic.h"
36
 
#include "xdgmimealias.h"
37
 
#include "xdgmimeparent.h"
38
 
#include "xdgmimecache.h"
39
 
#include <stdio.h>
40
 
#include <string.h>
41
 
#include <sys/stat.h>
42
 
#include <sys/types.h>
43
 
#include <sys/time.h>
44
 
#include <unistd.h>
45
 
#include <assert.h>
46
 
 
47
 
typedef struct XdgDirTimeList XdgDirTimeList;
48
 
typedef struct XdgCallbackList XdgCallbackList;
49
 
 
50
 
static int need_reread = TRUE;
51
 
static time_t last_stat_time = 0;
52
 
 
53
 
static XdgGlobHash *global_hash = NULL;
54
 
static XdgMimeMagic *global_magic = NULL;
55
 
static XdgAliasList *alias_list = NULL;
56
 
static XdgParentList *parent_list = NULL;
57
 
static XdgDirTimeList *dir_time_list = NULL;
58
 
static XdgCallbackList *callback_list = NULL;
59
 
 
60
 
XdgMimeCache **_xdg_mime_caches = NULL;
61
 
static int n_caches = 0;
62
 
 
63
 
const char xdg_mime_type_unknown[] = "application/octet-stream";
64
 
 
65
 
 
66
 
enum
67
 
{
68
 
  XDG_CHECKED_UNCHECKED,
69
 
  XDG_CHECKED_VALID,
70
 
  XDG_CHECKED_INVALID
71
 
};
72
 
 
73
 
struct XdgDirTimeList
74
 
{
75
 
  time_t mtime;
76
 
  char *directory_name;
77
 
  int checked;
78
 
  XdgDirTimeList *next;
79
 
  XdgMimeCache *cache;
80
 
};
81
 
 
82
 
struct XdgCallbackList
83
 
{
84
 
  XdgCallbackList *next;
85
 
  XdgCallbackList *prev;
86
 
  int              callback_id;
87
 
  XdgMimeCallback  callback;
88
 
  void            *data;
89
 
  XdgMimeDestroy   destroy;
90
 
};
91
 
 
92
 
/* Function called by xdg_run_command_on_dirs.  If it returns TRUE, further
93
 
 * directories aren't looked at */
94
 
typedef int (*XdgDirectoryFunc) (const char *directory,
95
 
                                 void       *user_data);
96
 
 
97
 
static XdgDirTimeList *
98
 
xdg_dir_time_list_new (void)
99
 
{
100
 
  XdgDirTimeList *retval;
101
 
 
102
 
  retval = calloc (1, sizeof (XdgDirTimeList));
103
 
  retval->checked = XDG_CHECKED_UNCHECKED;
104
 
 
105
 
  return retval;
106
 
}
107
 
 
108
 
static void
109
 
xdg_dir_time_list_free (XdgDirTimeList *list)
110
 
{
111
 
  XdgDirTimeList *next;
112
 
 
113
 
  while (list)
114
 
    {
115
 
      next = list->next;
116
 
      free (list->directory_name);
117
 
      free (list);
118
 
      list = next;
119
 
    }
120
 
}
121
 
 
122
 
static int
123
 
xdg_mime_init_from_directory (const char *directory)
124
 
{
125
 
  char *file_name;
126
 
  struct stat st;
127
 
  XdgDirTimeList *list;
128
 
 
129
 
  assert (directory != NULL);
130
 
 
131
 
  file_name = malloc (strlen (directory) + strlen ("/mime/mime.cache") + 1);
132
 
  strcpy (file_name, directory); strcat (file_name, "/mime/mime.cache");
133
 
  if (stat (file_name, &st) == 0)
134
 
    {
135
 
      XdgMimeCache *cache = _xdg_mime_cache_new_from_file (file_name);
136
 
 
137
 
      if (cache != NULL)
138
 
        {
139
 
          list = xdg_dir_time_list_new ();
140
 
          list->directory_name = file_name;
141
 
          list->mtime = st.st_mtime;
142
 
          list->next = dir_time_list;
143
 
          list->cache = cache;
144
 
          dir_time_list = list;
145
 
 
146
 
          _xdg_mime_caches = realloc (_xdg_mime_caches, sizeof (XdgMimeCache *) * (n_caches + 2));
147
 
          _xdg_mime_caches[n_caches] = cache;
148
 
          _xdg_mime_caches[n_caches + 1] = NULL;
149
 
          n_caches++;
150
 
 
151
 
          return FALSE;
152
 
        }
153
 
    }
154
 
  free (file_name);
155
 
 
156
 
  file_name = malloc (strlen (directory) + strlen ("/mime/globs") + 1);
157
 
  strcpy (file_name, directory); strcat (file_name, "/mime/globs");
158
 
  if (stat (file_name, &st) == 0)
159
 
    {
160
 
      _xdg_mime_glob_read_from_file (global_hash, file_name);
161
 
 
162
 
      list = xdg_dir_time_list_new ();
163
 
      list->directory_name = file_name;
164
 
      list->mtime = st.st_mtime;
165
 
      list->next = dir_time_list;
166
 
      dir_time_list = list;
167
 
    }
168
 
  else
169
 
    {
170
 
      free (file_name);
171
 
    }
172
 
 
173
 
  file_name = malloc (strlen (directory) + strlen ("/mime/magic") + 1);
174
 
  strcpy (file_name, directory); strcat (file_name, "/mime/magic");
175
 
  if (stat (file_name, &st) == 0)
176
 
    {
177
 
      _xdg_mime_magic_read_from_file (global_magic, file_name);
178
 
 
179
 
      list = xdg_dir_time_list_new ();
180
 
      list->directory_name = file_name;
181
 
      list->mtime = st.st_mtime;
182
 
      list->next = dir_time_list;
183
 
      dir_time_list = list;
184
 
    }
185
 
  else
186
 
    {
187
 
      free (file_name);
188
 
    }
189
 
 
190
 
  file_name = malloc (strlen (directory) + strlen ("/mime/aliases") + 1);
191
 
  strcpy (file_name, directory); strcat (file_name, "/mime/aliases");
192
 
  _xdg_mime_alias_read_from_file (alias_list, file_name);
193
 
  free (file_name);
194
 
 
195
 
  file_name = malloc (strlen (directory) + strlen ("/mime/subclasses") + 1);
196
 
  strcpy (file_name, directory); strcat (file_name, "/mime/subclasses");
197
 
  _xdg_mime_parent_read_from_file (parent_list, file_name);
198
 
  free (file_name);
199
 
 
200
 
  return FALSE; /* Keep processing */
201
 
}
202
 
 
203
 
/* Runs a command on all the directories in the search path */
204
 
static void
205
 
xdg_run_command_on_dirs (XdgDirectoryFunc  func,
206
 
                         void             *user_data)
207
 
{
208
 
  const char *xdg_data_home;
209
 
  const char *xdg_data_dirs;
210
 
  const char *ptr;
211
 
 
212
 
  xdg_data_home = getenv ("XDG_DATA_HOME");
213
 
  if (xdg_data_home)
214
 
    {
215
 
      if ((func) (xdg_data_home, user_data))
216
 
        return;
217
 
    }
218
 
  else
219
 
    {
220
 
      const char *home;
221
 
 
222
 
      home = getenv ("HOME");
223
 
      if (home != NULL)
224
 
        {
225
 
          char *guessed_xdg_home;
226
 
          int stop_processing;
227
 
 
228
 
          guessed_xdg_home = malloc (strlen (home) + strlen ("/.local/share/") + 1);
229
 
          strcpy (guessed_xdg_home, home);
230
 
          strcat (guessed_xdg_home, "/.local/share/");
231
 
          stop_processing = (func) (guessed_xdg_home, user_data);
232
 
          free (guessed_xdg_home);
233
 
 
234
 
          if (stop_processing)
235
 
            return;
236
 
        }
237
 
    }
238
 
 
239
 
  xdg_data_dirs = getenv ("XDG_DATA_DIRS");
240
 
  if (xdg_data_dirs == NULL)
241
 
    xdg_data_dirs = "/usr/local/share/:/usr/share/";
242
 
 
243
 
  ptr = xdg_data_dirs;
244
 
 
245
 
  while (*ptr != '\000')
246
 
    {
247
 
      const char *end_ptr;
248
 
      char *dir;
249
 
      int len;
250
 
      int stop_processing;
251
 
 
252
 
      end_ptr = ptr;
253
 
      while (*end_ptr != ':' && *end_ptr != '\000')
254
 
        end_ptr ++;
255
 
 
256
 
      if (end_ptr == ptr)
257
 
        {
258
 
          ptr++;
259
 
          continue;
260
 
        }
261
 
 
262
 
      if (*end_ptr == ':')
263
 
        len = end_ptr - ptr;
264
 
      else
265
 
        len = end_ptr - ptr + 1;
266
 
      dir = malloc (len + 1);
267
 
      strncpy (dir, ptr, len);
268
 
      dir[len] = '\0';
269
 
      stop_processing = (func) (dir, user_data);
270
 
      free (dir);
271
 
 
272
 
      if (stop_processing)
273
 
        return;
274
 
 
275
 
      ptr = end_ptr;
276
 
    }
277
 
}
278
 
 
279
 
static XdgMimeCache *
280
 
xdg_lookup_cache_for_file (const char *file_path)
281
 
{
282
 
  XdgDirTimeList *list;
283
 
 
284
 
  for (list = dir_time_list; list; list = list->next)
285
 
      if (! strcmp (list->directory_name, file_path))
286
 
         return list->cache;
287
 
 
288
 
  return NULL;
289
 
}
290
 
 
291
 
/* Checks file_path to make sure it has the same mtime as last time it was
292
 
 * checked.  If it has a different mtime, or if the file doesn't exist, it
293
 
 * returns FALSE.
294
 
 *
295
 
 * FIXME: This doesn't protect against permission changes.
296
 
 */
297
 
static int
298
 
xdg_check_file (const char *file_path)
299
 
{
300
 
  struct stat st;
301
 
 
302
 
  /* If the file exists */
303
 
  if (stat (file_path, &st) == 0)
304
 
    {
305
 
      XdgDirTimeList *list;
306
 
 
307
 
      for (list = dir_time_list; list; list = list->next)
308
 
        {
309
 
          if (! strcmp (list->directory_name, file_path) &&
310
 
              st.st_mtime == list->mtime)
311
 
            {
312
 
              if (list->checked == XDG_CHECKED_UNCHECKED)
313
 
                list->checked = XDG_CHECKED_VALID;
314
 
              else if (list->checked == XDG_CHECKED_VALID)
315
 
                list->checked = XDG_CHECKED_INVALID;
316
 
 
317
 
              return (list->checked != XDG_CHECKED_VALID);
318
 
            }
319
 
        }
320
 
      return TRUE;
321
 
    }
322
 
 
323
 
  return FALSE;
324
 
}
325
 
 
326
 
static int
327
 
xdg_check_dir (const char *directory,
328
 
               int        *invalid_dir_list)
329
 
{
330
 
  int invalid, has_cache;
331
 
  char *file_name;
332
 
 
333
 
  assert (directory != NULL);
334
 
 
335
 
  /* Check the mime.cache file */
336
 
  file_name = malloc (strlen (directory) + strlen ("/mime/mime.cache") + 1);
337
 
  strcpy (file_name, directory); strcat (file_name, "/mime/mime.cache");
338
 
  invalid = xdg_check_file (file_name);
339
 
  has_cache = xdg_lookup_cache_for_file (file_name) != NULL;
340
 
  free (file_name);
341
 
 
342
 
  if (has_cache)
343
 
    {
344
 
      if (invalid)
345
 
        {
346
 
          *invalid_dir_list = TRUE;
347
 
          return TRUE;
348
 
        }
349
 
 
350
 
      return FALSE;
351
 
    }
352
 
 
353
 
  /* Check the globs file */
354
 
  file_name = malloc (strlen (directory) + strlen ("/mime/globs") + 1);
355
 
  strcpy (file_name, directory); strcat (file_name, "/mime/globs");
356
 
  invalid = xdg_check_file (file_name);
357
 
  free (file_name);
358
 
  if (invalid)
359
 
    {
360
 
      *invalid_dir_list = TRUE;
361
 
      return TRUE;
362
 
    }
363
 
 
364
 
  /* Check the magic file */
365
 
  file_name = malloc (strlen (directory) + strlen ("/mime/magic") + 1);
366
 
  strcpy (file_name, directory); strcat (file_name, "/mime/magic");
367
 
  invalid = xdg_check_file (file_name);
368
 
  free (file_name);
369
 
  if (invalid)
370
 
    {
371
 
      *invalid_dir_list = TRUE;
372
 
      return TRUE;
373
 
    }
374
 
 
375
 
  return FALSE; /* Keep processing */
376
 
}
377
 
 
378
 
/* Walks through all the mime files stat()ing them to see if they've changed.
379
 
 * Returns TRUE if they have. */
380
 
static int
381
 
xdg_check_dirs (void)
382
 
{
383
 
  XdgDirTimeList *list;
384
 
  int invalid_dir_list = FALSE;
385
 
 
386
 
  for (list = dir_time_list; list; list = list->next)
387
 
    list->checked = XDG_CHECKED_UNCHECKED;
388
 
 
389
 
  xdg_run_command_on_dirs ((XdgDirectoryFunc) xdg_check_dir,
390
 
                           &invalid_dir_list);
391
 
 
392
 
  if (invalid_dir_list)
393
 
    return TRUE;
394
 
 
395
 
  for (list = dir_time_list; list; list = list->next)
396
 
    {
397
 
      if (list->checked != XDG_CHECKED_VALID)
398
 
        return TRUE;
399
 
    }
400
 
 
401
 
  return FALSE;
402
 
}
403
 
 
404
 
/* We want to avoid stat()ing on every single mime call, so we only look for
405
 
 * newer files every 5 seconds.  This will return TRUE if we need to reread the
406
 
 * mime data from disk.
407
 
 */
408
 
static int
409
 
xdg_check_time_and_dirs (void)
410
 
{
411
 
  struct timeval tv;
412
 
  time_t current_time;
413
 
  int retval = FALSE;
414
 
 
415
 
  gettimeofday (&tv, NULL);
416
 
  current_time = tv.tv_sec;
417
 
 
418
 
  if (current_time >= last_stat_time + 5)
419
 
    {
420
 
      retval = xdg_check_dirs ();
421
 
      last_stat_time = current_time;
422
 
    }
423
 
 
424
 
  return retval;
425
 
}
426
 
 
427
 
/* Called in every public function.  It reloads the hash function if need be.
428
 
 */
429
 
static void
430
 
xdg_mime_init (void)
431
 
{
432
 
  if (xdg_check_time_and_dirs ())
433
 
    {
434
 
      xdg_mime_shutdown ();
435
 
    }
436
 
 
437
 
  if (need_reread)
438
 
    {
439
 
      global_hash = _xdg_glob_hash_new ();
440
 
      global_magic = _xdg_mime_magic_new ();
441
 
      alias_list = _xdg_mime_alias_list_new ();
442
 
      parent_list = _xdg_mime_parent_list_new ();
443
 
 
444
 
      xdg_run_command_on_dirs ((XdgDirectoryFunc) xdg_mime_init_from_directory,
445
 
                               NULL);
446
 
 
447
 
      need_reread = FALSE;
448
 
    }
449
 
}
450
 
 
451
 
const char *
452
 
xdg_mime_get_mime_type_for_data (const void *data,
453
 
                                 size_t      len)
454
 
{
455
 
  const char *mime_type;
456
 
 
457
 
  xdg_mime_init ();
458
 
 
459
 
  if (_xdg_mime_caches)
460
 
    return _xdg_mime_cache_get_mime_type_for_data (data, len);
461
 
 
462
 
  mime_type = _xdg_mime_magic_lookup_data (global_magic, data, len, NULL, 0);
463
 
 
464
 
  if (mime_type)
465
 
    return mime_type;
466
 
 
467
 
  return XDG_MIME_TYPE_UNKNOWN;
468
 
}
469
 
 
470
 
const char *
471
 
xdg_mime_get_mime_type_for_file (const char  *file_name,
472
 
                                 struct stat *statbuf)
473
 
{
474
 
  const char *mime_type;
475
 
  /* Used to detect whether multiple MIME types match file_name */
476
 
  const char *mime_types[2];
477
 
  FILE *file;
478
 
  unsigned char *data;
479
 
  int max_extent;
480
 
  int bytes_read;
481
 
  struct stat buf;
482
 
  const char *base_name;
483
 
  int n;
484
 
 
485
 
  if (file_name == NULL)
486
 
    return NULL;
487
 
  if (! _xdg_utf8_validate (file_name))
488
 
    return NULL;
489
 
 
490
 
  xdg_mime_init ();
491
 
 
492
 
  if (_xdg_mime_caches)
493
 
    return _xdg_mime_cache_get_mime_type_for_file (file_name, statbuf);
494
 
 
495
 
  base_name = _xdg_get_base_name (file_name);
496
 
  n = _xdg_glob_hash_lookup_file_name (global_hash, base_name, mime_types, 2);
497
 
 
498
 
  if (n == 1)
499
 
    return mime_types[0];
500
 
 
501
 
  if (!statbuf)
502
 
    {
503
 
      if (stat (file_name, &buf) != 0)
504
 
        return XDG_MIME_TYPE_UNKNOWN;
505
 
 
506
 
      statbuf = &buf;
507
 
    }
508
 
 
509
 
  if (!S_ISREG (statbuf->st_mode))
510
 
    return XDG_MIME_TYPE_UNKNOWN;
511
 
 
512
 
  /* FIXME: Need to make sure that max_extent isn't totally broken.  This could
513
 
   * be large and need getting from a stream instead of just reading it all
514
 
   * in. */
515
 
  max_extent = _xdg_mime_magic_get_buffer_extents (global_magic);
516
 
  data = malloc (max_extent);
517
 
  if (data == NULL)
518
 
    return XDG_MIME_TYPE_UNKNOWN;
519
 
        
520
 
  file = fopen (file_name, "r");
521
 
  if (file == NULL)
522
 
    {
523
 
      free (data);
524
 
      return XDG_MIME_TYPE_UNKNOWN;
525
 
    }
526
 
 
527
 
  bytes_read = fread (data, 1, max_extent, file);
528
 
  if (ferror (file))
529
 
    {
530
 
      free (data);
531
 
      fclose (file);
532
 
      return XDG_MIME_TYPE_UNKNOWN;
533
 
    }
534
 
 
535
 
  mime_type = _xdg_mime_magic_lookup_data (global_magic, data, bytes_read,
536
 
                                           mime_types, n);
537
 
 
538
 
  free (data);
539
 
  fclose (file);
540
 
 
541
 
  if (mime_type)
542
 
    return mime_type;
543
 
 
544
 
  return XDG_MIME_TYPE_UNKNOWN;
545
 
}
546
 
 
547
 
const char *
548
 
xdg_mime_get_mime_type_from_file_name (const char *file_name)
549
 
{
550
 
  const char *mime_types[2];
551
 
 
552
 
  xdg_mime_init ();
553
 
 
554
 
  if (_xdg_mime_caches)
555
 
    return _xdg_mime_cache_get_mime_type_from_file_name (file_name);
556
 
 
557
 
  if (_xdg_glob_hash_lookup_file_name (global_hash, file_name, mime_types, 2) == 1)
558
 
    return mime_types[0];
559
 
  else
560
 
    return XDG_MIME_TYPE_UNKNOWN;
561
 
}
562
 
 
563
 
int
564
 
xdg_mime_is_valid_mime_type (const char *mime_type)
565
 
{
566
 
  /* FIXME: We should make this a better test
567
 
   */
568
 
  return _xdg_utf8_validate (mime_type);
569
 
}
570
 
 
571
 
void
572
 
xdg_mime_shutdown (void)
573
 
{
574
 
  XdgCallbackList *list;
575
 
 
576
 
  /* FIXME: Need to make this (and the whole library) thread safe */
577
 
  if (dir_time_list)
578
 
    {
579
 
      xdg_dir_time_list_free (dir_time_list);
580
 
      dir_time_list = NULL;
581
 
    }
582
 
        
583
 
  if (global_hash)
584
 
    {
585
 
      _xdg_glob_hash_free (global_hash);
586
 
      global_hash = NULL;
587
 
    }
588
 
  if (global_magic)
589
 
    {
590
 
      _xdg_mime_magic_free (global_magic);
591
 
      global_magic = NULL;
592
 
    }
593
 
 
594
 
  if (alias_list)
595
 
    {
596
 
      _xdg_mime_alias_list_free (alias_list);
597
 
      alias_list = NULL;
598
 
    }
599
 
 
600
 
  if (parent_list)
601
 
    {
602
 
      _xdg_mime_parent_list_free (parent_list);
603
 
      parent_list = NULL;
604
 
    }
605
 
 
606
 
  if (_xdg_mime_caches)
607
 
    {
608
 
      int i;
609
 
      for (i = 0; i < n_caches; i++)
610
 
        _xdg_mime_cache_unref (_xdg_mime_caches[i]);
611
 
      free (_xdg_mime_caches);
612
 
      _xdg_mime_caches = NULL;
613
 
      n_caches = 0;
614
 
    }
615
 
 
616
 
  for (list = callback_list; list; list = list->next)
617
 
    (list->callback) (list->data);
618
 
 
619
 
  need_reread = TRUE;
620
 
}
621
 
 
622
 
int
623
 
xdg_mime_get_max_buffer_extents (void)
624
 
{
625
 
  xdg_mime_init ();
626
 
  
627
 
  if (_xdg_mime_caches)
628
 
    return _xdg_mime_cache_get_max_buffer_extents ();
629
 
 
630
 
  return _xdg_mime_magic_get_buffer_extents (global_magic);
631
 
}
632
 
 
633
 
static const char *
634
 
_xdg_mime_unalias_mime_type (const char *mime_type)
635
 
{
636
 
  const char *lookup;
637
 
 
638
 
  if (_xdg_mime_caches)
639
 
    return _xdg_mime_cache_unalias_mime_type (mime_type);
640
 
 
641
 
  if ((lookup = _xdg_mime_alias_list_lookup (alias_list, mime_type)) != NULL)
642
 
    return lookup;
643
 
 
644
 
  return mime_type;
645
 
}
646
 
 
647
 
const char *
648
 
xdg_mime_unalias_mime_type (const char *mime_type)
649
 
{
650
 
  xdg_mime_init ();
651
 
 
652
 
  return _xdg_mime_unalias_mime_type (mime_type);
653
 
}
654
 
 
655
 
int
656
 
_xdg_mime_mime_type_equal (const char *mime_a,
657
 
                           const char *mime_b)
658
 
{
659
 
  const char *unalias_a, *unalias_b;
660
 
 
661
 
  unalias_a = _xdg_mime_unalias_mime_type (mime_a);
662
 
  unalias_b = _xdg_mime_unalias_mime_type (mime_b);
663
 
 
664
 
  if (strcmp (unalias_a, unalias_b) == 0)
665
 
    return 1;
666
 
 
667
 
  return 0;
668
 
}
669
 
 
670
 
int
671
 
xdg_mime_mime_type_equal (const char *mime_a,
672
 
                          const char *mime_b)
673
 
{
674
 
  xdg_mime_init ();
675
 
 
676
 
  return _xdg_mime_mime_type_equal (mime_a, mime_b);
677
 
}
678
 
 
679
 
int
680
 
_xdg_mime_media_type_equal (const char *mime_a,
681
 
                            const char *mime_b)
682
 
{
683
 
  char *sep;
684
 
 
685
 
  xdg_mime_init ();
686
 
 
687
 
  sep = strchr (mime_a, '/');
688
 
  
689
 
  if (sep && strncmp (mime_a, mime_b, sep - mime_a + 1) == 0)
690
 
    return 1;
691
 
 
692
 
  return 0;
693
 
}
694
 
 
695
 
int
696
 
xdg_mime_media_type_equal (const char *mime_a,
697
 
                           const char *mime_b)
698
 
{
699
 
  xdg_mime_init ();
700
 
 
701
 
  return _xdg_mime_media_type_equal (mime_a, mime_b);
702
 
}
703
 
 
704
 
#if 0
705
 
static int
706
 
xdg_mime_is_super_type (const char *mime)
707
 
{
708
 
  int length;
709
 
  const char *type;
710
 
 
711
 
  length = strlen (mime);
712
 
  type = &(mime[length - 2]);
713
 
 
714
 
  if (strcmp (type, "/*") == 0)
715
 
    return 1;
716
 
 
717
 
  return 0;
718
 
}
719
 
#endif
720
 
 
721
 
int
722
 
_xdg_mime_mime_type_subclass (const char *mime,
723
 
                              const char *base)
724
 
{
725
 
  const char *umime, *ubase;
726
 
  const char **parents;
727
 
 
728
 
  if (_xdg_mime_caches)
729
 
    return _xdg_mime_cache_mime_type_subclass (mime, base);
730
 
 
731
 
  umime = _xdg_mime_unalias_mime_type (mime);
732
 
  ubase = _xdg_mime_unalias_mime_type (base);
733
 
 
734
 
  if (strcmp (umime, ubase) == 0)
735
 
    return 1;
736
 
 
737
 
#if 0  
738
 
  /* Handle supertypes */
739
 
  if (xdg_mime_is_super_type (ubase) &&
740
 
      _xdg_mime_media_type_equal (umime, ubase))
741
 
    return 1;
742
 
#endif
743
 
 
744
 
  /*  Handle special cases text/plain and application/octet-stream */
745
 
  if (strcmp (ubase, "text/plain") == 0 && 
746
 
      strncmp (umime, "text/", 5) == 0)
747
 
    return 1;
748
 
 
749
 
  if (strcmp (ubase, "application/octet-stream") == 0)
750
 
    return 1;
751
 
  
752
 
  parents = _xdg_mime_parent_list_lookup (parent_list, umime);
753
 
  for (; parents && *parents; parents++)
754
 
    {
755
 
      if (_xdg_mime_mime_type_subclass (*parents, ubase))
756
 
        return 1;
757
 
    }
758
 
 
759
 
  return 0;
760
 
}
761
 
 
762
 
int
763
 
xdg_mime_mime_type_subclass (const char *mime,
764
 
                             const char *base)
765
 
{
766
 
  xdg_mime_init ();
767
 
 
768
 
  return _xdg_mime_mime_type_subclass (mime, base);
769
 
}
770
 
 
771
 
char **
772
 
xdg_mime_list_mime_parents (const char *mime)
773
 
{
774
 
  const char **parents;
775
 
  char **result;
776
 
  int i, n;
777
 
 
778
 
  if (_xdg_mime_caches)
779
 
    return _xdg_mime_cache_list_mime_parents (mime);
780
 
 
781
 
  parents = xdg_mime_get_mime_parents (mime);
782
 
 
783
 
  if (!parents)
784
 
    return NULL;
785
 
 
786
 
  for (i = 0; parents[i]; i++) ;
787
 
  
788
 
  n = (i + 1) * sizeof (char *);
789
 
  result = (char **) malloc (n);
790
 
  memcpy (result, parents, n);
791
 
 
792
 
  return result;
793
 
}
794
 
 
795
 
const char **
796
 
xdg_mime_get_mime_parents (const char *mime)
797
 
{
798
 
  const char *umime;
799
 
 
800
 
  xdg_mime_init ();
801
 
 
802
 
  umime = _xdg_mime_unalias_mime_type (mime);
803
 
 
804
 
  return _xdg_mime_parent_list_lookup (parent_list, umime);
805
 
}
806
 
 
807
 
void 
808
 
xdg_mime_dump (void)
809
 
{
810
 
  printf ("*** ALIASES ***\n\n");
811
 
  _xdg_mime_alias_list_dump (alias_list);
812
 
  printf ("\n*** PARENTS ***\n\n");
813
 
  _xdg_mime_parent_list_dump (parent_list);
814
 
  printf ("\n*** CACHE ***\n\n");
815
 
  _xdg_glob_hash_dump (global_hash);
816
 
}
817
 
 
818
 
 
819
 
/* Registers a function to be called every time the mime database reloads its files
820
 
 */
821
 
int
822
 
xdg_mime_register_reload_callback (XdgMimeCallback  callback,
823
 
                                   void            *data,
824
 
                                   XdgMimeDestroy   destroy)
825
 
{
826
 
  XdgCallbackList *list_el;
827
 
  static int callback_id = 1;
828
 
 
829
 
  /* Make a new list element */
830
 
  list_el = calloc (1, sizeof (XdgCallbackList));
831
 
  list_el->callback_id = callback_id;
832
 
  list_el->callback = callback;
833
 
  list_el->data = data;
834
 
  list_el->destroy = destroy;
835
 
  list_el->next = callback_list;
836
 
  if (list_el->next)
837
 
    list_el->next->prev = list_el;
838
 
 
839
 
  callback_list = list_el;
840
 
  callback_id ++;
841
 
 
842
 
  return callback_id - 1;
843
 
}
844
 
 
845
 
void
846
 
xdg_mime_remove_callback (int callback_id)
847
 
{
848
 
  XdgCallbackList *list;
849
 
 
850
 
  for (list = callback_list; list; list = list->next)
851
 
    {
852
 
      if (list->callback_id == callback_id)
853
 
        {
854
 
          if (list->next)
855
 
            list->next = list->prev;
856
 
 
857
 
          if (list->prev)
858
 
            list->prev->next = list->next;
859
 
          else
860
 
            callback_list = list->next;
861
 
 
862
 
          /* invoke the destroy handler */
863
 
          (list->destroy) (list->data);
864
 
          free (list);
865
 
          return;
866
 
        }
867
 
    }
868
 
}