~ubuntu-branches/ubuntu/lucid/boinc/lucid

« back to all changes in this revision

Viewing changes to html/inc/forum.inc

  • Committer: Bazaar Package Importer
  • Author(s): Frank S. Thomas, Frank S. Thomas
  • Date: 2008-05-31 08:02:47 UTC
  • mfrom: (1.1.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20080531080247-4ce890lp2rc768cr
Tags: 6.2.7-1
[ Frank S. Thomas ]
* New upstream release.
  - BOINC Manager: Redraw disk usage charts immediately after connecting to
    a (different) client. (closes: 463823)
* debian/copyright:
  - Added the instructions from debian/README.Debian-source about how
    repackaged BOINC tarballs can be reproduced because DevRef now
    recommends to put this here instead of in the afore-mentioned file.
  - Updated for the new release.
* Removed the obsolete debian/README.Debian-source.
* For consistency upstream renamed the core client and the command tool
  ("boinc_client" to "boinc" and "boinc_cmd" to "boinccmd"). Done the same
  in all packages and created symlinks with the old names for the binaries
  and man pages. Also added an entry in debian/boinc-client.NEWS explaining
  this change.
* debian/rules: Do not list Makefile.ins in the clean target individually,
  just remove all that can be found.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
<?php
2
 
$cvs_version_tracker[]="\$Id: forum.inc 12748 2007-05-26 17:00:01Z Rytis $";  //Generated automatically - do not edit
3
 
 
4
 
require_once('../inc/db.inc');
5
 
require_once('../inc/db_forum.inc');
6
 
require_once('../inc/time.inc');
7
 
require_once('../inc/forum_moderators.inc');
8
 
require_once('../inc/text_transform.inc');
9
 
require_once('../inc/util.inc');
10
 
require_once('../inc/forum_pm.inc');
 
2
 
 
3
require_once("../inc/forum_db.inc");
 
4
require_once("../inc/pm.inc");
 
5
require_once("../inc/team.inc");
 
6
require_once("../inc/text_transform.inc");
 
7
 
 
8
define('THREADS_PER_PAGE', 50);
 
9
 
 
10
// sorting styles
 
11
define('MODIFIED_NEW', 1);
 
12
define('MODIFIED_OLD',2);
 
13
define('VIEWS_MOST',3);
 
14
define('REPLIES_MOST',4);
 
15
define('CREATE_TIME_NEW',5);
 
16
define('CREATE_TIME_OLD',6);
 
17
define('POST_SCORE',7);
 
18
 
 
19
// names for the above
 
20
$thread_sort_styles[CREATE_TIME_OLD] = "Oldest post first";
 
21
$thread_sort_styles[CREATE_TIME_NEW] = "Newest post first";
 
22
$thread_sort_styles[POST_SCORE] = "Highest rated posts first";
 
23
 
 
24
$forum_sort_styles[MODIFIED_NEW] = "Newest reply first";
 
25
//$forum_sort_styles[MODIFIED_OLD] = "Oldest reply first";
 
26
$forum_sort_styles[VIEWS_MOST] = "Most views first";
 
27
$forum_sort_styles[REPLIES_MOST] = "Most posts first";
 
28
$forum_sort_styles[CREATE_TIME_NEW] = "Newest first";
 
29
//$forum_sort_styles[CREATE_TIME_OLD] = "Oldest first";
 
30
 
 
31
// values for thread.status
 
32
define('THREAD_SOLVED', 1);
11
33
 
12
34
define('AVATAR_WIDTH', 100);
13
35
define('AVATAR_HEIGHT',100);
14
36
 
15
 
$special_user_bitfield[0]="Forum moderator";
16
 
$special_user_bitfield[1]="Project administrator";
17
 
$special_user_bitfield[2]="Project developer";
18
 
$special_user_bitfield[3]="Project tester";
19
 
$special_user_bitfield[4]="Volunteer developer";
20
 
$special_user_bitfield[5]="Volunteer tester";
21
 
$special_user_bitfield[6]="Project scientist";
22
 
 
23
37
define('ST_NEW_TIME', 1209600); //3600*24*14 - 14 days
24
38
define('ST_NEW', 'New member');
25
39
 
26
 
define('MAXIMUM_EDIT_TIME',3600); //Maximally allow edits of forums posts up till one hour after posting.
 
40
define('MAXIMUM_EDIT_TIME',3600);
 
41
    // allow edits of forums posts up till one hour after posting.
27
42
 
28
 
define('FORUM_OPEN_LINK_IN_NEW_WINDOW',1);
29
43
define('MAX_FORUM_LOGGING_TIME', 2419200); //3600*24*28 - 28 days
30
44
define('NO_CONTROLS', 0);
31
45
define('FORUM_CONTROLS', 1);
58
72
define ('DEFAULT_LOW_RATING_THRESHOLD', -25);
59
73
define ('DEFAULT_HIGH_RATING_THRESHOLD', 5);
60
74
 
61
 
$thread_sort_styles['timestamp'] = "Newest first";
62
 
$thread_sort_styles['timestamp_asc'] = "Oldest first";
63
 
$thread_sort_styles['score'] = "Highest rated first";
64
 
 
65
 
$faq_sort_styles['create_time'] = "Most recent question first";
66
 
$faq_sort_styles['timestamp'] = "Most recent answer first";
67
 
$faq_sort_styles['activity'] = "Most frequently asked first";
68
 
 
69
 
$answer_sort_styles['score'] = "Highest score first";
70
 
$answer_sort_styles['timestamp'] = "Most recent first";
71
 
$answer_sort_styles['timestamp_asc'] = "Oldest first";
72
 
 
73
 
$thread_filter_styles['2'] = "\"Very helpful\"";
74
 
$thread_filter_styles['1'] = "At least \"helpful\"";
75
 
$thread_filter_styles['0'] = "At least \"neutral\"";
76
 
$thread_filter_styles['-1'] = "At least \"unhelpful\"";
77
 
$thread_filter_styles['-2'] = "All posts";
78
 
 
79
 
$post_ratings['2'] = "Very helpful (+2)";
80
 
$post_ratings['1'] = "Helpful (+1)";
81
 
$post_ratings['0'] = "Neutral";
82
 
$post_ratings['-1'] = "Not helpful (-1)";
83
 
$post_ratings['-2'] = "Off topic (-2)";
84
 
 
85
 
$config = get_config();
86
 
$no_forum_rating = parse_bool($config, "no_forum_rating"); 
87
 
 
88
 
/**
89
 
 *  Process a user-supplied title to remove HTML stuff
90
 
 **/
 
75
// A list of what kind of special users exist
 
76
define('S_MODERATOR', 0);
 
77
define('S_ADMIN', 1);
 
78
define('S_DEV', 2);
 
79
define('S_TESTER', 3);
 
80
define('S_VOLUNTEER', 4);
 
81
define('S_VOLUNTEER_TESTER', 5);
 
82
define('S_SCIENTIST', 6);
 
83
 
 
84
$special_user_bitfield[S_MODERATOR]="Forum moderator";
 
85
$special_user_bitfield[S_ADMIN]="Project administrator";
 
86
$special_user_bitfield[S_DEV]="Project developer";
 
87
$special_user_bitfield[S_TESTER]="Project tester";
 
88
$special_user_bitfield[S_VOLUNTEER]="Volunteer developer";
 
89
$special_user_bitfield[S_VOLUNTEER_TESTER]="Volunteer tester";
 
90
$special_user_bitfield[S_SCIENTIST]="Project scientist";
 
91
 
 
92
// show a banner with search form on left and PM info on right
 
93
//
 
94
function show_forum_header($user) {
 
95
    start_table_noborder();
 
96
    echo "<tr>\n";
 
97
    
 
98
    // Search
 
99
    echo "<td><form action=\"forum_search_action.php\" method=\"POST\">
 
100
        <input type=\"hidden\" name=\"search_max_time\" value=\"30\">
 
101
        <input type=\"hidden\" name=\"search_forum\" value=\"-1\">
 
102
        <input type=\"hidden\" name=\"search_sort\" value=\"5\">
 
103
        <input type=\"text\" name=\"search_keywords\">
 
104
        <input class=\"btn\" title=\"".tra("Search for words in forum messages")."\" type=\"submit\" value=\"".tra("Search forums")."\"><br>
 
105
        <span class=\"smalltext\"><a href=\"forum_search.php\">".tra("Advanced search")."</a></span>
 
106
        </form>
 
107
    ";
 
108
    echo "</td>\n";
 
109
    
 
110
    if ($user) {
 
111
        echo "<td align=\"right\">\n";
 
112
        echo "<p>".tra("Private messages").": ", pm_notification($user);
 
113
        echo "</td>\n";
 
114
    }
 
115
    echo "</tr>\n";
 
116
    end_table();
 
117
}
 
118
 
 
119
// Output the forum/thread title.
 
120
//
 
121
function show_forum_title($category, $forum, $thread, $link_thread=false) {
 
122
    if ($category) {
 
123
        $is_helpdesk = $category->is_helpdesk;
 
124
    } else {
 
125
        $is_helpdesk = false;
 
126
    }
 
127
    $where = $is_helpdesk?tra("Questions and Answers"):tra("Message boards");
 
128
    $top_url = $is_helpdesk?"forum_help_desk.php":"forum_index.php";
 
129
    if (!$forum && !$thread) {
 
130
        echo "<span class=\"title\">$where</span>";
 
131
 
 
132
    } else if ($forum && !$thread) {
 
133
        echo "<span class=title>";
 
134
        echo "<a href=\"$top_url\">$where</a> : ";
 
135
        echo $forum->title;
 
136
        echo "</span>";
 
137
    } else if ($forum && $thread) {
 
138
        echo "<span class=title>
 
139
            <a href=\"$top_url\">$where</a> : 
 
140
            <a href=\"forum_forum.php?id=".$forum->id."\">", $forum->title, "</a> : 
 
141
        ";
 
142
        if ($link_thread) {
 
143
            echo "<a href=forum_thread.php?id=$thread->id>";
 
144
        }
 
145
        echo cleanup_title($thread->title);
 
146
        if ($link_thread) {
 
147
            echo "</a>";
 
148
        }
 
149
        echo "</span>";
 
150
    } else {
 
151
        echo "Invalid input to show_forum_title<br>";
 
152
        echo "threadid $thread->id";
 
153
        // TODO: handle this condition gracefully 
 
154
    }
 
155
}
 
156
 
 
157
function show_team_forum_title($forum, $thread=null, $link_thread=false) {
 
158
    $team = BoincTeam::lookup_id($forum->category);
 
159
    echo "<span class=title>
 
160
        <a href=\"forum_index.php\">".tra("Message boards")."</a> :
 
161
    ";
 
162
    if ($thread) {
 
163
        echo "
 
164
            <a href=team_forum.php?teamid=$team->id>".tra("%1 message board", $team->name)."</a>
 
165
        ";
 
166
        if ($link_thread) {
 
167
            echo " : <a href=forum_thread.php?id=$thread->id>$thread->title</a>";
 
168
        } else {
 
169
            echo " : $thread->title";
 
170
        }
 
171
    } else {
 
172
        echo tra("%1 message board", $team->name);
 
173
    }
 
174
    echo "</span>";
 
175
}
 
176
 
 
177
// Start the forum table, output the proper headings and such.
 
178
//
 
179
function start_forum_table($headings, $extra="width=\"100%\"") {
 
180
    $span = null;
 
181
    
 
182
    start_table($extra." cellspacing=\"0\"");
 
183
    echo "<tr>";
 
184
 
 
185
    for ($i=0; $i<count($headings); $i++) {
 
186
        if (is_array($headings[$i])){
 
187
            $title = $headings[$i][0];
 
188
            $class = $headings[$i][1]?$headings[$i][1]:"heading";
 
189
            if (isset($headings[$i][2])) {
 
190
                $span = " colspan=\"".$headings[$i][2]."\" ";
 
191
            }
 
192
        } else {
 
193
            $title = $headings[$i];
 
194
            $class = "heading";
 
195
            $span="";
 
196
        }
 
197
        echo "<th class=$class$span>$title</th>";
 
198
    }
 
199
    echo "</tr>\n";
 
200
}
 
201
 
 
202
// return a string containing a paged navigation bar 
 
203
// for the given forum.  The default start place is 0. 
 
204
//
 
205
function show_page_nav($forum, $start=0){
 
206
    // How many pages to potentially show before and after this one:
 
207
    $preshow = 5; $postshow = 10;
 
208
    $navbar = "";
 
209
    
 
210
    if ($forum->threads > THREADS_PER_PAGE) {
 
211
        $total = ceil($forum->threads / THREADS_PER_PAGE);
 
212
        $curpage = ceil($start / THREADS_PER_PAGE);
 
213
        // If this is not the first page, display "previous"
 
214
        if ($curpage > 0){
 
215
            $navbar = '<a href="forum_forum.php?id='.get_int("id").'&start='.(($curpage-1)*THREADS_PER_PAGE);
 
216
            $sort = get_int("sort",true);
 
217
            if ($sort) $navbar.='&sort='.$sort;
 
218
            $navbar.= '"> &lt;-- Previous</a> ';
 
219
        }
 
220
        
 
221
        // Display a list of pages surrounding this one
 
222
        for ($i=$curpage-$preshow;$i<($curpage+$postshow);$i++){
 
223
            if ($i<1) continue;
 
224
            if ($i>$total) break;
 
225
            // If this is the current page, emphasize it.
 
226
            if ($i == $curpage+1){
 
227
                $navbar.="<em>";
 
228
            }
 
229
            $navbar.='<a href="forum_forum.php?id='.get_int("id").'&start='.(($i-1)*THREADS_PER_PAGE);
 
230
            $sort = get_int("sort",true);
 
231
            if ($sort) $navbar.='&sort='.$sort;
 
232
            $navbar.='">'.$i.' |</a> ';
 
233
            if ($i == $curpage+1){$navbar.="</em>";}
 
234
        }
 
235
 
 
236
        // If there is a next page
 
237
        if ($curpage+1 < $total){
 
238
            $navbar.= '<a href="forum_forum.php?id='.get_int("id").'&start='.(($curpage+1)*THREADS_PER_PAGE);
 
239
            $sort = get_int("sort",true);
 
240
            if ($sort) $navbar.='&sort='.$sort;
 
241
            $navbar.= '"> Next --&gt;</a>';
 
242
        }
 
243
 
 
244
    }
 
245
    return $navbar;
 
246
}
 
247
 
 
248
function thread_last_visit($user, $thread) {
 
249
    if (!$user) return false;
 
250
    $log = BoincForumLogging::lookup($user->id, $thread->id);
 
251
    return $log->timestamp;
 
252
}
 
253
 
 
254
function thread_is_unread($user, $thread) {
 
255
    if (!$user) return false;
 
256
    if ($thread->timestamp < $user->prefs->mark_as_read_timestamp) return false;
 
257
    $log = BoincForumLogging::lookup($user->id, $thread->id);
 
258
    if ($log && ($thread->timestamp < $log->timestamp)) return false;
 
259
    return true;
 
260
}
 
261
 
 
262
//  Process a user-supplied title to remove HTML stuff
 
263
//
91
264
function cleanup_title($title) {
92
265
    $x = trim(htmlspecialchars($title));
93
266
    $x = stripslashes($x);      // clean up funky old titles in DB
95
268
    else return $x;
96
269
}
97
270
 
98
 
/** 
99
 
 * Check if user has special user bit enabled
100
 
 **/
101
 
function isSpecialUser($user, $specialbit){
102
 
    return (substr($user->special_user, $specialbit,1)==1);
103
 
}
104
 
 
105
 
/**
106
 
 * Check to see if a specific user has rated a specific post before
107
 
 **/
108
 
function getHasRated($user, $postid){
109
 
    return (strstr($user->rated_posts,"|".$postid));
110
 
}
111
 
 
112
 
/**
113
 
 * Get the user's preferred sorting style.
114
 
 **/
115
 
function getSortStyle($user,$place){
116
 
    if ($user->id!=""){
117
 
        list($forum,$thread,$faq,$answer)=explode("|",$user->sorting);
 
271
function can_reply($thread, $forum, $user) {
 
272
    if ($thread->locked) {
 
273
        if (!is_moderator($user, $forum)) return false;
 
274
    }
 
275
    return true;
 
276
}
 
277
 
 
278
function should_show_post(
 
279
    $logged_in_user, $postcount, $postnumber, $post, $sort_style, $last_visit
 
280
){
 
281
    $no_wraparound = get_str("nowrap",true);
 
282
 
 
283
    // If no user logged in, display everything (useful for Google bots etc)
 
284
    //
 
285
    if (!$logged_in_user) return true;
 
286
            
 
287
    // If the user hasn't enabled the feature to display only
 
288
    // a certain amount of posts, simply display all of them.
 
289
    //
 
290
    if (!$logged_in_user->prefs->minimum_wrap_postcount) return true;
 
291
                    
 
292
    // If the user has asked to display all the posts just display them
 
293
    //
 
294
    if ($no_wraparound) return true;
 
295
            
 
296
    // If it is enabled and we havent yet hit the limit, simply display all
 
297
    if ($postcount < $logged_in_user->prefs->minimum_wrap_postcount) return true;
 
298
                                    
 
299
    // display the post if it is the first post
 
300
    //
 
301
    if ($postnumber==1 || $postnumber==($postcount+1)) return true;
 
302
                                    
 
303
    // if this post is unread, show it
 
304
    //
 
305
    if ($post->timestamp > $last_visit) return true;
 
306
                                                    
 
307
    // The user can choose to display the last X posts in a thread only,
 
308
    // "last" here depends on sorting criteria:
 
309
    //
 
310
    if ($sort_style == CREATE_TIME_OLD){
 
311
        if ($postnumber > $postcount+1-$logged_in_user->prefs->display_wrap_postcount) return true;
 
312
    } else if ($sort_style == CREATE_TIME_NEW){
 
313
        if ($postnumber <= $logged_in_user->prefs->display_wrap_postcount) return true;
118
314
    } else {
119
 
        list($forum,$thread,$faq,$answer)=explode("|",$_COOKIE['sorting']);
 
315
        // For other sorting criteria we do not know how to define "last"
 
316
        // so simply display it all
 
317
        //
 
318
        return true;
120
319
    }
121
 
    return $$place;    // Huh?
 
320
    
 
321
    // In all other cases we should not show this particular post
 
322
    return false;
122
323
}
123
324
 
124
 
 
125
 
/*** display functions ***/
126
 
 
127
 
/**
128
 
 * Show the posts in a thread for a user.
129
 
 * It's a big one.
130
 
 **/
131
 
function show_posts($thread, $sort_style, $filter, $logged_in_user, $show_controls=true) {
 
325
// Show the posts in a thread for a user.
 
326
//
 
327
function show_posts(
 
328
    $thread, $forum, $sort_style, $filter, $logged_in_user, $show_controls=true
 
329
) {
132
330
    $n = 1;
133
 
 
 
331
    $first_unread_post = null;
 
332
    $last_visit = 0;
 
333
    
134
334
    if ($show_controls) {
135
335
        $controls = FORUM_CONTROLS;
136
336
    } else {
139
339
 
140
340
    // If logged in user is moderator,
141
341
    // let him see all posts - including hidden ones
142
 
    if ($logged_in_user && $logged_in_user->isSpecialUser(S_MODERATOR)){
143
 
        $show_hidden_posts = true;
 
342
    //
 
343
    if (is_moderator($logged_in_user, $forum)) {
 
344
        $show_hidden = true;
144
345
    } else {
145
 
        $show_hidden_posts = false;
 
346
        $show_hidden = false;
146
347
    }
147
 
    $posts = $thread->getPosts($sort_style, $show_hidden_posts);
 
348
    $posts = get_thread_posts($thread->id, $sort_style, $show_hidden);
148
349
    $postcount = (sizeof($posts)-1);
149
 
    if ($logged_in_user) $last_visit = $thread->getLastReadTimestamp($logged_in_user);
 
350
    if ($logged_in_user) {
 
351
        $last_visit = thread_last_visit($logged_in_user, $thread);
 
352
    }
150
353
 
151
354
    $postnumber=0; $previous_post=0;
152
355
    $no_wraparound = get_str("nowrap",true);
153
 
    foreach ($posts as $key => $post){
154
 
            $postnumber++;
155
 
            
156
 
            // There *HAS* to be a better way to do this.  WOW.
157
 
            if ((!$logged_in_user) // If the user isn't logged in
158
 
                || (!$logged_in_user->getMinimumWrapPostcount()) //or If the user hasn't enabled the feature to display only a certain amount of posts, simply display all of them.
159
 
                || ($postcount < $logged_in_user->getMinimumWrapPostcount()) //If it is enabled and we havent yet hit the limit, simply display all
160
 
                || ($no_wraparound)  // If the user has asked to display all the posts just display them
161
 
                ||
162
 
                (
163
 
                    ($postcount >= $logged_in_user->getMinimumWrapPostcount()) //If it is enabled and we have hit the limit AND we have the minimum wraparound number of posts or more
164
 
                    &&
165
 
                    (
166
 
                        ($postnumber==1 || $postnumber==($postcount+1)) // Let's display the post only if it is the first post 
167
 
                        || 
168
 
                        (        
169
 
                            (($postnumber > $postcount+1-$logged_in_user->getDisplayWrapPostcount()) //or it is one of the last wrap_display_postcount posts.
170
 
                            && ($sort_style==CREATE_TIME_OLD))
171
 
                            ||
172
 
                            (($postnumber <= $logged_in_user->getDisplayWrapPostcount()) //or it is one of the last wrap_display_postcount posts.
173
 
                            && ($sort_style==CREATE_TIME_NEW))
174
 
                            || ($sort_style!=CREATE_TIME_NEW && $sort_style!=CREATE_TIME_OLD)
175
 
                        )  
176
 
                        || ($post->getTimestamp() > $last_visit) //or if this post is unread
177
 
                    )
178
 
                )
179
 
            ) {
180
 
                if ($postnumber!=$previous_post+1){
181
 
                    //A number of posts were hidden, display a way to unhide them:
182
 
                    echo "<tr class=\"postseperator\"><td></td><td colspan=\"2\">
183
 
                    Only the first post and the last ".($logged_in_user->getDisplayWrapPostcount())." posts 
 
356
    foreach ($posts as $post){
 
357
        $postnumber++;
 
358
        if (should_show_post(
 
359
            $logged_in_user, $postcount, $postnumber, $post,
 
360
            $sort_style, $last_visit)
 
361
        ) {
 
362
 
 
363
            if ($postnumber!=$previous_post+1){
 
364
                // A number of posts were hidden, display a way to unhide them:
 
365
                //
 
366
                echo "<tr class=\"postseperator\"><td></td><td colspan=\"2\">
 
367
                    Only the first post and the last ".($logged_in_user->prefs->display_wrap_postcount)." posts 
184
368
                    (of the ".($postcount+1)." posts in this thread) are displayed. <br />
185
 
                    <a href=\"?id=".$thread->getID()."&amp;nowrap=true\">Click here to also display the remaining posts</a>.</td></tr>";
186
 
                }
187
 
                $previous_post=$postnumber;
188
 
                show_post($post, $thread, $logged_in_user, $n, $controls, $filter);
189
 
                // To allow users to start reading a thread even though our DB layer is super slow
190
 
                $n = ($n+1)%2;
191
 
                
192
 
                if (($post->getTimestamp()>$last_visit) && 
193
 
                    ((!$first_unread_post) || ($post->getTimestamp()<$first_unread_post->getTimestamp()))
194
 
                   ){
195
 
                    $first_unread_post=$post;
196
 
                }
197
 
            }
 
369
                    <a href=\"?id=".$thread->id."&amp;nowrap=true\">Click here to also display the remaining posts</a>.</td></tr>
 
370
                ";
 
371
            }
 
372
            $previous_post=$postnumber;
 
373
            show_post($post, $thread, $forum, $logged_in_user, $last_visit, $n, $controls, $filter);
 
374
            $n = ($n+1)%2;
 
375
            
 
376
            if (($post->timestamp>$last_visit) && 
 
377
                ((!$first_unread_post) || ($post->timestamp<$first_unread_post->timestamp))
 
378
               ){
 
379
                $first_unread_post=$post;
 
380
            }
 
381
        }
198
382
    }
199
383
 
200
 
    if ($logged_in_user && $logged_in_user->hasJumpToUnread()){
 
384
    if ($logged_in_user && $logged_in_user->prefs->jump_to_unread){
201
385
        if ($first_unread_post){
202
 
            echo "<script>function jumpToUnread(){location.href='#".$first_unread_post->getID()."';}</script>";
 
386
            echo "<script>function jumpToUnread(){location.href='#".$first_unread_post->id."';}</script>";
203
387
        } else {
204
388
            echo "<script>function jumpToUnread(){};</script>";
205
389
        }
206
390
    }
207
391
 
208
 
    if ($logged_in_user) $thread->setLastReadTimestamp($logged_in_user);
209
 
}
210
 
 
211
 
/**
212
 
 * Display an individual post, as though in a thread.
213
 
 **/
214
 
function show_post($post, $thread, $logged_in_user, $n, $controls=FORUM_CONTROLS, $filter=true) {
215
 
    $user = $post->getOwner();
216
 
    global $no_forum_rating;
217
 
    global $config;
218
 
 
219
392
    if ($logged_in_user) {
220
 
        $tokens = url_tokens($logged_in_user->getAuthenticator());
221
 
    }
222
 
 
223
 
    //If the user that made this post is on the list of people to ignore, change thresholds to be much more strict
 
393
        BoincForumLogging::replace($logged_in_user->id, $thread->id, time());
 
394
    }
 
395
}
 
396
 
 
397
function get_ignored_list($user) {
 
398
    return explode("|", $user->prefs->ignorelist);
 
399
}
 
400
 
 
401
function add_ignored_user($user, $other_user) {
 
402
    $list = explode("|", $user->prefs->ignorelist);
 
403
    foreach ($list as $key=>$userid) {
 
404
        if ($userid == $other_user->id) {
 
405
            return true;
 
406
        }
 
407
    }
 
408
    $list[] = $other_user->id;
 
409
    $x = implode("|", array_values($list));
 
410
    return $user->prefs->update("ignorelist='$x'");
 
411
}
 
412
 
 
413
function remove_ignored_user($user, $other_user) {
 
414
    $list = explode("|", $user->prefs->ignorelist);
 
415
    foreach ($list as $key=>$userid) {
 
416
        if ($userid == $other_user->id) {
 
417
            unset($list[$key]);
 
418
        }
 
419
    }
 
420
    $x = implode("|", array_values($list));
 
421
    return $user->prefs->update("ignorelist='$x'");
 
422
}
 
423
 
 
424
function is_ignoring($user, $other_user) {
 
425
    $list = explode("|", $user->prefs->ignorelist);
 
426
    return in_array($other_user->id, $list);
 
427
}
 
428
 
 
429
// Display an individual post
 
430
//
 
431
function show_post(
 
432
    $post, $thread, $forum, $logged_in_user, $last_visit, $n, $controls=FORUM_CONTROLS, $filter=true
 
433
) {
 
434
    $user = BoincUser::lookup_id($post->user);
 
435
    BoincForumPrefs::lookup($user);
 
436
    if (is_banished($user) && !is_moderator($logged_in_user, $forum)) {
 
437
        return;
 
438
    }
 
439
 
 
440
    $config = get_config();
 
441
    $no_forum_rating = parse_bool($config, "no_forum_rating");
 
442
 
 
443
    $tokens = "";
 
444
    $rated_below_threshold = false;
 
445
    $rated_above_threshold = false;
 
446
    $options = get_output_options($logged_in_user);
 
447
 
 
448
    //If the user that made this post is on the list of people to ignore,
 
449
    // change thresholds to be much more strict
 
450
    //
224
451
    if ($logged_in_user){
225
 
        if (in_array($user->getID(),$logged_in_user->getIgnoreList())){
 
452
        $tokens = url_tokens($logged_in_user->authenticator);
 
453
        if (is_ignoring($logged_in_user, $user)){
226
454
            $user_is_on_ignorelist=true;
227
 
            $rated_below_threshold = ($logged_in_user->getHighRatingThreshold()>$post->getRating());
228
 
            $rated_above_threshold = ($logged_in_user->getHighRatingThreshold()+abs($logged_in_user->getLowRatingThreshold())<($post->getRating()));
 
455
            $rated_below_threshold = ($logged_in_user->prefs->high_rating_threshold>$post->rating());
 
456
            $rated_above_threshold = ($logged_in_user->prefs->high_rating_threshold+abs($logged_in_user->prefs->low_rating_threshold)<($post->rating));
229
457
        } else {                //Use normal threshold values
230
 
            $rated_below_threshold = ($logged_in_user->getLowRatingThreshold()>($post->getRating()));
231
 
            $rated_above_threshold = ($logged_in_user->getHighRatingThreshold()<($post->getRating()));
 
458
            $rated_below_threshold = ($logged_in_user->prefs->low_rating_threshold>($post->rating()));
 
459
            $rated_above_threshold = ($logged_in_user->prefs->high_rating_threshold<($post->rating()));
232
460
        }
233
461
    }
 
462
 
234
463
    // The creator can edit the post, but only in a specified amount of time
235
464
    // (exception: a moderator can edit his/her posts at any time)
236
465
    //
237
466
    $can_edit = false;
238
467
    if ($logged_in_user) {
239
 
        if ($user->getID() == $logged_in_user->getID()) {
240
 
            if ($logged_in_user->isSpecialUser(S_MODERATOR)) {
 
468
        if ($user->id == $logged_in_user->id) {
 
469
            if (is_moderator($logged_in_user, $forum)) {
241
470
                $can_edit = true;
242
 
            } else if (can_reply($thread, $logged_in_user)) {
243
 
                $time_limit = $post->getTimestamp()+MAXIMUM_EDIT_TIME;
 
471
            } else if (can_reply($thread, $forum, $logged_in_user)) {
 
472
                $time_limit = $post->timestamp+MAXIMUM_EDIT_TIME;
244
473
                $can_edit = time()<$time_limit;
245
474
            } else {
246
475
                $can_edit = false;
249
478
    }
250
479
 
251
480
    echo "
252
 
        <tr class=\"row$n\" valign=\"top\">
253
 
        <td rowspan=\"3\"><div class=\"authorcol\">
254
 
        <a name=\"".$post->getID()."\"></a>
 
481
        <tr class=\"row".$n."\" valign=\"top\">
 
482
        <td rowspan=\"3\"><a name=\"".$post->id."\"></a><div class=\"authorcol\">
255
483
    ";
256
484
 
257
 
    // Print the user links
258
 
    echo re_user_links($user, URL_BASE);
 
485
    echo user_links($user);
259
486
    echo "<br>";
260
487
 
261
488
    // Print the special user lines, if any
263
490
    $fstatus="";
264
491
    $keys = array_keys($special_user_bitfield);
265
492
    for ($i=0; $i<sizeof($special_user_bitfield);$i++) {
266
 
        if ($user->isSpecialUser($keys[$i])) {
 
493
        if ($user->prefs->privilege($keys[$i])) {
267
494
            $fstatus.=$special_user_bitfield[$keys[$i]]."<br>";
268
495
        }
269
496
    }
270
 
    if ($user->create_time>time()-ST_NEW_TIME) $fstatus.=ST_NEW."<br>";
 
497
    if ($user->create_time > time()-ST_NEW_TIME) $fstatus.=ST_NEW."<br>";
271
498
    if ($fstatus) echo "<font size=\"-2\">$fstatus</font>";
272
499
 
273
500
    echo "<span class=\"authorinfo\">";
274
501
    if (!$filter || !$rated_below_threshold){
275
 
        if ($user->hasAvatar() && (!$logged_in_user || ($logged_in_user->hasHideAvatars()==false))) {
276
 
            echo "<img width=\"".AVATAR_WIDTH."\" height=\"".AVATAR_HEIGHT."\" src=\"".$user->getAvatar()."\" alt=\"Avatar\"><br>";
 
502
        if ($user->prefs->avatar!=""  && (!$logged_in_user || ($logged_in_user->prefs->hide_avatars==false))) {
 
503
            echo "<img width=\"".AVATAR_WIDTH."\" height=\"".AVATAR_HEIGHT."\" src=\"".$user->prefs->avatar."\" alt=\"Avatar\"><br>";
277
504
        }
278
505
    }
279
506
    
280
 
    echo "<a href=\"forum_pm.php?action=new&userid=".$user->getID()."\" class=\"smalltext\">private message</a><br>\n";
281
 
    echo "Joined: ", gmdate('M j, Y', $user->getCreateTime()), "<br>";
 
507
    $url = "pm.php?action=new&userid=".$user->id;
 
508
    $name = $user->name;
 
509
    show_button($url, "Send message", "Send $name a private message");
 
510
    echo "<br>Joined: ", gmdate('M j y', $user->create_time), "<br>";
 
511
 
 
512
    if (!isset($user->nposts)) {
 
513
        $user->nposts = BoincPost::count("user=$user->id");
 
514
    }
282
515
    
283
516
    if(function_exists('project_forum_user_info')){
284
517
        project_forum_user_info($user);
285
518
    } else { // default
286
519
        // circumvent various forms of identity spoofing
287
520
        // by displaying the  user id of the poster.
288
 
        // its cheap, easy, and doesn't require any additional database calls.
289
 
        echo "Posts: ".$user->getPostCount()."<br>";
290
 
        echo "ID: ".$user->getID()."<br>";
291
 
        echo "Credit: ".number_format($user->getTotalCredit())."<br>";
292
 
        echo "RAC: ".number_format($user->getExpavgCredit())."<br>";
 
521
        //
 
522
        echo "Posts: $user->nposts<br>";
 
523
        echo "ID: ".$user->id."<br>";
 
524
        echo "Credit: ".number_format($user->total_credit)."<br>";
 
525
        echo "RAC: ".number_format($user->expavg_credit)."<br>";
293
526
    }
294
527
    echo "</span></div></td>";
295
528
 
296
529
    if ($controls == FORUM_CONTROLS) {
297
 
        echo "<form action=\"forum_rate.php?post=", $post->getID(), "\" method=\"post\">";
298
530
        echo "<td colspan=\"2\" class=\"postheader\">";
 
531
        echo "<form action=\"forum_rate.php?post=", $post->id, "\" method=\"post\">";
299
532
    } else {
300
533
        echo "<td class=\"postheader\">";
301
534
    }
302
535
 
303
 
    if ($logged_in_user && $post->getTimestamp()>$thread->getLastReadTimestamp($logged_in_user)){
304
 
        echo "<img src=\"".NEW_IMAGE."\" alt=\"Unread post\" height=\"".NEW_IMAGE_HEIGHT."\">";
 
536
    if ($logged_in_user && $post->timestamp>$last_visit){
 
537
        show_image(NEW_IMAGE, "You haven't read this message yet", "Unread", NEW_IMAGE_HEIGHT);
305
538
    }
306
539
    if ($rated_above_threshold){
307
 
        echo "<img src=\"".EMPHASIZE_IMAGE."\" alt=\"!\" height=\"".EMPHASIZE_IMAGE_HEIGHT."\">";
 
540
        show_image(EMPHASIZE_IMAGE, "This message has a high average rating", "Highly rated", EMPHASIZE_IMAGE_HEIGHT);
308
541
    }
309
542
 
310
 
    echo " <a href=\"forum_thread.php?id=".$thread->getID()."&nowrap=true#$post->id\">Message ".$post->getID()."</a> - ";
311
 
    if ($post->isHidden()) echo "<font color=red>[deleted] </font>";
 
543
    echo " <a href=\"forum_thread.php?id=".$thread->id."&nowrap=true#$post->id\">Message ".$post->id."</a> - ";
 
544
    if ($post->hidden) echo "<font color=red>[hidden] </font>";
312
545
    echo "
313
 
        Posted ", pretty_time_str($post->getTimestamp());
 
546
        Posted ", pretty_time_str($post->timestamp);
314
547
    ;
315
548
 
316
 
    if ($post->getParentPostID()) echo " - in response to <a href=\"forum_thread.php?id=".$thread->getID()."&nowrap=true#".$post->getParentPostID()."\">Message ID ".$post->getParentPostID()."</a>.";
317
 
    if ($can_edit && $controls != NO_CONTROLS) echo "&nbsp;<a href=\"forum_edit.php?id=".$post->getID()."$tokens\">[Edit this post]</a>";
318
 
    if ($logged_in_user && $logged_in_user->isSpecialUser(S_MODERATOR)) echo post_moderation_links($config,$logged_in_user,$post,$tokens); //If user is moderator, show links
319
 
    if ($post->getModificationTimestamp()) echo "<br>Last modified: ", pretty_time_Str($post->getModificationTimestamp());
 
549
    if ($post->parent_post) {
 
550
        echo " - in response to <a href=\"forum_thread.php?id=".$thread->id."&nowrap=true#".$post->parent_post."\">Message ID ".$post->parent_post."</a>.";
 
551
    }
 
552
    echo " ";
 
553
    if ($can_edit && $controls != NO_CONTROLS) {
 
554
        show_button("forum_edit.php?id=".$post->id."$tokens", "Edit", "Edit this message");
 
555
    }
 
556
    if (is_moderator($logged_in_user, $forum)) {
 
557
        show_post_moderation_links($config, $logged_in_user, $post, $forum, $tokens);
 
558
    }
 
559
    if ($post->modified) {
 
560
        echo "<br>Last modified: ", pretty_time_Str($post->modified);
 
561
    }
320
562
    if ($rated_below_threshold && $filter){
321
 
        if ($user_is_on_ignorelist) $andtext=" and the user is on your ignore list";
322
 
        echo "<br>This post has been filtered (rating: ".($post->getRating()).")$andtext, press <a href=\"?id=".$thread->getID()."&amp;filter=false#".$post->getID()."\">here</a> to view this thread without filtering";
 
563
        if ($user_is_on_ignorelist) {
 
564
            $andtext=" and the user is on your ignore list";
 
565
        }
 
566
        echo "<br>This post has been filtered (rating: ".($post->rating()).")$andtext, press <a href=\"?id=".$thread->id."&amp;filter=false#".$post->id."\">here</a> to view this thread without filtering";
323
567
    }
324
568
    echo "</td></tr></form>";
325
569
    echo "<tr class=\"row$n\"><td class=\"postbody\" colspan=\"2\">";
326
570
 
327
 
    //If either filtering is turned off or this post is not below the threshold
328
571
    if (!$filter || !$rated_below_threshold){
329
 
        $posttext = $post->getContent();
 
572
        $posttext = $post->content;
330
573
 
331
574
        // If the creator of this post has a signature and
332
575
        // wants it to be shown for this post AND the logged in
333
576
        // user has signatures enabled: show it
334
577
        //
335
 
        if ($post->hasSignature() && (!$logged_in_user || !$logged_in_user->hasHideSignatures())){
336
 
            $posttext.="\n____________\n".$user->getSignature();
 
578
        if ($post->signature && (!$logged_in_user || !$logged_in_user->prefs->hide_signatures)){
 
579
            $posttext.="\n____________\n".$user->prefs->signature;
337
580
        }
338
581
 
339
 
        if ($logged_in_user){
340
 
            $options = $logged_in_user->getTextTransformSettings();
341
 
        } else {
342
 
            $options = new output_options;
343
 
        }
344
 
        $posttext = output_transform($posttext,$options);
 
582
        $posttext = output_transform($posttext, $options);
345
583
        
346
584
        echo "<p>", $posttext, "</p>";
347
585
        echo "</td></tr><tr><td class=\"postfooter\">ID: <i>", $post->id;
348
586
        if ($no_forum_rating != NULL) { 
349
 
            echo " | <a href=\"forum_report_post.php?post=".$post->getID()."\"><img src=\"".REPORT_POST_IMAGE."\" alt=\"Report this post as offensive\" height=\"".REPORT_POST_IMAGE_HEIGHT."\" border=0></a></td>";
 
587
            echo " | <a href=\"forum_report_post.php?post=".$post->id."\">";
 
588
            show_image(REPORT_POST_IMAGE, "Report this post as offensive", "Report as offensive", REPORT_POST_IMAGE_HEIGHT);
 
589
            echo "</td>";
350
590
        } else {
351
 
        $rating = $post->getRating();
352
 
        echo " | Rating: ", $rating, "</i> | rate: <a href=\"forum_rate.php?post=".$post->getID()."&amp;choice=p$tokens\"><img src=\"".RATE_POSITIVE_IMAGE."\" alt=\"+\" height=\"".RATE_POSITIVE_IMAGE_HEIGHT."\" border=0></a> / <a href=\"forum_rate.php?post=".$post->getID()."&amp;choice=n$tokens\"><img src=\"".RATE_NEGATIVE_IMAGE."\" alt=\"-\" height=\"".RATE_NEGATIVE_IMAGE_HEIGHT."\" border=0></a> - <a href=\"forum_report_post.php?post=".$post->getID()."\"><img src=\"".REPORT_POST_IMAGE."\" alt=\"Report this post as offensive\" height=\"".REPORT_POST_IMAGE_HEIGHT."\" border=0></a></td>";
 
591
            $rating = $post->rating();
 
592
            echo " | Rating: ", $rating, "</i> | rate: 
 
593
                <a href=\"forum_rate.php?post=".$post->id."&amp;choice=p$tokens\">
 
594
            ";
 
595
            show_image(RATE_POSITIVE_IMAGE, "Click if you like this message", "Rate +", RATE_POSITIVE_IMAGE_HEIGHT);
 
596
            echo "</a> / <a href=\"forum_rate.php?post=".$post->id."&choice=n$tokens\">";
 
597
            show_image(RATE_NEGATIVE_IMAGE, "Click if you don't like this message", "Rate -", RATE_NEGATIVE_IMAGE_HEIGHT);
 
598
            echo "</a> <a href=\"forum_report_post.php?post=".$post->id."\">";
 
599
            show_image(REPORT_POST_IMAGE, "Report this post as offensive", "Report as offensive", REPORT_POST_IMAGE_HEIGHT);
 
600
            echo "</a></td> ";
353
601
        }
354
 
        if (($controls == FORUM_CONTROLS) && (can_reply($thread, $logged_in_user))) {
355
 
            echo "<td align=right class=\"postfooter\">[<a href=\"forum_reply.php?thread=" . $thread->getID() . "&amp;post=" . $post->getID() . "#input\">Reply to this post</a>]</td>";
 
602
        if (($controls == FORUM_CONTROLS) && (can_reply($thread, $forum, $logged_in_user))) {
 
603
            echo "<td align=right class=\"postfooter\">";
 
604
            $url = "forum_reply.php?thread=" . $thread->id . "&post=" . $post->id . "#input";
 
605
            show_button($url, "Reply", "Post a reply to this message");
 
606
            echo "</td>";
356
607
        } else {
357
608
            echo "<td class=\"postfooter\"></td>";
358
609
        }
359
610
        echo "</tr>";
 
611
    } else {
 
612
        echo "</td></tr><tr><td class=\"postfooter\" colspan=\"2\">";
360
613
    }
361
 
    echo "</td></tr>";
362
614
    echo "<tr class=\"postseperator\"><td colspan=3></td></tr>";
363
615
}
364
616
 
365
 
/*** utility functions ***/
366
 
 
367
 
/**
368
 
 * Start the forum table, output the proper headings and such.
369
 
 **/
370
 
function start_forum_table($headings, $extra="width=100%") {
371
 
    start_table($extra." cellspacing=0 cellpadding=2");
372
 
    echo "<tr>";
373
 
 
374
 
    for ($i=0; $i<count($headings); $i++) {
375
 
        if (is_array($headings[$i])){
376
 
            $title = $headings[$i][0];
377
 
            $class = $headings[$i][1]?$headings[$i][1]:"heading";
378
 
            if ($headings[$i][2]) $span = " colspan=\"".$headings[$i][2]."\" ";
379
 
        } else {
380
 
            $title = $headings[$i];
381
 
            $class = "heading";
382
 
            $span="";
383
 
        }
384
 
        echo "<th class=$class$span>$title</th>";
385
 
    }
386
 
    echo "</tr>\n";
387
 
}
388
 
 
389
 
/**
390
 
 * End the forum table, currently just close the open table tag.
391
 
 **/
392
 
function end_forum_table() {
393
 
    echo "</table>\n";
394
 
}
395
 
 
396
 
/**
397
 
 * Output the forum/thread title.
398
 
 **/
399
 
function show_forum_title($forum=NULL, $thread=NULL, $extended=true) {
400
 
    if ($extended) {
401
 
        start_table_noborder();
402
 
        echo "<tr>\n";
403
 
      
404
 
        // Search
405
 
        echo "<td><form action=\"forum_search_action.php\" method=\"POST\">
406
 
            <input type=\"hidden\" name=\"search_max_time\" value=\"30\">
407
 
            <input type=\"hidden\" name=\"search_forum\" value=\"-1\">
408
 
            <input type=\"hidden\" name=\"search_sort\" value=\"5\">
409
 
            <input type=\"text\" name=\"search_keywords\">
410
 
            <input type=\"submit\" value=\"search\"><br>
411
 
            <span class=\"smalltext\"><a href=\"forum_search.php\">advanced search</a></span>
412
 
            </form>
413
 
        ";
414
 
        echo "</td>\n";
415
 
      
416
 
        $logged_in_user = get_logged_in_user(false);
417
 
        // Custom stuff for logged in user
418
 
        if ($logged_in_user) {
419
 
            echo "<td align=\"right\">\n";
420
 
            
421
 
            // Private messages
422
 
            echo pm_notification($logged_in_user);
423
 
            
424
 
            echo "</td>\n";
425
 
        }
426
 
        echo "</tr>\n";
427
 
        end_table();
428
 
    }
429
 
 
430
 
    echo "<p>\n";
431
 
    if ($forum) {
432
 
        $category = $forum->getCategory();
433
 
        $is_helpdesk = $category->getType();
434
 
    } else {
435
 
        $is_helpdesk = false;
436
 
    }
437
 
    $where = $is_helpdesk?tr(LINKS_QA):tr(FORUM_TITLE_SHORT);
438
 
    $top_url = $is_helpdesk?"forum_help_desk.php":"forum_index.php";
439
 
    if (!$forum && !$thread) {
440
 
        echo "<p class=\"title\">";
441
 
        echo $where;
442
 
 
443
 
    } else if ($forum && !$thread) {
444
 
        echo "<span class=title>";
445
 
        echo "<a href=\"$top_url\">$where</a> : ";
446
 
        echo $forum->getTitle();
447
 
        echo "</span><br>";
448
 
    } else if ($forum && $thread) {
449
 
        echo "<span class=title>";
450
 
        echo "<a href=\"$top_url\">$where</a> : ";
451
 
 
452
 
        echo "<a href=\"forum_forum.php?id=".$forum->getID()."\">", $forum->getTitle(), "</a> : ";
453
 
        echo cleanup_title($thread->getTitle());
454
 
        echo "</span><br>";
455
 
    } else {
456
 
        echo "Invalid input to show_forum_title<br>"; // TODO: handle this condition gracefully 
457
 
    }
458
 
    echo "</p>\n";
459
 
}
460
 
 
461
 
/**
462
 
 * show a thread with its context (e.g. for search results)
463
 
 **/
464
 
function show_thread($thread, $n) {
465
 
    $forum = getForum($thread->forum);
466
 
    $category = getCategory($forum->category);
467
 
    $first_post = getFirstPost($thread->id);
468
 
    $title = cleanup_title($thread->title);
469
 
    $where = $category->is_helpdesk?"Questions and answers":"Message boards";
470
 
    $top_url = $category->is_helpdesk?"forum_help_desk.php":"forum_index.php";
471
 
    $excerpt = sub_sentence(stripslashes($first_post->content), ' ', EXCERPT_LENGTH, true);
472
 
    $posted = time_diff_str($thread->create_time, time());
473
 
    $last = time_diff_str($thread->timestamp, time());
474
 
    $m = $n%2;
475
 
    echo "
476
 
        <tr class=\"row$m\">
477
 
        <td><font size=\"-2\">
478
 
            $n) Posted $posted
479
 
            <br>
480
 
            Last response $last
481
 
        </td>
482
 
        <td valign=top>
483
 
            <a href=\"$top_url\">$where</a> : $category->name :
484
 
            <a href=\"forum_forum.php?id=$forum->id\">$forum->title</a> :
485
 
            <a href=\"forum_thread.php?id=$thread->id\">$title</a>
486
 
            <br>
487
 
            <font size=\"-2\">$excerpt</font>
488
 
        </td>
489
 
        </tr>
490
 
    ";
491
 
}
492
 
 
493
 
/**
494
 
 * Show a post with its context (e.g. for search results)
495
 
 **/
496
 
function show_post2($post, $n) {
497
 
    $thread = getThread($post->thread);
498
 
    $forum = getForum($thread->forum);
499
 
    $category = getCategory($forum->category);
500
 
    $where = $category->is_helpdesk?"Questions and answers":"Message boards";
501
 
    $top_url = $category->is_helpdesk?"forum_help_desk.php":"forum_index.php";
502
 
    $content = output_transform($post->content);
 
617
// Show a post and its context (e.g. for search results, user posts)
 
618
//
 
619
function show_post_and_context($post, $thread, $forum, $options, $n) {
 
620
    $thread = BoincThread::lookup_id($post->thread);
 
621
    $forum = BoincForum::lookup_id($thread->forum);
 
622
 
 
623
    $content = output_transform($post->content, $options);
503
624
    $when = time_diff_str($post->timestamp, time());
504
625
    $user = lookup_user_id($post->user);
505
626
    $title = cleanup_title($thread->title);
506
627
    $m = $n%2;
507
 
    if($post->hidden) {
508
 
        //Todo: factor this array out, it is also used elsewhere
509
 
        $deleted_text = array( "Obscene", "Flame/Hate", "Commercial Spam", "Flamebait", "Doublepost", "User Request", "Other");
510
 
        $deleted = "<br><font color=red>[Deleted " .
511
 
                   "by a moderator " .
512
 
                   //as " . $deleted_text[$post->hidden-1] .
513
 
                   "] </font>";
 
628
    if ($post->hidden) {
 
629
        $deleted = "<br><font color=red>[Hidden by a moderator]</font>";
514
630
    } else {
515
631
        $deleted = "";
516
632
    }
517
633
    echo "
518
634
        <tr class=row$m>
519
635
        <td>
520
 
            $n) <a href=\"$top_url\">$where</a> : $category->name :
521
 
            <a href=\"forum_forum.php?id=$forum->id\">$forum->title</a> :
522
 
            <a href=\"forum_thread.php?id=$thread->id\">$title</a>
523
 
            <br>
524
 
            Posted $when by $user->name $deleted
525
 
            <hr>
526
 
            $content
527
 
        </td>
528
 
        </tr>
529
 
    ";
530
 
}
531
 
 
 
636
            $n)
 
637
    ";
 
638
    switch ($forum->parent_type) {
 
639
    case 0:
 
640
        $category = BoincCategory::lookup_id($forum->category);
 
641
        show_forum_title($category, $forum, $thread);
 
642
        break;
 
643
    case 1:
 
644
        show_team_forum_title($forum);
 
645
        break;
 
646
    }
 
647
    echo "
 
648
        (<a href=\"forum_thread.php?id=".$thread->id."&amp;nowrap=true#".$post->id."\">Message ".$post->id."</a>)
 
649
        <br>
 
650
        Posted $when by ".user_links($user)." $deleted
 
651
        <hr>
 
652
        $content
 
653
        </td></tr>
 
654
    ";
 
655
}
 
656
 
 
657
function is_banished($user) {
 
658
    return ($user->prefs->banished_until > time());
 
659
}
 
660
 
 
661
function check_banished($user) {
 
662
    if (is_banished($user)) {
 
663
        error_page(
 
664
            "You may not post or rate messages until ".gmdate('M j, Y', $user->prefs->banished_until)
 
665
        );
 
666
    }
 
667
}
532
668
 
533
669
function post_rules() {
 
670
    if (function_exists("project_forum_post_rules")) {
 
671
      $project_rules=project_forum_post_rules();
 
672
    } else {
 
673
      $project_rules="";
 
674
    }
534
675
    return "
535
676
        <ul>
536
677
        <li> Posts must be 'kid friendly': they may not contain
544
685
        <li> No messages that are deliberately hostile or insulting.
545
686
        <li> No abusive comments involving race, religion,
546
687
            nationality, gender, class or sexuality.
 
688
        ".$project_rules."
547
689
        </ul>
548
690
    ";
549
691
}
550
692
 
551
693
function post_warning() {
552
694
    return "<br><br>
553
 
        <table><tr><td>
 
695
        <table><tr><td align=left>
554
696
        <font size=-2>
555
697
        Rules:
556
698
    ".post_rules()."
560
702
    ";
561
703
}
562
704
 
563
 
function check_banished($user) {
564
 
    $x = $user->getBanishedUntil();
565
 
    if ($x>time()) {
566
 
        error_page(
567
 
            "You may not post or rate messages until ".gmdate('M j, Y', $x)
568
 
        );
569
 
    }
570
 
}
571
 
 
572
 
function can_reply($thread, $user) {
573
 
    if (!$thread->isLocked() || ($user && $user->isSpecialUser(S_MODERATOR))) {
574
 
        return true;
575
 
    } else {
576
 
        return false;
577
 
    }
578
 
}
579
 
 
580
 
function pm_notification($user) {
581
 
    $output = "";
582
 
    $pm = mysql_query("SELECT COUNT(*) AS unread FROM private_messages WHERE userid=".$user->id." AND opened=0");
583
 
    $pm = mysql_fetch_object($pm);
584
 
    if ($pm->unread > 1) {
585
 
        $output .= "<strong><a href=\"forum_pm.php?action=inbox\">You have ".$pm->unread." unread private messages.</a> </strong>";
586
 
    } elseif ($pm->unread == 1) {
587
 
        $output .= "<strong><a href=\"forum_pm.php?action=inbox\">You have one unread private message.</a> </strong>";
588
 
    } else {
589
 
        $output .= "You have no unread private messages. ";
590
 
    }
591
 
    
592
 
    $output .= "| <a href=\"forum_pm.php?action=inbox\">Inbox</a>\n";
593
 
    $output .= "| <a href=\"forum_pm.php?action=new\">Write</a>\n";
594
 
    return $output;
 
705
function notify_subscriber($thread, $user) {
 
706
    BoincForumPrefs::lookup($user);
 
707
    if ($user->prefs->pm_notification == 1) {
 
708
        send_reply_notification_email($thread, $user);
 
709
    }
 
710
    $now = time();
 
711
    $type = NOTIFY_SUBSCRIBED_POST;
 
712
    BoincNotify::replace("userid=$user->id, create_time=$now, type=$type, opaque=$thread->id");
 
713
}
 
714
 
 
715
// Various functions for adding/hiding/unhiding stuff.
 
716
// These take care of counts and timestamps.
 
717
// Don't do these things directly - use these functions
 
718
//
 
719
function create_post($content, $parent_id, $user, $forum, $thread, $signature) {
 
720
    $content = substr($content, 0, 64000);
 
721
    $content = mysql_real_escape_string($content);
 
722
    $now = time();
 
723
    $sig = $signature?1:0;
 
724
    $id = BoincPost::insert("(thread, user, timestamp, content, parent_post, signature) values ($thread->id, $user->id, $now, '$content', $parent_id, $sig)");
 
725
    if (!$id) return null;
 
726
 
 
727
    // notify subscribed users
 
728
    //
 
729
    $subs = BoincSubscription::enum("threadid=$thread->id");
 
730
    foreach ($subs as $sub) {
 
731
        if ($user->id == $sub->userid) continue;
 
732
        $user2 = BoincUser::lookup_id($sub->userid);
 
733
        notify_subscriber($thread, $user2);
 
734
    }
 
735
    $user->update("posts=posts+1");
 
736
    $thread->update("replies=replies+1, timestamp=$now");
 
737
    $forum->update("posts=posts+1, timestamp=$now");
 
738
}
 
739
 
 
740
function create_thread($title, $content, $user, $forum, $signature) {
 
741
    $title = trim($title);
 
742
    $title = strip_tags($title);
 
743
    $title = mysql_real_escape_string($title);
 
744
    $now = time();
 
745
    $id  = BoincThread::insert("(forum, owner, title, create_time, timestamp, replies) values ($forum->id, $user->id, '$title', $now, $now, -1)");
 
746
    if (!$id) return null;
 
747
    $thread = BoincThread::lookup_id($id);
 
748
    create_post($content, 0, $user, $forum, $thread, $signature);
 
749
    $forum->update("threads=threads+1");
 
750
    return $thread;
 
751
}
 
752
 
 
753
function hide_post($post, $thread, $forum) {
 
754
    $post->update("hidden=1");
 
755
    $thread->update("replies=replies-1");
 
756
    return $forum->update("posts=posts-1");
 
757
}
 
758
 
 
759
function unhide_post($post, $thread, $forum) {
 
760
    $now = time();
 
761
    $post->update("hidden=0");
 
762
    $thread->update("replies=replies+1, timestamp=$now");
 
763
    return $forum->update("posts=posts+1, timestamp=$now");
 
764
}
 
765
 
 
766
function delete_post($post, $thread, $forum) {
 
767
    $post->delete();
 
768
    $thread->update("replies=replies-1");
 
769
    $forum->update("posts=posts-1");
 
770
    $count = BoincPost::count("thread=$thread->id");
 
771
    if ($count == 0) {
 
772
        $forum->update("threads=threads-1");
 
773
        $thread->delete();
 
774
    }
 
775
}
 
776
 
 
777
function move_post($post, $old_thread, $old_forum, $new_thread, $new_forum) {
 
778
    $now = time();
 
779
    $post->update("thread=$new_thread->id");
 
780
    $old_thread->update("replies=replies-1");
 
781
    $new_thread->update("replies=replies+1, timestamp=$now");
 
782
    $old_forum->update("posts=posts-1");
 
783
    return $new_forum->update("posts=posts+1, timestamp=$now");
 
784
}
 
785
 
 
786
function hide_thread($thread, $forum) {
 
787
    $thread->update("hidden=1");
 
788
    $forum->update("threads=threads-1");
 
789
    return $forum->update("posts=posts-$thread->replies-1");
 
790
}
 
791
 
 
792
function unhide_thread($thread, $forum) {
 
793
    $now = time();
 
794
    $thread->update("hidden=0");
 
795
    return $forum->update("threads=threads+1, posts=posts+$thread->replies+1, timestamp=$now");
 
796
}
 
797
 
 
798
function move_thread($thread, $old_forum, $new_forum) {
 
799
    $now = time();
 
800
    $old_forum->update("threads=threads-1, posts=posts-$thread->replies-1");
 
801
    $new_forum->update("threads=threads+1, posts=posts+$thread->replies+1, timestamp=$now");
 
802
    return $thread->update("forum=$new_forum->id");
 
803
}
 
804
 
 
805
// $show_hidden: 1 if it is a moderator reading
 
806
// Error page if this function returns NULL.
 
807
// $forumID - int
 
808
// $min - int
 
809
// $nRec - int
 
810
// $sort_style - string (checked by switch statement)
 
811
// $show_hidden - bool (not directly passed to SQL)
 
812
// $sticky - bool (not directly passed to SQL)
 
813
//
 
814
function get_forum_threads(
 
815
    $forumID, $start=-1, $nRec=-1, $sort_style=MODIFIED_NEW,
 
816
    $show_hidden = 0, $sticky = 1
 
817
) {
 
818
    //if (! (is_numeric($forumID) && is_numeric($min) && is_numeric($nRec))) {
 
819
    //    return NULL;  // Something is wrong here.
 
820
    //}
 
821
        
 
822
    $sql = 'forum = ' . $forumID ;
 
823
    if ($sticky){
 
824
        $stickysql = "sticky DESC, ";
 
825
    }
 
826
    if (!$show_hidden) {
 
827
        $sql .= ' AND hidden = 0';
 
828
    }
 
829
    switch($sort_style) {
 
830
    case MODIFIED_NEW:
 
831
        $sql .= ' ORDER BY '.$stickysql.'timestamp DESC';
 
832
        break;
 
833
    case MODIFIED_OLD:
 
834
        $sql .= ' ORDER BY '.$stickysql.'timestamp ASC';
 
835
        break;
 
836
    case VIEWS_MOST:
 
837
        $sql .= ' ORDER BY '.$stickysql.'views DESC';
 
838
        break;
 
839
    case REPLIES_MOST:
 
840
        $sql .= ' ORDER BY '.$stickysql.'replies DESC';
 
841
        break;
 
842
    case CREATE_TIME_NEW:
 
843
        $sql .= ' ORDER by '.$stickysql.'create_time desc';
 
844
        break;
 
845
    case CREATE_TIME_OLD:
 
846
        $sql .= ' ORDER by '.$stickysql.'create_time asc';
 
847
        break;
 
848
    case 'sufferers':
 
849
        $sql .= ' ORDER by '.$stickysql.'sufferers desc';
 
850
        break;
 
851
    case 'activity':
 
852
        $sql .= ' ORDER by '.$stickysql.'activity desc';
 
853
        break;
 
854
    case 'score':
 
855
        $sql .= ' ORDER by '.$stickysql.'score desc';
 
856
        break;
 
857
    default:
 
858
        $sql .= ' ORDER BY '.$stickysql.'timestamp DESC';
 
859
        break;
 
860
    }
 
861
    if ($start > -1) {
 
862
        $sql .= ' LIMIT '.$start;
 
863
        if ($nRec > -1) {
 
864
            $sql .= ', '.$nRec;
 
865
        }
 
866
    } else if ($nRec > -1) {
 
867
        $sql .= ' LIMIT '.$nRec;
 
868
    }
 
869
    return BoincThread::enum($sql);
 
870
}
 
871
 
 
872
// $show_hidden = true when it is a moderator reading
 
873
// error_page if this function returns NULL.
 
874
// $sort_style - string (checked by switch statement)
 
875
// $show_hidden - bool (not directly passed to SQL)
 
876
//
 
877
function get_thread_posts($threadid, $sort_style, $show_hidden) {
 
878
    $sql = "thread=$threadid";
 
879
    if (!$show_hidden) {
 
880
        $sql .= ' AND hidden = 0';
 
881
    }
 
882
    switch($sort_style) {
 
883
    case CREATE_TIME_NEW:
 
884
        $sql .= ' ORDER BY timestamp desc';
 
885
        break;
 
886
    case CREATE_TIME_OLD:
 
887
        $sql .= ' ORDER BY timestamp asc';
 
888
        break;
 
889
    case POST_SCORE:
 
890
        $sql .= ' ORDER BY score DESC';
 
891
        break;
 
892
    default:
 
893
        $sql .= ' ORDER BY timestamp asc';
 
894
        break;        
 
895
    }
 
896
    return BoincPost::enum($sql);
 
897
}
 
898
 
 
899
// Show the links for possible moderation actions related to a single post 
 
900
//
 
901
function show_post_moderation_links(
 
902
    $config, $logged_in_user, $post, $forum, $tokens
 
903
){
 
904
    $moderators_allowed_to_ban = parse_bool($config, "moderators_allowed_to_ban"); 
 
905
    $moderators_vote_to_ban = parse_bool($config, "moderators_vote_to_ban");
 
906
 
 
907
    if ($post->hidden) {
 
908
        show_button("forum_moderate_post_action.php?action=unhide&id=".$post->id."$tokens", "Unhide", "Unhide this post");
 
909
    } else {
 
910
        show_button("forum_moderate_post.php?action=hide&id=".$post->id."$tokens", "Hide", "Hide this post");
 
911
    }
 
912
 
 
913
    show_button(
 
914
        "forum_moderate_post.php?action=move&id=".$post->id."$tokens",
 
915
        "Move", "Move post to a different thread"
 
916
    );
 
917
 
 
918
    if ($forum->parent_type == 0) {
 
919
        if ($logged_in_user->prefs->privilege(S_ADMIN) || ($logged_in_user->prefs->privilege(S_MODERATOR) && $moderators_allowed_to_ban)) {
 
920
            show_button("forum_moderate_post.php?action=banish_user&id=".$post->id."&userid=".$post->user."$tokens", "Banish author", "Banish author");
 
921
        }
 
922
        if ($logged_in_user->prefs->privilege(S_MODERATOR) && $moderators_vote_to_ban) {
 
923
            require_once("../inc/forum_banishment_vote.inc");
 
924
            if (vote_is_in_progress($post->user)) {
 
925
                show_button("forum_banishment_vote.php?action=yes&userid=".$post->user, "Vote to banish author", "Vote to banish author");
 
926
                show_button("forum_banishment_vote.php?action=no&userid=".$post->user, "Vote not to banish author", "Vote not to banish author");
 
927
            } else {
 
928
                show_button("forum_banishment_vote.php?action=start&userid=".$post->user, "Start vote to banish author", "Start vote to banish author");
 
929
            }
 
930
        }
 
931
    }
 
932
}
 
933
 
 
934
function check_create_thread_access($user, $forum) {
 
935
    if ($forum->is_dev_blog){
 
936
        if (
 
937
           (!$user->prefs->privilege(S_SCIENTIST)) &&
 
938
           (!$user->prefs->privilege(S_DEV)) &&
 
939
           (!$user->prefs->privilege(S_ADMIN))
 
940
        ) {
 
941
            error_page("This forum is marked as a development blog, only people directly working with the project may start a new thread here. <br/>However, you may post a reply to an existing thread.");
 
942
        }
 
943
    }
 
944
    check_post_access($user, $forum);
 
945
}
 
946
 
 
947
function check_post_access($user, $forum) {
 
948
    switch ($forum->parent_type) {
 
949
    case 0:
 
950
        if ($user->prefs->privilege(S_MODERATOR)) return;
 
951
        break;
 
952
    case 1:
 
953
        $team = BoincTeam::lookup_id($forum->category);
 
954
        if (is_team_admin($user, $team)) return;
 
955
 
 
956
        // non-team-members can't post
 
957
        //
 
958
        if ($user->teamid != $team->id) {
 
959
            error_page("Only team members can post to the team message board");
 
960
        }
 
961
        break;
 
962
    }
 
963
 
 
964
    // If user haven't got enough credit (according to forum regulations)
 
965
    // We do not tell the (ab)user how much this is -
 
966
    // no need to make it easy for them to break the system.
 
967
    //
 
968
    if ($user->total_credit<$forum->post_min_total_credit || $user->expavg_credit<$forum->post_min_expavg_credit) {
 
969
        error_page(tra("In order to create a new thread in %1 you must have a certain amount of credit. This is to prevent and protect against abuse of the system.", $forum->title));
 
970
    }
 
971
 
 
972
    // If the user is posting faster than forum regulations allow
 
973
    // Tell the user to wait a while before creating any more posts
 
974
    //
 
975
    if (time()-$user->prefs->last_post <$forum->post_min_interval) {
 
976
        error_page(tra("You cannot create any more threads right now. Please wait a while before trying again. This delay has been enforced to protect against abuse of the system."));
 
977
    }
 
978
}
 
979
 
 
980
function check_reply_access($user, $forum, $thread) {
 
981
    if ($thread->locked && !is_moderator($user, $forum)) {
 
982
        error_page(
 
983
            "This thread is locked. Only forum moderators and administrators are allowed to post there."
 
984
        );
 
985
    }
 
986
    if ($thread->hidden) {
 
987
        error_page(
 
988
           "Can't post to a hidden thread."
 
989
        );
 
990
    }
 
991
 
 
992
    check_post_access($user, $forum);
 
993
}
 
994
 
 
995
function is_moderator($user, $forum) {
 
996
    if (!$user) return false;
 
997
    switch ($forum->parent_type) {
 
998
    case 0:
 
999
        if ($user->prefs->privilege(S_MODERATOR)) return true;
 
1000
        if ($user->prefs->privilege(S_ADMIN)) return true;
 
1001
        if ($user->prefs->privilege(S_DEV)) return true;
 
1002
        break;
 
1003
    case 1:
 
1004
        if ($user->prefs->privilege(S_ADMIN)) return true;
 
1005
        $team = BoincTeam::lookup_id($forum->category);
 
1006
        return is_team_admin($user, $team);
 
1007
        break;
 
1008
    }
 
1009
    return false;
 
1010
}
 
1011
 
 
1012
function show_thread_and_context_header() {
 
1013
    start_forum_table(array(tra("Thread"), tra("Posts"), tra("Author"), tra("Views"), "<nobr>".tra("Last post")."</nobr>"));
 
1014
}
 
1015
 
 
1016
// show a 1-line summary of thread and its forum.
 
1017
// Used for search results and subscription list
 
1018
//
 
1019
function show_thread_and_context($thread, $user) {
 
1020
    $thread_forum = BoincForum::lookup_id($thread->forum);
 
1021
    if (!$thread_forum) return;
 
1022
    if (!is_forum_visible_to_user($thread_forum, $user)) return;
 
1023
    $owner = BoincUser::lookup_id($thread->owner);
 
1024
    echo "<tr><td>\n";
 
1025
    switch($thread_forum->parent_type) {
 
1026
    case 0:
 
1027
        $category = BoincCategory::lookup_id($thread_forum->category);
 
1028
        show_forum_title($category, $thread_forum, $thread, true);
 
1029
        break;
 
1030
    case 1:
 
1031
        show_team_forum_title($thread_forum, $thread);
 
1032
        break;
 
1033
    }
 
1034
    echo '
 
1035
        </td><td>'.($thread->replies+1).'</td>
 
1036
        <td align="left"><div class="authorcol">'.user_links($owner).'</div></td>
 
1037
        <td>'.$thread->views.'</td>
 
1038
        <td style="text-align:right">'.time_diff_str($thread->timestamp, time()).'</td>
 
1039
        </tr>
 
1040
    ';
 
1041
}
 
1042
 
 
1043
// see if thread is in subscription list
 
1044
//
 
1045
function is_subscribed($thread, $subs) {
 
1046
    foreach ($subs as $sub) {
 
1047
        if ($sub->threadid == $thread->id) return true;
 
1048
    }
 
1049
    return false;
 
1050
}
 
1051
 
 
1052
function is_forum_visible_to_user($forum, $user) {
 
1053
    if ($forum->parent_type == 1) {
 
1054
        if (parse_config(get_config(), "<team_forums_members_only>")) {
 
1055
            if (!$user) return false;
 
1056
            if ($user->teamid != $forum->category) return false;
 
1057
        }
 
1058
    }
 
1059
    return true;
 
1060
}
 
1061
 
 
1062
function subscribed_post_email_line($notify) {
 
1063
    $thread = BoincThread::lookup_id($notify->opaque);
 
1064
    return "There are new posts in the thread '$thread->title'";
 
1065
}
 
1066
 
 
1067
function subscribed_post_web_line($notify) {
 
1068
    $thread = BoincThread::lookup_id($notify->opaque);
 
1069
    return "New posts in the thread <a href=forum_thread.php?id=$thread->id>$thread->title</a>";
 
1070
}
 
1071
 
 
1072
function subscribe_rss($notify, &$title, &$msg, &$url) {
 
1073
    $thread = BoincThread::lookup_id($notify->opaque);
 
1074
    $title = "New posts in subscribed thread";
 
1075
    $msg = "There are new posts in the thread '$thread->title'";
 
1076
    $url = URL_BASE."forum_thread.php?id=$thread->id";
 
1077
}
 
1078
 
 
1079
function show_mark_as_read_button($user) {
 
1080
    if ($user) {
 
1081
        $return = urlencode(current_url());
 
1082
        $tokens = url_tokens($user->authenticator);
 
1083
        $url = "forum_index.php?read=1$tokens&return=$return";
 
1084
        show_button($url, tra("Mark all threads as read"), tra("Mark all threads in all message boards as 'read'."));
 
1085
    }
595
1086
}
596
1087
 
597
1088
?>