View source
<?php
define('PRIVATEMSG_READ', 0);
define('PRIVATEMSG_UNREAD', 1);
define('PRIVATEMSG_UNLIMITED', 'unlimited');
function privatemsg_help($path, $arg) {
$output = '';
switch ($path) {
case 'admin/help#privatemsg':
$output .= '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Privatemsg module is designed to be a flexible and powerful system for sending and receiving internal messages. This includes user-to-user messages, user-to-role messages, messages from the site administrator, and much more. If you want some or all users on your site to have their own "mailbox"--and other users with the proper permissions to be able to message them through this mailbox--then this is the module for you.') . '</p>';
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<p>' . t('One of the strengths of Privatemsg is that it has a broad feature set and a modular architecture. The core Private Message module includes features such as threaded conversations (making it easier to keep track of messages and replies), search capability, new message alerts (via Drupal messages and blocks), and message tokens (similar to a mail merge).') . '</p>';
$output .= '<dl>';
$output .= '<dt>' . t('<h6>Configuration Steps</h6>') . '</dt>';
$output .= '<dd>' . t('1. Go to People > Permissions (admin/people/permissions) and find the relevant module permissions underneath the "Private messages" section. If you are not logged in as user #1, you must give at least one role (probably the administrator role) the "Administer privatemsg" permission to configure this module.') . '</dd>';
$output .= '<dd>' . t('2. On this same Permissions page, give at least one role the "Read private messages" permission and the "Write new private messages" permission. This will allow members of that role to read and write private messages.') . '</dd>';
$output .= '<dd>' . t('3. Go to Configuration > Private messages (admin/config/messaging/privatemsg) and configure the module settings per your requirements. If you have various sub-modules enabled, their settings pages may appear as tabs on this page. ') . '</dd>';
$output .= '<dd>' . t('4. Login as a user with the role we specified in Step #2. Visit /messages to see the user's mailbox. Visit /messages/new to write a new message.') . '</dd>';
$output .= '</dl>';
}
return $output;
}
function privatemsg_permission() {
return array(
'administer privatemsg settings' => array(
'title' => t('Administer privatemsg'),
'description' => t('Perform maintenance tasks for privatemsg'),
),
'read privatemsg' => array(
'title' => t('Read private messages'),
'description' => t('Read private messages'),
),
'read all private messages' => array(
'title' => t('Read all private messages'),
'description' => t('Includes messages of other users'),
),
'write privatemsg' => array(
'title' => t('Write new private messages'),
'description' => t('Write new private messages'),
),
'delete privatemsg' => array(
'title' => t('Delete private messages'),
'description' => t('Delete private messages'),
),
'allow disabling privatemsg' => array(
'title' => t('Allow disabling private messages'),
'description' => t("Allows user to disable privatemsg so that they can't receive or send any private messages."),
),
'reply only privatemsg' => array(
'title' => t('Reply to private messages'),
'description' => t('Allows to reply to private messages but not send new ones. Note that the write new private messages permission includes replies.'),
),
'use tokens in privatemsg' => array(
'title' => t('Use tokens in private messages'),
'description' => t("Allows user to use available tokens when sending private messages."),
),
'select text format for privatemsg' => array(
'title' => t('Select text format for private messages'),
'description' => t('Allows to choose the text format when sending private messages. Otherwise, the default is used.'),
),
);
}
function _privatemsg_generate_user_array($string, $slice = NULL) {
$users = explode(',', $string);
if (!is_null($slice)) {
$users = array_slice($users, $slice);
}
$participants = array();
foreach ($users as $uid) {
if ((int) $uid > 0) {
$user_ids = privatemsg_user_load_multiple(array(
$uid,
));
if ($account = array_shift($user_ids)) {
$participants[privatemsg_recipient_key($account)] = $account;
}
}
elseif (strpos($uid, '_') !== FALSE) {
list($type, $id) = explode('_', $uid);
$type_info = privatemsg_recipient_get_type($type);
if ($type_info && isset($type_info['load']) && is_callable($type_info['load'])) {
$temp_load = $type_info['load'](array(
$id,
));
if ($participant = array_shift($temp_load)) {
$participants[privatemsg_recipient_key($participant)] = $participant;
}
}
}
}
return $participants;
}
function _privatemsg_format_participants($part_array, $limit = NULL, $no_text = FALSE) {
global $user;
if (count($part_array) > 0) {
$to = array();
$limited = FALSE;
foreach ($part_array as $account) {
if (isset($account->type) && in_array($account->type, array(
'hidden',
'user',
)) && $account->recipient == $user->uid) {
array_unshift($to, $no_text ? t('You', array(), array(
'context' => 'Dative',
)) : t('you', array(), array(
'context' => 'Dative',
)));
continue;
}
if (isset($account->type) && $account->type == 'hidden') {
continue;
}
if (is_int($limit) && count($to) >= $limit) {
$limited = TRUE;
break;
}
$to[] = privatemsg_recipient_format($account);
}
$limit_string = '';
if ($limited) {
$limit_string = t(' and others');
}
if ($no_text) {
return implode(', ', $to) . $limit_string;
}
$last = array_pop($to);
if (count($to) == 0) {
return t("From !last", array(
'!last' => $last,
));
}
else {
$participants = implode(', ', $to);
return t('Between !participants and !last', array(
'!participants' => $participants,
'!last' => $last,
));
}
}
return '';
}
function privatemsg_menu() {
$items['messages'] = array(
'title' => 'Messages',
'title callback' => 'privatemsg_title_callback',
'page callback' => 'privatemsg_list_page',
'page arguments' => array(
'list',
),
'file' => 'privatemsg.pages.inc',
'access callback' => 'privatemsg_user_access',
'type' => MENU_NORMAL_ITEM,
'menu_name' => 'user-menu',
);
$items['messages/list'] = array(
'title' => 'Messages',
'page callback' => 'privatemsg_list_page',
'page arguments' => array(
'list',
),
'file' => 'privatemsg.pages.inc',
'access callback' => 'privatemsg_user_access',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
'menu_name' => 'user-menu',
);
$items['messages/view/%privatemsg_thread'] = array(
'load arguments' => array(
NULL,
NULL,
TRUE,
),
'title' => 'Read message',
'page callback' => 'privatemsg_view',
'page arguments' => array(
2,
),
'file' => 'privatemsg.pages.inc',
'access callback' => 'privatemsg_view_access',
'access arguments' => array(
2,
),
'type' => MENU_LOCAL_TASK,
'weight' => -5,
'menu_name' => 'user-menu',
);
$items['messages/delete/%privatemsg_thread/%privatemsg_message'] = array(
'title' => 'Delete message',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'privatemsg_delete',
2,
3,
),
'file' => 'privatemsg.pages.inc',
'access callback' => 'privatemsg_user_access',
'access arguments' => array(
'delete privatemsg',
),
'type' => MENU_CALLBACK,
'weight' => -10,
'menu_name' => 'user-menu',
);
$items['messages/new'] = array(
'title' => 'Write new message',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'privatemsg_new',
2,
3,
NULL,
),
'file' => 'privatemsg.pages.inc',
'access callback' => 'privatemsg_user_access',
'access arguments' => array(
'write privatemsg',
),
'type' => MENU_LOCAL_ACTION,
'weight' => -3,
'menu_name' => 'user-menu',
);
$items['messages/autocomplete'] = array(
'page callback' => 'privatemsg_autocomplete',
'file' => 'privatemsg.pages.inc',
'access callback' => 'privatemsg_user_access',
'access arguments' => array(
'write privatemsg',
),
'type' => MENU_CALLBACK,
);
$items['admin/config/messaging'] = array(
'title' => 'Messaging',
'description' => 'Messaging systems.',
'page callback' => 'system_admin_menu_block_page',
'access arguments' => array(
'access administration pages',
),
'file' => 'system.admin.inc',
'file path' => drupal_get_path('module', 'system'),
);
$items['admin/config/messaging/privatemsg'] = array(
'title' => 'Private message settings',
'description' => 'Configure private messaging settings.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'privatemsg_admin_settings',
),
'file' => 'privatemsg.admin.inc',
'access arguments' => array(
'administer privatemsg settings',
),
'type' => MENU_NORMAL_ITEM,
);
$items['admin/config/messaging/privatemsg/settings'] = array(
'title' => 'Private message settings',
'description' => 'Configure private messaging settings.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'privatemsg_admin_settings',
),
'file' => 'privatemsg.admin.inc',
'access arguments' => array(
'administer privatemsg settings',
),
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
$items['messages/undo/action'] = array(
'title' => 'Private messages',
'description' => 'Undo last thread action',
'page callback' => 'privatemsg_undo_action',
'file' => 'privatemsg.pages.inc',
'access arguments' => array(
'read privatemsg',
),
'type' => MENU_CALLBACK,
'menu' => 'user-menu',
);
$items['user/%/messages'] = array(
'title' => 'Messages',
'page callback' => 'privatemsg_list_page',
'page arguments' => array(
'list',
1,
),
'file' => 'privatemsg.pages.inc',
'access callback' => 'privatemsg_user_access',
'access arguments' => array(
'read all private messages',
),
'type' => MENU_LOCAL_TASK,
);
return $items;
}
function privatemsg_menu_local_tasks_alter(&$data, $router_item, $root_path) {
$add_to_array = array(
'messages/list',
'messages/inbox',
'messages/sent',
);
foreach ($add_to_array as $add_to) {
if (strpos($root_path, $add_to) !== FALSE) {
$item = menu_get_item('messages/new');
if ($item['access']) {
$data['actions']['output'][] = array(
'#theme' => 'menu_local_action',
'#link' => $item,
);
}
break;
}
}
}
function privatemsg_user_access($permission = 'read privatemsg', $account = NULL) {
static $disabled_displayed = FALSE;
if ($account === NULL) {
global $user;
$account = $user;
}
if (!$account->uid) {
return FALSE;
}
if (privatemsg_is_disabled($account) && $permission == 'write privatemsg') {
if (arg(0) == 'messages' && variable_get('privatemsg_display_disabled_message', TRUE) && !$disabled_displayed) {
$disabled_displayed = TRUE;
drupal_set_message(t('You have disabled Privatemsg and are not allowed to write messages. Go to your <a href="@settings_url">Account settings</a> to enable it again.', array(
'@settings_url' => url('user/' . $account->uid . '/edit'),
)), 'warning');
}
return FALSE;
}
if (!user_access($permission, $account)) {
return FALSE;
}
return TRUE;
}
function privatemsg_view_access($thread) {
if (empty($thread['messages'])) {
return FALSE;
}
if (privatemsg_user_access('read privatemsg') && arg(1) == 'view') {
return TRUE;
}
return FALSE;
}
function privatemsg_is_disabled($account) {
if (!$account || !isset($account->uid) || !$account->uid) {
return FALSE;
}
if (!isset($account->privatemsg_disabled)) {
if ((!empty($account->roles) || ($account = user_load($account->uid))) && user_access('allow disabling privatemsg', $account)) {
$account->privatemsg_disabled = (bool) db_query('SELECT 1 FROM {pm_disable} WHERE uid = :uid ', array(
':uid' => $account->uid,
))
->fetchField();
}
else {
$account->privatemsg_disabled = FALSE;
}
}
return $account->privatemsg_disabled;
}
function privatemsg_thread_load($thread_id, $account = NULL, $start = NULL, $useAccessDenied = FALSE) {
$threads =& drupal_static(__FUNCTION__, array());
$thread_id = (int) $thread_id;
if ($thread_id > 0) {
$thread = array(
'thread_id' => $thread_id,
);
if (is_null($account)) {
global $user;
$account = clone $user;
}
if (!isset($threads[$account->uid])) {
$threads[$account->uid] = array();
}
if (!array_key_exists($thread_id, $threads[$account->uid])) {
$thread['participants'] = _privatemsg_load_thread_participants($thread_id, $account, FALSE, 'view');
$thread['read_all'] = FALSE;
if (empty($thread['participants']) && privatemsg_user_access('read all private messages', $account)) {
$thread['read_all'] = TRUE;
$thread['participants'] = _privatemsg_load_thread_participants($thread_id, FALSE, FALSE, 'view');
}
$query = _privatemsg_assemble_query('messages', array(
$thread_id,
), $thread['read_all'] ? NULL : $account);
$countQuery = db_select($query);
$countQuery
->addExpression('COUNT(*)');
$thread['message_count'] = $thread['to'] = $countQuery
->execute()
->fetchField();
$thread['from'] = 1;
$max_amount = variable_get('privatemsg_view_max_amount', 20);
if (is_null($start)) {
if (isset($_GET['start']) && $_GET['start'] < $thread['message_count']) {
$start = $_GET['start'];
}
elseif (!variable_get('privatemsg_view_use_max_as_default', FALSE) && $max_amount == PRIVATEMSG_UNLIMITED) {
$start = PRIVATEMSG_UNLIMITED;
}
else {
$start = $thread['message_count'] - (variable_get('privatemsg_view_use_max_as_default', FALSE) ? variable_get('privatemsg_view_default_amount', 10) : $max_amount);
}
}
if ($start != PRIVATEMSG_UNLIMITED) {
if ($max_amount == PRIVATEMSG_UNLIMITED) {
$last_page = 0;
$max_amount = $thread['message_count'];
}
else {
$paging_count = variable_get('privatemsg_view_use_max_as_default', FALSE) ? $thread['message_count'] - variable_get('privatemsg_view_default_amount', 10) : $thread['message_count'];
$last_page = $paging_count % $max_amount;
}
if ($start < 0) {
$start = 0;
}
$thread['start'] = $start;
if ($start + $max_amount + 1 < $thread['message_count']) {
$thread['to'] = $start + $max_amount;
$thread['newer_start'] = $start + $max_amount;
}
if ($start - $max_amount >= 0) {
$thread['older_start'] = $start - $max_amount;
}
elseif ($start > 0) {
$thread['older_start'] = 0;
}
if ($start < $last_page && $max_amount != PRIVATEMSG_UNLIMITED && $max_amount < $thread['message_count']) {
unset($thread['older_start']);
$thread['to'] = $thread['newer_start'] = $max_amount = $last_page;
$start = 0;
}
$thread['from'] = $start + 1;
$query
->range($start, $max_amount);
}
$conditions = array();
if (!$thread['read_all']) {
$conditions['account'] = $account;
}
$ids = $query
->execute()
->fetchCol();
if (count($ids)) {
$thread['messages'] = privatemsg_message_load_multiple($ids, $conditions);
}
if (empty($thread['messages'])) {
if ($useAccessDenied) {
$query = _privatemsg_assemble_query('messages', array(
$thread_id,
), NULL);
$exists = $query
->countQuery()
->execute()
->fetchField();
if (!$exists) {
$thread = FALSE;
}
}
else {
$thread = FALSE;
}
}
else {
$thread['user'] = $account;
$message = current($thread['messages']);
$thread['subject'] = $thread['subject-original'] = $message->subject;
if ($message->has_tokens) {
$thread['subject'] = privatemsg_token_replace($thread['subject'], array(
'privatemsg_message' => $message,
), array(
'sanitize' => TRUE,
'privatemsg-show-span' => FALSE,
));
}
}
$threads[$account->uid][$thread_id] = $thread;
}
return $threads[$account->uid][$thread_id];
}
return FALSE;
}
function privatemsg_privatemsg_view_template() {
return array(
'privatemsg-view' => 'Default view',
);
}
function privatemsg_cron() {
if (variable_get('privatemsg_flush_enabled', FALSE)) {
$query = _privatemsg_assemble_query('deleted', variable_get('privatemsg_flush_days', 30), variable_get('privatemsg_flush_max', 200));
foreach ($query
->execute()
->fetchCol() as $mid) {
$message = privatemsg_message_load($mid);
module_invoke_all('privatemsg_message_flush', $message);
db_delete('pm_index')
->condition('mid', $mid)
->execute();
db_delete('pm_message')
->condition('mid', $mid)
->execute();
}
}
$total_remaining = variable_get('privatemgs_cron_recipient_per_run', 1000);
$current_process = variable_get('privatemsg_cron_recipient_process', array());
$rows = array();
$types = privatemsg_recipient_get_types();
unset($types['user']);
$types = array_keys($types);
if (empty($types)) {
return;
}
$result = db_query("SELECT pmi.recipient, pmi.type, pmi.mid FROM {pm_index} pmi WHERE pmi.type IN (:types) AND pmi.is_new = 1", array(
':types' => $types,
));
foreach ($result as $row) {
if (!empty($current_process) && $current_process['mid'] == $row->mid && $current_process['type'] == $row->type && $current_process['recipient'] == $row->recipient) {
array_unshift($rows, $row);
}
else {
$rows[] = $row;
}
}
foreach ($rows as $row) {
$type = privatemsg_recipient_get_type($row->type);
if (isset($type['load']) && is_callable($type['load'])) {
$loaded = $type['load'](array(
$row->recipient,
));
if (empty($loaded)) {
continue;
}
$recipient = reset($loaded);
}
$offset = 0;
if (!empty($current_process) && $current_process['mid'] == $row->mid && $current_process['recipient'] == $row->recipient && $current_process['type'] == $row->type) {
$offset = $current_process['offset'];
}
$load_function = $type['generate recipients'];
$uids = $load_function($recipient, $total_remaining, $offset);
if (!empty($uids)) {
foreach ($uids as $uid) {
privatemsg_message_change_recipient($row->mid, $uid, 'hidden');
}
}
if (count($uids) < $total_remaining) {
$total_remaining -= count($uids);
db_update('pm_index')
->fields(array(
'is_new' => PRIVATEMSG_READ,
))
->condition('mid', $row->mid)
->condition('recipient', $row->recipient)
->condition('type', $row->type)
->execute();
if ($offset > 0) {
variable_set('privatemsg_cron_recipient_process', array());
}
}
else {
$existing_offset = isset($current_process['offset']) ? $current_process['offset'] : 0;
$current_process = (array) $row;
$current_process['offset'] = $existing_offset + count($uids);
variable_set('privatemsg_cron_recipient_process', $current_process);
break;
}
}
}
function privatemsg_theme() {
$templates = array(
'privatemsg_view' => array(
'variables' => array(
'message' => NULL,
),
'template' => variable_get('private_message_view_template', 'privatemsg-view'),
),
'privatemsg_from' => array(
'variables' => array(
'author' => NULL,
),
'template' => 'privatemsg-from',
),
'privatemsg_recipients' => array(
'variables' => array(
'message' => NULL,
),
'template' => 'privatemsg-recipients',
),
'privatemsg_between' => array(
'variables' => array(
'recipients' => NULL,
),
'template' => 'privatemsg-between',
),
'privatemsg_list_header' => array(
'file' => 'privatemsg.theme.inc',
'path' => drupal_get_path('module', 'privatemsg'),
'pattern' => 'privatemsg_list_header__',
'variables' => array(),
),
'privatemsg_list_field' => array(
'file' => 'privatemsg.theme.inc',
'path' => drupal_get_path('module', 'privatemsg'),
'pattern' => 'privatemsg_list_field__',
'variables' => array(
'thread' => array(),
),
),
'privatemsg_new_block' => array(
'file' => 'privatemsg.theme.inc',
'path' => drupal_get_path('module', 'privatemsg'),
'variables' => array(
'count',
),
),
'privatemsg_username' => array(
'file' => 'privatemsg.theme.inc',
'path' => drupal_get_path('module', 'privatemsg'),
'variables' => array(
'recipient' => NULL,
'options' => array(),
),
),
);
module_load_include('inc', 'privatemsg', 'privatemsg.theme');
$templates += drupal_find_theme_functions($templates, array(
'theme',
));
return $templates;
}
function template_preprocess_privatemsg_view(&$vars) {
global $user;
$message = $vars['message'];
$vars['mid'] = isset($message->mid) ? $message->mid : NULL;
$vars['message_classes'] = isset($message->classes) ? $message->classes : array();
$vars['thread_id'] = isset($message->thread_id) ? $message->thread_id : NULL;
$vars['author_picture'] = theme('user_picture', array(
'account' => $message->author,
));
if ($user->uid == $message->author->uid) {
$vars['author_name_link'] = t('You');
}
else {
$vars['author_name_link'] = privatemsg_recipient_format($message->author);
}
$vars['message_timestamp'] = privatemsg_format_date($message->timestamp);
$message->content = array(
'#view_mode' => 'message',
'body' => array(
'#markup' => check_markup($message->body, $message->format),
'#weight' => -4,
),
);
if ($message->has_tokens) {
$message->content['body']['#markup'] = privatemsg_token_replace($message->content['body']['#markup'], array(
'privatemsg_message' => $message,
), array(
'privatemsg-token-notice' => TRUE,
'sanitize' => TRUE,
));
}
field_attach_prepare_view('privatemsg_message', array(
$vars['mid'] => $message,
), 'message');
$message->content += field_attach_view('privatemsg_message', $message, 'message');
$vars['message_body'] = drupal_render($message->content);
if (isset($vars['mid']) && isset($vars['thread_id']) && privatemsg_user_access('delete privatemsg')) {
$vars['message_actions'][] = array(
'title' => t('Delete'),
'href' => 'messages/delete/' . $vars['thread_id'] . '/' . $vars['mid'],
);
}
$vars['message_anchors'][] = 'privatemsg-mid-' . $vars['mid'];
if (!empty($message->is_new)) {
$vars['message_anchors'][] = 'new';
$vars['new'] = drupal_ucfirst(t('new'));
}
drupal_alter('privatemsg_message_view', $vars);
$vars['message_actions'] = !empty($vars['message_actions']) ? theme('links', array(
'links' => $vars['message_actions'],
'attributes' => array(
'class' => array(
'privatemsg-message-actions',
'links',
'inline',
),
),
)) : '';
$vars['anchors'] = '';
foreach ($vars['message_anchors'] as $anchor) {
$vars['anchors'] .= '<a name="' . $anchor . '"></a>';
}
}
function template_preprocess_privatemsg_recipients(&$vars) {
$vars['participants'] = '';
if (isset($vars['thread']['participants'])) {
$vars['participants'] = _privatemsg_format_participants($vars['thread']['participants']);
}
}
function privatemsg_message_change_status($pmid, $status, $account = NULL) {
if (!$account) {
global $user;
$account = $user;
}
db_update('pm_index')
->fields(array(
'is_new' => $status,
))
->condition('mid', $pmid)
->condition('recipient', $account->uid)
->condition('type', array(
'hidden',
'user',
))
->execute();
module_invoke_all('privatemsg_message_status_changed', $pmid, $status, $account);
}
function privatemsg_unread_count($account = NULL) {
$counts =& drupal_static(__FUNCTION__, array());
if (!$account || $account->uid == 0) {
global $user;
$account = $user;
}
if (!isset($counts[$account->uid])) {
$counts[$account->uid] = _privatemsg_assemble_query('unread_count', $account)
->execute()
->fetchField();
}
return $counts[$account->uid];
}
function _privatemsg_load_thread_participants($thread_id, $account, $ignore_hidden = TRUE, $access = 'write') {
$query = _privatemsg_assemble_query('participants', $thread_id, $account);
$participants = array();
$to_load = array();
foreach ($query
->execute() as $participant) {
if ($ignore_hidden && $participant->type == 'hidden') {
continue;
}
elseif (privatemsg_recipient_access($participant->type, $access, $participant)) {
$to_load[$participant->type][] = $participant->recipient;
}
}
foreach ($to_load as $type => $ids) {
$type_info = privatemsg_recipient_get_type($type);
if (isset($type_info['load']) && is_callable($type_info['load'])) {
$loaded = $type_info['load']($ids);
if (is_array($loaded)) {
$participants += $loaded;
}
}
}
if ($access == 'write' && $account) {
if (isset($participants['user_' . $account->uid]) && count($participants) > 1) {
unset($participants['user_' . $account->uid]);
}
}
return $participants;
}
function _privatemsg_parse_userstring($input, $types_limitations = array()) {
if (is_string($input)) {
$input = explode(',', $input);
}
$invalid = array();
$recipients = array();
$duplicates = array();
$denieds = array();
foreach ($input as $string) {
$string = trim($string);
if (!empty($string)) {
$matches = array();
$access_denied = FALSE;
foreach (module_implements('privatemsg_name_lookup') as $module) {
$function = $module . '_privatemsg_name_lookup';
$return = $function($string);
if (isset($return) && is_array($return)) {
foreach ($return as $recipient) {
if (empty($recipient->type)) {
$recipient->type = 'user';
$recipient->recipient = $recipient->uid;
}
$matches[privatemsg_recipient_key($recipient)] = $recipient;
}
}
}
foreach ($matches as $key => $recipient) {
if (!privatemsg_recipient_access($recipient->type, 'write', $recipient)) {
unset($matches[$key]);
$access_denied = TRUE;
}
if (!empty($types_limitations) && !in_array($recipient->type, $types_limitations)) {
unset($matches[$key]);
}
}
drupal_alter('privatemsg_name_lookup_matches', $matches, $string);
$number_of_matches = count($matches);
switch ($number_of_matches) {
case 1:
$recipients += $matches;
break;
case 0:
if ($access_denied) {
$denieds[$string] = $string;
}
else {
$invalid[$string] = $string;
}
break;
default:
$duplicates[$string] = $matches;
break;
}
}
}
return array(
$recipients,
$invalid,
$duplicates,
$denieds,
);
}
function privatemsg_privatemsg_name_lookup($string) {
$string = trim(str_replace('[user]', '', $string));
if (!($error = module_invoke('user', 'validate_name', $string))) {
if ($recipient = user_load_by_name($string)) {
$recipient->recipient = $recipient->uid;
$recipient->type = 'user';
return array(
privatemsg_recipient_key($recipient) => $recipient,
);
}
}
}
function privatemsg_sql_list($account, $argument = 'list') {
$query = db_select('pm_message', 'pm')
->extend('TableSort')
->extend('PagerDefault');
$query
->join('pm_index', 'pmi', 'pm.mid = pmi.mid');
$count_query = db_select('pm_message', 'pm');
$count_query
->addExpression('COUNT(DISTINCT pmi.thread_id)', 'count');
$count_query
->join('pm_index', 'pmi', 'pm.mid = pmi.mid');
$count_query
->condition('pmi.recipient', $account->uid)
->condition('pmi.type', array(
'hidden',
'user',
))
->condition('pmi.deleted', 0);
$query
->setCountQuery($count_query);
$query
->addField('pmi', 'thread_id');
$query
->addExpression('MIN(pm.subject)', 'subject');
$query
->addExpression('MAX(pm.timestamp)', 'last_updated');
$query
->addExpression('MAX(pm.has_tokens)', 'has_tokens');
$query
->addExpression('SUM(pmi.is_new)', 'is_new');
$fields = array_filter(variable_get('privatemsg_display_fields', array(
'participants',
)));
if (in_array('count', $fields)) {
$query
->addExpression('COUNT(distinct pmi.mid)', 'count');
}
if (in_array('participants', $fields)) {
if (db_driver() == 'pgsql') {
$query
->addExpression("array_to_string(array(SELECT DISTINCT pmia.type || '_' || pmia.recipient\n FROM {pm_index} pmia\n WHERE pmia.type <> 'hidden' AND pmia.thread_id = pmi.thread_id AND pmia.recipient <> :current), ',')", 'participants', array(
':current' => $account->uid,
));
}
else {
$query
->addExpression("(SELECT GROUP_CONCAT(DISTINCT CONCAT(pmia.type, '_', pmia.recipient))\n FROM {pm_index} pmia\n WHERE pmia.type <> 'hidden' AND pmia.thread_id = pmi.thread_id AND pmia.recipient <> :current)", 'participants', array(
':current' => $account->uid,
));
}
}
if (in_array('thread_started', $fields)) {
$query
->addExpression('MIN(pm.timestamp)', 'thread_started');
}
return $query
->condition('pmi.recipient', $account->uid)
->condition('pmi.type', array(
'hidden',
'user',
))
->condition('pmi.deleted', 0)
->groupBy('pmi.thread_id')
->orderByHeader(_privatemsg_list_headers(array_merge(array(
'subject',
'last_updated',
), $fields)))
->limit(variable_get('privatemsg_per_page', 25));
}
function privatemsg_sql_messages($threads, $account = NULL, $load_all = FALSE) {
$query = db_select('pm_index', 'pmi');
$query
->addField('pmi', 'mid');
$query
->join('pm_message', 'pm', 'pm.mid = pmi.mid');
if (!$load_all) {
$query
->condition('pmi.deleted', 0);
}
$query
->condition('pmi.thread_id', $threads)
->groupBy('pm.timestamp')
->groupBy('pmi.mid')
->orderBy('pm.timestamp', 'ASC')
->orderBy('pmi.mid', 'ASC');
if ($account) {
$query
->condition('pmi.recipient', $account->uid)
->condition('pmi.type', array(
'hidden',
'user',
));
}
return $query;
}
function privatemsg_sql_participants($thread_id, $account = NULL) {
$query = db_select('pm_index', 'pmi');
$query
->leftJoin('users', 'u', "u.uid = pmi.recipient AND pmi.type IN ('user', 'hidden')");
$query
->fields('pmi', array(
'recipient',
'type',
))
->fields('u', array(
'name',
))
->condition('pmi.thread_id', $thread_id);
if ($account) {
$query
->condition(db_or()
->condition('pmi.type', 'hidden', '<>')
->condition(db_and()
->condition('pmi.type', 'hidden')
->condition('pmi.recipient', $account->uid)));
$query
->where('(SELECT 1 FROM {pm_index} pmiu WHERE pmi.mid = pmiu.mid AND pmiu.recipient = :recipient LIMIT 1) = 1', array(
':recipient' => $account->uid,
));
}
else {
$query
->condition('pmi.type', 'hidden', '<>');
}
return $query
->groupBy('pmi.recipient')
->groupBy('u.name')
->groupBy('pmi.type');
}
function privatemsg_sql_unread_count($account) {
$query = db_select('pm_index', 'pmi');
$query
->addExpression('COUNT(DISTINCT thread_id)', 'unread_count');
return $query
->condition('pmi.deleted', 0)
->condition('pmi.is_new', 1)
->condition('pmi.recipient', $account->uid)
->condition('pmi.type', array(
'hidden',
'user',
));
}
function privatemsg_sql_autocomplete($search, $names) {
$query = db_select('users', 'u')
->fields('u', array(
'uid',
))
->condition('u.name', $search . '%', 'LIKE')
->condition('u.status', 0, '<>')
->where('NOT EXISTS (SELECT 1 FROM {pm_disable} pd WHERE pd.uid=u.uid)')
->orderBy('u.name', 'ASC')
->range(0, 10);
if (!empty($names)) {
$query
->condition('u.name', $names, 'NOT IN');
}
return $query;
}
function privatemsg_sql_deleted($days, $max) {
$query = db_select('pm_message', 'pm');
$query
->addField('pm', 'mid');
$query
->join('pm_index', 'pmi', 'pmi.mid = pm.mid');
return $query
->groupBy('pm.mid')
->having('MIN(pmi.deleted) > 0 AND MAX(pmi.deleted) < :old', array(
':old' => REQUEST_TIME - $days * 86400,
))
->range(0, $max);
}
function privatemsg_user_view($account) {
if (($url = privatemsg_get_link(array(
$account,
))) && variable_get('privatemsg_display_profile_links', 1)) {
$account->content['privatemsg_send_new_message'] = array(
'#type' => 'link',
'#title' => t('Send this user a private message'),
'#href' => $url,
'#weight' => 10,
'#options' => array(
'query' => drupal_get_destination(),
'title' => t('Send this user a private message'),
'attributes' => array(
'class' => 'privatemsg-send-link privatemsg-send-link-profile',
),
),
);
}
}
function privatemsg_user_login(&$edit, $account) {
if (variable_get('privatemsg_display_loginmessage', TRUE) && privatemsg_user_access()) {
$count = privatemsg_unread_count();
if ($count) {
drupal_set_message(format_plural($count, 'You have <a href="@messages">1 unread message</a>.', 'You have <a href="@messages">@count unread messages</a>', array(
'@messages' => url('messages'),
)));
}
}
}
function privatemsg_user_cancel($edit, $account, $method) {
switch ($method) {
case 'user_cancel_reassign':
db_update('pm_message')
->condition('author', $account->uid)
->fields(array(
'author' => 0,
))
->execute();
break;
case 'user_cancel_block_unpublish':
_privatemsg_delete_data($account);
break;
}
db_delete('pm_disable')
->condition('uid', $account->uid)
->execute();
}
function privatemsg_user_delete($account) {
_privatemsg_delete_data($account);
db_delete('pm_disable')
->condition('uid', $account->uid)
->execute();
}
function _privatemsg_delete_data($account) {
$mids = db_select('pm_message', 'pm')
->fields('pm', array(
'mid',
))
->condition('author', $account->uid)
->execute()
->fetchCol();
if (!empty($mids)) {
db_delete('pm_index')
->condition('mid', $mids)
->execute();
}
db_delete('pm_message')
->condition('author', $account->uid)
->execute();
db_delete('pm_index')
->condition('recipient', $account->uid)
->condition('type', array(
'user',
'hidden',
))
->execute();
db_delete('pm_disable')
->condition('uid', $account->uid)
->execute();
}
function privatemsg_form_alter(&$form, &$form_state, $form_id) {
if (($form_id == 'user_register_form' || $form_id == 'user_profile_form') && $form['#user_category'] == 'account') {
if (!isset($form['privatemsg'])) {
$form['privatemsg'] = array();
}
$form['privatemsg'] += array(
'#type' => 'fieldset',
'#title' => t('Private messages'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
'#weight' => 10,
'#after_build' => array(
'privatemsg_account_fieldset_remove_if_empty',
),
);
if ((user_access('write privatemsg') || user_access('read privatemsg')) && user_access('allow disabling privatemsg')) {
$form['privatemsg']['pm_enable'] = array(
'#type' => 'checkbox',
'#title' => t('Enable private messages'),
'#default_value' => !privatemsg_is_disabled($form['#user']),
'#description' => t('Disabling private messages prevents you from sending or receiving messages from other users.'),
'#weight' => -10,
);
}
}
}
function privatemsg_account_fieldset_remove_if_empty($element) {
if (count(element_children($element)) == 0) {
$element['#access'] = FALSE;
}
return $element;
}
function privatemsg_user_insert(&$edit, $account, $category) {
privatemsg_user_update($edit, $account, $category);
}
function privatemsg_user_update(&$edit, $account, $category) {
if (isset($edit['pm_enable']) && (user_access('write privatemsg') || user_access('read privatemsg')) && user_access('allow disabling privatemsg')) {
$current = privatemsg_is_disabled($account);
$disabled = !$edit['pm_enable'];
$edit['pm_enable'] = NULL;
$account->privatemsg_disabled = $disabled;
if ($current != $disabled) {
if ($disabled) {
db_insert('pm_disable')
->fields(array(
'uid' => $account->uid,
))
->execute();
}
else {
db_delete('pm_disable')
->condition('uid', $account->uid)
->execute();
}
}
}
}
function privatemsg_privatemsg_block_message($author, $recipients, $context = array()) {
$blocked = array();
if (privatemsg_is_disabled($author)) {
$blocked[] = array(
'recipient' => 'user_' . $author->uid,
'message' => t('You have disabled private message sending and receiving.'),
);
}
foreach ($recipients as $recipient) {
if (privatemsg_is_disabled($recipient)) {
$blocked[] = array(
'recipient' => 'user_' . $recipient->uid,
'message' => t('%recipient has disabled private message receiving.', array(
'%recipient' => privatemsg_recipient_format($recipient, array(
'plain' => TRUE,
)),
)),
);
}
else {
if (isset($recipient->status) && !$recipient->status) {
$blocked[] = array(
'recipient' => 'user_' . $recipient->uid,
'message' => t('%recipient has disabled his or her account.', array(
'%recipient' => privatemsg_recipient_format($recipient, array(
'plain' => TRUE,
)),
)),
);
}
}
}
return $blocked;
}
function privatemsg_block_info() {
$blocks = array();
$blocks['privatemsg-menu'] = array(
'info' => t('Privatemsg links'),
'cache' => DRUPAL_NO_CACHE,
);
$blocks['privatemsg-new'] = array(
'info' => t('New message indication'),
'cache' => DRUPAL_NO_CACHE,
);
return $blocks;
}
function privatemsg_block_view($delta) {
$block = array();
switch ($delta) {
case 'privatemsg-menu':
$block = _privatemsg_block_menu();
break;
case 'privatemsg-new':
$block = _privatemsg_block_new();
break;
}
return $block;
}
function privatemsg_block_configure($delta = '') {
if ($delta == 'privatemsg-new') {
$form['notification'] = array(
'#type' => 'checkbox',
'#title' => t('Display block when there are no new messages'),
'#default_value' => variable_get('privatemsg_no_messages_notification', 0),
'#description' => t('Enable this to have this block always displayed, even if there are no new messages'),
);
return $form;
}
}
function privatemsg_block_save($delta = '', $edit = array()) {
if ($delta == 'privatemsg-new') {
variable_set('privatemsg_no_messages_notification', $edit['notification']);
}
}
function privatemsg_title_callback($title = NULL) {
$count = privatemsg_unread_count();
if ($count > 0) {
return format_plural($count, 'Messages (1 new)', 'Messages (@count new)');
}
return t('Messages');
}
function _privatemsg_block_new() {
$block = array();
if (!privatemsg_user_access()) {
return $block;
}
$count = privatemsg_unread_count();
if ($count || variable_get('privatemsg_no_messages_notification', 0)) {
$block = array(
'subject' => $count ? format_plural($count, 'New message', 'New messages') : t('No new messages'),
'content' => theme('privatemsg_new_block', array(
'count' => $count,
)),
);
return $block;
}
return array();
}
function _privatemsg_block_menu() {
$block = array();
$links = array();
if (privatemsg_user_access('write privatemsg')) {
$links[] = l(t('Write new message'), 'messages/new');
}
if (privatemsg_user_access('read privatemsg') || privatemsg_user_access('read all private messages')) {
$links[] = l(privatemsg_title_callback(), 'messages');
}
if (count($links)) {
$block = array(
'subject' => t('Private messages'),
'content' => theme('item_list', array(
'items' => $links,
)),
);
}
return $block;
}
function privatemsg_message_change_delete($pmid, $delete, $account = NULL) {
$delete_value = 0;
if ($delete == TRUE) {
$delete_value = REQUEST_TIME;
}
$update = db_update('pm_index')
->fields(array(
'deleted' => $delete_value,
))
->condition('mid', $pmid);
if ($account) {
$update
->condition('recipient', $account->uid)
->condition('type', array(
'user',
'hidden',
));
}
$update
->execute();
}
function privatemsg_new_thread($recipients, $subject, $body = NULL, $options = array()) {
global $user;
$author = clone $user;
$message = (object) $options;
$message->subject = $subject;
$message->body = $body;
foreach ($recipients as $recipient) {
if (!isset($recipient->type)) {
$recipient->type = 'user';
$recipient->recipient = $recipient->uid;
}
$message->recipients[privatemsg_recipient_key($recipient)] = $recipient;
}
if (!isset($message->author)) {
$message->author = $author;
}
if (!isset($message->timestamp)) {
$message->timestamp = REQUEST_TIME;
}
if (!isset($message->format)) {
$message->format = filter_default_format($message->author);
}
$validated = _privatemsg_validate_message($message);
if ($validated['success']) {
$validated['message'] = _privatemsg_send($message);
if ($validated['message'] !== FALSE) {
_privatemsg_handle_recipients($validated['message']->mid, $validated['message']->recipients, FALSE);
}
}
return $validated;
}
function privatemsg_reply($thread_id, $body, $options = array()) {
global $user;
$author = clone $user;
$message = (object) $options;
$message->body = $body;
if (!isset($message->author)) {
$message->author = $author;
}
if (!isset($message->timestamp)) {
$message->timestamp = REQUEST_TIME;
}
if (!isset($message->format)) {
$message->format = filter_default_format($message->author);
}
$first_message = privatemsg_message_load($thread_id, $message->author);
if (!$first_message) {
return array(
'success' => FALSE,
'messages' => array(
'error' => array(
t('Thread %thread_id not found, unable to answer', array(
'%thread_id' => $thread_id,
)),
),
),
);
}
$message->thread_id = $thread_id;
$message->recipients = _privatemsg_load_thread_participants($thread_id, $message->author);
$message->subject = $first_message->subject;
$validated = _privatemsg_validate_message($message);
if ($validated['success']) {
$validated['message'] = _privatemsg_send($message);
if ($validated['message'] !== FALSE) {
_privatemsg_handle_recipients($validated['message']->mid, $validated['message']->recipients, FALSE);
}
}
return $validated;
}
function _privatemsg_validate_message(&$message, $form = FALSE) {
$messages = array(
'error' => array(),
'warning' => array(),
);
if (!(privatemsg_user_access('write privatemsg', $message->author) || privatemsg_user_access('reply only privatemsg', $message->author) && isset($message->thread_id))) {
if ($form) {
form_set_error('author', t('You are not allowed to write messages.'));
return array(
'success' => FALSE,
'messages' => $messages,
);
}
else {
$messages['error'][] = t('@user is not allowed to write messages.', array(
'@user' => privatemsg_recipient_format($message->author, array(
'plain' => TRUE,
)),
));
return array(
'success' => FALSE,
'messages' => $messages,
);
}
}
$message->subject = trim($message->subject);
if (empty($message->subject)) {
if ($form) {
form_set_error('subject', t('You must include a subject line with your message.'));
}
else {
$messages['error'][] = t('A subject must be included with the message.');
}
}
if (!empty($message->thread_id) && ($message->body === NULL || $message->body === '')) {
if ($form) {
form_set_error('body', t('You must include a message in your reply.'));
}
else {
$messages['error'][] = t('A message must be included in your reply.');
}
}
if (!filter_access(filter_format_load($message->format), $message->author)) {
if ($form) {
form_set_error('format', t('You are not allowed to use the specified format.'));
}
else {
$messages['error'][] = t('@user is not allowed to use the specified input format.', array(
'@user' => privatemsg_recipient_format($message->author, array(
'plain' => TRUE,
)),
));
}
}
if (empty($message->recipients) || !is_array($message->recipients)) {
if ($form) {
form_set_error('recipient', t('You must include at least one valid recipient.'));
}
else {
$messages['error'][] = t('At least one valid recipient must be included with the message.');
}
}
if (!empty($message->recipients) && is_array($message->recipients)) {
foreach (module_invoke_all('privatemsg_block_message', $message->author, $message->recipients, (array) $message) as $blocked) {
unset($message->recipients[$blocked['recipient']]);
if ($form) {
drupal_set_message($blocked['message'], 'warning');
}
else {
$messages['warning'][] = $blocked['message'];
}
}
}
if (empty($message->recipients)) {
if ($form) {
form_set_error('recipient', t('You are not allowed to send this message because all recipients are blocked.'));
}
else {
$messages['error'][] = t('The message cannot be sent because all recipients are blocked.');
}
}
$message->has_tokens = privatemsg_user_access('use tokens in privatemsg', $message->author) && count(token_scan($message->subject . $message->body));
$messages = array_merge_recursive(module_invoke_all('privatemsg_message_validate', $message, $form), $messages);
$success = empty($messages['error']) || $form && count((array) form_get_errors()) > 0;
return array(
'success' => $success,
'messages' => $messages,
);
}
function _privatemsg_send($message) {
$transaction = db_transaction();
try {
drupal_alter('privatemsg_message_presave', $message);
field_attach_presave('privatemsg_message', $message);
$query = db_insert('pm_index')
->fields(array(
'mid',
'thread_id',
'recipient',
'type',
'is_new',
'deleted',
));
if (isset($message->read_all) && $message->read_all && isset($message->thread_id)) {
$query_messages = _privatemsg_assemble_query('messages', array(
$message->thread_id,
), NULL);
foreach ($query_messages
->execute()
->fetchCol() as $mid) {
$query
->values(array(
'mid' => $mid,
'thread_id' => $message->thread_id,
'recipient' => $message->author->uid,
'type' => 'user',
'is_new' => 0,
'deleted' => 0,
));
}
}
$args = array();
$args['subject'] = $message->subject;
$args['author'] = $message->author->uid;
$args['body'] = $message->body;
$args['format'] = $message->format;
$args['timestamp'] = $message->timestamp;
$args['has_tokens'] = (int) $message->has_tokens;
$mid = db_insert('pm_message')
->fields($args)
->execute();
$message->mid = $mid;
if (!isset($message->thread_id)) {
$message->thread_id = $mid;
}
foreach ($message->recipients as $recipient) {
$query
->values(array(
'mid' => $mid,
'thread_id' => $message->thread_id,
'recipient' => $recipient->recipient,
'type' => $recipient->type,
'is_new' => 1,
'deleted' => 0,
));
}
if (!isset($message->recipients['user_' . $message->author->uid])) {
$query
->values(array(
'mid' => $mid,
'thread_id' => $message->thread_id,
'recipient' => $message->author->uid,
'type' => 'user',
'is_new' => 0,
'deleted' => 0,
));
}
$query
->execute();
module_invoke_all('privatemsg_message_insert', $message);
field_attach_insert('privatemsg_message', $message);
cache_clear_all("field:privatemsg_message:{$message->mid}", 'cache_field');
} catch (Exception $exception) {
$transaction
->rollback();
watchdog_exception('privatemsg', $exception);
throw $exception;
}
return $message;
}
function privatemsg_get_link($recipients, $account = array(), $subject = NULL) {
if ($account == NULL) {
global $user;
$account = $user;
}
if (!is_array($recipients)) {
$recipients = array(
$recipients,
);
}
if (!privatemsg_user_access('write privatemsg', $account) || $account->uid == 0) {
return FALSE;
}
$validated = array();
foreach ($recipients as $recipient) {
if (!privatemsg_user_access('read privatemsg', $recipient)) {
continue;
}
if (variable_get('privatemsg_display_link_self', TRUE) == FALSE && $account->uid == $recipient->uid) {
continue;
}
if (count(module_invoke_all('privatemsg_block_message', $account, array(
privatemsg_recipient_key($recipient) => $recipient,
))) > 0) {
continue;
}
$validated[] = $recipient->uid;
}
if (empty($validated)) {
return FALSE;
}
$url = 'messages/new/' . implode(',', $validated);
if (!is_null($subject)) {
$url .= '/' . str_replace('/', '%2F', $subject);
}
return $url;
}
function privatemsg_message_load($pmid, $account = NULL) {
if (is_array($pmid) || is_object($pmid)) {
return NULL;
}
$conditions = array();
if ($account) {
$conditions['account'] = $account;
}
$messages = privatemsg_message_load_multiple(array(
$pmid,
), $conditions);
return current($messages);
}
function privatemsg_message_load_multiple(array $pmids, array $conditions = array(), $reset = FALSE) {
$result = entity_load('privatemsg_message', $pmids, $conditions, $reset);
return $result;
}
function _privatemsg_assemble_query($query) {
if (is_array($query)) {
$query_id = $query[0];
$query_group = $query[1];
}
else {
$query_id = $query;
$query_group = 'privatemsg';
}
$args = func_get_args();
unset($args[0]);
$query_function = $query_group . '_sql_' . $query_id;
if (!function_exists($query_function)) {
drupal_set_message(t('Query function %function does not exist', array(
'%function' => $query_function,
)), 'error');
return FALSE;
}
$query = call_user_func_array($query_function, $args);
$query
->addTag($query_group . '_' . $query_id);
foreach ($args as $id => $arg) {
$query
->addMetaData('arg_' . $id, $arg);
}
return $query;
}
function privatemsg_thread_change_status($threads, $status, $account = NULL) {
if (!is_array($threads)) {
$threads = array(
$threads,
);
}
if (empty($account)) {
global $user;
$account = clone $user;
}
$params = array(
':status' => $status,
':recipient' => $account->uid,
':threads' => $threads,
);
$result = db_query("SELECT mid FROM {pm_index} WHERE is_new <> :status AND recipient = :recipient and type IN ('user', 'hidden') AND thread_id IN (:threads)", $params);
$changed = $result
->fetchCol();
db_update('pm_index')
->fields(array(
'is_new' => $status,
))
->condition('thread_id', $threads)
->condition('recipient', $account->uid)
->condition('type', array(
'user',
'hidden',
))
->execute();
foreach ($changed as $mid) {
module_invoke_all('privatemsg_message_status_changed', $mid, $status, $account);
}
if ($status == PRIVATEMSG_UNREAD) {
drupal_set_message(format_plural(count($threads), 'Marked 1 thread as unread.', 'Marked @count threads as unread.'));
}
else {
drupal_set_message(format_plural(count($threads), 'Marked 1 thread as read.', 'Marked @count threads as read.'));
}
}
function _privatemsg_list_headers($keys) {
include_once drupal_get_path('module', 'privatemsg') . '/privatemsg.theme.inc';
$header = array();
foreach ($keys as $key) {
if ($return = theme('privatemsg_list_header__' . $key)) {
$header[$key] = $return;
}
}
uasort($header, 'element_sort');
foreach ($header as $key => $element) {
if (isset($header[$key]['#weight'])) {
unset($header[$key]['#weight']);
}
}
return $header;
}
function _privatemsg_list_thread($tableselect) {
foreach ($tableselect['#options'] as $id => $thread) {
$row = array();
if (!empty($thread['is_new'])) {
$row['#attributes']['class'][] = 'privatemsg-unread';
}
foreach ($thread as $key => $data) {
if ($return = theme('privatemsg_list_field__' . $key, array(
'thread' => $thread,
))) {
$row[$key] = $return;
}
}
$tableselect['#options'][$id] = $row;
}
return $tableselect;
}
function privatemsg_operation_execute($operation, $threads, $account = NULL) {
$threads = array_filter($threads);
if (empty($threads)) {
drupal_set_message(t('You must first select one (or more) messages before you can take that action.'), 'warning');
return FALSE;
}
if (isset($operation['callback arguments'])) {
$args = array_merge(array(
$threads,
), $operation['callback arguments']);
}
else {
$args = array(
$threads,
);
}
if ($account) {
$args[] = $account;
}
call_user_func_array($operation['callback'], $args);
if (!empty($operation['success message'])) {
drupal_set_message($operation['success message']);
}
if (isset($operation['undo callback']) && ($undo_function = $operation['undo callback'])) {
if (isset($operation['undo callback arguments'])) {
$undo_args = array_merge(array(
$threads,
), $operation['undo callback arguments']);
}
else {
$undo_args = array(
$threads,
);
}
if ($account) {
$undo_args['account'] = $account->uid;
}
$_SESSION['privatemsg']['undo callback'] = array(
'function' => $undo_function,
'args' => $undo_args,
);
$undo = url('messages/undo/action', array(
'query' => drupal_get_destination(),
));
drupal_set_message(t('The previous action can be <a href="!undo">undone</a>.', array(
'!undo' => $undo,
)));
}
module_invoke_all('privatemsg_operation_executed', $operation, $threads, $account);
return TRUE;
}
function privatemsg_thread_change_delete($threads, $delete, $account = NULL) {
if (!is_array($threads)) {
$threads = array(
$threads,
);
}
if (empty($account)) {
global $user;
$account = clone $user;
}
$query = _privatemsg_assemble_query('messages', $threads, $account, TRUE);
foreach ($query
->execute() as $row) {
privatemsg_message_change_delete($row->mid, $delete, $account);
}
if ($delete) {
drupal_set_message(format_plural(count($threads), 'Deleted 1 thread.', 'Deleted @count threads.'));
}
else {
drupal_set_message(format_plural(count($threads), 'Restored 1 thread.', 'Restored @count threads.'));
}
}
function privatemsg_privatemsg_thread_operations() {
$operations = array(
'mark as read' => array(
'label' => t('Mark as read'),
'callback' => 'privatemsg_thread_change_status',
'callback arguments' => array(
'status' => PRIVATEMSG_READ,
),
'undo callback' => 'privatemsg_thread_change_status',
'undo callback arguments' => array(
'status' => PRIVATEMSG_UNREAD,
),
),
'mark as unread' => array(
'label' => t('Mark as unread'),
'callback' => 'privatemsg_thread_change_status',
'callback arguments' => array(
'status' => PRIVATEMSG_UNREAD,
),
'undo callback' => 'privatemsg_thread_change_status',
'undo callback arguments' => array(
'status' => PRIVATEMSG_READ,
),
),
);
if (privatemsg_user_access('delete privatemsg')) {
$operations['delete'] = array(
'label' => t('Delete'),
'callback' => 'privatemsg_thread_change_delete',
'callback arguments' => array(
'delete' => 1,
),
'undo callback' => 'privatemsg_thread_change_delete',
'undo callback arguments' => array(
'delete' => 0,
),
'button' => TRUE,
);
}
return $operations;
}
function privatemsg_entity_info() {
return array(
'privatemsg_message' => array(
'label' => t('Privatemsg'),
'base table' => 'pm_message',
'fieldable' => TRUE,
'controller class' => 'PrivatemsgMessageController',
'uri callback' => 'privatemsg_message_uri_callback',
'entity keys' => array(
'id' => 'mid',
),
'bundles' => array(
'privatemsg_message' => array(
'label' => t('Private message'),
'admin' => array(
'path' => 'admin/config/messaging/privatemsg',
'access arguments' => array(
'administer privatemsg settings',
),
),
),
),
),
);
}
function privatemsg_message_uri_callback($message) {
$uri = array();
if (isset($message->mid) && isset($message->thread_id)) {
$uri = array(
'path' => 'messages/view/' . $message->thread_id,
'options' => array(),
);
if ($message->mid != $message->thread_id) {
$uri['options']['fragment'] = 'privatemsg-mid-' . $message->mid;
}
}
return $uri;
}
function privatemsg_build_modes($obj_type) {
$modes = array();
if ($obj_type == 'privatemsg_message') {
$modes['message'] = t('Message');
}
return $modes;
}
function privatemsg_node_view($node, $view_mode) {
$types = array_filter(variable_get('privatemsg_link_node_types', array()));
if (in_array($node->type, $types) && ($view_mode == 'full' || variable_get('privatemsg_display_on_teaser', 1) && $view_mode == 'teaser')) {
$url = privatemsg_get_link(user_load($node->uid));
if (!empty($url)) {
$node->content['links']['#links']['privatemsg_link'] = array(
'title' => t('Send author a message'),
'href' => $url . '/' . t('Message regarding @node', array(
'@node' => $node->title,
)),
'query' => drupal_get_destination(),
'attributes' => array(
'class' => 'privatemsg-send-link privatemsg-send-link-node',
),
);
}
}
}
function privatemsg_comment_view($comment) {
$types = array_filter(variable_get('privatemsg_link_node_types', array()));
if (in_array(node_load($comment->nid)->type, $types) && variable_get('privatemsg_display_on_comments', 0)) {
$url = privatemsg_get_link(user_load($comment->uid));
if (!empty($url)) {
$links['privatemsg_link'] = array(
'title' => t('Send author a message'),
'href' => $url . '/' . t('Message regarding @comment', array(
'@comment' => trim($comment->subject),
)),
'query' => drupal_get_destination(),
);
$comment->content['links']['privatemsg'] = array(
'#theme' => 'links',
'#links' => $links,
'#attributes' => array(
'class' => array(
'privatemsg-send-link',
'privatemsg-send-link-node',
'links',
'inline',
),
),
);
}
}
}
function privatemsg_views_api() {
return array(
'api' => 2,
'path' => drupal_get_path('module', 'privatemsg') . '/views',
);
}
function privatemsg_user_load_multiple($uids) {
$accounts = array();
foreach (user_load_multiple($uids) as $account) {
$account->recipient = $account->uid;
$account->type = 'user';
$accounts[privatemsg_recipient_key($account)] = $account;
}
return $accounts;
}
function privatemsg_recipient_key($recipient) {
if (empty($recipient->type)) {
return 'user_' . $recipient->uid;
}
return $recipient->type . '_' . $recipient->recipient;
}
function privatemsg_recipient_get_types() {
$types =& drupal_static(__FUNCTION__, NULL);
if ($types === NULL) {
$types = module_invoke_all('privatemsg_recipient_type_info');
if (!is_array($types)) {
$types = array();
}
drupal_alter('privatemsg_recipient_type_info', $types);
uasort($types, 'element_sort');
}
return $types;
}
function privatemsg_recipient_get_type($type) {
$types = privatemsg_recipient_get_types();
if (!is_string($type)) {
exit;
}
if (isset($types[$type])) {
return $types[$type];
}
}
function privatemsg_message_change_recipient($mid, $uid, $type = 'user', $add = TRUE) {
$message = privatemsg_message_load($mid);
$thread_id = $message->thread_id;
if ($add) {
$recipient = user_load($uid);
$context = $thread_id == $mid ? array() : array(
'thread_id' => $thread_id,
);
$user_blocked = module_invoke_all('privatemsg_block_message', $message->author, array(
privatemsg_recipient_key($recipient) => $recipient,
), $context);
if (count($user_blocked) != 0) {
return;
}
$query = db_select('pm_index', 'pmi');
$query
->addExpression('1');
$exists = $query
->condition('mid', $mid)
->condition('recipient', $uid)
->condition('type', $type == 'user' || $type == 'hidden' ? array(
'user',
'hidden',
) : $type)
->execute()
->fetchField();
if (!$exists) {
db_insert('pm_index')
->fields(array(
'mid' => $mid,
'thread_id' => $thread_id,
'recipient' => $uid,
'type' => $type,
'is_new' => 1,
'deleted' => 0,
))
->execute();
}
}
else {
db_delete('pm_index')
->condition('mid', $mid)
->condition('recipient', $uid)
->condition('type', $type)
->execute();
}
module_invoke_all('privatemsg_message_recipient_changed', $mid, $thread_id, $uid, $type, $add);
}
function _privatemsg_handle_recipients($mid, $recipients, $use_batch = TRUE) {
$batch = array(
'title' => t('Processing recipients'),
'operations' => array(),
'file' => drupal_get_path('module', 'privatemsg') . '/privatemsg.pages.inc',
'progress_message' => t('Processing recipients'),
);
$small_threshold = variable_get('privatemsg_recipient_small_threshold', 100);
foreach ($recipients as $recipient) {
if ($recipient->type != 'user' && $recipient->type != 'hidden') {
$type = privatemsg_recipient_get_type($recipient->type);
$count_function = $type['count'];
if (!is_callable($count_function)) {
db_update('pm_index')
->fields(array(
'is_new' => PRIVATEMSG_READ,
))
->condition('mid', $mid)
->condition('recipient', $recipient->recipient)
->condition('type', $recipient->type)
->execute();
drupal_set_message(t('Recipient type %type is not correctly implemented', array(
'%type' => $recipient->type,
)), 'error');
continue;
}
$count = $count_function($recipient);
if ($count < $small_threshold) {
$load_function = $type['generate recipients'];
if (!is_callable($load_function)) {
db_update('pm_index')
->fields(array(
'is_new' => PRIVATEMSG_READ,
))
->condition('mid', $mid)
->condition('recipient', $recipient->recipient)
->condition('type', $recipient->type)
->execute();
drupal_set_message(t('Recipient type %type is not correctly implemented', array(
'%type' => $recipient->type,
)), 'error');
continue;
}
$uids = $load_function($recipient, $small_threshold, 0);
if (!empty($uids)) {
foreach ($uids as $uid) {
privatemsg_message_change_recipient($mid, $uid, 'hidden');
}
}
db_update('pm_index')
->fields(array(
'is_new' => PRIVATEMSG_READ,
))
->condition('mid', $mid)
->condition('recipient', $recipient->recipient)
->condition('type', $recipient->type)
->execute();
continue;
}
if ($use_batch) {
$batch['operations'][] = array(
'privatemsg_load_recipients',
array(
$mid,
$recipient,
),
);
}
}
}
if ($use_batch && !empty($batch['operations'])) {
batch_set($batch);
}
}
function privatemsg_recipient_access($type_name, $permission, $recipient = NULL) {
if ($type = privatemsg_recipient_get_type($type_name)) {
if (!empty($type[$permission . ' callback']) && is_callable($type[$permission . ' callback'])) {
$callback = $type[$permission . ' callback'];
return $callback($recipient);
}
if (isset($type[$permission . ' access'])) {
if (is_bool($type[$permission . ' access'])) {
return $type[$permission . ' access'];
}
return user_access($type[$permission . ' access']);
}
}
return TRUE;
}
function privatemsg_recipient_format($recipient, $options = array()) {
if (!isset($recipient->type)) {
$recipient->type = 'user';
$recipient->recipient = $recipient->uid;
}
$type = privatemsg_recipient_get_type($recipient->type);
if (isset($type['format'])) {
return theme($type['format'], array(
'recipient' => $recipient,
'options' => $options,
));
}
return NULL;
}
function privatemsg_privatemsg_recipient_type_info() {
return array(
'user' => array(
'name' => t('User'),
'description' => t('Enter a user name to write a message to a user.'),
'load' => 'privatemsg_user_load_multiple',
'format' => 'privatemsg_username',
'autocomplete' => 'privatemsg_user_autocomplete',
'#weight' => 50,
),
);
}
function privatemsg_user_autocomplete($fragment, $names, $limit) {
$uids = _privatemsg_assemble_query('autocomplete', $fragment, $names)
->range(0, $limit)
->execute()
->fetchCol();
$query = _privatemsg_assemble_query('autocomplete', $fragment, $names);
$query
->preExecute();
$query
->getArguments();
$accounts = user_load_multiple(array_unique($uids));
$suggestions = array();
foreach ($accounts as $account) {
$account->type = 'user';
$account->recipient = $account->uid;
$suggestions[privatemsg_recipient_key($account)] = $account;
}
return $suggestions;
}
function privatemsg_field_extra_fields() {
$extra['user']['user'] = array(
'form' => array(
'privatemsg' => array(
'label' => 'Private msg',
'description' => t('Private messages'),
'weight' => 5,
),
),
'display' => array(
'privatemsg_send_new_message' => array(
'label' => 'Private msg',
'description' => t('Private messages'),
'weight' => 5,
),
),
);
$extra['privatemsg_message']['privatemsg_message'] = array(
'form' => array(
'recipient' => array(
'label' => t('To'),
'description' => t('Recipient field'),
'weight' => -10,
),
'subject' => array(
'label' => t('Message subject'),
'description' => t('Message subject'),
'weight' => -5,
),
'body' => array(
'label' => t('Message body'),
'description' => t('Message body'),
'weight' => -3,
),
'token' => array(
'label' => t('Token browser'),
'description' => t('Displays usable tokens in a table for those who are allowed to use tokens in private messages.'),
'weight' => -1,
),
),
'display' => array(
'body' => array(
'label' => t('Message body'),
'description' => t('Message body'),
'weight' => -4,
),
),
);
return $extra;
}
function privatemsg_file_download_access($field, $entity_type, $entity) {
global $user;
if ($entity_type == 'privatemsg_message') {
if (user_access('read all private messages')) {
return TRUE;
}
return (bool) db_query_range("SELECT 1 FROM {pm_index} WHERE recipient = :uid AND type IN ('user', 'hidden') AND mid = :mid", 0, 1, array(
':uid' => $user->uid,
':mid' => $entity->mid,
))
->fetchField();
}
}
function privatemsg_token_info() {
$type = array(
'name' => t('Private message'),
'description' => t('Tokens related to private messages.'),
'needs-data' => 'privatemsg_message',
);
$message['mid'] = array(
'name' => t("Message ID"),
'description' => t("The unique ID of the message."),
);
$message['thread-id'] = array(
'name' => t("Thread ID"),
'description' => t("The unique ID of the thread."),
);
$message['url'] = array(
'name' => t("URL"),
'description' => t("URL that points to the message."),
);
$message['subject'] = array(
'name' => t("Subject"),
'description' => t("The subject of the message."),
);
$message['body'] = array(
'name' => t("Body"),
'description' => t("The body of the message."),
);
$message['timestamp'] = array(
'name' => t("Date created"),
'description' => t("The date the message was sent."),
'type' => 'date',
);
$message['author'] = array(
'name' => t("Author"),
'description' => t("The author of the message."),
'type' => 'user',
);
$message['recipient'] = array(
'name' => t("Recipient"),
'description' => t("The recipient of the message."),
'type' => 'user',
);
return array(
'types' => array(
'privatemsg_message' => $type,
),
'tokens' => array(
'privatemsg_message' => $message,
),
);
}
function privatemsg_tokens($type, $tokens, array $data = array(), array $options = array()) {
global $user;
$url_options = array(
'absolute' => TRUE,
);
if (isset($options['language'])) {
$url_options['language'] = $options['language'];
$language_code = $options['language']->language;
}
else {
$language_code = NULL;
}
$recipient = $user;
if (isset($data['privatemsg_recipient'])) {
$recipient = $data['privatemsg_recipient'];
}
$sanitize = !empty($options['sanitize']);
$replacements = array();
if ($type == 'privatemsg_message' && !empty($data['privatemsg_message'])) {
$message = $data['privatemsg_message'];
foreach ($tokens as $name => $original) {
switch ($name) {
case 'mid':
$replacements[$original] = $message->mid;
break;
case 'thread-id':
$replacements[$original] = $message->thread_id;
break;
case 'subject':
if (empty($options['privatemsg_recursion'])) {
$subject = privatemsg_token_replace($message->subject, $data, $options + array(
'privatemsg_recursion' => 1,
));
}
else {
$subject = $message->subject;
}
$replacements[$original] = $sanitize ? check_plain($subject) : $subject;
break;
case 'body':
if (empty($options['privatemsg_recursion'])) {
$replacements[$original] = privatemsg_token_replace($sanitize ? check_markup($message->body, $message->format) : $message->body, $data, $options + array(
'privatemsg_recursion' => 1,
));
}
else {
$replacements[$original] = $sanitize ? check_markup($message->body, $message->format) : $message->body;
}
break;
case 'url':
$uri = entity_uri('privatemsg_message', $message);
$replacements[$original] = url($uri['path'], $url_options + $uri['options']);
break;
case 'author':
$replacements[$original] = $sanitize ? filter_xss(privatemsg_recipient_format($message->author, array(
'plain' => TRUE,
))) : privatemsg_recipient_format($message->author, array(
'plain' => TRUE,
));
break;
case 'recipient':
$replacements[$original] = $sanitize ? filter_xss(privatemsg_recipient_format($recipient, array(
'plain' => TRUE,
))) : privatemsg_recipient_format($recipient, array(
'plain' => TRUE,
));
break;
case 'timestamp':
$replacements[$original] = format_date($message->timestamp, 'medium', '', NULL, $language_code);
break;
}
}
if ($author_tokens = token_find_with_prefix($tokens, 'author')) {
$replacements += token_generate('user', $author_tokens, array(
'user' => $message->author,
), $options);
}
if ($recipient_tokens = token_find_with_prefix($tokens, 'recipient')) {
$replacements += token_generate('user', $recipient_tokens, array(
'user' => $recipient,
), $options);
}
if ($sent_tokens = token_find_with_prefix($tokens, 'timestamp')) {
$replacements += token_generate('date', $sent_tokens, array(
'date' => $message->timestamp,
), $options);
}
}
return $replacements;
}
function privatemsg_token_replace($text, $data, array $options = array()) {
global $user;
if (empty($data['privatemsg_recipient'])) {
$recipient = $user;
}
else {
$recipient = $data['privatemsg_recipient'];
}
if (isset($options['language'])) {
$url_options['language'] = $options['language'];
$language_code = $options['language']->language;
}
else {
$language_code = NULL;
}
$message = $data['privatemsg_message'];
$show_span = !isset($options['privatemsg-show-span']) || $options['privatemsg-show-span'];
$sql = "SELECT 1 FROM {pm_index} WHERE recipient = :uid AND type IN ('hidden', 'user') AND mid = :mid";
$args = array(
':uid' => $recipient->uid,
':mid' => $message->mid,
);
if ($message->author->uid == $recipient->uid || !db_query($sql, $args)
->fetchField()) {
$tokens = token_scan($text);
$invalid_tokens = array();
if (function_exists('token_get_invalid_tokens_by_context')) {
$invalid_tokens = token_get_invalid_tokens_by_context($text, array(
'privatemsg_message',
));
}
if (!empty($tokens)) {
$replacements = array();
foreach ($tokens as $tokens_type) {
foreach ($tokens_type as $original) {
if (in_array($original, $invalid_tokens)) {
$token = t('INVALID TOKEN @token', array(
'@token' => $original,
), array(
'langcode' => $language_code,
));
if (!$show_span) {
$replacements[$original] = '< ' . $token . ' >';
}
else {
$replacements[$original] = '<span class="privatemsg-token-invalid">< ' . $token . ' ></span>';
}
}
else {
$token = t('Token @token', array(
'@token' => $original,
), array(
'langcode' => $language_code,
));
if (!$show_span) {
$replacements[$original] = '< ' . $token . ' >';
}
else {
$replacements[$original] = '<span class="privatemsg-token-valid">< ' . $token . ' ></span>';
}
}
}
}
$text = str_replace(array_keys($replacements), $replacements, $text);
if (!empty($options['privatemsg-token-notice'])) {
$text .= '<p class="privatemsg-token-notice">' . t('Note: Valid tokens will be replaced when a recipient is reading this message.') . '</p>';
}
}
return $text;
}
return token_replace($text, $data, $options);
}
function privatemsg_entity_property_info() {
$info = array();
$properties =& $info['privatemsg_message']['properties'];
$properties = array(
'mid' => array(
'type' => 'integer',
'label' => t('Private message ID'),
'description' => t('Private message ID'),
),
'thread_id' => array(
'type' => 'integer',
'label' => t('Private message thread ID'),
'description' => t('Private message thread ID'),
'getter callback' => 'entity_property_verbatim_get',
),
'author' => array(
'type' => 'user',
'label' => t('Private message author'),
'description' => t('Private message author'),
'setter callback' => 'entity_property_verbatim_set',
),
'subject' => array(
'type' => 'text',
'label' => t('Private message subject'),
'description' => t('Private message subject'),
'setter callback' => 'entity_property_verbatim_set',
),
'body' => array(
'type' => 'text',
'label' => t('Private message body'),
'description' => t('Private message body'),
'setter callback' => 'entity_property_verbatim_set',
),
'timestamp' => array(
'type' => 'date',
'label' => t('Private message sent date'),
'description' => t('Private message sent date'),
),
);
return $info;
}
class PrivatemsgMessageController extends DrupalDefaultEntityController {
protected $account = NULL;
protected function attachLoad(&$messages, $revision_id = FALSE) {
global $user;
foreach ($messages as $message) {
$message->user = $this->account ? $this->account : $user;
if (!($message->author = user_load($message->author))) {
$message->author = user_load(0);
}
}
parent::attachLoad($messages, $revision_id);
}
protected function buildQuery($ids, $conditions = array(), $revision_id = FALSE) {
if (isset($conditions['account'])) {
$this->account = $conditions['account'];
unset($conditions['account']);
}
$query = parent::buildQuery($ids, $conditions, $revision_id);
$query
->fields('pmi', array(
'is_new',
'thread_id',
));
if ($this->account) {
$query
->condition('pmi.recipient', $this->account->uid)
->condition('pmi.type', array(
'hidden',
'user',
));
}
else {
$query
->distinct();
}
$query
->join('pm_index', 'pmi', "base.mid = pmi.mid");
return $query;
}
protected function cacheGet($ids, $conditions = array()) {
if (isset($conditions['account'])) {
unset($conditions['account']);
}
return parent::cacheGet($ids, $conditions);
}
}
function privatemsg_date_formats() {
$formats = array(
'g:i a',
'H:i',
'M j',
'j M',
'm/d/y',
'd/m/y',
'j/n/y',
'n/j/y',
);
$types = array_keys(privatemsg_date_format_types());
$date_formats = array();
foreach ($types as $type) {
foreach ($formats as $format) {
$date_formats[] = array(
'type' => $type,
'format' => $format,
'locales' => array(),
);
}
}
return $date_formats;
}
function privatemsg_date_format_types() {
return array(
'privatemsg_current_day' => t('Privatemsg: Current day'),
'privatemsg_current_year' => t('Privatemsg: Current year'),
'privatemsg_years' => t('Privatemsg: Other years'),
);
}
function privatemsg_format_date($timestamp) {
if ($timestamp > (int) (REQUEST_TIME / 3600) * 3600) {
return t('@interval ago', array(
'@interval' => format_interval(abs(REQUEST_TIME - $timestamp), 1),
));
}
if ($timestamp > (int) (REQUEST_TIME / 86400) * 86400) {
return format_date($timestamp, 'privatemsg_current_day');
}
if ($timestamp > mktime(0, 0, 0, 1, 0, date('Y'))) {
return format_date($timestamp, 'privatemsg_current_year');
}
return format_date($timestamp, 'privatemsg_years');
}