57 |
|
|
58 |
|
|
59 |
let chunk_size = Int64.of_int (256 * 1024) |
let chunk_size = Int64.of_int (256 * 1024) |
60 |
|
|
61 |
let decode_torrent s = |
let decode_torrent s = |
62 |
if !verbose_msg_servers then lprintf_nl "[BT]: .torrent file loaded\n"; |
if !verbose_msg_servers then lprintf_nl "[BT]: .torrent file loaded"; |
63 |
(* lprintf "Loaded: %s\n" (String.escaped s); *) |
(* lprintf "Loaded: %s\n" (String.escaped s); *) |
64 |
let v = Bencode.decode s in |
let v = Bencode.decode s in |
65 |
(* lprintf "Decoded file: %s\n" (Bencode.print v); *) |
(* lprintf "Decoded file: %s\n" (Bencode.print v); *) |
66 |
|
|
67 |
|
|
68 |
let announce = ref "" in |
let announce = ref "" in |
69 |
|
let announce_list = ref [] in |
70 |
let file_info = ref (List []) in |
let file_info = ref (List []) in |
71 |
let file_name = ref "" in |
let file_name = ref "" in |
72 |
|
let file_torrent_filename = ref "" in |
73 |
|
let file_name_utf8 = ref "" in |
74 |
let file_piece_size = ref zero in |
let file_piece_size = ref zero in |
75 |
let file_pieces = ref "" in |
let file_pieces = ref "" in |
76 |
|
let file_comment = ref "" in |
77 |
|
let file_created_by = ref "" in |
78 |
|
let file_creation_date = ref zero in |
79 |
|
let file_modified_by = ref "" in |
80 |
|
let file_encoding = ref "" in |
81 |
|
let file_ed2k_hash = ref "" in |
82 |
|
let file_nodes = ref "" in |
83 |
|
let file_is_private = ref zero in |
84 |
|
let file_aps = ref (List []) in |
85 |
|
let file_dht_backup_enable = ref zero in |
86 |
let length = ref zero in |
let length = ref zero in |
87 |
let file_files = ref [] in |
let file_files = ref [] in |
88 |
|
|
134 |
List.iter (fun (key, value) -> |
List.iter (fun (key, value) -> |
135 |
match key, value with |
match key, value with |
136 |
String "announce", String tracker_url -> |
String "announce", String tracker_url -> |
137 |
|
if !verbose_msg_servers then |
138 |
|
lprintf_nl "[BT]: New tracker added :%s" tracker_url; |
139 |
announce := tracker_url |
announce := tracker_url |
140 |
|
| String "announce-list", List list -> |
141 |
|
List.iter (fun url_list -> |
142 |
|
let next_urls = ref [] in |
143 |
|
match url_list with |
144 |
|
| List next_url_list -> |
145 |
|
List.iter (fun myvalue -> |
146 |
|
match myvalue with |
147 |
|
| String next_url -> |
148 |
|
next_urls := next_url :: !next_urls; |
149 |
|
if !verbose_msg_servers then |
150 |
|
lprintf_nl "[BT]: New tracker received :%s" next_url |
151 |
|
| _ -> |
152 |
|
if !verbose_msg_servers then |
153 |
|
lprintf_nl "[BT]: error while decoding announce list" |
154 |
|
) next_url_list; |
155 |
|
if List.length !next_urls > 1 then begin |
156 |
|
next_urls := List2.shuffle !next_urls; |
157 |
|
announce_list := !next_urls @ !announce_list |
158 |
|
end |
159 |
|
else |
160 |
|
announce_list := List.hd !next_urls :: !announce_list |
161 |
|
| _ -> |
162 |
|
lprintf_nl "[BT]: unknown field in announce list" |
163 |
|
) list; |
164 |
|
announce_list := List.rev !announce_list; |
165 |
|
if !verbose_msg_servers then |
166 |
|
List.iter (fun url -> |
167 |
|
lprintf_nl "[BT]: New tracker added :%s" url |
168 |
|
) !announce_list |
169 |
| String "info", ((Dictionary list) as info) -> |
| String "info", ((Dictionary list) as info) -> |
170 |
|
|
171 |
file_info := info; |
file_info := info; |
172 |
List.iter (fun (key, value) -> |
List.iter (fun (key, value) -> |
173 |
match key, value with |
match key, value with |
181 |
file_piece_size := n |
file_piece_size := n |
182 |
| String "pieces", String pieces -> |
| String "pieces", String pieces -> |
183 |
file_pieces := pieces |
file_pieces := pieces |
184 |
| String key, _ -> |
| String "ed2k", String string_ed2k -> |
185 |
if !verbose_msg_servers then lprintf "other field [%s] in info\n" key |
if !!enable_donkey then |
186 |
| _ -> |
file_ed2k_hash := string_ed2k; |
187 |
lprintf "other field in info\n" |
(* TODO: Add new ed2k download if ed2k hash is available, |
188 |
|
then merge it with current download *) |
189 |
|
| String "sha1", String string_sha1 -> () |
190 |
|
(* TODO: Parse sha1 hash *) |
191 |
|
|
192 |
|
| String "publisher", String created_by -> |
193 |
|
file_created_by := created_by |
194 |
|
| String "publisher-url", String publisher_url -> |
195 |
|
file_created_by := !file_created_by ^ " @ " ^ publisher_url |
196 |
|
|
197 |
|
| String "name.utf-8", String name_utf8 -> |
198 |
|
file_name_utf8 := name_utf8 |
199 |
|
|
200 |
|
| String "publisher.utf-8", String publisher_utf8 -> () |
201 |
|
| String "publisher-url.utf-8", String publisher_url_utf8 -> () |
202 |
|
|
203 |
|
| String "private", Int n -> |
204 |
|
(* TODO: if set to 1, only accept peers from tracker *) |
205 |
|
file_is_private := n; |
206 |
|
if !verbose_msg_servers && |
207 |
|
Int64.to_int !file_is_private = 1 then |
208 |
|
lprintf_nl "[BT]: torrent is private" |
209 |
|
| String key, _ -> |
210 |
|
if !verbose_msg_servers then |
211 |
|
lprintf_nl "[BT]: found other field [%s] with value [%s] in info" key (Bencode.print value) |
212 |
|
| _ -> |
213 |
|
lprintf_nl "[BT]: other field in info" |
214 |
|
) list |
215 |
|
|
216 |
|
| String "comment", String comment |
217 |
|
| String "comment.utf-8", String comment -> |
218 |
|
file_comment := comment |
219 |
|
(* Next 2 strings are after info sometimes *) |
220 |
|
| String "publisher", String created_by -> |
221 |
|
file_created_by := created_by |
222 |
|
| String "publisher-url", String publisher_url -> |
223 |
|
file_created_by := !file_created_by ^ " @ " ^ publisher_url |
224 |
|
|
225 |
|
| String "created by", String created_by -> |
226 |
|
file_created_by := created_by |
227 |
|
| String "creation date", Int creation_date -> |
228 |
|
file_creation_date := creation_date |
229 |
|
| String "modified-by", String modified_by -> |
230 |
|
file_modified_by := modified_by |
231 |
|
| String "encoding", String encoding -> |
232 |
|
file_encoding := encoding |
233 |
|
| String "torrent filename", String torrent_filename -> |
234 |
|
file_torrent_filename := torrent_filename |
235 |
|
| String "nodes", nodes -> () |
236 |
|
(* TODO : nodes is a list of DHT Network nodes ,parse and use them *) |
237 |
|
|
238 |
|
(* |
239 |
|
file_nodes := nodes |
240 |
|
*) |
241 |
|
|
242 |
|
| String "azureus_properties", ((Dictionary list) as azureus_properties) -> |
243 |
|
file_aps := azureus_properties; |
244 |
|
List.iter (fun (key, value) -> |
245 |
|
match key, value with |
246 |
|
| String "dht_backup_enable", Int n -> |
247 |
|
file_dht_backup_enable := n; |
248 |
|
if !verbose_msg_servers && |
249 |
|
Int64.to_int !file_dht_backup_enable = 1 then |
250 |
|
lprintf_nl "[BT]: azureus properties : Torrent has dht backup" |
251 |
|
| String key, _ -> |
252 |
|
if !verbose_msg_servers then |
253 |
|
lprintf_nl "[BT]: found other field [%s] with value [%s] in azureus properties" key (Bencode.print value) |
254 |
|
| _ -> |
255 |
|
lprintf_nl "[BT]: other field in azureus properties" |
256 |
) list |
) list |
257 |
| String key, _ -> |
| String key, _ -> |
258 |
if !verbose_msg_servers then lprintf "other field [%s] after info\n" key |
if !verbose_msg_servers then lprintf_nl "[BT]: found other field [%s] with value [%s] after info" key (Bencode.print value) |
259 |
| _ -> |
| _ -> |
260 |
lprintf "other field after info\n" |
lprintf_nl "[BT]: other field after info" |
261 |
) list |
) list |
262 |
| _ -> assert false |
| _ -> assert false |
263 |
end; |
end; |
286 |
|
|
287 |
file_id, { |
file_id, { |
288 |
torrent_name = !file_name; |
torrent_name = !file_name; |
289 |
|
torrent_filename = !file_torrent_filename; |
290 |
|
torrent_name_utf8 = !file_name_utf8; |
291 |
torrent_length = !length; |
torrent_length = !length; |
292 |
torrent_announce = !announce; |
torrent_announce = !announce; |
293 |
|
torrent_announce_list = !announce_list; |
294 |
torrent_piece_size = !file_piece_size; |
torrent_piece_size = !file_piece_size; |
295 |
torrent_files = !file_files; |
torrent_files = !file_files; |
296 |
torrent_pieces = pieces; |
torrent_pieces = pieces; |
297 |
|
torrent_comment = !file_comment; |
298 |
|
torrent_created_by = !file_created_by; |
299 |
|
torrent_creation_date = !file_creation_date; |
300 |
|
torrent_modified_by = !file_modified_by; |
301 |
|
torrent_encoding = !file_encoding; |
302 |
|
torrent_private = !file_is_private; |
303 |
|
|
304 |
|
(* |
305 |
|
torrent_nodes = !file_nodes; |
306 |
|
*) |
307 |
} |
} |
308 |
|
|
309 |
let encode_torrent torrent = |
let encode_torrent torrent = |
336 |
Dictionary [ |
Dictionary [ |
337 |
files; |
files; |
338 |
String "name", String torrent.torrent_name; |
String "name", String torrent.torrent_name; |
339 |
|
String "name.utf-8", String torrent.torrent_name_utf8; |
340 |
String "piece length", Int torrent.torrent_piece_size; |
String "piece length", Int torrent.torrent_piece_size; |
341 |
String "pieces", String pieces; |
String "pieces", String pieces; |
342 |
|
String "private", Int torrent.torrent_private; |
343 |
] |
] |
344 |
in |
in |
345 |
|
|
346 |
let info_encoded = Bencode.encode info in |
let info_encoded = Bencode.encode info in |
347 |
let file_id = Sha1.string info_encoded in |
let file_id = Sha1.string info_encoded in |
348 |
file_id, |
file_id, |
349 |
Dictionary [ |
Dictionary [ |
350 |
String "announce", String torrent.torrent_announce; |
String "announce", String torrent.torrent_announce; |
351 |
String "info", info; |
String "info", info; |
352 |
|
String "comment", String torrent.torrent_comment; |
353 |
|
String "created by", String torrent.torrent_created_by; |
354 |
|
String "creation date", Int torrent.torrent_creation_date; |
355 |
|
String "encoding", String torrent.torrent_encoding; |
356 |
|
String "modified-by", String torrent.torrent_modified_by; |
357 |
|
(* |
358 |
|
String "nodes", String torrent.torrent_nodes; |
359 |
|
*) |
360 |
] |
] |
361 |
|
|
362 |
let make_torrent announce filename = |
let make_torrent announce filename comment is_private = |
363 |
|
let announce_list = [ announce ] in |
364 |
let basename = Filename.basename filename in |
let basename = Filename.basename filename in |
365 |
let files, t = |
let files, t = |
366 |
if Unix2.is_directory filename then |
if Unix2.is_directory filename then |
407 |
|
|
408 |
{ |
{ |
409 |
torrent_name = basename; |
torrent_name = basename; |
410 |
|
torrent_filename = ""; |
411 |
|
torrent_name_utf8 = Charset.to_utf8 basename; |
412 |
torrent_length = length; |
torrent_length = length; |
413 |
torrent_announce = announce; |
torrent_announce = announce; |
414 |
|
torrent_announce_list = announce_list; |
415 |
torrent_piece_size = chunk_size; |
torrent_piece_size = chunk_size; |
416 |
torrent_files = files; |
torrent_files = files; |
417 |
torrent_pieces = pieces; |
torrent_pieces = pieces; |
418 |
|
torrent_comment = |
419 |
|
if String.length comment > 1 then |
420 |
|
comment |
421 |
|
else |
422 |
|
Printf.sprintf "Created by MLdonkey/%s" Autoconf.current_version; |
423 |
|
|
424 |
|
torrent_created_by = Printf.sprintf "MLdonkey/%s" Autoconf.current_version; |
425 |
|
torrent_creation_date = Int64.of_float (Unix.gettimeofday ()); |
426 |
|
torrent_modified_by = ""; |
427 |
|
torrent_encoding = ""; |
428 |
|
torrent_private = is_private; |
429 |
|
(* |
430 |
|
torrent_nodes = ""; |
431 |
|
*) |
432 |
} |
} |
433 |
|
|
434 |
let generate_torrent announce torrent_filename filename = |
let generate_torrent announce torrent_filename torrent_comment torrent_private filename = |
435 |
let torrent = make_torrent announce filename in |
let torrent = make_torrent announce filename torrent_comment torrent_private in |
436 |
let file_id, encoded = encode_torrent torrent in |
let file_id, encoded = encode_torrent torrent in |
437 |
let encoded = Bencode.encode encoded in |
let encoded = Bencode.encode encoded in |
438 |
File.from_string torrent_filename encoded |
File.from_string torrent_filename encoded |