static uint64_t loadDND (tr_variant * dict, tr_torrent * tor) { uint64_t ret = 0; tr_variant * list = NULL; const tr_file_index_t n = tor->info.fileCount; if (tr_variantDictFindList (dict, TR_KEY_dnd, &list) && (tr_variantListSize (list) == n)) { int64_t tmp; tr_file_index_t * dl = tr_new (tr_file_index_t, n); tr_file_index_t * dnd = tr_new (tr_file_index_t, n); tr_file_index_t i, dlCount = 0, dndCount = 0; for (i=0; i<n; ++i) { if (tr_variantGetInt (tr_variantListChild (list, i), &tmp) && tmp) dnd[dndCount++] = i; else dl[dlCount++] = i; } if (dndCount) { tr_torrentInitFileDLs (tor, dnd, dndCount, false); tr_logAddTorDbg (tor, "Resume file found %d files listed as dnd", dndCount); } if (dlCount) { tr_torrentInitFileDLs (tor, dl, dlCount, true); tr_logAddTorDbg (tor, "Resume file found %d files marked for download", dlCount); } tr_free (dnd); tr_free (dl); ret = TR_FR_DND; } else { tr_logAddTorDbg ( tor, "Couldn't load DND flags. DND list (%p) has %zu children; torrent has %d files", list, tr_variantListSize (list), (int)n); } return ret; }
static int test_list (void) { size_t len; int64_t i; const char * str; tr_variant top; tr_rpc_parse_list_str (&top, "12", -1); check (tr_variantIsInt (&top)); check (tr_variantGetInt (&top, &i)); check_int_eq (12, i); tr_variantFree (&top); tr_rpc_parse_list_str (&top, "12", 1); check (tr_variantIsInt (&top)); check (tr_variantGetInt (&top, &i)); check_int_eq (1, i); tr_variantFree (&top); tr_rpc_parse_list_str (&top, "6,7", -1); check (tr_variantIsList (&top)); check (tr_variantListSize (&top) == 2); check (tr_variantGetInt (tr_variantListChild (&top, 0), &i)); check_int_eq (6, i); check (tr_variantGetInt (tr_variantListChild (&top, 1), &i)); check_int_eq (7, i); tr_variantFree (&top); tr_rpc_parse_list_str (&top, "asdf", -1); check (tr_variantIsString (&top)); check (tr_variantGetStr (&top, &str, &len)); check_int_eq (4, len); check_streq ("asdf", str); tr_variantFree (&top); tr_rpc_parse_list_str (&top, "1,3-5", -1); check (tr_variantIsList (&top)); check (tr_variantListSize (&top) == 4); check (tr_variantGetInt (tr_variantListChild (&top, 0), &i)); check_int_eq (1, i); check (tr_variantGetInt (tr_variantListChild (&top, 1), &i)); check_int_eq (3, i); check (tr_variantGetInt (tr_variantListChild (&top, 2), &i)); check_int_eq (4, i); check (tr_variantGetInt (tr_variantListChild (&top, 3), &i)); check_int_eq (5, i); tr_variantFree (&top); return 0; }
static uint64_t loadFilenames(tr_variant* dict, tr_torrent* tor) { tr_variant* list; uint64_t ret = 0; if (tr_variantDictFindList(dict, TR_KEY_files, &list)) { size_t const n = tr_variantListSize(list); tr_file* files = tor->info.files; for (size_t i = 0; i < tor->info.fileCount && i < n; ++i) { char const* str; size_t str_len; if (tr_variantGetStr(tr_variantListChild(list, i), &str, &str_len) && str != NULL && str_len != 0) { tr_free(files[i].name); files[i].name = tr_strndup(str, str_len); files[i].is_renamed = true; } } ret = TR_FR_FILENAMES; } return ret; }
static const char* parseFiles (tr_info * inf, tr_variant * files, const tr_variant * length) { int64_t len; inf->totalSize = 0; if (tr_variantIsList (files)) /* multi-file mode */ { tr_file_index_t i; struct evbuffer * buf = evbuffer_new (); inf->isMultifile = 1; inf->fileCount = tr_variantListSize (files); inf->files = tr_new0 (tr_file, inf->fileCount); for (i=0; i<inf->fileCount; i++) { tr_variant * file; tr_variant * path; file = tr_variantListChild (files, i); if (!tr_variantIsDict (file)) return "files"; if (!tr_variantDictFindList (file, TR_KEY_path_utf_8, &path)) if (!tr_variantDictFindList (file, TR_KEY_path, &path)) return "path"; if (!getfile (&inf->files[i].name, inf->name, path, buf)) return "path"; if (!tr_variantDictFindInt (file, TR_KEY_length, &len)) return "length"; inf->files[i].length = len; inf->totalSize += len; } evbuffer_free (buf); } else if (tr_variantGetInt (length, &len)) /* single-file mode */ { if (path_is_suspicious (inf->name)) return "path"; inf->isMultifile = 0; inf->fileCount = 1; inf->files = tr_new0 (tr_file, 1); inf->files[0].name = tr_strdup (inf->name); inf->files[0].length = len; inf->totalSize += len; } else { return "length"; } return NULL; }
static bool getfile (char ** setme, const char * root, tr_variant * path, struct evbuffer * buf) { bool success = false; size_t root_len = 0; *setme = NULL; /* root's already been checked by caller */ assert (!path_component_is_suspicious (root)); if (tr_variantIsList (path)) { int i; const int n = tr_variantListSize (path); success = true; evbuffer_drain (buf, evbuffer_get_length (buf)); root_len = strlen (root); evbuffer_add (buf, root, root_len); for (i=0; i<n; i++) { size_t len; const char * str; if (!tr_variantGetStr (tr_variantListChild (path, i), &str, &len) || path_component_is_suspicious (str)) { success = false; break; } if (!*str) continue; evbuffer_add (buf, TR_PATH_DELIMITER_STR, 1); evbuffer_add (buf, str, len); } } if (success && (evbuffer_get_length (buf) <= root_len)) { success = false; } if (success) { *setme = tr_utf8clean ((char*)evbuffer_pullup (buf, -1), evbuffer_get_length (buf)); /*fprintf (stderr, "[%s]\n", *setme);*/ } return success; }
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; }
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 uint64_t loadFilePriorities (tr_variant * dict, tr_torrent * tor) { tr_variant * list; uint64_t ret = 0; const tr_file_index_t n = tor->info.fileCount; if (tr_variantDictFindList (dict, TR_KEY_priority, &list) && (tr_variantListSize (list) == n)) { int64_t priority; tr_file_index_t i; for (i = 0; i < n; ++i) if (tr_variantGetInt (tr_variantListChild (list, i), &priority)) tr_torrentInitFilePriority (tor, i, priority); ret = TR_FR_FILE_PRIORITIES; } return ret; }
static bool getfile (char ** setme, const char * root, tr_variant * path, struct evbuffer * buf) { bool success = false; if (tr_variantIsList (path)) { int i; const int n = tr_variantListSize (path); evbuffer_drain (buf, evbuffer_get_length (buf)); evbuffer_add (buf, root, strlen (root)); for (i=0; i<n; i++) { size_t len; const char * str; if (tr_variantGetStr (tr_variantListChild (path, i), &str, &len)) { evbuffer_add (buf, TR_PATH_DELIMITER_STR, 1); evbuffer_add (buf, str, len); } } *setme = tr_utf8clean ((char*)evbuffer_pullup (buf, -1), evbuffer_get_length (buf)); /* fprintf (stderr, "[%s]\n", *setme); */ success = true; } if ((*setme != NULL) && path_is_suspicious (*setme)) { tr_free (*setme); *setme = NULL; success = false; } return success; }
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 char const* parseFiles(tr_info* inf, tr_variant* files, tr_variant const* length) { int64_t len; inf->totalSize = 0; if (tr_variantIsList(files)) /* multi-file mode */ { struct evbuffer* buf; char const* result; if (path_component_is_suspicious(inf->name)) { return "path"; } buf = evbuffer_new(); result = NULL; inf->isFolder = true; inf->fileCount = tr_variantListSize(files); inf->files = tr_new0(tr_file, inf->fileCount); for (tr_file_index_t i = 0; i < inf->fileCount; i++) { tr_variant* file; tr_variant* path; file = tr_variantListChild(files, i); if (!tr_variantIsDict(file)) { result = "files"; break; } if (!tr_variantDictFindList(file, TR_KEY_path_utf_8, &path)) { if (!tr_variantDictFindList(file, TR_KEY_path, &path)) { result = "path"; break; } } if (!getfile(&inf->files[i].name, inf->name, path, buf)) { result = "path"; break; } if (!tr_variantDictFindInt(file, TR_KEY_length, &len)) { result = "length"; break; } inf->files[i].length = len; inf->totalSize += len; } evbuffer_free(buf); return result; } else if (tr_variantGetInt(length, &len)) /* single-file mode */ { if (path_component_is_suspicious(inf->name)) { return "path"; } inf->isFolder = false; inf->fileCount = 1; inf->files = tr_new0(tr_file, 1); inf->files[0].name = tr_strdup(inf->name); inf->files[0].length = len; inf->totalSize += len; } else { return "length"; } return NULL; }
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; }