1###############################################################################
2# Notify.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$notifypmver = 'YaBB 2.6.11 $Revision: 1611 $';
19if ( $action eq 'detailedversion' ) { return 1; }
20
21LoadLanguage('Notify');
22
23sub ManageBoardNotify {
24    my ( $todo, $theboard, $user, $userlang, $notetype, $noteview ) = @_;
25    if (   $todo eq 'load'
26        || $todo eq 'update'
27        || $todo eq 'delete'
28        || $todo eq 'add' )
29    {
30        undef %theboard;
31        ## open board mail file and build hash name / detail
32        if ( -e "$boardsdir/$theboard.mail" ) {
33            fopen( BOARDNOTE, "$boardsdir/$theboard.mail" );
34            %theboard = map { /(.*)\t(.*)/xsm } <BOARDNOTE>;
35            fclose(BOARDNOTE);
36        }
37    }
38    if ( $todo eq 'add' ) {
39        if ( !$maxtnote ) { $maxtnote = 10; }
40        $theboard{$user} = "$userlang|$notetype|$noteview";
41        LoadUser($user);
42        my %bb;
43        my @oldnote = split /,/xsm,
44          ${ $uid . $username }{'board_notifications'};
45        if ( @oldnote < ( $maxtnote || 10 ) ) {
46            foreach ( split /,/xsm, ${ $uid . $user }{'board_notifications'} ) {
47                $bb{$_} = 1;
48           }
49            $bb{$theboard} = 1;
50            ${ $uid . $user }{'board_notifications'} = join q{,}, keys %bb;
51            UserAccount($user);
52        }
53    }
54    elsif ( $todo eq 'update' ) {
55        if ( exists $theboard{$user} ) {
56            my ( $memlang, $memtype, $memview ) =
57              split /\|/xsm, $theboard{$user};
58            if ($userlang) { $memlang = $userlang; }
59            if ($notetype) { $memtype = $notetype; }
60            if ($noteview) { $memview = $noteview; }
61            $theboard{$user} = "$memlang|$memtype|$memview";
62        }
63    }
64    elsif ( $todo eq 'delete' ) {
65        my %bb;
66        foreach my $u ( split /,/xsm, $user ) {
67            delete $theboard{$u};
68            LoadUser($u);
69            foreach ( split /,/xsm, ${ $uid . $u }{'board_notifications'} ) {
70                $bb{$_} = 1;
71            }
72            if ( delete $bb{$theboard} ) {
73                ${ $uid . $u }{'board_notifications'} = join q{,}, keys %bb;
74                UserAccount($u);
75            }
76            undef %bb;
77        }
78    }
79    if (   $todo eq 'save'
80        || $todo eq 'update'
81        || $todo eq 'delete'
82        || $todo eq 'add' )
83    {
84        if (%theboard) {
85            fopen( BOARDNOTE, ">$boardsdir/$theboard.mail" );
86            print {BOARDNOTE} map { "$_\t$theboard{$_}\n" }
87              sort { $theboard{$a} cmp $theboard{$b} } keys %theboard
88              or croak "$croak{'print'} BOARDNOTE";
89            fclose(BOARDNOTE);
90            undef %theboard;
91        }
92        else {
93            unlink "$boardsdir/$theboard.mail";
94        }
95    }
96    return;
97}
98
99sub BoardNotify {
100    if ( !$currentboard ) { fatal_error('no_access'); }
101    if ($iamguest)        { fatal_error('members_only'); }
102    $selected1 = q{};
103    $selected2 = q{};
104    $deloption = q{};
105    my ( $boardname, undef ) = split /\|/xsm, $board{$currentboard}, 2;
106    ToChars($boardname);
107    ManageBoardNotify( 'load', $currentboard );
108
109##  popup from MessageIndex
110
111    LoadLanguage('Notify');
112    get_template('MessageIndex');
113
114    if ( exists $theboard{$username} ) {
115        ( $memlang, $memtype, $memview ) = split /\|/xsm, $theboard{$username};
116        ${ 'selected' . $memtype } = q~ selected="selected"~;
117        $deloption = qq~<option value="3">$notify_txt{'134'}</option>~;
118        $my_delopt = qq~$notify_txt{'137'} &nbsp;~;
119    }
120    else {
121        $my_delopt = qq~$notify_txt{'126'} &nbsp;~;
122    }
123
124    $yymain .= $brd_notify;
125    $yymain =~ s/{yabb boardname}/$boardname/gsm;
126    $yymain =~ s/{yabb currentboard}/$currentboard/gsm;
127    $yymain =~ s/{yabb currentboard}/$currentboard/gsm;
128    $yymain =~ s/{yabb selected1}/$selected1/gsm;
129    $yymain =~ s/{yabb selected2}/$selected2/gsm;
130    $yymain =~ s/{yabb deloption}/$deloption/gsm;
131    $yymain =~ s/{yabb my_delopt}/$my_delopt/gsm;
132
133    undef %theboard;
134    $yytitle = "$notify_txt{'125'}";
135    template();
136    return;
137}
138
139sub BoardNotify2 {
140    if ($iamguest) { fatal_error('members_only'); }
141    foreach my $variable ( keys %FORM ) {
142        if ( $variable eq 'formsession' ) { next; }
143        $notify_type = $FORM{$variable};
144        if ( $notify_type == 1 || $notify_type == 2 ) {
145            ManageBoardNotify( 'add', $variable, $username,
146                ${ $uid . $username }{'language'},
147                $notify_type, '1' );
148        }
149        elsif ( $notify_type == 3 ) {
150            ManageBoardNotify( 'delete', $variable, $username );
151        }
152    }
153    if ( $action eq 'boardnotify3' ) {
154        $yySetLocation = qq~$scripturl?board=$INFO{'board'}~;
155    }
156    else {
157        $yySetLocation = qq~$scripturl?action=shownotify~;
158    }
159    redirectexit();
160    return;
161}
162
163sub ManageThreadNotify {
164    my ( $todo, $thethread, $user, $userlang, $notetype, $noteview ) = @_;
165    if (   $todo eq 'load'
166        || $todo eq 'update'
167        || $todo eq 'delete'
168        || $todo eq 'add' )
169    {
170        undef %thethread;
171        ##  open mail file and build hash
172        if ( -e "$datadir/$thethread.mail" ) {
173            fopen( THREADNOTE, "$datadir/$thethread.mail" );
174            %thethread = map /(.*)\t(.*)/, <THREADNOTE>;
175            fclose(THREADNOTE);
176        }
177    }
178    if ( $todo eq 'add' ) {
179        $thethread{$user} = "$userlang|$notetype|$noteview";
180        LoadUser($user);
181        my %t;
182        foreach ( split /,/xsm, ${ $uid . $user }{'thread_notifications'} ) {
183            $t{$_} = 1;
184        }
185        $t{$thethread} = 1;
186        ${ $uid . $user }{'thread_notifications'} = join q{,}, keys %t;
187        UserAccount($user);
188    }
189    elsif ( $todo eq 'update' ) {
190        if ( exists $thethread{$user} ) {
191            ( $memlang, $memtype, $memview ) = split /\|/xsm, $thethread{$user};
192            if ($userlang) { $memlang = $userlang; }
193            if ($notetype) { $memtype = $notetype; }
194            if ($noteview) { $memview = $noteview; }
195            $thethread{$user} = "$memlang|$memtype|$memview";
196        }
197    }
198    elsif ( $todo eq 'delete' ) {
199        my %t;
200        foreach my $u ( split /,/xsm, $user ) {
201            delete $thethread{$u};
202            LoadUser($u);
203            foreach ( split /,/xsm, ${ $uid . $u }{'thread_notifications'} ) {
204                $t{$_} = 1;
205            }
206            if ( delete $t{$thethread} ) {
207                ${ $uid . $u }{'thread_notifications'} = join q{,}, keys %t;
208                UserAccount($u);
209            }
210            undef %t;
211        }
212    }
213    if (   $todo eq 'save'
214        || $todo eq 'update'
215        || $todo eq 'delete'
216        || $todo eq 'add' )
217    {
218        if (%thethread) {
219            fopen( THREADNOTE, ">$datadir/$thethread.mail" );
220            print {THREADNOTE} map { "$_\t$thethread{$_}\n" }
221              sort { $thethread{$a} cmp $thethread{$b} } keys %thethread
222              or croak "$croak{'print'} THREADNOTE";
223            fclose(THREADNOTE);
224            undef %thethread;
225        }
226        else {
227            unlink "$datadir/$thethread.mail";
228        }
229    }
230    return;
231}
232
233# sub Notify { deleted because not needed since YaBB 2.3 (deti)
234
235sub Notify2 {
236    if ($iamguest) { fatal_error('members_only'); }
237
238    ManageThreadNotify( 'add', $INFO{'num'}, $username,
239        ${ $uid . $username }{'language'},
240        1, 1 );
241
242    if ( $INFO{'oldnotify'} ) {
243        redirectinternal();
244    }
245    $elenable = 0;
246    croak q{};    # This is here only to avoid server error log entries!
247}
248
249sub Notify3 {
250    if ($iamguest) { fatal_error('members_only'); }
251
252    ManageThreadNotify( 'delete', $INFO{'num'}, $username );
253
254    if ( $INFO{'oldnotify'} ) {
255        redirectinternal();
256    }
257    $elenable = 0;
258    croak q{};    # This is here only to avoid server error log entries!
259}
260
261sub Notify4 {
262    if ($iamguest) { fatal_error('members_only'); }
263    foreach my $variable ( keys %FORM ) {
264        my ( $notype, $threadno ) = split /-/xsm, $variable;
265        if ( $notype eq 'thread' ) {
266            ManageThreadNotify( 'delete', $threadno, $username );
267        }
268    }
269    $action = 'shownotify';
270    ShowNotifications();
271    return;
272}
273
274sub updateLanguage {
275    my ( $user, $newlang ) = @_;
276    getMailFiles();
277    foreach (@bmaildir) {
278        ManageBoardNotify( 'update', $_, $user, $newlang, q{}, q{} );
279    }
280    foreach (@tmaildir) {
281        ManageThreadNotify( 'update', $_, $user, $newlang, q{}, q{} );
282    }
283    return;
284}
285
286sub removeNotifications {
287    my $user_s = shift;
288    getMailFiles();
289    foreach (@bmaildir) {
290        ManageBoardNotify( 'delete', $_, $user_s );
291    }
292    foreach (@tmaildir) {
293        ManageThreadNotify( 'delete', $_, $user_s );
294    }
295    return;
296}
297
298sub getMailFiles {
299    opendir BOARDNOT, "$boardsdir";
300    @bmaildir =
301      map { ( split /\./xsm, $_ )[0] } grep { /\.mail$/xsm } readdir BOARDNOT;
302    closedir BOARDNOT;
303    opendir THREADNOT, "$datadir";
304    @tmaildir =
305      map { ( split /\./xsm, $_ )[0] } grep { /\.mail$/xsm } readdir THREADNOT;
306    closedir THREADNOT;
307    return;
308}
309
310sub ShowNotifications {
311    ## bye bye guest....
312    if ($iamguest) { fatal_error('members_only'); }
313
314    $yynavigation =
315qq~&rsaquo; <a href="$scripturl?action=mycenter" class="nav">$img_txt{'mycenter'}</a> &rsaquo; $img_txt{'418'}~;
316
317    LoadLanguage('Notify');
318    get_template('MyPosts');
319
320    my @oldnote = split /,/xsm, ${ $uid . $username }{'board_notifications'};
321    $curbrd = @oldnote;
322 #   if ( !$maxtnote ) { $maxtnote = 10; }
323
324 #   $note_brd = qq~<br />$notify_txt{'75'}<br />$notify_txt{'76'} $curbrd $notify_txt{'77'} $maxtnote $notify_txt{'78'}~;
325    $curbrd = NumberFormat($curbrd);
326
327    # Show Javascript for 'check all' notifications
328
329    ( $board_notify, $thread_notify ) = NotificationAlert();
330    my ( $num, $new );
331
332    # Board notifications
333    foreach ( keys %{$board_notify} ) {    # boardname, boardnotifytype , new
334        $num++;
335
336        my ( $selected1, $selected2 );
337        if ( ${ $$board_notify{$_} }[1] == 1 ) {    # new topics
338            $selected1 = q~ selected="selected"~;
339        }
340        else {                                      # all new posts
341            $selected2 = q~ selected="selected"~;
342        }
343
344        if ( ${ $$board_notify{$_} }[2] ) {
345            $new =
346qq~<img src="$imagesdir/$brdimg_new" alt="$notify_txt{'333'}" title="$notify_txt{'333'}" />~;
347        }
348        else {
349            $new =
350qq~<img src="$imagesdir/$brdimg_old" alt="$notify_txt{'334'}" title="$notify_txt{'334'}" />~;
351        }
352
353        ## output notify detail - option 3 = remove notify
354        $boardblock .= $my_boardblock;
355        $boardblock =~ s/{yabb brd}/$_/gsm;
356        $boardblock =~ s/{yabb new}/$new/gsm;
357        $boardblock =~ s/{yabb brdnote0}/${$$board_notify{$_}}[0]/gsm;
358        $boardblock =~ s/{yabb selected1}/$selected1/gsm;
359        $boardblock =~ s/{yabb selected2}/$selected2/gsm;
360    }
361
362    if ( !$num ) {    # no board notifies up
363        $my_showNotifications_b = $my_nonotes;
364    }
365    else {            # list boards
366        $my_showNotifications_b = $my_notebrdlist;
367        $my_showNotifications_b =~ s/{yabb boardblock}/$boardblock/gsm;
368    }
369
370    $num = 0;
371    foreach ( keys %{$thread_notify} )
372    { # mythread, msub, new, username_link, catname_link, boardname_link, lastpostdate
373        $num++;
374
375        ## build block for display
376        $threadblock .= $my_threadblock;
377        $threadblock =~ s/{yabb tnote0}/${$$thread_notify{$_}}[0]/gsm;
378        $threadblock =~ s/{yabb tnote1}/${$$thread_notify{$_}}[1]/gsm;
379        $threadblock =~ s/{yabb tnote2}/${$$thread_notify{$_}}[2]/gsm;
380        $threadblock =~ s/{yabb tnote3}/${$$thread_notify{$_}}[3]/gsm;
381        $threadblock =~ s/{yabb tnote4}/${$$thread_notify{$_}}[4]/gsm;
382        $threadblock =~ s/{yabb tnote5}/${$$thread_notify{$_}}[5]/gsm;
383        $threadblock =~ s/{yabb tnote6}/${$$thread_notify{$_}}[6]/gsm;
384    }
385
386    if ( !$num ) {    ## no threads listed
387        $my_showNotifications_t = $my_nothreads;
388    }
389    else {            ## output details
390        $my_showNotifications_t = $my_threadnote_b;
391        $my_showNotifications_t =~ s/{yabb threadblock}/$threadblock/gsm;
392    }
393    $showNotifications = $my_boardnote;
394
395    #    $showNotifications =~ s/{yabb note_brd}/$note_brd/sm;
396    $showNotifications =~ s/{yabb note_brd}//sm;
397    $showNotifications =~
398      s/{yabb my_showNotifications_b}/$my_showNotifications_b/sm;
399    $showNotifications =~
400      s/{yabb my_showNotifications_t}/$my_showNotifications_t/sm;
401    $showNotifications .= $my_threadnote_end;
402
403    $yytitle = "$notify_txt{'124'}";
404
405    ## and finally, add jump menu for a route back.
406    if ( !$view ) {
407        jumpto();
408        $yymain .= qq~$showNotifications$selecthtml~;
409        template();
410    }
411    return;
412}
413
414sub NotificationAlert {
415    my ( $myboard, %board_notify, $mythread, %thread_notify );
416
417    @bmaildir = split /,/xsm, ${ $uid . $username }{'board_notifications'};
418    @tmaildir = split /,/xsm, ${ $uid . $username }{'thread_notifications'};
419
420    # needed for $new - icon (on/off/new)
421    my @noloadboard =
422      grep { !exists ${ $uid . $_ }{'lastposttime'} } @allboards;
423    if (@noloadboard) { BoardTotals( 'load', @noloadboard ); }
424
425    # to get ${$uid.$myboard}{'lastposttime'}
426    getlog();    # sub in Subs.pm, for $yyuserlog{$myboard}
427    my $dmax = $date - ( $max_log_days_old * 86400 );
428
429    ## run through boards list
430    foreach my $myboard (@bmaildir) {    # board name from file name
431        if ( !-e "$boardsdir/$myboard.txt" )
432        {                             # remove from user board_notifications
433            ManageBoardNotify( 'delete', $myboard, $username );
434            next;
435        }
436
437        ## load in hash of name / detail for board
438        ManageBoardNotify( 'load', $myboard );
439
440        if ( exists $theboard{$username} ) {
441            ## grab board name
442            my $boardname = ( split /\|/xsm, $board{$myboard} )[0];
443
444            $board_notify{$myboard} = [
445                $boardname,
446                ( split /\|/xsm, $theboard{$username} )[1],    # boardnotifytype
447                (
448                    (
449                             $max_log_days_old
450                          && int( ${ $uid . $myboard }{'lastposttime'} )
451                          && (
452                            (
453                                !$yyuserlog{$myboard}
454                                && ${ $uid . $myboard }{'lastposttime'} > $dmax
455                            )
456                            || (   $yyuserlog{$myboard} > $dmax
457                                && $yyuserlog{$myboard} <
458                                ${ $uid . $myboard }{'lastposttime'} )
459                          )
460                    ) ? 1 : 0
461                ),    # new == 1
462            ];
463
464            undef %theboard;
465        }
466    }
467
468    if ( $action eq 'shownotify' ) { LoadCensorList(); }
469
470    ## load board names
471    get_forum_master();    # for $board{...}
472
473    foreach my $mythread (@tmaildir) {    # number of next thread
474            # see if thread exists and search for it if moved
475        if ( !-e "$datadir/$mythread.txt" ) {
476            ManageThreadNotify( 'delete', $mythread, $username );
477            if ( eval { require Variables::Movedthreads; 1 } ) {
478                next
479                  if !exists $moved_file{$mythread} || !$moved_file{$mythread};
480            my $newthread;
481            while ( exists $moved_file{$mythread} ) {
482                $mythread  = $moved_file{$mythread};
483                    if ( !exists $moved_file{$mythread}
484                        && -e "$datadir/$mythread.txt" )
485                    {
486                        $newthread = $mythread;
487                    }
488            }
489            next if !$newthread;
490                ManageThreadNotify( 'add', $newthread, $username,
491                ${ $uid . $username }{'language'},
492                1, 1 );
493        }
494        }
495
496        ## load threads hash
497        ManageThreadNotify( 'load', $mythread );
498
499        if ( exists $thethread{$username} ) {
500            ## load ctb file for board data
501            MessageTotals( 'load', $mythread );
502
503            ## pull out board and last post
504            my $boardid = ${$mythread}{'board'};
505            my ( $msub, $mname, $musername, $new, $username_link, $catname_link,
506                $boardname_link, $lastpostdate );
507            if ( $action eq 'shownotify' ) {
508                if ( !${ ${ 'notify' . $boardid . $mythread } }[0] ) {
509                    my ( $messageid, $messagesubject );
510                    fopen( BOARDTXT, "$boardsdir/$boardid.txt" )
511                      or fatal_error( 'cannot_open', "$boardsdir/$boardid.txt",
512                        1 );
513                    while ( my $brd = <BOARDTXT> ) {
514                        (
515                            $messageid, $messagesubject, $mname, undef, undef,
516                            undef, $musername, undef
517                        ) = split /\|/xsm, $brd, 8;
518                        ${ 'notify' . $boardid . $messageid } =
519                          [ $messagesubject, $mname, $musername ];
520                    }
521                    fclose(BOARDTXT);
522                }
523                $msub      = ${ ${ 'notify' . $boardid . $mythread } }[0];
524                $mname     = ${ ${ 'notify' . $boardid . $mythread } }[1];
525                $musername = ${ ${ 'notify' . $boardid . $mythread } }[2];
526
527                ToChars($msub);
528                ( $msub, undef ) = Split_Splice_Move( $msub, 0 );
529                $msub = Censor($msub);    # censor subject text !
530
531                ## run through the categories until we hit the match for category name
532                my ( $catname, $thiscatid, $catid );
533                my $boardname = ( split /\|/xsm, $board{$boardid} )[0];
534
535                # grab boardname from list
536              CHECKBOARDNAME: foreach my $catid (@categoryorder) {
537                    foreach ( split /\,/xsm, $cat{$catid} ) {
538                        ## find the match, grab data and jump out
539                        if ( $_ eq $boardid ) {
540                            $catname = ( split /\|/xsm, $catinfo{$catid} )[0];
541                            $thiscatid = $catid;
542                            last CHECKBOARDNAME;
543                        }
544                    }
545                }
546                $catname_link =
547                  qq~<a href="$scripturl?catselect=$thiscatid">$catname</a>~;
548                $boardname_link =
549                  qq~<a href="$scripturl?board=$boardid">$boardname</a>~;
550
551                ## build view profile link, if real name exists
552                LoadUser($musername);    # load poster
553                if ( ${ $uid . $musername }{'realname'} ) {
554                    $username_link =
555qq~<a href="$scripturl?action=viewprofile;username=$useraccount{$musername}">$format_unbold{$musername}</a>~;
556                }
557                elsif ($mname) {
558                    $username_link = $mname;
559                }
560                else {
561                    $username_link = $musername;
562                }
563
564                ## format last post for output
565                $lastpostdate = timeformat( ${$mythread}{'lastpostdate'} );
566            }
567
568            if ($max_log_days_old) {
569
570               # Decide if thread should have the "NEW" indicator next to it.
571               # Do this by reading the user's log for last read time on thread,
572               # and compare to the last post time on the thread.
573                my $dlp  = int $yyuserlog{$mythread};
574                my $dlpb = int $yyuserlog{"$boardid--mark"};
575                $dlp = $dlp > $dlpb ? $dlp : $dlpb;
576                if (   $yyuserlog{"$mythread--unread"}
577                    || ( !$dlp && ${$mythread}{'lastpostdate'} > $dmax )
578                    || ( $dlp > $dmax && $dlp < ${$mythread}{'lastpostdate'} ) )
579                {
580                    $new =
581qq~<img src="$imagesdir/$brdimg_new" alt="$notify_txt{'335'}" title="$notify_txt{'335'}"/>~;
582                }
583            }
584
585            $thread_notify{$mythread} = [
586                $mythread,      $msub,         $new,
587                $username_link, $catname_link, $boardname_link,
588                $lastpostdate
589            ];
590        }
591    }
592
593    return ( \%board_notify, \%thread_notify );
594}
595
5961;
597