source: trunk/gtk/tr-torrent.c @ 7693

Last change on this file since 7693 was 7693, checked in by charles, 12 years ago

(trunk gtk) #1690: Torrent is completed without ever starting (because there's nothing to download)

  • Property svn:keywords set to Date Rev Author Id
File size: 9.3 KB
RevLine 
[760]1/******************************************************************************
2 * $Id: tr-torrent.c 7693 2009-01-13 01:44:59Z charles $
3 *
[4404]4 * Copyright (c) 2006-2008 Transmission authors and contributors
[760]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 *****************************************************************************/
[260]24
[248]25#include <string.h>
26#include <unistd.h>
27
28#include <gtk/gtk.h>
29#include <glib/gi18n.h>
30
[2400]31#include <libtransmission/transmission.h>
[248]32
[5122]33#include "tr-prefs.h"
34#include "tr-torrent.h"
[3206]35#include "conf.h"
[5100]36#include "notify.h"
[248]37#include "util.h"
38
[5005]39struct TrTorrentPrivate
40{
[6795]41    tr_torrent *  handle;
42    gboolean      do_remove;
[5005]43};
44
45
[248]46static void
[6795]47tr_torrent_init( GTypeInstance *  instance,
48                 gpointer g_class UNUSED )
[1654]49{
[6795]50    TrTorrent *               self = TR_TORRENT( instance );
[5005]51    struct TrTorrentPrivate * p;
[248]52
[5005]53    p = self->priv = G_TYPE_INSTANCE_GET_PRIVATE( self,
54                                                  TR_TORRENT_TYPE,
55                                                  struct TrTorrentPrivate );
56    p->handle = NULL;
57
[1914]58#ifdef REFDBG
[5005]59    g_message( "torrent %p init", self );
[1914]60#endif
[5005]61}
[1914]62
[5005]63static int
[5989]64isDisposed( const TrTorrent * tor )
[5005]65{
[5989]66    return !tor || !TR_IS_TORRENT( tor ) || !tor->priv;
[248]67}
68
69static void
[5005]70tr_torrent_dispose( GObject * o )
[3381]71{
[5015]72    GObjectClass * parent;
[6795]73    TrTorrent *    self = TR_TORRENT( o );
[248]74
[5005]75    if( !isDisposed( self ) )
76    {
77        if( self->priv->handle )
[5066]78        {
[5868]79            if( self->priv->do_remove )
80                tr_torrentRemove( self->priv->handle );
[5066]81            else
[5880]82                tr_torrentFree( self->priv->handle );
[5066]83        }
84
[5005]85        self->priv = NULL;
86    }
[248]87
[6795]88    parent = g_type_class_peek( g_type_parent( TR_TORRENT_TYPE ) );
[5005]89    parent->dispose( o );
[248]90}
91
[6344]92void
93tr_torrent_clear( TrTorrent * tor )
94{
95    g_return_if_fail( tor );
96    g_return_if_fail( tor->priv );
97
98    tor->priv->handle = NULL;
99}
100
[3381]101static void
[6795]102tr_torrent_class_init( gpointer              g_class,
103                       gpointer g_class_data UNUSED )
[3381]104{
[6795]105    GObjectClass *gobject_class = G_OBJECT_CLASS( g_class );
106
[5005]107    gobject_class->dispose = tr_torrent_dispose;
[5015]108    g_type_class_add_private( g_class, sizeof( struct TrTorrentPrivate ) );
[3381]109}
110
111GType
[5015]112tr_torrent_get_type( void )
[3381]113{
[6795]114    static GType type = 0;
[3381]115
[6795]116    if( !type )
117    {
118        static const GTypeInfo info = {
119            sizeof ( TrTorrentClass ),
120            NULL,                     /* base_init */
121            NULL,                     /* base_finalize */
122            tr_torrent_class_init,    /* class_init */
123            NULL,                     /* class_finalize */
124            NULL,                     /* class_data */
125            sizeof ( TrTorrent ),
126            0,                        /* n_preallocs */
127            tr_torrent_init,          /* instance_init */
128            NULL,
129        };
130        type = g_type_register_static( G_TYPE_OBJECT, "TrTorrent", &info, 0 );
131    }
132    return type;
[3381]133}
134
[3111]135tr_torrent *
[6795]136tr_torrent_handle( TrTorrent *tor )
[2202]137{
[5005]138    return isDisposed( tor ) ? NULL : tor->priv->handle;
[248]139}
140
[3111]141const tr_stat *
[6795]142tr_torrent_stat( TrTorrent *tor )
[2202]143{
[5005]144    tr_torrent * handle = tr_torrent_handle( tor );
[6795]145
[5005]146    return handle ? tr_torrentStatCached( handle ) : NULL;
[248]147}
148
[3111]149const tr_info *
[5005]150tr_torrent_info( TrTorrent * tor )
151{
152    tr_torrent * handle = tr_torrent_handle( tor );
[6795]153
[5005]154    return handle ? tr_torrentInfo( handle ) : NULL;
[248]155}
156
[5100]157static gboolean
158notifyInMainThread( gpointer user_data )
159{
[5480]160    tr_notify_send( TR_TORRENT( user_data ) );
[5100]161    return FALSE;
162}
[6795]163
[5100]164static void
[7693]165completenessChangedCallback( tr_torrent       * tor,
[6935]166                             tr_completeness    completeness,
167                             void *             user_data )
[5100]168{
[7693]169    if( ( completeness != TR_LEECH ) && ( tr_torrentStat( tor )->sizeWhenDone != 0 ) )
[5100]170        g_idle_add( notifyInMainThread, user_data );
171}
[6795]172
[1918]173static TrTorrent *
[6935]174maketorrent( tr_torrent * tor )
[1918]175{
[6935]176    TrTorrent * gtor = g_object_new( TR_TORRENT_TYPE, NULL );
[6795]177
[6935]178    gtor->priv->handle = tor;
179    tr_torrentSetCompletenessCallback( tor, completenessChangedCallback, gtor );
180    return gtor;
[1918]181}
182
[2463]183TrTorrent*
[3111]184tr_torrent_new_preexisting( tr_torrent * tor )
[2463]185{
186    return maketorrent( tor );
187}
188
[248]189TrTorrent *
[6978]190tr_torrent_new_ctor( tr_session   * session,
191                     tr_ctor      * ctor,
192                     char        ** err )
[1918]193{
[5015]194    tr_torrent * tor;
[6795]195    int          errcode;
196    uint8_t      doTrash = FALSE;
[248]197
[5015]198    errcode = -1;
199    *err = NULL;
[248]200
[6279]201    /* let the gtk client handle the removal, since libT
202     * doesn't have any concept of the glib trash API */
203    tr_ctorGetDeleteSource( ctor, &doTrash );
[5230]204    tr_ctorSetDeleteSource( ctor, FALSE );
[6978]205    tor = tr_torrentNew( session, ctor, &errcode );
[5230]206
[6279]207    if( tor && doTrash )
[6836]208    {
[6978]209        const char * config = tr_sessionGetConfigDir( session );
[6836]210        const char * source = tr_ctorGetSourceFile( ctor );
211        const int is_internal = source && ( strstr( source, config ) == source );
[6795]212
[6836]213        /* #1294: don't delete the source .torrent file if it's our internal copy */
214        if( !is_internal )
215            tr_file_trash_or_unlink( source );
216    }
217
[5015]218    if( !tor )
219    {
220        const char * filename = tr_ctorGetSourceFile( ctor );
221        if( !filename )
222            filename = "(null)";
[248]223
[5015]224        switch( errcode )
225        {
226            case TR_EINVALID:
[6795]227                *err =
228                    g_strdup_printf( _(
229                                         "File \"%s\" isn't a valid torrent" ),
230                                     filename );
231                break;
232
[5015]233            case TR_EDUPLICATE:
[6795]234                *err = g_strdup_printf( _(
235                                            "File \"%s\" is already open" ),
236                                        filename );
[5015]237                break;
[6795]238
[5015]239            default:
240                *err = g_strdup( filename );
241                break;
242        }
[248]243
[5015]244        return NULL;
[1936]245    }
246
[5015]247    return maketorrent( tor );
[1936]248}
249
[1998]250char *
[6795]251tr_torrent_status_str( TrTorrent * gtor )
[1998]252{
[6795]253    char *          top = NULL;
[1998]254
[3111]255    const tr_stat * st = tr_torrent_stat( gtor );
[1998]256
[6795]257    const int       tpeers = MAX ( st->peersConnected, 0 );
258    const int       upeers = MAX ( st->peersGettingFromUs, 0 );
259    const int       eta = st->eta;
[1998]260
[6935]261    switch( st->activity )
[1998]262    {
[2202]263        case TR_STATUS_CHECK_WAIT:
[6795]264            top =
265                g_strdup_printf( _(
266                                     "Waiting to verify local data (%.1f%% tested)" ),
[6796]267                                 st->recheckProgress * 100.0 );
[2202]268            break;
269
270        case TR_STATUS_CHECK:
[6795]271            top =
272                g_strdup_printf( _(
273                                     "Verifying local data (%.1f%% tested)" ),
[6796]274                                 st->recheckProgress * 100.0 );
[2202]275            break;
276
277        case TR_STATUS_DOWNLOAD:
[5539]278
[6474]279            if( eta < 0 )
[6796]280                top = g_strdup_printf( _( "Remaining time unknown" ) );
[6795]281            else
282            {
[4338]283                char timestr[128];
284                tr_strltime( timestr, eta, sizeof( timestr ) );
[6796]285                /* %s is # of minutes */
286                top = g_strdup_printf( _( "%1$s remaining" ), timestr );
[2202]287            }
288            break;
289
290        case TR_STATUS_SEED:
291            top = g_strdup_printf(
[5313]292                ngettext( "Seeding to %1$'d of %2$'d connected peer",
[6795]293                          "Seeding to %1$'d of %2$'d connected peers",
294                          tpeers ),
295                upeers, tpeers );
[2202]296            break;
297
298        case TR_STATUS_STOPPED:
[6796]299            top = g_strdup( _( "Stopped" ) );
[2202]300            break;
301
302        default:
[6796]303            top = g_strdup( "???" );
[2202]304            break;
[1998]305    }
306
307    return top;
308}
[5064]309
310void
[6795]311tr_torrent_set_remove_flag( TrTorrent * gtor,
312                            gboolean    do_remove )
[5066]313{
314    if( !isDisposed( gtor ) )
[5868]315        gtor->priv->do_remove = do_remove;
[5066]316}
317
318void
[5064]319tr_torrent_delete_files( TrTorrent * gtor )
320{
[7473]321    tr_torrentDeleteLocalData( tr_torrent_handle( gtor ), tr_file_trash_or_unlink );
[5064]322}
[5583]323
324void
325tr_torrent_open_folder( TrTorrent * gtor )
326{
[6795]327    tr_torrent *    tor = tr_torrent_handle( gtor );
[5583]328    const tr_info * info = tr_torrent_info( gtor );
[6795]329    char *          path = info->fileCount == 1
330                           ? g_build_filename( tr_torrentGetDownloadDir(
331                                                   tor ), NULL )
332                           : g_build_filename( tr_torrentGetDownloadDir(
333                                                   tor ), info->name, NULL );
334
[5583]335    gtr_open_file( path );
336    g_free( path );
337}
[6795]338
Note: See TracBrowser for help on using the repository browser.