On two separate sites I work on we ran into huge problems when users had sent private messages and then were deleted before all their messages had been read. Anyone who hadn't read the messages before the user was deleted were greeted with "You have n new private messages" on every page they visited. Going to their inbox showed no new messages, and even if they deleted all their messages, the message didn't go away.

Explanation:
If a user sends a private message, and then is deleted before the recipient has a chance to read or delete the message, then the recipient will receive the message "You have n new messages(s)" at the top of every page, with no recourse to deleting the unread message since it won't show up in the in box. The reason it won't show up is that the query that selects for new messages relies on the user existing (JOIN) whereas the queries that just checks for unread messages does not.

This patch adds another pruning task to be run during cron that will check for message authors who no longer exist in the users table, and mark unread messages from such authors as read, and set them to eventually be archived.

Comments

apotek’s picture

Well, after writing this code and thinking more about it, I think the real problem is the SQL query that generates the message list. There must be some way to rewrite it using a join so that even if the author no longer exists in the users table, the message will still show up. That would be the better way to solve this problem.

These two queries would have to be updated to LEFT JOIN queries, so that non-existent users would still produce a result, just without any user info (set to NULL).

$result = pager_query('SELECT id, subject, p.timestamp, u.uid, u.name, newmsg FROM {privatemsg} p, {users} u WHERE p.author = u.uid AND p.recipient = %d AND folder = %d AND p.recipient_del = 0 ORDER BY p.timestamp DESC', variable_get('privatemsg_per_page', 10), 0, NULL, $user->uid, $current_folder);

SHOULD BE
$result = pager_query('SELECT id, subject, p.timestamp, u.uid, u.name, newmsg FROM {privatemsg} p LEFT JOIN {users} u ON p.author = u.uid WHERE p.recipient = %d AND folder = %d AND p.recipient_del = 0 ORDER BY p.timestamp DESC', variable_get('privatemsg_per_page', 10), 0, NULL, $user->uid, $current_folder);

Rewriting the query this way will allow messages to be displayed even if the user has been deleted. The fields for uid and name will be filled with null, that's all, and that's certainly preferable to the message no showing up.

Similarly, this should be rewritten, although that's not as critical, considering it would be unlikely for a deleted user to look at their sent messages:
// sent messages
$result = pager_query('SELECT id, subject, p.timestamp, u.uid, u.name, newmsg FROM {privatemsg} p, {users} u WHERE p.recipient = u.uid AND p.author = %d AND p.author_del = 0 ORDER BY p.timestamp DESC', variable_get('privatemsg_per_page', 10), 0, NULL, $user->uid);

What do you guys think? Worth rolling a patch? I think the rewrite of the query is the way to go. The patch at top should probably still be in there, just to clean up gunk that cannot be cleaned out in any other way (a deleted user cannot delete their messages, for example).

apotek’s picture

StatusFileSize
new1.57 KB

For some reason, my patch file was deleted. Submitting again.

jaydub’s picture

Version: 4.7.x-1.3 » 5.x-2.x-dev
StatusFileSize
new614 bytes

In the current 2.x-dev version I think there are two issues here both of which
should not be too difficult to handle.

The attached patch solves the issue of the new message count on the My Inbox menu
item and the new mail notification message showing 'zombie' messages. Basically
the function to get new message counts _privatemsg_get_new_messages() just
needs a JOIN on the user table.

The other issue you refer to above shouldn't happen in the current version from what
I can tell. The current version has code in the 'delete' operation for its implementation
of hook_user(). In the case of user deletion, all private messages sent by that user
are updated to a uid of 0. So any JOINs on the user table should still work as there is
a uid of 0 - in other words we are just ending up with the anonymous user.

Or maybe I am misunderstanding this?

Gabriel R.’s picture

Not working for me, I've applied the change manually and the zombiness is still around.
"You have 3 new private messages."

I am on Drupal 5.12, with
project = "privatemsg"
version = "5.x-3.0"
datestamp = "1216232413"

Could it be caused by my use of PHP and MySQL caching?

berdir’s picture

Status: Needs review » Closed (won't fix)

Sorry for pinging the participants, I am closing old issues.

This version of Privatemsg is not supported anymore, maybe it is already implemented in Privatemsg for Drupal 6 and if not, you are welcome to open a new issue for it.