-
Notifications
You must be signed in to change notification settings - Fork 239
Expand file tree
/
Copy pathfserve.pl
More file actions
3578 lines (3123 loc) · 107 KB
/
Copy pathfserve.pl
File metadata and controls
3578 lines (3123 loc) · 107 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#!/usr/bin/perl -w
#############################################################################
#
# FServe - file server for Irssi using DCC
#
# Copyright (C) 2001 Martin Persson
# Copyright (C) 2003 Andriy Gritsenko
# Copyright (C) 2002-2004 Piotr Krukowiecki
#
#
# If you have any comments, bug reports or anything else
# please contact me at piotr at pingu.ii.uj.edu.pl
#
# "Official" home page is at http://pingu.ii.uj.edu.pl/~piotr/irssi
#
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
#
# Changelog
# ====================================================================
#
# TODO:
# - when sending e.g. 3/2 files (e.g. because of min_upload), fserve
# ad should say it's 3/2 sends, not 2/2 as it is now
# - BUG: doesn't work if root_dir contains '+' ?
# - Improve distro: /fs distro clear, etc
# - possibility to, in case of failed send, not to resend file at once
# but to requeue it in slot X
# - More control in sends/queues (e.g. changing resends left, etc)
# - /fs show_current_sends_to_channel
# - restricted @find
# - user priorities: new priority_user option in queue_priority +
# /fs priouser nick
# - @find should search thorough dirs as well.
# - incorporate flood protection
# ? make sure all server tags and user nicks are first lc()'ed
# ? don't use send_user_msg, it's redundant
# ? don't use message levels, but set window number
# instead (might be better)
# - Add '/fs queue all' or '/fs queue *' etc.
#
# 2.0.0 (2004.05.09)
# * released rc4 without changes. Still a lot to do, but it's quite stable.
#
# 2.0.0rc4 (2004.01.27)
# * fixed "() queued (0 B)" queued files
#
# 2.0.0rc3 (2003.06.19)
# * fserve.pl works with old (before 0.8.6) irssi
# * bugfix: min_upload was not working
# * more documentation
#
# 2.0.0rc2 (2003.06.09)
# * fixed 'send speed < 0' bug
# * some queue-oriented fixes
# * fixed '/fs delt' to update remaining sends and queues
# * added '/fs queue *' to display all queues.
#
# 2.0.0rc1 (2003.06.01) Happy Child's Day :)
# * Changed format of config file, it won't work with old (1.2.4 and
# older file). If you're upgrading from 1.3.x and newer, just add
# "[ConfigFileVersion 1.0]" (without '"') at the beginning of the
# file.
# This should be the last user-visible change of config/queue files.
# * More documentation in /fs help
# * Reseting upload_counter after having sent file
# * renamed ignore_chat to ctcp_only
# * renamed short_notice to custom_notice, added custom_notice_fields
# * @find responses more Sysreset-like
#
# Important changes between 1.2.4 and 2.0.0rc1
# (for detailed version look at fserve-1.4.0pre6)
# Many thanks to Andriy Gritsenko for his work on the fserve.
# * multiple server support
# * multiple queue support (patch from A.G)
# * good documentation: '/fs help' (although it's still not complete)
# * changed format of queue file, saved sends and queues won't be back.
# * many bugfixes, small fixes, changes in server logic etc.
# * big patch from A.G, too much changes to list here.
#
#
# 1.2.4
# * bug workaround: removing ghost users (not tested... i don't have
# such problems...)
# * Removed window_close_on_quit - it was causing irssi to crash
# * Patch from Daniel Seifert (dseifert at gmx dot de):
# - added dont_notify option (to define channels where no notifies
# should be sent to)
# - english corrections
#
# 1.2.3
# * Added:
# - offline_message which is displayed when someone wants to access
# disabled fserve
# - fserve responds to !olist if (restricted_level > 0) and to
# !vlist if (restricted_level == 1)
# - fserve responds to "!list <my irc nick>"
# * bug (?) workaround: sometimes fserve thinks it's still sending
# the file when it's not. Now it's checking for such ghost sends
# and removes them from sends list
# * bugfix: can send files containing "'" now
#
# 1.2.2
# * works with irssi 0.8.6 now, but doesn't work with irssi 0.8.5 and
# former (incompatybile change in irssi 0.8.6 :( )
#
# 1.2.1
# * bugfix: @find didn't reported any files if there was only one match
#
# 1.2.0
# * IMPORTANT CHANGE: there is no longer 'ops_priority' setting. You must
# use 'queue_priority' instead (irssi will switch to it automatically
# when loading old config). queue_priority is a list of space separated
# priorities: "normal", "voice", "halfop", "op" and "others". Queue
# is sorted according to the order in which they appear in queue_priority.
# For example, if you set it to 'voice others normal' then first in queue
# will be voiced people, then people with priority not mentioned in
# queue_priority (in this case halfops and ops), then normal people.
# If 'others' doesn't exists in queue_priority it's assumed to be at
# the end
# * Added:
# - '/fs sortqueue' to sort queue according to queue_prority
# - count_send_as_queue setting. If set to 1 user sends take
# place in queue. For example, if it's set and user_slots == 1,
# user can have only one send, or only one queued file.
# - distro mode (/fs set distro, distro_file). When distro = 1
# fileserver counts how many times each file was sent, and first
# sends files with lowest send count.
# In fact, distro setting isn't simply 0/1. It's a PROBABILITY of
# using distro mode for the send. The values should be from range
# [0,1], where 0 means don't use distro mode at all, and 1 means
# allways use distro mode. For example when it's set to 0.7 it'll
# use distro mode in 7 cases of 10 (more or less).
# - '/fs distro stats' displays send count for files
# * bugfix:
# - send speed was wrongly calculated.
# - fserve could sometimes use wrong network
# - exit, bye shoult works now. Patch from Jan Rekorajski
# (baggins at sith.mimuw.edu.pl). Chat windows are closed unless
# close_window_on_quit is set to 0
# * in conffile, queuefile and log_name you can use $IRSSI as part of the
# path. It will be changed to Irssis home directory.
# * hopefully better support for fserve explorers etc (changed 'dir' output)
# * people who use different command char then '/' in /command shouldn't
# have problems now
# * some other fixes/changes
#
# 1.1.3
# * added:
# - +v/+%/+o only fserve. setting restricted_level to 3 means only ops
# can access, to 2 only ops and halfops, to 1 only ops, halfops and
# voiced users can access. if it's 0 everybody can access.
#
# 1.1.2
# * added:
# - !request support (/fs set request)
#
# 1.1.1
# * bugfix:
# - works with files containing more than one space in row
# (e.g. 'blah blah')
# * added:
# - /fs set autosave_on_close - when set to 1 sends and queues
# will be saved on /fs off
#
# 1.1.0
# * bugfix:
# - Enabling debug (/fs set debug 1) works now
# * New:
# - /fs set content - adds "On Fserve:(content)" to notice.
# - /fs set motdfile - gets MOTD from file
# - /fs set recache_interval - does /fs recache every recache_interval
# seconds
# - /ctcp ... NoResend
#
# 1.0.0
# -----
# * added:
# - sending small files without waiting in queues
# (/fs set instant_send). Patch from Jan Rekorajski
# (baggins at sith.mimuw.edu.pl)
# - @find support (/fs set find, /fs set find_results). Patch from
# Jan Rekorajski (baggins at sith.mimuw.edu.pl
# - queuefile and $conffile in $fs_prefs{}
# - /fs notify #channel1 #channel2 #etc
# - current upstream is displayed in server notice
# - resends ($max_resends) and better min_cps handling ($speedp). New
# log position (dcc_soft_fail) if resend is possibile
# - MOTD - '/fs set motd blah blah'
# * bugfixes
# - fserver should respond to all !list's (comparing # names not cases s.)
# - fixed '/fs insert file'
# - displays notice with correct colors even if Note: contains braces
# - queued position reported after queueing file by +o/+v with
# ops_priority on
# * moved most usefull variables to %fs_prefs (/fs set ...)
# * priority users are moved to the beginnign of the queue
# * 'Autosaving...' is not printed anymore unless in debug mode
# * Previously if ops_priority was on and nick was +o/+v the file was added
# even if there was no free queue slot. Now it's not added, unless
# ops_priority > 2.
# * if irc server disconnects, fserve will change to 'frozen' state and will
# wait for reconnection, then will wait next 150s to join channels etc.
# If send will fail in that time then it will be moved to queue.
# If you want to manually connect to new irc server, do /fs off, /fs on
#
# --
# Changes above by Cvbge (piotr at pingu.ii.uj.edu.pl)
# --
#
# 0.6.0
# -----
#
# * Merged patch from Ethan Fischer (allanon@crystaltokyo.com)
# - added ignore_chat option that, when turned on, ignores the
# trigger if said in the channel; it also changes the trigger
# advertisement to "/ctcp nick !trigger"
# - added ops_priority option that, when set to 1, force-adds
# requests from to the top of the download queue regardless of
# queue size; when set to 2, it does the same thing for voices
# - added log_name option to specify the name of a logfile which
# will be used to store transfer logs; the log contains the time
# a dcc transfer finishes, whether it finished or failed, filename,
# nick, bytes sent, start time, and end time
# - added a kludge to kill dcc chats after an "exit" in sig_timeout()
# - added a -clear option to the set command (eg, /fs set -clear
# log_name) which sets the variable to an empty string
#
# * Merged patch from Brian (btherl@optushome.com.au)
# - Avoid division by zero when dcc send takes 0 time to complete
# - new user command "read" - allows reading of small (<30k) files,
# such as checksum files
# - set line delimeter before load_config()
# - formatting of function headers
#
# thanks for the patches guys :)
#
# * the bytecounter now also counts the number of bytes sent
# for failed transfers as well as successful transfers
# (with respects to resumed files)
# * some bugfixes I don't remember ;)
#
#############################################################################
# Best viewed with TAB size = 4 !
use strict;
no strict 'refs';
use Irssi;
use Irssi::Irc;
use vars qw($VERSION %IRSSI);
$VERSION = "2.0.0";
my $conffile = '$IRSSI/fserve.conf';
%IRSSI = (
authors => 'Piotr Krukowiecki & others',
contact => 'piotr at pingu.ii.uj.edu.pl',
name => 'FServe',
description => 'File server for irssi',
license => 'GPL v2',
url => 'http://pingu.ii.uj.edu.pl/~piotr/irssi'
);
my @welcome_msg = (
"FServe $VERSION for Irssi",
"-",
"Commands: ls dir cd get read dequeue clr_queue queue sends",
" help who stats quit",
);
my @help_msg = (
"-=[ Available commands ]=-",
" ls / dir - list files in current directory",
" cd <dir> - changes current directory to <dir>",
" (note: <dir> is case sensitive!)",
" get <file> - inserts <file> into the queue",
" read <file> - displays contents of <file>",
" dequeue <nr> - removes file in slot <nr>",
" clr_queue[s] - removes your queued files",
" queue[s] - lists the queue",
" sends - lists active sends",
" who - lists users online",
" stats - shows some statistice",
" quit - closes the connection",
);
my @srv_help_msg = (
"command - [params] description\003\n",
"on - [0] enables fileserver",
"off - [0] disables fileserver",
"save - [0] save config file",
"load - [0] load config file",
"saveq - [0] saves sends/queues",
"loadq - [0] loads the queues",
"set - [0/2] sets variables",
"addq - [0] adds new queue",
"delq - [1] deletes queue",
"selq - [1] sets default queue for next 4 commands",
"setq - [0/2] sets queue variables",
"queue - [0-1] lists file queue",
"sortq - [0-1] sorts queue",
"move - [2-3] moves queue slots around",
"insert - [3] inserts a file in queue",
"clear - [1] removes queued files",
"sends - [0] lists active sends",
"who - [0] lists users online",
"stats - [0] shows server statistics",
"recache - [0] updates filecache\003\n",
"Usage: /fs <command> [<arguments>]",
"For parameter info type /fs <cmd>",
"Please read beginning of the fserve.pl (the changelog)",
"for more information",
);
###############################################################################
# fileserver preferences (/fs set <var> <data>)
# default values, feel free to change them
###############################################################################
my %fs_prefs = (
auto_save => 599,
autosave_on_close => 1,
clr_dir => "\00312",
clr_file => "\00315",
clr_hi => "\00312",
clr_txt => "\00315",
count_send_as_queue => 0,
debug => 0,
distro => 0,
distro_file => '$IRSSI/fserve.distro',
idle_time => 120,
ignores => "",
log_name => '$IRSSI/fserve.log', # FIXME should be renamed to logfile or similar
max_queues => 10,
max_sends => 2,
max_time => 600,
max_users => 5,
min_upload => 0,
motd => '',
motdfile => '',
offline_message => '', # is displayed when someone wants to enter disabled fserve
queuefile => '$IRSSI/fserve.queue',
recache_interval => 3607,
);
my %fs_queue_defaults = (
channels => '#CHANGE_ME',
content => '',
ctcp_only => 1,
custom_notice => 1,
custom_notice_fields=> "trigger sends queues min_cps note content",
dont_notify => "",
find => 3,
guaranted_queues => 0,
guaranted_sends => 0,
ignore_msg => 1,
ignores => "",
instant_send => 10240,
max_queues => 10,
max_resends => 3,
max_sends => 2,
min_cps => 9728,
motd => '',
nice => 0,
note => '',
notify_interval => 0,
notify_on_join => 0,
queue_priority => "",
request => "",
restricted_level => 0,
root_dir => '/path/to/files/CHANGE_ME',
servers => 'CHANGE_ME',
speed_warnings => 1,
trigger => '!trigger',
user_slots => 3,
);
###############################################################################
# fileserver statistics
###############################################################################
my %fs_stats = (
record_cps => 0,
rcps_nick => "",
sends_ok => 0, # sends succeeded
sends_fail => 0, # sends failed
transfd => 0, # total bytes transferred
login_count => 0, # total number of logins
);
my @fs_queues = ();
my @fs_sends = ();
my %fs_users = ();
my %fs_distro = ();
###############################################################################
# private variables
###############################################################################
my $fs_enabled = 0; # always start disabled
my $online_time = 0; # time since last script restart
my $timer_tag;
my $logfp;
my @kill_dcc;
my $upload_counter = 0;
my $last_upload = 0;
my $last_upload_check = 0;
my $motdfile_modified = 0; #when was motd file last modified
my @motd = ();
my $default_queue = 0;
my $next_queue = 0;
my $FD = "'"; # old irssi (<0.8.6) doesn't use "'" in /dcc send 'file'
###############################################################################
# setup signal handlers
###############################################################################
Irssi::signal_add_first('event privmsg', 'sig_event_privmsg');
Irssi::signal_add_first('event join', 'sig_event_join');
Irssi::signal_add_first('default ctcp msg', 'sig_ctcp_msg');
Irssi::signal_add_last('dcc chat message', 'sig_dcc_msg');
Irssi::signal_add_last('dcc connected', 'sig_dcc_connected');
Irssi::signal_add('dcc destroyed', 'sig_dcc_destroyed');
Irssi::signal_add('nicklist changed', 'sig_nicklist_changed');
Irssi::command_bind('fs', 'sig_fs_command');
print_msg("FServe version $VERSION");
print_log("FServe starting up");
$_ = $conffile;
s/\$IRSSI/Irssi::get_irssi_dir()/e or s/~/$ENV{"HOME"}/;
if (-e) {
load_config();
} else {
print_msg("If this is your first time using this fserve");
print_msg("I advise you to read help (/fs help)");
}
if (!@fs_queues) {
print_debug("Added inital trigger");
push (@fs_queues, { %fs_queue_defaults });
@{$fs_queues[$#fs_queues]->{queue}} = ();
}
{
my $ver = 'Very Old';
eval { $ver = Irssi::version(); };
if ($ver - 20021117 < 0) {
print_debug("Detected old irssi version: $ver") ;
$FD = "";
}
}
if ($fs_prefs{distro} and $fs_prefs{distro_file}) {
$_ = $fs_prefs{distro_file};
s/\$IRSSI/Irssi::get_irssi_dir()/e or s/~/$ENV{"HOME"}/;
if (-e) {
load_distro($_) and print_msg("Distro file loaded");
}
}
###############################################################################
# prints debug messages in the (fserve_dbg) window
###############################################################################
sub print_debug
{
if ($fs_prefs{debug}) {
Irssi::print("<DBG> @_", MSGLEVEL_CLIENTERROR);
}
}
###############################################################################
# prints server message in current window
###############################################################################
sub print_msg
{
Irssi::active_win()->print("$fs_prefs{clr_txt} @_");
}
sub print_what_we_did {
Irssi::print("@_", MSGLEVEL_CLIENTCRAP);
}
sub max($$) { return @_[0]>@_[1]?@_[0]:@_[1]; }
sub min($$) { return @_[0]<@_[1]?@_[0]:@_[1]; }
###############################################################################
###############################################################################
##
## Signal handler routines
##
###############################################################################
###############################################################################
sub get_max_sends($) {
my $qn = @_[0];
my $qu_msends = $fs_queues[$qn]->{max_sends};
my $gl_msends = $fs_prefs{max_sends};
my $guaranted_sends = $fs_queues[$qn]->{guaranted_sends};
my $current_sends = $fs_queues[$qn]->{sends};
my $free_sends =
max( $guaranted_sends - $current_sends,
min($gl_msends - @fs_sends, $qu_msends - $current_sends) );
$free_sends = 0 if ($free_sends < 0);
my $max_sends = max( $guaranted_sends, min($qu_msends,$gl_msends) );
return ($current_sends, $free_sends, $max_sends);
}
sub get_max_queues($) {
my $qn = @_[0];
my $qu_mqueues = $fs_queues[$qn]->{max_queues};
my $gl_mqueues = $fs_prefs{max_queues};
my $guaranted_queues = $fs_queues[$qn]->{guaranted_queues};
# TODO: keep this somewhere?
my $gl_current_queues = 0;
foreach (0 .. $#fs_queues) {
$gl_current_queues += @{$fs_queues[$_]->{queue}};
}
my $current_queues = @{$fs_queues[$qn]->{queue}};
my $free_queues =
max( $guaranted_queues - $current_queues,
min($gl_mqueues - $gl_current_queues,
$qu_mqueues - $current_queues) );
$free_queues = 0 if ($free_queues < 0);
my $max_queues = max( $guaranted_queues, min($qu_mqueues, $gl_mqueues) );
return ($current_queues, $free_queues, $max_queues);
}
###############################################################################
# updates some variables when DCC CHAT is established
###############################################################################
sub sig_dcc_connected
{
my ($dcc) = @_;
my $tag = $dcc->{servertag};
my $user_id = $dcc->{nick}."@".$tag;
print_debug("DCC connected: $dcc->{type} $user_id");
return if ($dcc->{type} ne "CHAT" || !defined $fs_users{$user_id});
print_debug("User $user_id connected!");
$fs_users{$user_id}{status} = 0;
$fs_users{$user_id}{time} = 0;
$fs_stats{login_count}++;
foreach (@welcome_msg) {
send_user_msg($tag, $dcc->{nick}, $_);
}
send_user_msg($tag, $dcc->{nick}, "-");
my $qn = $fs_users{$user_id}{queue};
my ($curr_queues, $free_queues, $max_queues) = get_max_queues($qn);
my ($curr_sends, $free_sends, $max_sends) = get_max_sends($qn);
send_user_msg($tag, $dcc->{nick}, "Current/Free/Max Sends: ".
"$curr_sends/$free_sends/$max_sends");
send_user_msg($tag, $dcc->{nick}, "Current/Free/Max Queues: ".
"$curr_queues/$free_queues/$max_queues");
send_user_msg($tag, $dcc->{nick}, "Your queue: ".
count_user_files($tag, $dcc->{nick}, $qn).
"/$fs_queues[$qn]->{user_slots}");
send_user_msg($tag, $dcc->{nick}, "Instant send: ".
size_to_str($fs_queues[$qn]{instant_send}))
if ($fs_queues[$qn]{instant_send} > 0);
if ($fs_prefs{motdfile}) {
send_user_msg($tag, $dcc->{nick}, "-");
my $f = $fs_prefs{motdfile};
$f =~ s/\$IRSSI/Irssi::get_irssi_dir()/e or $f =~ s/~/$ENV{"HOME"}/;
if (! ((-f $f) and (-r $f))) {
print_msg("FServe: '$f' doesn't exists, isn't plain file or is not readable");
} else {
my $lm = (stat($f))[9];
if ($motdfile_modified < $lm) {
$motdfile_modified = $lm;
@motd = ();
open(FILE, "<", $f);
while(<FILE>) {
chomp;
s/\t/ /g;
push @motd, $_;
}
close(FILE, $f);
}
foreach (@motd) {
send_user_msg($tag, $dcc->{nick}, $_);
}
}
}
if (length($fs_prefs{motd})) {
send_user_msg($tag, $dcc->{nick}, "-");
send_user_msg($tag, $dcc->{nick}, "$fs_prefs{motd}");
}
if (length($fs_queues[$qn]{motd})) {
send_user_msg($tag, $dcc->{nick}, "-");
send_user_msg($tag, $dcc->{nick}, "$fs_queues[$qn]{motd}");
}
send_user_msg($tag, $dcc->{nick}, "-");
send_user_msg($tag, $dcc->{nick}, '[\]');
}
###############################################################################
# cleanups after DCC CHAT/SEND disconnects
###############################################################################
sub sig_dcc_destroyed
{
my ($dcc) = @_;
my $nick = $dcc->{nick};
my $server = $dcc->{server};
my $server_tag = $dcc->{servertag};
my $user_id = $nick.'@'.$server_tag;
print_debug("DCC destroyed: $dcc->{type} $user_id '$dcc->{arg}'");
if ($dcc->{type} eq "CHAT" && defined $fs_users{$user_id}) {
delete $fs_users{$user_id};
print_debug("Users left: ".keys %fs_users);
} elsif ($dcc->{type} eq "SEND") {
foreach my $sn (0 .. $#fs_sends) {
print_debug("check slot $sn: ".
"user=$fs_sends[$sn]->{nick}\@$fs_sends[$sn]->{server_tag}, ".
"file=$fs_sends[$sn]->{file}.");
if ($fs_sends[$sn]->{nick} eq $nick &&
$fs_sends[$sn]->{server_tag} eq $server_tag &&
$fs_sends[$sn]->{file} eq $dcc->{arg}) {
print_debug("found send in slot $sn");
if ($dcc->{transfd} == $fs_sends[$sn]->{size}) {
print_log("dcc_finish $dcc->{arg} $user_id ".
"$dcc->{skipped} $dcc->{transfd} ".
"$dcc->{starttime} ".time());
print_debug("file was finished");
$fs_stats{sends_ok}++;
if ($fs_prefs{distro}) {
$fs_distro{$dcc->{arg}}{$dcc->{transfd}}++;
save_distro();
}
## Update speed record (if new)
if (time() > $dcc->{starttime}) {
my $speed = ($dcc->{transfd}-$dcc->{skipped})/
(time() - $dcc->{starttime});
if ($speed > $fs_stats{record_cps}) {
$fs_stats{record_cps} = $speed;
$fs_stats{rcps_nick} = $nick;
}
}
} else {
if ($fs_sends[$sn]->{transfd} == -1) {
# send was too slow
print_log("dcc_abort $dcc->{arg} $user_id ".
"$dcc->{skipped} $dcc->{transfd} ".
"$dcc->{starttime} ".time());
} else {
$fs_sends[$sn]->{resends} += 1;
$fs_sends[$sn]->{warns} = 0;
$fs_sends[$sn]->{dontwarn} = 0;
delete $fs_sends[$sn]->{transfd};
if ($fs_sends[$sn]->{resends} <=
$fs_queues[$fs_sends[$sn]{queue}]{max_resends}) {
# queue it for resending
# don't resend right now, you may be treated as flood
my $fsq = $fs_queues[$fs_sends[$sn]->{queue}]->{queue};
# TODO should be parametrized (in which slot requeue)
my $resended_queue = 0;
foreach (0 .. $#{$fsq}) {
last if (!${$fsq}[$_]->{resends});
$resended_queue++;
}
$resended_queue = 1
if (!$resended_queue && @{$fsq}>0);
print_debug("requeued $dcc->{arg} for ".
"$user_id in slot $resended_queue, ".
"resend $fs_sends[$sn]->{resends}");
splice(@{$fsq}, $resended_queue, 0, { %{$fs_sends[$sn]} });
$server->command("^NOTICE ".
"$fs_sends[$sn]->{nick} ".
"$fs_prefs{clr_txt} Send failed on try ".
$fs_sends[$sn]->{resends}." of ".
($fs_queues[$fs_sends[$sn]{queue}]{max_resends}+1).
". Type /ctcp ".
"$$server{nick} NoReSend to cancel "
."any further resends.")
if ($server && $server->{connected});
print_what_we_did("NOTICE ".
"$fs_sends[$sn]->{nick} ".
"$fs_prefs{clr_txt} Send failed on try ".
$fs_sends[$sn]->{resends}." of ".
($fs_queues[$fs_sends[$sn]{queue}]{max_resends}+1).
". Type /ctcp ".
"$$server{nick} NoReSend to cancel "
."any further resends.")
if ($server && $server->{connected});
print_log("dcc_soft_fail $dcc->{arg} $user_id ".
"$dcc->{skipped} $dcc->{transfd} ".
"$dcc->{starttime} ".time());
} else {
print_log("dcc_fail $dcc->{arg} $user_id ".
"$dcc->{skipped} $dcc->{transfd} ".
"$dcc->{starttime} ".time());
}
}
$fs_stats{sends_fail}++;
}
## Update bytes transferred
$fs_stats{transfd} += ($dcc->{transfd} - $dcc->{skipped});
splice(@fs_sends, $sn, 1); # FIXME : decrease number of sends?
print_debug("SEND closed to $user_id, file: ".
"$dcc->{arg}, bytes sent: ".
($dcc->{transfd}-$dcc->{skipped}).
" (sent from slot $sn, ".@fs_sends." slots now)");
return;
}
}
}
}
###############################################################################
# handles dcc chat messages
###############################################################################
sub sig_dcc_msg
{
my $dcc = shift (@_);
my $msg = @_[0];
my $user_id = $dcc->{nick}.'@'.$dcc->{servertag};
# ignore messages from unconnected dcc chats
return unless ($fs_enabled && defined $fs_users{$user_id});
# reset idle time for user
$fs_users{$user_id}{status} = 0;
my ($cmd, $args) = split(' ', $msg, 2);
$cmd = lc($cmd);
if ($cmd eq "dir" || $cmd eq "ls") {
list_dir($user_id, "$args");
} elsif ($cmd eq "cd") {
change_dir($user_id, "$args");
} elsif ($cmd eq "cd..") { # darn windows users ;)
change_dir($user_id, '..');
} elsif ($cmd eq "get") {
queue_file($user_id, "$args");
} elsif ($cmd eq "dequeue") {
$args =~ s/^\D*(\d+)\D*$/$1/; # stupid leechers, we have to remove garbage
dequeue_file($user_id, $args);
} elsif ($cmd eq "clr_queue" || $cmd eq "clr_queues") {
clear_queue($user_id, 0, $fs_users{$user_id}{queue});
} elsif ($cmd eq "queue" || $cmd eq "queues") {
display_queue($user_id, $fs_users{$user_id}{queue});
} elsif ($cmd eq "sends") {
display_sends($user_id);
} elsif ($cmd eq "who") {
display_who($user_id);
} elsif ($cmd eq "stats") {
display_stats($user_id);
} elsif ($cmd eq "read") {
display_file($user_id, "$args");
} elsif ($cmd eq "help") {
foreach (@help_msg) {
send_user_msg($dcc->{servertag}, $dcc->{nick}, $_);
}
} elsif ($cmd eq "exit" || $cmd eq "quit" || $cmd eq "bye") {
push(@kill_dcc, $user_id);
}
}
###############################################################################
# server, nick, queue_number
###############################################################################
sub try_connecting_user ($$$)
{
my ($server, $sender, $qn) = @_;
my $tag = $server->{tag};
if (defined($fs_users{$sender."@".$tag})) {
if (!$fs_users{$sender."@".$tag}{ignore} &&
$fs_queues[$qn]->{ignore_msg}) {
$server->command("^NOTICE $sender $fs_prefs{clr_txt}".
"A DCC chat offer has already been sent to you!");
print_what_we_did("NOTICE $sender $fs_prefs{clr_txt}".
"A DCC chat offer has already been sent to you!");
}
$fs_users{$sender."@".$tag}{ignore} = 1;
return 1;
}
if (keys(%fs_users) < $fs_prefs{max_users}) {
if (!$fs_queues[$qn]->{restricted_level}) {
initiate_dcc_chat($server, $sender, $qn);
return 1;
} else {
foreach (split (' ', $fs_queues[$qn]->{channels})) {
my $ch = $server->channel_find($_);
next if !$ch;
my $n = $ch->nick_find($sender);
next if !$n;
if (($n->{op}) or
(($fs_queues[$qn]->{restricted_level} < 3) && $n->{halfop}) or
(($fs_queues[$qn]->{restricted_level} < 2) && $n->{voice})) {
initiate_dcc_chat($server, $sender, $qn);
return 1;
}
}
$server->command("^NOTICE $sender $fs_prefs{clr_txt}I'm sorry,"
." but this trigger is restricted. You need to be an".
(($fs_queues[$qn]->{restricted_level} == 3) ? " op" :
(($fs_queues[$qn]->{restricted_level} == 2) ? " op or halfop" :
" op, halfop or voiced")) . " to access this trigger");
print_what_we_did("NOTICE $sender $fs_prefs{clr_txt}I'm sorry,"
." but this trigger is restricted. You need to be an".
(($fs_queues[$qn]->{restricted_level} == 3) ? " op" :
(($fs_queues[$qn]->{restricted_level} == 2) ? " op or halfop" :
" op, halfop or voiced")) . " to access this trigger");
}
} else {
$server->command("^NOTICE $sender $fs_prefs{clr_txt}".
"Sorry, server is full (".
$fs_prefs{clr_hi}.$fs_prefs{max_users}.
$fs_prefs{clr_txt}.")!");
print_what_we_did("NOTICE $sender $fs_prefs{clr_txt}".
"Sorry, server is full (".
$fs_prefs{clr_hi}.$fs_prefs{max_users}.
$fs_prefs{clr_txt}.")!");
}
return 0;
}
###############################################################################
# handles ctcp messages
###############################################################################
sub sig_ctcp_msg
{
my ($server, $args, $sender, $addr, $target) = @_;
$args = uc($args);
$args =~ s/\s*$//; # strip ending spaces
my $tag = $server->{tag};
return if ($fs_prefs{ignores} &&
$server->masks_match($fs_prefs{ignores}, $sender, $addr));
if (!$fs_enabled) {
# find queue where the trigger is
foreach (0 .. $#fs_queues) {
next if ($args ne uc($fs_queues[$_]->{trigger}));
next if ($fs_queues[$_]{ignores} &&
$server->masks_match($fs_queues[$_]{ignores}, $sender, $addr));
foreach my $s (split(' ', $fs_queues[$_]->{servers})) {
if (uc($s) eq uc($tag) &&
user_in_channel($server, $sender, $fs_queues[$_])) {
$server->command("^NOTICE $sender $fs_prefs{clr_txt}".
"Sorry, fserve is currently offline. $fs_prefs{offline_message}");
print_what_we_did("NOTICE $sender $fs_prefs{clr_txt}".
"Sorry, fserve is currently offline. $fs_prefs{offline_message}");
Irssi::signal_stop();
return;
}
} # loop over servers
} # loop over queues
Irssi::signal_stop();
return;
}
print_debug("CTCP from $sender: '$args'");
if ($args eq "NORESEND") {
my $found = 0;
foreach (0 .. $#fs_sends) {
if ($fs_sends[$_]{nick} eq $sender &&
$fs_sends[$_]{server} eq $tag) {
print_debug("$sender: Canceling resends of $fs_sends[$_]->{file}");
$fs_sends[$_]->{resends} = $fs_queues[$fs_sends[$_]{queue}]{max_resends};
$found++;
}
}
my $message = ($found?
"Resend: All resends ($found) for currently sending ".
"files have been canceled." :
"Resend: You currently have no sending files set ".
"to resend.");
$server->command("^MSG $sender $message");
print_what_we_did("MSG $sender $message");
Irssi::signal_stop();
return;
} # end NORESEND
foreach my $qn (0 .. $#fs_queues) {
next if ($args ne uc($fs_queues[$qn]->{trigger}));
print_debug("Got trigger in queue $qn");
next if ($fs_queues[$qn]{ignores} &&
$server->masks_match($fs_queues[$qn]{ignores}, $sender, $addr));
print_debug("Not ignoring user");
print_debug("Servers are $fs_queues[$qn]->{servers}");
foreach my $s (split(' ', $fs_queues[$qn]->{servers})) {
print_debug("Checking server $s against $tag");
next if (uc($tag) ne uc($s) ||
!user_in_channel($server, $sender, $fs_queues[$qn]));
print_debug("Good tag and user in chan");
if (try_connecting_user($server, $sender, $qn)) {
Irssi::signal_stop();
return;
}
}
}
Irssi::signal_stop();
return;
}
###############################################################################
# notifies joining users
###############################################################################
sub sig_event_join
{
my ($server, $data, $sender, $addr) = @_;
my ($target) = ($data =~ /:(.*)/);
return if (!$fs_enabled);
foreach my $qn (0 .. $#fs_queues) {
next if (!$fs_queues[$qn]->{notify_on_join});
next if ($fs_queues[$qn]{ignores} &&
$server->masks_match($fs_queues[$qn]{ignores}, $sender, $addr));
foreach my $s (split(' ', $fs_queues[$qn]->{servers})) {
next if (uc($s) ne uc($server->{tag}));
foreach my $channel (split(' ', $fs_queues[$qn]->{channels})) {
next if (uc($channel) ne uc($target));
show_notice($server, $sender, $qn);
} # loop over channels
} # loop over servers
} # loop over queues
}
###############################################################################
# handles channel and private messages
###############################################################################
sub sig_event_privmsg
{
my ($server, $data, $sender, $addr) = @_;
my ($target, $text) = split(/ :/, $data, 2);
return if (!$fs_enabled);
return if ($fs_prefs{ignores} &&
$server->masks_match($fs_prefs{ignores}, $sender, $addr));
foreach my $qn (0 .. $#fs_queues) {
next if ($fs_queues[$qn]{ignores} &&
$server->masks_match($fs_queues[$qn]{ignores}, $sender, $addr));
foreach my $s (split(' ', $fs_queues[$qn]->{servers})) {
next if (uc($s) ne uc($server->{tag}));
foreach my $channel (split(' ', $fs_queues[$qn]->{channels})) {
next if (uc($channel) ne uc($target));
# trigger typed
if (!$fs_queues[$qn]->{ctcp_only} &&
uc($text) eq uc($fs_queues[$qn]->{trigger})) {
try_connecting_user($server, $sender, $qn);
return;
}
# strip extra spaces
$_ = uc($text);
s/\s+$//; s/^\s+$//; s/\s+/ /g;
if (($_ eq '!LIST') || ($_ eq ('!LIST '.uc($$server{nick}))) ||
($_ eq '!OLIST' and $fs_queues[$qn]->{restricted_level}) ||
($_ eq '!VLIST' and $fs_queues[$qn]->{restricted_level} == 1)
) {
show_notice($server, $sender, $qn);
}