source: trunk/gtk/conf.c @ 5167

Last change on this file since 5167 was 5167, checked in by charles, 14 years ago

add win32/posix wrapper function tr_lockfile() to libT and use it in daemon/gtk.

  • Property svn:keywords set to Date Rev Author Id
File size: 8.7 KB
Line 
1/******************************************************************************
2 * $Id: conf.c 5167 2008-02-28 19:06:23Z 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
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_build_filename( dir, "gtk", NULL );
55
56    if( mkdir_p(gl_confdir, 0755 ) )
57        return TRUE;
58
59    if( errstr != NULL )
60        *errstr = g_strdup_printf( _("Failed to create the directory %s:\n%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, char **errstr)
75{
76    const int 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( _("Failed to open lockfile %s: %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    return success;
94}
95
96static char*
97getLockFilename( void )
98{
99    assert( gl_confdir != NULL );
100    return g_build_filename( gl_confdir, "lock", NULL );
101}
102
103static void
104cf_removelocks( void )
105{
106    g_unlink( gl_lockpath );
107    g_free( gl_lockpath );
108}
109
110/* errstr may be NULL, this might be called before GTK is initialized */
111gboolean
112cf_lock( char ** errstr )
113{
114    char * path = getLockFilename( );
115    const gboolean didLock = lockfile( path, errstr );
116    if( didLock )
117        gl_lockpath = g_strdup( path );
118    g_atexit( cf_removelocks );
119    g_free( path );
120    return didLock;
121}
122
123char*
124cf_sockname( void )
125{
126    assert( gl_confdir != NULL );
127    return g_build_filename( gl_confdir, "socket", NULL );
128}
129
130/***
131****
132****  Preferences
133****
134***/
135
136#define GROUP "general"
137
138static char*
139getPrefsFilename( void )
140{
141    assert( gl_confdir != NULL );
142    return g_build_filename( gl_confdir, "prefs.ini", NULL );
143}
144
145static GKeyFile*
146getPrefsKeyFile( void )
147{
148    static GKeyFile * myKeyFile = NULL;
149
150    if( myKeyFile == NULL )
151    {
152        char * filename = getPrefsFilename( );
153        myKeyFile = g_key_file_new( );
154        g_key_file_load_from_file( myKeyFile, filename, 0, NULL );
155        g_free( filename );
156    }
157
158    return myKeyFile;
159}
160
161int
162pref_int_get( const char * key ) {
163    return g_key_file_get_integer( getPrefsKeyFile( ), GROUP, key, NULL );
164}
165void
166pref_int_set( const char * key, int value ) {
167    g_key_file_set_integer( getPrefsKeyFile( ), GROUP, key, value );
168}
169void
170pref_int_set_default( const char * key, int value ) {
171    if( !g_key_file_has_key( getPrefsKeyFile( ), GROUP, key, NULL ) )
172        pref_int_set( key, value );
173}
174
175gboolean
176pref_flag_get ( const char * key ) {
177    return g_key_file_get_boolean( getPrefsKeyFile( ), GROUP, key, NULL );
178}
179void
180pref_flag_set( const char * key, gboolean value ) {
181    g_key_file_set_boolean( getPrefsKeyFile( ), GROUP, key, value );
182}
183void
184pref_flag_set_default( const char * key, gboolean value ) {
185    if( !g_key_file_has_key( getPrefsKeyFile( ), GROUP, key, NULL ) )
186        pref_flag_set( key, value );
187}
188
189char*
190pref_string_get( const char * key ) {
191    return g_key_file_get_string( getPrefsKeyFile( ), GROUP, key, NULL );
192}
193void
194pref_string_set( const char * key, const char * value ) {
195    g_key_file_set_string( getPrefsKeyFile( ), GROUP, key, value );
196}
197void
198pref_string_set_default( const char * key, const char * value ) {
199    if( !g_key_file_has_key( getPrefsKeyFile( ), GROUP, key, NULL ) )
200        pref_string_set( key, value );
201}
202
203void
204pref_save(char **errstr)
205{
206    gsize datalen;
207    GError * err = NULL;
208    char * data;
209    char * filename;
210    char * path;
211
212    filename = getPrefsFilename( );
213    path = g_path_get_dirname( filename );
214    mkdir_p( path, 0755 );
215
216    data = g_key_file_to_data( getPrefsKeyFile(), &datalen, &err );
217    if( !err ) {
218        GIOChannel * out = g_io_channel_new_file( filename, "w+", &err );
219        g_io_channel_write_chars( out, data, datalen, NULL, &err );
220        g_io_channel_unref( out );
221    }
222
223    if( errstr != NULL )
224        *errstr = err ? g_strdup( err->message ) : NULL;
225
226    g_clear_error( &err );
227    g_free( data );
228    g_free( path );
229    g_free( filename );
230}
231
232/***
233****
234***/
235
236#if !GLIB_CHECK_VERSION(2,8,0)
237static void
238tr_file_set_contents( const char * filename, const void * out, size_t len, GError* unused UNUSED )
239{
240    FILE * fp = fopen( filename, "wb+" );
241    if( fp != NULL ) {
242        fwrite( out, 1, len, fp );
243        fclose( fp );
244    }
245}
246#define g_file_set_contents tr_file_set_contents
247#endif
248
249static char*
250getCompat08PrefsFilename( void )
251{
252    assert( gl_confdir != NULL );
253    return g_build_filename( gl_confdir, "prefs", NULL );
254}
255
256static void
257translate_08_to_09( const char* oldfile, const char* newfile )
258{
259    static struct pref_entry {
260        const char* oldkey;
261        const char* newkey;
262    } pref_table[] = {
263        { "add-behavior-ipc",       "add-behavior-ipc"},
264        { "add-behavior-standard",  "add-behavior-standard"},
265        { "download-directory",     "default-download-directory"},
266        { "download-limit",         "download-limit"},
267        { "use-download-limit",     "download-limit-enabled" },
268        { "listening-port",         "listening-port"},
269        { "use-nat-traversal",      "nat-traversal-enabled"},
270        { "use-peer-exchange",      "pex-enabled"},
271        { "ask-quit",               "prompt-before-exit"},
272        { "ask-download-directory", "prompt-for-download-directory"},
273        { "use-tray-icon",          "system-tray-icon-enabled"},
274        { "upload-limit",           "upload-limit"},
275        { "use-upload-limit",       "upload-limit-enabled"}
276    };
277
278    GString * out = g_string_new( NULL );
279    gchar * contents = NULL;
280    gsize contents_len = 0;
281    tr_benc top;
282
283    memset( &top, 0, sizeof(tr_benc) );
284
285    if( g_file_get_contents( oldfile, &contents, &contents_len, NULL )
286        && !tr_bencLoad( contents, contents_len, &top, NULL )
287        && top.type==TYPE_DICT )
288    {
289        unsigned int i;
290        g_string_append( out, "\n[general]\n" );
291        for ( i=0; i<G_N_ELEMENTS(pref_table); ++i ) {
292            const tr_benc * val = tr_bencDictFind( &top, pref_table[i].oldkey );
293            if( val != NULL ) {
294                const char * valstr = val->val.s.s;
295                if( !strcmp( valstr, "yes" ) ) valstr = "true";
296                if( !strcmp( valstr, "no" ) ) valstr = "false";
297                g_string_append_printf( out, "%s=%s\n", pref_table[i].newkey, valstr );
298            }
299        }
300    }
301
302    g_file_set_contents( newfile, out->str, out->len, NULL );
303    g_string_free( out, TRUE );
304    g_free( contents );
305}
306
307void
308cf_check_older_configs( void )
309{
310    char * cfn = getPrefsFilename( );
311    char * cfn08 = getCompat08PrefsFilename( );
312
313    if( !g_file_test( cfn,   G_FILE_TEST_IS_REGULAR )
314      && g_file_test( cfn08, G_FILE_TEST_IS_REGULAR ) )
315        translate_08_to_09( cfn08, cfn );
316
317    g_free( cfn08 );
318    g_free( cfn );
319}
Note: See TracBrowser for help on using the repository browser.