static void on_announce_done(tr_session * session, bool did_connect, bool did_timeout, long response_code, const void * msg, size_t msglen, void * vdata) { tr_announce_response * response; struct announce_data * data = vdata; response = &data->response; (...) // lê os dados da resposta do tracker if (variant_loaded && tr_variantIsDict(&benc)) { int64_t i; size_t len; tr_variant * tmp; // variáveis ... const char * str; const uint8_t * raw; // ... temporárias if (tr_variantDictFindStr(&benc, TR_KEY_failure_reason, &str, &len)) response->errmsg = tr_strndup(str, len); if (tr_variantDictFindStr(&benc, TR_KEY_tracker_id, &str, &len)) response->tracker_id_str = tr_strndup(str, len); if (tr_variantDictFindInt(&benc, TR_KEY_complete, &i)) response->seeders = i; (...) if (tr_variantDictFindRaw(&benc, TR_KEY_peers, &raw, &len)) { response->pex = tr_peerMgrCompactToPex(raw, len, NULL, 0, &response->pex_count); } else if (tr_variantDictFindList(&benc, TR_KEY_peers, &tmp)) { response->pex = listToPex(tmp, &response->pex_count); } }
static int test_utf8 (void) { const char * in = "{ \"key\": \"Letöltések\" }"; tr_variant top; const char * str; char * json; int err; const tr_quark key = tr_quark_new ("key", 3); err = tr_variantFromJson (&top, in, strlen(in)); check (!err); check (tr_variantIsDict (&top)); check (tr_variantDictFindStr (&top, key, &str, NULL)); check_streq ("Letöltések", str); if (!err) tr_variantFree (&top); in = "{ \"key\": \"\\u005C\" }"; err = tr_variantFromJson (&top, in, strlen(in)); check (!err); check (tr_variantIsDict (&top)); check (tr_variantDictFindStr (&top, key, &str, NULL)); check_streq ("\\", str); if (!err) tr_variantFree (&top); /** * 1. Feed it JSON-escaped nonascii to the JSON decoder. * 2. Confirm that the result is UTF-8. * 3. Feed the same UTF-8 back into the JSON encoder. * 4. Confirm that the result is JSON-escaped. * 5. Dogfood that result back into the parser. * 6. Confirm that the result is UTF-8. */ in = "{ \"key\": \"Let\\u00f6lt\\u00e9sek\" }"; err = tr_variantFromJson (&top, in, strlen(in)); check (!err); check (tr_variantIsDict (&top)); check (tr_variantDictFindStr (&top, key, &str, NULL)); check_streq ("Letöltések", str); json = tr_variantToStr (&top, TR_VARIANT_FMT_JSON, NULL); if (!err) tr_variantFree (&top); check (json); check (strstr (json, "\\u00f6") != NULL); check (strstr (json, "\\u00e9") != NULL); err = tr_variantFromJson (&top, json, strlen(json)); check (!err); check (tr_variantIsDict (&top)); check (tr_variantDictFindStr (&top, key, &str, NULL)); check_streq ("Letöltések", str); if (!err) tr_variantFree (&top); tr_free (json); return 0; }
static int test_elements(void) { char const* in; tr_variant top; char const* str; bool f; double d; int64_t i; int err = 0; tr_quark key; in = "{ \"string\": \"hello world\"," " \"escaped\": \"bell \\b formfeed \\f linefeed \\n carriage return \\r tab \\t\"," " \"int\": 5, " " \"float\": 6.5, " " \"true\": true, " " \"false\": false, " " \"null\": null }"; err = tr_variantFromJson(&top, in, strlen(in)); check_int(err, ==, 0); check(tr_variantIsDict(&top)); str = NULL; key = tr_quark_new("string", 6); check(tr_variantDictFindStr(&top, key, &str, NULL)); check_str(str, ==, "hello world"); check(tr_variantDictFindStr(&top, tr_quark_new("escaped", 7), &str, NULL)); check_str(str, ==, "bell \b formfeed \f linefeed \n carriage return \r tab \t"); i = 0; check(tr_variantDictFindInt(&top, tr_quark_new("int", 3), &i)); check_int(i, ==, 5); d = 0; check(tr_variantDictFindReal(&top, tr_quark_new("float", 5), &d)); check_int(((int)(d * 10)), ==, 65); f = false; check(tr_variantDictFindBool(&top, tr_quark_new("true", 4), &f)); check_int(f, ==, true); check(tr_variantDictFindBool(&top, tr_quark_new("false", 5), &f)); check_int(f, ==, false); check(tr_variantDictFindStr(&top, tr_quark_new("null", 4), &str, NULL)); check_str(str, ==, ""); if (err == 0) { tr_variantFree(&top); } return 0; }
static int test_elements (void) { const char * in; tr_variant top; const char * str; bool f; double d; int64_t i; int err = 0; tr_quark key; in = "{ \"string\": \"hello world\"," " \"escaped\": \"bell \\b formfeed \\f linefeed \\n carriage return \\r tab \\t\"," " \"int\": 5, " " \"float\": 6.5, " " \"true\": true, " " \"false\": false, " " \"null\": null }"; err = tr_variantFromJson (&top, in, strlen(in)); check_int_eq (0, err); check (tr_variantIsDict (&top)); str = NULL; key = tr_quark_new ("string", 6); check (tr_variantDictFindStr (&top, key, &str, NULL)); check_streq ("hello world", str); check (tr_variantDictFindStr (&top, tr_quark_new("escaped",7), &str, NULL)); check_streq ("bell \b formfeed \f linefeed \n carriage return \r tab \t", str); i = 0; check (tr_variantDictFindInt (&top, tr_quark_new("int",3), &i)); check_int_eq (5, i); d = 0; check (tr_variantDictFindReal (&top, tr_quark_new("float",5), &d)); check_int_eq (65, ((int)(d*10))); f = false; check (tr_variantDictFindBool (&top, tr_quark_new("true",4), &f)); check_int_eq (true, f); check (tr_variantDictFindBool (&top, tr_quark_new("false",5), &f)); check_int_eq (false, f); check (tr_variantDictFindStr (&top, tr_quark_new("null",4), &str, NULL)); check_streq ("", str); if (!err) tr_variantFree (&top); return 0; }
static int test1(void) { char const* in = "{\n" " \"headers\": {\n" " \"type\": \"request\",\n" " \"tag\": 666\n" " },\n" " \"body\": {\n" " \"name\": \"torrent-info\",\n" " \"arguments\": {\n" " \"ids\": [ 7, 10 ]\n" " }\n" " }\n" "}\n"; tr_variant top; tr_variant* headers; tr_variant* body; tr_variant* args; tr_variant* ids; char const* str; int64_t i; int const err = tr_variantFromJson(&top, in, strlen(in)); check_int(err, ==, 0); check(tr_variantIsDict(&top)); check_ptr((headers = tr_variantDictFind(&top, tr_quark_new("headers", 7))), !=, NULL); check(tr_variantIsDict(headers)); check(tr_variantDictFindStr(headers, tr_quark_new("type", 4), &str, NULL)); check_str(str, ==, "request"); check(tr_variantDictFindInt(headers, TR_KEY_tag, &i)); check_int(i, ==, 666); check_ptr((body = tr_variantDictFind(&top, tr_quark_new("body", 4))), !=, NULL); check(tr_variantDictFindStr(body, TR_KEY_name, &str, NULL)); check_str(str, ==, "torrent-info"); check_ptr((args = tr_variantDictFind(body, tr_quark_new("arguments", 9))), !=, NULL); check(tr_variantIsDict(args)); check_ptr((ids = tr_variantDictFind(args, TR_KEY_ids)), !=, NULL); check(tr_variantIsList(ids)); check_uint(tr_variantListSize(ids), ==, 2); check(tr_variantGetInt(tr_variantListChild(ids, 0), &i)); check_int(i, ==, 7); check(tr_variantGetInt(tr_variantListChild(ids, 1), &i)); check_int(i, ==, 10); tr_variantFree(&top); return 0; }
static int test1 (void) { const char * in = "{\n" " \"headers\": {\n" " \"type\": \"request\",\n" " \"tag\": 666\n" " },\n" " \"body\": {\n" " \"name\": \"torrent-info\",\n" " \"arguments\": {\n" " \"ids\": [ 7, 10 ]\n" " }\n" " }\n" "}\n"; tr_variant top, *headers, *body, *args, *ids; const char * str; int64_t i; const int err = tr_variantFromJson (&top, in, strlen(in)); check (!err); check (tr_variantIsDict (&top)); check ((headers = tr_variantDictFind (&top, tr_quark_new("headers",7)))); check (tr_variantIsDict (headers)); check (tr_variantDictFindStr (headers, tr_quark_new("type",4), &str, NULL)); check_streq ("request", str); check (tr_variantDictFindInt (headers, TR_KEY_tag, &i)); check_int_eq (666, i); check ((body = tr_variantDictFind (&top, tr_quark_new("body",4)))); check (tr_variantDictFindStr (body, TR_KEY_name, &str, NULL)); check_streq ("torrent-info", str); check ((args = tr_variantDictFind (body, tr_quark_new("arguments",9)))); check (tr_variantIsDict (args)); check ((ids = tr_variantDictFind (args, TR_KEY_ids))); check (tr_variantIsList (ids)); check_int_eq (2, tr_variantListSize (ids)); check (tr_variantGetInt (tr_variantListChild (ids, 0), &i)); check_int_eq (7, i); check (tr_variantGetInt (tr_variantListChild (ids, 1), &i)); check_int_eq (10, i); tr_variantFree (&top); return 0; }
const char* gtr_pref_string_get (const tr_quark key) { const char * str = NULL; tr_variantDictFindStr (getPrefs (), key, &str, NULL); return str; }
int tr_ctorSetMetainfoFromFile (tr_ctor * ctor, const char * filename) { uint8_t * metainfo; size_t len; int err; metainfo = tr_loadFile (filename, &len); if (metainfo && len) err = tr_ctorSetMetainfo (ctor, metainfo, len); else { clearMetainfo (ctor); err = 1; } setSourceFile (ctor, filename); /* if no `name' field was set, then set it from the filename */ if (ctor->isSet_metainfo) { tr_variant * info; if (tr_variantDictFindDict (&ctor->metainfo, TR_KEY_info, &info)) { const char * name; if (!tr_variantDictFindStr (info, TR_KEY_name_utf_8, &name, NULL)) if (!tr_variantDictFindStr (info, TR_KEY_name, &name, NULL)) name = NULL; if (!name || !*name) { char * base = tr_sys_path_basename (filename, NULL); tr_variantDictAddStr (info, TR_KEY_name, base); tr_free (base); } } } tr_free (metainfo); return err; }
static int test_unescape(void) { char const* in = "{ \"string-1\": \"\\/usr\\/lib\" }"; tr_variant top; char const* str; int const err = tr_variantFromJson(&top, in, strlen(in)); check_int(err, ==, 0); check(tr_variantDictFindStr(&top, tr_quark_new("string-1", 8), &str, NULL)); check_str(str, ==, "/usr/lib"); tr_variantFree(&top); return 0; }
static int test_unescape (void) { const char * in = "{ \"string-1\": \"\\/usr\\/lib\" }"; tr_variant top; const char * str; const int err = tr_variantFromJson (&top, in, strlen(in)); check_int_eq (0, err); check (tr_variantDictFindStr (&top, tr_quark_new("string-1",8), &str, NULL)); check_streq ("/usr/lib", str); tr_variantFree (&top); return 0; }
static uint64_t loadName(tr_variant* dict, tr_torrent* tor) { uint64_t ret = 0; char const* name; if (tr_variantDictFindStr(dict, TR_KEY_name, &name, NULL)) { ret = TR_FR_NAME; if (tr_strcmp0(tr_torrentName(tor), name) != 0) { tr_free(tor->info.name); tor->info.name = tr_strdup(name); } } return ret; }
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 int test3(void) { char const* in = "{ \"error\": 2," " \"errorString\": \"torrent not registered with this tracker 6UHsVW'*C\"," " \"eta\": 262792," " \"id\": 25," " \"leftUntilDone\": 2275655680 }"; tr_variant top; char const* str; int const err = tr_variantFromJson(&top, in, strlen(in)); check_int(err, ==, 0); check(tr_variantDictFindStr(&top, TR_KEY_errorString, &str, NULL)); check_str(str, ==, "torrent not registered with this tracker 6UHsVW'*C"); tr_variantFree(&top); return 0; }
static bool replaceURL (tr_variant * metainfo, const char * in, const char * out) { const char * str; tr_variant * announce_list; bool changed = false; if (tr_variantDictFindStr (metainfo, TR_KEY_announce, &str, NULL) && strstr (str, in)) { char * newstr = replaceSubstr (str, in, out); printf ("\tReplaced in \"announce\": \"%s\" --> \"%s\"\n", str, newstr); tr_variantDictAddStr (metainfo, TR_KEY_announce, newstr); tr_free (newstr); changed = true; } if (tr_variantDictFindList (metainfo, TR_KEY_announce_list, &announce_list)) { tr_variant * tier; int tierCount = 0; while ((tier = tr_variantListChild (announce_list, tierCount++))) { tr_variant * node; int nodeCount = 0; while ((node = tr_variantListChild (tier, nodeCount++))) { if (tr_variantGetStr (node, &str, NULL) && strstr (str, in)) { char * newstr = replaceSubstr (str, in, out); printf ("\tReplaced in \"announce-list\" tier %d: \"%s\" --> \"%s\"\n", tierCount, str, newstr); tr_variantFree (node); tr_variantInitStr (node, newstr, -1); tr_free (newstr); changed = true; } } } } return changed; }
static tr_pex* listToPex (tr_variant * peerList, size_t * setme_len) { size_t i; size_t n; const size_t len = tr_variantListSize (peerList); tr_pex * pex = tr_new0 (tr_pex, len); for (i=n=0; i<len; ++i) { int64_t port; const char * ip; tr_address addr; tr_variant * peer = tr_variantListChild (peerList, i); if (peer == NULL) continue; if (!tr_variantDictFindStr (peer, TR_KEY_ip, &ip, NULL)) continue; if (!tr_address_from_string (&addr, ip)) continue; if (!tr_variantDictFindInt (peer, TR_KEY_port, &port)) continue; if ((port < 0) || (port > USHRT_MAX)) continue; if (!tr_address_is_valid_for_peers (&addr, port)) continue; pex[n].addr = addr; pex[n].port = htons ((uint16_t)port); ++n; } *setme_len = n; return pex; }
static void on_scrape_done (tr_session * session, bool did_connect, bool did_timeout, long response_code, const void * msg, size_t msglen, void * vdata) { tr_scrape_response * response; struct scrape_data * data = vdata; response = &data->response; response->did_connect = did_connect; response->did_timeout = did_timeout; dbgmsg (data->log_name, "Got scrape response for \"%s\"", response->url); if (response_code != HTTP_OK) { const char * fmt = _("Tracker gave HTTP response code %1$ld (%2$s)"); const char * response_str = tr_webGetResponseStr (response_code); response->errmsg = tr_strdup_printf (fmt, response_code, response_str); } else { tr_variant top; int64_t intVal; tr_variant * files; tr_variant * flags; size_t len; const char * str; const bool variant_loaded = !tr_variantFromBenc (&top, msg, msglen); if (getenv ("TR_CURL_VERBOSE") != NULL) { if (!variant_loaded) fprintf (stderr, "%s", "Scrape response was not in benc format\n"); else { int i, len; char * str = tr_variantToStr (&top, TR_VARIANT_FMT_JSON, &len); fprintf (stderr, "%s", "Scrape response:\n< "); for (i=0; i<len; ++i) fputc (str[i], stderr); fputc ('\n', stderr); tr_free (str); } } if (variant_loaded) { if (tr_variantDictFindStr (&top, TR_KEY_failure_reason, &str, &len)) response->errmsg = tr_strndup (str, len); if (tr_variantDictFindDict (&top, TR_KEY_flags, &flags)) if (tr_variantDictFindInt (flags, TR_KEY_min_request_interval, &intVal)) response->min_request_interval = intVal; if (tr_variantDictFindDict (&top, TR_KEY_files, &files)) { int i = 0; for (;;) { int j; tr_quark key; tr_variant * val; /* get the next "file" */ if (!tr_variantDictChild (files, i++, &key, &val)) break; /* populate the corresponding row in our response array */ for (j=0; j<response->row_count; ++j) { struct tr_scrape_response_row * row = &response->rows[j]; if (!memcmp (tr_quark_get_string(key,NULL), row->info_hash, SHA_DIGEST_LENGTH)) { if (tr_variantDictFindInt (val, TR_KEY_complete, &intVal)) row->seeders = intVal; if (tr_variantDictFindInt (val, TR_KEY_incomplete, &intVal)) row->leechers = intVal; if (tr_variantDictFindInt (val, TR_KEY_downloaded, &intVal)) row->downloads = intVal; if (tr_variantDictFindInt (val, TR_KEY_downloaders, &intVal)) row->downloaders = intVal; break; } } } } tr_variantFree (&top); } } tr_runInEventThread (session, on_scrape_done_eventthread, data); }
static void on_announce_done (tr_session * session, bool did_connect, bool did_timeout, long response_code, const void * msg, size_t msglen, void * vdata) { tr_announce_response * response; struct announce_data * data = vdata; response = &data->response; response->did_connect = did_connect; response->did_timeout = did_timeout; dbgmsg (data->log_name, "Got announce response"); if (response_code != HTTP_OK) { const char * fmt = _("Tracker gave HTTP response code %1$ld (%2$s)"); const char * response_str = tr_webGetResponseStr (response_code); response->errmsg = tr_strdup_printf (fmt, response_code, response_str); } else { tr_variant benc; const bool variant_loaded = !tr_variantFromBenc (&benc, msg, msglen); if (getenv ("TR_CURL_VERBOSE") != NULL) { if (!variant_loaded) fprintf (stderr, "%s", "Announce response was not in benc format\n"); else { int i, len; char * str = tr_variantToStr (&benc, TR_VARIANT_FMT_JSON, &len); fprintf (stderr, "%s", "Announce response:\n< "); for (i=0; i<len; ++i) fputc (str[i], stderr); fputc ('\n', stderr); tr_free (str); } } if (variant_loaded && tr_variantIsDict (&benc)) { int64_t i; size_t len; tr_variant * tmp; const char * str; const uint8_t * raw; if (tr_variantDictFindStr (&benc, TR_KEY_failure_reason, &str, &len)) response->errmsg = tr_strndup (str, len); if (tr_variantDictFindStr (&benc, TR_KEY_warning_message, &str, &len)) response->warning = tr_strndup (str, len); if (tr_variantDictFindInt (&benc, TR_KEY_interval, &i)) response->interval = i; if (tr_variantDictFindInt (&benc, TR_KEY_min_interval, &i)) response->min_interval = i; if (tr_variantDictFindStr (&benc, TR_KEY_tracker_id, &str, &len)) response->tracker_id_str = tr_strndup (str, len); if (tr_variantDictFindInt (&benc, TR_KEY_complete, &i)) response->seeders = i; if (tr_variantDictFindInt (&benc, TR_KEY_incomplete, &i)) response->leechers = i; if (tr_variantDictFindInt (&benc, TR_KEY_downloaded, &i)) response->downloads = i; if (tr_variantDictFindRaw (&benc, TR_KEY_peers6, &raw, &len)) { dbgmsg (data->log_name, "got a peers6 length of %zu", len); response->pex6 = tr_peerMgrCompact6ToPex (raw, len, NULL, 0, &response->pex6_count); } if (tr_variantDictFindRaw (&benc, TR_KEY_peers, &raw, &len)) { dbgmsg (data->log_name, "got a compact peers length of %zu", len); response->pex = tr_peerMgrCompactToPex (raw, len, NULL, 0, &response->pex_count); } else if (tr_variantDictFindList (&benc, TR_KEY_peers, &tmp)) { response->pex = listToPex (tmp, &response->pex_count); dbgmsg (data->log_name, "got a peers list with %zu entries", response->pex_count); } } if (variant_loaded) tr_variantFree (&benc); } tr_runInEventThread (session, on_announce_done_eventthread, data); }
static uint64_t loadFromFile(tr_torrent* tor, uint64_t fieldsToLoad) { TR_ASSERT(tr_isTorrent(tor)); size_t len; int64_t i; char const* str; char* filename; tr_variant top; bool boolVal; uint64_t fieldsLoaded = 0; bool const wasDirty = tor->isDirty; tr_error* error = NULL; filename = getResumeFilename(tor); if (!tr_variantFromFile(&top, TR_VARIANT_FMT_BENC, filename, &error)) { tr_logAddTorDbg(tor, "Couldn't read \"%s\": %s", filename, error->message); tr_error_free(error); tr_free(filename); return fieldsLoaded; } tr_logAddTorDbg(tor, "Read resume file \"%s\"", filename); if ((fieldsToLoad & TR_FR_CORRUPT) != 0 && tr_variantDictFindInt(&top, TR_KEY_corrupt, &i)) { tor->corruptPrev = i; fieldsLoaded |= TR_FR_CORRUPT; } if ((fieldsToLoad & (TR_FR_PROGRESS | TR_FR_DOWNLOAD_DIR)) != 0 && tr_variantDictFindStr(&top, TR_KEY_destination, &str, &len) && str != NULL && *str != '\0') { bool const is_current_dir = tor->currentDir == tor->downloadDir; tr_free(tor->downloadDir); tor->downloadDir = tr_strndup(str, len); if (is_current_dir) { tor->currentDir = tor->downloadDir; } fieldsLoaded |= TR_FR_DOWNLOAD_DIR; } if ((fieldsToLoad & (TR_FR_PROGRESS | TR_FR_INCOMPLETE_DIR)) != 0 && tr_variantDictFindStr(&top, TR_KEY_incomplete_dir, &str, &len) && str != NULL && *str != '\0') { bool const is_current_dir = tor->currentDir == tor->incompleteDir; tr_free(tor->incompleteDir); tor->incompleteDir = tr_strndup(str, len); if (is_current_dir) { tor->currentDir = tor->incompleteDir; } fieldsLoaded |= TR_FR_INCOMPLETE_DIR; } if ((fieldsToLoad & TR_FR_DOWNLOADED) != 0 && tr_variantDictFindInt(&top, TR_KEY_downloaded, &i)) { tor->downloadedPrev = i; fieldsLoaded |= TR_FR_DOWNLOADED; } if ((fieldsToLoad & TR_FR_UPLOADED) != 0 && tr_variantDictFindInt(&top, TR_KEY_uploaded, &i)) { tor->uploadedPrev = i; fieldsLoaded |= TR_FR_UPLOADED; } if ((fieldsToLoad & TR_FR_MAX_PEERS) != 0 && tr_variantDictFindInt(&top, TR_KEY_max_peers, &i)) { tor->maxConnectedPeers = i; fieldsLoaded |= TR_FR_MAX_PEERS; } if ((fieldsToLoad & TR_FR_RUN) != 0 && tr_variantDictFindBool(&top, TR_KEY_paused, &boolVal)) { tor->isRunning = !boolVal; fieldsLoaded |= TR_FR_RUN; } if ((fieldsToLoad & TR_FR_ADDED_DATE) != 0 && tr_variantDictFindInt(&top, TR_KEY_added_date, &i)) { tor->addedDate = i; fieldsLoaded |= TR_FR_ADDED_DATE; } if ((fieldsToLoad & TR_FR_DONE_DATE) != 0 && tr_variantDictFindInt(&top, TR_KEY_done_date, &i)) { tor->doneDate = i; fieldsLoaded |= TR_FR_DONE_DATE; } if ((fieldsToLoad & TR_FR_ACTIVITY_DATE) != 0 && tr_variantDictFindInt(&top, TR_KEY_activity_date, &i)) { tr_torrentSetActivityDate(tor, i); fieldsLoaded |= TR_FR_ACTIVITY_DATE; } if ((fieldsToLoad & TR_FR_TIME_SEEDING) != 0 && tr_variantDictFindInt(&top, TR_KEY_seeding_time_seconds, &i)) { tor->secondsSeeding = i; fieldsLoaded |= TR_FR_TIME_SEEDING; } if ((fieldsToLoad & TR_FR_TIME_DOWNLOADING) != 0 && tr_variantDictFindInt(&top, TR_KEY_downloading_time_seconds, &i)) { tor->secondsDownloading = i; fieldsLoaded |= TR_FR_TIME_DOWNLOADING; } if ((fieldsToLoad & TR_FR_BANDWIDTH_PRIORITY) != 0 && tr_variantDictFindInt(&top, TR_KEY_bandwidth_priority, &i) && tr_isPriority(i)) { tr_torrentSetPriority(tor, i); fieldsLoaded |= TR_FR_BANDWIDTH_PRIORITY; } if ((fieldsToLoad & TR_FR_PEERS) != 0) { fieldsLoaded |= loadPeers(&top, tor); } if ((fieldsToLoad & TR_FR_FILE_PRIORITIES) != 0) { fieldsLoaded |= loadFilePriorities(&top, tor); } if ((fieldsToLoad & TR_FR_PROGRESS) != 0) { fieldsLoaded |= loadProgress(&top, tor); } if ((fieldsToLoad & TR_FR_DND) != 0) { fieldsLoaded |= loadDND(&top, tor); } if ((fieldsToLoad & TR_FR_SPEEDLIMIT) != 0) { fieldsLoaded |= loadSpeedLimits(&top, tor); } if ((fieldsToLoad & TR_FR_RATIOLIMIT) != 0) { fieldsLoaded |= loadRatioLimits(&top, tor); } if ((fieldsToLoad & TR_FR_IDLELIMIT) != 0) { fieldsLoaded |= loadIdleLimits(&top, tor); } if ((fieldsToLoad & TR_FR_FILENAMES) != 0) { fieldsLoaded |= loadFilenames(&top, tor); } if ((fieldsToLoad & TR_FR_NAME) != 0) { fieldsLoaded |= loadName(&top, tor); } /* loading the resume file triggers of a lot of changes, * but none of them needs to trigger a re-saving of the * same resume information... */ tor->isDirty = wasDirty; tr_variantFree(&top); tr_free(filename); return fieldsLoaded; }
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 bool removeURL (tr_variant * metainfo, const char * url) { const char * str; tr_variant * announce_list; bool changed = false; if (tr_variantDictFindStr (metainfo, TR_KEY_announce, &str, NULL) && !strcmp (str, url)) { printf ("\tRemoved \"%s\" from \"announce\"\n", str); tr_variantDictRemove (metainfo, TR_KEY_announce); changed = true; } if (tr_variantDictFindList (metainfo, TR_KEY_announce_list, &announce_list)) { tr_variant * tier; int tierIndex = 0; while ((tier = tr_variantListChild (announce_list, tierIndex))) { tr_variant * node; int nodeIndex = 0; while ((node = tr_variantListChild (tier, nodeIndex))) { if (tr_variantGetStr (node, &str, NULL) && !strcmp (str, url)) { printf ("\tRemoved \"%s\" from \"announce-list\" tier #%d\n", str, (tierIndex+1)); tr_variantListRemove (tier, nodeIndex); changed = true; } else ++nodeIndex; } if (tr_variantListSize (tier) == 0) { printf ("\tNo URLs left in tier #%d... removing tier\n", (tierIndex+1)); tr_variantListRemove (announce_list, tierIndex); } else { ++tierIndex; } } if (tr_variantListSize (announce_list) == 0) { printf ("\tNo tiers left... removing announce-list\n"); tr_variantDictRemove (metainfo, TR_KEY_announce_list); } } /* if we removed the "announce" field and there's still another track left, * use it as the "announce" field */ if (changed && !tr_variantDictFindStr (metainfo, TR_KEY_announce, &str, NULL)) { tr_variant * tier; tr_variant * node; if ((tier = tr_variantListChild (announce_list, 0))) { if ((node = tr_variantListChild (tier, 0))) { if (tr_variantGetStr (node, &str, NULL)) { tr_variantDictAddStr (metainfo, TR_KEY_announce, str); printf ("\tAdded \"%s\" to announce\n", str); } } } } return changed; }
tr_session * libttest_session_init (tr_variant * settings) { size_t len; const char * str; char * sandbox; char * path; tr_quark q; static bool formatters_inited = false; tr_session * session; tr_variant local_settings; tr_variantInitDict (&local_settings, 10); if (settings == NULL) settings = &local_settings; sandbox = libtest_sandbox_create (); if (!formatters_inited) { formatters_inited = true; tr_formatter_mem_init (MEM_K, MEM_K_STR, MEM_M_STR, MEM_G_STR, MEM_T_STR); tr_formatter_size_init (DISK_K,DISK_K_STR, DISK_M_STR, DISK_G_STR, DISK_T_STR); tr_formatter_speed_init (SPEED_K, SPEED_K_STR, SPEED_M_STR, SPEED_G_STR, SPEED_T_STR); } /* download dir */ q = TR_KEY_download_dir; if (tr_variantDictFindStr (settings, q, &str, &len)) path = tr_strdup_printf ("%s/%*.*s", sandbox, (int)len, (int)len, str); else path = tr_buildPath (sandbox, "Downloads", NULL); tr_mkdirp (path, 0700); tr_variantDictAddStr (settings, q, path); tr_free (path); /* incomplete dir */ q = TR_KEY_incomplete_dir; if (tr_variantDictFindStr (settings, q, &str, &len)) path = tr_strdup_printf ("%s/%*.*s", sandbox, (int)len, (int)len, str); else path = tr_buildPath (sandbox, "Incomplete", NULL); tr_variantDictAddStr (settings, q, path); tr_free (path); path = tr_buildPath (sandbox, "blocklists", NULL); tr_mkdirp (path, 0700); tr_free (path); q = TR_KEY_port_forwarding_enabled; if (!tr_variantDictFind (settings, q)) tr_variantDictAddBool (settings, q, false); q = TR_KEY_dht_enabled; if (!tr_variantDictFind (settings, q)) tr_variantDictAddBool (settings, q, false); q = TR_KEY_message_level; if (!tr_variantDictFind (settings, q)) tr_variantDictAddInt (settings, q, verbose ? TR_LOG_DEBUG : TR_LOG_ERROR); session = tr_sessionInit ("libtransmission-test", sandbox, !verbose, settings); tr_free (sandbox); tr_variantFree (&local_settings); return session; }