source: trunk/gtk/conf.c @ 8580

Last change on this file since 8580 was 8580, checked in by charles, 13 years ago

(trunk gtk) drop support for the gtk client's 0.80 config file. this format hasn't been used since September 2007 and it's not clear to me that the code works correctly anymore.

  • Property svn:keywords set to Date Rev Author Id
File size: 11.6 KB
Line 
1/******************************************************************************
2 * $Id: conf.c 8580 2009-06-01 17:24:12Z charles $
3 *
4 * Copyright (c) 2005-2008 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#include <assert.h>
26#include <errno.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30
31#include <unistd.h>
32
33#include <glib.h>
34#include <glib/gi18n.h>
35#include <glib/gstdio.h>
36
37#include <libtransmission/transmission.h>
38#include <libtransmission/bencode.h>
39#include <libtransmission/platform.h>
40
41#include "conf.h"
42#include "tr-prefs.h"
43#include "util.h"
44
45#define MY_NAME "transmission"
46
47static char * gl_confdir = NULL;
48static char * gl_lockpath = NULL;
49
50/* errstr may be NULL, this might be called before GTK is initialized */
51gboolean
52cf_init( const char   * configDir,
53         char        ** errstr )
54{
55    if( errstr != NULL )
56        *errstr = NULL;
57
58    gl_confdir = g_strdup( configDir );
59
60    if( mkdir_p( gl_confdir, 0755 ) )
61        return TRUE;
62
63    if( errstr != NULL )
64        *errstr = g_strdup_printf( _( "Couldn't create \"%1$s\": %2$s" ),
65                                  gl_confdir, g_strerror( errno ) );
66
67    return FALSE;
68}
69
70/***
71****
72****  Lockfile
73****
74***/
75
76/* errstr may be NULL, this might be called before GTK is initialized */
77static gboolean
78lockfile( const char *         filename,
79          tr_lockfile_state_t *tr_state,
80          char **              errstr )
81{
82    const tr_lockfile_state_t state = tr_lockfile( filename );
83    const gboolean            success = state == TR_LOCKFILE_SUCCESS;
84
85    if( errstr ) switch( state )
86        {
87            case TR_LOCKFILE_EOPEN:
88                *errstr =
89                    g_strdup_printf( _( "Couldn't open \"%1$s\": %2$s" ),
90                                    filename, g_strerror( errno ) );
91                break;
92
93            case TR_LOCKFILE_ELOCK:
94                *errstr = g_strdup_printf( _( "%s is already running." ),
95                                          g_get_application_name( ) );
96                break;
97
98            case TR_LOCKFILE_SUCCESS:
99                *errstr = NULL;
100                break;
101        }
102
103    if( tr_state != NULL )
104        *tr_state = state;
105
106    return success;
107}
108
109static char*
110getLockFilename( void )
111{
112    assert( gl_confdir != NULL );
113    return g_build_filename( gl_confdir, "lock", NULL );
114}
115
116static void
117cf_removelocks( void )
118{
119    if( gl_lockpath )
120    {
121        g_unlink( gl_lockpath );
122        g_free( gl_lockpath );
123    }
124}
125
126/* errstr may be NULL, this might be called before GTK is initialized */
127gboolean
128cf_lock( tr_lockfile_state_t *tr_state,
129         char **              errstr )
130{
131    char *         path = getLockFilename( );
132    const gboolean didLock = lockfile( path, tr_state, errstr );
133
134    if( didLock )
135        gl_lockpath = g_strdup( path );
136    g_atexit( cf_removelocks );
137    g_free( path );
138    return didLock;
139}
140
141/***
142****
143****  Preferences
144****
145***/
146
147static void cf_check_older_configs( void );
148
149/**
150 * This is where we initialize the preferences file with the default values.
151 * If you add a new preferences key, you /must/ add a default value here.
152 */
153static void
154tr_prefs_init_defaults( tr_benc * d )
155{
156    const char * str;
157
158    cf_check_older_configs( );
159
160#ifdef HAVE_GIO
161    str = NULL;
162    if( !str ) str = g_get_user_special_dir( G_USER_DIRECTORY_DOWNLOAD );
163    if( !str ) str = g_get_user_special_dir( G_USER_DIRECTORY_DESKTOP );
164    if( !str ) str = tr_getDefaultDownloadDir( );
165    tr_bencDictAddStr( d, PREF_KEY_DIR_WATCH, str );
166    tr_bencDictAddBool( d, PREF_KEY_DIR_WATCH_ENABLED, FALSE );
167#endif
168
169    tr_bencDictAddBool( d, PREF_KEY_INHIBIT_HIBERNATION, FALSE );
170    tr_bencDictAddBool( d, PREF_KEY_BLOCKLIST_UPDATES_ENABLED, TRUE );
171
172    tr_bencDictAddStr( d, PREF_KEY_OPEN_DIALOG_FOLDER, g_get_home_dir( ) );
173
174    tr_bencDictAddBool( d, PREF_KEY_TOOLBAR, TRUE );
175    tr_bencDictAddBool( d, PREF_KEY_FILTERBAR, TRUE );
176    tr_bencDictAddBool( d, PREF_KEY_STATUSBAR, TRUE );
177    tr_bencDictAddBool( d, PREF_KEY_SHOW_TRAY_ICON, FALSE );
178    tr_bencDictAddBool( d, PREF_KEY_SHOW_DESKTOP_NOTIFICATION, TRUE );
179    tr_bencDictAddStr( d, PREF_KEY_STATUSBAR_STATS, "total-ratio" );
180
181    tr_bencDictAddBool( d, PREF_KEY_OPTIONS_PROMPT, TRUE );
182
183    tr_bencDictAddInt( d, PREF_KEY_MAIN_WINDOW_HEIGHT, 500 );
184    tr_bencDictAddInt( d, PREF_KEY_MAIN_WINDOW_WIDTH, 300 );
185    tr_bencDictAddInt( d, PREF_KEY_MAIN_WINDOW_X, 50 );
186    tr_bencDictAddInt( d, PREF_KEY_MAIN_WINDOW_Y, 50 );
187    tr_bencDictAddStr( d, PREF_KEY_MAIN_WINDOW_LAYOUT_ORDER, "menu,toolbar,filter,list,statusbar" );
188
189    str = NULL;
190#if GLIB_CHECK_VERSION( 2, 14, 0 )
191    if( !str ) str = g_get_user_special_dir( G_USER_DIRECTORY_DOWNLOAD );
192#endif
193    if( !str ) str = tr_getDefaultDownloadDir( );
194    tr_bencDictAddStr( d, TR_PREFS_KEY_DOWNLOAD_DIR, str );
195
196    tr_bencDictAddBool( d, PREF_KEY_ASKQUIT, TRUE );
197
198    tr_bencDictAddStr( d, PREF_KEY_FILTER_MODE, "show-all" );
199    tr_bencDictAddStr( d, PREF_KEY_SORT_MODE, "sort-by-name" );
200    tr_bencDictAddBool( d, PREF_KEY_SORT_REVERSED, FALSE );
201    tr_bencDictAddBool( d, PREF_KEY_MINIMAL_VIEW, FALSE );
202
203    tr_bencDictAddBool( d, PREF_KEY_START, TRUE );
204    tr_bencDictAddBool( d, PREF_KEY_TRASH_ORIGINAL, FALSE );
205}
206
207static char*
208getPrefsFilename( void )
209{
210    assert( gl_confdir != NULL );
211    return g_build_filename( gl_confdir, "settings.json", NULL );
212}
213
214static tr_benc*
215getPrefs( void )
216{
217    static tr_benc settings;
218    static gboolean loaded = FALSE;
219
220    if( !loaded )
221    {
222        tr_bencInitDict( &settings, 0 );
223        tr_prefs_init_defaults( &settings );
224        tr_sessionLoadSettings( &settings, gl_confdir, MY_NAME );
225        loaded = TRUE;
226    }
227
228    return &settings;
229}
230
231/***
232****
233***/
234
235tr_benc*
236pref_get_all( void )
237{
238    return getPrefs( );
239}
240
241int64_t
242pref_int_get( const char * key )
243{
244    int64_t i = 0;
245
246    tr_bencDictFindInt( getPrefs( ), key, &i );
247    return i;
248}
249
250void
251pref_int_set( const char * key,
252              int64_t      value )
253{
254    tr_bencDictAddInt( getPrefs( ), key, value );
255}
256
257double
258pref_double_get( const char * key )
259{
260    double d = 0.0;
261    tr_bencDictFindReal( getPrefs( ), key, &d );
262    return d;
263}
264
265void
266pref_double_set( const char * key,
267                 double       value )
268{
269    tr_bencDictAddReal( getPrefs( ), key, value );
270}
271
272/***
273****
274***/
275
276gboolean
277pref_flag_get( const char * key )
278{
279    tr_bool boolVal;
280    tr_bencDictFindBool( getPrefs( ), key, &boolVal );
281    return boolVal != 0;
282}
283
284gboolean
285pref_flag_eval( pref_flag_t  val,
286                const char * key )
287{
288    switch( val )
289    {
290        case PREF_FLAG_TRUE:
291            return TRUE;
292
293        case PREF_FLAG_FALSE:
294            return FALSE;
295
296        default:
297            return pref_flag_get( key );
298    }
299}
300
301void
302pref_flag_set( const char * key,
303               gboolean     value )
304{
305    tr_bencDictAddBool( getPrefs( ), key, value );
306}
307
308/***
309****
310***/
311
312const char*
313pref_string_get( const char * key )
314{
315    const char * str = NULL;
316    tr_bencDictFindStr( getPrefs( ), key, &str );
317    return str;
318}
319
320void
321pref_string_set( const char * key, const char * value )
322{
323    tr_bencDictAddStr( getPrefs( ), key, value );
324}
325
326/***
327****
328***/
329
330void
331pref_save( tr_session * session )
332{
333    tr_sessionSaveSettings( session, gl_confdir, getPrefs( ) );
334}
335
336/***
337****
338***/
339
340#if !GLIB_CHECK_VERSION( 2, 8, 0 )
341static void
342tr_file_set_contents( const char *   filename,
343                      const void *   out,
344                      size_t         len,
345                      GError* unused UNUSED )
346{
347    FILE * fp = fopen( filename, "wb+" );
348
349    if( fp != NULL )
350    {
351        fwrite( out, 1, len, fp );
352        fclose( fp );
353    }
354}
355
356 #define g_file_set_contents tr_file_set_contents
357#endif
358
359static char*
360getCompat090PrefsFilename( void )
361{
362    assert( gl_confdir != NULL );
363
364    return g_build_filename( g_get_home_dir( ), ".transmission", "gtk", "prefs.ini", NULL );
365}
366
367static char*
368getCompat121PrefsFilename( void )
369{
370    return g_build_filename( g_get_user_config_dir( ), "transmission", "gtk", "prefs.ini", NULL );
371}
372
373static void
374translate_keyfile_to_json( const char * old_file,
375                           const char * new_file )
376{
377    tr_benc    dict;
378    GKeyFile * keyfile;
379    gchar **   keys;
380    gsize      i;
381    gsize      length;
382
383    static struct pref_entry {
384        const char*   oldkey;
385        const char*   newkey;
386    } renamed[] = {
387        { "default-download-directory", "download-dir"             },
388        { "encrypted-connections-only", "encryption"               },
389        { "listening-port",             "peer-port"                },
390        { "nat-traversal-enabled",      "port-forwarding-enabled"  },
391        { "open-dialog-folder",         "open-dialog-dir"          },
392        { "watch-folder",               "watch-dir"                },
393        { "watch-folder-enabled",       "watch-dir-enabled"        }
394    };
395
396    keyfile = g_key_file_new( );
397    g_key_file_load_from_file( keyfile, old_file, 0, NULL );
398    length = 0;
399    keys = g_key_file_get_keys( keyfile, "general", &length, NULL );
400
401    tr_bencInitDict( &dict, length );
402    for( i = 0; i < length; ++i )
403    {
404        guint        j;
405        const char * key = keys[i];
406        gchar *      val = g_key_file_get_value( keyfile, "general", key,
407                                                 NULL );
408
409        for( j = 0; j < G_N_ELEMENTS( renamed ); ++j )
410            if( !strcmp( renamed[j].oldkey, key ) )
411                key = renamed[j].newkey;
412
413        if( !strcmp( val, "true" ) || !strcmp( val, "false" ) )
414            tr_bencDictAddInt( &dict, key, !strcmp( val, "true" ) );
415        else
416        {
417            char * end;
418            long   l;
419            errno = 0;
420            l = strtol( val, &end, 10 );
421            if( !errno && end && !*end )
422                tr_bencDictAddInt( &dict, key, l );
423            else
424                tr_bencDictAddStr( &dict, key, val );
425        }
426
427        g_free( val );
428    }
429
430    g_key_file_free( keyfile );
431    tr_bencSaveJSONFile( new_file, &dict );
432    tr_bencFree( &dict );
433}
434
435static void
436cf_check_older_configs( void )
437{
438    char * filename = getPrefsFilename( );
439
440    if( !g_file_test( filename, G_FILE_TEST_IS_REGULAR ) )
441    {
442        char * key1 = getCompat121PrefsFilename( );
443        char * key2 = getCompat090PrefsFilename( );
444
445        if( g_file_test( key1, G_FILE_TEST_IS_REGULAR ) )
446        {
447            g_message( _( "Importing \"%s\"" ), key1 );
448            translate_keyfile_to_json( key1, filename );
449        }
450        else if( g_file_test( key2, G_FILE_TEST_IS_REGULAR ) )
451        {
452            g_message( _( "Importing \"%s\"" ), key2 );
453            translate_keyfile_to_json( key2, filename );
454        }
455
456        g_free( key2 );
457        g_free( key1 );
458    }
459
460    g_free( filename );
461}
Note: See TracBrowser for help on using the repository browser.