1###############################################################################
2# MoveSplitSplice.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);
16our $VERSION = '2.6.11';
17
18$movesplitsplicepmver = 'YaBB 2.6.11 $Revision: 1611 $';
19if ( $action eq 'detailedversion' ) { return 1; }
20
21LoadLanguage('MoveSplitSplice');
22
23get_template('Display');
24
25sub Split_Splice {
26    if ( !$staff ) { fatal_error('split_splice_not_allowed'); }
27    if ( $FORM{'ss_submit'} || $INFO{'ss_submit'} ) { Split_Splice_2(); }
28
29    my $curboard  = $INFO{'board'};
30    my $curthread = $INFO{'thread'};
31    if ( !exists $FORM{'oldposts'} ) { $FORM{'oldposts'} = $INFO{'oldposts'}; }
32    if ( !exists $FORM{'leave'} )    { $FORM{'leave'}    = $INFO{'leave'}; }
33    if ( exists $INFO{'newinfo'} )   { $FORM{'newinfo'}  = $INFO{'newinfo'}; }
34    my $newcat   = $FORM{'newcat'}   || $INFO{'newcat'};
35    my $newboard = $FORM{'newboard'} || $INFO{'newboard'};
36    if ( !exists $FORM{'newthread'} ) {
37        $FORM{'newthread'} = $INFO{'newthread'};
38    }
39    my $newthread = $FORM{'newthread'} || 'new';
40    if ( !exists $FORM{'newthread_subject'} ) {
41        $FORM{'newthread_subject'} = $INFO{'newthread_subject'};
42    }
43    if ( !exists $FORM{'position'} ) { $FORM{'position'} = $INFO{'position'}; }
44
45    require Sources::YaBBC;
46    LoadCensorList();
47
48    # Get posts of current thread
49    if ( !ref $thread_arrayref{$curthread} ) {
50        fopen( FILE, "$datadir/$curthread.txt" );
51        @{ $thread_arrayref{$curthread} } = <FILE>;
52        fclose(FILE);
53    }
54    my @messages = @{ $thread_arrayref{$curthread} };
55
56    my ( $counter, $size1 );
57    for my $counter ( 0 .. ( @messages - 1 ) ) {
58        $message = ( split /\|/xsm, $messages[$counter], 10 )[8];
59        ( $message, undef ) = Split_Splice_Move( $message, 1 );
60        DoUBBC();
61
62        $convertstr = $message;
63        $convertstr =~ s/<(p|br|div).*?>/ /gxsm;
64        $convertstr =~ s/<.*?>//gxsm;              # remove HTML-tags
65        $convertcut = 50;
66        CountChars();
67        $message = $convertstr;
68        if ($cliped) { $message .= ' ...'; }
69
70        ToChars($message);
71        $message = Censor($message);
72
73        $messages[$counter] = qq~<option value="$counter" ~
74          . (
75            $FORM{'oldposts'} =~ /\b$counter\b/xsm
76            ? q~selected="selected"~
77            : q{}
78          )
79          . q~>~
80          . ( $counter ? "$sstxt{'40'} $counter" : $sstxt{'41'} )
81          . qq~: $message</option>\n~;
82    }
83    if ( ( $ttsureverse && ${ $uid . $username }{'reversetopic'} )
84        || $ttsreverse )
85    {
86        @messages = reverse @messages;
87    }
88    my $postlist = (
89        $FORM{'oldposts'} eq 'all'
90        ? qq~<option value="all" selected="selected">$sstxt{'26'}</option>\n~
91        : qq~<option value="all">$sstxt{'26'}</option>\n~
92    ) . join q{}, @messages;
93    $size1 = @messages + 1;
94    $size1 = $size1 > 10 ? 10 : $size1;    # maximum size of multiselect field
95
96    # List of options of what, if anything, to leave in place of the posts moved
97    my @leaveopts = ( $sstxt{'11'}, $sstxt{'12'}, $sstxt{'13'} );
98    for my $counter ( 0 .. ( @leaveopts - 1 ) ) {
99        $leavelist .=
100            qq~<option value="$counter" ~
101          . ( $FORM{'leave'} == $counter ? q~selected="selected"~ : q{} )
102          . qq~>$leaveopts[$counter]</option>\n~;
103    }
104
105    # Get categories and make the current one the default selection
106    my $catlist = qq~<option value="cats" >$sstxt{'28'}</option>\n~;
107    foreach (@categoryorder) {
108        my ( $catname, $catperms ) = split /\|/xsm, $catinfo{$_}, 3;
109        next if !CatAccess($catperms);
110        $catlist .=
111            qq~<option value="$_" ~
112          . ( $newcat eq $_ ? q~selected="selected"~ : q{} )
113          . qq~>$catname</option>\n~;
114    }
115
116    # Get boards and make the current one the default selection
117    $boardlist = qq~<option value="boards">$sstxt{'29'}</option>\n~;
118    my $indent = -2;
119
120    *get_subboards = sub {
121        my @x = @_;
122        $indent += 2;
123        foreach my $childbd (@x) {
124            my $dash;
125            if ( $indent > 0 ) { $dash = q{-}; }
126            my ( $boardname, $boardperms ) = split /\|/xsm, $board{$childbd}, 3;
127            ToChars($boardname);
128            my $access = AccessCheck( $_, q{}, $boardperms );
129            next if !$iamadmin && $access ne 'granted' && $boardview != 1;
130
131            my $bdnopost =
132              ( ${ $uid . $childbd }{'canpost'} || !$subboard{$childbd} )
133              ? q{}
134              : q~ class="nopost"~;
135            $boardlist .=
136                qq~<option$bdnopost value="$childbd" ~
137              . ( $newboard eq $childbd ? q~selected="selected"~ : q{} ) . q~>~
138              . ( '&nbsp;' x $indent )
139              . ( $dash x ( $indent / 2 ) )
140              . qq~&nbsp;$boardname</option>\n~;
141
142            if ( $subboard{$childbd} ) {
143                get_subboards( split /\|/xsm, $subboard{$childbd} );
144            }
145        }
146        $indent -= 2;
147        return;
148    };
149    get_subboards( split /,/xsm, $cat{$newcat} );
150
151    # Get threads and make the current one the default selection
152    my ( $threadlist, $threadids, $positionlist );
153    fopen( FILE, "$boardsdir/$newboard.txt" );
154    my @threads = <FILE>;
155    fclose(FILE);
156
157    $threadlist = qq~<option value="new">$sstxt{'30'}</option>\n~;
158    my $threadid;
159    foreach (@threads) {
160        ( $threadid, $message, undef ) = split /\|/xsm, $_, 3;
161        next if $curthread eq $threadid;
162        $threadids .= "$threadid,";
163
164        ( $message, undef ) = Split_Splice_Move( $message, $threadid );
165        DoUBBC();
166
167        $convertstr = $message;
168        $convertcut = 50;
169        CountChars();
170        $message = $convertstr;
171        if ($cliped) { $message .= ' ...'; }
172
173        ToChars($message);
174        $message =~ s/<(p|br|div).*?>/ /gxsm;
175        $message =~ s/<.*?>//gxsm;              # remove HTML-tags
176        $message = Censor($message);
177
178        $threadlist .=
179            qq~<option value="$threadid" ~
180          . ( $newthread eq $threadid ? q~selected="selected"~ : q{} )
181          . qq~>$message</option>\n~;
182    }
183
184    # Get new thread posts to select splice site
185    if ( $FORM{'newthread'} ne 'new' ) {
186        if ( !ref $thread_arrayref{$newthread} ) {
187            fopen( FILE, "$datadir/$newthread.txt" );
188            @{ $thread_arrayref{$newthread} } = <FILE>;
189            fclose(FILE);
190        }
191        @messages = @{ $thread_arrayref{$newthread} };
192
193        for my $counter ( 0 .. ( @messages - 1 ) ) {
194            $message = ( split /[\|]/xsm, $messages[$counter], 10 )[8];
195            ( $message, undef ) = Split_Splice_Move( $message, 1 );
196            DoUBBC();
197
198            $convertstr = $message;
199            $convertcut = 50;
200            CountChars();
201            $message = $convertstr;
202            if ($cliped) { $message .= ' ...'; }
203
204            ToChars($message);
205            $message =~ s/<(p|br|div).*?>/ /gxsm;
206            $message =~ s/<.*?>//gxsm;              # remove HTML-tags
207            $message = Censor($message);
208
209            $messages[$counter] =
210                qq~<option value="$counter">~
211              . ( $counter ? "$sstxt{'40'} $counter" : $sstxt{'41'} )
212              . qq~: $message</option>\n~;
213        }
214        if ( ( $ttsureverse && ${ $uid . $username }{'reversetopic'} )
215            || $ttsreverse )
216        {
217            @messages = reverse @messages;
218        }
219        $positionlist = qq~<option value="end">$sstxt{'31'}</option>\n~;
220        $positionlist .=
221          qq~<option value="begin">$sstxt{'32'}</option>\n~;
222        $positionlist .= join q{}, @messages;
223        if (   $FORM{'position'}
224            && $newthread == $FORM{'old_position_thread'} )
225        {
226            $positionlist =~
227              s/(value="$FORM{'position'}")/$1 selected="selected"/xsm;
228        }
229    }
230
231    if (   $newthread eq 'new'
232        || !$threadlist
233        || $threadids !~ /\b$newthread\b/xsm )
234    {
235        $my_output = $mymove_output_a;
236        $my_output =~ s/{yabb newthread_subject}/$FORM{'newthread_subject'}/sm;
237        $my_output =~ s/{yabb position}/$FORM{'position'}/sm;
238        $my_output =~
239          s/{yabb old_position_thread}/$FORM{'old_position_thread'}/sm;
240    }
241    else {
242        $my_output = $mymove_output_b;
243        $my_output =~ s/{yabb positionlist}/$positionlist/sm;
244        $my_output =~ s/{yabb newthread_subject}/$FORM{'newthread_subject'}/sm;
245        $my_output =~ s/{yabb newthread}/$newthread/sm;
246    }
247
248    $my_checked = $FORM{'newinfo'} ? ' checked="checked"' : q{};
249
250    $output = $mymove_top;
251    $output =~ s/{yabb formsession}/$formsession/sm;
252    $output =~ s/{yabb postlist}/$postlist/sm;
253    $output =~ s/{yabb leavelist}/$leavelist/sm;
254    $output =~ s/{yabb catlist}/$catlist/sm;
255    $output =~ s/{yabb boardlist}/$boardlist/sm;
256    $output =~ s/{yabb threadlist}/$threadlist/sm;
257    $output =~ s/{yabb my_output}/$my_output/sm;
258    $output =~ s/{yabb my_checked}/$my_checked/sm;
259    $output =~ s/{yabb size1}/$size1/sm;
260
261    print_output_header();
262    print_HTML_output_and_finish();
263    return;
264}
265
266sub Split_Splice_2 {
267    if ( !$staff && $INFO{'newboard'} ne $binboard ) {
268        fatal_error('split_splice_not_allowed');
269    }
270
271    my $curboard    = $INFO{'board'};
272    my $curthreadid = $INFO{'thread'};
273    my $movingposts =
274      exists $INFO{'oldposts'} ? $INFO{'oldposts'} : $FORM{'oldposts'};
275    $FORM{'oldposts'} = $movingposts;
276    my $leavemess = exists $INFO{'leave'} ? $INFO{'leave'} : $FORM{'leave'};
277    my $forcenewinfo =
278      exists $INFO{'newinfo'} ? $INFO{'newinfo'} : $FORM{'newinfo'};
279    my $newcat = exists $INFO{'newcat'} ? $INFO{'newcat'} : $FORM{'newcat'};
280    my $newboard =
281      exists $INFO{'newboard'} ? $INFO{'newboard'} : $FORM{'newboard'};
282    my $newthreadid =
283      exists $INFO{'newthread'} ? $INFO{'newthread'} : $FORM{'newthread'};
284    $FORM{'newthread'} = $newthreadid;
285    my $newthreadsub =
286      exists $INFO{'newthread_subject'}
287      ? $INFO{'newthread_subject'}
288      : $FORM{'newthread_subject'};
289    my $newposition =
290      exists $INFO{'position'} ? $INFO{'position'} : $FORM{'position'};
291    $FORM{'position'} = $newposition;
292
293    # Error messages if something is not filled out right
294    if ( $movingposts eq q{} ) {
295        fatal_error( q{}, "$sstxt{'22b'} $sstxt{'23'} $sstxt{'50'}" );
296    }
297    if ( $newcat   eq 'cats' )   { fatal_error( q{}, "$sstxt{'22'}" ); }
298    if ( $newboard eq 'boards' ) { fatal_error( q{}, "$sstxt{'22a'}" ); }
299    if ( -e "$datadir/$curthreadid.poll" && -e "$datadir/$newthreadid.poll" ) {
300        fatal_error( q{}, "$sstxt{'51'} $sstxt{'50'}" );
301    }
302
303    my ( @postnum, @utdcurthread, @utdnewthread, $i );
304    my $linkcount = 0;
305
306    # Get current thread posts
307    if ( !ref $thread_arrayref{$curthreadid} ) {
308        fopen( FILE, "$datadir/$curthreadid.txt" );
309        @{ $thread_arrayref{$curthreadid} } = <FILE>;
310        fclose(FILE);
311    }
312    my @curthread = @{ $thread_arrayref{$curthreadid} };
313    MessageTotals( 'load', $curthreadid );
314
315    # Store post numbers to be moved in array
316    if ( ( split /\, /sm, $movingposts, 2 )[0] eq 'all' ) {
317        @postnum = ( 0 .. $#curthread );
318    }
319    else {
320        @postnum = sort { $a <=> $b } split /\, /sm, $movingposts;
321    }    # sort numerically ascending because may be reversed!
322
323# Check to see if current thread was the latest post for the board and if the last post was selected to change
324    BoardTotals( 'load', $curboard );
325    if (
326        ${$curthreadid}{'lastpostdate'} == ${ $uid . $curboard }{'lastposttime'}
327        && $leavemess == 2
328        && $postnum[-1] == $#curthread )
329    {
330        $newest_post = 1;
331    }
332
333    # Move selected posts to a brand new thread
334    if ( $newthreadid eq 'new' ) {
335
336        # Find a valid random ID for new thread.
337        $newthreadid = ( split /\|/xsm, $curthread[ $postnum[0] ], 5 )[3] + 1;
338        while ( -e "$datadir/$newthreadid.txt" ) { $newthreadid++; }
339
340        foreach (@postnum) {
341            if ( $newthreadsub || $leavemess == 1 )
342            {    # insert new subject name || add 'no_postcount' into copies
343                my @x = split /\|/xsm, $curthread[$_];
344                if ($newthreadsub) {
345                    $x[0] =
346                        $_ == $postnum[0]
347                      ? $newthreadsub
348                      : qq~$sstxt{'21'} $newthreadsub~;
349                }
350                if ( $leavemess == 1 ) { $x[5] = 'no_postcount'; }
351                push @utdnewthread, join q{|}, @x;
352            }
353            else {
354                push @utdnewthread, $curthread[$_];
355            }
356        }
357
358        # Place selected posts in existing thread at selected position
359    }
360    else {
361
362        # Get existing thread posts
363        if ( !ref $thread_arrayref{$newthreadid} ) {
364            fopen( FILE, "$datadir/$newthreadid.txt" );
365            @{ $thread_arrayref{$newthreadid} } = <FILE>;
366            fclose(FILE);
367        }
368        my @newthread = @{ $thread_arrayref{$newthreadid} };
369        MessageTotals( 'load', $newthreadid );
370
371        if ( $newposition eq 'end' ) { $newposition = $#newthread; }
372        elsif ( $newposition eq 'begin' ) {
373            foreach (@postnum) {
374                if ( $leavemess == 1 ) {    # add 'no_postcount' into copies
375                    my @x = split /\|/xsm, $curthread[$_];
376                    $x[5] = 'no_postcount';
377                    push @utdnewthread, join q{|}, @x;
378                }
379                else {
380                    push @utdnewthread, $curthread[$_];
381                }
382            }
383            $newposition = -1;
384        }
385        for my $i ( 0 .. ( @newthread - 1 ) ) {
386            push @utdnewthread, $newthread[$i];
387            if ( $newposition == $i ) {
388                foreach (@postnum) {
389                    if ( $leavemess == 1 ) {    # add 'no_postcount' into copies
390                        my @x = split /\|/xsm, $curthread[$_];
391                        $x[5] = 'no_postcount';
392                        push @utdnewthread, join q{|}, @x;
393                    }
394                    else {
395                        push @utdnewthread, $curthread[$_];
396                    }
397                }
398                $linkcount = $i + 1;
399            }
400        }
401    }
402
403    # Remove or copy selected posts from current thread
404    if ( $#postnum == $#curthread && $leavemess != 1 ) {
405        if ( $newboard ne $binboard ) {
406            my ( $tmpsub, $tmpmessage );
407            my $hidename = cloak($username);
408            ( $tmpsub, undef ) = split /\|/xsm, $curthread[0], 2;
409            if ( $curboard eq $newboard ) {
410                $tmpmessage =
411                  qq~[m by=$hidename dest=$newthreadid/$linkcount#$linkcount]~;
412                $tmpsub = qq~[m by=$hidename dest=$newthreadid]: '$tmpsub'~;
413            }
414            else {
415                $tmpmessage =
416qq~[m by=$hidename destboard=$newboard dest=$newthreadid/$linkcount#$linkcount]~;
417                $tmpsub =
418qq~[m by=$hidename destboard=$newboard dest=$newthreadid]: '$tmpsub'~;
419            }
420            FromChars($tmpmessage);
421            $utdcurthread[0] =
422qq~$tmpsub|${$uid.$username}{'realname'}|${$uid.$username}{'email'}|$date|$username|no_postcount||$user_ip|$tmpmessage||||\n~;
423
424            if ( eval { require Variables::Movedthreads; 1 } ) {
425                $moved_file{$curthreadid} = $newthreadid;
426                delete $moved_file{$newthreadid};
427                save_moved_file();
428                $leavemess = 0;
429            }
430        }
431        else {
432            $leavemess    = 2;
433            $forcenewinfo = 1;
434        }
435    }
436    elsif ( $leavemess != 1 ) {
437        if ( $newboard eq $binboard ) { $leavemess = 2; }
438        for my $i ( 0 .. ( @curthread - 1 ) ) {
439            if ( $movingposts =~ /\b$i\b/xsm ) {
440                if ( $leavemess == 0 && $i == $postnum[-1] ) {
441                    my $tmpsub;
442                    ( $tmpsub, undef ) = split /\|/xsm, $curthread[$i], 2;
443                    push @utdcurthread,
444qq~$tmpsub|${$uid.$username}{'realname'}|${$uid.$username}{'email'}|$date|$username|no_postcount||$user_ip|[split] [link=$scripturl?num=$newthreadid/$linkcount#$linkcount][splithere][/link][splithere_end]||||\n~;
445                }
446            }
447            else {
448                push @utdcurthread, $curthread[$i];
449            }
450        }
451
452    }
453    else { @utdcurthread = @curthread; }
454
455    if ($forcenewinfo) {
456        my ( $boardtitle, $tmpsub, $tmpmessage );
457        ( $boardtitle, undef ) = split /\|/xsm, $board{$curboard}, 2;
458        $tmpmessage = (
459            $#postnum == $#utdnewthread
460            ? '[b][movedhere]'
461            : '[b][postsmovedhere1] ' . @postnum . ' [postsmovedhere2]'
462          )
463          . " [i]$boardtitle\[/i] [move by] [i]${$uid.$username}{'realname'}\[/i].[/b]";
464        FromChars($tmpmessage);
465        ( $tmpsub, undef, undef, undef, undef, undef, undef ) =
466          split /\|/xsm, $utdnewthread[0], 7;
467        splice @utdnewthread, ( $linkcount + @postnum ), 0,
468qq~$sstxt{'21'} $tmpsub|${$uid.$username}{'realname'}|${$uid.$username}{'email'}|$date|$username|no_postcount||$user_ip|$tmpmessage||||\n~;
469    }
470
471    if (@utdcurthread) {
472        for my $i ( 0 .. ( @utdcurthread - 1 ) ) {    # sort post numbers
473            my @x = split /\|/xsm, $utdcurthread[$i];
474            $x[6] = $i;
475            $utdcurthread[$i] = join q{|}, @x;
476        }
477
478        # Update current thread
479        fopen( FILE, ">$datadir/$curthreadid.txt" );
480        print {FILE} @utdcurthread or croak "$croak{'print'} FILE";
481        fclose(FILE);
482    }
483    else {
484        require Sources::RemoveTopic;
485        my $moveit = $INFO{'moveit'};
486        $INFO{'moveit'} = 1;
487        RemoveThread();
488        $INFO{'moveit'} = $moveit;
489    }
490
491    for my $i ( 0 .. ( @utdnewthread - 1 ) ) {    # sort post numbers
492        my @x = split /\|/xsm, $utdnewthread[$i];
493        $x[6] = $i;
494        $utdnewthread[$i] = join q{|}, @x;
495    }
496
497    # Update new thread
498    fopen( FILE, ">$datadir/$newthreadid.txt" );
499    print {FILE} @utdnewthread or croak "$croak{'print'} FILE";
500    fclose(FILE);
501
502    # Update the .rlog files of the users
503    my (
504        $reply,               $ms,                 $mn,
505        $md,                  $mu,                 $mnp,
506        $mi,                  %mu,                 %curthreadusersdate,
507        %curthreaduserscount, %newthreadusersdate, %newthreaduserscount,
508        %BoardTotals
509    );
510    $reply = 0;
511    foreach (@utdcurthread)
512    { # $subject|$name|$email|$date|$username|$icon|0|$user_ip|$message|$ns|||$fixfile
513        ( $ms, $mn, undef, $md, $mu, $mnp, undef, $mi, undef ) =
514          split /\|/xsm, $_, 9;
515        if ( ${ $BoardTotals{$curthreadid} }[0] <= $md ) {
516            $BoardTotals{$curthreadid} = [ $md, $mu, $reply, $ms, $mn, $mi ];
517        }
518        $reply++;
519        next if $mnp eq 'no_postcount';
520        if ( $curthreadusersdate{$mu} < $md ) {
521            $curthreadusersdate{$mu} = $md;
522        }
523        $curthreaduserscount{$mu}++;
524        $mu{$mu} = 1;
525    }
526    $reply = 0;
527    foreach (@utdnewthread) {
528        ( $ms, $mn, undef, $md, $mu, $mnp, undef, $mi, undef ) =
529          split /\|/xsm, $_, 9;
530        if ( ${ $BoardTotals{$newthreadid} }[0] <= $md ) {
531            $BoardTotals{$newthreadid} = [ $md, $mu, $reply, $ms, $mn, $mi ];
532        }
533        $reply++;
534        next if $mnp eq 'no_postcount';
535        if ( $newthreadusersdate{$mu} < $md ) {
536            $newthreadusersdate{$mu} = $md;
537        }
538        $newthreaduserscount{$mu}++;
539        $mu{$mu} = 1;
540    }
541    foreach my $mu ( keys %mu ) {
542        Recent_Load($mu);
543        delete $recent{$curthreadid};
544        delete $recent{$newthreadid};
545        if ( $curthreaduserscount{$mu} ) {
546            ${ $recent{$curthreadid} }[0] = $curthreaduserscount{$mu};
547            ${ $recent{$curthreadid} }[1] = $curthreadusersdate{$mu};
548        }
549        if ( $newthreaduserscount{$mu} ) {
550            ${ $recent{$newthreadid} }[0] = $newthreaduserscount{$mu};
551            ${ $recent{$newthreadid} }[1] = $newthreadusersdate{$mu};
552        }
553        Recent_Save($mu);
554    }
555
556    # For: Mark threads/boards as read
557    getlog();
558    my $boardlog = 1;
559
560    # Mark new thread as read because you will be directed there at the end
561    delete $yyuserlog{"$newthreadid--unread"};
562    $yyuserlog{$newthreadid} = $date;
563
564# Update .ctb, tags=>(board replies views lastposter lastpostdate threadstatus repliers)
565# curthread
566    ${$curthreadid}{'replies'}      = $#utdcurthread;
567    ${$curthreadid}{'lastpostdate'} = ${ $BoardTotals{$curthreadid} }[0];
568    ${$curthreadid}{'lastposter'} =
569      ${ $BoardTotals{$curthreadid} }[1] eq 'Guest'
570      ? "Guest-${$BoardTotals{$curthreadid}}[4]"
571      : ${ $BoardTotals{$curthreadid} }[1];
572
573    # newthread
574    ${$newthreadid}{'replies'}      = $#utdnewthread;
575    ${$newthreadid}{'lastpostdate'} = ${ $BoardTotals{$newthreadid} }[0];
576    ${$newthreadid}{'lastposter'} =
577      ${ $BoardTotals{$newthreadid} }[1] eq 'Guest'
578      ? "Guest-${$BoardTotals{$newthreadid}}[4]"
579      : ${ $BoardTotals{$newthreadid} }[1];
580    if ( $FORM{'newthread'} eq 'new' ) {
581        ${$newthreadid}{'board'} = $newboard;
582        ${$newthreadid}{'views'} =
583          $#postnum == $#curthread
584          ? ${$curthreadid}{'views'}
585          : ( $INFO{'ss_submit'} ? 1 : 0 );
586        ${$newthreadid}{'threadstatus'} = ${$curthreadid}{'threadstatus'};
587        ${$curthreadid}{'views'}        = $#postnum == $#curthread
588          && $leavemess != 1 ? 0 : ${$curthreadid}{'views'};
589    }
590    else {
591        ${$newthreadid}{'views'} +=
592          int( ${$curthreadid}{'views'} / @curthread * @postnum );
593    }
594
595    # Update current message index
596    fopen( BOARD, "<$boardsdir/$curboard.txt", 1 );
597    my @curmessindex = <BOARD>;
598    fclose( BOARD );
599
600    my $old_mstate;
601    for my $i ( 0 .. ( @curmessindex - 1 ) ) {
602        my (
603            $mnum,     $msub,      $mname, $memail, $mdate,
604            $mreplies, $musername, $micon, $mstate
605        ) = split /\|/xsm, $curmessindex[$i];
606        if ( $mdate > $yyuserlog{$curboard} ) {
607            $boardlog = 0;
608        }    # For: Mark boards as read
609        if ( $mnum == $curthreadid ) {
610            chomp $mstate;
611            if ( $#postnum == $#curthread && $leavemess != 1 )
612            {    # thread was moved
613                my $hidename = cloak($username);
614                if ( $curboard eq $newboard ) {
615                    $msub = qq~[m by=$hidename dest=$newthreadid]: '$msub'~;
616                }
617                else {
618                    $msub =
619qq~[m by=$hidename destboard=$newboard dest=$newthreadid]: '$msub'~;
620                }
621                $mname     = ${ $uid . $username }{'realname'};
622                $memail    = ${ $uid . $username }{'email'};
623                $mreplies  = 0;
624                $musername = $username;
625
626                # alter message icon to 'exclamation' to match status 'lm'
627                if ( $micon ne 'no_postcount' ) { $micon = 'exclamation'; }
628
629      # thread status - (a)nnoumcement, (h)idden, (l)ocked, (m)oved and (s)ticky
630                $old_mstate = $mstate;
631                if ( $curboard eq $annboard && $mstate !~ /a/ism ) {
632                    $mstate .= 'a';
633                }
634                if ( $mstate !~ /l/ism ) { $mstate .= 'l'; }
635                if ( $mstate !~ /m/ism ) { $mstate .= 'm'; }
636                ${$curthreadid}{'threadstatus'} = $mstate;
637            }
638            else {
639                ( $msub, $mname, $memail, undef, $musername, $micon, undef ) =
640                  split /\|/xsm, $utdcurthread[0], 7;
641                $mreplies = ${$curthreadid}{'replies'};
642            }
643            $curmessindex[$i] =
644qq~$mnum|$msub|$mname|$memail|${$curthreadid}{'lastpostdate'}|$mreplies|$musername|$micon|$mstate\n~;
645            ${ $BoardTotals{$mnum} }[6] = $mstate;
646
647        }
648        elsif ( $mnum == $newthreadid ) {
649            chomp $mstate;
650            if ( $FORM{'position'} eq 'begin' ) {
651                ( $msub, $mname, $memail, undef, $musername, $micon, undef ) =
652                  split /\|/xsm, $utdnewthread[0], 7;
653            }
654            $yyThreadLine = $curmessindex[$i] =
655qq~$mnum|$msub|$mname|$memail|${$newthreadid}{'lastpostdate'}|${$newthreadid}{'replies'}|$musername|$micon|$mstate\n~;
656            ${ $BoardTotals{$mnum} }[6] = $mstate;
657            if (
658                ( $enable_notifications == 1 || $enable_notifications == 3 )
659                && (   -e "$boardsdir/$curboard.mail"
660                    || -e "$datadir/$newthreadid.mail" )
661              )
662            {
663                require Sources::Post;
664                $currentboard = $curboard;
665                $msub         = Censor($msub);
666                ReplyNotify( $newthreadid, $msub, ${$newthreadid}{'replies'} );
667            }
668        }
669    }
670    if ( $curboard eq $newboard && $FORM{'newthread'} eq 'new' ) {
671        my ( $msub, $mname, $memail, $musername, $micon );
672        ( $msub, $mname, $memail, undef, $musername, $micon, undef ) =
673          split /\|/xsm, $utdnewthread[0], 7;
674        if ( $old_mstate !~ /0/ism ) { $old_mstate .= '0'; }
675        $yyThreadLine =
676qq~$newthreadid|$msub|$mname|$memail|${$newthreadid}{'lastpostdate'}|${$newthreadid}{'replies'}|$musername|$micon|$old_mstate\n~;
677        unshift @curmessindex, $yyThreadLine;
678        ${ $BoardTotals{$newthreadid} }[6] = $old_mstate;
679        if ( ( $enable_notifications == 1 || $enable_notifications == 3 )
680            && -e "$boardsdir/$newboard.mail" )
681        {
682            require Sources::Post;
683            $currentboard = $curboard;
684            $msub         = Censor($msub);
685            NewNotify( $newthreadid, $msub );
686        }
687    }
688    fopen( BOARD, ">$boardsdir/$curboard.txt", 1 );
689    print {BOARD} reverse
690      sort { ( split /\|/xsm, $a, 6 )[4] <=> ( split /\|/xsm, $b, 6 )[4] }
691      @curmessindex
692      or croak "$croak{'print'} BOARD";
693    fclose( BOARD );
694
695    if ($boardlog) {
696        $yyuserlog{$curboard} = $date;
697    }    # For: Mark boards as read
698
699    # Update new message index if needed
700    if ( $curboard ne $newboard ) {
701        $boardlog = 1;    # For: Mark boards as read
702
703        fopen( BOARD, "+<$boardsdir/$newboard.txt", 1 );
704        seek BOARD, 0, 0;
705        my @newmessindex = <BOARD>;
706        truncate BOARD, 0;
707        seek BOARD, 0, 0;
708
709        if ( $FORM{'newthread'} eq 'new' ) {
710
711            # For: Mark boards as read
712            foreach (@newmessindex) {
713                if ( ( split /\|/xsm, $_, 6 )[4] > $yyuserlog{$newboard} ) {
714                    $boardlog = 0;
715                }
716                last if !$boardlog;
717            }
718
719            my ( $msub, $mname, $memail, undef, $musername, $micon, undef ) =
720              split /\|/xsm, $utdnewthread[0], 7;
721            if ( $old_mstate =~ /a/ism ) {
722                if ( $newboard ne $annboard ) { $old_mstate =~ s/a//gism; }
723            }
724            elsif ( $newboard eq $annboard ) {
725                $old_mstate .= 'a';
726            }
727            if ( $old_mstate !~ /0/ism ) { $old_mstate .= '0'; }
728            $yyThreadLine =
729qq~$newthreadid|$msub|$mname|$memail|${$newthreadid}{'lastpostdate'}|${$newthreadid}{'replies'}|$musername|$micon|$old_mstate\n~;
730            unshift @newmessindex, $yyThreadLine;
731            ${ $BoardTotals{$newthreadid} }[6] = $old_mstate;
732            if ( ( $enable_notifications == 1 || $enable_notifications == 3 )
733                && -e "$boardsdir/$newboard.mail" )
734            {
735                require Sources::Post;
736                $currentboard = $newboard;
737                $msub         = Censor($msub);
738                NewNotify( $newthreadid, $msub );
739            }
740        }
741        else {
742            for my $i ( 0 .. ( @newmessindex - 1 ) ) {
743                my (
744                    $mnum,     $msub,      $mname, $memail, $mdate,
745                    $mreplies, $musername, $micon, $mstate
746                ) = split /\|/xsm, $newmessindex[$i];
747                if ( $mdate > $yyuserlog{$newboard} ) {
748                    $boardlog = 0;
749                }    # For: Mark boards as read
750                if ( $mnum == $newthreadid ) {
751                    chomp $mstate;
752                    if ( $FORM{'position'} eq 'begin' ) {
753                        (
754                            $msub, $mname, $memail, undef, $musername, $micon,
755                            undef
756                        ) = split /\|/xsm, $utdnewthread[0], 7;
757                    }
758                    $yyThreadLine = $newmessindex[$i] =
759qq~$mnum|$msub|$mname|$memail|${$newthreadid}{'lastpostdate'}|${$newthreadid}{'replies'}|$musername|$micon|$mstate\n~;
760                    ${ $BoardTotals{$mnum} }[6] = $mstate;
761                }
762            }
763            if (
764                ( $enable_notifications == 1 || $enable_notifications == 3 )
765                && (   -e "$boardsdir/$newboard.mail"
766                    || -e "$datadir/$newthreadid.mail" )
767              )
768            {
769                require Sources::Post;
770                $currentboard = $newboard;
771                $msub         = Censor($msub);
772                ReplyNotify( $newthreadid, $msub, ${$newthreadid}{'replies'} );
773            }
774        }
775        print {BOARD} reverse
776          sort { ( split /\|/xsm, $a, 6 )[4] <=> ( split /\|/xsm, $b, 6 )[4] }
777          @newmessindex
778          or croak "$croak{'print'} BOARD";
779        fclose(BOARD);
780
781        if ($boardlog) {
782            $yyuserlog{$newboard} = $date;
783        }    # For: Mark boards as read
784    }
785
786    if (@utdcurthread) { MessageTotals( 'update', $curthreadid ); }
787    MessageTotals( 'update', $newthreadid );
788
789# update current board totals
790# BoardTotals- tags => (board threadcount messagecount lastposttime lastposter lastpostid lastreply lastsubject lasticon lasttopicstate)
791#&BoardTotals("load", $curboard); - Load this at top now to detect if newest board post is being moved - Unilat
792    if ( ${ $BoardTotals{$curthreadid} }[6] =~ /m/sm ) {    # Moved-Info thread
793        if ( $curboard ne $newboard ) {
794            ${ $uid . $curboard }{'threadcount'}--;
795            ${ $uid . $curboard }{'messagecount'} -= @postnum;
796        }
797        BoardSetLastInfo( $curboard, \@curmessindex );
798    }
799    else {
800        if ( $FORM{'newthread'} eq 'new' && $curboard eq $newboard ) {
801            ${ $uid . $curboard }{'threadcount'}++;
802        }
803        if ( $leavemess == 0 ) {
804            if ( $curboard ne $newboard ) {
805                ${ $uid . $curboard }{'messagecount'} -= $#postnum;
806            }
807            else {
808                ${ $uid . $curboard }{'messagecount'} +=
809                  ( $forcenewinfo ? 2 : 1 );
810            }
811        }
812        elsif ( $leavemess == 1 && $curboard eq $newboard ) {
813            ${ $uid . $curboard }{'messagecount'} +=
814              $#postnum + ( $forcenewinfo ? 1 : 0 );
815        }
816        elsif ( $leavemess == 2 && $curboard ne $newboard && @utdcurthread ) {
817            ${ $uid . $curboard }{'messagecount'} -= @postnum;
818        }
819        if (
820            $newest_post
821            || (
822                (
823                    (
824                        ${ $uid . $curboard }{'threadcount'} == 1
825                        && @utdcurthread
826                    )
827                    || ${ $BoardTotals{$curthreadid} }[0] >=
828                    ${ $uid . $curboard }{'lastposttime'}
829                )
830                && ( $curboard ne $newboard
831                    || ${ $BoardTotals{$curthreadid} }[0] >=
832                    ${ $BoardTotals{$newthreadid} }[0] )
833            )
834          )
835        {
836            ${ $uid . $curboard }{'lastposttime'} =
837              ${ $BoardTotals{$curthreadid} }[0];
838            ${ $uid . $curboard }{'lastposter'} =
839              ${ $BoardTotals{$curthreadid} }[1] eq 'Guest'
840              ? "Guest-${$BoardTotals{$curthreadid}}[4]"
841              : ${ $BoardTotals{$curthreadid} }[1];
842            ${ $uid . $curboard }{'lastpostid'} = $curthreadid;
843            ${ $uid . $curboard }{'lastreply'} =
844              ${ $BoardTotals{$curthreadid} }[2]--;
845            ${ $uid . $curboard }{'lastsubject'} =
846              ${ $BoardTotals{$curthreadid} }[3];
847            ${ $uid . $curboard }{'lasticon'} =
848              ${ $BoardTotals{$curthreadid} }[5];
849            ${ $uid . $curboard }{'lasttopicstate'} =
850              ${ $BoardTotals{$curthreadid} }[6];
851        }
852        elsif ( ${ $BoardTotals{$newthreadid} }[0] >=
853            ${ $uid . $curboard }{'lastposttime'}
854            && $curboard eq $newboard )
855        {
856            ${ $uid . $curboard }{'lastposttime'} =
857              ${ $BoardTotals{$newthreadid} }[0];
858            ${ $uid . $curboard }{'lastposter'} =
859              ${ $BoardTotals{$newthreadid} }[1] eq 'Guest'
860              ? "Guest-${$BoardTotals{$newthreadid}}[4]"
861              : ${ $BoardTotals{$newthreadid} }[1];
862            ${ $uid . $curboard }{'lastpostid'} = $newthreadid;
863            ${ $uid . $curboard }{'lastreply'} =
864              ${ $BoardTotals{$newthreadid} }[2]--;
865            ${ $uid . $curboard }{'lastsubject'} =
866              ${ $BoardTotals{$newthreadid} }[3];
867            ${ $uid . $curboard }{'lasticon'} =
868              ${ $BoardTotals{$newthreadid} }[5];
869            ${ $uid . $curboard }{'lasttopicstate'} =
870              ${ $BoardTotals{$newthreadid} }[6];
871        }
872        BoardSetLastInfo( $curboard, \@curmessindex );
873    }
874
875    # update new board totals if needed
876    if ( $curboard ne $newboard ) {
877        BoardTotals( 'load', $newboard );
878        if ( $FORM{'newthread'} eq 'new' ) {
879            ${ $uid . $newboard }{'threadcount'}++;
880        }
881        ${ $uid . $newboard }{'messagecount'} +=
882          @postnum + ( $forcenewinfo ? 1 : 0 );
883        if (   ${ $uid . $newboard }{'threadcount'} == 1
884            || ${ $BoardTotals{$newthreadid} }[0] >=
885            ${ $uid . $newboard }{'lastposttime'} )
886        {
887            ${ $uid . $newboard }{'lastposttime'} =
888              ${ $BoardTotals{$newthreadid} }[0];
889            ${ $uid . $newboard }{'lastposter'} =
890              ${ $BoardTotals{$newthreadid} }[1] eq 'Guest'
891              ? "Guest-${$BoardTotals{$newthreadid}}[4]"
892              : ${ $BoardTotals{$newthreadid} }[1];
893            ${ $uid . $newboard }{'lastpostid'} = $newthreadid;
894            ${ $uid . $newboard }{'lastreply'} =
895              ${ $BoardTotals{$newthreadid} }[2]--;
896            ${ $uid . $newboard }{'lastsubject'} =
897              ${ $BoardTotals{$newthreadid} }[3];
898            ${ $uid . $newboard }{'lasticon'} =
899              ${ $BoardTotals{$newthreadid} }[5];
900            ${ $uid . $newboard }{'lasttopicstate'} =
901              ${ $BoardTotals{$newthreadid} }[6];
902        }
903        BoardTotals( 'update', $newboard );
904    }
905
906    # now fix all attachments.txt info
907    my $attachments;
908    for my $i ( $postnum[0] .. ( @curthread - 1 ) )
909    {    # see if old thread had attachments
910        $attachments = ( split /\|/xsm, $curthread[$i] )[12];
911        chomp $attachments;
912        if ($attachments) {
913            $attachments = 1;
914            last;
915        }
916    }
917    if ( !$attachments ) {    # see if new thread has attachments
918        for my $i ( $linkcount .. ( @utdnewthread - 1 ) ) {
919            $attachments = ( split /\|/xsm, $utdnewthread[$i] )[12];
920            chomp $attachments;
921            if ($attachments) {
922                $attachments = 2;
923                last;
924            }
925        }
926    }
927    if ($attachments) {
928        my ( @newattachments, %attachments );
929        fopen( ATM, "<$vardir/attachments.txt", 1 )
930          or fatal_error( 'cannot_open', "$vardir/attachments.txt", 1 );
931        my @attach = <ATM>;
932        fclose(ATM);
933        for (@attach) {
934            my (
935                $attid, undef, undef, undef, undef, undef, undef,
936                $attachmentname, $downloadscount
937            ) = split /\|/xsm, $_;
938            if (   ( $attid != $curthreadid && $attid != $newthreadid )
939                || ( $attid == $curthreadid && $attachments != 1 ) )
940            {
941                push @newattachments, $_;
942            }
943            chomp $downloadscount;
944            $attachments{$attachmentname} = $downloadscount;
945        }
946
947        my $mreplies = 0;
948        if ( $attachments == 1 ) {
949            foreach (@utdcurthread) {    # fix new old thread attachments
950                my (
951                    $msub, $mname, undef, $mdate, undef, undef, undef,
952                    undef, undef,  undef, undef,  undef, $mfn
953                ) = split /\|/xsm, $_;
954                chomp $mfn;
955                foreach ( split /,/xsm, $mfn ) {
956                    if ( -e "$uploaddir/$_" ) {
957                        my $asize = int( ( -s "$uploaddir/$_" ) / 1024 )
958                          || 1;
959                        push @newattachments,
960qq~$curthreadid|$mreplies|$msub|$mname|$curboard|$asize|$mdate|$_|~
961                          . ( $attachments{$_} || 0 ) . qq~\n~;
962                    }
963                }
964                $mreplies++;
965            }
966        }
967
968        $mreplies = 0;
969        foreach (@utdnewthread) {    # fix new thread attachments
970            my (
971                $msub, $mname, undef, $mdate, undef, undef, undef,
972                undef, undef,  undef, undef,  undef, $mfn
973            ) = split /\|/xsm, $_;
974            chomp $mfn;
975            foreach ( split /,/xsm, $mfn ) {
976                if ( -e "$uploaddir/$_" ) {
977                    my $asize = int( ( -s "$uploaddir/$_" ) / 1024 ) || 1;
978                    push @newattachments,
979qq~$newthreadid|$mreplies|$msub|$mname|$newboard|$asize|$mdate|$_|~
980                      . ( $attachments{$_} || 0 ) . qq~\n~;
981                }
982            }
983            $mreplies++;
984        }
985        fopen( FATM, ">$vardir/attachments.txt" )
986          or fatal_error( 'cannot_open', "$vardir/attachments.txt" );
987            print {FATM}
988            sort { ( split /\|/xsm, $a, 8 )[6] <=> ( split /\|/xsm, $b, 8 )[6] }
989            @newattachments or croak "$croak{'print'} ATM";
990        fclose(FATM);
991    }
992
993    if ( $#postnum == $#curthread ) {
994        if ( -e "$datadir/$curthreadid.poll" ) {
995            rename
996              "$datadir/$curthreadid.poll",
997              "$datadir/$newthreadid.poll";
998        }
999        if ( -e "$datadir/$curthreadid.polled" ) {
1000            rename
1001              "$datadir/$curthreadid.polled",
1002              "$datadir/$newthreadid.polled";
1003        }
1004        if ( -e "$datadir/$curthreadid.mail" ) {
1005            rename
1006              "$datadir/$curthreadid.mail",
1007              "$datadir/$newthreadid.mail";
1008            require Sources::Notify;
1009            ManageThreadNotify( 'load', $newthreadid );
1010            my (%t);
1011            foreach my $u ( keys %thethread ) {
1012                LoadUser($u);
1013                foreach ( split /,/xsm, ${ $uid . $u }{'thread_notifications'} )
1014                {
1015                    $t{$_} = 1;
1016                }
1017                delete $t{$curthreadid};
1018                $t{$newthreadid} = 1;
1019                ${ $uid . $u }{'thread_notifications'} = join q{,}, keys %t;
1020                UserAccount($u);
1021                undef %t;
1022            }
1023        }
1024    }
1025
1026    # Mark current thread as read
1027    delete $yyuserlog{"$curthreadid--unread"};
1028    dumplog($curthreadid);    # Save threads/boards as read
1029
1030    chomp $yyThreadLine;
1031
1032    if ( $INFO{'moveit'} == 1 ) {
1033        $currentboard = $curboard;
1034        return;
1035    }
1036    if ( $INFO{'ss_submit'} ) {
1037        $currentboard = $newboard;
1038        $INFO{'num'} = $INFO{'thread'} = $FORM{'threadid'} = $curnum =
1039          $newthreadid;
1040        redirectinternal();
1041    }
1042    if ( $debug == 1 or ( $debug == 2 && $iamadmin ) ) {
1043        require Sources::Debug;
1044        Debug();
1045        $yydebug =
1046qq~\n- $#utdnewthread<br />\n- @utdnewthread<br />\n- ${$newthreadid}{'lastpostdate'}<br />\n- ${$newthreadid}{'lastposter'}<br />\n- \$enable_notifications == $enable_notifications<br />\n- \$attachments = $attachments<br />\n<a href="javascript:load_thread($newthreadid,$linkcount);">continue</a>\n$yydebug~;
1047    }
1048
1049    print_output_header();
1050
1051    $output =
1052qq~<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
1053<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="$abbr_lang" lang="$abbr_lang">
1054<head>
1055<title>$sstxt{'1'}</title>
1056<meta http-equiv="Content-Type" content="text/html; charset=$yymycharset" />
1057<script type="text/javascript">
1058    function load_thread(threadid,replies) {
1059        try{
1060            if (typeof(opener.document) == 'object') throw '1';
1061            else throw '0';
1062        } catch (e) {
1063            if (replies > 0 || ~
1064      . (
1065        (
1066            ( $ttsureverse && ${ $uid . $username }{'reversetopic'} )
1067              || $ttsreverse
1068        ) ? 1 : 0
1069      )
1070      . qq~ == 1) replies = '/' + replies + '#' + replies;
1071            else replies = '';
1072            if (e == 1) {
1073                opener.focus();
1074                opener.location.href='$scripturl?num=' + threadid + replies;
1075                self.close();
1076            } else {
1077                location.href='$scripturl?num=' + threadid + replies;
1078            }
1079        }
1080    }
1081</script>
1082</head>
1083<body onload="load_thread($newthreadid,$linkcount);">
1084&nbsp;$yydebug
1085</body>
1086</html>~;
1087
1088    print_HTML_output_and_finish();
1089    return;
1090}
1091
10921;
1093