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); }
void tr_torrentSaveResume(tr_torrent* tor) { int err; tr_variant top; char* filename; if (!tr_isTorrent(tor)) { return; } tr_variantInitDict(&top, 50); /* arbitrary "big enough" number */ tr_variantDictAddInt(&top, TR_KEY_seeding_time_seconds, tor->secondsSeeding); tr_variantDictAddInt(&top, TR_KEY_downloading_time_seconds, tor->secondsDownloading); tr_variantDictAddInt(&top, TR_KEY_activity_date, tor->activityDate); tr_variantDictAddInt(&top, TR_KEY_added_date, tor->addedDate); tr_variantDictAddInt(&top, TR_KEY_corrupt, tor->corruptPrev + tor->corruptCur); tr_variantDictAddInt(&top, TR_KEY_done_date, tor->doneDate); tr_variantDictAddStr(&top, TR_KEY_destination, tor->downloadDir); if (tor->incompleteDir != NULL) { tr_variantDictAddStr(&top, TR_KEY_incomplete_dir, tor->incompleteDir); } tr_variantDictAddInt(&top, TR_KEY_downloaded, tor->downloadedPrev + tor->downloadedCur); tr_variantDictAddInt(&top, TR_KEY_uploaded, tor->uploadedPrev + tor->uploadedCur); tr_variantDictAddInt(&top, TR_KEY_max_peers, tor->maxConnectedPeers); tr_variantDictAddInt(&top, TR_KEY_bandwidth_priority, tr_torrentGetPriority(tor)); tr_variantDictAddBool(&top, TR_KEY_paused, !tor->isRunning && !tor->isQueued); savePeers(&top, tor); if (tr_torrentHasMetadata(tor)) { saveFilePriorities(&top, tor); saveDND(&top, tor); saveProgress(&top, tor); } saveSpeedLimits(&top, tor); saveRatioLimits(&top, tor); saveIdleLimits(&top, tor); saveFilenames(&top, tor); saveName(&top, tor); filename = getResumeFilename(tor); if ((err = tr_variantToFile(&top, TR_VARIANT_FMT_BENC, filename)) != 0) { tr_torrentSetLocalError(tor, "Unable to save resume file: %s", tr_strerror(err)); } tr_free(filename); tr_variantFree(&top); }
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 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; }
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; }
/** * This is where we initialize the preferences file with the default values. * If you add a new preferences key, you /must/ add a default value here. */ static void tr_prefs_init_defaults (tr_variant * d) { const char * dir; dir = g_get_user_special_dir (G_USER_DIRECTORY_DOWNLOAD); if (dir == NULL) dir = g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP); if (dir == NULL) dir = tr_getDefaultDownloadDir (); tr_variantDictReserve (d, 29); tr_variantDictAddStr (d, TR_KEY_watch_dir, dir); tr_variantDictAddBool (d, TR_KEY_watch_dir_enabled, FALSE); tr_variantDictAddBool (d, TR_KEY_user_has_given_informed_consent, FALSE); tr_variantDictAddBool (d, TR_KEY_inhibit_desktop_hibernation, FALSE); tr_variantDictAddBool (d, TR_KEY_blocklist_updates_enabled, TRUE); tr_variantDictAddStr (d, TR_KEY_open_dialog_dir, g_get_home_dir ()); tr_variantDictAddBool (d, TR_KEY_show_toolbar, TRUE); tr_variantDictAddBool (d, TR_KEY_show_filterbar, TRUE); tr_variantDictAddBool (d, TR_KEY_show_statusbar, TRUE); tr_variantDictAddBool (d, TR_KEY_trash_can_enabled, TRUE); tr_variantDictAddBool (d, TR_KEY_show_notification_area_icon, FALSE); tr_variantDictAddBool (d, TR_KEY_show_tracker_scrapes, FALSE); tr_variantDictAddBool (d, TR_KEY_show_extra_peer_details, FALSE); tr_variantDictAddBool (d, TR_KEY_show_backup_trackers, FALSE); tr_variantDictAddStr (d, TR_KEY_statusbar_stats, "total-ratio"); tr_variantDictAddBool (d, TR_KEY_torrent_added_notification_enabled, true); tr_variantDictAddBool (d, TR_KEY_torrent_complete_notification_enabled, true); tr_variantDictAddStr (d, TR_KEY_torrent_complete_sound_command, "canberra-gtk-play -i complete-download -d 'transmission torrent downloaded'"); tr_variantDictAddBool (d, TR_KEY_torrent_complete_sound_enabled, true); tr_variantDictAddBool (d, TR_KEY_show_options_window, TRUE); tr_variantDictAddBool (d, TR_KEY_main_window_is_maximized, FALSE); tr_variantDictAddInt (d, TR_KEY_main_window_height, 500); tr_variantDictAddInt (d, TR_KEY_main_window_width, 300); tr_variantDictAddInt (d, TR_KEY_main_window_x, 50); tr_variantDictAddInt (d, TR_KEY_main_window_y, 50); tr_variantDictAddStr (d, TR_KEY_download_dir, dir); tr_variantDictAddStr (d, TR_KEY_sort_mode, "sort-by-name"); tr_variantDictAddBool (d, TR_KEY_sort_reversed, FALSE); tr_variantDictAddBool (d, TR_KEY_compact_view, FALSE); }
static void handle_upload (struct evhttp_request * req, struct tr_rpc_server * server) { if (req->type != EVHTTP_REQ_POST) { send_simple_response (req, 405, NULL); } else { int i; int n; bool hasSessionId = false; tr_ptrArray parts = TR_PTR_ARRAY_INIT; const char * query = strchr (req->uri, '?'); const bool paused = query && strstr (query + 1, "paused=true"); extract_parts_from_multipart (req->input_headers, req->input_buffer, &parts); n = tr_ptrArraySize (&parts); /* first look for the session id */ for (i=0; i<n; ++i) { struct tr_mimepart * p = tr_ptrArrayNth (&parts, i); if (tr_memmem (p->headers, p->headers_len, TR_RPC_SESSION_ID_HEADER, strlen (TR_RPC_SESSION_ID_HEADER))) break; } if (i<n) { const struct tr_mimepart * p = tr_ptrArrayNth (&parts, i); const char * ours = get_current_session_id (server); const size_t ourlen = strlen (ours); hasSessionId = ourlen <= p->body_len && memcmp (p->body, ours, ourlen) == 0; } if (!hasSessionId) { int code = 409; const char * codetext = tr_webGetResponseStr (code); struct evbuffer * body = evbuffer_new (); evbuffer_add_printf (body, "%s", "{ \"success\": false, \"msg\": \"Bad Session-Id\" }");; evhttp_send_reply (req, code, codetext, body); evbuffer_free (body); } else for (i=0; i<n; ++i) { struct tr_mimepart * p = tr_ptrArrayNth (&parts, i); size_t body_len = p->body_len; tr_variant top, *args; tr_variant test; bool have_source = false; char * body = p->body; if (body_len >= 2 && memcmp (&body[body_len - 2], "\r\n", 2) == 0) body_len -= 2; tr_variantInitDict (&top, 2); tr_variantDictAddStr (&top, TR_KEY_method, "torrent-add"); args = tr_variantDictAddDict (&top, TR_KEY_arguments, 2); tr_variantDictAddBool (args, TR_KEY_paused, paused); if (tr_urlIsValid (body, body_len)) { tr_variantDictAddRaw (args, TR_KEY_filename, body, body_len); have_source = true; } else if (!tr_variantFromBenc (&test, body, body_len)) { char * b64 = tr_base64_encode (body, body_len, NULL); tr_variantDictAddStr (args, TR_KEY_metainfo, b64); tr_free (b64); have_source = true; } if (have_source) tr_rpc_request_exec_json (server->session, &top, NULL, NULL); tr_variantFree (&top); } tr_ptrArrayDestruct (&parts, (PtrArrayForeachFunc)tr_mimepart_free); /* send "success" response */ { int code = HTTP_OK; const char * codetext = tr_webGetResponseStr (code); struct evbuffer * body = evbuffer_new (); evbuffer_add_printf (body, "%s", "{ \"success\": true, \"msg\": \"Torrent Added\" }");; evhttp_send_reply (req, code, codetext, body); evbuffer_free (body); } } }
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 void saveName(tr_variant* dict, tr_torrent const* tor) { tr_variantDictAddStr(dict, TR_KEY_name, tr_torrentName(tor)); }
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; }
void gtr_pref_string_set (const tr_quark key, const char * value) { tr_variantDictAddStr (getPrefs (), key, value); }