Newer
Older
<?php
// $Id$
/**
* @file
* User menu callbacks for Privatemsg.
*/
/**
* List messages.
*
* @param $argument
* An argument to pass through to the query builder.
* @param $uid
* User id messages of another user should be displayed
*/
Sascha Grossenbacher
committed
function privatemsg_list_page($argument = 'list', $uid = NULL) {
global $user;
// Setting default behavior...
$account = $user;
// Because uid is submitted by the menu system, it's a string not a integer.
if ((int)$uid > 0 && $uid != $user->uid) {
// Trying to view someone else's messages...
Sascha Grossenbacher
committed
if (!$account_check = privatemsg_user_load($uid)) {
return MENU_NOT_FOUND;
Sascha Grossenbacher
committed
if (!privatemsg_user_access('read all private messages')) {
return MENU_ACCESS_DENIED;
Sascha Grossenbacher
committed
// Has rights and user_load return an array so user does exist
$account = $account_check;
Sascha Grossenbacher
committed
return drupal_get_form('privatemsg_list', $argument, $account);
}
function privatemsg_list(&$form_state, $argument, $account) {
$query = _privatemsg_assemble_query('list', $account, $argument);
$result = pager_query($query['query'], variable_get('privatemsg_per_page', 25), 0, $query['count']);
$threads = array();
Sascha Grossenbacher
committed
$form = array('#list_argument' => $argument);
$form['#data'] = array();
while ($row = db_fetch_array($result)) {
// Store the raw row data.
$form['#data'][$row['thread_id']] = $row;
// store thread id for the checkboxes array
$threads[$row['thread_id']] = '';
}
if (!empty($form['#data'])) {
$form['actions'] = _privatemsg_action_form();
}
Sascha Grossenbacher
committed
// Save the currently active account, used for actions.
$form['account'] = array('#type' => 'value', '#value' => $account);
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// Define checkboxes, pager and theme
$form['threads'] = array('#type' => 'checkboxes', '#options' => $threads);
$form['pager'] = array('#value' => theme('pager'), '#weight' => 20);
$form['#theme'] = 'privatemsg_list';
// Store the account for which the threads are displayed.
$form['#account'] = $account;
return $form;
}
/**
* Process privatemsg_list form submissions.
*
* Execute the chosen action on the selected messages. This function is
* based on node_admin_nodes_submit().
*/
function privatemsg_list_submit($form, &$form_state) {
// Load all available operation definitions.
$operations = module_invoke_all('privatemsg_thread_operations');
// Default "default" operation, which won't do anything.
$operation = array('callback' => 0);
// Check if a valid operation has been submitted.
if (isset($form_state['values']['operation']) && isset($operations[$form_state['values']['operation']])) {
$operation = $operations[$form_state['values']['operation']];
}
// Load all keys where the value is the current op.
$keys = array_keys($form_state['values'], $form_state['values']['op']);
// The first one is op itself, we need to use the second.
if (isset($keys[1]) && isset($operations[$keys[1]])) {
$operation = $operations[$keys[1]];
}
// Only execute something if we have a valid callback and at least one checked thread.
if (!empty($operation['callback'])) {
Sascha Grossenbacher
committed
privatemsg_operation_execute($operation, $form_state['values']['threads'], $form_state['values']['account']);
}
}
/**
* Menu callback for viewing a thread.
*
* @param $thread
* A array containing all information about a specific thread, generated by
* privatemsg_thread_load().
* @return
* The page content.
* @see privatemsg_thread_load()
*/
function privatemsg_view($thread) {
drupal_set_title(check_plain($thread['subject']));
// Generate paging links.
$older = '';
if (isset($thread['older_start'])) {
$options = array(
'query' => array('start' => $thread['older_start']),
'title' => t('Display older messages'),
);
$older = l(t('<<'), 'messages/view/' . $thread['thread_id'], $options);
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
}
$newer = '';
if (isset($thread['newer_start'])) {
$options = array(
'query' => array('start' => $thread['newer_start']),
'title' => t('Display newer messages'),
);
$newer = l(t('>>'), 'messages/view/' . $thread['thread_id'], $options);
}
$substitutions = array('@from' => $thread['from'], '@to' => $thread['to'], '@total' => $thread['message_count'], '!previous_link' => $older, '!newer_link' => $newer);
$title = t('!previous_link Displaying messages @from - @to of @total !newer_link', $substitutions);
$content['pager_top'] = array(
'#value' => trim($title),
'#prefix' => '<div class="privatemsg-view-pager">',
'#suffix' => '</div>',
'#weight' => -10,
);
// Display a copy at the end.
$content['pager_bottom'] = $content['pager_top'];
$content['pager_bottom']['#weight'] = 3;
// Render the participants.
$content['participants']['#value'] = theme('privatemsg_recipients', $thread);
$content['participants']['#weight'] = -5;
// Render the messages.
$output = '';
foreach ($thread['messages'] as $pmid => $message) {
// Set message as read and theme it.
if (!empty($message['is_new'])) {
privatemsg_message_change_status($pmid, PRIVATEMSG_READ, $thread['user']);
}
$output .= theme('privatemsg_view', $message);
}
$content['messages']['#value'] = $output;
$content['messages']['#weight'] = 0;
// Display the reply form if user is allowed to use it.
Sascha Grossenbacher
committed
if (privatemsg_user_access('write privatemsg') || privatemsg_user_access('reply only privatemsg')) {
$content['reply']['#value'] = drupal_get_form('privatemsg_new', $thread['participants'], $thread['subject'], $thread['thread_id'], $thread['read_all']);
$content['reply']['#weight'] = 5;
}
// Check after calling the privatemsg_new form so that this message is only
// displayed when we are not sending a message.
if ($thread['read_all']) {
// User has permission to read all messages AND is not a participant of the current thread.
Sascha Grossenbacher
committed
drupal_set_message(t('This conversation is being viewed with escalated privileges and may not be the same as shown to normal users.'), 'warning');
}
// Allow other modules to hook into the $content array and alter it.
drupal_alter('privatemsg_view_messages', $content, $thread);
return drupal_render($content);
}
function privatemsg_new(&$form_state, $recipients = array(), $subject = '', $thread_id = NULL, $read_all = FALSE) {
global $user;
$recipients_string = '';
Sascha Grossenbacher
committed
$recipients_plain = '';
$body = '';
// convert recipients to array of user objects
if (!empty($recipients) && is_string($recipients) || is_int($recipients)) {
$recipients = _privatemsg_generate_user_array($recipients);
}
elseif (is_object($recipients)) {
$recipients = array($recipients);
}
elseif (empty($recipients) && is_string($recipients)) {
$recipients = array();
}
$usercount = 0;
$to = array();
Sascha Grossenbacher
committed
$to_plain = array();
$blocked = FALSE;
foreach ($recipients as $recipient) {
Sascha Grossenbacher
committed
if ($recipient->type == 'hidden') {
continue;
}
if (isset($to[privatemsg_recipient_key($recipient)])) {
// We already added the recipient to the list, skip him.
continue;
}
Sascha Grossenbacher
committed
if (!privatemsg_recipient_access($recipient->type, 'write', $recipient)) {
// User does not have access to write to this recipient, continue.
continue;
}
// Check if another module is blocking the sending of messages to the recipient by current user.
Sascha Grossenbacher
committed
$user_blocked = module_invoke_all('privatemsg_block_message', $user, array(privatemsg_recipient_key($recipient) => $recipient));
if (!count($user_blocked) <> 0 && $recipient->recipient) {
if ($recipient->type == 'user' && $recipient->recipient == $user->uid) {
$usercount++;
// Skip putting author in the recipients list for now.
continue;
}
Sascha Grossenbacher
committed
$to[privatemsg_recipient_key($recipient)] = privatemsg_recipient_format($recipient);
Sascha Grossenbacher
committed
$to_plain[privatemsg_recipient_key($recipient)] = privatemsg_recipient_format($recipient, array('plain' => TRUE));
}
else {
// Recipient list contains blocked users.
$blocked = TRUE;
}
}
if (empty($to) && $usercount >= 1 && !$blocked) {
// Assume the user sent message to own account as if the usercount is one or less, then the user sent a message but not to self.
Sascha Grossenbacher
committed
$to['user_' . $user->uid] = privatemsg_recipient_format($user);
Sascha Grossenbacher
committed
$to_plain['user_' . $user->uid] = privatemsg_recipient_format($user, array('plain' => TRUE));
}
if (!empty($to)) {
$recipients_string = implode(', ', $to);
Sascha Grossenbacher
committed
$recipients_plain = implode(', ', $to_plain);
}
if (isset($form_state['values'])) {
if (isset($form_state['values']['recipient'])) {
Sascha Grossenbacher
committed
$recipients_plain = $form_state['values']['recipient'];
}
$subject = $form_state['values']['subject'];
$body = $form_state['values']['body'];
}
Sascha Grossenbacher
committed
if (!$thread_id && !empty($recipients_plain)) {
drupal_set_title(t('Write new message to %recipient', array('%recipient' => $recipients_plain)));
}
elseif (!$thread_id) {
drupal_set_title(t('Write new message'));
}
$form = array();
if (isset($form_state['privatemsg_preview'])) {
$form['message_header'] = array(
'#type' => 'fieldset',
'#title' => empty($form_state['validate_built_message']['thread_id']) ? check_plain($form_state['validate_built_message']['subject']) : t('Preview'),
'#attributes' => array('class' => 'preview'),
);
$form['message_header']['message_preview'] = array(
'#value' => $form_state['privatemsg_preview'],
);
}
$form['privatemsg'] = array(
'#type' => 'fieldset',
Sascha Grossenbacher
committed
'#access' => privatemsg_user_access('write privatemsg') || privatemsg_user_access('reply only privatemsg'),
);
$form['privatemsg']['author'] = array(
'#type' => 'value',
'#value' => $user,
);
if (is_null($thread_id)) {
Sascha Grossenbacher
committed
$description_array = array();
foreach (privatemsg_recipient_get_types() as $name => $type) {
if (privatemsg_recipient_access($name, 'write')) {
$description_array[] = $type['description'];
}
}
$description = t('Enter the recipient, separate recipients with commas.');
$description .= theme('item_list', array('items' => $description_array));
Sascha Grossenbacher
committed
$form['privatemsg']['recipient'] = array(
'#type' => 'textfield',
'#title' => t('To'),
Sascha Grossenbacher
committed
'#description' => $description,
Sascha Grossenbacher
committed
'#default_value' => $recipients_plain,
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
'#required' => TRUE,
'#weight' => -10,
'#size' => 50,
'#autocomplete_path' => 'messages/user-name-autocomplete',
// Do not hardcode #maxlength, make it configurable by number of recipients, not their name length.
);
}
$form['privatemsg']['subject'] = array(
'#type' => 'textfield',
'#title' => t('Subject'),
'#size' => 50,
'#maxlength' => 255,
'#default_value' => $subject,
'#weight' => -5,
);
$form['privatemsg']['body'] = array(
'#type' => 'textarea',
'#title' => t('Message'),
'#rows' => 6,
'#weight' => 0,
'#default_value' => $body,
'#resizable' => TRUE,
);
$format = FILTER_FORMAT_DEFAULT;
// The input filter widget looses the format during preview, specify it
// explicitly.
if (isset($form_state['values']) && array_key_exists('format', $form_state['values'])) {
$format = $form_state['values']['format'];
}
$form['privatemsg']['format'] = filter_form($format);
$form['privatemsg']['preview'] = array(
'#type' => 'submit',
'#value' => t('Preview message'),
'#submit' => array('privatemsg_new_preview'),
'#weight' => 10,
);
$form['privatemsg']['submit'] = array(
'#type' => 'submit',
'#value' => t('Send message'),
'#weight' => 15,
);
$url = 'messages';
$title = t('Cancel');
if (isset($_REQUEST['destination'])) {
$url = $_REQUEST['destination'];
}
elseif (!is_null($thread_id)) {
$url = $_GET['q'];
$title = t('Clear');
}
$form['privatemsg']['cancel'] = array(
'#value' => l($title, $url, array('attributes' => array('id' => 'edit-cancel'))),
'#weight' => 20,
);
if (!is_null($thread_id)) {
$form['privatemsg']['thread_id'] = array(
'#type' => 'value',
'#value' => $thread_id,
);
$form['privatemsg']['subject'] = array(
'#type' => 'value',
'#default_value' => $subject,
);
Sascha Grossenbacher
committed
$recipients_string_themed = implode(', ', $to);
$form['privatemsg']['recipient_display'] = array(
'#value' => '<p>'. t('<strong>Reply to thread</strong>:<br /> Recipients: !to', array('!to' => $recipients_string_themed)) .'</p>',
'#weight' => -10,
);
if (empty($recipients_string)) {
// If there are no valid recipients, unset the message reply form.
$form['privatemsg']['#access'] = FALSE;
}
}
Sascha Grossenbacher
committed
// Only set read all if it is a boolean TRUE. It might also be an integer set
// through the URL.
$form['privatemsg']['read_all'] = array(
'#type' => 'value',
Sascha Grossenbacher
committed
'#value' => $read_all === TRUE,
);
return $form;
}
function privatemsg_new_validate($form, &$form_state) {
// The actual message that is being sent, we create this during validation and pass to submit to send out.
$message = $form_state['values'];
$message['timestamp'] = time();
$trimed_body = trim(truncate_utf8(strip_tags($message['body']), 50, TRUE, TRUE));
if (empty($message['subject']) && !empty($trimed_body)) {
$message['subject'] = $trimed_body;
}
// Only parse the user string for a new thread.
if (!isset($message['thread_id'])) {
list($message['recipients'], $invalid) = _privatemsg_parse_userstring($message['recipient']);
}
else {
Sascha Grossenbacher
committed
// Load participants. Limit recipients to visible unless read_all is TRUE.
$message['recipients'] = _privatemsg_load_thread_participants($message['thread_id'], $message['read_all'] ? FALSE : $message['author']);
Sascha Grossenbacher
committed
$validated = _privatemsg_validate_message($message, TRUE, !isset($message['thread_id']));
foreach ($validated['messages'] as $type => $text) {
drupal_set_message($text, $type);
}
$form_state['validate_built_message'] = $message;
if (!empty($invalid)) {
drupal_set_message(t('The following users will not receive this private message: @invalid', array('@invalid' => implode(", ", $invalid))), 'error');
}
}
/**
* Submit callback for the privatemsg_new form.
*/
function privatemsg_new_submit($form, &$form_state) {
Sascha Grossenbacher
committed
// Clear form_state storage so that it does not rebuild.
$form_state['storage'] = NULL;
$status = _privatemsg_send($form_state['validate_built_message']);
Sascha Grossenbacher
committed
// Format each recipient.
$recipient_names = array();
foreach ($form_state['validate_built_message']['recipients'] as $recipient) {
Sascha Grossenbacher
committed
$recipient_names[] = privatemsg_recipient_format($recipient);
}
if ($status !== FALSE ) {
Sascha Grossenbacher
committed
_privatemsg_handle_recipients($status['mid'], $status['recipients']);
drupal_set_message(t('A message has been sent to !recipients.', array('!recipients' => implode(', ', $recipient_names))));
Sascha Grossenbacher
committed
// Only redirect on new threads.
if ($status['mid'] == $status['thread_id'] || variable_get('privatemsg_default_redirect_reply', FALSE)) {
$redirect = variable_get('privatemsg_default_redirect', '<new-message>');
if ($redirect == '<new-message>') {
// Forward to the new message in the thread.
$form_state['redirect'] = array('messages/view/' . $status['thread_id'], NULL, 'privatemsg-mid-' . $status['mid']);
}
elseif (!empty($redirect)) {
$form_state['redirect'] = $redirect;
}
}
Sascha Grossenbacher
committed
// Replace [new-message] placeholder with actual destination.
if (!empty($_REQUEST['destination']) && $_REQUEST['destination'] == '[new-message]') {
// url() can not be used because it does create an path with base path and
// prefix.
$_REQUEST['destination'] = urlencode(('messages/view/' . $status['thread_id'] . '#' . 'privatemsg-mid-' . $status['mid']));
}
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
}
else {
drupal_set_message(t('An attempt to send a message <em>may have failed</em> when sending to !recipients.', array('!recipients' => implode(', ', $recipient_names))), 'error');
}
}
function privatemsg_new_preview($form, &$form_state) {
drupal_validate_form($form['form_id']['#value'], $form, $form_state);
if (!form_get_errors()) {
$form_state['privatemsg_preview'] = theme('privatemsg_view', $form_state['validate_built_message']);
}
$form_state['rebuild'] = TRUE; // this forces our form to be rebuilt instead of being submitted.
}
function privatemsg_delete($form_state, $thread, $message) {
$form['pmid'] = array(
'#type' => 'value',
'#value' => $message['mid'],
);
$form['delete_destination'] = array(
'#type' => 'value',
'#value' => count($thread['messages']) > 1 ? 'messages/view/' . $message['thread_id'] : 'messages',
);
if (privatemsg_user_access('read all private messages')) {
$form['delete_options'] = array(
'#type' => 'checkbox',
'#title' => t('Delete this message for all users?'),
'#description' => t('Tick the box to delete the message for all users.'),
'#default_value' => FALSE,
);
}
return confirm_form($form,
t('Are you sure you want to delete this message?'),
isset($_GET['destination']) ? $_GET['destination'] : 'messages/view/'. $message['thread_id'],
t('This action cannot be undone.'),
t('Delete'),
t('Cancel')
);
}
function privatemsg_delete_submit($form, &$form_state) {
global $user;
$account = drupal_clone($user);
if ($form_state['values']['confirm']) {
if (isset($form_state['values']['delete_options']) && $form_state['values']['delete_options']) {
privatemsg_message_change_delete($form_state['values']['pmid'], 1);
drupal_set_message(t('Message has been deleted for all users.'));
}
else {
privatemsg_message_change_delete($form_state['values']['pmid'], 1, $account);
drupal_set_message(t('Message has been deleted.'));
}
}
$form_state['redirect'] = $form_state['values']['delete_destination'];
}
/**
* Returns a form which handles and displays thread actions.
*
* Additional actions can be added with the privatemsg_thread_operations hook.
* It is also possible to extend this form with additional buttons or other
* elements, in that case, the definitions in the above hook need no label tag,
* instead, the submit button key needs to match with the key of the operation.
*
* @see hook_privatemsg_thread_operations()
*
* @return
* The FAPI definitions for the thread action form.
*/
function _privatemsg_action_form() {
$form = array(
'#type' => 'fieldset',
'#title' => t('Actions'),
'#prefix' => '<div class="container-inline">',
'#suffix' => '</div>',
'#collapsible' => TRUE,
'#collapsed' => FALSE,
'#weight' => 15,
);
if (privatemsg_user_access('delete privatemsg')) {
$form['delete'] = array(
'#type' => 'submit',
'#value' => t('Delete'),
);
}
// Display all operations which have a label.
$options = array(0 => t('More actions...'));
foreach (module_invoke_all('privatemsg_thread_operations') as $operation => $array) {
if (isset($array['label'])) {
$options[$operation] = $array['label'];
}
}
$form['operation'] = array(
'#type' => 'select',
'#options' => $options,
'#default_value' => 0,
);
$form['submit'] = array(
'#prefix' => '<div class="privatemsg-op-button">',
'#suffix' => '</div>',
'#type' => 'submit',
'#value' => t('Execute'),
'#submit' => array('privatemsg_list_submit'),
'#attributes' => array('class' => 'privatemsg-action-button'),
);
// JS for hiding the execute button.
drupal_add_js(drupal_get_path('module', 'privatemsg') .'/privatemsg-list.js');
return $form;
}
/**
* Returns a table header definition based on the submitted keys.
*
* Uses @link theming theme patterns @endlink to theme single headers.
*
* @param $has_posts
* TRUE when there is at least one row. Decides if the select all checkbox
* should be displayed.
* @param $keys
* Array with the keys which are present in the query/should be displayed.
* @return
* Array with header defintions for tablesort_sql and theme('table').
*/
function _privatemsg_list_headers($has_posts, $keys) {
$select_header = $has_posts ? theme('table_select_header_cell') : '';
$select_header['#weight'] = -50;
// theme() doesn't include the theme file for patterns, we need to do it manually.
include_once drupal_get_path('module', 'privatemsg') .'/privatemsg.theme.inc';
$header = array($select_header);
foreach ($keys as $key) {
// First, try to load a specific theme for that header, if not present, use the default.
if ($return = theme(array('privatemsg_list_header__'. $key, 'privatemsg_list_header'))) {
// The default theme returns nothing, only store the value if we have something.
$header[$key] = $return;
}
}
if (count($header) == 1) {
// No header definition returned, fallback to the default.
$header += _privatemsg_list_headers_fallback($keys);
}
return $header;
}
/**
* Table header definition for themes that don't support theme patterns.
*
* @return
* Array with the correct headers.
*/
function _privatemsg_list_headers_fallback($keys) {
$header = array();
foreach ($keys as $key) {
$theme_function = 'phptemplate_privatemsg_list_header__' . $key;
if (function_exists($theme_function)) {
$header[$key] = $theme_function();
}
}
return $header;
}
/**
* Formats a row in the message list.
*
* Uses @link theming theme patterns @endlink to theme single fields.
*
* @param $thread
* Array with the row data returned by the database.
* @return
* Row definition for use with theme('table')
*/
function _privatemsg_list_thread($thread) {
$row = array('data' => array());
if (!empty($thread['is_new'])) {
// Set the css class in the tr tag.
$row['class'] = 'privatemsg-unread';
}
foreach ($thread as $key => $data) {
// First, try to load a specific theme for that field, if not present, use the default.
if ($return = theme(array('privatemsg_list_field__'. $key, 'privatemsg_list_field'), $thread)) {
// The default theme returns nothing, only store the value if we have something.
$row['data'][$key] = $return;
}
}
if (empty($row['data'])) {
$row['data'] = _privatemsg_list_thread_fallback($thread);
}
return $row;
}
/**
* Table row definition for themes that don't support theme patterns.
*
* @return
* Array with row data.
*/
function _privatemsg_list_thread_fallback($thread) {
$row_data = array();
foreach ($thread as $key => $data) {
$theme_function = 'phptemplate_privatemsg_list_field__' . $key;
if (function_exists($theme_function)) {
$row_data[$key] = $theme_function($thread);
}
}
return $row_data;
}
/**
* Menu callback for messages/undo/action.
*
* This function will test if an undo callback is stored in SESSION and
* execute it.
*/
function privatemsg_undo_action() {
// Check if a undo callback for that user exists.
if (isset($_SESSION['privatemsg']['undo callback']) && is_array($_SESSION['privatemsg']['undo callback'])) {
$undo = $_SESSION['privatemsg']['undo callback'];
// If the defined undo callback exists, execute it
if (isset($undo['function']) && isset($undo['args'])) {
Sascha Grossenbacher
committed
// Load the user object.
if (isset($undo['args']['account']) && $undo['args']['account'] > 0) {
$undo['args']['account'] = user_load((int)$undo['args']['account']);
}
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
call_user_func_array($undo['function'], $undo['args']);
}
// Return back to the site defined by the destination GET param.
drupal_goto();
}
}
/**
* Return autocomplete results for usernames.
*
* Prevents usernames from being used and/or suggested twice.
*/
function privatemsg_user_name_autocomplete($string) {
$names = array();
// 1: Parse $string and build list of valid user names.
$fragments = explode(',', $string);
foreach ($fragments as $index => $name) {
if ($name = trim($name)) {
$names[$name] = $name;
}
}
// 2: Find the next user name suggestion.
$fragment = array_pop($names);
$matches = array();
if (!empty($fragment)) {
Sascha Grossenbacher
committed
$remaining = 10;
$types = privatemsg_recipient_get_types();
foreach ($types as $name => $type) {
if (isset($type['autocomplete']) && is_callable($type['autocomplete']) && privatemsg_recipient_access($name, 'write')) {
$function = $type['autocomplete'];
$return = $function($fragment, $names, $remaining);
if (is_array($return) && !empty($return)) {
$matches = array_merge($matches, $return);
}
Sascha Grossenbacher
committed
$remaining = 10 - count($matches);
if ($remaining <= 0) {
break;
}
}
Sascha Grossenbacher
committed
// Prefix the matches and convert them to the correct form for the
// autocomplete.
$prefix = count($names) ? implode(", ", $names) .", " : '';
$suggestions = array();
foreach ($matches as $match) {
$suggestions[$prefix . $match . ', '] = $match;
}
// convert to object to prevent drupal bug, see http://drupal.org/node/175361
Sascha Grossenbacher
committed
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
drupal_json((object)$suggestions);
}
/**
* Batch processing function for rebuilding the index.
*/
function privatemsg_load_recipients($mid, $recipient, &$context) {
// Get type information.
$type = privatemsg_recipient_get_type($recipient->type);
// First run, initialize sandbox.
if (!isset($context['sandbox']['current_offset'])) {
$context['sandbox']['current_offset'] = 0;
$count_function = $type['count'];
$context['sandbox']['count'] = $count_function($recipient);
}
// Fetch the 10 next recipients.
$load_function = $type['generate recipients'];
$uids = $load_function($recipient, 10, $context['sandbox']['current_offset']);
if (!empty($uids)) {
foreach ($uids as $uid) {
privatemsg_message_change_recipient($mid, $uid, 'hidden');
}
$context['sandbox']['current_offset'] += 10;
// Set finished based on sandbox.
$context['finished'] = empty($context['sandbox']['count']) ? 1 : ($context['sandbox']['current_offset'] / $context['sandbox']['count']);
}
else {
// If no recipients were returned, mark as finished too.
$context['sandbox']['finished'] = 1;
}
// If we are finished, mark the recipient as read.
if ($context['finished'] >= 1) {
db_query("UPDATE {pm_index} SET is_new = %d WHERE mid = %d AND recipient = %d AND type = '%s'", PRIVATEMSG_READ, $mid, $recipient->recipient, $recipient->type);
}