1###############################################################################
2# Checkspace.pm                                                               #
3# $Date: 12.02.14 $                                                           #
4###############################################################################
5# YaBB: Yet another Bulletin Board                                            #
6# Open-Source Community Software for Webmasters                               #
7# Version:        YaBB 2.6.11                                                 #
8# Packaged:       December 2, 2014                                            #
9# Distributed by: http://www.yabbforum.com                                    #
10# =========================================================================== #
11# Copyright (c) 2000-2014 YaBB (www.yabbforum.com) - All Rights Reserved.     #
12# Software by:  The YaBB Development Team                                     #
13#               with assistance from the YaBB community.                      #
14###############################################################################
15use CGI::Carp qw(fatalsToBrowser);
16use English '-no_match_vars';
17our $VERSION = '2.6.11';
18
19$checkspacepmver = 'YaBB 2.6.11 $Revision: 1611 $';
20if ( $action eq 'detailedversion' ) { return 1; }
21
22sub checkspace {
23    is_admin_or_gmod();
24
25    # Free Disk Space Checking
26    if ( $OSNAME =~ /Win/sm ) {
27        open my $fh, q{-|}, 'DIR /-C' or croak "Can't open pipe: $!";
28        my @x = <$fh>;
29        close $fh or croak "Can't close pipe: $!";
30        my $lastline = pop @x;
31
32        # should look like: 17 Directory(s), 21305790464 Bytes free
33        return -1
34          if $lastline !~ m/byte/ism;
35
36        # error trapping if output fails. The word byte should be in the line
37        if ( $lastline =~ /^\s+(\d+)\s+(.+?)\s+(\d+)\s+(.+?)\n$/xsm ) {
38            $FreeBytes = $3 - 100_000;
39        }    # 100000 bytes reserve
40        if ( $FreeBytes >= 1_073_741_824 ) {
41            $yyfreespace =
42              sprintf( '%.2f', $FreeBytes / ( 1024 * 1024 * 1024 ) ) . ' GB';
43        }
44        elsif ( $FreeBytes >= 1_048_576 ) {
45            $yyfreespace =
46              sprintf( '%.2f', $FreeBytes / ( 1024 * 1024 ) ) . ' MB';
47        }
48        else {
49            $yyfreespace = sprintf( '%.2f', $FreeBytes / 1024 ) . ' KB';
50        }
51        @disk_space = $yyfreespace;
52    }
53    else {
54        open my $dsh, q{-|}, 'df -k .' or croak "Can't open pipe: $!";
55        @disk_space = <$dsh>;
56        close $dsh or croak "Can't close pipe: $!";
57
58        map { $_ =~ s/ +/  /gsm } @disk_space;
59
60        open my $ffh, q{-|}, 'find . -noleaf -type f -printf "%s-"'
61          or croak "Can't open pipe: $!";
62        my @find = <$ffh>;
63        close $ffh or croak "Can't close pipe: $!";
64    }
65    $hostusername = $hostusername
66      || ( split / +/sm, qx{ls -l YaBB.$yyext} )[2];
67    my @quota = qx{quota -u $hostusername -v};
68    $quota[0] =~ s/^ +//sm;
69    $quota[0] =~ s/ /&nbsp;/gsm;
70    $quota[1] =~ s/^ +//sm;
71    $quota[1] =~ s/ /&nbsp;/gsm;
72    my $quota_select = qq~$quota[0]<br />$quota[1]~;
73
74    if ( $quota[2] ) {
75        if ( !$enable_quota ) { $ds = ( split / +/sm, $disk_space[1], 2 )[0]; }
76        $my_q_select =
77          isselected( $i == $enable_quota
78              || ( $ds && $quota[$i] =~ /^$ds/sm ) );
79        $quota_select .= q~<br /><select name="enable_quota_value" id="enable_quota_value">~;
80        for my $i ( 2 .. ( @quota - 1 ) ) {
81            $quota[$i] =~ s/^ +//sm;
82            $quota[$i] =~ s/ +/&nbsp;&nbsp;/gsm;
83            $quota_select .=
84              qq~<option value="$i" ~ . $my_q_select . qq~>$quota[$i]</option>~;
85        }
86        $quota_select .= '</select>';
87    }
88
89    #    }
90
91    $ch_spc      = ischecked($enable_freespace_check);
92    $ch_enable_q = ischecked($enable_quota);
93
94    @settings = (
95        {
96            name  => $settings_txt{'checkspace'},
97            id    => 'checkspace',
98            items => [
99                { header => $settings_txt{'freedisk'}, },
100                {
101                    description =>
102                      qq~<label for="enable_quota">$admin_txt{'quota'}</label>~,
103                    input_html =>
104q~<input type="checkbox" name="enable_quota" id="enable_quota" value="1" ~
105                      . (
106                         !$quota[2] ? 'disabled="disabled" '
107                        : $ch_enable_q
108                      )
109                      . q~/>~,
110                    name       => 'enable_quota',
111                    validate   => 'boolean',
112                    depends_on => (
113                        !$quota[2] ? []
114                        : [
115                            '!enable_freespace_check',
116                            '(findfile_time==0||',
117                            'findfile_time==||',
118                            'findfile_maxsize==0||',
119                            'findfile_maxsize==)'
120                        ]
121                    ),
122                },
123                {
124                    description =>
125qq~<label for="enable_quota_value">$admin_txt{'quota_value'}</label>~,
126                    input_html => (
127                        $quota[2] ? $quota_select
128                        : q~<input type="text" disabled="disabled" name="enable_quota_value" id="enable_quota_value" value="" style="display:none" />~
129                    ),
130                    name       => 'enable_quota_value',
131                    validate   => 'number,null',
132                    depends_on => ['enable_quota'],
133                },
134                {
135                    description =>
136qq~<label for="hostusername">$admin_txt{'quotahostuser'}</label>~,
137                    input_html =>
138qq~<input type="text" name="hostusername" id="hostusername" size="20" value="$hostusername" />~,
139                    name       => 'hostusername',
140                    validate   => 'text,null',
141                    depends_on => ['enable_quota'],
142                },
143                {
144                    description =>
145qq~<label for="findfile_time">$admin_txt{'findtime'}</label>~,
146                    input_html =>
147q~<input type="text" name="findfile_time" id="findfile_time" size="4" value="~
148                      . (
149                        @find ? qq~$findfile_time"~ : '0" disabled="disabled"'
150                      )
151                      . qq~ /> $admin_txt{'537'}~,
152                    name       => 'findfile_time',
153                    validate   => 'number,null',
154                    depends_on => (
155                        @find ? [ '!enable_quota', '!enable_freespace_check' ]
156                        : []
157                    ),
158                },
159                {
160                    description =>
161qq~<label for="findfile_root">$admin_txt{'findroot'}</label>~,
162                    input_html =>
163qq~<input type="text" name="findfile_root" id="findfile_root" size="40" value="$findfile_root" ~
164                      . ( @find ? q{} : 'disabled="disabled" ' ) . q~/>~,
165                    name       => 'findfile_root',
166                    validate   => 'text,null',
167                    depends_on => (
168                        @find ? [ '!enable_quota', '!enable_freespace_check' ]
169                        : []
170                    ),
171                },
172                {
173                    description =>
174qq~<label for="findfile_maxsize">$admin_txt{'findmax'}</label>~,
175                    input_html =>
176qq~<input type="text" name="findfile_maxsize" id="findfile_maxsize" size="10" value="$findfile_maxsize" ~
177                      . ( @find ? q{} : 'disabled="disabled" ' )
178                      . q~/> MB~,
179                    name       => 'findfile_maxsize',
180                    validate   => 'number,null',
181                    depends_on => (
182                        @find ? [ '!enable_quota', '!enable_freespace_check' ]
183                        : []
184                    ),
185                },
186                {
187                    description =>
188qq~<label for="enable_freespace_check">$admin_txt{'diskspacecheck'}</label>~,
189                    input_html =>
190qq~<input type="checkbox" name="enable_freespace_check" id="enable_freespace_check" value="1" $ch_spc /><pre>@disk_space</pre>~,
191                    name       => 'enable_freespace_check',
192                    validate   => 'boolean',
193                    depends_on => [
194                        '!enable_quota',     '(findfile_time==0||',
195                        'findfile_time==||', 'findfile_maxsize==0||',
196                        'findfile_maxsize==)'
197                    ],
198                },
199            ],
200        },
201    );
202    chsettings();
203    $action_area = 'checkspace';
204    AdminTemplate();
205    exit;
206}
207
208sub chsettings {
209    is_admin_or_gmod();
210
211    $yytitle = $admin_txt{'checkspclabel'};
212    $page    = 'checkspace';
213
214    my @requireorder;    # an array for the correct order of the requirements
215    my %requirements;    # a hash that says "Y is required by X"
216
217    $yymain .= qq~
218    <div class="bordercolor rightboxdiv">
219        <table class="border-space pad-cell" style="margin-bottom:.5em">
220            <tr>
221                <td class="titlebg"><b>$yytitle</b></td>
222            </tr><tr>
223                <td class="windowbg2"><div class="pad-more">$admin_txt{'347'}</div></td>
224            </tr>
225        </table>
226  </div>
227  <form action="$adminurl?action=checkspace_save" method="post" onsubmit="savealert()" accept-charset="$yymycharset">
228~;
229    foreach my $tab (@settings) {
230        $yymain .= qq~
231    <div class="bordercolor rightboxdiv">
232        <table class="section border-space pad-cell" style="margin-bottom:.5em" id="tab_$tab->{'id'}">
233            <colgroup>
234                <col span="2" style="width:50%" />
235            </colgroup>
236            <tr>
237                <td class="titlebg" colspan="2">
238                    $admin_img{'prefimg'} <b>$tab->{'name'}</b>
239                </td>
240           </tr>~;
241
242        foreach my $item ( @{ $tab->{'items'} } ) {
243            if ( $item->{'header'} ) {
244                $yymain .= qq~<tr>
245                <td class="catbg" colspan="2">
246                    <span class="small">$item->{'header'}</span>
247                </td>
248            </tr>~;
249            }
250            elsif ( $item->{'two_rows'} && $item->{'input_html'} ) {
251                $yymain .= qq~<tr>
252                <td class="windowbg2" colspan="2">
253         $item->{'description'}
254       </td>
255            </tr><tr>
256                <td class="windowbg2" colspan="2">
257         $item->{'input_html'}
258       </td>
259     </tr>~;
260            }
261            elsif ( $item->{'input_html'} ) {
262                $yymain .= qq~<tr>
263                <td class="windowbg2 vtop">
264         $item->{'description'}
265       </td>
266                <td class="windowbg2 vtop">
267         $item->{'input_html'}
268       </td>
269     </tr>~;
270            }
271
272            # Handle settings that require other settings
273            if ( $item->{'depends_on'} && $item->{'name'} ) {
274                foreach my $require ( @{ $item->{'depends_on'} } ) {
275
276# This is somewhat messy, but it works well.
277# We strip off the possible options: inverse, equal, and not equal
278# Then we attach those to this current option in the detailed string for requirements
279# While this data does not really belong with the value, it transfers nicely.
280# We then remove it and reuse it later.
281                    my ( $inverse, $realname, $remainder ) =
282                      $require =~ m{(\(?\!?)(\w+)(.*)}xsm;
283                    if ( !$requirements{$realname} ) {
284                        push @requireorder, $realname;
285                    }
286                    push
287                      @{ $requirements{$realname} },
288                      $inverse . $item->{'name'} . $remainder;
289                }
290            }
291        }
292
293        $yymain .= q~
294   </table>
295  </div>~;
296    }
297
298    my %requirejs;
299
300    my $dependicies = q{};
301    my $onloadevents;
302    foreach my $ritem (@requireorder) {
303        $dependicies .= qq~
304    function handleDependent_$ritem() {
305        var isChecked = document.getElementsByName("$ritem")[0].checked;
306        var itemValue = document.getElementsByName("$ritem")[0].value;\n~;
307
308        foreach my $require ( @{ $requirements{$ritem} } ) {
309
310            # && or ||, ( and )
311            my $AndOr = $require =~ s/\)//xsm ? ')' : q{};
312            $AndOr .= $require =~ s/\|\|//xsm ? ' ||' : ' &&';
313            my $C = $require =~ s/\(//xsm ? '(' : q{};
314
315            # Is false
316            if ( $require =~ s/^\!//xsm ) {
317                $requirejs{$require} .=
318qq~$C\!document.getElementsByName("$ritem")[0].checked$AndOr ~;
319            }
320
321            # Is equal to
322            elsif ( $require =~ s/\=\=(.*)$//xsm ) {
323                $requirejs{$require} .=
324qq~$C\document.getElementsByName("$ritem")[0].value == '$1'$AndOr ~;
325            }
326
327            # Is not equal to
328            elsif ( $require =~ s/\!\=(.*)$//xsm ) {
329                $requirejs{$require} .=
330qq~$C\document.getElementsByName("$ritem")[0].value != '$1'$AndOr ~;
331            }
332
333            # Is true
334            else {
335                $requirejs{$require} .=
336                  qq~$C\document.getElementsByName("$ritem")[0].checked$AndOr ~;
337            }
338            $dependicies .= qq~     checkDependent("$require");\n~;
339        }
340        $dependicies .= qq~ }
341    document.getElementsByName("$ritem")[0].onclick = handleDependent_$ritem;
342    document.getElementsByName("$ritem")[0].onkeyup = handleDependent_$ritem;
343~;
344        $onloadevents .= qq~handleDependent_$ritem(); ~;
345    }
346
347    # Hidden "feature": jump directly to a tab by default via the URL bar.
348    $INFO{'tab'} =~ s/\W//gxsm;
349    $default_tab = $INFO{'tab'} || $settings[0]->{'id'};
350    $yymain .= qq~
351<div class="bordercolor rightboxdiv">
352    <table class="border-space pad-cell">
353        <tr>
354            <td class="titlebg" colspan="2">
355                $admin_img{'prefimg'} <b>$admin_txt{'10'}</b>
356       </td>
357        </tr><tr>
358            <td class="catbg center pad-cell" colspan="2">
359         <input class="button" type="submit" value="$admin_txt{'10'}" />
360       </td>
361     </tr>
362   </table>
363  </div>
364  </form>
365  <script type="text/javascript">
366    function checkDependent(eid) {
367        var elm = document.getElementsByName(eid)[0];\n~;
368
369    # Loop through each item that depends on something else
370    foreach my $name ( keys %requirejs ) {
371        my $logic = $requirejs{$name};
372        $logic =~ s/ (&&|\|\|) $//sm;
373        $yymain .= qq~
374        if (eid == "$name" && ($logic)) {
375            elm.disabled = false;
376        } else if (eid == "$name") {
377            elm.disabled = true;
378        }\n~;
379    }
380
381    $yymain .= qq~
382    }
383$dependicies
384    window.onload = function(){ $onloadevents};
385    function undisableAll(node) {
386        var elements = document.getElementsByTagName("input");
387        for(var i = 0; i < elements.length; i++) {
388            elements[i].disabled = false;
389        }
390        elements = document.getElementsByTagName("textarea");
391        for( i = 0; i < elements.length; i++) {
392            elements[i].disabled = false;
393        }
394        elements = document.getElementsByTagName("select");
395        for( i = 0; i < elements.length; i++) {
396            elements[i].disabled = false;
397        }
398    }
399  </script>~;
400
401    return;
402}
403
404sub ischecked {
405    my ($inp) = @_;
406
407    # Return a ref so we can be used like ${ischecked($var)} inside a string
408    if ( $inp == 1 ) { return 'checked="checked"'; }
409    return;
410}
411
412sub isselected {
413    my ($inp) = @_;
414
415    # Return a ref so we can be used like ${ischecked($var)} inside a string
416    if ( $inp == 1 ) { return 'selected="selected"'; }
417    return;
418}
419
420sub checkspace_save {
421    is_admin_or_gmod();
422
423    $enable_quota           = $FORM{'enable_quota'}           || '0';
424    $enable_quota_value     = $FORM{'enable_quota_value'}     || '0';
425    $hostusername           = $FORM{'hostusername'}           || q{};
426    $findfile_time          = $FORM{'findfile_time'}          || 0;
427    $findfile_root          = $FORM{'findfile_root'}          || q{};
428    $findfile_maxsize       = $FORM{'findfile_maxsize'}       || 0;
429    $findfile_space         = $FORM{'findfile_space'}         || '1<>0';
430    $enable_freespace_check = $FORM{'enable_freespace_check'} || 0;
431
432    if ( $enable_quota && $enable_quota_value > 1 && $hostusername ) {
433        $enable_quota           = $enable_quota_value;
434        $findfile_maxsize       = 0;
435        $enable_freespace_check = 0;
436    }
437    elsif (-d "$findfile_root"
438        && $findfile_maxsize > 0
439        && !$enable_freespace_check )
440    {
441        $findfile_space = '1<>0';
442        $enable_quota   = 0;
443    }
444    elsif ($enable_freespace_check) {
445        $findfile_maxsize = 0;
446        $enable_quota     = 0;
447    }
448    elsif ( !-d "$findfile_root" || !$findfile_maxsize ) {
449        $findfile_time    = 0;
450        $findfile_maxsize = 0;
451    }
452
453    require Admin::NewSettings;
454    SaveSettingsTo('Settings.pm');
455
456    if ( $action eq 'checkspace_save' ) {
457        $yySetLocation = qq~$adminurl?action=newsettings;page=advanced~;
458        redirectexit();
459    }
460    return;
461}
462
4631;
464