1 (* Copyright 2001, 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
28 open CommonInteractive
31 open CommonComplexOptions
51 let log_prefix = "[dcInt]"
54 lprintf_nl2
log_prefix fmt
56 (* Start new dowload from result *)
57 let start_new_download u tth fdir fname fsize
=
59 ignore
(Hashtbl.find dc_shared_files_by_hash tth
);
60 if !verbose_download
then lprintf_nl "Shared file with same hash exists (%s) (%s)" fname tth
;
63 let f = new_file tth fdir fname fsize
in (* ...create new file *)
64 match (file_state
f) with
65 | FileDownloaded
| FileShared
-> if !verbose_download
then lprintf_nl "File already downloaded"; None
66 | FileDownloading
-> if !verbose_download
then lprintf_nl "File being downloaded"; None
67 | FilePaused
-> if !verbose_download
then lprintf_nl "File paused"; None
68 | FileAborted _
| FileCancelled
| FileQueued
->
69 if !verbose_download
then lprintf_nl "File state invalid"; None
71 file_add
f.file_file FileDownloading
;
75 let c = new_client_to_user_with_file user
f in
76 c.client_state
<- DcDownloadWaiting
f;
77 if (can_user_start_downloading user
) then begin
78 user
.user_state
<- TryingToSendFirstContact
;
79 c.client_state
<- DcDownloadConnecting
(f,current_time
());
80 ignore
(DcClients.try_connect_client
c)
84 (* Start downloading of a file by user selection from resultlist *)
85 let start_result_download r
=
86 let filename = List.hd r
.result_names
in
87 let rinfo = Hashtbl.find dc_result_info r
.result_num
in
88 let newfile = start_new_download (Some
rinfo.user
) rinfo.tth
rinfo.directory
filename r
.result_size
in
90 | Some
f -> as_file
f.file_file
(* return CommonFile.file *)
91 | _
-> raise Not_found
)
93 let exn_catch f x
= try `Ok
(f x
) with exn
-> `Exn exn
94 let opt_default default
= function None
-> default
| Some v
-> v
96 let parse_url url user group
=
97 match exn_catch parse_magnet_url url
with
98 | `Exn _
-> "Not a magnet url", false
101 lprintf_nl "Got magnet url %S" url
;
102 (* TODO multiple TTHs, multiple xt, automatic merge of downloads from different networks (?!) *)
103 match List2.filter_map
(function TigerTree tth
-> Some tth
| _
-> None
) magnet#uids
with
104 | [] -> "No TTH found in magnet url", false
106 let _ = start_new_download None
(TigerTree.to_string tth
) "" magnet#name
(opt_default 0L magnet#size
) in
109 (* register DC commands *)
110 let register_commands list
=
111 register_commands (List2.tail_map
(fun (n
,f,h
) -> (n
, "Direct Connect", f,h
)) list
)
113 let td_command text title ?
(blink
=false) ?
(target
=`Output
) cmd
=
115 "\\<td class=\\\"srb\\\" %sonMouseOver=\\\"mOvr(this);\\\"
116 onMouseOut=\\\"mOut(this);\\\" title=\\\"%s\\\"
117 onClick=\\\"parent.%s.location.href='submit?q=%s'\\\"\\>%s\\</td\\>"
118 (if blink
then "style=\\\"text-decoration:blink\\\" " else "")
119 title
(match target
with `Output
-> "output" | `Status
-> "fstatus")
120 (String.concat
"+" cmd
) (* Url.encode ? *)
123 (* Print DC hubs header *)
124 let dc_hublist_print_html_header buf ext
=
125 html_mods_table_header buf
"serversTable" (Printf.sprintf
"servers%s" ext
) [
126 ( "1", "srh", "Hub number", "#" ) ;
127 ( "0", "srh", "Add hub to servers", "Add" ) ;
128 ( "0", "srh", "Hub name", "Hub name" ) ;
129 ( "0", "srh", "IP address", "IP address" ) ;
130 ( "1", "srh", "Users in hub", "Users" ) ;
131 ( "0", "srh", "Hub info", "Info" ) ]
133 (* print in html or txt list of hubs *)
134 let hublist_print h hnum o
=
135 let buf = o
.conn_buf
in
136 let hname = shorten_string h
.dc_name
50 in
137 let hinfo = shorten_string h
.dc_info
50 in
138 if use_html_mods o
then begin
140 \\<tr class=\\\"dl-%d\\\"\\>
141 \\<td class=\\\"srb\\\" \\>%d\\</td\\>
143 \\<td class=\\\"sr\\\"\\>%s\\</td\\>
144 \\<td class=\\\"sr\\\"\\>%s:%d\\</td\\>
145 \\<td class=\\\"sr\\\"\\>%d\\</td\\>
146 \\<td width=\\\"100%%\\\" class=\\\"sr\\\"\\>%s\\</td\\>\\</tr\\>\n"
149 (td_command "Add" "Add" ~target
:`Status
150 ["dcn"; Ip.string_of_addr h
.dc_ip
; string_of_int h
.dc_port
])
152 (Ip.string_of_addr h
.dc_ip
) h
.dc_port
155 Printf.bprintf
buf "[%5d] %20s %25s:%-10d Users:%-8d %20s\n"
158 (Ip.string_of_addr h
.dc_ip
) h
.dc_port
163 (* Print DC users header *)
164 let dc_user_print_html_header buf =
165 html_mods_table_header
buf "serversTable" "servers" [
166 ( "1", "srh", "User number", "#" );
167 ( "0", "srh", "User name", "Name" );
168 ( "0", "srh", "User type", "Type" );
169 ( "1", "srh", "Users slots (all/free)", "Slots" );
170 ( "1", "srh", "Users connected hubs (Normal/Vipped/Opped)", "Hubs" );
171 ( "0", "srh", "Users mode", "Mode" );
172 ( "1", "srh", "Users shared size", "Shared" );
173 ( "0", "srh", "User state", "State" );
174 ( "0", "srh", "User description field", "Description" );
175 ( "1", "srh", "User clients number", "Clients" );
176 ( "1", "srh", "Users servers number", "Servers" );
177 ( "0", "srh", "Download this clients filelist", "Filelist" );
178 ( "0", "srh", "Open chat window with this user. Blinking tells there are new unread messages", "Chat");
179 ( "1", "srh", "User total uploaded bytes", "Up" );
180 ( "1", "srh", "User total downloaded bytes", "Down" );
181 ( "0", "srh", "User client supports", "Supports" ); ];
184 (* print in html or txt list of users *)
185 let user_print user num o
=
186 let buf = o
.conn_buf
in
188 (match user
.user_type
with
195 (match user
.user_state
with
196 | UserIdle
-> "NotDefined"
197 | TryingToSendFirstContact
-> "TryingToSendFirstContact"
198 | UserActiveMeInitiating
-> "UserActiveMeInitiating"
199 | UserActiveUserInitiating
-> "UserActiveUserInitiating"
200 | UserPassiveUserInitiating
_ -> "UserPassiveUserInitiating" )
202 let clients = List.length user
.user_clients
in
203 let servers = List.length user
.user_servers
in
204 let messages = user_has_new_messages user
in
205 let hasmynick = has_my_nick user
in
207 let a,b
,c = user
.user_myinfo
.hubs in
208 Printf.sprintf
"(%d/%d/%d)" a b
c
211 if (List.length user
.user_clients
> 0) then begin
212 let c = List.hd user
.user_clients
in
213 (match c.client_supports
with
215 DcProtocol.Supports.create_supports_string
(ClientSupports
supports)
216 | _ -> empty_string
)
217 end else empty_string
219 if use_html_mods o
then begin
221 \\<tr class=\\\"dl-%d\\\"\\>
222 \\<td class=\\\"srb\\\" \\>%d\\</td\\>
223 \\<td class=\\\"sr\\\"\\>%s\\</td\\>
224 \\<td class=\\\"sr\\\"\\>%s\\</td\\>
225 \\<td class=\\\"sr\\\"\\>%d\\</td\\>
226 \\<td class=\\\"sr\\\"\\>%s\\</td\\>
227 \\<td class=\\\"sr\\\"\\>%c\\</td\\>
228 \\<td class=\\\"sr\\\"\\>%s\\</td\\>
229 \\<td class=\\\"sr\\\"\\>%s\\</td\\>
230 \\<td class=\\\"sr\\\"\\>%s\\</td\\>
231 \\<td class=\\\"sr\\\"\\>%d\\</td\\>
232 \\<td class=\\\"sr\\\"\\>%d\\</td\\>
234 \\<td class=\\\"sr\\\"\\>%s\\</td\\>
235 \\<td class=\\\"sr\\\"\\>%s\\</td\\>
236 \\<td class=\\\"sr\\\"\\>%s\\</td\\>\\</tr\\>\n"
237 (html_mods_cntr
()) num user
.user_nick
utype user
.user_myinfo
.slots
hubs user
.user_myinfo
.mode
238 (size_of_int64 user
.user_myinfo
.sharesize
) state user
.user_myinfo
.description
clients servers
239 (if not
hasmynick && (servers > 0) then (* is connected to any servers with us *)
240 td_command "Get List" "Download user filelist" ~target
:`Status
["dcloadfilelist"; user
.user_nick
]
243 if hasmynick then "Me"
246 Printf.sprintf
"\\<td class=\\\"sr\\\"\\>%s\\</td\\>" txt
248 (if not
hasmynick then (* not me *)
249 td_command "Open chat" "Open message window to this user" ~blink
:messages ["dcmessages"; user
.user_nick
]
251 "\\<td class=\\\"sr\\\"\\>\\</td\\>" )
252 (size_of_int64 user
.user_uploaded
) (size_of_int64 user
.user_downloaded
) supports
254 Printf.bprintf
buf "[%5d] %-20s %8s %20s\n" num user
.user_nick
utype state
256 (* Print DC hubs header *)
257 let dc_hub_print_html_header buf =
258 html_mods_table_header
buf "serversTable" "servers" [
259 ( "1", "srh", "Hub number", "#" ) ;
260 ( "0", "srh", "Set/UnSet server autoconnection state", "Auto" ) ;
261 ( "0", "srh", "Hub name", "Hub name" ) ;
262 ( "0", "srh", "IP address", "IP address" ) ;
263 ( "0", "srh", "My state in this hub", "State" ) ;
264 ( "1", "srh", "Users in hub", "Users" ) ;
265 ( "0", "srh", "Hub info", "Info" );
266 ( "0", "srh", "Open chat window with this hub. Blinking tells there are new unread message", "Chat" ) ]
268 (* Print list of connected hubs *)
269 let hub_print s num o
=
270 let buf = o
.conn_buf
in
271 let sinfo = shorten_string s
.server_info
50 in
272 let sname = shorten_string s
.server_name
50 in
273 let sip = Ip.to_string s
.server_ip
in
274 let sport = s
.server_port
in
275 let susers = List.length s
.server_users
in
276 let smessages = ((List.length s
.server_messages
) > s
.server_read_messages
) in
277 let sstate = dc_hubstate_to_text s
in
278 if use_html_mods o
then begin
280 \\<tr class=\\\"dl-%d\\\"\\>
281 \\<td class=\\\"srb\\\" \\>%d\\</td\\>
283 \\<td class=\\\"sr\\\"\\>%s\\</td\\>
284 \\<td class=\\\"sr\\\"\\>%s:%d\\</td\\>
285 \\<td class=\\\"sr\\\"\\>%s\\</td\\>
287 \\<td class=\\\"sr\\\"\\>%s\\</td\\>
292 (if s
.server_autoconnect
then "UnSet" else "Set")
293 "Set this hub autoconnection state"
294 ["dcautoconnect"; (if s
.server_autoconnect
then "false" else "true"); sip] )
295 sname sip sport sstate
296 (td_command (string_of_int
susers) "Show users for this hub only" ["dcusers";sip] )
298 (td_command "Open chat" "Open this hubs chat windows" ~blink
:smessages ["dcmessages";sip;string_of_int
sport])
300 Printf.bprintf
buf "[%5d] %20s %25s:%-10d Users:%-8d %20s\n"
308 (* Print DC clients header *)
309 let dc_client_print_html_header buf =
310 html_mods_table_header
buf "serversTable" "servers" [
311 ( "1", "srh", "Client number", "#" );
312 ( "0", "srh", "Remove Client", "Rem" );
313 ( "0", "srh", "Client name", "Name" );
314 ( "0", "srh", "Client ip/port", "Ip:Port" );
315 ( "0", "srh", "Client state", "State" );
316 ( "0", "srh", "Client connection", "Conn" );
317 ( "0", "srh", "Client last error/count", "Error" );
318 ( "0", "srh", "Client file", "File" ); ];
321 (* print in html or txt list of clients *)
322 let client_print name client num o
=
323 let buf = o
.conn_buf
in
325 (match client
.client_addr
with
326 | Some
(ip,port
) -> Ip.to_string
ip,port
330 (match client
.client_sock
with
331 | Connection
_ -> "Connected"
332 | ConnectionWaiting
_ -> "Connecting..."
333 | NoConnection
-> "NoConnection" )
335 let state = client_state_to_string client
in
337 (match client
.client_error
with
338 | NoError
-> empty_string
339 | NoFreeSlots
-> Printf.sprintf
"NoFreeSlots %d" client
.client_error_count
340 | FileNotAvailable
-> Printf.sprintf
"FileNotAvailable %d" client
.client_error_count
341 | UserNotReachable
-> Printf.sprintf
"UserNotReachable %d" client
.client_error_count
342 | ClosedOnInit
-> Printf.sprintf
"ClosedOnInit %d" client
.client_error_count
343 | ConnectionResetByPeer
-> Printf.sprintf
"ConnectionResetByPeer %d" client
.client_error_count
344 | UploadError
-> Printf.sprintf
"UploadError %d" client
.client_error_count
345 | UserDontReplyOnTime
-> Printf.sprintf
"UserDontReplyOnTime %d" client
.client_error_count
)
348 (match client
.client_state
with
349 | DcDownloadWaiting file
350 | DcDownloadConnecting
(file
,_)
351 | DcDownload file
-> file
.file_name
352 | DcUpload
(_,fd_file
,_,_)
353 | DcUploadList fd_file
354 | DcDownloadList fd_file
-> Unix32.filename fd_file
355 | DcUploadListStarting
filename -> filename
356 | DcUploadStarting
(dcsh
,_,_) -> dcsh
.dc_shared_codedname
359 if use_html_mods o
then begin
361 \\<tr class=\\\"dl-%d\\\"\\>
362 \\<td class=\\\"sr\\\" \\>%d\\</td\\>
364 \\<td class=\\\"sr\\\"\\>%s\\</td\\>
365 \\<td class=\\\"sr\\\"\\>%s:%d\\</td\\>
366 \\<td class=\\\"sr\\\" \\>%s\\</td\\>
367 \\<td class=\\\"sr\\\" \\>%s\\</td\\>
368 \\<td class=\\\"sr\\\" \\>%s\\</td\\>
369 \\<td class=\\\"sr\\\" \\>%s\\</td\\>\\</tr\\>\n"
370 (html_mods_cntr
()) num
371 (td_command "Rem" "Remove client" ~target
:`Status
372 ["dcremclient"; string_of_int
(client_num
(as_client client
.client_client
))] )
373 name
ip port
state conn error fil
375 Printf.bprintf
buf "[%5d] %25s %25s:%-10d S:%15s C:%15s F:%15s\n"
376 num name
ip port
state conn fil
378 (* Print DC files header *)
379 let dc_file_print_html_header buf =
380 html_mods_table_header
buf "serversTable" "servers" [
381 ( "1", "srh", "File number", "#" );
382 ( "0", "srh", "File name/path", "File" );
383 ( "1", "srh", "File size", "Size" );
384 ( "0", "srh", "Tiger Tree Hash and magnet url", "TTH and magnet" );
385 ( "1", "srh", "Files clients number (sources)", "Clients" );
386 ( "1", "srh", "Autosearches done", "Searches" );
387 ( "0", "srh", "Find new source by tth", "Find TTH" );
388 ( "0", "srh", "Find new source by similar name context", "Find similar" ); ];
391 let html_show_tth file size tth
=
392 begin match exn_catch TigerTree.of_string tth
with
396 method name
= Filename.basename file
397 method size
= match size
with 0L -> None
| _ -> Some size
(* do not report size if not available *)
398 method uids
= [TigerTree hash
]
400 Printf.sprintf
"\\<a href=\\\"%s\\\"\\>%s\\</a\\>" (show_magnet_url
magnet) tth
403 let html_show_shared dcsh
=
404 html_show_tth dcsh
.dc_shared_fullname dcsh
.dc_shared_size dcsh
.dc_shared_tiger_root
406 let html_show_file file
=
407 html_show_tth file
.file_name file
.file_file
.impl_file_size file
.file_unchecked_tiger_root
409 (* print in html or txt list of files *)
410 let file_print file num o
=
411 let buf = o
.conn_buf
in
412 let fname = ref (String.copy file
.file_name
) in
413 String2.replace_char
!fname char32 char42
; (* to * *)
414 String2.replace_char
!fname char39 char58
; (* ' to : *)
415 String2.replace_char
!fname char60 char38
; (* & to < *)
416 if use_html_mods o
then begin
418 \\<tr class=\\\"dl-%d\\\"\\>
419 \\<td class=\\\"srb\\\" \\>%d\\</td\\>
420 \\<td class=\\\"sr\\\"\\>%s\\</td\\>
421 \\<td class=\\\"srb\\\" \\>%Ld\\</td\\>
422 \\<td class=\\\"srb\\\" \\>%s\\</td\\>
423 \\<td class=\\\"srb\\\" \\>%d\\</td\\>
424 \\<td class=\\\"srb\\\" \\>%d\\</td\\>
427 (html_mods_cntr
()) num file
.file_name file
.file_file
.impl_file_size
428 (html_show_file file
) (List.length file
.file_clients
) file
.file_autosearch_count
429 (td_command "Find TTH" "Find new client for this file by TTH" ["dcfindsource"; file
.file_unchecked_tiger_root
])
430 (td_command "Find similar" "Find new client for this file by similar name" ["dcfindsource"; !fname])
432 Printf.bprintf
buf "[%5d] %40s %-15Ld %5d\n"
433 num file
.file_name file
.file_file
.impl_file_size
(List.length file
.file_clients
)
435 (* Print DC shared files header *)
436 let dc_shared_print_html_header buf =
437 html_mods_table_header
buf "serversTable" "servers" [
438 ( "1", "srh", "File number", "#" );
439 ( "0", "srh", "Shared file name", "Name" );
440 ( "1", "srh", "Shared file size", "Size" );
441 ( "0", "srh", "Tiger Tree Hash and magnet url", "TTH and magnet" );
442 (*( "1", "srh", "Shared files Tiger tree array length", "TTree #" );*) ];
446 (* print in html or txt list of shared files *)
447 let shared_print dcsh num o
=
448 let buf = o
.conn_buf
in
449 if use_html_mods o
then begin
451 \\<tr class=\\\"dl-%d\\\"\\>
452 \\<td class=\\\"srb\\\" \\>%d\\</td\\>
453 \\<td class=\\\"sr\\\"\\>%s\\</td\\>
454 \\<td class=\\\"srb\\\" \\>%Ld\\</td\\>
455 \\<td class=\\\"srb\\\" \\>%s\\</td\\>\\</tr\\>\n"
456 (html_mods_cntr
()) num dcsh
.dc_shared_codedname dcsh
.dc_shared_size
457 (html_show_shared dcsh
)
459 Printf.bprintf
buf "[%5d] %40s %-15Ld %24s\n"
460 num dcsh
.dc_shared_codedname dcsh
.dc_shared_size dcsh
.dc_shared_tiger_root
462 (* Print DC filelist header *)
463 let dc_filelist_print_html_header buf =
464 html_mods_table_header
buf "serversTable" "servers" [
465 ( "1", "srh", "Number", "#" ) ;
466 ( "0", "srh", "Filelist name", "Filelist" ) ]
468 (* Print one line from filelist *)
469 let filelist_print fname line o
=
470 let buf = o
.conn_buf
in
471 if use_html_mods o
then begin
473 \\<tr class=\\\"dl-%d\\\"\\>
474 \\<td class=\\\"srb\\\" \\>%d\\</td\\>
479 (td_command fname "Open filelist" ["dcshowfilelist"; fname])
481 Printf.bprintf
buf "[%5d] %s\n" line
fname
484 type dc_int_groups
= G_users
|G_hubs
|G_clients
|G_files
|G_shared
|G_filelists
486 (* register users,clients,files *)
487 let dc_list o group_type group_name
=
488 let buf = o
.conn_buf
in
490 html_mods_cntr_init
();
491 let html f = if use_html_mods o
then f buf else () in
493 begin match group_type
with
495 let new_messages_list = ref [] in (* lets order users with unread messages to the top *)
496 let others_list = ref [] in
497 Hashtbl.iter
(fun _ user
->
498 if user_has_new_messages user
then new_messages_list := user
:: !new_messages_list
499 else others_list := user
:: !others_list
501 html dc_user_print_html_header;
502 List.iter
(fun user
-> user_print user
!num o
; incr
num) !new_messages_list;
503 List.iter
(fun user
-> user_print user
!num o
; incr
num) !others_list;
505 html dc_hub_print_html_header;
506 Hashtbl.iter
(fun _ s
-> hub_print s
!num o
; incr
num) servers_by_ip
507 (*List.iter (fun s -> hub_print s !num o; incr num) !connected_servers*)
509 html dc_client_print_html_header;
511 (match c.client_name
with
512 | Some n
-> client_print n
c !num o
; incr
num
516 html dc_file_print_html_header;
517 List.iter
(fun file
-> file_print file
!num o
; incr
num) !current_files
;
519 html dc_shared_print_html_header;
520 Hashtbl.iter
(fun _ dcsh
-> shared_print dcsh
!num o
; incr
num) dc_shared_files_by_codedname
522 html dc_filelist_print_html_header;
523 let filelist = Unix2.list_directory filelist_directory
in
524 List.iter
(fun fname -> filelist_print fname !num o
; incr
num) filelist;
526 if use_html_mods o
then
527 Printf.bprintf
buf "\\</table\\>\\</div\\>";
529 lprintf_nl "Exception %s in printing %s" (Printexc2.to_string e
) group_name
533 (* Print DC filelist files header *)
534 let dc_filelist_files_print_html_header buf =
535 html_mods_table_header
buf "serversTable" (Printf.sprintf
"servers") [
536 ( "1", "srh", "Number", "#" );
537 ( "0", "srh", "File/Directory name", "File/Directory name" );
538 ( "1", "srh", "File Size", "Size" );
539 ( "0", "srh", "Files TTH", "TTH" ) ]
541 (* Print one line from filelist file *)
542 let filelist_file_print is_file spaces username dir
fname fsize ftth line o
=
543 (* is_file = if true, make the whole filename a link with submit command to load a file
545 username = username to submit in command
546 dir = current directory path to submit in command
547 fname = filename from mylist
548 fsize = filesize from mylist
549 ftth = tth from mylist *)
550 let buf = o
.conn_buf
in
551 let sdir = ref (String.copy dir
) in
552 let sname = ref (String.copy
fname) in
553 String2.replace_char
!sdir char32 char42
; (* to * *)
554 String2.replace_char
!sdir char39 char58
; (* ' to : *)
555 String2.replace_char
!sdir char38 char60
; (* & to < *)
556 String2.replace_char
!sdir char43 char62
; (* + to > *)
557 String2.replace_char
!sname char32 char42
;
558 String2.replace_char
!sname char39 char58
;
559 String2.replace_char
!sname char38 char60
;
560 String2.replace_char
!sname char43 char62
;
561 if use_html_mods o
then begin
563 \\<tr class=\\\"dl-%d\\\"\\>
564 \\<td class=\\\"srb\\\" \\>%d\\</td\\>
566 \\<td class=\\\"srb\\\" \\>%s\\</td\\>
567 \\<td class=\\\"srb\\\" \\>%s\\</td\\>\\</tr\\>\n"
571 td_command (spaces^
fname) "Start downloading" ~target
:`Status
572 ["dcloadfile"; username
; ftth
; !sdir; !sname; fsize
]
574 Printf.sprintf
"\\<td class=\\\"srb\\\" \\>\\<b\\>%s%s\\</b\\>\\</td\\>" spaces
fname
579 Printf.bprintf
buf "%30s %10s %30s\n" fname fsize ftth
582 (* Print DC info header *)
583 let dc_info_html_header buf =
584 html_mods_table_header
buf "sharesTable" "shares" [
585 ( "0", "srh", "Direct Connect information", "DC Info" ) ;
586 ( "0", "srh", empty_string
, empty_string
) ]
589 let dc_info_print info data line o
=
590 let buf = o
.conn_buf
in
591 if use_html_mods o
then begin
593 \\<tr class=\\\"dl-%d\\\"\\>
594 \\<td class=\\\"sr\\\"\\>%s\\</td\\>
595 \\<td class=\\\"sr\\\"\\>%s\\</td\\>\\</tr\\>"
596 (html_mods_cntr
()) info data
598 Printf.bprintf
buf "%s: %s\n" info data
601 let show_dc_buttons o
=
602 let buf = o
.conn_buf
in
603 let button id ?
(cmd
="dc"^id
) ?
(txt=String.capitalize id
) () =
604 Printf.bprintf
buf "\\<form style=\\\"margin: 0px;\\\" id=\\\"%s\\\" name=\\\"%s\\\"
605 action=\\\"javascript:parent.output.location.href='submit?q=%s'\\\"\\>
606 \\<td\\>\\<input style=\\\"font-family: verdana; font-size: 12px;\\\" type=submit
607 Value=\\\"%s\\\"\\>\\</td\\>\\</form\\>" id id cmd
txt
609 if use_html_mods o
then
611 Printf.bprintf
buf "\\<table\\>\\<tr\\>";
612 button "users" ~cmd
:"dcusers+all" ();
613 button "clients" ~cmd
:"dcclients" ();
617 button "info" ~
txt:"DC Info" ();
618 button "hublistshow" ~cmd
:"dchublist" ~
txt:"Show hublist" ();
619 button "filelists" ();
620 Printf.bprintf
buf "\\</tr\\>\\</table\\>";
623 (* List of commands to register *)
626 "dc", Arg_none
(fun o
->
627 if use_html_mods o
then
630 Printf.bprintf
buf "Try `?? dc` for more commands\n";
631 dc_list o G_hubs
"hubs"
632 ), ": Show Direct Connect buttons";
634 (* 'dcn address [port]' Add a new DC server with optional port (default 411) *)
635 "dcn", Arg_multiple
(fun args o
->
638 | [ip ; port
] -> ip, port
640 | _ -> failwith
"dcn <ip> [<port>]: bad argument number" )
642 let ip_addr = Ip.addr_of_string
ip in
643 Ip.async_ip_of_addr
ip_addr (fun t
-> (* do DNS check here *)
644 let port = int_of_string
port in
645 if !verbose_msg_servers
then lprintf_nl "New server being added: (%s) (%s) (%d)" ip (Ip.to_string t
) port;
646 if (Ip.valid t
) && (port>0) && (port<65536) then
647 ignore
(new_server
ip_addr t
port) ) (fun _ -> ());
649 ), "<ip> [<port>] : Add a server. Default port number is 411";
651 (* List connected hubs for chatting *)
652 "dchubs", Arg_none
(fun o
-> show_dc_buttons o
; dc_list o G_hubs
"hubs"
653 ), ": Show connected DC hubs";
655 (* List all DC users *)
656 "dcusers", Arg_one
(fun args o
->
658 let buf = o
.conn_buf
in
660 | "all" -> dc_list o G_users
"users"
663 let s = Hashtbl.find servers_by_ip
ip in
665 let new_messages_list = ref [] in (* lets order users with unread messages to the top *)
666 let others_list = ref [] in
667 List.iter
(fun user
->
668 if user_has_new_messages user
then new_messages_list := user
:: !new_messages_list
669 else others_list := user
:: !others_list
671 dc_user_print_html_header buf;
672 List.iter
(fun user
-> user_print user
!num o
; incr
num) !new_messages_list;
673 List.iter
(fun user
-> user_print user
!num o
; incr
num) !others_list;
675 with _ -> "dcusers <ip> : ip not valid" ) );
676 ), "<all>|<ip> :Show DC users";
678 (* List all DC clients *)
679 "dcclients", Arg_none
(fun o
-> show_dc_buttons o
; dc_list o G_clients
"clients"
680 ), ": Show all DC clients";
682 (* List all DC files *)
683 "dcfiles", Arg_none
(fun o
-> show_dc_buttons o
; dc_list o G_files
"files"
684 ), ": Show all DC files";
686 (* List all DC shared files *)
687 "dcshared", Arg_none
(fun o
-> show_dc_buttons o
; dc_list o G_shared
"shared"
688 ), ": Show all DC shared files. All/Hashed ";
690 (* 'dchublist [args]' - Show dchub list with optional filters args (max 5) *)
691 "dchublist", Arg_multiple
(fun args o
->
693 let buf = o
.conn_buf
in
694 let filter = ref [] in
695 let print_hublist () =
696 if use_html_mods o
then
698 html_mods_table_one_row
buf "serversTable" "servers" [
699 (empty_string
, "srh", Printf.sprintf
"Showing hublist"); ];
700 Printf.bprintf
buf "\\</table\\>\\</div\\>"
703 Printf.bprintf
buf "Showing hublist";
704 html_mods_cntr_init
();
705 let nb_hubs = ref 0 in
706 if use_html_mods o
then dc_hublist_print_html_header buf empty_string
;
707 let show_all = if (!filter = []) then true else false in
709 let hub_has_string searched
=
710 if String2.contains
(Ip.string_of_addr h
.dc_ip
) searched
||
711 String2.contains
(string_of_int h
.dc_port
) searched
||
712 String2.contains h
.dc_info searched
||
713 String2.contains h
.dc_name searched
then true
717 hublist_print h
!nb_hubs o
;
720 if !verbose_msg_servers
then
721 lprintf_nl "Exception %s in hub_print\n" (Printexc2.to_string e
))
727 let print = ref false in
728 let finished = ref false in
729 let counter = ref 0 in
730 let filters_length = List.length
!filter in
731 while (!print = false) && (!finished = false) do
732 if (!counter = filters_length) || (!counter > 5) then
735 if (hub_has_string (List.nth
!filter !counter)) then print := true;
738 if (!print = true) then print_hub ()
741 let txt = if show_all then "(showing all hubs from hublist)" else "(filtered)" in
742 if use_html_mods o
then
744 Printf.bprintf
buf "\\</table\\>\\</div\\>";
745 html_mods_table_one_row
buf "serversTable" "servers" [
746 (empty_string
, "srh", Printf.sprintf
"Hubs: %d known %s" !nb_hubs txt); ]
749 Printf.bprintf
buf "Hubs: %d known %s" !nb_hubs txt
753 | rest_args
-> filter := rest_args
757 ), "[filtertext]: dchublist fin - filters hubs with text fin";
759 (* 'dcuserip name' query user-ip from hub *)
760 "dcuserip", Arg_multiple
(fun args o
->
761 let buf = o
.conn_buf
in
763 | [hub
; port ; name
] ->
765 let s = Hashtbl.find servers_by_ip hub
in
766 (match s.server_sock
with
767 | Connection sock
-> dc_send_msg sock
( UserIPReq
( [name
] ))
770 if !verbose_unexpected_messages
then
771 lprintf_nl "dcuserip: No server found by ip (%s) (%s) (%s)" hub
port name
)
772 | _ -> if !verbose_unexpected_messages
then lprintf_nl "dcuserip: Invalid args count (%d)" (List.length args
) );
773 Printf.bprintf
buf "User query sent to hubs\n";
775 ), "<user> : Query users ip from hub";
777 "dcmsglog", Arg_multiple
(fun args o
->
778 let buf = o
.conn_buf
in
779 let counter = ref 0 in
780 let messages,name
,topic
=
782 | delay
:: ip :: port :: _ ->
784 let s = Hashtbl.find servers_by_ip
ip in
786 (match s.server_sock
with
787 | Connection
_ -> s.server_topic
788 | _ -> "NOT CONNECTED TO SERVER" )
790 s.server_read_messages
<- List.length
s.server_messages
; (* messages are set as read before *)
791 s.server_messages
, (* they are actually printed to user *)
792 (shorten_string
s.server_name
50),
795 if !verbose_unexpected_messages
then lprintf_nl "dcmsglog: No server with address found";
799 let u = search_user_by_name n
in
800 let connected = ((List.length
u.user_servers
) > 0) in
801 u.user_read_messages
<- List.length
u.user_messages
; (* messages are set as read before *)
802 u.user_messages
, u.user_nick
, (* they are actually printed to user *)
803 (if connected then empty_string
804 else "User not connected to any servers at the moment...")
806 if !verbose_unexpected_messages
then lprintf_nl "dcmsglog: No user found";
809 if !verbose_unexpected_messages
then lprintf_nl "dcmsglog: Invalid args count (%d)" (List.length args
);
812 if use_html_mods o
then begin
813 Printf.bprintf
buf "\\<div class=\\\"messages\\\"\\>";
814 Printf.bprintf
buf "\\<div\\>Chatting with \\<b\\>%s\\</b\\> - %d logged messages\\</div\\>"
815 name
(List.length
messages);
816 Printf.bprintf
buf "\\<div\\>\\<i\\>%s\\</i\\>\\</div\\>" topic
818 Printf.bprintf
buf "%d logged messages\n" (List.length
messages);
819 if use_html_mods o
then html_mods_table_header
buf "serversTable" "servers" [
820 ( "0", "srh", "Timestamp", "Time" );
821 ( "0", "srh", "Who message is from", "From" );
822 ( "0", "srh", "Message text", "Message" ) ];
823 List.iter
(fun (t
,f,m
) ->
826 | PrivateMessage
(_, msg) -> msg
827 | PublicMessage
(_, msg) -> msg
828 | ServerMessage
msg -> msg )
830 if use_html_mods o
then begin
831 Printf.bprintf
buf "\\<tr class=\\\"%s\\\"\\>"
832 (if (!counter mod 2 == 0) then "dl-1" else "dl-2");
834 (empty_string
, "sr", Date.simple
(BasicSocket.date_of_int t
));
835 (empty_string
, "sr", f);
836 (empty_string
, "srw", String2.replace
msg '
\r'
"\\<br/\\>") ];
837 Printf.bprintf
buf "\\</tr\\>"
839 Printf.bprintf
buf "\n%s [%s] : %s\n" (Date.simple
(BasicSocket.date_of_int t
)) f msg
843 if use_html_mods o
then Printf.bprintf
buf "\\</table\\>\\</div\\>\\</div\\>";
845 ), "<refresh> <user> | <refresh> <serverip> <serverport>";
847 "dcmessages", Arg_multiple
(fun args o
->
849 let buf = o
.conn_buf
in
854 let s = Hashtbl.find servers_by_ip
ip in
857 if !verbose_unexpected_messages
then lprintf_nl "dcmessages: No server with address found";
861 let u = search_user_by_name n
in
864 if !verbose_unexpected_messages
then lprintf_nl "dcmessages: No user found";
867 if !verbose_unexpected_messages
then lprintf_nl "dcmessages: No user or server";
870 if use_html_mods o
then begin
871 Printf.bprintf
buf "\\<script type=\\\"text/javascript\\\"\\>
873 function submitCmd() {
874 var formID = document.getElementById(\\\"msgForm\\\")
875 parent.output.location.href='submit?q=dcmessages+'+formID.sendCmd.value
877 function submitMessageForm() {
878 var formID = document.getElementById(\\\"msgForm\\\")
879 var regExp = new RegExp (' ', 'gi')
880 var msgTextOut = formID.msgText.value.replace(regExp, '+')
881 parent.fstatus.location.href='submit?q=dcsendmsg+'+formID.sendCmd.value+\\\"+\\\"+msgTextOut
882 formID.msgText.value=\\\"\\\"
883 msgWindow.location.reload();
887 let sendmsg,namelist
,first
=
890 let ip,port = (Ip.to_string
s.server_ip
),(string_of_int
s.server_port
) in
891 Printf.sprintf
"dcmsglog+20+%s+%s" ip port, s.server_users
, Printf.sprintf
"%s %s" ip port
895 Printf.sprintf
"dcmsglog+20+%s" u.user_nick
, [], u.user_nick
897 if !verbose_unexpected_messages
then lprintf_nl "dcmessages: No user or server";
901 Printf.bprintf
buf "\\<iframe id=\\\"msgWindow\\\" name=\\\"msgWindow\\\" height=\\\"80%%\\\"
902 width=\\\"100%%\\\" scrolling=yes src=\\\"submit?q=%s\\\"\\>\\</iframe\\>" sendmsg;
903 Printf.bprintf
buf "\\<form style=\\\"margin: 0px;\\\" name=\\\"msgForm\\\" id=\\\"msgForm\\\" action=\\\"javascript:submitMessageForm()\\\"\\>";
904 Printf.bprintf
buf "\\<table width=100%% cellspacing=0 cellpadding=0 border=0\\>\\<tr\\>\\<td\\>";
905 Printf.bprintf
buf "\\<select style=\\\"font-family: verdana; font-size: 12px; width: 150px;\\\" id=\\\"sendCmd\\\" name=\\\"sendCmd\\\" \\>";
906 Printf.bprintf
buf "\\<option value=\\\"%s\\\"\\>%s" first first
;
908 if not
(has_my_nick
u) then
909 Printf.bprintf
buf "\\<option value=\\\"%s\\\"\\>%s" u.user_nick
u.user_nick
911 Printf.bprintf
buf "\\</select\\>\\</td\\>";
912 Printf.bprintf
buf "\\<td width=100%%\\>\\<input style=\\\"width: 99%%; font-family: verdana; font-size: 12px;\\\"
913 type=text id=\\\"msgText\\\" name=\\\"msgText\\\" size=50 \\>\\</td\\>";
914 Printf.bprintf
buf "\\<td\\>\\<input style=\\\"font-family: verdana;
915 font-size: 12px;\\\" type=submit value=\\\"Send\\\"\\>\\</td\\>\\</form\\>";
916 Printf.bprintf
buf "\\<form style=\\\"margin: 0px;\\\" id=\\\"refresh\\\" name=\\\"refresh\\\"
917 action=\\\"javascript:msgWindow.location.reload();\\\"\\>
918 \\<td\\>\\<input style=\\\"font-family: verdana; font-size: 12px;\\\" type=submit
919 Value=\\\"Refresh\\\"\\>\\</td\\>\\</form\\>\\</tr\\>\\</table\\>";
920 Printf.bprintf
buf "\\<table\\>\\<tr\\>\\<form style=\\\"margin: 0px;\\\" id=\\\"users\\\" name=\\\"users\\\"
921 action=\\\"javascript:parent.output.location.href='submit?q=dcusers'\\\"\\>
922 \\<td\\>\\<input style=\\\"font-family: verdana; font-size: 12px;\\\" type=submit
923 Value=\\\"Users\\\"\\>\\</td\\>\\</form\\>";
924 Printf.bprintf
buf "\\<form style=\\\"margin: 0px;\\\" id=\\\"hubs\\\" name=\\\"hubs\\\"
925 action=\\\"javascript:parent.output.location.href='submit?q=dchubs'\\\"\\>
926 \\<td\\>\\<input style=\\\"font-family: verdana; font-size: 12px;\\\" type=submit
927 Value=\\\"Hubs\\\"\\>\\</td\\>\\</form\\>";
928 Printf.bprintf
buf "\\<form style=\\\"margin: 0px;\\\" id=\\\"hubs\\\" name=\\\"hubs\\\"
929 action=\\\"javascript:submitCmd()\\\"\\>
930 \\<td\\>\\<input style=\\\"font-family: verdana; font-size: 12px;\\\" type=submit
931 Value=\\\"Open chat\\\"\\>\\</td\\>\\</form\\>";
932 Printf.bprintf
buf "\\</tr\\>\\</table\\>";
935 _s
"Usage: dcmessages <username> | <serverip> <serverport>\n"
936 ), "<username> | <serverip> <serverport> : Show user or server messages ";
939 (* message type = (int * room_message) list
940 room_message type = | ServerMessage of string
941 | PublicMessage of int * string
942 | PrivateMessage of int * string *)
943 (* 'dcsendmsg hub port user message' - send message to specific user *)
944 "dcsendmsg", Arg_multiple
(fun args o
->
945 let buf = o
.conn_buf
in
946 (*let failtxt = "dcsendmsg <user> <message> | <serverip> <serverport> <message> : bad arguments" in*)
947 let u = (* check if first argument is valid user *)
949 let u = search_user_by_name
(List.hd args
) in
955 let s = Hashtbl.find servers_by_ip
(List.hd args
) in
960 | Some
u -> (* message is private usermessage *)
963 if not
(has_my_nick
u) && ((List.length
u.user_servers
) > 0) then begin
964 let sent = ref false in
965 List.iter
(fun s -> (* find a server we are connected to with this user *)
966 (match s.server_sock
with
968 if not
!sent then begin
969 let msg = String2.unsplit
messages ' '
in
971 ToReq
{ To.dest
= u.user_nick
;
972 To.from
= s.server_last_nick
;
973 To.message
= msg } );
975 u.user_messages
<- u.user_messages
@ [
976 (int_of_float
(current_time
()), s.server_last_nick
, PrivateMessage
(0, msg))];
983 (match s with (* message is probably hub chatmessage but check ip *)
984 | None
-> if !verbose_unexpected_messages
then lprintf_nl "dcsendmsg: No User or Server found"
987 | _ :: _ :: messages ->
988 (match s.server_sock
with
990 let msg = String2.unsplit
messages ' '
in
991 dc_send_msg sock
( MessageReq
{ Message.from
= s.server_last_nick
; Message.message
= msg } );
992 (* don't save this message, it is echoed from hub back to us and saved then *)
993 (* message window is refreshed too quickly to show this *)
998 Printf.bprintf
buf "User query sent to hubs\n";
1000 ), "<user> <message> : Send message to user";
1002 (* Try to load file from filelist *)
1003 "dcloadfile", Arg_multiple
(fun args o
->
1004 let buf = o
.conn_buf
in
1006 | [uname
; tth
; dir
; fname ; fsize
] -> (* convert filenames back to normal *)
1007 if !verbose_download
then lprintf_nl "dcloadfile: (%s) (%s) (%s)" dir
fname tth
;
1008 let sdir = ref (String.copy dir
) in
1009 let sname = ref (String.copy
fname) in
1010 String2.replace_char
!sdir char42 char32
; (* * to *)
1011 String2.replace_char
!sdir char58 char39
; (* : to ' *)
1012 String2.replace_char
!sdir char60 char38
; (* < to & *)
1013 String2.replace_char
!sdir char62 char43
; (* > to + *)
1014 String2.replace_char
!sname char42 char32
;
1015 String2.replace_char
!sname char58 char39
;
1016 String2.replace_char
!sname char60 char38
;
1017 String2.replace_char
!sname char62 char43
;
1018 Printf.bprintf
buf "Trying to download file: %s from user: %s\n" !sname uname
;
1020 let u = search_user_by_name uname
in
1021 ignore
(start_new_download (Some
u) tth
!sdir !sname (Int64.of_string fsize
))
1022 with _ -> if !verbose_download
then lprintf_nl "dcloadfile: No user found" )
1024 if !verbose_unexpected_messages
then
1025 lprintf_nl "dcloadfile: bad arguments count (%d)" (List.length args
) );
1027 ), "<username> <tth> <directory> <filename> : Load a file";
1029 (* load filelist from user *)
1030 "dcloadfilelist", Arg_one
(fun args o
->
1031 let buf = o
.conn_buf
in
1035 let u = search_user_by_name name
in
1036 if ((List.length
u.user_servers
) > 0) then begin
1037 if not
(filelist_already_downloading
u) then begin (* and is connected to server with us *)
1038 if !verbose_msg_clients
|| !verbose_download
then
1039 lprintf_nl "Loading filelist from user %s" name
; (* not already loading filelist *)
1040 let c = new_client
() in
1041 c.client_name
<- Some
u.user_nick
;
1042 add_client_to_user
c u;
1043 c.client_state
<- DcDownloadListWaiting
;
1044 if (can_user_start_downloading
u) then begin
1045 u.user_state
<- TryingToSendFirstContact
;
1046 c.client_state
<- DcDownloadListConnecting
(0,!!firewalled
,current_time
()); (* level is set later *)
1047 ignore
(DcClients.try_connect_client
c);
1052 if !verbose_unexpected_messages
then lprintf_nl "dcloadfilelist: No user (%s) found" name
) );
1053 Printf.bprintf
buf "Trying to download filelist\n";
1055 ), "<name> : Download filelist from user";
1057 "dcfilelists", Arg_none
(fun o
-> show_dc_buttons o
; dc_list o G_filelists
"filelists"
1058 ), ": List all filelists on disk";
1060 "dcremclient", Arg_one
(fun args o
->
1061 let buf = o
.conn_buf
in
1065 let cc = CommonClient.client_find
(int_of_string
num) in
1066 let impl = as_client_impl
cc in
1067 let c = impl.impl_client_val
in
1068 (match c.client_state
with
1069 | DcDownloadWaiting
_ | DcDownloadListWaiting
->
1070 Printf.bprintf
buf "Removing one client by name %s" (clients_username
c);
1074 if !verbose_msg_clients
then lprintf_nl "dcremclient: bad arguments (internal command)" ) );
1076 ), "<num> : Remove client by num";
1078 "dcfindsource", Arg_one
(fun args o
->
1080 | tth_or_filename
->
1081 (*lprintf_nl "Got dcfindsource command: (%s)" tth_or_filename;*)
1082 let tth_or_filename = ref (String.copy
tth_or_filename) in
1083 String2.replace_char
!tth_or_filename char42 char32
;
1084 String2.replace_char
!tth_or_filename char58 char39
;
1085 String2.replace_char
!tth_or_filename char38 char60
;
1086 if (is_valid_tiger_hash
!tth_or_filename) then begin
1087 let query = QAnd
(QHasField
(Field_Type
, "TTH") , (QHasWord
!tth_or_filename)) in
1088 let search = CommonSearch.new_search o
.conn_user
1089 (let module G
= GuiTypes
in
1091 G.search_query
= query;
1092 G.search_max_hits
= 10000;
1093 G.search_type
= RemoteSearch
;
1094 G.search_network
= network
.network_num
;
1097 dc_with_connected_servers
(fun s -> DcClients.server_send_search
s search 9 !tth_or_filename);
1098 dc_last_manual_search
:= current_time
();
1100 let fname = Filename.basename
!tth_or_filename in
1101 let words = clean_string
fname in
1102 let words_list = String2.split_simplify
words ' '
in
1103 let rec add_query list
=
1105 | hd
:: [] -> QHasWord hd
1106 | hd
:: tail
-> QAnd
((QHasWord hd
) , (add_query tail
))
1107 | [] -> failwith
"No words to search")
1109 let query = add_query words_list in
1110 let search = CommonSearch.new_search o
.conn_user
1111 (let module G
= GuiTypes
in
1113 G.search_query
= query;
1114 G.search_max_hits
= 10000;
1115 G.search_type
= RemoteSearch
;
1116 G.search_network
= network
.network_num
;
1119 dc_with_connected_servers
(fun s -> DcClients.server_send_search
s search 1 !tth_or_filename);
1120 dc_last_manual_search
:= current_time
();
1123 ), ": Find new source for a file";
1125 "dcinfo", Arg_none
(fun o
->
1127 let buf = o
.conn_buf
in
1132 shorten_string
s.server_name
20 ^
" (nick = " ^
s.server_last_nick ^
") (uptime = " ^
1133 (Date.time_to_string
(int_of_float
(current_time
()) -
1134 int_of_float
(s.server_connection_time
)) "verbose") ^
1135 (string_of_int
(List.length
s.server_users
)) ^
")"
1137 lst := !lst @ [ (empty_string
, data) ]
1138 ) !connected_servers
;
1141 let norm_hubs,reg_hubs
,opped_hubs
= get_myhubs_info
() in
1142 html_mods_cntr_init
();
1143 if use_html_mods o
then dc_info_html_header buf;
1144 let nservers = List.length
!connected_servers
in
1146 ("Hub supports", (DcProtocol.Supports.create_supports_string
(HubSupports mldonkey_dc_hub_supports
)) );
1147 ("Client supports", (DcProtocol.Supports.create_supports_string
(ClientSupports mldonkey_dc_client_supports
)) );
1148 ("All/Open slots", Printf.sprintf
"%d / %d" (open_slots
()) (current_slots
()) );
1149 ("Mode", (if !!firewalled
then "Passive" else "Active") );
1150 ("Connected servers", (if nservers > 0 then string_of_int
nservers else ""));
1151 (" Server list:", empty_string
); ]
1153 ("Hubs", (Printf.sprintf
"Normal:%d Vipped:%d Opped:%d" norm_hubs reg_hubs opped_hubs
) ); ]
1155 let counter = ref 0 in
1156 List.iter
(fun (info
,data) ->
1157 dc_info_print info
data line o
;
1160 if use_html_mods o
then Printf.bprintf
buf "\\</table\\>\\</div\\>";
1162 ), ": Direct Connect info";
1164 (* load filelist from user *)
1165 "dcshowfilelist", Arg_one
(fun args o
->
1167 let buf = o
.conn_buf
in
1170 let username, extension
=
1172 if (Filename.check_suffix
filename mylist_ext
) then (* if extension is DcLst ... *)
1173 Filename.chop_suffix
filename mylist_ext
,mylist_ext
(* return filename without it and ext *)
1174 else if (Filename.check_suffix
filename bz2_ext
) then begin (* else if extension is bz2 ... *)
1175 let filename = Filename.chop_suffix
filename bz2_ext
in (* chop it off *)
1176 if (Filename.check_suffix
filename xml_ext
) then (* check if there is extension xml ...*)
1177 Filename.chop_suffix
filename xml_ext
,mylistxmlbz2_ext
(* return filename without it and ext *)
1178 else raise Not_found
1179 end else raise Not_found
1180 with _ -> filename, empty_string
)
1182 let spaces num = (* add as many "...":s to string that counter num *)
1185 if (num <> 0) then begin
1192 if (extension
= mylist_ext
) then begin (* parse MyList.DcLst *)
1194 let s = file_to_che3_to_string
(Filename.concat filelist_directory
filename) in
1195 if not
(Charset.is_utf8
s) then lprintf_nl "not utf8 : %S" s;
1196 let s = Charset.Locale.to_utf8
s in (* really needed? *)
1198 String2.replace_char
s char13 '
\n'
;
1199 let lines = String2.split_simplify
s '
\n'
in
1200 let mlist = ref ([] : dc_mylistnode
list) in (* root node of the MyList *)
1201 let tablist = ref [(-1, mlist)] in (* list of previous open directory node for every tab *)
1202 (* [(0 , list ref); (1 , list ref) ... *)
1203 let rec count_tabs line pos
= (* count current lines tabs *)
1204 if line
.[pos
] <> '
\t'
then pos
else
1205 count_tabs line
(pos
+1)
1207 let add_dir name tabs
list =
1208 let newlist = ref ([] : dc_mylistnode
list) in
1209 list := !list @ [MylistDirectory
(name
, newlist)]; (* add this dir node to current list *)
1210 if (List.mem_assq tabs
!tablist) then begin (* check if a directory exists already for this tab *)
1211 tablist := List.remove_assq tabs
!tablist; (* remove existing previous tab *)
1213 tablist := !tablist @ [(tabs
, newlist)]; (* add current list to this tab *)
1215 let add_file name size
list =
1216 list := !list @ [MylistFile
(name
, size
)]; (*add this file to current node *)
1218 let find_tab_dir tabs
= (* find the node of last directory for this tab *)
1219 let nlist = List.assq tabs
!tablist in
1220 nlist (* return list ref *)
1222 let rec parse lines ctabs clist
=
1225 let ltabs = count_tabs first
0 in (* count lines tabs *)
1226 (match (String2.split first '
|'
) with
1227 | dir
:: [] -> (* if line is directory *)
1228 let dir = String2.after
dir ltabs in
1229 if ltabs = ctabs
then begin
1230 let nlist = find_tab_dir (ltabs-1) in
1231 add_dir dir ltabs nlist;
1232 if (tail
<> []) then begin
1233 let nlist = find_tab_dir ltabs in
1234 parse tail
ltabs nlist
1236 end else if ltabs > ctabs
then begin
1237 add_dir dir ltabs clist
;
1238 let nlist = find_tab_dir ltabs in
1239 if (tail
<> []) then parse tail
ltabs nlist
1241 let nlist = find_tab_dir ltabs in
1242 parse lines ltabs nlist
1244 | name
:: size
:: [] -> (* if line is file *)
1245 let name = String2.after
name ltabs in
1246 if ltabs > ctabs
then begin
1247 add_file name size clist
;
1248 if (tail
<> []) then parse tail ctabs clist
1249 end else if ltabs <= ctabs
then begin
1250 let nlist = find_tab_dir (ltabs-1) in
1251 add_file name size
nlist;
1252 parse tail
(ltabs-1) nlist
1254 | _ -> failwith
(Printf.sprintf
"Unknown line (%s)" first
) )
1257 parse lines (pred
0) mlist;
1259 html_mods_cntr_init
();
1261 if use_html_mods o
then dc_filelist_files_print_html_header buf;
1262 let rec print node
dir tabs
=
1265 | MylistFile
(name, size
) ->
1266 filelist_file_print true (spaces tabs
) username dir name size empty_string
!line o
;
1267 (*lprintf_nl "(%s) (%s)" (!spaces ^ name) (Int64.to_string size);*)
1268 | MylistDirectory
(name, nlist) ->
1270 if dir = "" then name
1271 else dir ^
"/" ^
name
1273 filelist_file_print false (spaces tabs
) username dir name empty_string empty_string
!line o
;
1274 (*lprintf_nl "(%s) list_count=(%d)" (!spaces ^ dir) (List.length !nlist);*)
1276 List.iter (fun node
-> print node
dir (tabs
+1)) !nlist )
1278 List.iter (fun node
-> print node empty_string
0) !mlist;
1279 if use_html_mods o
then Printf.bprintf
buf "\\</table\\>\\</div\\>";
1281 if !verbose_unexpected_messages
then
1282 lprintf_nl "dcshowfilelist: (%s) in .DcLst parsing" (Printexc2.to_string e
) )
1283 with _ -> if !verbose_unexpected_messages
then lprintf_nl "Error in che3 decompressing" )
1285 end else if (extension
= mylistxmlbz2_ext
) then begin (* parse .xml.bz2 *)
1286 (try (* try to unzip *)
1287 let s = Buffer.contents
(file_to_bz2_to_buffer
(Filename.concat filelist_directory
filename)) in
1288 (try (* try to parse xml and make a www page *)
1289 let xml = Xml.parse_string
s in
1290 let parse_xml_chars s = (* in xml there are html-escapes mixed in *)
1291 let s = dc_replace_str_to_str
s "&" "&" in
1294 if ((Xml.tag
xml) <> "FileListing") then failwith
"Xml-file don't start with FileListing";
1295 html_mods_cntr_init
();
1297 if use_html_mods o
then dc_filelist_files_print_html_header buf;
1298 let rec parse x
dir ndirs
= (* iterate this with all xml elements (one node with tag and attributes *)
1299 let tag = Xml.tag x
in
1301 if tag = "File" then dir (* if tag of element is file, return existing dir name *)
1302 else begin (* else this is "probably" a directory *)
1303 let newdir = Xml.attrib x
"Name" in (* get dir name *)
1304 if dir = "" then newdir (* if this is first dir to add, don't add the "/" *)
1305 else dir ^
"/" ^
newdir (* else add this new dir path name to existing dir *)
1309 | "File" -> (* is this xml element is a file element, add its line to http-page *)
1310 let fname = Xml.attrib x
"Name" in
1311 let fname = parse_xml_chars fname in
1312 let fsize = Xml.attrib x
"Size" in
1313 let ftth = Xml.attrib x
"TTH" in
1315 filelist_file_print true (spaces ndirs
) username dir fname fsize ftth !line o
;
1316 | "Directory" -> (* or if it is a directory element, add its line to http-page *)
1317 let fname = Xml.attrib x
"Name" in
1318 let fname = parse_xml_chars fname in
1319 let fsize = empty_string
in
1320 let ftth = empty_string
in
1322 filelist_file_print false (spaces ndirs
) username dir fname fsize ftth !line o
;
1323 | _ -> failwith
"Tag not File or Directory" );
1325 Xml.iter (fun x
-> parse x
dir (ndirs
+1)) x
1327 Xml.iter (fun x
-> parse x empty_string
0) xml;
1328 if use_html_mods o
then Printf.bprintf
buf "\\</table\\>\\</div\\>";
1330 | Error e
-> if !verbose_unexpected_messages
then lprintf_nl "%s" (Xml.error e
)
1331 | e
-> if !verbose_unexpected_messages
then
1332 lprintf_nl "dcshowfilelist: (%s) in xml parsing" (Printexc2.to_string e
) )
1333 with _ -> if !verbose_unexpected_messages
then lprintf_nl "Error in bz2 unzipping" )
1334 end else if !verbose_unexpected_messages
then lprintf_nl "dcshowfilelist: Filelist extension not valid" );
1336 ), "<name> : Show filelist for user";
1338 "dcautoconnect", Arg_two
(fun arg1 arg2 o
->
1341 let s = Hashtbl.find servers_by_ip arg2
in
1342 let auto = bool_of_string arg1
in
1343 s.server_autoconnect
<- auto;
1344 server_must_update
s;
1346 with exn
-> Printf.sprintf
"Failed : %s" (Printexc2.to_string exn
)
1347 ), "<true/false> <ip> : Set/unset the server autoconnection state";
1349 ] (* end of let commands = *)
1353 (* register user operations *)
1355 register_commands commands;
1357 user_ops
.op_user_info
<- (fun user
-> (* CHECK *)
1359 P.user_num
= user
.user_user
.impl_user_num
;
1360 P.user_md4
= Md4.null
;
1361 P.user_name
= user
.user_nick
;
1362 P.user_ip
= Ip.null
;
1366 if user
.user_data
> 1. then
1367 [ { tag_name
= Field_UNKNOWN
"link"; tag_value
= String user
.user_link
};
1368 { tag_name
= Field_UNKNOWN
"shared"; tag_value
= String
(
1369 Printf.sprintf
"%12.0f" user
.user_data
) } ]
1372 (match user
.user_type
with
1373 | Normal
| Vip
-> list
1374 | Op
-> { tag_name
= Field_UNKNOWN
"admin"; tag_value
= String
"admin" } :: list ) );
1376 (match user
.user_servers
with
1378 | s :: _ -> s.server_server
.impl_server_num
);
1381 user_ops
.op_user_remove
<- (fun user
-> () )
1383 user_ops.op_user_browse_files <- (fun user ->
1384 let c = client_of_user user in
1385 contact_add (as_client c.client_client)
1387 user_ops.op_user_set_friend <- (fun user ->
1388 let c = client_of_user user in
1389 friend_add (as_client c.client_client)
1392 mutable op_user_network : network;
1393 mutable op_user_set_friend : ('a -> unit);
1394 mutable op_user_browse_files : ('a -> unit);
1399 (*module C = CommonTypes
1401 result_ops.op_result_info <- (fun r ->
1403 C.result_num = r.result_result.impl_result_num;
1404 C.result_network = network.network_num;
1406 C.result_names = [r.result_name];
1407 C.result_md4 = Md4.null;
1408 C.result_size = r.result_size;
1409 C.result_format = result_format_of_name r.result_name;
1410 C.result_type = result_media_of_name r.result_name;
1412 C.result_comment = "";
1413 C.result_done = false;
1419 (* register file operations *)
1421 file_ops
.op_file_info
<- (fun file
->
1423 P.file_fields
= Fields_file_info.all
;
1424 P.file_comment
= empty_string
;
1425 P.file_name
= file
.file_name
;
1426 P.file_num
= (file_num file
);
1427 P.file_network
= network
.network_num
;
1428 P.file_names
= [file
.file_name
];
1429 P.file_md4
= Md4.null
;
1430 P.file_size
= file_size file
;
1431 P.file_downloaded
= file_downloaded file
;
1432 P.file_all_sources
= 0;
1433 P.file_active_sources
= 0;
1434 P.file_state
= file_state file
;
1435 P.file_sources
= None
;
1436 P.file_download_rate
= file_download_rate file
.file_file
;
1437 P.file_chunks
= None
;
1438 P.file_chunk_size
= None
;
1439 P.file_availability
= [network
.network_num
, "0"];
1440 P.file_format
= FormatUnknown
;
1441 P.file_chunks_age
= [|0|];
1442 P.file_age
= file_age file
;
1443 P.file_last_seen
= BasicSocket.last_time
();
1444 P.file_priority
= file_priority
(as_file file
.file_file
);
1446 P.file_sub_files
= [];
1447 P.file_comments
= [];
1448 P.file_magic
= None
;
1449 P.file_user
= empty_string
;
1450 P.file_group
= empty_string
;
1451 P.file_release
= false;
1454 file_ops
.op_file_all_sources
<- (fun file
->
1455 List2.tail_map
(fun c -> as_client
c.client_client
)
1458 file_ops
.op_file_active_sources
<- file_ops
.op_file_all_sources
;
1459 file_ops
.op_file_cancel
<- (fun file
->
1460 let remove_files_clients_not_downloading () =
1462 (match c.client_state
with
1463 | DcDownload
f -> () (* only one client should be in this state *)
1466 ) file
.file_clients
;
1469 List.iter (fun c -> (* find one files client that is currently downloading *)
1470 (match c.client_state
with
1471 | DcDownload
_ -> raise
(Found_client
c)
1473 ) file
.file_clients
;
1476 | Found_client
c -> (* found a download slot tried to continue *)
1477 (match (DcClients.find_next_client
c) with (* try to continue slot *)
1479 (match c.client_sock
with
1480 | Connection sock
->
1481 remove_files_clients_not_downloading ();
1482 remove_file_not_clients file
;
1483 c.client_receiving
<- Int64.zero
;
1484 c.client_pos
<- Int64.zero
;
1485 TcpBufferedSocket.set_rtimeout sock
30.;
1486 DcClients.next_download
false c sock cl
(* try to change downloading *)
1489 remove_files_clients_not_downloading ();
1490 remove_file_not_clients file
;
1491 c.client_state
<- DcIdle
;
1492 (match c.client_sock
with
1493 | Connection sock
-> TcpBufferedSocket.close sock
(Closed_for_error
"File cancelled")
1497 remove_file_with_clients file
);
1498 if !verbose_download
then lprintf_nl "File %s cancelled" file
.file_name
;
1500 file_ops
.op_file_commit
<- (fun file
name ->
1501 remove_file_with_clients file
;
1503 file_ops
.op_file_pause
<- (fun file
->
1506 (match c.client_state
with
1507 | DcDownload
f -> if file
== f then raise
(Found_client
c)
1509 ) file
.file_clients
;
1513 (match (DcClients.find_next_client
c) with (* try to continue slot *)
1515 (match c.client_sock
with
1516 | Connection sock
->
1517 DcClients.next_download
true c sock cl
(* try to change downloading *)
1519 | None
-> c.client_state
<- DcIdle
(* DcPaused ? *))
1520 | Not_found
-> () ) (* Should not happen *)
1524 file_ops.op_file_files <- (fun file impl ->
1525 match file.file_swarmer with
1526 None -> [CommonFile.as_file impl]
1528 CommonSwarming.subfiles swarmer)
1531 file_ops.op_file_save_as <- (fun file new_name ->
1532 match file_state file with
1533 FileDownloaded | FileShared ->
1534 DcClients.save_file_as file new_name
1539 (*let client_of_user user =
1540 let c = new_client user.user_nick in
1546 mutable op_file_network : network; *)
1547 file_ops
.op_file_save_as
<- (fun _ _ -> ());
1548 file_ops
.op_file_resume
<- (fun _ -> ());
1549 file_ops
.op_file_set_format
<- (fun _ _ -> ());
1550 file_ops
.op_file_check
<- (fun _ -> ());
1551 file_ops
.op_file_recover
<- (fun _ -> ());
1552 file_ops
.op_file_print
<- (fun file o
->
1553 let buf = o
.conn_buf
in
1554 if use_html_mods o
then
1557 Printf.bprintf
buf "\\</tr\\>\\<tr class=\\\"dl-%d\\\"\\>" (html_mods_cntr
());
1561 ("Directory", "sr br", "Directory");
1562 ("", "sr", file
.file_directory
) ];
1564 ("Filename", "sr br", "Filename");
1565 ("", "sr", file
.file_name
) ];
1567 ("Tiger tree hash and magnet url", "sr", "TTH and magnet");
1568 ("", "sr", html_show_file file
) ];
1570 ("Automatic TTH searches performed", "sr", "Autosearches");
1571 ("", "sr", string_of_int file
.file_autosearch_count
) ];
1575 (*file_ops.op_file_print_html <- (fun _ _ -> lprintf_nl "Received (op_file_print_html)"; ());*)
1576 (*file_ops.op_file_print_sources_html <- (fun _ _ -> lprintf_nl "Received (op_file_print_sources_html)"; ())*)
1577 (* mutable op_file_files : ('a -> 'a file_impl -> file list);
1578 mutable op_file_debug : ('a -> string);
1579 mutable op_file_proposed_filenames : ('a -> string list);
1583 CommonWeb.add_web_kind
"hublist" "DirectConnect hublist"
1584 (fun url
filename ->
1585 if !!enable_directconnect
then
1589 match List.rev
(String2.split
filename '
.'
) with
1590 | "bz2"::"xml"::_ -> DcServers.make_hublist_from_xml
(Xml.parse_file
(Misc2.bz2_extract
filename))
1591 | "xml"::_ -> DcServers.make_hublist_from_xml
(Xml.parse_file
filename)
1592 | "bz2"::_ -> DcServers.make_hublist_from_file
(Misc2.bz2_extract
filename)
1593 | _ -> DcServers.make_hublist_from_file
filename);
1594 lprintf_nl "loaded dc++ hublist, %d entries" (List.length
!dc_hublist
)
1596 if !verbose_msg_servers
then
1597 lprintf_nl "(%s) in loading/parsing serverlist" (Printexc2.to_string e
);
1602 lprintf_nl "DirectConnect module is disabled, ignoring...";