void tr_magnetCreateMetainfo (const tr_magnet_info * info, tr_variant * top) { int i; tr_variant * d; tr_variantInitDict (top, 4); /* announce list */ if (info->trackerCount == 1) { tr_variantDictAddStr (top, TR_KEY_announce, info->trackers[0]); } else { tr_variant * trackers = tr_variantDictAddList (top, TR_KEY_announce_list, info->trackerCount); for (i=0; i<info->trackerCount; ++i) tr_variantListAddStr (tr_variantListAddList (trackers, 1), info->trackers[i]); } /* webseeds */ if (info->webseedCount > 0) { tr_variant * urls = tr_variantDictAddList (top, TR_KEY_url_list, info->webseedCount); for (i=0; i<info->webseedCount; ++i) tr_variantListAddStr (urls, info->webseeds[i]); } /* nonstandard keys */ d = tr_variantDictAddDict (top, TR_KEY_magnet_info, 2); tr_variantDictAddRaw (d, TR_KEY_info_hash, info->hash, 20); if (info->displayName != NULL) tr_variantDictAddStr (d, TR_KEY_display_name, info->displayName); }
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); }
static void saveDND (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_dnd, n); for (i=0; i<n; ++i) tr_variantListAddInt (list, inf->files[i].dnd ? 1 : 0); }
static bool addURL (tr_variant * metainfo, const char * url) { const char * announce = NULL; tr_variant * announce_list = NULL; bool changed = false; const bool had_announce = tr_variantDictFindStr (metainfo, TR_KEY_announce, &announce, NULL); const bool had_announce_list = tr_variantDictFindList (metainfo, TR_KEY_announce_list, &announce_list); if (!had_announce && !had_announce_list) { /* this new tracker is the only one, so add it to "announce"... */ printf ("\tAdded \"%s\" in \"announce\"\n", url); tr_variantDictAddStr (metainfo, TR_KEY_announce, url); changed = true; } else { if (!had_announce_list) { announce_list = tr_variantDictAddList (metainfo, TR_KEY_announce_list, 2); if (had_announce) { /* we're moving from an 'announce' to an 'announce-list', * so copy the old announce URL to the list */ tr_variant * tier = tr_variantListAddList (announce_list, 1); tr_variantListAddStr (tier, announce); changed = true; } } /* If the user-specified URL isn't in the announce list yet, add it */ if (!announce_list_has_url (announce_list, url)) { tr_variant * tier = tr_variantListAddList (announce_list, 1); tr_variantListAddStr (tier, url); printf ("\tAdded \"%s\" to \"announce-list\" tier %"TR_PRIuSIZE"\n", url, tr_variantListSize (announce_list)); changed = true; } } return changed; }
static void saveFilenames (tr_variant * dict, const tr_torrent * tor) { tr_file_index_t i; bool any_renamed; const tr_file_index_t n = tor->info.fileCount; const tr_file * files = tor->info.files; any_renamed = false; for (i=0; !any_renamed && i<n; ++i) any_renamed = files[i].is_renamed; if (any_renamed) { tr_variant * list = tr_variantDictAddList (dict, TR_KEY_files, n); for (i=0; i<n; ++i) tr_variantListAddStr (list, files[i].is_renamed ? files[i].name : ""); } }
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)); }