Issues (1963)

html/user/pm.php (11 issues)

1
<?php
2
// This file is part of BOINC.
3
// http://boinc.berkeley.edu
4
// Copyright (C) 2021 University of California
5
//
6
// BOINC is free software; you can redistribute it and/or modify it
7
// under the terms of the GNU Lesser General Public License
8
// as published by the Free Software Foundation,
9
// either version 3 of the License, or (at your option) any later version.
10
//
11
// BOINC is distributed in the hope that it will be useful,
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
// See the GNU Lesser General Public License for more details.
15
//
16
// You should have received a copy of the GNU Lesser General Public License
17
// along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
18
19
require_once("../inc/boinc_db.inc");
20
require_once("../inc/email.inc");
21
require_once("../inc/pm.inc");
22
require_once("../inc/forum.inc");
23
require_once("../inc/akismet.inc");
24
25
function show_block_link($userid) {
26
    echo " <a href=\"pm.php?action=block&amp;id=$userid\">";
27
    show_image(REPORT_POST_IMAGE, tra("Block messages from this user"), tra("Block user"), REPORT_POST_IMAGE_HEIGHT);
28
    echo "</a>";
29
}
30
31
$logged_in_user = get_logged_in_user();
0 ignored issues
show
Are you sure the assignment to $logged_in_user is correct as get_logged_in_user() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
32
BoincForumPrefs::lookup($logged_in_user);
33
34
function make_script() {
35
    echo "
36
        <script type=\"text/javascript\">
37
        function set_all(val) {
38
            f = document.msg_list;
39
            n = f.elements.length;
40
            for (i=0; i<n; i++) {
41
                e = f.elements[i];
42
                if (e.type=='checkbox') {
43
                    e.checked = val;
44
                }
45
            }
46
        }
47
        </script>
48
    ";
49
}
50
51
// show private messages,
52
// and delete notifications of new messages
53
//
54
function do_inbox($logged_in_user) {
55
    page_head(
56
        sprintf('%s: %s',
57
            tra("Private messages"),
58
            tra("Inbox")
59
        )
60
    );
61
62
    make_script();
63
    if (get_int("sent", true) == 1) {
64
        echo "<h3>".tra("Your message has been sent.")."</h3>\n";
65
    }
66
    $options = get_output_options($logged_in_user);
67
68
    BoincNotify::delete_aux("userid=$logged_in_user->id and type=".NOTIFY_PM);
69
70
    $msgs = BoincPrivateMessage::enum(
71
        "userid=$logged_in_user->id ORDER BY date DESC"
72
    );
73
    $nmsgs = count($msgs);
74
    if ($nmsgs == 0) {
75
        echo tra("You have no private messages.");
76
    } else {
77
        // see if we have to paginate messages
78
        //
79
        $nshow = $logged_in_user->prefs->display_wrap_postcount;
80
        if ($nshow < 1) $nshow = 20;
81
        $offset = 0;
82
        if ($nmsgs > $nshow) {
83
            $offset = get_int('offset', true);
84
            if ($offset === false) $offset = 0;
85
            if ($offset >= $nmsgs) $offset = 0;
86
            echo sprintf('Showing messages %d to %d of %d',
87
                $offset+1,
88
                min($offset+$nshow, $nmsgs),
89
                $nmsgs
90
            );
91
            if ($offset) {
92
                echo sprintf(
93
                    ' &middot; <a href=pm.php?action=inbox&offset=%d>Previous %d</a>',
94
                    max(0, $offset-$nshow), $nshow
95
                );
96
            }
97
            if ($offset+$nshow < $nmsgs) {
98
                echo sprintf(
99
                    ' &middot; <a href=pm.php?action=inbox&offset=%d>Next %d</a>',
100
                    $offset+$nshow, $nshow
101
                );
102
            }
103
        }
104
105
        echo "<form name=msg_list action=pm.php method=post>
106
            <input type=hidden name=action value=delete_selected>
107
        ";
108
        echo form_tokens($logged_in_user->authenticator);
109
        start_table('table-striped');
110
        row_heading_array(
111
            array(tra("Subject"), tra("Sender and date"), tra("Message")),
112
            array('style="width: 12em;"', 'style="width: 10em;"', "")
113
        );
114
        $i = 0;
115
        foreach($msgs as $msg) {
116
            if ($i<$offset) {
117
                $i++;
118
                continue;
119
            }
120
            if ($i>=$offset+$nshow) break;
121
            $i++;
122
            $sender = BoincUser::lookup_id($msg->senderid);
123
            if (!$sender) {
124
                $msg->delete();
125
                continue;
126
            }
127
            echo "<tr>\n";
128
            $checkbox = "<input type=checkbox name=pm_select_$msg->id>";
129
            if (!$msg->opened) {
130
                $msg->update("opened=1");
131
            }
132
            echo "<td valign=top> $checkbox $msg->subject </td>\n";
133
            echo "<td valign=top>".user_links($sender, BADGE_HEIGHT_SMALL);
134
            show_block_link($msg->senderid);
135
            echo "<br>".time_str($msg->date)."</td>\n";
136
            echo "<td valign=top>".output_transform($msg->content, $options)."<p>";
137
            $tokens = url_tokens($logged_in_user->authenticator);
138
            show_button("pm.php?action=new&amp;replyto=$msg->id", tra("Reply"), tra("Reply to this message"));
139
            show_button("pm.php?action=delete&amp;id=$msg->id&amp;$tokens", tra("Delete"), tra("Delete this message"));
140
            echo "</ul></td></tr>\n";
141
        }
142
        echo "
143
            <tr><td>
144
            <a href=\"javascript:set_all(1)\">".tra("Select all")."</a>
145
            |
146
            <a href=\"javascript:set_all(0)\">".tra("Unselect all")."</a>
147
            </td>
148
            <td colspan=2>
149
            <input class=\"btn btn-danger\" type=submit value=\"".tra("Delete selected messages")."\">
150
            </td></tr>
151
        ";
152
        end_table();
153
        echo "</form>\n";
154
    }
155
    page_tail();
156
}
157
158
// the following isn't currently used - we never show single messages
159
//
160
function do_read($logged_in_user) {
161
    $id = get_int("id");
162
    $message = BoincPrivateMessage::lookup_id($id);
163
    if (!$message || $message->userid != $logged_in_user->id) {
164
        error_page(tra("no such message"));
165
    }
166
    page_head(tra("Private messages")." : ".$message->subject);
167
    pm_header();
168
169
    $sender = BoincUser::lookup_id($message->senderid);
170
171
    start_table();
172
    echo "<tr><th>".tra("Subject")."</th><td>".$message->subject."</td></tr>";
173
    echo "<tr><th>".tra("Sender")."</th><td>".user_links($sender, BADGE_HEIGHT_SMALL);
174
    show_block_link($message->senderid);
175
    echo "</td></tr>";
176
    echo "<tr><th>".tra("Date")."</th><td>".time_str($message->date)."</td></tr>";
177
    echo "<tr><th>".tra("Message")."</th><td>".output_transform($message->content, $options)."</td></tr>";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $options seems to be never defined.
Loading history...
178
    echo "<tr><td></td><td>\n";
179
    echo "<a href=\"pm.php?action=new&amp;replyto=$id\">".tra("Reply")."</a>\n";
180
    echo " &middot; <a href=\"pm.php?action=delete&amp;id=$id\">".tra("Delete")."</a>\n";
181
    echo " &middot; <a href=\"pm.php?action=inbox\">".tra("Inbox")."</a>\n";
182
    end_table();
183
184
    if ($message->opened == 0) {
185
        $message->update("opened=1");
186
    }
187
    page_tail();
188
}
189
190
// form to send a personal message
191
//
192
function do_new($logged_in_user) {
193
    global $replyto, $userid;
194
    check_banished($logged_in_user);
195
    if (VALIDATE_EMAIL_TO_POST) {
196
        check_validated_email($logged_in_user);
197
    }
198
    pm_form_page($replyto, $userid);
199
}
200
201
function do_delete($logged_in_user) {
202
    $id = get_int("id", true);
203
    if ($id == null) {
204
        $id = post_int("id");
205
    }
206
    check_tokens($logged_in_user->authenticator);
207
    BoincPrivateMessage::delete_aux("userid=".$logged_in_user->id." AND id=$id");
208
    header("Location: pm.php");
209
}
210
211
function do_send_team($logged_in_user) {
212
    check_tokens($logged_in_user->authenticator);
213
    $subject = post_str("subject", true);
214
    $content = post_str("content", true);
215
    $teamid = post_int("teamid");
216
    if (post_str("preview", true) == tra("Preview")) {
217
        pm_team_form($logged_in_user, $teamid);
218
        return;
219
    }
220
221
    // make sure user is authorized, i.e. is a team admin
222
    //
223
    $team = BoincTeam::lookup_id($teamid);
224
    if (!$team) {
225
        error_page("no such team");
226
    }
227
    if (!is_team_admin($logged_in_user, $team)) {
228
        error_page("no team admin");
229
    }
230
231
    if (($subject == null) || ($content == null)) {
0 ignored issues
show
It seems like you are loosely comparing $subject of type mixed|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
It seems like you are loosely comparing $content of type mixed|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
232
        pm_team_form(
233
            $logged_in_user, $teamid,
234
            tra("You need to fill all fields to send a private message")
235
        );
236
        return;
237
    }
238
239
    $subject = "Message from team ".$team->name.": ".$subject;
240
        // don't use tra() here because we don't know language of recipient
241
        // Also, we use it in pm_count() to exclude team messages from limit check
242
    $users = BoincUser::enum("teamid=$teamid");
243
    foreach ($users as $user) {
244
        pm_send_msg($logged_in_user, $user, $subject, $content, true);
245
    }
246
    page_head(tra("Message sent"));
247
    echo tra("Your message was sent to %1 team members.", count($users));
248
    page_tail();
249
}
250
251
function do_send($logged_in_user) {
252
    global $replyto, $userid;
253
    check_banished($logged_in_user);
254
    if (VALIDATE_EMAIL_TO_POST) {
255
        check_validated_email($logged_in_user);
256
    }
257
    check_tokens($logged_in_user->authenticator);
258
259
    $to = sanitize_tags(post_str("to", true));
260
    $subject = post_str("subject", true);
261
    $content = post_str("content", true);
262
263
    if (post_str("preview", true) == tra("Preview")) {
264
        pm_form_page($replyto, $userid);
265
        return;
266
    }
267
    if (($to == null) || ($subject == null) || ($content == null)) {
0 ignored issues
show
It seems like you are loosely comparing $to of type mixed|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
It seems like you are loosely comparing $subject of type mixed|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
It seems like you are loosely comparing $content of type mixed|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
268
        pm_form_page(
269
            $replyto, $userid,
270
            tra("You need to fill all fields to send a private message")
271
        );
272
        return;
273
    }
274
    if (!akismet_check($logged_in_user, $content)) {
275
        pm_form_page($replyto, $userid,
276
            tra("Your message was flagged as spam by the Akismet anti-spam system.  Please modify your text and try again.")
277
        );
278
        return;
279
    }
280
    $usernames = explode("\n", $to);
281
282
    $userlist = array();
283
    $userids = array(); // To prevent from spamming a single user by adding it multiple times
284
285
    foreach ($usernames as $username) {
286
        // can be <id>, name, or '<id> (name)'
287
        // (PM reply fills in the latter)
288
        //
289
        $x = explode(' ', $username);
290
        if (is_numeric($x[0])) {     // user ID
291
            $userid = (int)$x[0];
292
            $user = BoincUser::lookup_id($userid);
293
            if ($user == null) {
294
                pm_form_page(
295
                    $replyto, $userid,
296
                    tra("Could not find user with id %1", $userid)
297
                );
298
                return;
299
            }
300
        } else {
301
            $users = BoincUser::lookup_name($username);
302
            if (count($users) == 0) {
303
                pm_form_page(
304
                    $replyto, $userid,
305
                    tra("Could not find user with username %1", $username)
306
                );
307
                return;
308
            } elseif (count($users) > 1) { // Non-unique username
309
                pm_form_page(
310
                    $replyto, $userid,
311
                    tra("%1 is not a unique username; you will have to use user ID", $username)
312
                );
313
                return;
314
            }
315
            $user = $users[0];
316
        }
317
        BoincForumPrefs::lookup($user);
318
        if (!is_moderator($logged_in_user) && is_ignoring($user, $logged_in_user)) {
319
            pm_form_page(
320
                $replyto, $userid,
321
                UNIQUE_USER_NAME
322
                ?tra("User %1 is not accepting private messages from you.",
0 ignored issues
show
Expected 1 space before "?"; newline found
Loading history...
323
                    $user->name
324
                )
325
                :tra("User %1 (ID: %2) is not accepting private messages from you.",
0 ignored issues
show
Expected 1 space before ":"; newline found
Loading history...
326
                    $user->name,
327
                    $user->id
328
                )
329
            );
330
            return;
331
        }
332
        if (!isset($userids[$user->id])) {
333
            $userlist[] = $user;
334
            $userids[$user->id] = true;
335
        }
336
    }
337
338
    foreach ($userlist as $user) {
339
        if (!is_moderator($logged_in_user, null)) {
340
            check_pm_count($logged_in_user->id);
341
        }
342
        pm_send_msg($logged_in_user, $user, $subject, $content, true);
343
    }
344
345
    Header("Location: pm.php?action=inbox&sent=1");
0 ignored issues
show
Calls to inbuilt PHP functions must be lowercase; expected "header" but found "Header"
Loading history...
346
}
347
348
function do_block($logged_in_user) {
349
    $id = get_int("id");
350
    $user = BoincUser::lookup_id($id);
351
    if (!$user) {
352
        error_page(tra("No such user"));
353
    }
354
    page_head(tra("Really block %1?", $user->name));
355
    echo "<div>".tra("Are you really sure you want to block user %1 from sending you private messages?", $user->name)."<br>\n";
356
    echo tra("Please note that you can only block a limited amount of users.")."</div>\n";
357
    echo "<div>".tra("Once the user has been blocked you can unblock it using forum preferences page.")."</div>\n";
358
359
    echo "<form action=\"pm.php\" method=\"POST\">\n";
360
    echo form_tokens($logged_in_user->authenticator);
361
    echo "<input type=\"hidden\" name=\"action\" value=\"confirmedblock\">\n";
362
    echo "<input type=\"hidden\" name=\"id\" value=\"$id\">\n";
363
    echo "<input class=\"btn btn-default\" type=\"submit\" value=\"".tra("Add user to filter")."\">\n";
364
    echo "<a href=\"pm.php?action=inbox\">".tra("No, cancel")."</a>\n";
365
    echo "</form>\n";
366
    page_tail();
367
}
368
369
function do_confirmedblock($logged_in_user) {
370
    check_tokens($logged_in_user->authenticator);
371
    $id = post_int("id");
372
    $blocked_user = BoincUser::lookup_id($id);
373
    if (!$blocked_user) error_page(tra("no such user"));
374
    if (is_moderator($blocked_user)) {
375
        error_page(
376
            sprintf('%s is a moderator, and can\'t be blocked',
377
                $blocked_user->name
378
            )
379
        );
380
    }
381
    add_ignored_user($logged_in_user, $blocked_user);
382
383
    page_head(tra("User %1 blocked", $blocked_user->name));
384
385
    echo "<div>".tra("User %1 has been blocked from sending you private messages.", $blocked_user->name)."\n";
386
    echo tra("To unblock, visit %1 message board preferences %2", "<a href=\"edit_forum_preferences_form.php\">", "</a>")."</div>\n";
387
    page_tail();
388
}
389
390
function do_delete_selected($logged_in_user) {
391
    check_tokens($logged_in_user->authenticator);
392
393
    $msgs = BoincPrivateMessage::enum(
394
        "userid=$logged_in_user->id"
395
    );
396
    foreach($msgs as $msg) {
397
        $x = "pm_select_$msg->id";
398
        if (post_str($x, true)) {
399
            $msg = BoincPrivateMessage::lookup_id($msg->id);
400
            $msg->delete();
401
        }
402
    }
403
    Header("Location: pm.php?action=inbox&deleted=1");
0 ignored issues
show
Calls to inbuilt PHP functions must be lowercase; expected "header" but found "Header"
Loading history...
404
}
405
406
$replyto = get_int("replyto", true);
407
$userid = get_int("userid", true);
408
$teamid = get_int("teamid", true);
409
if (!$teamid) {
410
    $teamid = post_int("teamid", true);
411
}
412
413
$action = sanitize_tags(get_str("action", true));
414
if (!$action) {
415
    $action = sanitize_tags(post_str("action", true));
416
}
417
418
if (!$action) {
419
    $action = "inbox";
420
}
421
422
if ($action == "inbox") {
423
    do_inbox($logged_in_user);
424
} elseif ($action == "read") {
425
    do_read($logged_in_user);
426
} elseif ($action == "new") {
427
    if (!$teamid) $teamid = post_int("teamid", true);
428
    if ($teamid) {
429
        pm_team_form($logged_in_user, $teamid);
430
    } else {
431
        do_new($logged_in_user);
432
    }
433
} elseif ($action == "delete") {
434
    do_delete($logged_in_user);
435
} elseif ($action == "send") {
436
    if ($teamid) {
437
        do_send_team($logged_in_user);
438
    } else {
439
        do_send($logged_in_user);
440
    }
441
} elseif ($action == "block") {
442
    do_block($logged_in_user);
443
} elseif ($action == "confirmedblock") {
444
    do_confirmedblock($logged_in_user);
445
} elseif ($action == "delete_selected") {
446
    do_delete_selected($logged_in_user);
447
} else {
448
    error_page(tra("Unknown action"));
449
}
450
451
?>
452