1 // Copyright Daniel Wallin 2006. Use, modification and distribution is
2 // subject to the Boost Software License, Version 1.0. (See accompanying
3 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
4 
5 #include "boost_python.hpp"
6 #include <boost/python/tuple.hpp>
7 #include <boost/python/stl_iterator.hpp>
8 #include "bytes.hpp"
9 #include <libtorrent/torrent_handle.hpp>
10 #include <libtorrent/torrent_info.hpp>
11 #include <libtorrent/torrent_status.hpp>
12 #include <libtorrent/entry.hpp>
13 #include <libtorrent/peer_info.hpp>
14 #include "libtorrent/announce_entry.hpp"
15 #include <libtorrent/storage.hpp>
16 #include <libtorrent/disk_interface.hpp>
17 #include "gil.hpp"
18 
19 using namespace boost::python;
20 using namespace lt;
21 
22 #ifdef _MSC_VER
23 #pragma warning(push)
24 // warning c4996: x: was declared deprecated
25 #pragma warning( disable : 4996 )
26 #endif
27 
28 namespace
29 {
30 
url_seeds(torrent_handle & handle)31   list url_seeds(torrent_handle& handle)
32   {
33       list ret;
34       std::set<std::string> urls;
35       {
36           allow_threading_guard guard;
37           urls = handle.url_seeds();
38       }
39 
40       for (std::set<std::string>::iterator i(urls.begin())
41           , end(urls.end()); i != end; ++i)
42           ret.append(*i);
43       return ret;
44   }
45 
http_seeds(torrent_handle & handle)46   list http_seeds(torrent_handle& handle)
47   {
48       list ret;
49       std::set<std::string> urls;
50       {
51           allow_threading_guard guard;
52           urls = handle.http_seeds();
53       }
54 
55       for (std::set<std::string>::iterator i(urls.begin())
56           , end(urls.end()); i != end; ++i)
57           ret.append(*i);
58       return ret;
59   }
60 
piece_availability(torrent_handle & handle)61   list piece_availability(torrent_handle& handle)
62   {
63       list ret;
64       std::vector<int> avail;
65       {
66           allow_threading_guard guard;
67           handle.piece_availability(avail);
68       }
69 
70       for (auto const a : avail)
71           ret.append(a);
72       return ret;
73   }
74 
piece_priorities(torrent_handle & handle)75   list piece_priorities(torrent_handle& handle)
76   {
77       list ret;
78       std::vector<download_priority_t> prio;
79       {
80           allow_threading_guard guard;
81           prio = handle.get_piece_priorities();
82       }
83 
84       for (auto const p : prio)
85           ret.append(p);
86       return ret;
87   }
88 
89 } // namespace unnamed
90 
file_progress(torrent_handle & handle,int flags)91 list file_progress(torrent_handle& handle, int flags)
92 {
93     std::vector<std::int64_t> p;
94 
95     {
96         allow_threading_guard guard;
97         std::shared_ptr<const torrent_info> ti = handle.torrent_file();
98         if (ti)
99         {
100            p.reserve(ti->num_files());
101            handle.file_progress(p, flags);
102         }
103     }
104 
105     list result;
106 
107     for (std::vector<std::int64_t>::iterator i(p.begin()), e(p.end()); i != e; ++i)
108         result.append(*i);
109 
110     return result;
111 }
112 
get_peer_info(torrent_handle const & handle)113 list get_peer_info(torrent_handle const& handle)
114 {
115     std::vector<peer_info> pi;
116 
117     {
118         allow_threading_guard guard;
119         handle.get_peer_info(pi);
120     }
121 
122     list result;
123 
124     for (std::vector<peer_info>::iterator i = pi.begin(); i != pi.end(); ++i)
125         result.append(*i);
126 
127     return result;
128 }
129 
130 namespace
131 {
132    template <typename T>
extract_fn(object o)133    T extract_fn(object o)
134    {
135       return boost::python::extract<T>(o);
136    }
137 }
138 
prioritize_pieces(torrent_handle & info,object o)139 void prioritize_pieces(torrent_handle& info, object o)
140 {
141    stl_input_iterator<object> begin(o), end;
142    if (begin == end) return;
143 
144    // determine which overload should be selected. the one taking a list of
145    // priorities or the one taking a list of piece -> priority mappings
146    bool const is_piece_list = extract<std::pair<piece_index_t, download_priority_t>>(*begin).check();
147 
148    if (is_piece_list)
149    {
150       std::vector<std::pair<piece_index_t, download_priority_t>> piece_list;
151       std::transform(begin, end, std::back_inserter(piece_list)
152          , &extract_fn<std::pair<piece_index_t, download_priority_t>>);
153       info.prioritize_pieces(piece_list);
154    }
155    else
156    {
157       std::vector<download_priority_t> priority_vector;
158       std::transform(begin, end, std::back_inserter(priority_vector)
159          , &extract_fn<download_priority_t>);
160       info.prioritize_pieces(priority_vector);
161    }
162 }
163 
prioritize_files(torrent_handle & info,object o)164 void prioritize_files(torrent_handle& info, object o)
165 {
166    stl_input_iterator<download_priority_t> begin(o), end;
167    info.prioritize_files(std::vector<download_priority_t>(begin, end));
168 }
169 
file_priorities(torrent_handle & handle)170 list file_priorities(torrent_handle& handle)
171 {
172     list ret;
173     std::vector<download_priority_t> priorities = handle.get_file_priorities();
174 
175     for (auto const p : priorities)
176         ret.append(p);
177 
178     return ret;
179 }
180 
file_prioritity0(torrent_handle & h,file_index_t index)181 download_priority_t file_prioritity0(torrent_handle& h, file_index_t index)
182 {
183    return h.file_priority(index);
184 }
185 
file_prioritity1(torrent_handle & h,file_index_t index,download_priority_t prio)186 void file_prioritity1(torrent_handle& h, file_index_t index, download_priority_t prio)
187 {
188    return h.file_priority(index, prio);
189 }
190 
dict_to_announce_entry(dict d,announce_entry & ae)191 void dict_to_announce_entry(dict d, announce_entry& ae)
192 {
193    ae.url = extract<std::string>(d["url"]);
194    if (d.has_key("tier"))
195       ae.tier = extract<std::uint8_t>(d["tier"]);
196    if (d.has_key("fail_limit"))
197       ae.fail_limit = extract<std::uint8_t>(d["fail_limit"]);
198 }
199 
replace_trackers(torrent_handle & h,object trackers)200 void replace_trackers(torrent_handle& h, object trackers)
201 {
202     object iter(trackers.attr("__iter__")());
203 
204     std::vector<announce_entry> result;
205 
206     for (;;)
207     {
208         handle<> entry(allow_null(PyIter_Next(iter.ptr())));
209 
210         if (entry == handle<>())
211             break;
212 
213         if (extract<announce_entry>(object(entry)).check())
214         {
215            result.push_back(extract<announce_entry>(object(entry)));
216         }
217         else
218         {
219             dict d;
220             d = extract<dict>(object(entry));
221             announce_entry ae;
222             dict_to_announce_entry(d, ae);
223             result.push_back(ae);
224         }
225     }
226 
227     allow_threading_guard guard;
228     h.replace_trackers(result);
229 }
230 
add_tracker(torrent_handle & h,dict d)231 void add_tracker(torrent_handle& h, dict d)
232 {
233    announce_entry ae;
234    dict_to_announce_entry(d, ae);
235    h.add_tracker(ae);
236 }
237 
238 namespace
239 {
240 #if defined BOOST_ASIO_HAS_STD_CHRONO
241    using std::chrono::system_clock;
242 #else
243    using boost::chrono::system_clock;
244 #endif
245 
to_ptime(time_point tpt)246    time_t to_ptime(time_point tpt)
247    {
248       return system_clock::to_time_t(system_clock::now()
249          + duration_cast<system_clock::duration>(tpt - clock_type::now()));
250    }
251 }
252 
trackers(torrent_handle & h)253 list trackers(torrent_handle& h)
254 {
255     list ret;
256     std::vector<announce_entry> const trackers = h.trackers();
257     for (std::vector<announce_entry>::const_iterator i = trackers.begin(), end(trackers.end()); i != end; ++i)
258     {
259         dict d;
260         d["url"] = i->url;
261         d["trackerid"] = i->trackerid;
262         d["tier"] = i->tier;
263         d["fail_limit"] = i->fail_limit;
264         d["source"] = i->source;
265         d["verified"] = i->verified;
266 
267 #if TORRENT_ABI_VERSION == 1
268         if (!i->endpoints.empty())
269         {
270             announce_endpoint const& aep = i->endpoints.front();
271             d["message"] = aep.message;
272             dict last_error;
273             last_error["value"] = aep.last_error.value();
274             last_error["category"] = aep.last_error.category().name();
275             d["last_error"] = last_error;
276             if (aep.next_announce > min_time()) {
277                 d["next_announce"] = to_ptime(aep.next_announce);
278             }
279             else {
280                 d["next_announce"] = object();
281             }
282             if (aep.min_announce > min_time()) {
283                 d["min_announce"] = to_ptime(aep.min_announce);
284             }
285             else {
286                 d["min_announce"] = object();
287             }
288             d["scrape_incomplete"] = aep.scrape_incomplete;
289             d["scrape_complete"] = aep.scrape_complete;
290             d["scrape_downloaded"] = aep.scrape_downloaded;
291             d["fails"] = aep.fails;
292             d["updating"] = aep.updating;
293             d["start_sent"] = aep.start_sent;
294             d["complete_sent"] = aep.complete_sent;
295         }
296         else
297         {
298             d["message"] = std::string();
299             dict last_error;
300             last_error["value"] = 0;
301             last_error["category"] = "";
302             d["last_error"] = last_error;
303             d["next_announce"] = object();
304             d["min_announce"] = object();
305             d["scrape_incomplete"] = 0;
306             d["scrape_complete"] = 0;
307             d["scrape_downloaded"] = 0;
308             d["fails"] = 0;
309             d["updating"] = false;
310             d["start_sent"] = false;
311             d["complete_sent"] = false;
312         }
313 #endif
314 
315         list aeps;
316         for (auto const& aep : i->endpoints)
317         {
318             dict e;
319             e["message"] = aep.message;
320             e["local_address"] = boost::python::make_tuple(aep.local_endpoint.address().to_string(), aep.local_endpoint.port());
321             dict last_error;
322             last_error["value"] = aep.last_error.value();
323             last_error["category"] = aep.last_error.category().name();
324             e["last_error"] = last_error;
325             if (aep.next_announce > min_time()) {
326                 e["next_announce"] = to_ptime(aep.next_announce);
327             }
328             else {
329                 e["next_announce"] = object();
330             }
331             if (aep.min_announce > min_time()) {
332                 e["min_announce"] = to_ptime(aep.min_announce);
333             }
334             else {
335                 e["min_announce"] = object();
336             }
337             e["scrape_incomplete"] = aep.scrape_incomplete;
338             e["scrape_complete"] = aep.scrape_complete;
339             e["scrape_downloaded"] = aep.scrape_downloaded;
340             e["fails"] = aep.fails;
341             e["updating"] = aep.updating;
342             e["start_sent"] = aep.start_sent;
343             e["complete_sent"] = aep.complete_sent;
344             aeps.append(e);
345         }
346         d["endpoints"] = aeps;
347 
348 #if TORRENT_ABI_VERSION == 1
349         d["send_stats"] = i->send_stats;
350 #endif
351         ret.append(d);
352     }
353     return ret;
354 }
355 
get_download_queue(torrent_handle & handle)356 list get_download_queue(torrent_handle& handle)
357 {
358     list ret;
359 
360     std::vector<partial_piece_info> downloading;
361 
362     {
363         allow_threading_guard guard;
364         handle.get_download_queue(downloading);
365     }
366 
367     for (std::vector<partial_piece_info>::iterator i = downloading.begin()
368         , end(downloading.end()); i != end; ++i)
369     {
370         dict partial_piece;
371         partial_piece["piece_index"] = i->piece_index;
372         partial_piece["blocks_in_piece"] = i->blocks_in_piece;
373         list block_list;
374         for (int k = 0; k < i->blocks_in_piece; ++k)
375         {
376             dict block_info;
377             block_info["state"] = i->blocks[k].state;
378             block_info["num_peers"] = i->blocks[k].num_peers;
379             block_info["bytes_progress"] = i->blocks[k].bytes_progress;
380             block_info["block_size"] = i->blocks[k].block_size;
381             block_info["peer"] = boost::python::make_tuple(
382                 i->blocks[k].peer().address().to_string()
383                 , i->blocks[k].peer().port());
384             block_list.append(block_info);
385         }
386         partial_piece["blocks"] = block_list;
387 
388         ret.append(partial_piece);
389     }
390 
391     return ret;
392 }
393 
set_metadata(torrent_handle & handle,std::string const & buf)394 void set_metadata(torrent_handle& handle, std::string const& buf)
395 {
396    handle.set_metadata(buf);
397 }
398 
399 #if TORRENT_ABI_VERSION == 1
400 
get_torrent_info(torrent_handle const & h)401 std::shared_ptr<const torrent_info> get_torrent_info(torrent_handle const& h)
402 {
403     allow_threading_guard guard;
404     return h.torrent_file();
405 }
406 
407 #endif // TORRENT_ABI_VERSION
408 
add_piece_str(torrent_handle & th,piece_index_t piece,char const * data,add_piece_flags_t const flags)409 void add_piece_str(torrent_handle& th, piece_index_t piece, char const *data
410     , add_piece_flags_t const flags)
411 {
412     th.add_piece(piece, data, flags);
413 }
414 
add_piece_bytes(torrent_handle & th,piece_index_t piece,bytes data,add_piece_flags_t const flags)415 void add_piece_bytes(torrent_handle& th, piece_index_t piece, bytes data
416     , add_piece_flags_t const flags)
417 {
418     th.add_piece(piece, data.arr.c_str(), flags);
419 }
420 
421 class dummy5 {};
422 class dummy {};
423 class dummy4 {};
424 class dummy6 {};
425 class dummy7 {};
426 class dummy8 {};
427 class dummy15 {};
428 
429 using by_value = return_value_policy<return_by_value>;
bind_torrent_handle()430 void bind_torrent_handle()
431 {
432     // arguments are: number of seconds and tracker index
433     void (torrent_handle::*force_reannounce0)(int, int, reannounce_flags_t) const = &torrent_handle::force_reannounce;
434 
435 #if TORRENT_ABI_VERSION == 1
436     bool (torrent_handle::*super_seeding0)() const = &torrent_handle::super_seeding;
437     void (torrent_handle::*super_seeding1)(bool) const = &torrent_handle::super_seeding;
438 #endif
439     void (torrent_handle::*set_flags0)(torrent_flags_t) const = &torrent_handle::set_flags;
440     void (torrent_handle::*set_flags1)(torrent_flags_t, torrent_flags_t) const = &torrent_handle::set_flags;
441 
442     download_priority_t (torrent_handle::*piece_priority0)(piece_index_t) const = &torrent_handle::piece_priority;
443     void (torrent_handle::*piece_priority1)(piece_index_t, download_priority_t) const = &torrent_handle::piece_priority;
444 
445     void (torrent_handle::*move_storage0)(std::string const&, lt::move_flags_t) const = &torrent_handle::move_storage;
446     void (torrent_handle::*rename_file0)(file_index_t, std::string const&) const = &torrent_handle::rename_file;
447 
448 #if TORRENT_ABI_VERSION == 1
449 #ifdef TORRENT_WINDOWS
450     void (torrent_handle::*move_storage1)(std::wstring const&, int) const = &torrent_handle::move_storage;
451     void (torrent_handle::*rename_file1)(file_index_t, std::wstring const&) const = &torrent_handle::rename_file;
452 #endif
453 #endif
454 
455     std::vector<open_file_state> (torrent_handle::*file_status0)() const = &torrent_handle::file_status;
456 
457 #define _ allow_threads
458 
459     enum_<move_flags_t>("move_flags_t")
460         .value("always_replace_files", move_flags_t::always_replace_files)
461         .value("fail_if_exist", move_flags_t::fail_if_exist)
462         .value("dont_replace", move_flags_t::dont_replace)
463     ;
464 
465 #if TORRENT_ABI_VERSION == 1
466    enum_<deprecated_move_flags_t>("deprecated_move_flags_t")
467         .value("always_replace_files", deprecated_move_flags_t::always_replace_files)
468         .value("fail_if_exist", deprecated_move_flags_t::fail_if_exist)
469         .value("dont_replace", deprecated_move_flags_t::dont_replace)
470     ;
471 #endif
472 
473     {
474     scope s = class_<torrent_handle>("torrent_handle")
475         .def(self == self)
476         .def(self != self)
477         .def(self < self)
478         .def("__hash__", (std::size_t (*)(torrent_handle const&))&libtorrent::hash_value)
479         .def("get_peer_info", get_peer_info)
480         .def("status", _(&torrent_handle::status), arg("flags") = 0xffffffff)
481         .def("get_download_queue", get_download_queue)
482         .def("file_progress", file_progress, arg("flags") = 0)
483         .def("trackers", trackers)
484         .def("replace_trackers", replace_trackers)
485         .def("add_tracker", add_tracker)
486         .def("add_url_seed", _(&torrent_handle::add_url_seed))
487         .def("remove_url_seed", _(&torrent_handle::remove_url_seed))
488         .def("url_seeds", url_seeds)
489         .def("add_http_seed", _(&torrent_handle::add_http_seed))
490         .def("remove_http_seed", _(&torrent_handle::remove_http_seed))
491         .def("http_seeds", http_seeds)
492         .def("torrent_file", _(&torrent_handle::torrent_file))
493         .def("set_metadata", set_metadata)
494         .def("is_valid", _(&torrent_handle::is_valid))
495         .def("pause", _(&torrent_handle::pause), arg("flags") = 0)
496         .def("resume", _(&torrent_handle::resume))
497         .def("clear_error", _(&torrent_handle::clear_error))
498         .def("queue_position", _(&torrent_handle::queue_position))
499         .def("queue_position_up", _(&torrent_handle::queue_position_up))
500         .def("queue_position_down", _(&torrent_handle::queue_position_down))
501         .def("queue_position_top", _(&torrent_handle::queue_position_top))
502         .def("queue_position_bottom", _(&torrent_handle::queue_position_bottom))
503 
504         .def("add_piece", add_piece_str)
505         .def("add_piece", add_piece_bytes)
506         .def("read_piece", _(&torrent_handle::read_piece))
507         .def("have_piece", _(&torrent_handle::have_piece))
508         .def("set_piece_deadline", _(&torrent_handle::set_piece_deadline)
509             , (arg("index"), arg("deadline"), arg("flags") = 0))
510         .def("reset_piece_deadline", _(&torrent_handle::reset_piece_deadline), (arg("index")))
511         .def("clear_piece_deadlines", _(&torrent_handle::clear_piece_deadlines), (arg("index")))
512         .def("piece_availability", &piece_availability)
513         .def("piece_priority", _(piece_priority0))
514         .def("piece_priority", _(piece_priority1))
515         .def("prioritize_pieces", &prioritize_pieces)
516         .def("get_piece_priorities", &piece_priorities)
517         .def("prioritize_files", &prioritize_files)
518         .def("get_file_priorities", &file_priorities)
519         .def("file_priority", &file_prioritity0)
520         .def("file_priority", &file_prioritity1)
521         .def("file_status", _(file_status0))
522         .def("save_resume_data", _(&torrent_handle::save_resume_data), arg("flags") = 0)
523         .def("need_save_resume_data", _(&torrent_handle::need_save_resume_data))
524         .def("force_reannounce", _(force_reannounce0)
525             , (arg("seconds") = 0, arg("tracker_idx") = -1, arg("flags") = reannounce_flags_t{}))
526 #ifndef TORRENT_DISABLE_DHT
527         .def("force_dht_announce", _(&torrent_handle::force_dht_announce))
528 #endif
529         .def("scrape_tracker", _(&torrent_handle::scrape_tracker), arg("index") = -1)
530         .def("flush_cache", &torrent_handle::flush_cache)
531         .def("set_upload_limit", _(&torrent_handle::set_upload_limit))
532         .def("upload_limit", _(&torrent_handle::upload_limit))
533         .def("set_download_limit", _(&torrent_handle::set_download_limit))
534         .def("download_limit", _(&torrent_handle::download_limit))
535         .def("connect_peer", &torrent_handle::connect_peer, (arg("endpoint"), arg("source")=0, arg("flags")=0xd))
536         .def("set_max_uploads", &torrent_handle::set_max_uploads)
537         .def("max_uploads", _(&torrent_handle::max_uploads))
538         .def("set_max_connections", &torrent_handle::set_max_connections)
539         .def("max_connections", _(&torrent_handle::max_connections))
540         .def("move_storage", _(move_storage0), (arg("path"), arg("flags") = move_flags_t::always_replace_files))
541         .def("info_hash", _(&torrent_handle::info_hash))
542         .def("force_recheck", _(&torrent_handle::force_recheck))
543         .def("rename_file", _(rename_file0))
544         .def("set_ssl_certificate", &torrent_handle::set_ssl_certificate, (arg("cert"), arg("private_key"), arg("dh_params"), arg("passphrase")=""))
545         .def("flags", _(&torrent_handle::flags))
546         .def("set_flags", _(set_flags0))
547         .def("set_flags", _(set_flags1))
548         .def("unset_flags", _(&torrent_handle::unset_flags))
549         // deprecated
550 #if TORRENT_ABI_VERSION == 1
551         .def("piece_priorities", &piece_priorities)
552         .def("file_priorities", &file_priorities)
553         .def("stop_when_ready", _(&torrent_handle::stop_when_ready))
554         .def("super_seeding", super_seeding1)
555         .def("auto_managed", _(&torrent_handle::auto_managed))
556         .def("set_priority", _(&torrent_handle::set_priority))
557         .def("get_torrent_info", &get_torrent_info)
558         .def("super_seeding", super_seeding0)
559         .def("write_resume_data", _(&torrent_handle::write_resume_data))
560         .def("is_seed", _(&torrent_handle::is_seed))
561         .def("is_finished", _(&torrent_handle::is_finished))
562         .def("has_metadata", _(&torrent_handle::has_metadata))
563         .def("use_interface", &torrent_handle::use_interface)
564         .def("name", _(&torrent_handle::name))
565         .def("is_paused", _(&torrent_handle::is_paused))
566         .def("is_auto_managed", _(&torrent_handle::is_auto_managed))
567         .def("set_upload_mode", _(&torrent_handle::set_upload_mode))
568         .def("set_share_mode", _(&torrent_handle::set_share_mode))
569         .def("apply_ip_filter", &torrent_handle::apply_ip_filter)
570         .def("set_sequential_download", _(&torrent_handle::set_sequential_download))
571         .def("set_peer_upload_limit", &torrent_handle::set_peer_upload_limit)
572         .def("set_peer_download_limit", &torrent_handle::set_peer_download_limit)
573         .def("set_ratio", _(&torrent_handle::set_ratio))
574         .def("save_path", _(&torrent_handle::save_path))
575         .def("set_tracker_login", &torrent_handle::set_tracker_login)
576 #ifdef TORRENT_WINDOWS
577         .def("move_storage", _(move_storage1), (arg("path"), arg("flags") = always_replace_files))
578         .def("rename_file", _(rename_file1))
579 #endif
580 #endif
581         ;
582 
583     s.attr("ignore_min_interval") = torrent_handle::ignore_min_interval;
584     s.attr("overwrite_existing") = torrent_handle::overwrite_existing;
585     s.attr("piece_granularity") = int(torrent_handle::piece_granularity);
586     s.attr("graceful_pause") = torrent_handle::graceful_pause;
587     s.attr("flush_disk_cache") = torrent_handle::flush_disk_cache;
588     s.attr("save_info_dict") = torrent_handle::save_info_dict;
589     s.attr("only_if_modified") = torrent_handle::only_if_modified;
590     s.attr("alert_when_available") = torrent_handle::alert_when_available;
591     s.attr("query_distributed_copies") = torrent_handle::query_distributed_copies;
592     s.attr("query_accurate_download_counters") = torrent_handle::query_accurate_download_counters;
593     s.attr("query_last_seen_complete") = torrent_handle::query_last_seen_complete;
594     s.attr("query_pieces") = torrent_handle::query_pieces;
595     s.attr("query_verified_pieces") = torrent_handle::query_verified_pieces;
596     }
597 
598     class_<open_file_state>("open_file_state")
599        .add_property("file_index", make_getter((&open_file_state::file_index), by_value()))
600        .def_readonly("last_use", &open_file_state::last_use)
601        .def_readonly("open_mode", &open_file_state::open_mode)
602     ;
603 
604     {
605     scope s = class_<dummy>("file_open_mode");
606     s.attr("read_only") = file_open_mode::read_only;
607     s.attr("write_only") = file_open_mode::write_only;
608     s.attr("read_write") = file_open_mode::read_write;
609     s.attr("rw_mask") = file_open_mode::rw_mask;
610     s.attr("sparse") = file_open_mode::sparse;
611     s.attr("no_atime") = file_open_mode::no_atime;
612     s.attr("random_access") = file_open_mode::random_access;
613 #if TORRENT_ABI_VERSION == 1
614     s.attr("locked") = 0;
615 #endif
616     }
617 
618     enum_<torrent_handle::file_progress_flags_t>("file_progress_flags")
619         .value("piece_granularity", torrent_handle::piece_granularity)
620     ;
621 
622     {
623     scope s = class_<dummy6>("add_piece_flags_t");
624     s.attr("overwrite_existing") = torrent_handle::overwrite_existing;
625     }
626 
627     {
628     scope s = class_<dummy7>("pause_flags_t");
629     s.attr("graceful_pause") = torrent_handle::graceful_pause;
630     }
631 
632     {
633     scope s = class_<dummy4>("save_resume_flags_t");
634     s.attr("flush_disk_cache") = torrent_handle::flush_disk_cache;
635     s.attr("save_info_dict") = torrent_handle::save_info_dict;
636     s.attr("only_if_modified") = torrent_handle::only_if_modified;
637     }
638 
639     {
640     scope s = class_<dummy15>("reannounce_flags_t");
641     s.attr("ignore_min_interval") = torrent_handle::ignore_min_interval;
642     }
643 
644     {
645     scope s = class_<dummy8>("deadline_flags_t");
646     s.attr("alert_when_available") = torrent_handle::alert_when_available;
647     }
648 
649 	 {
650 	 scope s = class_<dummy5>("status_flags_t");
651     s.attr("query_distributed_copies") = torrent_handle::query_distributed_copies;
652     s.attr("query_accurate_download_counters") = torrent_handle::query_accurate_download_counters;
653     s.attr("query_last_seen_complete") = torrent_handle::query_last_seen_complete;
654     s.attr("query_pieces") = torrent_handle::query_pieces;
655     s.attr("query_verified_pieces") = torrent_handle::query_verified_pieces;
656 	 }
657 
658 }
659 
660 #ifdef _MSC_VER
661 #pragma warning(pop)
662 #endif
663