source: trunk/gtk/conf.c @ 9237

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

(trunk, gtk, qt) #2478: popup dialog for first-time users

  • Property svn:keywords set to Date Rev Author Id
File size: 11.9 KB
Line 
1/******************************************************************************
2 * $Id: conf.c 9237 2009-10-02 22:53:19Z 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( gtr_mkdir_with_parents( 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          gtr_lockfile_state_t   * tr_state,
80          char                  ** errstr )
81{
82    const gtr_lockfile_state_t state = gtr_lockfile( filename );
83    const gboolean success = state == GTR_LOCKFILE_SUCCESS;
84
85    if( errstr ) switch( state )
86        {
87            case GTR_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 GTR_LOCKFILE_ELOCK:
94                *errstr = g_strdup_printf( _( "%s is already running." ),
95                                          g_get_application_name( ) );
96                break;
97
98            case GTR_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( gtr_lockfile_state_t * tr_state, char ** errstr )
129{
130    char *         path = getLockFilename( );
131    const gboolean didLock = lockfile( path, tr_state, errstr );
132
133    if( didLock )
134        gl_lockpath = g_strdup( path );
135    g_atexit( cf_removelocks );
136    g_free( path );
137    return didLock;
138}
139
140/***
141****
142****  Preferences
143****
144***/
145
146static void cf_check_older_configs( void );
147
148/**
149 * This is where we initialize the preferences file with the default values.
150 * If you add a new preferences key, you /must/ add a default value here.
151 */
152static void
153tr_prefs_init_defaults( tr_benc * d )
154{
155    const char * str;
156
157    cf_check_older_configs( );
158
159#ifdef HAVE_GIO
160    str = NULL;
161    if( !str ) str = g_get_user_special_dir( G_USER_DIRECTORY_DOWNLOAD );
162    if( !str ) str = g_get_user_special_dir( G_USER_DIRECTORY_DESKTOP );
163    if( !str ) str = tr_getDefaultDownloadDir( );
164    tr_bencDictAddStr( d, PREF_KEY_DIR_WATCH, str );
165    tr_bencDictAddBool( d, PREF_KEY_DIR_WATCH_ENABLED, FALSE );
166#endif
167
168    tr_bencDictAddBool( d, PREF_KEY_USER_HAS_GIVEN_INFORMED_CONSENT, FALSE );
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_bencDictAddBool( d, PREF_KEY_SHOW_MORE_TRACKER_INFO, FALSE );
180    tr_bencDictAddBool( d, PREF_KEY_SHOW_BACKUP_TRACKERS, FALSE );
181    tr_bencDictAddStr( d, PREF_KEY_STATUSBAR_STATS, "total-ratio" );
182
183    tr_bencDictAddBool( d, PREF_KEY_OPTIONS_PROMPT, TRUE );
184
185    tr_bencDictAddBool( d, PREF_KEY_MAIN_WINDOW_IS_MAXIMIZED, FALSE );
186    tr_bencDictAddInt( d, PREF_KEY_MAIN_WINDOW_HEIGHT, 500 );
187    tr_bencDictAddInt( d, PREF_KEY_MAIN_WINDOW_WIDTH, 300 );
188    tr_bencDictAddInt( d, PREF_KEY_MAIN_WINDOW_X, 50 );
189    tr_bencDictAddInt( d, PREF_KEY_MAIN_WINDOW_Y, 50 );
190    tr_bencDictAddStr( d, PREF_KEY_MAIN_WINDOW_LAYOUT_ORDER, "menu,toolbar,filter,list,statusbar" );
191
192    str = NULL;
193#if GLIB_CHECK_VERSION( 2, 14, 0 )
194    if( !str ) str = g_get_user_special_dir( G_USER_DIRECTORY_DOWNLOAD );
195#endif
196    if( !str ) str = tr_getDefaultDownloadDir( );
197    tr_bencDictAddStr( d, TR_PREFS_KEY_DOWNLOAD_DIR, str );
198
199    tr_bencDictAddBool( d, PREF_KEY_ASKQUIT, TRUE );
200
201    tr_bencDictAddStr( d, PREF_KEY_FILTER_MODE, "show-all" );
202    tr_bencDictAddStr( d, PREF_KEY_SORT_MODE, "sort-by-name" );
203    tr_bencDictAddBool( d, PREF_KEY_SORT_REVERSED, FALSE );
204    tr_bencDictAddBool( d, PREF_KEY_MINIMAL_VIEW, FALSE );
205
206    tr_bencDictAddBool( d, PREF_KEY_START, TRUE );
207    tr_bencDictAddBool( d, PREF_KEY_TRASH_ORIGINAL, FALSE );
208}
209
210static char*
211getPrefsFilename( void )
212{
213    assert( gl_confdir != NULL );
214    return g_build_filename( gl_confdir, "settings.json", NULL );
215}
216
217static tr_benc*
218getPrefs( void )
219{
220    static tr_benc settings;
221    static gboolean loaded = FALSE;
222
223    if( !loaded )
224    {
225        tr_bencInitDict( &settings, 0 );
226        tr_prefs_init_defaults( &settings );
227        tr_sessionLoadSettings( &settings, gl_confdir, MY_NAME );
228        loaded = TRUE;
229    }
230
231    return &settings;
232}
233
234/***
235****
236***/
237
238tr_benc*
239pref_get_all( void )
240{
241    return getPrefs( );
242}
243
244int64_t
245pref_int_get( const char * key )
246{
247    int64_t i = 0;
248
249    tr_bencDictFindInt( getPrefs( ), key, &i );
250    return i;
251}
252
253void
254pref_int_set( const char * key,
255              int64_t      value )
256{
257    tr_bencDictAddInt( getPrefs( ), key, value );
258}
259
260double
261pref_double_get( const char * key )
262{
263    double d = 0.0;
264    tr_bencDictFindReal( getPrefs( ), key, &d );
265    return d;
266}
267
268void
269pref_double_set( const char * key,
270                 double       value )
271{
272    tr_bencDictAddReal( getPrefs( ), key, value );
273}
274
275/***
276****
277***/
278
279gboolean
280pref_flag_get( const char * key )
281{
282    tr_bool boolVal;
283    tr_bencDictFindBool( getPrefs( ), key, &boolVal );
284    return boolVal != 0;
285}
286
287gboolean
288pref_flag_eval( pref_flag_t  val,
289                const char * key )
290{
291    switch( val )
292    {
293        case PREF_FLAG_TRUE:
294            return TRUE;
295
296        case PREF_FLAG_FALSE:
297            return FALSE;
298
299        default:
300            return pref_flag_get( key );
301    }
302}
303
304void
305pref_flag_set( const char * key,
306               gboolean     value )
307{
308    tr_bencDictAddBool( getPrefs( ), key, value );
309}
310
311/***
312****
313***/
314
315const char*
316pref_string_get( const char * key )
317{
318    const char * str = NULL;
319    tr_bencDictFindStr( getPrefs( ), key, &str );
320    return str;
321}
322
323void
324pref_string_set( const char * key, const char * value )
325{
326    tr_bencDictAddStr( getPrefs( ), key, value );
327}
328
329/***
330****
331***/
332
333void
334pref_save( tr_session * session )
335{
336    tr_sessionSaveSettings( session, gl_confdir, getPrefs( ) );
337}
338
339/***
340****
341***/
342
343#if !GLIB_CHECK_VERSION( 2, 8, 0 )
344static void
345tr_file_set_contents( const char *   filename,
346                      const void *   out,
347                      size_t         len,
348                      GError* unused UNUSED )
349{
350    FILE * fp = fopen( filename, "wb+" );
351
352    if( fp != NULL )
353    {
354        fwrite( out, 1, len, fp );
355        fclose( fp );
356    }
357}
358
359 #define g_file_set_contents tr_file_set_contents
360#endif
361
362static char*
363getCompat090PrefsFilename( void )
364{
365    assert( gl_confdir != NULL );
366
367    return g_build_filename( g_get_home_dir( ), ".transmission", "gtk", "prefs.ini", NULL );
368}
369
370static char*
371getCompat121PrefsFilename( void )
372{
373    return g_build_filename( g_get_user_config_dir( ), "transmission", "gtk", "prefs.ini", NULL );
374}
375
376static void
377translate_keyfile_to_json( const char * old_file,
378                           const char * new_file )
379{
380    tr_benc    dict;
381    GKeyFile * keyfile;
382    gchar **   keys;
383    gsize      i;
384    gsize      length;
385
386    static struct pref_entry {
387        const char*   oldkey;
388        const char*   newkey;
389    } renamed[] = {
390        { "default-download-directory", "download-dir"             },
391        { "encrypted-connections-only", "encryption"               },
392        { "listening-port",             "peer-port"                },
393        { "nat-traversal-enabled",      "port-forwarding-enabled"  },
394        { "open-dialog-folder",         "open-dialog-dir"          },
395        { "watch-folder",               "watch-dir"                },
396        { "watch-folder-enabled",       "watch-dir-enabled"        }
397    };
398
399    keyfile = g_key_file_new( );
400    g_key_file_load_from_file( keyfile, old_file, 0, NULL );
401    length = 0;
402    keys = g_key_file_get_keys( keyfile, "general", &length, NULL );
403
404    tr_bencInitDict( &dict, length );
405    for( i = 0; i < length; ++i )
406    {
407        guint        j;
408        const char * key = keys[i];
409        gchar *      val = g_key_file_get_value( keyfile, "general", key,
410                                                 NULL );
411
412        for( j = 0; j < G_N_ELEMENTS( renamed ); ++j )
413            if( !strcmp( renamed[j].oldkey, key ) )
414                key = renamed[j].newkey;
415
416        if( !strcmp( val, "true" ) || !strcmp( val, "false" ) )
417            tr_bencDictAddInt( &dict, key, !strcmp( val, "true" ) );
418        else
419        {
420            char * end;
421            long   l;
422            errno = 0;
423            l = strtol( val, &end, 10 );
424            if( !errno && end && !*end )
425                tr_bencDictAddInt( &dict, key, l );
426            else
427                tr_bencDictAddStr( &dict, key, val );
428        }
429
430        g_free( val );
431    }
432
433    g_key_file_free( keyfile );
434    tr_bencToFile( &dict, TR_FMT_JSON, new_file );
435    tr_bencFree( &dict );
436}
437
438static void
439cf_check_older_configs( void )
440{
441    char * filename = getPrefsFilename( );
442
443    if( !g_file_test( filename, G_FILE_TEST_IS_REGULAR ) )
444    {
445        char * key1 = getCompat121PrefsFilename( );
446        char * key2 = getCompat090PrefsFilename( );
447
448        if( g_file_test( key1, G_FILE_TEST_IS_REGULAR ) )
449        {
450            g_message( _( "Importing \"%s\"" ), key1 );
451            translate_keyfile_to_json( key1, filename );
452        }
453        else if( g_file_test( key2, G_FILE_TEST_IS_REGULAR ) )
454        {
455            g_message( _( "Importing \"%s\"" ), key2 );
456            translate_keyfile_to_json( key2, filename );
457        }
458
459        g_free( key2 );
460        g_free( key1 );
461    }
462
463    g_free( filename );
464}
Note: See TracBrowser for help on using the repository browser.