/* * This file Copyright (C) 2009-2014 Mnemosyne LLC * * It may be used under the GNU GPL versions 2 or 3 * or any future license endorsed by Mnemosyne LLC. * */ #include /* EINVAL */ #include "transmission.h" #include "file.h" #include "magnet.h" #include "session.h" /* tr_sessionFindTorrentFile() */ #include "torrent.h" /* tr_ctorGetSave() */ #include "tr-assert.h" #include "utils.h" /* tr_new0 */ #include "variant.h" struct optional_args { bool isSet_paused; bool isSet_connected; bool isSet_downloadDir; bool isPaused; uint16_t peerLimit; char* downloadDir; }; /** Opaque class used when instantiating torrents. * @ingroup tr_ctor */ struct tr_ctor { tr_session const* session; bool saveInOurTorrentsDir; bool doDelete; tr_priority_t bandwidthPriority; bool isSet_metainfo; bool isSet_delete; tr_variant metainfo; char* sourceFile; struct optional_args optionalArgs[2]; char* cookies; char* incompleteDir; tr_file_index_t* want; tr_file_index_t wantSize; tr_file_index_t* notWant; tr_file_index_t notWantSize; tr_file_index_t* low; tr_file_index_t lowSize; tr_file_index_t* normal; tr_file_index_t normalSize; tr_file_index_t* high; tr_file_index_t highSize; }; /*** **** ***/ static void setSourceFile(tr_ctor* ctor, char const* sourceFile) { tr_free(ctor->sourceFile); ctor->sourceFile = tr_strdup(sourceFile); } static void clearMetainfo(tr_ctor* ctor) { if (ctor->isSet_metainfo) { ctor->isSet_metainfo = false; tr_variantFree(&ctor->metainfo); } setSourceFile(ctor, NULL); } int tr_ctorSetMetainfo(tr_ctor* ctor, void const* metainfo, size_t len) { int err; clearMetainfo(ctor); err = tr_variantFromBenc(&ctor->metainfo, metainfo, len); ctor->isSet_metainfo = err == 0; return err; } char const* tr_ctorGetSourceFile(tr_ctor const* ctor) { return ctor->sourceFile; } int tr_ctorSetMetainfoFromMagnetLink(tr_ctor* ctor, char const* magnet_link) { int err; tr_magnet_info* magnet_info = tr_magnetParse(magnet_link); if (magnet_info == NULL) { err = -1; } else { size_t len; tr_variant tmp; char* str; tr_magnetCreateMetainfo(magnet_info, &tmp); str = tr_variantToStr(&tmp, TR_VARIANT_FMT_BENC, &len); err = tr_ctorSetMetainfo(ctor, (uint8_t const*)str, len); tr_free(str); tr_variantFree(&tmp); tr_magnetFree(magnet_info); } return err; } int tr_ctorSetMetainfoFromFile(tr_ctor* ctor, char const* filename) { uint8_t* metainfo; size_t len; int err; metainfo = tr_loadFile(filename, &len, NULL); if (metainfo != NULL && len != 0) { 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)) { char const* name; if (!tr_variantDictFindStr(info, TR_KEY_name_utf_8, &name, NULL) && !tr_variantDictFindStr(info, TR_KEY_name, &name, NULL)) { name = NULL; } if (tr_str_is_empty(name)) { char* base = tr_sys_path_basename(filename, NULL); if (base != NULL) { tr_variantDictAddStr(info, TR_KEY_name, base); tr_free(base); } } } } tr_free(metainfo); return err; } int tr_ctorSetMetainfoFromHash(tr_ctor* ctor, char const* hashString) { int err; char const* filename; filename = tr_sessionFindTorrentFile(ctor->session, hashString); if (filename == NULL) { err = EINVAL; } else { err = tr_ctorSetMetainfoFromFile(ctor, filename); } return err; } /*** **** ***/ void tr_ctorSetFilePriorities(tr_ctor* ctor, tr_file_index_t const* files, tr_file_index_t fileCount, tr_priority_t priority) { tr_file_index_t** myfiles; tr_file_index_t* mycount; switch (priority) { case TR_PRI_LOW: myfiles = &ctor->low; mycount = &ctor->lowSize; break; case TR_PRI_HIGH: myfiles = &ctor->high; mycount = &ctor->highSize; break; default /*TR_PRI_NORMAL*/: myfiles = &ctor->normal; mycount = &ctor->normalSize; break; } tr_free(*myfiles); *myfiles = tr_memdup(files, sizeof(tr_file_index_t) * fileCount); *mycount = fileCount; } void tr_ctorInitTorrentPriorities(tr_ctor const* ctor, tr_torrent* tor) { for (tr_file_index_t i = 0; i < ctor->lowSize; ++i) { tr_torrentInitFilePriority(tor, ctor->low[i], TR_PRI_LOW); } for (tr_file_index_t i = 0; i < ctor->normalSize; ++i) { tr_torrentInitFilePriority(tor, ctor->normal[i], TR_PRI_NORMAL); } for (tr_file_index_t i = 0; i < ctor->highSize; ++i) { tr_torrentInitFilePriority(tor, ctor->high[i], TR_PRI_HIGH); } } void tr_ctorSetFilesWanted(tr_ctor* ctor, tr_file_index_t const* files, tr_file_index_t fileCount, bool wanted) { tr_file_index_t** myfiles = wanted ? &ctor->want : &ctor->notWant; tr_file_index_t* mycount = wanted ? &ctor->wantSize : &ctor->notWantSize; tr_free(*myfiles); *myfiles = tr_memdup(files, sizeof(tr_file_index_t) * fileCount); *mycount = fileCount; } void tr_ctorInitTorrentWanted(tr_ctor const* ctor, tr_torrent* tor) { if (ctor->notWantSize != 0) { tr_torrentInitFileDLs(tor, ctor->notWant, ctor->notWantSize, false); } if (ctor->wantSize != 0) { tr_torrentInitFileDLs(tor, ctor->want, ctor->wantSize, true); } } /*** **** ***/ void tr_ctorSetDeleteSource(tr_ctor* ctor, bool deleteSource) { ctor->doDelete = deleteSource; ctor->isSet_delete = true; } bool tr_ctorGetDeleteSource(tr_ctor const* ctor, bool* setme) { bool ret = true; if (!ctor->isSet_delete) { ret = false; } else if (setme != NULL) { *setme = ctor->doDelete; } return ret; } /*** **** ***/ void tr_ctorSetSave(tr_ctor* ctor, bool saveInOurTorrentsDir) { ctor->saveInOurTorrentsDir = saveInOurTorrentsDir; } bool tr_ctorGetSave(tr_ctor const* ctor) { return ctor != NULL && ctor->saveInOurTorrentsDir; } void tr_ctorSetPaused(tr_ctor* ctor, tr_ctorMode mode, bool isPaused) { TR_ASSERT(ctor != NULL); TR_ASSERT(mode == TR_FALLBACK || mode == TR_FORCE); struct optional_args* args = &ctor->optionalArgs[mode]; args->isSet_paused = true; args->isPaused = isPaused; } void tr_ctorSetPeerLimit(tr_ctor* ctor, tr_ctorMode mode, uint16_t peerLimit) { TR_ASSERT(ctor != NULL); TR_ASSERT(mode == TR_FALLBACK || mode == TR_FORCE); struct optional_args* args = &ctor->optionalArgs[mode]; args->isSet_connected = true; args->peerLimit = peerLimit; } void tr_ctorSetDownloadDir(tr_ctor* ctor, tr_ctorMode mode, char const* directory) { TR_ASSERT(ctor != NULL); TR_ASSERT(mode == TR_FALLBACK || mode == TR_FORCE); struct optional_args* args = &ctor->optionalArgs[mode]; tr_free(args->downloadDir); args->downloadDir = NULL; args->isSet_downloadDir = false; if (!tr_str_is_empty(directory)) { args->isSet_downloadDir = true; args->downloadDir = tr_strdup(directory); } } void tr_ctorSetIncompleteDir(tr_ctor* ctor, char const* directory) { tr_free(ctor->incompleteDir); ctor->incompleteDir = tr_strdup(directory); } bool tr_ctorGetPeerLimit(tr_ctor const* ctor, tr_ctorMode mode, uint16_t* setmeCount) { bool ret = true; struct optional_args const* args = &ctor->optionalArgs[mode]; if (!args->isSet_connected) { ret = false; } else if (setmeCount != NULL) { *setmeCount = args->peerLimit; } return ret; } bool tr_ctorGetPaused(tr_ctor const* ctor, tr_ctorMode mode, bool* setmeIsPaused) { bool ret = true; struct optional_args const* args = &ctor->optionalArgs[mode]; if (!args->isSet_paused) { ret = false; } else if (setmeIsPaused != NULL) { *setmeIsPaused = args->isPaused; } return ret; } bool tr_ctorGetDownloadDir(tr_ctor const* ctor, tr_ctorMode mode, char const** setmeDownloadDir) { bool ret = true; struct optional_args const* args = &ctor->optionalArgs[mode]; if (!args->isSet_downloadDir) { ret = false; } else if (setmeDownloadDir != NULL) { *setmeDownloadDir = args->downloadDir; } return ret; } bool tr_ctorGetIncompleteDir(tr_ctor const* ctor, char const** setmeIncompleteDir) { bool ret = true; if (ctor->incompleteDir == NULL) { ret = false; } else { *setmeIncompleteDir = ctor->incompleteDir; } return ret; } bool tr_ctorGetMetainfo(tr_ctor const* ctor, tr_variant const** setme) { bool ret = true; if (!ctor->isSet_metainfo) { ret = false; } else if (setme != NULL) { *setme = &ctor->metainfo; } return ret; } tr_session* tr_ctorGetSession(tr_ctor const* ctor) { return (tr_session*)ctor->session; } /*** **** ***/ static bool isPriority(int i) { return i == TR_PRI_LOW || i == TR_PRI_NORMAL || i == TR_PRI_HIGH; } void tr_ctorSetBandwidthPriority(tr_ctor* ctor, tr_priority_t priority) { if (isPriority(priority)) { ctor->bandwidthPriority = priority; } } tr_priority_t tr_ctorGetBandwidthPriority(tr_ctor const* ctor) { return ctor->bandwidthPriority; } /*** **** ***/ tr_ctor* tr_ctorNew(tr_session const* session) { tr_ctor* ctor = tr_new0(struct tr_ctor, 1); ctor->session = session; ctor->bandwidthPriority = TR_PRI_NORMAL; if (session != NULL) { tr_ctorSetDeleteSource(ctor, tr_sessionGetDeleteSource(session)); tr_ctorSetPaused(ctor, TR_FALLBACK, tr_sessionGetPaused(session)); tr_ctorSetPeerLimit(ctor, TR_FALLBACK, session->peerLimitPerTorrent); tr_ctorSetDownloadDir(ctor, TR_FALLBACK, tr_sessionGetDownloadDir(session)); } tr_ctorSetSave(ctor, true); return ctor; } void tr_ctorFree(tr_ctor* ctor) { clearMetainfo(ctor); tr_free(ctor->optionalArgs[1].downloadDir); tr_free(ctor->optionalArgs[0].downloadDir); tr_free(ctor->incompleteDir); tr_free(ctor->want); tr_free(ctor->notWant); tr_free(ctor->low); tr_free(ctor->high); tr_free(ctor->normal); tr_free(ctor); }