source: trunk/gtk/conf.c @ 6559

Last change on this file since 6559 was 6559, checked in by muks, 13 years ago

Don't show an error when transmission is run twice

Instead, present the main window. This commit also auto-generates
the dbus bindings.

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