static int compareByName( GtkTreeModel * m, GtkTreeIter * a, GtkTreeIter * b, gpointer user_data UNUSED ) { int ret = 0; if( !ret ) { char *ca, *cb; gtk_tree_model_get( m, a, MC_NAME_COLLATED, &ca, -1 ); gtk_tree_model_get( m, b, MC_NAME_COLLATED, &cb, -1 ); ret = gtr_strcmp0( ca, cb ); g_free( cb ); g_free( ca ); } if( !ret ) { tr_torrent * t; const tr_info *ia, *ib; gtk_tree_model_get( m, a, MC_TORRENT_RAW, &t, -1 ); ia = tr_torrentInfo( t ); gtk_tree_model_get( m, b, MC_TORRENT_RAW, &t, -1 ); ib = tr_torrentInfo( t ); ret = memcmp( ia->hash, ib->hash, SHA_DIGEST_LENGTH ); } return ret; }
bool TorrentObject::LoadFromPath(const tr_session* Session, const char* TorrentPath) { tr_ctor* ctor = tr_ctorNew(Session); tr_ctorSetPaused(ctor, TR_FORCE, TRUE); if( tr_ctorSetMetainfoFromFile(ctor, TorrentPath) != TR_PARSE_OK ) return false; // // fTorrentHandle = tr_torrentNew(ctor, NULL); tr_ctorFree(ctor); if( fTorrentHandle == NULL ) return false; fInfo = tr_torrentInfo(fTorrentHandle); fStatistics = tr_torrentStat(fTorrentHandle); return true; }
static char* getResumeFilename(tr_torrent const* tor) { char* base = tr_metainfoGetBasename(tr_torrentInfo(tor)); char* filename = tr_strdup_printf("%s" TR_PATH_DELIMITER_STR "%s.resume", tr_getResumeDir(tor->session), base); tr_free(base); return filename; }
static void get_size_full( TorrentCellRenderer * cell, GtkWidget * widget, gint * width, gint * height ) { int w, h; GdkRectangle icon_area; GdkRectangle name_area; GdkRectangle stat_area; GdkRectangle prog_area; const char * name; char * status; char * progress; GdkPixbuf * icon; GtkCellRenderer * text_renderer; struct TorrentCellRendererPrivate * p = cell->priv; const tr_torrent * tor = p->tor; const tr_stat * st = tr_torrentStatCached( (tr_torrent*)tor ); const tr_info * inf = tr_torrentInfo( tor ); icon = get_icon( tor, FULL_ICON_SIZE, widget ); name = inf->name; status = getStatusString( tor, st, p->upload_speed, p->download_speed ); progress = getProgressString( tor, inf, st ); /* get the idealized cell dimensions */ g_object_set( p->icon_renderer, "pixbuf", icon, NULL ); gtk_cell_renderer_get_size( p->icon_renderer, widget, NULL, NULL, NULL, &w, &h ); icon_area.width = w; icon_area.height = h; text_renderer = get_text_renderer( st, cell ); g_object_set( text_renderer, "text", name, "weight", PANGO_WEIGHT_BOLD, "scale", 1.0, "ellipsize", PANGO_ELLIPSIZE_NONE, NULL ); gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w, &h ); name_area.width = w; name_area.height = h; g_object_set( text_renderer, "text", progress, "weight", PANGO_WEIGHT_NORMAL, "scale", SMALL_SCALE, NULL ); gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w, &h ); prog_area.width = w; prog_area.height = h; g_object_set( text_renderer, "text", status, NULL ); gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w, &h ); stat_area.width = w; stat_area.height = h; /** *** LAYOUT **/ if( width != NULL ) *width = cell->parent.xpad * 2 + icon_area.width + GUI_PAD + MAX3( name_area.width, prog_area.width, stat_area.width ); if( height != NULL ) *height = cell->parent.ypad * 2 + name_area.height + prog_area.height + GUI_PAD_SMALL + p->bar_height + GUI_PAD_SMALL + stat_area.height; /* cleanup */ g_free( status ); g_free( progress ); g_object_unref( icon ); }
static void get_size_full( TorrentCellRenderer * cell, GtkWidget * widget, gint * width, gint * height ) { int w, h; int xpad, ypad; GdkRectangle icon_area; GdkRectangle name_area; GdkRectangle stat_area; GdkRectangle prog_area; const char * name; GdkPixbuf * icon; struct TorrentCellRendererPrivate * p = cell->priv; const tr_torrent * tor = p->tor; const tr_stat * st = tr_torrentStatCached( (tr_torrent*)tor ); const tr_info * inf = tr_torrentInfo( tor ); GString * gstr_prog = p->gstr1; GString * gstr_stat = p->gstr2; icon = get_icon( tor, FULL_ICON_SIZE, widget ); name = tr_torrentName( tor ); g_string_truncate( gstr_stat, 0 ); getStatusString( gstr_stat, tor, st, p->upload_speed_KBps, p->download_speed_KBps ); g_string_truncate( gstr_prog, 0 ); getProgressString( gstr_prog, tor, inf, st ); gtr_cell_renderer_get_padding( GTK_CELL_RENDERER( cell ), &xpad, &ypad ); /* get the idealized cell dimensions */ g_object_set( p->icon_renderer, "pixbuf", icon, NULL ); gtk_cell_renderer_get_size( p->icon_renderer, widget, NULL, NULL, NULL, &w, &h ); icon_area.width = w; icon_area.height = h; g_object_set( p->text_renderer, "text", name, "weight", PANGO_WEIGHT_BOLD, "scale", 1.0, "ellipsize", PANGO_ELLIPSIZE_NONE, NULL ); gtk_cell_renderer_get_size( p->text_renderer, widget, NULL, NULL, NULL, &w, &h ); name_area.width = w; name_area.height = h; g_object_set( p->text_renderer, "text", gstr_prog->str, "weight", PANGO_WEIGHT_NORMAL, "scale", SMALL_SCALE, NULL ); gtk_cell_renderer_get_size( p->text_renderer, widget, NULL, NULL, NULL, &w, &h ); prog_area.width = w; prog_area.height = h; g_object_set( p->text_renderer, "text", gstr_stat->str, NULL ); gtk_cell_renderer_get_size( p->text_renderer, widget, NULL, NULL, NULL, &w, &h ); stat_area.width = w; stat_area.height = h; /** *** LAYOUT **/ if( width != NULL ) *width = xpad * 2 + icon_area.width + GUI_PAD + MAX3( name_area.width, prog_area.width, stat_area.width ); if( height != NULL ) *height = ypad * 2 + name_area.height + prog_area.height + GUI_PAD_SMALL + p->bar_height + GUI_PAD_SMALL + stat_area.height; /* cleanup */ g_object_unref( icon ); }
int libbt_get_info(int index, struct libbt_info *pinfo) { tr_info_t *info; tr_torrent_t *tor = tor_list_get(index); if(tor) { MEMSET(pinfo, 0, sizeof(struct libbt_info)); tr_info_t* info = tr_torrentInfo( tor ); pinfo->torrent = info->torrent; pinfo->comment = info->comment; pinfo->creator = info->creator; pinfo->dateCreated = info->dateCreated; pinfo->multifile = info->multifile; pinfo->fileCount = info->fileCount; pinfo->files = (bt_file_t*)info->files; pinfo->hash = info->hash; pinfo->name = info->name; pinfo->pieceCount = info->pieceCount; pinfo->pieceSize = info->pieceSize; pinfo->totalSize = info->totalSize; pinfo->trackerList = (struct bt_tracker_list *)info->trackerList; return index; } return -1; }
static void requestNextChunk( tr_webseed * w ) { tr_torrent * tor = tr_torrentFindFromHash( w->session, w->hash ); if( tor != NULL ) { const tr_info * inf = tr_torrentInfo( tor ); const uint32_t have = EVBUFFER_LENGTH( w->content ); const uint32_t left = w->byteCount - have; const uint32_t pieceOffset = w->pieceOffset + have; tr_file_index_t fileIndex; uint64_t fileOffset; uint32_t thisPass; char * url; char * range; tr_ioFindFileLocation( tor, w->pieceIndex, pieceOffset, &fileIndex, &fileOffset ); thisPass = MIN( left, inf->files[fileIndex].length - fileOffset ); url = makeURL( w, &inf->files[fileIndex] ); /*fprintf( stderr, "url is [%s]\n", url );*/ range = tr_strdup_printf( "%"PRIu64"-%"PRIu64, fileOffset, fileOffset + thisPass - 1 ); /*fprintf( stderr, "range is [%s] ... we want %lu total, we have %lu, so %lu are left, and we're asking for %lu this time\n", range, (unsigned long)w->byteCount, (unsigned long)have, (unsigned long)left, (unsigned long)thisPass );*/ tr_webRun( w->session, url, range, webResponseFunc, w ); tr_free( range ); tr_free( url ); } }
static GtkTreeModel* tracker_model_new( tr_torrent * tor ) { int i; const tr_info * inf = tr_torrentInfo( tor ); GtkListStore * store = gtk_list_store_new( TR_N_COLS, G_TYPE_INT, G_TYPE_STRING ); for( i = 0; inf && i < inf->trackerCount; ++i ) { GtkTreeIter iter; const tr_tracker_info * tinf = inf->trackers + i; gtk_list_store_append( store, &iter ); gtk_list_store_set( store, &iter, TR_COL_TIER, tinf->tier + 1, TR_COL_ANNOUNCE, tinf->announce, -1 ); } gtk_tree_sortable_set_sort_column_id( GTK_TREE_SORTABLE( store ), TR_COL_TIER, GTK_SORT_ASCENDING ); return GTK_TREE_MODEL( store ); }
static int compareBySize( GtkTreeModel * m, GtkTreeIter * a, GtkTreeIter * b, gpointer user_data ) { int ret = 0; tr_torrent *t; const tr_info *ia, *ib; gtk_tree_model_get( m, a, MC_TORRENT_RAW, &t, -1 ); ia = tr_torrentInfo( t ); gtk_tree_model_get( m, b, MC_TORRENT_RAW, &t, -1 ); ib = tr_torrentInfo( t ); if( !ret ) ret = compareUint64( ia->totalSize, ib->totalSize ); if( !ret ) ret = compareByName( m, a, b, user_data ); return ret; }
static gboolean testText (const tr_torrent * tor, const char * key) { gboolean ret = FALSE; if (!key || !*key) { ret = TRUE; } else { tr_file_index_t i; const tr_info * inf = tr_torrentInfo (tor); /* test the torrent name... */ { char * pch = g_utf8_casefold (tr_torrentName (tor), -1); ret = !key || strstr (pch, key) != NULL; g_free (pch); } /* test the files... */ for (i=0; i<inf->fileCount && !ret; ++i) { char * pch = g_utf8_casefold (inf->files[i].name, -1); ret = !key || strstr (pch, key) != NULL; g_free (pch); } } return ret; }
bool TorrentObject::LoadFromHandle(tr_torrent* TorrentHandle) { fTorrentHandle = TorrentHandle; fInfo = tr_torrentInfo(fTorrentHandle); fStatistics = tr_torrentStat(fTorrentHandle); return true; }
uint64_t tr_cpSizeWhenDone( const tr_completion * ccp ) { if( ccp->sizeWhenDoneIsDirty ) { uint64_t size = 0; const tr_torrent * tor = ccp->tor; const tr_info * inf = tr_torrentInfo( tor ); tr_completion * cp = (tr_completion *) ccp; /* mutable */ if( tr_cpHasAll( ccp ) ) { size = inf->totalSize; } else { tr_piece_index_t p; for( p=0; p<inf->pieceCount; ++p ) { uint64_t n = 0; const uint64_t pieceSize = tr_torPieceCountBytes( tor, p ); if( !inf->pieces[p].dnd ) { n = pieceSize; } else { uint64_t o = 0; tr_block_index_t b, f, l; tr_torGetPieceBlockRange( cp->tor, p, &f, &l ); for( b=f; b<=l; ++b ) if( tr_cpBlockIsComplete( cp, b ) ) n += tr_torBlockCountBytes( tor, b ); o = tr_bitfieldCountRange( &cp->blockBitfield, f, l+1 ); o *= cp->tor->blockSize; if( l == ( cp->tor->blockCount - 1 ) && tr_bitfieldHas( &cp->blockBitfield, l ) ) o -= ( cp->tor->blockSize - cp->tor->lastBlockSize ); assert( n == o ); } assert( n <= tr_torPieceCountBytes( tor, p ) ); size += n; } } assert( size <= inf->totalSize ); assert( size >= cp->sizeNow ); cp->sizeWhenDoneLazy = size; cp->sizeWhenDoneIsDirty = false; } return ccp->sizeWhenDoneLazy; }
static void get_size_compact( TorrentCellRenderer * cell, GtkWidget * widget, gint * width, gint * height ) { int w, h; int xpad, ypad; GdkRectangle icon_area; GdkRectangle name_area; GdkRectangle stat_area; const char * name; char * status; GdkPixbuf * icon; GtkCellRenderer * text_renderer; struct TorrentCellRendererPrivate * p = cell->priv; const tr_torrent * tor = p->tor; const tr_stat * st = tr_torrentStatCached( (tr_torrent*)tor ); icon = get_icon( tor, COMPACT_ICON_SIZE, widget ); name = tr_torrentInfo( tor )->name; status = getShortStatusString( tor, st, p->upload_speed_KBps, p->download_speed_KBps ); gtr_cell_renderer_get_padding( GTK_CELL_RENDERER( cell ), &xpad, &ypad ); /* get the idealized cell dimensions */ g_object_set( p->icon_renderer, "pixbuf", icon, NULL ); gtk_cell_renderer_get_size( p->icon_renderer, widget, NULL, NULL, NULL, &w, &h ); icon_area.width = w; icon_area.height = h; text_renderer = get_text_renderer( st, cell ); g_object_set( text_renderer, "text", name, "ellipsize", PANGO_ELLIPSIZE_NONE, "scale", 1.0, NULL ); gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w, &h ); name_area.width = w; name_area.height = h; g_object_set( text_renderer, "text", status, "scale", SMALL_SCALE, NULL ); gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w, &h ); stat_area.width = w; stat_area.height = h; /** *** LAYOUT **/ #define BAR_WIDTH 50 if( width != NULL ) *width = xpad * 2 + icon_area.width + GUI_PAD + name_area.width + GUI_PAD + BAR_WIDTH + GUI_PAD + stat_area.width; if( height != NULL ) *height = ypad * 2 + MAX( name_area.height, p->bar_height ); /* cleanup */ g_free( status ); g_object_unref( icon ); }
static void saveFilePriorities (tr_variant * dict, const tr_torrent * tor) { tr_variant * list; tr_file_index_t i; const tr_info * const inf = tr_torrentInfo (tor); const tr_file_index_t n = inf->fileCount; list = tr_variantDictAddList (dict, TR_KEY_priority, n); for (i=0; i<n; ++i) tr_variantListAddInt (list, inf->files[i].priority); }
uint64_t tr_cpSizeWhenDone(tr_completion const* ccp) { if (ccp->sizeWhenDoneIsDirty) { uint64_t size = 0; tr_torrent const* tor = ccp->tor; tr_info const* inf = tr_torrentInfo(tor); tr_completion* cp = (tr_completion*)ccp; /* mutable */ if (tr_cpHasAll(ccp)) { size = inf->totalSize; } else { for (tr_piece_index_t p = 0; p < inf->pieceCount; ++p) { uint64_t n = 0; uint64_t const pieceSize = tr_torPieceCountBytes(tor, p); if (!inf->pieces[p].dnd) { n = pieceSize; } else { tr_block_index_t f; tr_block_index_t l; tr_torGetPieceBlockRange(cp->tor, p, &f, &l); n = tr_bitfieldCountRange(&cp->blockBitfield, f, l + 1); n *= cp->tor->blockSize; if (l == cp->tor->blockCount - 1 && tr_bitfieldHas(&cp->blockBitfield, l)) { n -= cp->tor->blockSize - cp->tor->lastBlockSize; } } TR_ASSERT(n <= tr_torPieceCountBytes(tor, p)); size += n; } } TR_ASSERT(size <= inf->totalSize); TR_ASSERT(size >= cp->sizeNow); cp->sizeWhenDoneLazy = size; cp->sizeWhenDoneIsDirty = false; } return ccp->sizeWhenDoneLazy; }
static void saveDND( tr_benc * dict, const tr_torrent * tor ) { tr_benc * list; tr_file_index_t i; const tr_info * const inf = tr_torrentInfo( tor ); const tr_file_index_t n = inf->fileCount; list = tr_bencDictAddList( dict, KEY_DND, n ); for( i=0; i<n; ++i ) tr_bencListAddInt( list, inf->files[i].dnd ? 1 : 0 ); }
static void saveFilePriorities( tr_benc * dict, const tr_torrent * tor ) { const tr_info * inf = tr_torrentInfo( tor ); const tr_file_index_t n = inf->fileCount; tr_file_index_t i; tr_benc * list; list = tr_bencDictAddList( dict, KEY_FILE_PRIORITIES, n ); for( i = 0; i < n; ++i ) tr_bencListAddInt( list, inf->files[i].priority ); }
static void saveDND(tr_variant* dict, tr_torrent const* tor) { tr_variant* list; tr_info const* const inf = tr_torrentInfo(tor); tr_file_index_t const n = inf->fileCount; list = tr_variantDictAddList(dict, TR_KEY_dnd, n); for (tr_file_index_t i = 0; i < n; ++i) { tr_variantListAddInt(list, inf->files[i].dnd ? 1 : 0); } }
static char * torrentTrackerString( tr_torrent * tor ) { int i; GString * str = g_string_new( NULL ); const tr_info * inf = tr_torrentInfo( tor ); for( i = 0; i < inf->trackerCount; ++i ) { const tr_tracker_info * t = &inf->trackers[i]; g_string_append( str, t->announce ); } return g_string_free( str, FALSE ); }
static GdkPixbuf* get_icon( const tr_torrent * tor, GtkIconSize icon_size, GtkWidget * for_widget ) { const char * mime_type; const tr_info * info = tr_torrentInfo( tor ); if( info->fileCount == 0 ) mime_type = UNKNOWN_MIME_TYPE; else if( info->fileCount > 1 ) mime_type = DIRECTORY_MIME_TYPE; else if( strchr( info->files[0].name, '/' ) != NULL ) mime_type = DIRECTORY_MIME_TYPE; else mime_type = gtr_get_mime_type_from_filename( info->files[0].name ); return gtr_get_mime_type_icon( mime_type, icon_size, for_widget ); }
static void startMovingNextTorrent( struct relocate_dialog_data * data ) { char * str; const int id = GPOINTER_TO_INT( data->torrent_ids->data ); tr_session * session = tr_core_session( data->core ); tr_torrent * tor = tr_torrentFindFromId( session, id ); if( tor != NULL ) tr_torrentSetLocation( tor, previousLocation, data->do_move, NULL, &data->done ); data->torrent_ids = g_slist_delete_link( data->torrent_ids, data->torrent_ids ); str = g_strdup_printf( _( "Moving \"%s\"" ), tr_torrentInfo(tor)->name ); gtk_message_dialog_set_markup( GTK_MESSAGE_DIALOG( data->message_dialog ), str ); g_free( str ); }
static void webseed_free( struct tr_webseed * w ) { tr_torrent * tor = tr_torrentFindFromId( w->session, w->torrent_id ); const tr_info * inf = tr_torrentInfo( tor ); tr_file_index_t i; for( i=0; i<inf->fileCount; ++i ) tr_free( w->file_urls[i] ); tr_free( w->file_urls ); /* webseed destruct */ event_free( w->timer ); tr_bandwidthDestruct( &w->bandwidth ); tr_free( w->base_url ); /* parent class destruct */ tr_peerDestruct( tor, &w->parent ); tr_free( w ); }
/******************************************************************************* * main ******************************************************************************/ int main(int argc, char ** argv) { /* vars */ int i, error, nat; tr_handle_t * h; tr_torrent_t * tor; tr_stat_t * s; double tf_sharing = 0.0; char tf_string[80]; int tf_seeders, tf_leechers; /* Get options */ if (parseCommandLine(argc, argv)) { printf("Transmission %s [%d] - tfCLI [%d]\nhttp://transmission.m0k.org/ - http://tf-b4rt.berlios.de/\n\n", VERSION_STRING, VERSION_REVISION, VERSION_REVISION_CLI); printf(USAGE, argv[0], TR_DEFAULT_PORT); return 1; } /* show help */ if (showHelp) { printf("Transmission %s [%d] - tfCLI [%d]\nhttp://transmission.m0k.org/ - http://tf-b4rt.berlios.de/\n\n", VERSION_STRING, VERSION_REVISION, VERSION_REVISION_CLI); printf(USAGE, argv[0], TR_DEFAULT_PORT); return 0; } // verbose if (verboseLevel < 0) { verboseLevel = 0; } else if (verboseLevel > 9) { verboseLevel = 9; } if (verboseLevel) { static char env[11]; sprintf(env, "TR_DEBUG=%d", verboseLevel); putenv(env); } // check port if (bindPort < 1 || bindPort > 65535) { printf("Invalid port '%d'\n", bindPort); return 1; } // Initialize libtransmission h = tr_init(); // Open and parse torrent file if (!(tor = tr_torrentInit(h, torrentPath, 0, &error))) { printf("Failed opening torrent file `%s'\n", torrentPath); goto failed; } /* show info */ if (showInfo) { // info tr_info_t * info = tr_torrentInfo(tor); // stat s = tr_torrentStat(tor); // Print torrent info (quite à la btshowmetainfo) printf("hash: "); for (i = 0; i < SHA_DIGEST_LENGTH; i++) { printf("%02x", info->hash[i]); } printf("\n"); printf( "tracker: %s:%d\n", s->trackerAddress, s->trackerPort ); printf( "announce: %s\n", s->trackerAnnounce ); printf("size: %"PRIu64" (%"PRIu64" * %d + %"PRIu64")\n", info->totalSize, info->totalSize / info->pieceSize, info->pieceSize, info->totalSize % info->pieceSize); if (info->comment[0]) { printf("comment: %s\n", info->comment); } if (info->creator[0]) { printf("creator: %s\n", info->creator); } printf("file(s):\n"); for (i = 0; i < info->fileCount; i++) { printf(" %s (%"PRIu64")\n", info->files[i].name, info->files[i].length); } // cleanup goto cleanup; } /* show scrape */ if (showScrape) { int seeders, leechers, downloaded; if (tr_torrentScrape(tor, &seeders, &leechers, &downloaded)) { printf("Scrape failed.\n"); } else { printf("%d seeder(s), %d leecher(s), %d download(s).\n", seeders, leechers, downloaded); } // cleanup goto cleanup; } /* start up transmission */ // Create PID file if wanted by user if (tf_pid != NULL) { FILE * pid_file; pid_file = fopen(tf_pid, "w+"); if (pid_file != NULL) { fprintf(pid_file, "%d", getpid()); fclose(pid_file); } } // signal signal(SIGINT, sigHandler); // If running torrentflux, Download limit = 0 means no limit if (tf_stat_file != NULL) { /* tfCLI */ // up switch (uploadLimit) { case 0: uploadLimit = -1; break; case -2: uploadLimit = 0; break; } // down switch (downloadLimit) { case 0: downloadLimit = -1; break; case -2: downloadLimit = 0; break; } } // init some things tr_setBindPort(h, bindPort); tr_setGlobalUploadLimit(h, uploadLimit); tr_setGlobalDownloadLimit(h, downloadLimit); // nat-traversal if (natTraversal) { tr_natTraversalEnable(h); } else { tr_natTraversalDisable(h); } // set folder tr_torrentSetFolder(tor, "."); // start the torrent tr_torrentStart(tor); /* main-loop */ while (!mustDie) { // status-string char string[80]; int chars = 0; // int result; char stat_state; // sleep sleep(displayInterval); // Check if we must stop if (tf_stat_file != NULL) { /* tfCLI */ tf_stat = fopen(tf_stat_file, "r"); if (tf_stat != NULL) { // Get state stat_state = fgetc(tf_stat); // Close the file fclose(tf_stat); // Torrentflux asked to shutdown the torrent if (stat_state == '0') { mustDie = 1; } } } // torrent-stat s = tr_torrentStat(tor); if (s->status & TR_STATUS_CHECK) { /* --- CHECK --- */ if (tf_stat_file == NULL) { /* standalone */ // status-string chars = snprintf(string, 80, "Checking files... %.2f %%", 100.0 * s->progress ); } else { /* tfCLI */ // write tf-stat-file tr_info_t * info = tr_torrentInfo(tor); tf_stat = fopen(tf_stat_file, "w+"); if (tf_stat != NULL) { fprintf(tf_stat, "%d\n%.1f\n%s\n0 kB/s\n0 kB/s\n%s\n0\n0\n0.0\n%d\n0\n%" PRIu64 "\n%" PRIu64, 1, /* State */ 100.0 * s->progress, /* checking progress */ "Checking existing data", /* State text */ /* download speed */ /* upload speed */ tf_user, /* user */ /* seeds */ /* peers */ /* sharing */ seedLimit, /* seedlimit */ /* uploaded bytes */ s->downloaded, /* downloaded bytes */ info->totalSize); /* global size */ fclose(tf_stat); } } } else if (s->status & TR_STATUS_DOWNLOAD) { /* --- DOWNLOAD --- */ if (tf_stat_file == NULL) { /* standalone */ // status-string chars = snprintf(string, 80, "Progress: %.2f %%, %d peer%s, dl from %d (%.2f KB/s), " "ul to %d (%.2f KB/s)", 100.0 * s->progress, s->peersTotal, ( s->peersTotal == 1 ) ? "" : "s", s->peersUploading, s->rateDownload, s->peersDownloading, s->rateUpload); } else { /* tfCLI */ // sharing if (s->downloaded != 0) { tf_sharing = ((double)(s->uploaded) / (double)(s->downloaded)) * 100; } // seeders + leechers if (s->seeders < 0) { tf_seeders = 0; } else { tf_seeders = s->seeders; } if (s->leechers < 0) { tf_leechers = 0; } else { tf_leechers = s->leechers; } // eta if (s->eta != -1) { // sanity-check. value of eta >= 7 days is not really of use if (s->eta < 604800) { if ((s->eta / (24 * 60 * 60)) != 0) { sprintf(tf_string,"%d:%02d:%02d:%02d", s->eta / (24 * 60 * 60), ((s->eta) % (24 * 60 * 60)) / (60 * 60), ((s->eta) % (60 * 60) / 60), s->eta % 60); } else if ((s->eta / (60 * 60)) != 0) { sprintf(tf_string, "%d:%02d:%02d", (s->eta) / (60 * 60), ((s->eta) % (60 * 60) / 60), s->eta % 60); } else { sprintf(tf_string, "%d:%02d", (s->eta) / 60, s->eta % 60); } } else { sprintf(tf_string,"-"); } } else { sprintf(tf_string,"-"); } if ((s->seeders == -1) && (s->peersTotal == 0)) { sprintf(tf_string,"Connecting to Peers"); } // write tf-stat-file tf_stat = fopen(tf_stat_file, "w+"); if (tf_stat != NULL) { tr_info_t * info = tr_torrentInfo( tor ); fprintf(tf_stat, "%d\n%.1f\n%s\n%.1f kB/s\n%.1f kB/s\n%s\n%d (%d)\n%d (%d)\n%.1f\n%d\n%" PRIu64 "\n%" PRIu64 "\n%" PRIu64, 1, /* State */ 100.0 * s->progress, /* progress */ tf_string, /* Estimated time */ s->rateDownload, /* download speed */ s->rateUpload, /* upload speed */ tf_user, /* user */ s->peersUploading, tf_seeders, /* seeds */ s->peersDownloading, tf_leechers, /* peers */ tf_sharing, /* sharing */ seedLimit, /* seedlimit */ s->uploaded, /* uploaded bytes */ s->downloaded, /* downloaded bytes */ info->totalSize); /* global size */ fclose(tf_stat); } } } else if (s->status & TR_STATUS_SEED) { /* --- SEED --- */ // info tr_info_t * info = tr_torrentInfo(tor); if (tf_stat_file == NULL) { /* standalone */ // status-string chars = snprintf(string, 80, "Seeding, uploading to %d of %d peer(s), %.2f KB/s", s->peersDownloading, s->peersTotal, s->rateUpload); } else { /* tfCLI */ // sharing if (s->downloaded != 0) { tf_sharing = ((double)(s->uploaded) / (double)(s->downloaded)) * 100; } else { tf_sharing = ((double)(s->uploaded) / (double)(info->totalSize)) * 100; } // If we reached the seeding limit, we have to quit transmission if ((seedLimit != 0) && ((tf_sharing > (double)(seedLimit)) || (seedLimit == -1))) { mustDie = 1; } // seeders + leechers if (s->seeders < 0) { tf_seeders = 0; } else { tf_seeders = s->seeders; } if (s->leechers < 0) { tf_leechers = 0; } else { tf_leechers = s->leechers; } // write tf-stat-file tf_stat = fopen(tf_stat_file, "w+"); if (tf_stat != NULL) { fprintf(tf_stat, "%d\n%.1f\n%s\n%.1f kB/s\n%.1f kB/s\n%s\n%d (%d)\n%d (%d)\n%.1f\n%d\n%" PRIu64 "\n%" PRIu64 "\n%" PRIu64, 1, /* State */ 100.0 * s->progress, /* progress */ "Download Succeeded!", /* State text */ s->rateDownload, /* download speed */ s->rateUpload, /* upload speed */ tf_user, /* user */ s->peersUploading, tf_seeders, /* seeds */ s->peersDownloading, tf_leechers, /* peers */ tf_sharing, /* sharing */ seedLimit, /* seedlimit */ s->uploaded, /* uploaded bytes */ s->downloaded, /* downloaded bytes */ info->totalSize); /* global size */ fclose(tf_stat); } } } // status-string if (tf_stat_file == NULL) { /* standalone */ memset( &string[chars], ' ', 79 - chars ); string[79] = '\0'; // print status to stderr fprintf(stderr, "\r%s", string); } // errors if (s->error & TR_ETRACKER) { if (tf_stat_file == NULL) { /* standalone */ // print errors to stderr fprintf(stderr, "\n%s\n", s->trackerError); } else { /* tfCLI */ // append errors to stat-file tf_stat = fopen(tf_stat_file, "a+"); if (tf_stat != NULL) { fprintf(tf_stat, "\n%s\n", s->trackerError); fclose(tf_stat); } } } else if (verboseLevel > 0) { if (tf_stat_file == NULL) { /* standalone */ // stderr fprintf(stderr, "\n"); } } // finishCall if (tr_getFinished(tor)) { result = system(finishCall); } } /* main-loop */ // mark torrent as stopped in tf-stat-file if (tf_stat_file != NULL) { /* tfCLI */ // info tr_info_t * info = tr_torrentInfo(tor); // sharing if (s->downloaded != 0) { tf_sharing = ((double)(s->uploaded) / (double)(s->downloaded)) * 100; } else { tf_sharing = ((double)(s->uploaded) / (double)(info->totalSize)) * 100; } // write tf-stat-file tf_stat = fopen(tf_stat_file, "w+"); if (tf_stat != NULL) { float progress; if (s->status & TR_STATUS_SEED) { sprintf(tf_string,"Download Succeeded!"); progress = 100; } else { sprintf(tf_string,"Torrent Stopped"); progress = -(1 + s->progress) * 100; } fprintf(tf_stat, "%d\n%.1f\n%s\n\n\n%s\n\n\n%.1f\n%d\n%" PRIu64 "\n%" PRIu64 "\n%" PRIu64, 0, /* State */ progress, /* progress */ tf_string, /* State text */ /* download speed */ /* upload speed */ tf_user, /* user */ /* seeds */ /* peers */ tf_sharing, /* sharing */ seedLimit, /* seedlimit */ s->uploaded, /* uploaded bytes */ s->downloaded, /* downloaded bytes */ info->totalSize); /* global size */ fclose(tf_stat); } } // stderr if (tf_stat_file == NULL) { /* standalone */ fprintf(stderr, "\n"); } // Try for 5 seconds to notify the tracker that we are leaving // and to delete any port mappings for nat traversal tr_torrentStop(tor); tr_natTraversalDisable(h); for (i = 0; i < 10; i++) { s = tr_torrentStat(tor); nat = tr_natTraversalStatus(h); if (s->status & TR_STATUS_PAUSE && TR_NAT_TRAVERSAL_DISABLED == nat) { // The 'stopped' tracker message was sent // and port mappings were deleted break; } usleep(500000); } // Remove PID file if created ! if (tf_pid != NULL) { remove(tf_pid); } cleanup: tr_torrentClose(h, tor); failed: tr_close(h); return 0; }
static gboolean category_filter_model_update( GtkTreeStore * store ) { int i, n; int low = 0; int all = 0; int high = 0; int public = 0; int normal = 0; int private = 0; int store_pos; GtkTreeIter top; GtkTreeIter iter; GtkTreeModel * model = GTK_TREE_MODEL( store ); GPtrArray * hosts = g_ptr_array_new( ); GStringChunk * strings = g_string_chunk_new( 4096 ); GHashTable * hosts_hash = g_hash_table_new_full( g_str_hash, g_str_equal, NULL, g_free ); GObject * o = G_OBJECT( store ); GtkTreeModel * tmodel = GTK_TREE_MODEL( g_object_get_qdata( o, TORRENT_MODEL_KEY ) ); g_object_steal_qdata( o, DIRTY_KEY ); /* Walk through all the torrents, tallying how many matches there are * for the various categories. Also make a sorted list of all tracker * hosts s.t. we can merge it with the existing list */ if( gtk_tree_model_iter_nth_child( tmodel, &iter, NULL, 0 ) ) do { tr_torrent * tor; const tr_info * inf; int keyCount; char ** keys; gtk_tree_model_get( tmodel, &iter, MC_TORRENT, &tor, -1 ); inf = tr_torrentInfo( tor ); keyCount = 0; keys = g_new( char*, inf->trackerCount ); for( i=0, n=inf->trackerCount; i<n; ++i ) { int k; int * count; char buf[1024]; char * key; gtr_get_host_from_url( buf, sizeof( buf ), inf->trackers[i].announce ); key = g_string_chunk_insert_const( strings, buf ); count = g_hash_table_lookup( hosts_hash, key ); if( count == NULL ) { count = tr_new0( int, 1 ); g_hash_table_insert( hosts_hash, key, count ); g_ptr_array_add( hosts, key ); } for( k=0; k<keyCount; ++k ) if( !strcmp( keys[k], key ) ) break; if( k==keyCount ) keys[keyCount++] = key; } for( i=0; i<keyCount; ++i ) { int * incrementme = g_hash_table_lookup( hosts_hash, keys[i] ); ++*incrementme; } g_free( keys ); ++all; if( inf->isPrivate ) ++private; else ++public;
GdkRectangle prog_area; GdkRectangle fill_area; const char * name; char * status; GdkPixbuf * icon; GtkCellRenderer * text_renderer; struct TorrentCellRendererPrivate * p = cell->priv; const tr_torrent * tor = p->tor; const tr_stat * st = tr_torrentStatCached( (tr_torrent*)tor ); const gboolean active = st->activity != TR_STATUS_STOPPED; const double percentDone = MAX( 0.0, st->percentDone ); const gboolean sensitive = active || st->error; icon = get_icon( tor, COMPACT_ICON_SIZE, widget ); name = tr_torrentInfo( tor )->name; status = getShortStatusString( tor, st, p->upload_speed_KBps, p->download_speed_KBps ); gtr_cell_renderer_get_padding( GTK_CELL_RENDERER( cell ), &xpad, &ypad ); fill_area = *background_area; fill_area.x += xpad; fill_area.y += ypad; fill_area.width -= xpad * 2; fill_area.height -= ypad * 2; icon_area = name_area = stat_area = prog_area = fill_area; g_object_set( p->icon_renderer, "pixbuf", icon, NULL ); gtk_cell_renderer_get_size( p->icon_renderer, widget, NULL, NULL, NULL, &icon_area.width, NULL ); text_renderer = get_text_renderer( st, cell ); g_object_set( text_renderer, "text", name, "ellipsize", PANGO_ELLIPSIZE_NONE, "scale", 1.0, NULL ); gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &name_area.width, NULL );
static void saveProgress( tr_benc * dict, tr_torrent * tor ) { tr_benc * l; tr_benc * prog; tr_file_index_t fi; const tr_info * inf = tr_torrentInfo( tor ); const time_t now = tr_time( ); prog = tr_bencDictAddDict( dict, KEY_PROGRESS, 3 ); /* add the file/piece check timestamps... */ l = tr_bencDictAddList( prog, KEY_PROGRESS_CHECKTIME, inf->fileCount ); for( fi=0; fi<inf->fileCount; ++fi ) { const tr_piece * p; const tr_piece * pend; time_t oldest_nonzero = now; time_t newest = 0; tr_bool has_zero = FALSE; const time_t mtime = tr_torrentGetFileMTime( tor, fi ); const tr_file * f = &inf->files[fi]; /* get the oldest and newest nonzero timestamps for pieces in this file */ for( p=&inf->pieces[f->firstPiece], pend=&inf->pieces[f->lastPiece]; p!=pend; ++p ) { if( !p->timeChecked ) has_zero = TRUE; else if( oldest_nonzero > p->timeChecked ) oldest_nonzero = p->timeChecked; if( newest < p->timeChecked ) newest = p->timeChecked; } /* If some of a file's pieces have been checked more recently than the file's mtime, and some lest recently, then that file will have a list containing timestamps for each piece. However, the most common use case is that the file doesn't change after it's downloaded. To reduce overhead in the .resume file, only a single timestamp is saved for the file if *all* or *none* of the pieces were tested more recently than the file's mtime. */ if( !has_zero && ( mtime <= oldest_nonzero ) ) /* all checked */ tr_bencListAddInt( l, oldest_nonzero ); else if( newest < mtime ) /* none checked */ tr_bencListAddInt( l, newest ); else { /* some are checked, some aren't... so list piece by piece */ const int offset = oldest_nonzero - 1; tr_benc * ll = tr_bencListAddList( l, 2 + f->lastPiece - f->firstPiece ); tr_bencListAddInt( ll, offset ); for( p=&inf->pieces[f->firstPiece], pend=&inf->pieces[f->lastPiece]+1; p!=pend; ++p ) tr_bencListAddInt( ll, p->timeChecked ? p->timeChecked - offset : 0 ); } } /* add the progress */ if( tor->completeness == TR_SEED ) tr_bencDictAddStr( prog, KEY_PROGRESS_HAVE, "all" ); /* add the blocks bitfield */ tr_bitsetToBenc( tr_cpBlockBitset( &tor->completion ), tr_bencDictAdd( prog, KEY_PROGRESS_BLOCKS ) ); }
static void saveProgress(tr_variant* dict, tr_torrent* tor) { tr_variant* l; tr_variant* prog; tr_info const* inf = tr_torrentInfo(tor); time_t const now = tr_time(); prog = tr_variantDictAddDict(dict, TR_KEY_progress, 3); /* add the file/piece check timestamps... */ l = tr_variantDictAddList(prog, TR_KEY_time_checked, inf->fileCount); for (tr_file_index_t fi = 0; fi < inf->fileCount; ++fi) { time_t oldest_nonzero = now; time_t newest = 0; bool has_zero = false; time_t const mtime = tr_torrentGetFileMTime(tor, fi); tr_file const* f = &inf->files[fi]; /* get the oldest and newest nonzero timestamps for pieces in this file */ for (tr_piece_index_t i = f->firstPiece; i <= f->lastPiece; ++i) { tr_piece const* const p = &inf->pieces[i]; if (p->timeChecked == 0) { has_zero = true; } else if (oldest_nonzero > p->timeChecked) { oldest_nonzero = p->timeChecked; } if (newest < p->timeChecked) { newest = p->timeChecked; } } /* If some of a file's pieces have been checked more recently than the file's mtime, and some less recently, then that file will have a list containing timestamps for each piece. However, the most common use case is that the file doesn't change after it's downloaded. To reduce overhead in the .resume file, only a single timestamp is saved for the file if *all* or *none* of the pieces were tested more recently than the file's mtime. */ if (!has_zero && mtime <= oldest_nonzero) /* all checked */ { tr_variantListAddInt(l, oldest_nonzero); } else if (newest < mtime) /* none checked */ { tr_variantListAddInt(l, newest); } else /* some are checked, some aren't... so list piece by piece */ { int const offset = oldest_nonzero - 1; tr_variant* ll = tr_variantListAddList(l, 2 + f->lastPiece - f->firstPiece); tr_variantListAddInt(ll, offset); for (tr_piece_index_t i = f->firstPiece; i <= f->lastPiece; ++i) { tr_piece const* const p = &inf->pieces[i]; tr_variantListAddInt(ll, p->timeChecked != 0 ? p->timeChecked - offset : 0); } } } /* add the progress */ if (tor->completeness == TR_SEED) { tr_variantDictAddStr(prog, TR_KEY_have, "all"); } /* add the blocks bitfield */ bitfieldToBenc(&tor->completion.blockBitfield, tr_variantDictAdd(prog, TR_KEY_blocks)); }
static uint64_t loadProgress(tr_variant* dict, tr_torrent* tor) { uint64_t ret = 0; tr_variant* prog; tr_info const* inf = tr_torrentInfo(tor); for (size_t i = 0; i < inf->pieceCount; ++i) { inf->pieces[i].timeChecked = 0; } if (tr_variantDictFindDict(dict, TR_KEY_progress, &prog)) { char const* err; char const* str; uint8_t const* raw; size_t rawlen; tr_variant* l; tr_variant* b; struct tr_bitfield blocks = TR_BITFIELD_INIT; if (tr_variantDictFindList(prog, TR_KEY_time_checked, &l)) { /* per-piece timestamps were added in 2.20. If some of a file's pieces have been checked more recently than the file's mtime, and some lest recently, then that file will have a list containing timestamps for each piece. However, the most common use case is that the file doesn't change after it's downloaded. To reduce overhead in the .resume file, only a single timestamp is saved for the file if *all* or *none* of the pieces were tested more recently than the file's mtime. */ for (tr_file_index_t fi = 0; fi < inf->fileCount; ++fi) { tr_variant* b = tr_variantListChild(l, fi); tr_file const* f = &inf->files[fi]; if (tr_variantIsInt(b)) { int64_t t; tr_variantGetInt(b, &t); for (tr_piece_index_t i = f->firstPiece; i <= f->lastPiece; ++i) { inf->pieces[i].timeChecked = (time_t)t; } } else if (tr_variantIsList(b)) { int64_t offset = 0; int const pieces = f->lastPiece + 1 - f->firstPiece; tr_variantGetInt(tr_variantListChild(b, 0), &offset); for (int i = 0; i < pieces; ++i) { int64_t t = 0; tr_variantGetInt(tr_variantListChild(b, i + 1), &t); inf->pieces[f->firstPiece + i].timeChecked = (time_t)(t != 0 ? t + offset : 0); } } } } else if (tr_variantDictFindList(prog, TR_KEY_mtimes, &l)) { /* Before 2.20, we stored the files' mtimes in the .resume file. When loading the .resume file, a torrent's file would be flagged as untested if its stored mtime didn't match its real mtime. */ for (tr_file_index_t fi = 0; fi < inf->fileCount; ++fi) { int64_t t; if (tr_variantGetInt(tr_variantListChild(l, fi), &t)) { tr_file const* f = &inf->files[fi]; time_t const mtime = tr_torrentGetFileMTime(tor, fi); time_t const timeChecked = mtime == t ? mtime : 0; for (tr_piece_index_t i = f->firstPiece; i <= f->lastPiece; ++i) { inf->pieces[i].timeChecked = timeChecked; } } } } err = NULL; tr_bitfieldConstruct(&blocks, tor->blockCount); if ((b = tr_variantDictFind(prog, TR_KEY_blocks)) != NULL) { size_t buflen; uint8_t const* buf; if (!tr_variantGetRaw(b, &buf, &buflen)) { err = "Invalid value for \"blocks\""; } else if (buflen == 3 && memcmp(buf, "all", 3) == 0) { tr_bitfieldSetHasAll(&blocks); } else if (buflen == 4 && memcmp(buf, "none", 4) == 0) { tr_bitfieldSetHasNone(&blocks); } else { tr_bitfieldSetRaw(&blocks, buf, buflen, true); } } else if (tr_variantDictFindStr(prog, TR_KEY_have, &str, NULL)) { if (strcmp(str, "all") == 0) { tr_bitfieldSetHasAll(&blocks); } else { err = "Invalid value for HAVE"; } } else if (tr_variantDictFindRaw(prog, TR_KEY_bitfield, &raw, &rawlen)) { tr_bitfieldSetRaw(&blocks, raw, rawlen, true); } else { err = "Couldn't find 'pieces' or 'have' or 'bitfield'"; } if (err != NULL) { tr_logAddTorDbg(tor, "Torrent needs to be verified - %s", err); } else { tr_cpBlockInit(&tor->completion, &blocks); } tr_bitfieldDestruct(&blocks); ret = TR_FR_PROGRESS; } return ret; }
static uint64_t loadProgress( tr_benc * dict, tr_torrent * tor ) { size_t i, n; uint64_t ret = 0; tr_benc * prog; const tr_info * inf = tr_torrentInfo( tor ); for( i=0, n=inf->pieceCount; i<n; ++i ) inf->pieces[i].timeChecked = 0; if( tr_bencDictFindDict( dict, KEY_PROGRESS, &prog ) ) { const char * err; const char * str; const uint8_t * raw; size_t rawlen; tr_benc * l; tr_benc * b; struct tr_bitset bitset = TR_BITSET_INIT; if( tr_bencDictFindList( prog, KEY_PROGRESS_CHECKTIME, &l ) ) { /* per-piece timestamps were added in 2.20. If some of a file's pieces have been checked more recently than the file's mtime, and some lest recently, then that file will have a list containing timestamps for each piece. However, the most common use case is that the file doesn't change after it's downloaded. To reduce overhead in the .resume file, only a single timestamp is saved for the file if *all* or *none* of the pieces were tested more recently than the file's mtime. */ tr_file_index_t fi; for( fi=0; fi<inf->fileCount; ++fi ) { tr_benc * b = tr_bencListChild( l, fi ); const tr_file * f = &inf->files[fi]; tr_piece * p = &inf->pieces[f->firstPiece]; const tr_piece * pend = &inf->pieces[f->lastPiece]+1; if( tr_bencIsInt( b ) ) { int64_t t; tr_bencGetInt( b, &t ); for( ; p!=pend; ++p ) p->timeChecked = (time_t)t; } else if( tr_bencIsList( b ) ) { int i = 0; int64_t offset = 0; const int pieces = f->lastPiece + 1 - f->firstPiece; tr_bencGetInt( tr_bencListChild( b, 0 ), &offset ); for( i=0; i<pieces; ++i ) { int64_t t = 0; tr_bencGetInt( tr_bencListChild( b, i+1 ), &t ); inf->pieces[f->firstPiece+i].timeChecked = (time_t)(t ? t + offset : 0); } } } } else if( tr_bencDictFindList( prog, KEY_PROGRESS_MTIMES, &l ) ) { tr_file_index_t fi; /* Before 2.20, we stored the files' mtimes in the .resume file. When loading the .resume file, a torrent's file would be flagged as untested if its stored mtime didn't match its real mtime. */ for( fi=0; fi<inf->fileCount; ++fi ) { int64_t t; if( tr_bencGetInt( tr_bencListChild( l, fi ), &t ) ) { const tr_file * f = &inf->files[fi]; tr_piece * p = &inf->pieces[f->firstPiece]; const tr_piece * pend = &inf->pieces[f->lastPiece]; const time_t mtime = tr_torrentGetFileMTime( tor, fi ); const time_t timeChecked = mtime==t ? mtime : 0; for( ; p!=pend; ++p ) p->timeChecked = timeChecked; } } } err = NULL; if(( b = tr_bencDictFind( prog, KEY_PROGRESS_BLOCKS ))) { if( !tr_bitsetFromBenc( &bitset, b ) ) err = "Invalid value for PIECES"; } else if( tr_bencDictFindStr( prog, KEY_PROGRESS_HAVE, &str ) ) { if( !strcmp( str, "all" ) ) tr_bitsetSetHaveAll( &bitset ); else err = "Invalid value for HAVE"; } else if( tr_bencDictFindRaw( prog, KEY_PROGRESS_BITFIELD, &raw, &rawlen ) ) { bitset.bitfield.bits = (void*) raw; bitset.bitfield.byteCount = rawlen; bitset.bitfield.bitCount = rawlen * 8; } else err = "Couldn't find 'pieces' or 'have' or 'bitfield'"; if( !err && !tr_cpBlockBitsetInit( &tor->completion, &bitset ) ) err = "Error loading bitfield"; if( err != NULL ) tr_tordbg( tor, "Torrent needs to be verified - %s", err ); ret = TR_FR_PROGRESS; } return ret; }
static void torrent_cell_renderer_get_size( GtkCellRenderer * cell, GtkWidget * widget, GdkRectangle * cell_area, gint * x_offset, gint * y_offset, gint * width, gint * height ) { TorrentCellRenderer * self = TORRENT_CELL_RENDERER( cell ); if( self && self->priv->tor ) { const tr_torrent * tor = self->priv->tor; const tr_info * info = tr_torrentInfo( tor ); const char * name = info->name; const tr_stat * torStat = tr_torrentStatCached( (tr_torrent*)tor ); char * str; int w = 0, h = 0; struct TorrentCellRendererPrivate * p = self->priv; GtkCellRenderer * text_renderer = torStat->error != 0 ? p-> text_renderer_err : p-> text_renderer; g_object_set( text_renderer, "ellipsize", PANGO_ELLIPSIZE_NONE, NULL ); /* above the progressbar */ if( p->minimal ) { int w1, w2, h1, h2; char * shortStatus = getShortStatusString( torStat ); g_object_set( text_renderer, "text", name, NULL ); gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w1, &h1 ); str = g_markup_printf_escaped( "<small>%s</small>", shortStatus ); g_object_set( text_renderer, "markup", str, NULL ); gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w2, &h2 ); h += MAX( h1, h2 ); w = MAX( w, w1 + GUI_PAD_BIG + w2 ); g_free( str ); g_free( shortStatus ); } else { int w1, h1; char * progressString = getProgressString( info, torStat ); str = g_markup_printf_escaped( "<b>%s</b>\n<small>%s</small>", name, progressString ); g_object_set( text_renderer, "markup", str, NULL ); gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w1, &h1 ); h += h1; w = MAX( w, w1 ); g_free( str ); g_free( progressString ); } /* below the progressbar */ if( !p->minimal ) { int w1, h1; char * statusString = getStatusString( torStat ); str = g_markup_printf_escaped( "<small>%s</small>", statusString ); g_object_set( text_renderer, "markup", str, NULL ); gtk_cell_renderer_get_size( text_renderer, widget, NULL, NULL, NULL, &w1, &h1 ); h += h1; w = MAX( w, w1 ); g_free( str ); g_free( statusString ); } h += p->bar_height; if( cell_area ) { if( x_offset ) *x_offset = 0; if( y_offset ) { *y_offset = 0.5 * ( cell_area->height - ( h + ( 2 * cell->ypad ) ) ); *y_offset = MAX( *y_offset, 0 ); } } *width = w + cell->xpad * 2; *height = h + cell->ypad * 2; } }