source: trunk/gtk/conf.c @ 7367

Last change on this file since 7367 was 7367, checked in by charles, 10 years ago

(trunk) #1559: Simplify tr_sessionInitFull

  • Property svn:keywords set to Date Rev Author Id
File size: 12.4 KB
Line 
1/******************************************************************************
2 * $Id: conf.c 7367 2008-12-13 23:17:36Z 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 "util.h"
43
44#define MY_NAME "transmission"
45
46static char * gl_confdir = NULL;
47static char * gl_lockpath = NULL;
48
49/* errstr may be NULL, this might be called before GTK is initialized */
50gboolean
51cf_init( const char   * configDir,
52         char        ** errstr )
53{
54    if( errstr != NULL )
55        *errstr = NULL;
56
57    gl_confdir = g_strdup( configDir );
58
59    if( mkdir_p( gl_confdir, 0755 ) )
60        return TRUE;
61
62    if( errstr != NULL )
63        *errstr = g_strdup_printf( _( "Couldn't create \"%1$s\": %2$s" ),
64                                  gl_confdir, g_strerror( errno ) );
65
66    return FALSE;
67}
68
69/***
70****
71****  Lockfile
72****
73***/
74
75/* errstr may be NULL, this might be called before GTK is initialized */
76static gboolean
77lockfile( const char *         filename,
78          tr_lockfile_state_t *tr_state,
79          char **              errstr )
80{
81    const tr_lockfile_state_t state = tr_lockfile( filename );
82    const gboolean            success = state == TR_LOCKFILE_SUCCESS;
83
84    if( errstr ) switch( state )
85        {
86            case TR_LOCKFILE_EOPEN:
87                *errstr =
88                    g_strdup_printf( _( "Couldn't open \"%1$s\": %2$s" ),
89                                    filename, g_strerror( errno ) );
90                break;
91
92            case TR_LOCKFILE_ELOCK:
93                *errstr = g_strdup_printf( _( "%s is already running." ),
94                                          g_get_application_name( ) );
95                break;
96
97            case TR_LOCKFILE_SUCCESS:
98                *errstr = NULL;
99                break;
100        }
101
102    if( tr_state != NULL )
103        *tr_state = state;
104
105    return success;
106}
107
108static char*
109getLockFilename( void )
110{
111    assert( gl_confdir != NULL );
112    return g_build_filename( gl_confdir, "lock", NULL );
113}
114
115static void
116cf_removelocks( void )
117{
118    if( gl_lockpath )
119    {
120        g_unlink( gl_lockpath );
121        g_free( gl_lockpath );
122    }
123}
124
125/* errstr may be NULL, this might be called before GTK is initialized */
126gboolean
127cf_lock( tr_lockfile_state_t *tr_state,
128         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 char*
147getPrefsFilename( void )
148{
149    assert( gl_confdir != NULL );
150    return g_build_filename( gl_confdir, "settings.json", NULL );
151}
152
153static tr_benc*
154getPrefs( void )
155{
156    static tr_benc settings;
157    static gboolean loaded = FALSE;
158
159    if( !loaded )
160    {
161        tr_bencInitDict( &settings, 0 );
162        tr_sessionLoadSettings( &settings, gl_confdir, MY_NAME );
163        loaded = TRUE;
164    }
165
166    return &settings;
167}
168
169/***
170****
171***/
172
173tr_benc*
174pref_get_all( void )
175{
176    return getPrefs( );
177}
178
179int64_t
180pref_int_get( const char * key )
181{
182    int64_t i = 0;
183
184    tr_bencDictFindInt( getPrefs( ), key, &i );
185    return i;
186}
187
188void
189pref_int_set( const char * key,
190              int64_t      value )
191{
192    tr_benc * d = getPrefs( );
193
194    tr_bencDictRemove( d, key );
195    tr_bencDictAddInt( d, key, value );
196}
197
198void
199pref_int_set_default( const char * key,
200                      int64_t      value )
201{
202    if( !tr_bencDictFind( getPrefs( ), key ) )
203        pref_int_set( key, value );
204}
205
206/***
207****
208***/
209
210gboolean
211pref_flag_get( const char * key )
212{
213    int64_t i;
214
215    tr_bencDictFindInt( getPrefs( ), key, &i );
216    return i != 0;
217}
218
219gboolean
220pref_flag_eval( pref_flag_t  val,
221                const char * key )
222{
223    switch( val )
224    {
225        case PREF_FLAG_TRUE:
226            return TRUE;
227
228        case PREF_FLAG_FALSE:
229            return FALSE;
230
231        default:
232            return pref_flag_get( key );
233    }
234}
235
236void
237pref_flag_set( const char * key,
238               gboolean     value )
239{
240    pref_int_set( key, value != 0 );
241}
242
243void
244pref_flag_set_default( const char * key,
245                       gboolean     value )
246{
247    pref_int_set_default( key, value != 0 );
248}
249
250/***
251****
252***/
253
254const char*
255pref_string_get( const char * key )
256{
257    const char * str = NULL;
258
259    tr_bencDictFindStr( getPrefs( ), key, &str );
260    return str;
261}
262
263void
264pref_string_set( const char * key,
265                 const char * value )
266{
267    tr_benc * d = getPrefs( );
268
269    tr_bencDictRemove( d, key );
270    tr_bencDictAddStr( d, key, value );
271}
272
273void
274pref_string_set_default( const char * key,
275                         const char * value )
276{
277    if( !tr_bencDictFind( getPrefs( ), key ) )
278        pref_string_set( key, value );
279}
280
281/***
282****
283***/
284
285void
286pref_save( tr_session * session )
287{
288    tr_sessionSaveSettings( session, gl_confdir, getPrefs( ) );
289}
290
291/***
292****
293***/
294
295#if !GLIB_CHECK_VERSION( 2, 8, 0 )
296static void
297tr_file_set_contents( const char *   filename,
298                      const void *   out,
299                      size_t         len,
300                      GError* unused UNUSED )
301{
302    FILE * fp = fopen( filename, "wb+" );
303
304    if( fp != NULL )
305    {
306        fwrite( out, 1, len, fp );
307        fclose( fp );
308    }
309}
310
311 #define g_file_set_contents tr_file_set_contents
312#endif
313
314static char*
315getCompat080PrefsFilename( void )
316{
317    assert( gl_confdir != NULL );
318
319    return g_build_filename( g_get_home_dir( ), ".transmission", "gtk", "prefs", NULL );
320}
321
322static char*
323getCompat090PrefsFilename( void )
324{
325    assert( gl_confdir != NULL );
326
327    return g_build_filename( g_get_home_dir( ), ".transmission", "gtk", "prefs.ini", NULL );
328}
329
330static char*
331getCompat121PrefsFilename( void )
332{
333    return g_build_filename( g_get_user_config_dir( ), "transmission", "gtk", "prefs.ini", NULL );
334}
335
336static void
337translate_08_to_09( const char* oldfile,
338                    const char* newfile )
339{
340    static struct pref_entry {
341        const char*   oldkey;
342        const char*   newkey;
343    } pref_table[] = {
344        { "add-behavior-ipc",       "add-behavior-ipc"               },
345        { "add-behavior-standard",  "add-behavior-standard"          },
346        { "download-directory",     "default-download-directory"     },
347        { "download-limit",         "download-limit"                 },
348        { "use-download-limit",     "download-limit-enabled"         },
349        { "listening-port",         "listening-port"                 },
350        { "use-nat-traversal",      "nat-traversal-enabled"          },
351        { "use-peer-exchange",      "pex-enabled"                    },
352        { "ask-quit",               "prompt-before-exit"             },
353        { "ask-download-directory", "prompt-for-download-directory"  },
354        { "use-tray-icon",          "system-tray-icon-enabled"       },
355        { "upload-limit",           "upload-limit"                   },
356        { "use-upload-limit",       "upload-limit-enabled"           }
357    };
358
359    GString * out = g_string_new( NULL );
360    gchar *   contents = NULL;
361    gsize     contents_len = 0;
362    tr_benc   top;
363
364    memset( &top, 0, sizeof( tr_benc ) );
365
366    if( g_file_get_contents( oldfile, &contents, &contents_len, NULL )
367      && !tr_bencLoad( contents, contents_len, &top, NULL )
368      && top.type == TYPE_DICT )
369    {
370        unsigned int i;
371        g_string_append( out, "\n[general]\n" );
372        for( i = 0; i < G_N_ELEMENTS( pref_table ); ++i )
373        {
374            const tr_benc * val = tr_bencDictFind( &top,
375                                                   pref_table[i].oldkey );
376            if( val != NULL )
377            {
378                const char * valstr = val->val.s.s;
379                if( !strcmp( valstr, "yes" ) ) valstr = "true";
380                if( !strcmp( valstr, "no" ) ) valstr = "false";
381                g_string_append_printf( out, "%s=%s\n",
382                                        pref_table[i].newkey,
383                                        valstr );
384            }
385        }
386    }
387
388    g_file_set_contents( newfile, out->str, out->len, NULL );
389    g_string_free( out, TRUE );
390    g_free( contents );
391}
392
393static void
394translate_keyfile_to_json( const char * old_file,
395                           const char * new_file )
396{
397    tr_benc    dict;
398    GKeyFile * keyfile;
399    gchar **   keys;
400    gsize      i;
401    gsize      length;
402
403    static struct pref_entry {
404        const char*   oldkey;
405        const char*   newkey;
406    } renamed[] = {
407        { "default-download-directory", "download-dir"             },
408        { "encrypted-connections-only", "encryption"               },
409        { "listening-port",             "peer-port"                },
410        { "nat-traversal-enabled",      "port-forwarding-enabled"  },
411        { "open-dialog-folder",         "open-dialog-dir"          },
412        { "watch-folder",               "watch-dir"                },
413        { "watch-folder-enabled",       "watch-dir-enabled"        }
414    };
415
416    keyfile = g_key_file_new( );
417    g_key_file_load_from_file( keyfile, old_file, 0, NULL );
418    length = 0;
419    keys = g_key_file_get_keys( keyfile, "general", &length, NULL );
420
421    tr_bencInitDict( &dict, length );
422    for( i = 0; i < length; ++i )
423    {
424        guint        j;
425        const char * key = keys[i];
426        gchar *      val = g_key_file_get_value( keyfile, "general", key,
427                                                 NULL );
428
429        for( j = 0; j < G_N_ELEMENTS( renamed ); ++j )
430            if( !strcmp( renamed[j].oldkey, key ) )
431                key = renamed[j].newkey;
432
433        if( !strcmp( val, "true" ) || !strcmp( val, "false" ) )
434            tr_bencDictAddInt( &dict, key, !strcmp( val, "true" ) );
435        else
436        {
437            char * end;
438            long   l;
439            errno = 0;
440            l = strtol( val, &end, 10 );
441            if( !errno && end && !*end )
442                tr_bencDictAddInt( &dict, key, l );
443            else
444                tr_bencDictAddStr( &dict, key, val );
445        }
446
447        g_free( val );
448    }
449
450    g_key_file_free( keyfile );
451    tr_bencSaveJSONFile( new_file, &dict );
452    tr_bencFree( &dict );
453}
454
455void
456cf_check_older_configs( void )
457{
458    char * filename = getPrefsFilename( );
459
460    if( !g_file_test( filename, G_FILE_TEST_IS_REGULAR ) )
461    {
462        char * key1 = getCompat121PrefsFilename( );
463        char * key2 = getCompat090PrefsFilename( );
464        char * benc = getCompat080PrefsFilename( );
465
466        if( g_file_test( key1, G_FILE_TEST_IS_REGULAR ) )
467        {
468            translate_keyfile_to_json( key1, filename );
469        }
470        else if( g_file_test( key2, G_FILE_TEST_IS_REGULAR ) )
471        {
472            translate_keyfile_to_json( key2, filename );
473        }
474        else if( g_file_test( benc, G_FILE_TEST_IS_REGULAR ) )
475        {
476            char * tmpfile;
477            int    fd =
478                g_file_open_tmp( "transmission-prefs-XXXXXX", &tmpfile,
479                                 NULL );
480            if( fd != -1 ) close( fd );
481            translate_08_to_09( benc, tmpfile );
482            translate_keyfile_to_json( tmpfile, filename );
483            unlink( tmpfile );
484        }
485
486        g_free( benc );
487        g_free( key2 );
488        g_free( key1 );
489    }
490
491    g_free( filename );
492}
493
Note: See TracBrowser for help on using the repository browser.