Coverage Report

Created: 2026-04-01 06:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pidgin/libpurple/core.c
Line
Count
Source
1
/**
2
 * @file core.c Purple Core API
3
 * @ingroup core
4
 */
5
6
/* purple
7
 *
8
 * Purple is the legal property of its developers, whose names are too numerous
9
 * to list here.  Please refer to the COPYRIGHT file distributed with this
10
 * source distribution.
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program 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
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111-1301  USA
25
 */
26
#include "internal.h"
27
#include "cipher.h"
28
#include "certificate.h"
29
#include "cmds.h"
30
#include "connection.h"
31
#include "conversation.h"
32
#include "core.h"
33
#include "debug.h"
34
#include "dnsquery.h"
35
#include "ft.h"
36
#include "idle.h"
37
#include "imgstore.h"
38
#include "network.h"
39
#include "notify.h"
40
#include "plugin.h"
41
#include "pounce.h"
42
#include "prefs.h"
43
#include "privacy.h"
44
#include "proxy.h"
45
#include "savedstatuses.h"
46
#include "signals.h"
47
#include "smiley.h"
48
#include "sound.h"
49
#include "sound-theme-loader.h"
50
#include "sslconn.h"
51
#include "status.h"
52
#include "stun.h"
53
#include "theme-manager.h"
54
#include "util.h"
55
56
#ifdef HAVE_DBUS
57
#  ifndef DBUS_API_SUBJECT_TO_CHANGE
58
#    define DBUS_API_SUBJECT_TO_CHANGE
59
#  endif
60
#  include <dbus/dbus.h>
61
#  include "dbus-purple.h"
62
#  include "dbus-server.h"
63
#  include "dbus-bindings.h"
64
#endif
65
66
struct PurpleCore
67
{
68
  char *ui;
69
70
  void *reserved;
71
};
72
73
static PurpleCoreUiOps *_ops  = NULL;
74
static PurpleCore      *_core = NULL;
75
76
STATIC_PROTO_INIT
77
78
gboolean
79
purple_core_init(const char *ui)
80
0
{
81
0
  PurpleCoreUiOps *ops;
82
0
  PurpleCore *core;
83
84
0
  g_return_val_if_fail(ui != NULL, FALSE);
85
0
  g_return_val_if_fail(purple_get_core() == NULL, FALSE);
86
87
0
#ifdef ENABLE_NLS
88
0
  bindtextdomain(PACKAGE, LOCALEDIR);
89
0
#endif
90
#ifdef _WIN32
91
  wpurple_init();
92
#endif
93
94
#if !GLIB_CHECK_VERSION(2, 36, 0)
95
  /* GLib type system is automaticaly initialized since 2.36. */
96
  g_type_init();
97
#endif
98
99
0
  _core = core = g_new0(PurpleCore, 1);
100
0
  core->ui = g_strdup(ui);
101
0
  core->reserved = NULL;
102
103
0
  ops = purple_core_get_ui_ops();
104
105
  /* The signals subsystem is important and should be first. */
106
0
  purple_signals_init();
107
108
0
  purple_util_init();
109
110
0
  purple_signal_register(core, "uri-handler",
111
0
    purple_marshal_BOOLEAN__POINTER_POINTER_POINTER,
112
0
    purple_value_new(PURPLE_TYPE_BOOLEAN), 3,
113
0
    purple_value_new(PURPLE_TYPE_STRING), /* Protocol */
114
0
    purple_value_new(PURPLE_TYPE_STRING), /* Command */
115
0
    purple_value_new(PURPLE_TYPE_BOXED, "GHashTable *")); /* Parameters */
116
117
0
  purple_signal_register(core, "quitting", purple_marshal_VOID, NULL, 0);
118
119
  /* The prefs subsystem needs to be initialized before static protocols
120
   * for protocol prefs to work. */
121
0
  purple_prefs_init();
122
123
0
  purple_debug_init();
124
125
0
  if (ops != NULL)
126
0
  {
127
0
    if (ops->ui_prefs_init != NULL)
128
0
      ops->ui_prefs_init();
129
130
0
    if (ops->debug_ui_init != NULL)
131
0
      ops->debug_ui_init();
132
0
  }
133
134
#ifdef HAVE_DBUS
135
  purple_dbus_init();
136
#endif
137
138
0
  purple_ciphers_init();
139
0
  purple_cmds_init();
140
141
  /* Since plugins get probed so early we should probably initialize their
142
   * subsystem right away too.
143
   */
144
0
  purple_plugins_init();
145
146
  /* Initialize all static protocols. */
147
0
  static_proto_init();
148
149
0
  purple_plugins_probe(G_MODULE_SUFFIX);
150
151
0
  purple_theme_manager_init();
152
153
  /* The buddy icon code uses the imgstore, so init it early. */
154
0
  purple_imgstore_init();
155
156
  /* Accounts use status, buddy icons and connection signals, so
157
   * initialize these before accounts
158
   */
159
0
  purple_status_init();
160
0
  purple_buddy_icons_init();
161
0
  purple_connections_init();
162
163
0
  purple_accounts_init();
164
0
  purple_savedstatuses_init();
165
0
  purple_notify_init();
166
0
  purple_certificate_init();
167
0
  purple_conversations_init();
168
0
  purple_blist_init();
169
0
  purple_log_init();
170
0
  purple_network_init();
171
0
  purple_privacy_init();
172
0
  purple_pounces_init();
173
0
  purple_proxy_init();
174
0
  purple_dnsquery_init();
175
0
  purple_sound_init();
176
0
  purple_ssl_init();
177
0
  purple_stun_init();
178
0
  purple_xfers_init();
179
0
  purple_idle_init();
180
0
  purple_smileys_init();
181
  /*
182
   * Call this early on to try to auto-detect our IP address and
183
   * hopefully save some time later.
184
   */
185
0
  purple_network_get_my_ip(-1);
186
187
0
  if (ops != NULL && ops->ui_init != NULL)
188
0
    ops->ui_init();
189
190
  /* The UI may have registered some theme types, so refresh them */
191
0
  purple_theme_manager_refresh();
192
193
0
  return TRUE;
194
0
}
195
196
void
197
purple_core_quit(void)
198
0
{
199
0
  PurpleCoreUiOps *ops;
200
0
  PurpleCore *core = purple_get_core();
201
202
0
  g_return_if_fail(core != NULL);
203
204
  /* The self destruct sequence has been initiated */
205
0
  purple_signal_emit(purple_get_core(), "quitting");
206
207
  /* Transmission ends */
208
0
  purple_connections_disconnect_all();
209
210
  /*
211
   * Certificates must be destroyed before the SSL plugins, because
212
   * PurpleCertificates contain pointers to PurpleCertificateSchemes,
213
   * and the PurpleCertificateSchemes will be unregistered when the
214
   * SSL plugin is uninit.
215
   */
216
0
  purple_certificate_uninit();
217
218
  /* The SSL plugins must be uninit before they're unloaded */
219
0
  purple_ssl_uninit();
220
221
  /* Unload all non-loader, non-prpl plugins before shutting down
222
   * subsystems. */
223
0
  purple_debug_info("main", "Unloading normal plugins\n");
224
0
  purple_plugins_unload(PURPLE_PLUGIN_STANDARD);
225
226
  /* Save .xml files, remove signals, etc. */
227
0
  purple_smileys_uninit();
228
0
  purple_idle_uninit();
229
0
  purple_pounces_uninit();
230
0
  purple_blist_uninit();
231
0
  purple_ciphers_uninit();
232
0
  purple_notify_uninit();
233
0
  purple_conversations_uninit();
234
0
  purple_connections_uninit();
235
0
  purple_buddy_icons_uninit();
236
0
  purple_savedstatuses_uninit();
237
0
  purple_status_uninit();
238
0
  purple_accounts_uninit();
239
0
  purple_sound_uninit();
240
0
  purple_theme_manager_uninit();
241
0
  purple_xfers_uninit();
242
0
  purple_proxy_uninit();
243
0
  purple_dnsquery_uninit();
244
0
  purple_imgstore_uninit();
245
0
  purple_network_uninit();
246
247
  /* Everything after unloading all plugins must not fail if prpls aren't
248
   * around */
249
0
  purple_debug_info("main", "Unloading all plugins\n");
250
0
  purple_plugins_destroy_all();
251
252
0
  ops = purple_core_get_ui_ops();
253
0
  if (ops != NULL && ops->quit != NULL)
254
0
    ops->quit();
255
256
  /* Everything after prefs_uninit must not try to read any prefs */
257
0
  purple_prefs_uninit();
258
0
  purple_plugins_uninit();
259
#ifdef HAVE_DBUS
260
  purple_dbus_uninit();
261
#endif
262
263
0
  purple_cmds_uninit();
264
  /* Everything after util_uninit cannot try to write things to the confdir */
265
0
  purple_util_uninit();
266
0
  purple_log_uninit();
267
268
0
  purple_signals_uninit();
269
270
0
  g_free(core->ui);
271
0
  g_free(core);
272
273
#ifdef _WIN32
274
  wpurple_cleanup();
275
#endif
276
277
0
  _core = NULL;
278
0
}
279
280
gboolean
281
purple_core_quit_cb(gpointer unused)
282
0
{
283
0
  purple_core_quit();
284
285
0
  return FALSE;
286
0
}
287
288
const char *
289
purple_core_get_version(void)
290
0
{
291
0
  return VERSION;
292
0
}
293
294
const char *
295
purple_core_get_ui(void)
296
0
{
297
0
  PurpleCore *core = purple_get_core();
298
299
0
  g_return_val_if_fail(core != NULL, NULL);
300
301
0
  return core->ui;
302
0
}
303
304
PurpleCore *
305
purple_get_core(void)
306
0
{
307
0
  return _core;
308
0
}
309
310
void
311
purple_core_set_ui_ops(PurpleCoreUiOps *ops)
312
0
{
313
0
  _ops = ops;
314
0
}
315
316
PurpleCoreUiOps *
317
purple_core_get_ui_ops(void)
318
0
{
319
0
  return _ops;
320
0
}
321
322
#ifdef HAVE_DBUS
323
static char *purple_dbus_owner_user_dir(void)
324
{
325
  DBusMessage *msg = NULL, *reply = NULL;
326
  DBusConnection *dbus_connection = NULL;
327
  DBusError dbus_error;
328
  char *remote_user_dir = NULL;
329
330
  if ((dbus_connection = purple_dbus_get_connection()) == NULL)
331
    return NULL;
332
333
  if ((msg = dbus_message_new_method_call(DBUS_SERVICE_PURPLE, DBUS_PATH_PURPLE, DBUS_INTERFACE_PURPLE, "PurpleUserDir")) == NULL)
334
    return NULL;
335
336
  dbus_error_init(&dbus_error);
337
  reply = dbus_connection_send_with_reply_and_block(dbus_connection, msg, 5000, &dbus_error);
338
  dbus_message_unref(msg);
339
  dbus_error_free(&dbus_error);
340
341
  if (reply)
342
  {
343
    dbus_error_init(&dbus_error);
344
    dbus_message_get_args(reply, &dbus_error, DBUS_TYPE_STRING, &remote_user_dir, DBUS_TYPE_INVALID);
345
    remote_user_dir = g_strdup(remote_user_dir);
346
    dbus_error_free(&dbus_error);
347
    dbus_message_unref(reply);
348
  }
349
350
  return remote_user_dir;
351
}
352
353
#endif /* HAVE_DBUS */
354
355
gboolean
356
purple_core_ensure_single_instance()
357
0
{
358
0
  gboolean is_single_instance = TRUE;
359
#ifdef HAVE_DBUS
360
  /* in the future, other mechanisms might have already set this to FALSE */
361
  if (is_single_instance)
362
  {
363
    if (!purple_dbus_is_owner())
364
    {
365
      const char *user_dir = purple_user_dir();
366
      char *dbus_owner_user_dir = purple_dbus_owner_user_dir();
367
368
      is_single_instance = !purple_strequal(dbus_owner_user_dir, user_dir);
369
      g_free(dbus_owner_user_dir);
370
    }
371
  }
372
#endif /* HAVE_DBUS */
373
374
0
  return is_single_instance;
375
0
}
376
377
static gboolean
378
move_and_symlink_dir(const char *path, const char *basename, const char *old_base, const char *new_base, const char *relative)
379
0
{
380
0
  char *new_name = g_build_filename(new_base, basename, NULL);
381
0
#ifndef _WIN32
382
0
  char *old_name;
383
0
#endif
384
0
  if (g_rename(path, new_name))
385
0
  {
386
0
    purple_debug_error("core", "Error renaming %s to %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n",
387
0
                       path, new_name, g_strerror(errno));
388
0
    g_free(new_name);
389
0
    return FALSE;
390
0
  }
391
0
  g_free(new_name);
392
393
0
#ifndef _WIN32
394
  /* NOTE: This new_name is relative. */
395
0
  new_name = g_build_filename(relative, basename, NULL);
396
0
  old_name = g_build_filename(old_base, basename, NULL);
397
0
  if (symlink(new_name, old_name))
398
0
  {
399
0
    purple_debug_warning("core", "Error symlinking %s to %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n",
400
0
                         old_name, new_name, g_strerror(errno));
401
0
  }
402
0
  g_free(old_name);
403
0
  g_free(new_name);
404
0
#endif
405
406
0
  return TRUE;
407
0
}
408
409
gboolean
410
purple_core_migrate(void)
411
0
{
412
0
  const char *user_dir = purple_user_dir();
413
0
  char *old_user_dir = g_strconcat(purple_home_dir(),
414
0
                                   G_DIR_SEPARATOR_S ".gaim", NULL);
415
0
  char *status_file;
416
0
  FILE *fp;
417
0
  GDir *dir;
418
0
  GError *err;
419
0
  const char *entry;
420
0
#ifndef _WIN32
421
0
  char *logs_dir;
422
0
#endif
423
0
  char *old_icons_dir;
424
425
0
  if (!g_file_test(old_user_dir, G_FILE_TEST_EXISTS))
426
0
  {
427
    /* ~/.gaim doesn't exist, so there's nothing to migrate. */
428
0
    g_free(old_user_dir);
429
0
    return TRUE;
430
0
  }
431
432
0
  status_file = g_strconcat(user_dir, G_DIR_SEPARATOR_S "migrating", NULL);
433
434
0
  if (g_file_test(user_dir, G_FILE_TEST_EXISTS))
435
0
  {
436
    /* If we're here, we have both ~/.gaim and .purple. */
437
438
0
    if (!g_file_test(status_file, G_FILE_TEST_EXISTS))
439
0
    {
440
      /* There's no "migrating" status file,
441
       * so ~/.purple is all up to date. */
442
0
      g_free(status_file);
443
0
      g_free(old_user_dir);
444
0
      return TRUE;
445
0
    }
446
0
  }
447
448
  /* If we're here, it's time to migrate from ~/.gaim to ~/.purple. */
449
450
        /* Ensure the user directory exists */
451
0
  if (!g_file_test(user_dir, G_FILE_TEST_IS_DIR))
452
0
  {
453
0
    if (g_mkdir(user_dir, S_IRUSR | S_IWUSR | S_IXUSR) == -1)
454
0
    {
455
0
      purple_debug_error("core", "Error creating directory %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n",
456
0
                         user_dir, g_strerror(errno));
457
0
      g_free(status_file);
458
0
      g_free(old_user_dir);
459
0
      return FALSE;
460
0
    }
461
0
  }
462
463
  /* This writes ~/.purple/migrating, which allows us to detect
464
   * incomplete migrations and properly retry. */
465
0
  if (!(fp = g_fopen(status_file, "w")))
466
0
  {
467
0
    purple_debug_error("core", "Error opening file %s for writing: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n",
468
0
                       status_file, g_strerror(errno));
469
0
    g_free(status_file);
470
0
    g_free(old_user_dir);
471
0
    return FALSE;
472
0
  }
473
0
  fclose(fp);
474
475
  /* Open ~/.gaim so we can loop over its contents. */
476
0
  err = NULL;
477
0
  if (!(dir = g_dir_open(old_user_dir, 0, &err)))
478
0
  {
479
0
    purple_debug_error("core", "Error opening directory %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n",
480
0
                       status_file,
481
0
                       (err ? err->message : "Unknown error"));
482
0
    if (err)
483
0
      g_error_free(err);
484
0
    g_free(status_file);
485
0
    g_free(old_user_dir);
486
0
    return FALSE;
487
0
  }
488
489
  /* Loop over the contents of ~/.gaim */
490
0
  while ((entry = g_dir_read_name(dir)))
491
0
  {
492
0
    char *name = g_build_filename(old_user_dir, entry, NULL);
493
494
0
#ifndef _WIN32
495
    /* Deal with symlinks... */
496
0
    if (g_file_test(name, G_FILE_TEST_IS_SYMLINK))
497
0
    {
498
      /* We're only going to duplicate a logs symlink. */
499
0
      if (purple_strequal(entry, "logs"))
500
0
      {
501
0
        char *link;
502
0
        err = NULL;
503
504
0
        if ((link = g_file_read_link(name, &err)) == NULL)
505
0
        {
506
0
          char *name_utf8 = g_filename_to_utf8(name, -1, NULL, NULL, NULL);
507
0
          purple_debug_error("core", "Error reading symlink %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n",
508
0
                             name_utf8 ? name_utf8 : name, err->message);
509
0
          g_free(name_utf8);
510
0
          g_error_free(err);
511
0
          g_free(name);
512
0
          g_dir_close(dir);
513
0
          g_free(status_file);
514
0
          g_free(old_user_dir);
515
0
          return FALSE;
516
0
        }
517
518
0
        logs_dir = g_build_filename(user_dir, "logs", NULL);
519
520
0
        if (purple_strequal(link, "../.purple/logs") ||
521
0
            purple_strequal(link, logs_dir))
522
0
        {
523
          /* If the symlink points to the new directory, we're
524
           * likely just trying again after a failed migration,
525
           * so there's no need to fail here. */
526
0
          g_free(link);
527
0
          g_free(logs_dir);
528
0
          continue;
529
0
        }
530
531
        /* In case we are trying again after a failed migration, we need
532
         * to unlink any existing symlink.  If it's a directory, this
533
         * will fail, and so will the symlink below, which is good
534
         * because the user should sort things out. */
535
0
        g_unlink(logs_dir);
536
537
        /* Relative links will most likely still be
538
         * valid from ~/.purple, though it's not
539
         * guaranteed.  Oh well. */
540
0
        if (symlink(link, logs_dir))
541
0
        {
542
0
          purple_debug_error("core", "Error symlinking %s to %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n",
543
0
                             logs_dir, link, g_strerror(errno));
544
0
          g_free(link);
545
0
          g_free(name);
546
0
          g_free(logs_dir);
547
0
          g_dir_close(dir);
548
0
          g_free(status_file);
549
0
          g_free(old_user_dir);
550
0
          return FALSE;
551
0
        }
552
553
0
        g_free(link);
554
0
        g_free(logs_dir);
555
0
        continue;
556
0
      }
557
558
      /* Ignore all other symlinks. */
559
0
      continue;
560
0
    }
561
0
#endif
562
563
    /* Deal with directories... */
564
0
    if (g_file_test(name, G_FILE_TEST_IS_DIR))
565
0
    {
566
0
      if (purple_strequal(entry, "icons"))
567
0
      {
568
        /* This is a special case for the Album plugin, which
569
         * stores data in the icons folder.  We're not copying
570
         * the icons directory over because previous bugs
571
         * meant that it filled up with junk for many users.
572
         * This is a great time to purge it. */
573
574
0
        GDir *icons_dir;
575
0
        char *new_icons_dir;
576
0
        const char *icons_entry;
577
578
0
        err = NULL;
579
0
        if (!(icons_dir = g_dir_open(name, 0, &err)))
580
0
        {
581
0
          purple_debug_error("core", "Error opening directory %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n",
582
0
                             name,
583
0
                             (err ? err->message : "Unknown error"));
584
0
          if (err)
585
0
            g_error_free(err);
586
0
          g_free(name);
587
0
          g_dir_close(dir);
588
0
          g_free(status_file);
589
0
          g_free(old_user_dir);
590
0
          return FALSE;
591
0
        }
592
593
0
        new_icons_dir = g_build_filename(user_dir, "icons", NULL);
594
              /* Ensure the new icon directory exists */
595
0
        if (!g_file_test(new_icons_dir, G_FILE_TEST_IS_DIR))
596
0
        {
597
0
          if (g_mkdir(new_icons_dir, S_IRUSR | S_IWUSR | S_IXUSR) == -1)
598
0
          {
599
0
            purple_debug_error("core", "Error creating directory %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n",
600
0
                               new_icons_dir, g_strerror(errno));
601
0
            g_free(new_icons_dir);
602
0
            g_dir_close(icons_dir);
603
0
            g_free(name);
604
0
            g_dir_close(dir);
605
0
            g_free(status_file);
606
0
            g_free(old_user_dir);
607
0
            return FALSE;
608
0
          }
609
0
        }
610
611
0
        while ((icons_entry = g_dir_read_name(icons_dir)))
612
0
        {
613
0
          char *icons_name = g_build_filename(name, icons_entry, NULL);
614
615
0
          if (g_file_test(icons_name, G_FILE_TEST_IS_DIR))
616
0
          {
617
0
            if (!move_and_symlink_dir(icons_name, icons_entry,
618
0
                                      name, new_icons_dir, "../../.purple/icons"))
619
0
            {
620
0
              g_free(icons_name);
621
0
              g_free(new_icons_dir);
622
0
              g_dir_close(icons_dir);
623
0
              g_free(name);
624
0
              g_dir_close(dir);
625
0
              g_free(status_file);
626
0
              g_free(old_user_dir);
627
0
              return FALSE;
628
0
            }
629
0
          }
630
0
          g_free(icons_name);
631
0
        }
632
633
0
        g_dir_close(icons_dir);
634
0
      }
635
0
      else if (purple_strequal(entry, "plugins"))
636
0
      {
637
        /* Do nothing, because we broke plugin compatibility.
638
         * This means that the plugins directory gets left behind. */
639
0
      }
640
0
      else
641
0
      {
642
        /* All other directories are moved and symlinked. */
643
0
        if (!move_and_symlink_dir(name, entry, old_user_dir, user_dir, "../.purple"))
644
0
        {
645
0
          g_free(name);
646
0
          g_dir_close(dir);
647
0
          g_free(status_file);
648
0
          g_free(old_user_dir);
649
0
          return FALSE;
650
0
        }
651
0
      }
652
0
    }
653
0
    else if (g_file_test(name, G_FILE_TEST_IS_REGULAR))
654
0
    {
655
      /* Regular files are copied. */
656
657
0
      char *new_name;
658
0
      FILE *new_file;
659
660
0
      if (!(fp = g_fopen(name, "rb")))
661
0
      {
662
0
        purple_debug_error("core", "Error opening file %s for reading: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n",
663
0
                           name, g_strerror(errno));
664
0
        g_free(name);
665
0
        g_dir_close(dir);
666
0
        g_free(status_file);
667
0
        g_free(old_user_dir);
668
0
        return FALSE;
669
0
      }
670
671
0
      new_name = g_build_filename(user_dir, entry, NULL);
672
0
      if (!(new_file = g_fopen(new_name, "wb")))
673
0
      {
674
0
        purple_debug_error("core", "Error opening file %s for writing: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n",
675
0
                           new_name, g_strerror(errno));
676
0
        fclose(fp);
677
0
        g_free(new_name);
678
0
        g_free(name);
679
0
        g_dir_close(dir);
680
0
        g_free(status_file);
681
0
        g_free(old_user_dir);
682
0
        return FALSE;
683
0
      }
684
685
0
      while (!feof(fp))
686
0
      {
687
0
        unsigned char buf[256];
688
0
        size_t size;
689
690
0
        size = fread(buf, 1, sizeof(buf), fp);
691
0
        if (size != sizeof(buf) && !feof(fp))
692
0
        {
693
0
          purple_debug_error("core", "Error reading %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n",
694
0
                             name, g_strerror(errno));
695
0
          fclose(new_file);
696
0
          fclose(fp);
697
0
          g_free(new_name);
698
0
          g_free(name);
699
0
          g_dir_close(dir);
700
0
          g_free(status_file);
701
0
          g_free(old_user_dir);
702
0
          return FALSE;
703
0
        }
704
705
0
        if (!fwrite(buf, size, 1, new_file) && ferror(new_file) != 0)
706
0
        {
707
0
          purple_debug_error("core", "Error writing %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n",
708
0
                             new_name, g_strerror(errno));
709
0
          fclose(new_file);
710
0
          fclose(fp);
711
0
          g_free(new_name);
712
0
          g_free(name);
713
0
          g_dir_close(dir);
714
0
          g_free(status_file);
715
0
          g_free(old_user_dir);
716
0
          return FALSE;
717
0
        }
718
0
      }
719
720
0
      if (fclose(new_file))
721
0
      {
722
0
        purple_debug_error("core", "Error writing: %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n",
723
0
                           new_name, g_strerror(errno));
724
0
      }
725
0
      if (fclose(fp))
726
0
      {
727
0
        purple_debug_warning("core", "Error closing %s: %s\n",
728
0
                             name, g_strerror(errno));
729
0
      }
730
0
      g_free(new_name);
731
0
    }
732
0
    else
733
0
      purple_debug_warning("core", "Not a regular file or directory: %s\n", name);
734
735
0
    g_free(name);
736
0
  }
737
738
  /* The migration was successful, so delete the status file. */
739
0
  if (g_unlink(status_file))
740
0
  {
741
0
    purple_debug_error("core", "Error unlinking file %s: %s. Please report this at " PURPLE_DEVEL_WEBSITE "\n",
742
0
                       status_file, g_strerror(errno));
743
0
    g_free(status_file);
744
0
    return FALSE;
745
0
  }
746
747
0
  old_icons_dir = g_build_filename(old_user_dir, "icons", NULL);
748
0
  _purple_buddy_icon_set_old_icons_dir(old_icons_dir);
749
0
  g_free(old_icons_dir);
750
751
0
  g_free(old_user_dir);
752
753
0
  g_free(status_file);
754
0
  return TRUE;
755
0
}
756
757
0
GHashTable* purple_core_get_ui_info() {
758
0
  PurpleCoreUiOps *ops = purple_core_get_ui_ops();
759
760
0
  if(NULL == ops || NULL == ops->get_ui_info)
761
0
    return NULL;
762
763
0
  return ops->get_ui_info();
764
0
}