XmlRpcMethodImpl.cc 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2009 Tatsuhiro Tsujikawa
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * In addition, as a special exception, the copyright holders give
  22. * permission to link the code of portions of this program with the
  23. * OpenSSL library under certain conditions as described in each
  24. * individual source file, and distribute linked combinations
  25. * including the two.
  26. * You must obey the GNU General Public License in all respects
  27. * for all of the code used other than OpenSSL. If you modify
  28. * file(s) with this exception, you may extend this exception to your
  29. * version of the file(s), but you are not obligated to do so. If you
  30. * do not wish to do so, delete this exception statement from your
  31. * version. If you delete this exception statement from all source
  32. * files in the program, then also delete it here.
  33. */
  34. /* copyright --> */
  35. #include "XmlRpcMethodImpl.h"
  36. #include <cassert>
  37. #include <algorithm>
  38. #include "Logger.h"
  39. #include "LogFactory.h"
  40. #include "BDE.h"
  41. #include "DlAbortEx.h"
  42. #include "Option.h"
  43. #include "OptionParser.h"
  44. #include "OptionHandler.h"
  45. #include "DownloadEngine.h"
  46. #include "RequestGroup.h"
  47. #include "download_helper.h"
  48. #include "util.h"
  49. #include "RequestGroupMan.h"
  50. #include "StringFormat.h"
  51. #include "XmlRpcRequest.h"
  52. #include "PieceStorage.h"
  53. #include "DownloadContext.h"
  54. #include "DiskAdaptor.h"
  55. #include "FileEntry.h"
  56. #include "BtProgressInfoFile.h"
  57. #include "prefs.h"
  58. #include "message.h"
  59. #include "FeatureConfig.h"
  60. #include "array_fun.h"
  61. #include "XmlRpcMethodFactory.h"
  62. #include "XmlRpcResponse.h"
  63. #include "SegmentMan.h"
  64. #include "TimedHaltCommand.h"
  65. #ifdef ENABLE_BITTORRENT
  66. # include "bittorrent_helper.h"
  67. # include "BtRegistry.h"
  68. # include "PeerStorage.h"
  69. # include "Peer.h"
  70. # include "BtRuntime.h"
  71. # include "BtAnnounce.h"
  72. #endif // ENABLE_BITTORRENT
  73. namespace aria2 {
  74. namespace xmlrpc {
  75. namespace {
  76. const BDE BDE_TRUE = BDE("true");
  77. const BDE BDE_FALSE = BDE("false");
  78. const BDE BDE_OK = BDE("OK");
  79. const BDE BDE_ACTIVE = BDE("active");
  80. const BDE BDE_WAITING = BDE("waiting");
  81. const BDE BDE_PAUSED = BDE("paused");
  82. const BDE BDE_REMOVED = BDE("removed");
  83. const BDE BDE_ERROR = BDE("error");
  84. const BDE BDE_COMPLETE = BDE("complete");
  85. const BDE BDE_USED = BDE("used");
  86. const std::string KEY_GID = "gid";
  87. const std::string KEY_ERROR_CODE = "errorCode";
  88. const std::string KEY_STATUS = "status";
  89. const std::string KEY_TOTAL_LENGTH = "totalLength";
  90. const std::string KEY_COMPLETED_LENGTH = "completedLength";
  91. const std::string KEY_DOWNLOAD_SPEED = "downloadSpeed";
  92. const std::string KEY_UPLOAD_SPEED = "uploadSpeed";
  93. const std::string KEY_UPLOAD_LENGTH = "uploadLength";
  94. const std::string KEY_CONNECTIONS = "connections";
  95. const std::string KEY_BITFIELD = "bitfield";
  96. const std::string KEY_PIECE_LENGTH = "pieceLength";
  97. const std::string KEY_NUM_PIECES = "numPieces";
  98. const std::string KEY_FOLLOWED_BY = "followedBy";
  99. const std::string KEY_BELONGS_TO = "belongsTo";
  100. const std::string KEY_INFO_HASH = "infoHash";
  101. const std::string KEY_NUM_SEEDERS = "numSeeders";
  102. const std::string KEY_PEER_ID = "peerId";
  103. const std::string KEY_IP = "ip";
  104. const std::string KEY_PORT = "port";
  105. const std::string KEY_AM_CHOKING = "amChoking";
  106. const std::string KEY_PEER_CHOKING = "peerChoking";
  107. const std::string KEY_SEEDER = "seeder";
  108. const std::string KEY_INDEX = "index";
  109. const std::string KEY_PATH = "path";
  110. const std::string KEY_SELECTED = "selected";
  111. const std::string KEY_LENGTH = "length";
  112. const std::string KEY_URI = "uri";
  113. const std::string KEY_CURRENT_URI = "currentUri";
  114. const std::string KEY_VERSION = "version";
  115. const std::string KEY_ENABLED_FEATURES = "enabledFeatures";
  116. const std::string KEY_METHOD_NAME = "methodName";
  117. const std::string KEY_PARAMS = "params";
  118. const std::string KEY_SESSION_ID = "sessionId";
  119. const std::string KEY_FILES = "files";
  120. const std::string KEY_DIR = "dir";
  121. const std::string KEY_URIS = "uris";
  122. const std::string KEY_BITTORRENT = "bittorrent";
  123. const std::string KEY_INFO = "info";
  124. const std::string KEY_NAME = "name";
  125. const std::string KEY_ANNOUNCE_LIST = "announceList";
  126. const std::string KEY_COMMENT = "comment";
  127. const std::string KEY_CREATION_DATE = "creationDate";
  128. const std::string KEY_MODE = "mode";
  129. const std::string KEY_SERVERS = "servers";
  130. }
  131. static BDE createGIDResponse(gid_t gid)
  132. {
  133. return BDE(util::itos(gid));
  134. }
  135. static BDE addRequestGroup(const SharedHandle<RequestGroup>& group,
  136. DownloadEngine* e,
  137. bool posGiven, int pos)
  138. {
  139. if(posGiven) {
  140. e->_requestGroupMan->insertReservedGroup(pos, group);
  141. } else {
  142. e->_requestGroupMan->addReservedGroup(group);
  143. }
  144. return createGIDResponse(group->getGID());
  145. }
  146. static
  147. SharedHandle<RequestGroup>
  148. findRequestGroup(const SharedHandle<RequestGroupMan>& rgman, gid_t gid)
  149. {
  150. SharedHandle<RequestGroup> group = rgman->findRequestGroup(gid);
  151. if(group.isNull()) {
  152. group = rgman->findReservedGroup(gid);
  153. }
  154. return group;
  155. }
  156. static bool hasDictParam(const BDE& params, size_t index)
  157. {
  158. return params.size() > index && params[index].isDict();
  159. }
  160. static void getPosParam(const BDE& params, size_t posParamIndex,
  161. bool& posGiven, size_t& pos)
  162. {
  163. if(params.size() > posParamIndex && params[posParamIndex].isInteger()) {
  164. if(params[posParamIndex].i() >= 0) {
  165. pos = params[posParamIndex].i();
  166. posGiven = true;
  167. } else {
  168. throw DL_ABORT_EX("Position must be greater than or equal to 0.");
  169. }
  170. } else {
  171. posGiven = false;
  172. }
  173. }
  174. template<typename OutputIterator>
  175. static void extractUris(OutputIterator out, const BDE& src)
  176. {
  177. for(BDE::List::const_iterator i = src.listBegin(), eoi = src.listEnd();
  178. i != eoi; ++i) {
  179. if((*i).isString()) {
  180. out++ = (*i).s();
  181. }
  182. }
  183. }
  184. BDE AddUriXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  185. {
  186. const BDE& params = req._params;
  187. assert(params.isList());
  188. if(params.empty() || !params[0].isList() || params[0].empty()) {
  189. throw DL_ABORT_EX("URI is not provided.");
  190. }
  191. std::vector<std::string> uris;
  192. extractUris(std::back_inserter(uris), params[0]);
  193. SharedHandle<Option> requestOption(new Option(*e->option));
  194. if(hasDictParam(params, 1)) {
  195. gatherRequestOption(requestOption, params[1]);
  196. }
  197. size_t pos = 0;
  198. bool posGiven = false;
  199. getPosParam(params, 2, posGiven, pos);
  200. std::vector<SharedHandle<RequestGroup> > result;
  201. createRequestGroupForUri(result, requestOption, uris,
  202. /* ignoreForceSeq = */ true,
  203. /* ignoreLocalPath = */ true);
  204. if(!result.empty()) {
  205. return addRequestGroup(result.front(), e, posGiven, pos);
  206. } else {
  207. throw DL_ABORT_EX("No URI to download.");
  208. }
  209. }
  210. #ifdef ENABLE_BITTORRENT
  211. BDE AddTorrentXmlRpcMethod::process
  212. (const XmlRpcRequest& req, DownloadEngine* e)
  213. {
  214. const BDE& params = req._params;
  215. assert(params.isList());
  216. if(params.empty() || !params[0].isString()) {
  217. throw DL_ABORT_EX("Torrent data is not provided.");
  218. }
  219. std::vector<std::string> uris;
  220. if(params.size() > 1 && params[1].isList()) {
  221. extractUris(std::back_inserter(uris), params[1]);
  222. }
  223. SharedHandle<Option> requestOption(new Option(*e->option));
  224. if(hasDictParam(params, 2)) {
  225. gatherRequestOption(requestOption, params[2]);
  226. }
  227. size_t pos = 0;
  228. bool posGiven = false;
  229. getPosParam(params, 3, posGiven, pos);
  230. std::vector<SharedHandle<RequestGroup> > result;
  231. createRequestGroupForBitTorrent(result, requestOption,
  232. uris,
  233. params[0].s());
  234. if(!result.empty()) {
  235. return addRequestGroup(result.front(), e, posGiven, pos);
  236. } else {
  237. throw DL_ABORT_EX("No Torrent to download.");
  238. }
  239. }
  240. #endif // ENABLE_BITTORRENT
  241. #ifdef ENABLE_METALINK
  242. BDE AddMetalinkXmlRpcMethod::process
  243. (const XmlRpcRequest& req, DownloadEngine* e)
  244. {
  245. const BDE& params = req._params;
  246. assert(params.isList());
  247. if(params.empty() || !params[0].isString()) {
  248. throw DL_ABORT_EX("Metalink data is not provided.");
  249. }
  250. SharedHandle<Option> requestOption(new Option(*e->option));
  251. if(hasDictParam(params, 1)) {
  252. gatherRequestOption(requestOption, params[1]);
  253. };
  254. size_t pos = 0;
  255. bool posGiven = false;
  256. getPosParam(params, 2, posGiven, pos);
  257. std::vector<SharedHandle<RequestGroup> > result;
  258. createRequestGroupForMetalink(result, requestOption, params[0].s());
  259. if(!result.empty()) {
  260. if(posGiven) {
  261. e->_requestGroupMan->insertReservedGroup(pos, result);
  262. } else {
  263. e->_requestGroupMan->addReservedGroup(result);
  264. }
  265. BDE gids = BDE::list();
  266. for(std::vector<SharedHandle<RequestGroup> >::const_iterator i =
  267. result.begin(), eoi = result.end(); i != eoi; ++i) {
  268. gids << BDE(util::itos((*i)->getGID()));
  269. }
  270. return gids;
  271. } else {
  272. throw DL_ABORT_EX("No files to download.");
  273. }
  274. }
  275. #endif // ENABLE_METALINK
  276. static BDE removeDownload
  277. (const XmlRpcRequest& req, DownloadEngine* e, bool forceRemove)
  278. {
  279. const BDE& params = req._params;
  280. assert(params.isList());
  281. if(params.empty() || !params[0].isString()) {
  282. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  283. }
  284. gid_t gid = util::parseLLInt(params[0].s());
  285. SharedHandle<RequestGroup> group = e->_requestGroupMan->findRequestGroup(gid);
  286. if(group.isNull()) {
  287. group = e->_requestGroupMan->findReservedGroup(gid);
  288. if(group.isNull()) {
  289. throw DL_ABORT_EX
  290. (StringFormat("Active Download not found for GID#%s",
  291. util::itos(gid).c_str()).str());
  292. }
  293. if(group->isDependencyResolved()) {
  294. e->_requestGroupMan->removeReservedGroup(gid);
  295. } else {
  296. throw DL_ABORT_EX
  297. (StringFormat("GID#%s cannot be removed now",
  298. util::itos(gid).c_str()).str());
  299. }
  300. } else {
  301. if(forceRemove) {
  302. group->setForceHaltRequested(true, RequestGroup::USER_REQUEST);
  303. } else {
  304. group->setHaltRequested(true, RequestGroup::USER_REQUEST);
  305. }
  306. }
  307. return createGIDResponse(gid);
  308. }
  309. BDE RemoveXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  310. {
  311. return removeDownload(req, e, false);
  312. }
  313. BDE ForceRemoveXmlRpcMethod::process
  314. (const XmlRpcRequest& req, DownloadEngine* e)
  315. {
  316. return removeDownload(req, e, true);
  317. }
  318. static bool pauseRequestGroup
  319. (const SharedHandle<RequestGroup>& group, bool reserved, bool forcePause)
  320. {
  321. if((reserved && !group->isPauseRequested()) ||
  322. (!reserved &&
  323. !group->isForceHaltRequested() &&
  324. ((forcePause && group->isHaltRequested() && group->isPauseRequested()) ||
  325. (!group->isHaltRequested() && !group->isPauseRequested())))) {
  326. if(!reserved) {
  327. // Call setHaltRequested before setPauseRequested because
  328. // setHaltRequested calls setPauseRequested(false) internally.
  329. if(forcePause) {
  330. group->setForceHaltRequested(true, RequestGroup::NONE);
  331. } else {
  332. group->setHaltRequested(true, RequestGroup::NONE);
  333. }
  334. }
  335. group->setPauseRequested(true);
  336. return true;
  337. } else {
  338. return false;
  339. }
  340. }
  341. static BDE pauseDownload
  342. (const XmlRpcRequest& req, DownloadEngine* e, bool forcePause)
  343. {
  344. const BDE& params = req._params;
  345. assert(params.isList());
  346. if(params.empty() || !params[0].isString()) {
  347. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  348. }
  349. gid_t gid = util::parseLLInt(params[0].s());
  350. bool reserved = false;
  351. SharedHandle<RequestGroup> group = e->_requestGroupMan->findRequestGroup(gid);
  352. if(group.isNull()) {
  353. reserved = true;
  354. group = e->_requestGroupMan->findReservedGroup(gid);
  355. }
  356. if(!group.isNull() && pauseRequestGroup(group, reserved, forcePause)) {
  357. return createGIDResponse(gid);
  358. } else {
  359. throw DL_ABORT_EX
  360. (StringFormat("GID#%s cannot be paused now",
  361. util::itos(gid).c_str()).str());
  362. }
  363. }
  364. BDE PauseXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  365. {
  366. return pauseDownload(req, e, false);
  367. }
  368. BDE ForcePauseXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  369. {
  370. return pauseDownload(req, e, true);
  371. }
  372. template<typename InputIterator>
  373. static void pauseRequestGroups
  374. (InputIterator first, InputIterator last, bool reserved, bool forcePause)
  375. {
  376. for(; first != last; ++first) {
  377. pauseRequestGroup(*first, reserved, forcePause);
  378. }
  379. }
  380. static BDE pauseAllDownloads
  381. (const XmlRpcRequest& req, DownloadEngine* e, bool forcePause)
  382. {
  383. const std::deque<SharedHandle<RequestGroup> >& groups =
  384. e->_requestGroupMan->getRequestGroups();
  385. pauseRequestGroups(groups.begin(), groups.end(), false, forcePause);
  386. const std::deque<SharedHandle<RequestGroup> >& reservedGroups =
  387. e->_requestGroupMan->getReservedGroups();
  388. pauseRequestGroups(reservedGroups.begin(), reservedGroups.end(),
  389. true, forcePause);
  390. return BDE_OK;
  391. }
  392. BDE PauseAllXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  393. {
  394. return pauseAllDownloads(req, e, false);
  395. }
  396. BDE ForcePauseAllXmlRpcMethod::process
  397. (const XmlRpcRequest& req, DownloadEngine* e)
  398. {
  399. return pauseAllDownloads(req, e, true);
  400. }
  401. BDE UnpauseXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  402. {
  403. const BDE& params = req._params;
  404. assert(params.isList());
  405. if(params.empty() || !params[0].isString()) {
  406. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  407. }
  408. gid_t gid = util::parseLLInt(params[0].s());
  409. SharedHandle<RequestGroup> group =e->_requestGroupMan->findReservedGroup(gid);
  410. if(group.isNull() || !group->isPauseRequested()) {
  411. throw DL_ABORT_EX
  412. (StringFormat("GID#%s cannot be unpaused now",
  413. util::itos(gid).c_str()).str());
  414. } else {
  415. group->setPauseRequested(false);
  416. e->_requestGroupMan->requestQueueCheck();
  417. }
  418. return createGIDResponse(gid);
  419. }
  420. BDE UnpauseAllXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  421. {
  422. const std::deque<SharedHandle<RequestGroup> >& groups =
  423. e->_requestGroupMan->getReservedGroups();
  424. std::for_each(groups.begin(), groups.end(),
  425. std::bind2nd(mem_fun_sh(&RequestGroup::setPauseRequested),
  426. false));
  427. e->_requestGroupMan->requestQueueCheck();
  428. return BDE_OK;
  429. }
  430. static void createUriEntry(BDE& uriList, const SharedHandle<FileEntry>& file)
  431. {
  432. {
  433. const std::deque<std::string>& uris = file->getSpentUris();
  434. for(std::deque<std::string>::const_iterator i = uris.begin(),
  435. eoi = uris.end(); i != eoi; ++i) {
  436. BDE entry = BDE::dict();
  437. entry[KEY_URI] = *i;
  438. entry[KEY_STATUS] = BDE_USED;
  439. uriList << entry;
  440. }
  441. }
  442. {
  443. const std::deque<std::string>& uris = file->getRemainingUris();
  444. for(std::deque<std::string>::const_iterator i = uris.begin(),
  445. eoi = uris.end(); i != eoi; ++i) {
  446. BDE entry = BDE::dict();
  447. entry[KEY_URI] = *i;
  448. entry[KEY_STATUS] = BDE_WAITING;
  449. uriList << entry;
  450. }
  451. }
  452. }
  453. template<typename InputIterator>
  454. static void createFileEntry(BDE& files, InputIterator first, InputIterator last)
  455. {
  456. size_t index = 1;
  457. for(; first != last; ++first, ++index) {
  458. BDE entry = BDE::dict();
  459. entry[KEY_INDEX] = util::uitos(index);
  460. entry[KEY_PATH] = (*first)->getPath();
  461. entry[KEY_SELECTED] = (*first)->isRequested()?BDE_TRUE:BDE_FALSE;
  462. entry[KEY_LENGTH] = util::uitos((*first)->getLength());
  463. BDE uriList = BDE::list();
  464. createUriEntry(uriList, *first);
  465. entry[KEY_URIS] = uriList;
  466. files << entry;
  467. }
  468. }
  469. void gatherProgressCommon
  470. (BDE& entryDict, const SharedHandle<RequestGroup>& group)
  471. {
  472. entryDict[KEY_GID] = util::itos(group->getGID());
  473. // This is "filtered" total length if --select-file is used.
  474. entryDict[KEY_TOTAL_LENGTH] = util::uitos(group->getTotalLength());
  475. // This is "filtered" total length if --select-file is used.
  476. entryDict[KEY_COMPLETED_LENGTH] = util::uitos(group->getCompletedLength());
  477. TransferStat stat = group->calculateStat();
  478. entryDict[KEY_DOWNLOAD_SPEED] = util::uitos(stat.getDownloadSpeed());
  479. entryDict[KEY_UPLOAD_SPEED] = util::uitos(stat.getUploadSpeed());
  480. entryDict[KEY_UPLOAD_LENGTH] = util::uitos(stat.getAllTimeUploadLength());
  481. entryDict[KEY_CONNECTIONS] = util::uitos(group->getNumConnection());
  482. SharedHandle<PieceStorage> ps = group->getPieceStorage();
  483. if(!ps.isNull()) {
  484. if(ps->getBitfieldLength() > 0) {
  485. entryDict[KEY_BITFIELD] = util::toHex(ps->getBitfield(),
  486. ps->getBitfieldLength());
  487. }
  488. }
  489. const SharedHandle<DownloadContext>& dctx = group->getDownloadContext();
  490. entryDict[KEY_PIECE_LENGTH] = util::uitos(dctx->getPieceLength());
  491. entryDict[KEY_NUM_PIECES] = util::uitos(dctx->getNumPieces());
  492. if(!group->followedBy().empty()) {
  493. BDE list = BDE::list();
  494. // The element is GID.
  495. for(std::vector<gid_t>::const_iterator i = group->followedBy().begin(),
  496. eoi = group->followedBy().end(); i != eoi; ++i) {
  497. list << util::itos(*i);
  498. }
  499. entryDict[KEY_FOLLOWED_BY] = list;
  500. }
  501. if(group->belongsTo()) {
  502. entryDict[KEY_BELONGS_TO] = util::itos(group->belongsTo());
  503. }
  504. BDE files = BDE::list();
  505. createFileEntry
  506. (files, dctx->getFileEntries().begin(), dctx->getFileEntries().end());
  507. entryDict[KEY_FILES] = files;
  508. entryDict[KEY_DIR] = group->getOption()->get(PREF_DIR);
  509. }
  510. #ifdef ENABLE_BITTORRENT
  511. void gatherBitTorrentMetadata(BDE& btDict, const BDE& torrentAttrs)
  512. {
  513. if(torrentAttrs.containsKey(bittorrent::COMMENT)) {
  514. btDict[KEY_COMMENT] = torrentAttrs[bittorrent::COMMENT];
  515. }
  516. if(torrentAttrs.containsKey(bittorrent::CREATION_DATE)) {
  517. btDict[KEY_CREATION_DATE] = torrentAttrs[bittorrent::CREATION_DATE];
  518. }
  519. if(torrentAttrs.containsKey(bittorrent::MODE)) {
  520. btDict[KEY_MODE] = torrentAttrs[bittorrent::MODE];
  521. }
  522. // Copy announceList to avoid modification on entyDict to be
  523. // affected original announceList.
  524. // TODO Would it be good to add copy() method in BDE?
  525. const BDE& announceList = torrentAttrs[bittorrent::ANNOUNCE_LIST];
  526. BDE destAnnounceList = BDE::list();
  527. for(BDE::List::const_iterator l = announceList.listBegin(),
  528. eoi = announceList.listEnd(); l != eoi; ++l) {
  529. BDE destAnnounceTier = BDE::list();
  530. for(BDE::List::const_iterator t = (*l).listBegin(),
  531. eoi2 = (*l).listEnd(); t != eoi2; ++t) {
  532. destAnnounceTier << (*t);
  533. }
  534. destAnnounceList << destAnnounceTier;
  535. }
  536. btDict[KEY_ANNOUNCE_LIST] = destAnnounceList;
  537. if(torrentAttrs.containsKey(bittorrent::METADATA)) {
  538. BDE infoDict = BDE::dict();
  539. infoDict[KEY_NAME] = torrentAttrs[bittorrent::NAME];
  540. btDict[KEY_INFO] = infoDict;
  541. }
  542. }
  543. static void gatherProgressBitTorrent
  544. (BDE& entryDict, const BDE& torrentAttrs, const BtObject& btObject)
  545. {
  546. const std::string& infoHash = torrentAttrs[bittorrent::INFO_HASH].s();
  547. entryDict[KEY_INFO_HASH] = util::toHex(infoHash);
  548. BDE btDict = BDE::dict();
  549. gatherBitTorrentMetadata(btDict, torrentAttrs);
  550. entryDict[KEY_BITTORRENT] = btDict;
  551. if(!btObject.isNull()) {
  552. SharedHandle<PeerStorage> peerStorage = btObject._peerStorage;
  553. assert(!peerStorage.isNull());
  554. std::vector<SharedHandle<Peer> > peers;
  555. peerStorage->getActivePeers(peers);
  556. entryDict[KEY_NUM_SEEDERS] =
  557. util::uitos(countSeeder(peers.begin(), peers.end()));
  558. }
  559. }
  560. static void gatherPeer(BDE& peers, const SharedHandle<PeerStorage>& ps)
  561. {
  562. std::vector<SharedHandle<Peer> > activePeers;
  563. ps->getActivePeers(activePeers);
  564. for(std::vector<SharedHandle<Peer> >::const_iterator i =
  565. activePeers.begin(), eoi = activePeers.end(); i != eoi; ++i) {
  566. BDE peerEntry = BDE::dict();
  567. peerEntry[KEY_PEER_ID] = util::torrentPercentEncode((*i)->getPeerId(),
  568. PEER_ID_LENGTH);
  569. peerEntry[KEY_IP] = (*i)->ipaddr;
  570. if((*i)->isIncomingPeer()) {
  571. peerEntry[KEY_PORT] = std::string("0");
  572. } else {
  573. peerEntry[KEY_PORT] = util::uitos((*i)->port);
  574. }
  575. peerEntry[KEY_BITFIELD] = util::toHex((*i)->getBitfield(),
  576. (*i)->getBitfieldLength());
  577. peerEntry[KEY_AM_CHOKING] = (*i)->amChoking()?BDE_TRUE:BDE_FALSE;
  578. peerEntry[KEY_PEER_CHOKING] = (*i)->peerChoking()?BDE_TRUE:BDE_FALSE;
  579. TransferStat stat = ps->getTransferStatFor(*i);
  580. peerEntry[KEY_DOWNLOAD_SPEED] = util::uitos(stat.getDownloadSpeed());
  581. peerEntry[KEY_UPLOAD_SPEED] = util::uitos(stat.getUploadSpeed());
  582. peerEntry[KEY_SEEDER] = (*i)->isSeeder()?BDE_TRUE:BDE_FALSE;
  583. peers << peerEntry;
  584. }
  585. }
  586. #endif // ENABLE_BITTORRENT
  587. static void gatherProgress
  588. (BDE& entryDict, const SharedHandle<RequestGroup>& group, DownloadEngine* e)
  589. {
  590. gatherProgressCommon(entryDict, group);
  591. #ifdef ENABLE_BITTORRENT
  592. if(group->getDownloadContext()->hasAttribute(bittorrent::BITTORRENT)) {
  593. const BDE& torrentAttrs =
  594. group->getDownloadContext()->getAttribute(bittorrent::BITTORRENT);
  595. BtObject btObject = e->getBtRegistry()->get(group->getGID());
  596. gatherProgressBitTorrent(entryDict, torrentAttrs, btObject);
  597. }
  598. #endif // ENABLE_BITTORRENT
  599. }
  600. void gatherStoppedDownload
  601. (BDE& entryDict, const SharedHandle<DownloadResult>& ds)
  602. {
  603. entryDict[KEY_GID] = util::itos(ds->gid);
  604. entryDict[KEY_ERROR_CODE] = util::itos(static_cast<int>(ds->result));
  605. if(ds->result == downloadresultcode::IN_PROGRESS) {
  606. entryDict[KEY_STATUS] = BDE_REMOVED;
  607. } else if(ds->result == downloadresultcode::FINISHED) {
  608. entryDict[KEY_STATUS] = BDE_COMPLETE;
  609. } else {
  610. entryDict[KEY_STATUS] = BDE_ERROR;
  611. }
  612. if(!ds->followedBy.empty()) {
  613. BDE list = BDE::list();
  614. // The element is GID.
  615. for(std::vector<gid_t>::const_iterator i = ds->followedBy.begin(),
  616. eoi = ds->followedBy.end(); i != eoi; ++i) {
  617. list << util::itos(*i);
  618. }
  619. entryDict[KEY_FOLLOWED_BY] = list;
  620. }
  621. if(ds->belongsTo) {
  622. entryDict[KEY_BELONGS_TO] = util::itos(ds->belongsTo);
  623. }
  624. BDE files = BDE::list();
  625. createFileEntry(files, ds->fileEntries.begin(), ds->fileEntries.end());
  626. entryDict[KEY_FILES] = files;
  627. }
  628. BDE GetFilesXmlRpcMethod::process
  629. (const XmlRpcRequest& req, DownloadEngine* e)
  630. {
  631. const BDE& params = req._params;
  632. assert(params.isList());
  633. if(params.empty() || !params[0].isString()) {
  634. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  635. }
  636. gid_t gid = util::parseLLInt(params[0].s());
  637. BDE files = BDE::list();
  638. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  639. if(group.isNull()) {
  640. SharedHandle<DownloadResult> dr =
  641. e->_requestGroupMan->findDownloadResult(gid);
  642. if(dr.isNull()) {
  643. throw DL_ABORT_EX
  644. (StringFormat("No file data is available for GID#%s",
  645. util::itos(gid).c_str()).str());
  646. } else {
  647. createFileEntry(files, dr->fileEntries.begin(), dr->fileEntries.end());
  648. }
  649. } else {
  650. createFileEntry(files,
  651. group->getDownloadContext()->getFileEntries().begin(),
  652. group->getDownloadContext()->getFileEntries().end());
  653. }
  654. return files;
  655. }
  656. BDE GetUrisXmlRpcMethod::process
  657. (const XmlRpcRequest& req, DownloadEngine* e)
  658. {
  659. const BDE& params = req._params;
  660. assert(params.isList());
  661. if(params.empty() || !params[0].isString()) {
  662. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  663. }
  664. gid_t gid = util::parseLLInt(params[0].s());
  665. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  666. if(group.isNull()) {
  667. throw DL_ABORT_EX
  668. (StringFormat("No URI data is available for GID#%s",
  669. util::itos(gid).c_str()).str());
  670. }
  671. BDE uriList = BDE::list();
  672. // TODO Current implementation just returns first FileEntry's URIs.
  673. if(!group->getDownloadContext()->getFileEntries().empty()) {
  674. createUriEntry(uriList, group->getDownloadContext()->getFirstFileEntry());
  675. }
  676. return uriList;
  677. }
  678. #ifdef ENABLE_BITTORRENT
  679. BDE GetPeersXmlRpcMethod::process
  680. (const XmlRpcRequest& req, DownloadEngine* e)
  681. {
  682. const BDE& params = req._params;
  683. assert(params.isList());
  684. if(params.empty() || !params[0].isString()) {
  685. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  686. }
  687. gid_t gid = util::parseLLInt(params[0].s());
  688. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  689. if(group.isNull()) {
  690. throw DL_ABORT_EX
  691. (StringFormat("No peer data is available for GID#%s",
  692. util::itos(gid).c_str()).str());
  693. }
  694. BDE peers = BDE::list();
  695. BtObject btObject = e->getBtRegistry()->get(group->getGID());
  696. if(!btObject.isNull()) {
  697. assert(!btObject._peerStorage.isNull());
  698. gatherPeer(peers, btObject._peerStorage);
  699. }
  700. return peers;
  701. }
  702. #endif // ENABLE_BITTORRENT
  703. BDE TellStatusXmlRpcMethod::process
  704. (const XmlRpcRequest& req, DownloadEngine* e)
  705. {
  706. const BDE& params = req._params;
  707. assert(params.isList());
  708. if(params.empty() || !params[0].isString()) {
  709. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  710. }
  711. gid_t gid = util::parseLLInt(params[0].s());
  712. SharedHandle<RequestGroup> group = e->_requestGroupMan->findRequestGroup(gid);
  713. BDE entryDict = BDE::dict();
  714. if(group.isNull()) {
  715. group = e->_requestGroupMan->findReservedGroup(gid);
  716. if(group.isNull()) {
  717. SharedHandle<DownloadResult> ds =
  718. e->_requestGroupMan->findDownloadResult(gid);
  719. if(ds.isNull()) {
  720. throw DL_ABORT_EX
  721. (StringFormat("No such download for GID#%s",
  722. util::itos(gid).c_str()).str());
  723. }
  724. gatherStoppedDownload(entryDict, ds);
  725. } else {
  726. if(group->isPauseRequested()) {
  727. entryDict[KEY_STATUS] = BDE_PAUSED;
  728. } else {
  729. entryDict[KEY_STATUS] = BDE_WAITING;
  730. }
  731. gatherProgress(entryDict, group, e);
  732. }
  733. } else {
  734. entryDict[KEY_STATUS] = BDE_ACTIVE;
  735. gatherProgress(entryDict, group, e);
  736. }
  737. return entryDict;
  738. }
  739. BDE TellActiveXmlRpcMethod::process
  740. (const XmlRpcRequest& req, DownloadEngine* e)
  741. {
  742. BDE list = BDE::list();
  743. const std::deque<SharedHandle<RequestGroup> >& groups =
  744. e->_requestGroupMan->getRequestGroups();
  745. for(std::deque<SharedHandle<RequestGroup> >::const_iterator i =
  746. groups.begin(), eoi = groups.end(); i != eoi; ++i) {
  747. BDE entryDict = BDE::dict();
  748. entryDict[KEY_STATUS] = BDE_ACTIVE;
  749. gatherProgress(entryDict, *i, e);
  750. list << entryDict;
  751. }
  752. return list;
  753. }
  754. const std::deque<SharedHandle<RequestGroup> >&
  755. TellWaitingXmlRpcMethod::getItems(DownloadEngine* e) const
  756. {
  757. return e->_requestGroupMan->getReservedGroups();
  758. }
  759. void TellWaitingXmlRpcMethod::createEntry
  760. (BDE& entryDict, const SharedHandle<RequestGroup>& item,
  761. DownloadEngine* e) const
  762. {
  763. if(item->isPauseRequested()) {
  764. entryDict[KEY_STATUS] = BDE_PAUSED;
  765. } else {
  766. entryDict[KEY_STATUS] = BDE_WAITING;
  767. }
  768. gatherProgress(entryDict, item, e);
  769. }
  770. const std::deque<SharedHandle<DownloadResult> >&
  771. TellStoppedXmlRpcMethod::getItems(DownloadEngine* e) const
  772. {
  773. return e->_requestGroupMan->getDownloadResults();
  774. }
  775. void TellStoppedXmlRpcMethod::createEntry
  776. (BDE& entryDict, const SharedHandle<DownloadResult>& item,
  777. DownloadEngine* e) const
  778. {
  779. gatherStoppedDownload(entryDict, item);
  780. }
  781. BDE PurgeDownloadResultXmlRpcMethod::process
  782. (const XmlRpcRequest& req, DownloadEngine* e)
  783. {
  784. e->_requestGroupMan->purgeDownloadResult();
  785. return BDE_OK;
  786. }
  787. BDE ChangeOptionXmlRpcMethod::process
  788. (const XmlRpcRequest& req, DownloadEngine* e)
  789. {
  790. const BDE& params = req._params;
  791. assert(params.isList());
  792. if(params.empty() || !params[0].isString()) {
  793. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  794. }
  795. gid_t gid = util::parseLLInt(params[0].s());
  796. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  797. if(group.isNull()) {
  798. throw DL_ABORT_EX
  799. (StringFormat("Cannot change option for GID#%s",
  800. util::itos(gid).c_str()).str());
  801. }
  802. SharedHandle<Option> option(new Option());
  803. if(params.size() > 1 && params[1].isDict()) {
  804. gatherChangeableOption(option, params[1]);
  805. applyChangeableOption(group->getOption().get(), option.get());
  806. if(option->defined(PREF_MAX_DOWNLOAD_LIMIT)) {
  807. group->setMaxDownloadSpeedLimit
  808. (option->getAsInt(PREF_MAX_DOWNLOAD_LIMIT));
  809. }
  810. if(option->defined(PREF_MAX_UPLOAD_LIMIT)) {
  811. group->setMaxUploadSpeedLimit(option->getAsInt(PREF_MAX_UPLOAD_LIMIT));
  812. }
  813. #ifdef ENABLE_BITTORRENT
  814. BtObject btObject = e->getBtRegistry()->get(group->getGID());
  815. if(!btObject.isNull()) {
  816. if(option->defined(PREF_BT_MAX_PEERS)) {
  817. btObject._btRuntime->setMaxPeers(option->getAsInt(PREF_BT_MAX_PEERS));
  818. }
  819. }
  820. #endif // ENABLE_BITTORRENT
  821. }
  822. return BDE_OK;
  823. }
  824. BDE ChangeGlobalOptionXmlRpcMethod::process
  825. (const XmlRpcRequest& req, DownloadEngine* e)
  826. {
  827. const BDE& params = req._params;
  828. assert(params.isList());
  829. if(params.empty() || !params[0].isDict()) {
  830. return BDE_OK;
  831. }
  832. SharedHandle<Option> option(new Option());
  833. gatherChangeableGlobalOption(option, params[0]);
  834. applyChangeableGlobalOption(e->option, option.get());
  835. if(option->defined(PREF_MAX_OVERALL_DOWNLOAD_LIMIT)) {
  836. e->_requestGroupMan->setMaxOverallDownloadSpeedLimit
  837. (option->getAsInt(PREF_MAX_OVERALL_DOWNLOAD_LIMIT));
  838. }
  839. if(option->defined(PREF_MAX_OVERALL_UPLOAD_LIMIT)) {
  840. e->_requestGroupMan->setMaxOverallUploadSpeedLimit
  841. (option->getAsInt(PREF_MAX_OVERALL_UPLOAD_LIMIT));
  842. }
  843. if(option->defined(PREF_MAX_CONCURRENT_DOWNLOADS)) {
  844. e->_requestGroupMan->setMaxSimultaneousDownloads
  845. (option->getAsInt(PREF_MAX_CONCURRENT_DOWNLOADS));
  846. e->_requestGroupMan->requestQueueCheck();
  847. }
  848. return BDE_OK;
  849. }
  850. BDE GetVersionXmlRpcMethod::process
  851. (const XmlRpcRequest& req, DownloadEngine* e)
  852. {
  853. BDE result = BDE::dict();
  854. result[KEY_VERSION] = std::string(PACKAGE_VERSION);
  855. BDE featureList = BDE::list();
  856. const FeatureMap& features = FeatureConfig::getInstance()->getFeatures();
  857. for(FeatureMap::const_iterator i = features.begin(), eoi = features.end();
  858. i != eoi;++i){
  859. if((*i).second) {
  860. featureList << (*i).first;
  861. }
  862. }
  863. result[KEY_ENABLED_FEATURES] = featureList;
  864. return result;
  865. }
  866. template<typename InputIterator>
  867. static void pushRequestOption
  868. (BDE& dict, InputIterator optionFirst, InputIterator optionLast)
  869. {
  870. const std::set<std::string>& requestOptions = listRequestOptions();
  871. for(; optionFirst != optionLast; ++optionFirst) {
  872. if(requestOptions.count((*optionFirst).first)) {
  873. dict[(*optionFirst).first] = (*optionFirst).second;
  874. }
  875. }
  876. }
  877. BDE GetOptionXmlRpcMethod::process
  878. (const XmlRpcRequest& req, DownloadEngine* e)
  879. {
  880. const BDE& params = req._params;
  881. assert(params.isList());
  882. if(params.empty() || !params[0].isString()) {
  883. throw DL_ABORT_EX(MSG_GID_NOT_PROVIDED);
  884. }
  885. gid_t gid = util::parseLLInt(params[0].s());
  886. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  887. if(group.isNull()) {
  888. throw DL_ABORT_EX
  889. (StringFormat("Cannot get option for GID#%s",
  890. util::itos(gid).c_str()).str());
  891. }
  892. BDE result = BDE::dict();
  893. SharedHandle<Option> option = group->getOption();
  894. pushRequestOption(result, option->begin(), option->end());
  895. return result;
  896. }
  897. BDE GetGlobalOptionXmlRpcMethod::process
  898. (const XmlRpcRequest& req, DownloadEngine* e)
  899. {
  900. BDE result = BDE::dict();
  901. for(std::map<std::string, std::string>::const_iterator i = e->option->begin(),
  902. eoi = e->option->end(); i != eoi; ++i) {
  903. SharedHandle<OptionHandler> h = _optionParser->findByName((*i).first);
  904. if(!h.isNull() && !h->isHidden()) {
  905. result[(*i).first] = (*i).second;
  906. }
  907. }
  908. return result;
  909. }
  910. BDE ChangePositionXmlRpcMethod::process
  911. (const XmlRpcRequest& req, DownloadEngine* e)
  912. {
  913. const BDE& params = req._params;
  914. assert(params.isList());
  915. if(params.size() != 3 ||
  916. !params[0].isString() || !params[1].isInteger() || !params[2].isString()) {
  917. throw DL_ABORT_EX("Illegal argument.");
  918. }
  919. gid_t gid = util::parseLLInt(params[0].s());
  920. int pos = params[1].i();
  921. const std::string& howStr = params[2].s();
  922. RequestGroupMan::HOW how;
  923. if(howStr == "POS_SET") {
  924. how = RequestGroupMan::POS_SET;
  925. } else if(howStr == "POS_CUR") {
  926. how = RequestGroupMan::POS_CUR;
  927. } else if(howStr == "POS_END") {
  928. how = RequestGroupMan::POS_END;
  929. } else {
  930. throw DL_ABORT_EX("Illegal argument.");
  931. }
  932. size_t destPos =
  933. e->_requestGroupMan->changeReservedGroupPosition(gid, pos, how);
  934. BDE result(destPos);
  935. return result;
  936. }
  937. BDE GetSessionInfoXmlRpcMethod::process
  938. (const XmlRpcRequest& req, DownloadEngine* e)
  939. {
  940. BDE result = BDE::dict();
  941. result[KEY_SESSION_ID] = util::toHex(e->getSessionId());
  942. return result;
  943. }
  944. BDE GetServersXmlRpcMethod::process
  945. (const XmlRpcRequest& req, DownloadEngine* e)
  946. {
  947. const BDE& params = req._params;
  948. assert(params.isList());
  949. if(params.empty() || !params[0].isString()) {
  950. throw DL_ABORT_EX("Bad request");
  951. }
  952. gid_t gid = util::parseLLInt(params[0].s());
  953. SharedHandle<RequestGroup> group = e->_requestGroupMan->findRequestGroup(gid);
  954. if(group.isNull()) {
  955. throw DL_ABORT_EX(StringFormat("No active download for GID#%s",
  956. util::itos(gid).c_str()).str());
  957. }
  958. SharedHandle<DownloadContext> dctx = group->getDownloadContext();
  959. const std::vector<SharedHandle<FileEntry> >& files = dctx->getFileEntries();
  960. BDE result = BDE::list();
  961. size_t index = 1;
  962. for(std::vector<SharedHandle<FileEntry> >::const_iterator fi = files.begin(),
  963. eoi = files.end(); fi != eoi; ++fi, ++index) {
  964. BDE fileEntry = BDE::dict();
  965. fileEntry[KEY_INDEX] = util::uitos(index);
  966. BDE servers = BDE::list();
  967. const std::deque<SharedHandle<Request> >& requests =
  968. (*fi)->getInFlightRequests();
  969. for(std::deque<SharedHandle<Request> >::const_iterator ri =requests.begin(),
  970. eoi = requests.end(); ri != eoi; ++ri) {
  971. SharedHandle<PeerStat> ps = (*ri)->getPeerStat();
  972. if(!ps.isNull()) {
  973. BDE serverEntry = BDE::dict();
  974. serverEntry[KEY_URI] = (*ri)->getUri();
  975. serverEntry[KEY_CURRENT_URI] = (*ri)->getCurrentUri();
  976. serverEntry[KEY_DOWNLOAD_SPEED] =
  977. util::uitos(ps->calculateDownloadSpeed());
  978. servers << serverEntry;
  979. }
  980. }
  981. fileEntry[KEY_SERVERS] = servers;
  982. result << fileEntry;
  983. }
  984. return result;
  985. }
  986. BDE ChangeUriXmlRpcMethod::process
  987. (const XmlRpcRequest& req, DownloadEngine* e)
  988. {
  989. const BDE& params = req._params;
  990. assert(params.isList());
  991. if(params.size() < 4 ||
  992. !params[0].isString() || !params[1].isInteger() ||
  993. !params[2].isList() || !params[3].isList() ||
  994. params[1].i() <= 0) {
  995. throw DL_ABORT_EX("Bad request");
  996. }
  997. size_t pos = 0;
  998. bool posGiven = false;
  999. getPosParam(params, 4, posGiven, pos);
  1000. gid_t gid = util::parseLLInt(params[0].s());
  1001. size_t index = params[1].i()-1;
  1002. const BDE& deluris = params[2];
  1003. const BDE& adduris = params[3];
  1004. SharedHandle<RequestGroup> group = findRequestGroup(e->_requestGroupMan, gid);
  1005. if(group.isNull()) {
  1006. throw DL_ABORT_EX
  1007. (StringFormat("Cannot remove URIs from GID#%s",
  1008. util::itos(gid).c_str()).str());
  1009. }
  1010. SharedHandle<DownloadContext> dctx = group->getDownloadContext();
  1011. const std::vector<SharedHandle<FileEntry> >& files = dctx->getFileEntries();
  1012. if(files.size() <= index) {
  1013. throw DL_ABORT_EX(StringFormat("fileIndex is out of range").str());
  1014. }
  1015. SharedHandle<FileEntry> s = files[index];
  1016. size_t delcount = 0;
  1017. for(BDE::List::const_iterator i = deluris.listBegin(),
  1018. eoi = deluris.listEnd(); i != eoi; ++i) {
  1019. if(s->removeUri((*i).s())) {
  1020. ++delcount;
  1021. }
  1022. }
  1023. size_t addcount = 0;
  1024. if(posGiven) {
  1025. for(BDE::List::const_iterator i = adduris.listBegin(),
  1026. eoi = adduris.listEnd(); i != eoi; ++i) {
  1027. if(s->insertUri((*i).s(), pos)) {
  1028. ++addcount;
  1029. ++pos;
  1030. }
  1031. }
  1032. } else {
  1033. for(BDE::List::const_iterator i = adduris.listBegin(),
  1034. eoi = adduris.listEnd(); i != eoi; ++i) {
  1035. if(s->addUri((*i).s())) {
  1036. ++addcount;
  1037. }
  1038. }
  1039. }
  1040. if(addcount && !group->getPieceStorage().isNull()) {
  1041. std::vector<Command*> commands;
  1042. group->createNextCommand(commands, e);
  1043. e->addCommand(commands);
  1044. group->getSegmentMan()->recognizeSegmentFor(s);
  1045. }
  1046. BDE res = BDE::list();
  1047. res << delcount;
  1048. res << addcount;
  1049. return res;
  1050. }
  1051. static BDE goingShutdown
  1052. (const XmlRpcRequest& req, DownloadEngine* e, bool forceHalt)
  1053. {
  1054. // Schedule shutdown after 3seconds to give time to client to
  1055. // receive XML-RPC response.
  1056. e->addRoutineCommand(new TimedHaltCommand(e->newCUID(), e, 3, forceHalt));
  1057. LogFactory::getInstance()->info("Scheduled shutdown in 3 seconds.");
  1058. return BDE_OK;
  1059. }
  1060. BDE ShutdownXmlRpcMethod::process(const XmlRpcRequest& req, DownloadEngine* e)
  1061. {
  1062. return goingShutdown(req, e, false);
  1063. }
  1064. BDE ForceShutdownXmlRpcMethod::process
  1065. (const XmlRpcRequest& req, DownloadEngine* e)
  1066. {
  1067. return goingShutdown(req, e, true);
  1068. }
  1069. BDE SystemMulticallXmlRpcMethod::process
  1070. (const XmlRpcRequest& req, DownloadEngine* e)
  1071. {
  1072. const BDE& params = req._params;
  1073. assert(params.isList());
  1074. if(params.size() != 1) {
  1075. throw DL_ABORT_EX("Illegal argument. One item list is expected.");
  1076. }
  1077. const BDE& methodSpecs = params[0];
  1078. BDE list = BDE::list();
  1079. for(BDE::List::const_iterator i = methodSpecs.listBegin(),
  1080. eoi = methodSpecs.listEnd(); i != eoi; ++i) {
  1081. if(!(*i).isDict()) {
  1082. list << createErrorResponse
  1083. (DL_ABORT_EX("system.multicall expected struct."));
  1084. continue;
  1085. }
  1086. if(!(*i).containsKey(KEY_METHOD_NAME) ||
  1087. !(*i).containsKey(KEY_PARAMS)) {
  1088. list << createErrorResponse
  1089. (DL_ABORT_EX("Missing methodName or params."));
  1090. continue;
  1091. }
  1092. const std::string& methodName = (*i)[KEY_METHOD_NAME].s();
  1093. if(methodName == getMethodName()) {
  1094. list << createErrorResponse
  1095. (DL_ABORT_EX("Recursive system.multicall forbidden."));
  1096. continue;
  1097. }
  1098. SharedHandle<XmlRpcMethod> method = XmlRpcMethodFactory::create(methodName);
  1099. XmlRpcRequest innerReq(methodName, (*i)[KEY_PARAMS]);
  1100. XmlRpcResponse res = method->execute(innerReq, e);
  1101. if(res._code == 0) {
  1102. BDE l = BDE::list();
  1103. l << res._param;
  1104. list << l;
  1105. } else {
  1106. list << res._param;
  1107. }
  1108. }
  1109. return list;
  1110. }
  1111. BDE NoSuchMethodXmlRpcMethod::process
  1112. (const XmlRpcRequest& req, DownloadEngine* e)
  1113. {
  1114. throw DL_ABORT_EX
  1115. (StringFormat("No such method: %s", req._methodName.c_str()).str());
  1116. }
  1117. } // namespace xmlrpc
  1118. } // namespace aria2