1 (* Copyright 2002 b8_bavard, b8_fee_carabine, INRIA *)
3 This file is part of mldonkey.
5 mldonkey is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 mldonkey is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with mldonkey; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
29 open CommonComplexOptions
40 module VB
= VerificationBitmap
42 let shared_files_ini = create_options_file
"shared_files_new.ini"
44 let file_sources_ini = create_options_file
"file_sources.ini"
46 let stats_ini = create_options_file
"stats.ini"
48 let mod_stats_ini = create_options_file
"stats_mod.ini"
50 let shared_section = file_section
shared_files_ini [] ""
51 let stats_section = file_section
stats_ini [] ""
52 let mod_stats_section = file_section
mod_stats_ini [] ""
53 let file_sources_section = file_section
file_sources_ini [] ""
57 (* emulate emule onlinesig.dat
59 <connected (0|1)> | <server name> | <ip> | <port#>
60 <downloadrate %.1f> | <uploadrate %.1f>| <queuesize int>
62 I know this is stupid, but "give the people what they want"..
66 let create_online_sig () =
68 let most_users = ref Int64.zero
in
69 let server_name= ref "" in
70 let server_ip = ref "" in
71 let server_port = ref 0 in
73 match s
.server_nusers
with
74 | Some v
when v
> !most_users ->
75 server_name := s
.server_name;
76 server_ip := (Ip.to_string s
.server_ip);
77 server_port := s
.server_port;
78 most_users := (match s
.server_nusers
with None
-> 0L | Some v
-> v
)
80 ) (connected_servers
());
82 Unix2.tryopen_write
"onlinesig.dat" (fun oc
->
84 if !most_users = Int64.zero
then
85 output_string oc
("0\n")
87 output_string oc
(Printf.sprintf
"1|%s|%s|%d\n" !server_name !server_ip !server_port);
88 let dlkbs = (( (float_of_int
!udp_download_rate
) +. (float_of_int
!control_download_rate
)) /. 1024.0) in
89 let ulkbs = (( (float_of_int
!udp_upload_rate
) +. (float_of_int
!control_upload_rate
)) /. 1024.0) in
91 output_string oc
(Printf.sprintf
"%.1f|%.1f|%d\n" dlkbs ulkbs
92 (Intmap.length
!CommonUploads.pending_slots_map
)))
94 (************ COMPLEX OPTIONS *****************)
98 List
[v1
;v2
] | SmallList
[v1
;v2
] ->
99 (Ip.of_string
(value_to_string v1
), value_to_int v2
)
100 | _
-> failwith
"Options: Not an int32 pair"
102 let addr_to_value ip port
=
103 SmallList
[string_to_value
(Ip.to_string ip
); int_to_value port
]
106 Md4.of_string
(value_to_string v
)
108 let value_to_client is_friend assocs
=
109 let get_value name conv
= conv
(List.assoc name assocs
) in
112 get_value "client_addr" (fun v
->
114 List
[ip
;port
] | SmallList
[ip
;port
] ->
115 let ip = Ip.of_string
(value_to_string
ip) in
116 let port = value_to_int
port in
118 | _
-> failwith
"Options: Not an client option"
121 failwith
"Source without address: removed"
127 (min
(get_value "client_age" value_to_int
)
128 (BasicSocket.last_time
()))
130 let last_conn = normalize_time
last_conn in
133 let cc = Geoip.get_country_code_option
ip in
134 let l = DonkeyGlobals.new_client
(Direct_address
(ip,port)) cc in
137 get_value "client_md4" value_to_md4
141 get_value "client_name" value_to_string
with _ -> "" in
142 set_client_name
l name md4;
144 if is_friend
then friend_add
l;
147 let value_to_donkey_client v
=
149 List
[ip;port] | SmallList
[ip;port] ->
150 let ip = Ip.of_string
(value_to_string
ip) in
151 let port = value_to_int
port in
152 let cc = Geoip.get_country_code_option
ip in
153 DonkeyGlobals.new_client
(Direct_address
(ip, port)) cc
155 value_to_client false assocs
158 let client_to_value c
=
160 "client_md4", string_to_value
(Md4.to_string c
.client_md4
);
161 "client_name", string_to_value c
.client_name
;
165 match c
.client_kind
with
166 Direct_address
(ip, port) ->
167 ("client_addr", addr_to_value ip port) :: list
168 | _ -> raise Exit
(* Don't save these options *)
170 let donkey_client_to_value c
=
171 Options.Module
(client_to_value c
)
174 define_option_class
"Client" value_to_donkey_client
175 donkey_client_to_value
177 let value_to_server assocs
=
178 let get_value name conv
= conv
(List.assoc
name assocs
) in
179 let ip, port = get_value "server_addr" (fun v
->
181 List
[ip;port] | SmallList
[ip;port] ->
182 let ip = Ip.of_string
(value_to_string
ip) in
183 let port = value_to_int
port in
185 | _ -> failwith
"Options: Not an server option"
187 let l = DonkeyGlobals.new_server
ip port in
190 l.server_name <- get_value "server_name" value_to_string
193 l.server_preferred
<- get_value "server_preferred" value_to_bool
196 connection_set_last_conn
l.server_connection_control
197 (normalize_time
(min
(get_value "server_age" value_to_int
)
198 (BasicSocket.last_time
())));
200 as_server
l.server_server
202 let server_to_value c
=
205 "server_addr", addr_to_value c
.server_ip c
.server_port;
206 "server_age", int_to_value
(
207 connection_last_conn c
.server_connection_control
);
212 if c
.server_name <> "" then
213 ("server_name", string_to_value c
.server_name) :: fields
217 if c
.server_preferred
then
218 ("server_preferred", bool_to_value
true) :: fields else
222 let value_to_int32pair v
=
224 List
[v1
;v2
] | SmallList
[v1
;v2
] ->
225 (value_to_int64 v1
, value_to_int64 v2
)
227 failwith
"Options: Not an int32 pair"
229 let value_to_file file_size file_state user group assocs
=
230 let get_value name conv
= conv
(List.assoc
name assocs
) in
234 get_value "file_md4" value_to_string
235 with _ -> failwith
"Bad file_md4"
237 let file_diskname, empty
=
240 get_value "file_diskname" value_to_string
242 let filename = Filename.concat
!!temp_directory
file_md4 in
243 lprintf_nl
"getting file_diskname from ini failed, testing for ed2k-temp-file %s" filename;
244 if Sys.file_exists
filename then
251 ( string_of_uid
( Ed2k
(Md4.of_string
file_md4) ) )
253 lprintf_nl
"getting file_diskname from ini failed, testing for ed2k-temp-file %s"
255 if Sys.file_exists
filename then
260 ( file_string_of_uid
( Ed2k
(Md4.of_string
file_md4) ) )
263 let file_exists filename = Sys.file_exists filename in
264 if not
(file_exists filename) then
265 (* I think we should die here, to prevent any corruption. *)
266 lprintf_nl
"Error: temp file %s not found, re-creating empty one" filename;
268 if !verbose
&& (not
!CommonGlobals.is_startup_phase
) then
269 lprintf_nl
"ed2k-temp-file %s used." filename;
271 filename, not
(file_exists filename)
274 let file = DonkeyGlobals.new_file
file_diskname file_state
275 (Md4.of_string
file_md4) file_size
"" true user group
in
278 set_file_best_name
(as_file
file)
279 (get_value "file_filename" value_to_string
) "" 0
280 with _ -> update_best_name
file);
282 let md4s = try get_value "file_md4s" (value_to_array
value_to_md4)
287 if md4_of_array
md4s <> (Md4.of_string
file_md4) ||
288 Array.length
md4s <> file.file_nchunk_hashes
then
289 lprintf_nl
"discarding partial chunks hashes, computed hash is wrong for %s"
290 (file_best_name
file)
292 file.file_computed_md4s
<- md4s
295 (match file.file_swarmer
with
298 CommonSwarming.value_to_frontend swarmer assocs
;
299 CommonSwarming.set_verifier swarmer
(if md4s = [||] then
300 VerificationNotAvailable
303 (Array.map
(fun md4 -> Ed2k
md4) md4s));
306 lprintf_nl
"re-created missing temp file of %s , resetting chunk status to missing"
307 (file_best_name
file);
308 let ver_str = String.make
(Array.length
md4s) (VB.state_to_char
VB.State_missing
) in
309 CommonSwarming.set_chunks_verified_bitmap swarmer
(VB.of_string
ver_str);
314 let file_to_value file =
317 "file_md4", string_to_value
(Md4.to_string
file.file_md4);
318 "file_diskname", string_to_value
file.file_diskname;
320 array_to_value
Md4.hash_to_value
file.file_computed_md4s
);
324 match file.file_swarmer
with
327 CommonSwarming.frontend_to_value swarmer
fields
331 module SharedFileOption
= struct
333 let value_to_shinfo v
=
335 Options.Module assocs
->
337 value_to_array
(fun v
->
338 Md4.of_string
(value_to_string v
)) (List.assoc
"md4s" assocs
)
339 with _ -> failwith
"Bad shared file md4"
342 value_to_int64
(List.assoc
"size" assocs
)
343 with _ -> failwith
"Bad shared file size"
346 value_to_filename
(List.assoc
"name" assocs
)
347 with _ -> failwith
"Bad shared file name"
350 value_to_float
(List.assoc
"mtime" assocs
)
351 with _ -> failwith
"Bad shared file mtime"
353 { sh_name = sh_name; sh_mtime = sh_mtime;
354 sh_size = sh_size; sh_md4s = sh_md4s;
357 | _ -> failwith
"Options: not a shared file info option"
359 let shinfo_to_value sh
=
361 "name", filename_to_value sh
.sh_name;
362 "md4s", array_to_value
Md4.hash_to_value sh
.sh_md4s;
363 "mtime", float_to_value sh
.sh_mtime;
364 "size", int64_to_value sh
.sh_size;
368 let t = define_option_class
"SharedFile" value_to_shinfo shinfo_to_value
371 module StatsOption
= struct
373 let value_to_stat v
=
375 Options.Module assocs
->
377 brand_seen
= value_to_int
(List.assoc
"seen" assocs
);
378 brand_banned
= value_to_int
(List.assoc
"banned" assocs
);
379 brand_filerequest
= value_to_int
(List.assoc
"filereqs" assocs
);
380 brand_download
= value_to_int64
(List.assoc
"download" assocs
);
381 brand_upload
= value_to_int64
(List.assoc
"upload" assocs
);
384 | _ -> failwith
"Options: not a stat option"
386 let stat_to_value b
=
388 "seen", int_to_value b
.brand_seen
;
389 "banned", int_to_value b
.brand_banned
;
390 "filereqs", int_to_value b
.brand_filerequest
;
391 "download", int64_to_value b
.brand_download
;
392 "upload", int64_to_value b
.brand_upload
;
396 let t = define_option_class
"Stat" value_to_stat stat_to_value
399 module ModStatsOption
= struct
401 let value_to_mod_stat v
=
403 Options.Module assocs
->
405 brand_seen
= value_to_int
(List.assoc
"mseen" assocs
);
406 brand_banned
= value_to_int
(List.assoc
"mbanned" assocs
);
407 brand_filerequest
= value_to_int
(List.assoc
"mfilereqs" assocs
);
408 brand_download
= value_to_int64
(List.assoc
"mdownload" assocs
);
409 brand_upload
= value_to_int64
(List.assoc
"mupload" assocs
);
412 | _ -> failwith
"Options: not a mod_stat option"
414 let stat_to_mod_value b
=
416 "mseen", int_to_value b
.brand_seen
;
417 "mbanned", int_to_value b
.brand_banned
;
418 "mfilereqs", int_to_value b
.brand_filerequest
;
419 "mdownload", int64_to_value b
.brand_download
;
420 "mupload", int64_to_value b
.brand_upload
;
424 let t = define_option_class
"ModStat" value_to_mod_stat stat_to_mod_value
427 let value_to_module f v
=
429 Module
list -> f
list
430 | _ -> failwith
"Option should be a module"
432 let save_time = define_header_option
file_sources_ini
433 ["save_time"] "" int_option
(last_time
())
435 let known_shared_files = define_option
shared_section
437 (list_option
SharedFileOption.t) []
439 (************ UPDATE OPTIONS *************)
441 (* This function is used only with the "n" command and the
442 op_network_add_server method, which are the only ways for the user
443 to enter servers, bypassing the update_server_list variable. *)
445 let force_add_server ip port =
447 DonkeyGlobals.find_server
ip port
449 let s = DonkeyGlobals.new_server
ip port in
452 let check_add_server ip port =
454 not
(is_black_address
ip port None
) && port <> 4662 then
455 force_add_server ip port
458 let safe_add_server ip port =
460 not
(is_black_address
ip port None
) && port <> 4662 then
462 ignore
(DonkeyGlobals.find_server
ip port)
464 ignore
(DonkeyGlobals.new_server
ip port)
466 let config_files_loaded = ref false
469 if !verbose
then lprintf_nl
"Loading shared files";
471 Options.load shared_files_ini;
472 Options.load stats_ini;
473 Options.load mod_stats_ini;
475 Options.save_with_help
shared_files_ini);
476 config_files_loaded := true
478 let guptime = define_option
stats_section ["guptime"] "" int_option
0
480 let new_stats_array () =
481 Array.init brand_count
(fun _ ->
482 { dummy_stats
with brand_seen
= 0 }
485 let new_mod_stats_array () =
486 Array.init brand_mod_count
(fun _ ->
487 { dummy_stats
with brand_seen
= 0 }
490 let gstats_array = define_option
stats_section ["stats"] ""
491 (array_option
StatsOption.t) (new_stats_array ())
493 let gstats_mod_array = define_option
mod_stats_section ["stats"] ""
494 (array_option
ModStatsOption.t) (new_mod_stats_array ())
497 option_hook
gstats_array (fun _ ->
498 let old_stats = !!gstats_array in
499 let old_len = Array.length
old_stats in
500 if old_len <> brand_count
then
501 let t = new_stats_array () in
502 for i
= 0 to old_len - 1 do
503 t.(i
) <- old_stats.(i
)
509 option_hook
gstats_mod_array (fun _ ->
510 let old_mod_stats = !!gstats_mod_array in
511 let old_mod_len = Array.length
old_mod_stats in
512 if old_mod_len <> brand_mod_count
then
513 let t = new_mod_stats_array () in
514 for i
= 0 to old_mod_len - 1 do
515 t.(i
) <- old_mod_stats.(i
)
517 gstats_mod_array =:= t
520 let diff_time = ref 0
522 let sources_loaded = ref false (* added 2.5.24 *)
525 if !config_files_loaded then begin
526 Options.save_with_help
shared_files_ini;
527 guptime =:= !!guptime + (last_time
() - start_time
) - !diff_time;
528 diff_time := (last_time
() - start_time
);
529 Options.save_with_help
stats_ini;
530 Options.save_with_help
mod_stats_ini;
535 if !sources_loaded && !!keep_sources
then begin
536 save_time =:= last_time
();
537 let cleaner = DonkeySources.attach_sources_to_file
file_sources_section in
538 Options.save_with_help
file_sources_ini;
542 let guptime () = !!guptime - !diff_time
544 let load_sources () =
545 if not
!!keep_sources
then () else
547 let cleaner = DonkeySources.attach_sources_to_file
file_sources_section in
549 Options.load file_sources_ini;
551 sources_loaded := true;
552 lprintf_nl
"loading sources completed"
555 let check_result r tags
=
556 if r
.result_names
= [] || r
.result_size
= Int64.zero
then begin
557 if !verbose
then begin
558 lprintf_n
"Bad search result: ";
559 List.iter
(fun tag
->
560 lprintf
"[%s] = [%s] " (string_of_field tag
.tag_name
)
561 (string_of_tag_value tag
.tag_value
)
569 (* Inserted in complexOptions to be able to access old_files (ugly) *)
570 let result_of_file md4 tags
=
571 let rec r = { dummy_result
with
572 result_uids
= [Uid.create
(Ed2k
md4)];
573 result_done
= (List.mem
md4 !!old_files
) || (Hashtbl.mem files_by_md4
md4);
574 result_source_network
= network
.network_num
;
576 List.iter
(fun tag
->
578 { tag_name
= Field_Filename
; tag_value
= String
s } ->
579 r.result_names
<- s :: r.result_names
580 | { tag_name
= Field_Size
; tag_value
= (Uint64 v
| Fint64 v
) } ->
582 | { tag_name
= Field_Size
; tag_value
= (Uint16 v
| Uint8 v
) } ->
583 r.result_size
<- Int64.of_int v
;
584 | { tag_name
= Field_Size_Hi
; tag_value
= Uint8 v
} ->
585 r.result_size
<- Int64.logor
r.result_size
(Int64.shift_left
(Int64.of_int v
) 32);
586 | { tag_name
= Field_Format
; tag_value
= String
s } ->
587 r.result_tags
<- tag
:: r.result_tags
;
589 | { tag_name
= Field_Type
; tag_value
= String
s } ->
590 r.result_tags
<- tag
:: r.result_tags
;
593 r.result_tags
<- tag
:: r.result_tags
595 if check_result r tags
then
596 let rs = update_result_num
r in
602 network
.op_network_file_of_option
<- value_to_file;
603 file_ops
.op_file_to_option
<- file_to_value;
605 network
.op_network_server_of_option
<- value_to_server;
606 server_ops
.op_server_to_option
<- server_to_value;
608 network
.op_network_client_of_option
<- (fun is_friend
l ->
609 as_client
(value_to_client is_friend
l));
610 client_ops
.op_client_to_option
<- client_to_value;
612 network
.op_network_load_complex_options
<- load;
613 network
.op_network_save_complex_options
<- save;
614 network
.op_network_save_sources
<- save_sources;
616 let cleaner = DonkeySources.attach_sources_to_file
file_sources_section in