| Commit | Line | Data |
|---|---|---|
| 129e8ef6 OT |
1 | <?php |
| 2 | // $Id$ | |
| 3 | ||
| 4 | /** | |
| 5 | * @file | |
| 6 | * Allows users to send private messages to other users. | |
| 7 | */ | |
| 544d3bb5 | 8 | |
| 4ba95ee6 OT |
9 | /** |
| 10 | * Status constant for read messages. | |
| 11 | */ | |
| 12 | define('PRIVATEMSG_READ', 0); | |
| 13 | /** | |
| 14 | * Status constant for unread messages. | |
| 15 | */ | |
| 16 | define('PRIVATEMSG_UNREAD', 1); | |
| cd266b9d | 17 | |
| 56306fe2 | 18 | /** |
| 129e8ef6 | 19 | * Implementation of hook_perm(). |
| 258788ab | 20 | */ |
| 3be9375b OT |
21 | function privatemsg_perm() { |
| 22 | return array( | |
| 23 | 'read privatemsg', | |
| 24 | 'read all private messages', | |
| 129e8ef6 | 25 | 'administer privatemsg settings', |
| 3be9375b | 26 | 'write privatemsg' |
| c1ab6ef9 | 27 | ); |
| c1ab6ef9 KN |
28 | } |
| 29 | ||
| 5605b147 OT |
30 | /** |
| 31 | * Generate aray of user objects based on a string. | |
| 32 | * | |
| 33 | * | |
| 34 | * @param $userstring | |
| 35 | * A string with user id, for example 1,2,4. Returned by the list query | |
| 36 | * | |
| 37 | * @return | |
| 38 | * Array with user objects. | |
| 39 | */ | |
| 68847a38 | 40 | function _privatemsg_generate_user_array($userstring, $slice = NULL) { |
| fbbe3e72 OT |
41 | static $user_cache = array(); |
| 42 | ||
| 68847a38 OT |
43 | // Convert user uid list (uid1,uid2,uid3) into an array. If $slice is not NULL |
| 44 | // pass that as argument to array_slice(). For example, -4 will only load the | |
| 45 | // last four users. | |
| 46 | $users = explode(',', $userstring); | |
| 47 | if (!is_null($slice)) { | |
| 48 | $users = array_slice($users, $slice); | |
| 49 | } | |
| fbbe3e72 | 50 | $participants = array(); |
| 68847a38 OT |
51 | foreach ($users as $uid) { |
| 52 | if (!array_key_exists($uid, $user_cache)) { | |
| 53 | $user_cache[$uid] = user_load($uid); | |
| fbbe3e72 | 54 | } |
| 68847a38 OT |
55 | if (is_object($user_cache[$uid])) { |
| 56 | $participants[$uid] = $user_cache[$uid]; | |
| fbbe3e72 OT |
57 | } |
| 58 | } | |
| 59 | return $participants; | |
| 60 | } | |
| 61 | ||
| 5605b147 OT |
62 | /** |
| 63 | * Format an array of user objects. | |
| 64 | * | |
| 65 | * @param $part_array | |
| 66 | * Array with user objects, for example the one returnd by | |
| 67 | * _privatemsg_generate_user_array. | |
| 68 | * | |
| 69 | * @param $limit | |
| 70 | * Limit the number of user objects which should be displayed. | |
| 71 | * @param $no_text | |
| 72 | * When TRUE, don't display the Participants/From text. | |
| 73 | * @return | |
| 74 | * String with formated user objects, like user1, user2. | |
| 75 | */ | |
| 4b3cbfb4 OT |
76 | function _privatemsg_format_participants($part_array, $limit = 20, $no_text = FALSE) { |
| 77 | if (count($part_array) > 0) { | |
| fbbe3e72 | 78 | $to = array(); |
| 4b3cbfb4 OT |
79 | $limited = FALSE; |
| 80 | foreach ($part_array as $account) { | |
| fbbe3e72 | 81 | if (count($to) >= $limit) { |
| 4b3cbfb4 | 82 | $limited = TRUE; |
| fbbe3e72 OT |
83 | break; |
| 84 | } | |
| 4b3cbfb4 | 85 | $to[] = theme('username', $account); |
| fbbe3e72 OT |
86 | } |
| 87 | ||
| 88 | $limit_string = ''; | |
| 89 | if ($limited) { | |
| 90 | $limit_string = t(' and others'); | |
| 91 | } | |
| 92 | ||
| 93 | ||
| 4b3cbfb4 | 94 | if ($no_text) { |
| fbbe3e72 OT |
95 | return implode(', ', $to) . $limit_string; |
| 96 | } | |
| 97 | ||
| 98 | $last = array_pop($to); | |
| 99 | if (count($to) == 0) { // Only one participant | |
| 100 | return t("From !last", array('!last' => $last)); | |
| 101 | } | |
| 102 | else { // Multipe participants.. | |
| 103 | $participants = implode(', ', $to); | |
| 4b3cbfb4 | 104 | return t('Participants: !participants and !last', array('!participants' => $participants, '!last' => $last)); |
| fbbe3e72 OT |
105 | } |
| 106 | } | |
| 107 | return ''; | |
| 108 | } | |
| 109 | ||
| c1ab6ef9 | 110 | /** |
| 129e8ef6 | 111 | * Implementation of hook_menu(). |
| c73fcb85 | 112 | */ |
| 3be9375b | 113 | function privatemsg_menu() { |
| 129e8ef6 OT |
114 | $items['messages'] = array( |
| 115 | 'title' => 'Messages', | |
| 116 | 'title callback' => 'privatemsg_title_callback', | |
| 4ba95ee6 | 117 | 'page callback' => 'drupal_get_form', |
| c277e471 | 118 | 'page arguments' => array('privatemsg_list', 'list'), |
| bc4689a7 | 119 | 'access callback' => 'privatemsg_user_access', |
| 129e8ef6 | 120 | 'type' => MENU_NORMAL_ITEM, |
| 3be9375b | 121 | ); |
| c277e471 OT |
122 | $items['messages/list'] = array( |
| 123 | 'title' => 'Messages', | |
| 4ba95ee6 | 124 | 'page callback' => 'drupal_get_form', |
| c277e471 | 125 | 'page arguments' => array('privatemsg_list', 'list'), |
| bc4689a7 | 126 | 'access callback' => 'privatemsg_user_access', |
| 129e8ef6 OT |
127 | 'type' => MENU_DEFAULT_LOCAL_TASK, |
| 128 | 'weight' => -10, | |
| 3be9375b | 129 | ); |
| fb405f31 OT |
130 | $items['messages/view/%privatemsg_thread'] = array( |
| 131 | 'title' => 'Read message', | |
| 129e8ef6 OT |
132 | 'page callback' => 'privatemsg_view', |
| 133 | 'page arguments' => array(2), | |
| bc4689a7 | 134 | 'access callback' => 'privatemsg_view_access', |
| fb405f31 | 135 | 'type' => MENU_LOCAL_TASK, |
| 129e8ef6 | 136 | 'weight' => -10, |
| 3be9375b | 137 | ); |
| 129e8ef6 OT |
138 | $items['messages/delete/%'] = array( |
| 139 | 'title' => 'Delete message', | |
| 140 | 'page callback' => 'drupal_get_form', | |
| 141 | 'page arguments' => array('privatemsg_delete', 2), | |
| bc4689a7 | 142 | 'access callback' => 'privatemsg_user_access', |
| 129e8ef6 OT |
143 | 'type' => MENU_CALLBACK, |
| 144 | 'weight' => -10, | |
| 145 | ); | |
| 146 | $items['messages/new'] = array( | |
| 147 | 'title' => 'Write new message', | |
| 148 | 'page callback' => 'drupal_get_form', | |
| 68847a38 | 149 | 'page arguments' => array('privatemsg_new', 2, 3, NULL), |
| bc4689a7 | 150 | 'access callback' => 'privatemsg_user_access', |
| 129e8ef6 OT |
151 | 'access arguments' => array('write privatemsg'), |
| 152 | 'type' => MENU_LOCAL_TASK, | |
| 153 | 'weight' => -7, | |
| 154 | ); | |
| 129e8ef6 OT |
155 | // Auto-completes available user names & removes duplicates. |
| 156 | $items['messages/user-name-autocomplete'] = array( | |
| 157 | 'page callback' => 'privatemsg_user_name_autocomplete', | |
| bc4689a7 | 158 | 'access callback' => 'privatemsg_user_access', |
| 3be9375b | 159 | 'access arguments' => array('write privatemsg'), |
| 129e8ef6 OT |
160 | 'type' => MENU_CALLBACK, |
| 161 | 'weight' => -10, | |
| 162 | ); | |
| 163 | $items['admin/settings/messages'] = array( | |
| 164 | 'title' => 'Private messages', | |
| 165 | 'description' => 'Configure private messaging settings.', | |
| 166 | 'page callback' => 'drupal_get_form', | |
| 167 | 'page arguments' => array('private_message_settings'), | |
| 168 | 'access arguments' => array('administer privatemsg settings'), | |
| 169 | 'type' => MENU_NORMAL_ITEM, | |
| c1ab6ef9 | 170 | ); |
| e5fe4a8d OT |
171 | $items['admin/settings/messages/default'] = array( |
| 172 | 'title' => 'Private messages', | |
| 173 | 'description' => 'Configure private messaging settings.', | |
| 174 | 'page callback' => 'drupal_get_form', | |
| 175 | 'page arguments' => array('private_message_settings'), | |
| 176 | 'access arguments' => array('administer privatemsg settings'), | |
| 177 | 'type' => MENU_DEFAULT_LOCAL_TASK, | |
| 178 | 'weight' => -10, | |
| 179 | ); | |
| 4ba95ee6 OT |
180 | $items['messages/undo/action'] = array( |
| 181 | 'title' => 'Private messages', | |
| 182 | 'description' => 'Undo last thread action', | |
| 183 | 'page callback' => 'privatemsg_undo_action', | |
| 184 | 'access arguments' => array('read privatemsg'), | |
| 185 | 'type' => MENU_CALLBACK, | |
| 186 | ); | |
| 3be9375b | 187 | return $items; |
| c1ab6ef9 | 188 | } |
| bc4689a7 OT |
189 | |
| 190 | /** | |
| 5605b147 OT |
191 | * Privatemsg wrapper for user_access. |
| 192 | * | |
| 193 | * Never allows anonymous user access as that doesn't makes sense. | |
| bc4689a7 | 194 | * |
| 5605b147 OT |
195 | * @param $permission |
| 196 | * Permission string, defaults to read privatemsg | |
| bc4689a7 | 197 | * |
| 5605b147 OT |
198 | * @return |
| 199 | * TRUE if user has access, FALSE if not | |
| bc4689a7 | 200 | * |
| 5605b147 | 201 | * @ingroup api |
| bc4689a7 OT |
202 | */ |
| 203 | function privatemsg_user_access($permission = 'read privatemsg', $account = NULL) { | |
| 204 | if ( $account === NULL ) { | |
| 205 | global $user; | |
| 206 | $account = $user; | |
| 207 | } | |
| 208 | if (!$account->uid) { // Disallow anonymous access, regardless of permissions | |
| 209 | return FALSE; | |
| 210 | } | |
| 211 | if (!user_access($permission, $account)) { | |
| 212 | return FALSE; | |
| 213 | } | |
| 214 | return TRUE; | |
| 215 | } | |
| 216 | ||
| 217 | ||
| 218 | /** | |
| 5605b147 OT |
219 | * Check access to the view messages page. |
| 220 | * | |
| 221 | * Function to restrict the access of the view messages page to just the | |
| 222 | * messages/view/% pages and not to leave tabs artifact on other lower | |
| 223 | * level pages such as the messages/new/%. | |
| 224 | * | |
| 225 | * @ingroup api | |
| bc4689a7 OT |
226 | */ |
| 227 | function privatemsg_view_access() { | |
| 228 | if (privatemsg_user_access('read privatemsg') && arg(1) == 'view') { | |
| 229 | return TRUE; | |
| 230 | } | |
| 231 | return FALSE; | |
| 232 | } | |
| 233 | ||
| fb405f31 | 234 | /** |
| 5605b147 OT |
235 | * Load a thread with all the messages and participants. |
| 236 | * | |
| 237 | * This function is called by the menu system through the %privatemsg_thread | |
| 238 | * wildcard. | |
| fb405f31 | 239 | * |
| 5605b147 OT |
240 | * @param $thread_id |
| 241 | * Thread id, pmi.thread_id or pm.mid of the first message in that thread. | |
| 053a2f78 OT |
242 | * @param $account |
| 243 | * User object for which the thread should be loaded, defaults to | |
| 244 | * the current user. | |
| 5605b147 | 245 | * |
| 053a2f78 OT |
246 | * @return |
| 247 | * $thread object, with keys messages, participants, title and user. messages | |
| 248 | * contains an array of messages, participants an array of user, subject the | |
| 249 | * subject of the thread and user the user viewing the thread. | |
| 250 | * | |
| 251 | * If no messages are found, or the thread_id is invalid, the function returns | |
| 252 | * FALSE. | |
| 253 | ||
| 5605b147 | 254 | * @ingroup api |
| fb405f31 | 255 | */ |
| 053a2f78 | 256 | function privatemsg_thread_load($thread_id, $account = NULL) { |
| fb405f31 | 257 | if ((int)$thread_id > 0) { |
| 68847a38 | 258 | $thread = array('thread_id' => $thread_id); |
| 053a2f78 OT |
259 | |
| 260 | if (is_null($account)) { | |
| 261 | global $user; | |
| 262 | $account = drupal_clone($user); | |
| 263 | } | |
| 264 | // load messages returned by the messages query with _privatemsg_load(). | |
| 265 | $query = _privatemsg_assemble_query('messages', array($thread_id), $account); | |
| 266 | $conversation = db_query($query['query']); | |
| 267 | while ($result = db_fetch_array($conversation)) { | |
| 268 | if ($message = _privatemsg_load($result['mid'], $account)) { | |
| 269 | $thread['messages'][$result['mid']] = $message; | |
| 270 | } | |
| 271 | } | |
| 272 | // if there are no messages, don't allow access to the thread. | |
| 273 | if (empty($thread['messages'])) { | |
| 274 | return FALSE; | |
| 275 | } | |
| 276 | ||
| 277 | // general data, assume subject is the same for all messages of that thread. | |
| 278 | $thread['user'] = $account; | |
| 279 | $message = current($thread['messages']); | |
| 280 | $thread['subject'] = $message['subject']; | |
| 281 | ||
| 282 | // Load the list of participants. | |
| 283 | $query = _privatemsg_assemble_query('participants', $thread_id); | |
| 284 | $participants = db_query($query['query']); | |
| 285 | while ($result = db_fetch_array($participants)) { | |
| 286 | $thread['participants'][$result['uid']] = user_load($result['uid']); | |
| 287 | } | |
| 288 | return $thread; | |
| fb405f31 OT |
289 | } |
| 290 | return FALSE; | |
| 291 | } | |
| 129e8ef6 | 292 | |
| 3be9375b OT |
293 | function private_message_view_options() { |
| 294 | $options = module_invoke_all('privatemsg_view_template'); | |
| 295 | return $options; | |
| fe5f5474 | 296 | } |
| 129e8ef6 | 297 | |
| c1ab6ef9 | 298 | /** |
| 129e8ef6 OT |
299 | * Implementation of hook_privatemsg_view_template(). |
| 300 | * | |
| 301 | * Allows modules to define different message view template. | |
| 302 | * | |
| 303 | * This hook returns information about available themes for privatemsg viewing. | |
| 3be9375b | 304 | * |
| 3be9375b OT |
305 | * array( |
| 306 | * 'machine_template_name' => 'Human readable template name', | |
| 307 | * 'machine_template_name_2' => 'Human readable template name 2' | |
| 308 | * }; | |
| 309 | */ | |
| 310 | function privatemsg_privatemsg_view_template() { | |
| 311 | return array( | |
| 129e8ef6 | 312 | 'privatemsg-view' => 'Default view', |
| c1ab6ef9 | 313 | ); |
| 3be9375b | 314 | } |
| 129e8ef6 | 315 | |
| 3be9375b OT |
316 | function private_message_settings() { |
| 317 | $form = array(); | |
| 129e8ef6 | 318 | |
| 3be9375b | 319 | $form['theming_settings'] = array( |
| 129e8ef6 OT |
320 | '#type' => 'fieldset', |
| 321 | '#collapsible' => TRUE, | |
| 322 | '#collapsed' => TRUE, | |
| 323 | '#title' => t('Theming settings'), | |
| 3be9375b OT |
324 | ); |
| 325 | $form['theming_settings']['private_message_view_template'] = array( | |
| 129e8ef6 OT |
326 | '#type' => 'radios', |
| 327 | '#title' => t('Private message display template'), | |
| 3be9375b | 328 | '#default_value' => variable_get('private_message_view_template', 'privatemsg-view'), |
| 129e8ef6 OT |
329 | '#options' => private_message_view_options(), |
| 330 | ); | |
| 331 | $form['privatemsg_per_page'] = array( | |
| 332 | '#type' => 'select', | |
| 333 | '#title' => t('Messages per page'), | |
| 334 | '#default_value' => variable_get('privatemsg_per_page', 25), | |
| 335 | '#options' => drupal_map_assoc(array(10, 25, 50, 75, 100)), | |
| 336 | '#description' => t('Choose the number of conversations that should be listed per page.'), | |
| 3be9375b | 337 | ); |
| 20b4f5d2 OT |
338 | $form['privatemsg_display_loginmessage'] = array( |
| 339 | '#type' => 'checkbox', | |
| 340 | '#title' => t('Inform the user about new messages on login'), | |
| 341 | '#default_value' => variable_get('privatemsg_display_loginmessage', TRUE), | |
| 342 | '#description' => t('This option can safely be disabled if the "New message indication" block is used instead.'), | |
| 343 | ); | |
| 4ba95ee6 OT |
344 | $form['privatemsg_listing'] = array( |
| 345 | '#type' => 'fieldset', | |
| 346 | '#title' => t('Configure listings'), | |
| 347 | '#collapsible' => TRUE, | |
| 348 | '#collapsed' => TRUE, | |
| 349 | ); | |
| 350 | ||
| 351 | $form['privatemsg_listing']['privatemsg_display_fields'] = array( | |
| 352 | '#type' => 'checkboxes', | |
| 353 | '#title' => t('Configure fields'), | |
| 354 | '#description' => t('Select which columns/fields should be displayed in the message listings. Subject and Last updated cannot be disabled.'), | |
| 355 | '#options' => array( | |
| c277e471 | 356 | 'participants' => t('Participants'), |
| 4ba95ee6 OT |
357 | 'thread_started' => t('Started'), |
| 358 | 'count' => t('Answers'), | |
| 359 | ), | |
| c277e471 | 360 | '#default_value' => variable_get('privatemsg_display_fields', array('participants')), |
| 4ba95ee6 OT |
361 | ); |
| 362 | ||
| 3be9375b OT |
363 | $form['#submit'][] = 'private_message_settings_submit'; |
| 364 | return system_settings_form($form); | |
| 365 | } | |
| 129e8ef6 | 366 | |
| 3be9375b OT |
367 | function private_message_settings_submit() { |
| 368 | drupal_rebuild_theme_registry(); | |
| 369 | } | |
| c1ab6ef9 | 370 | |
| 3be9375b OT |
371 | function privatemsg_theme() { |
| 372 | return array( | |
| 373 | 'privatemsg_view' => array( | |
| 129e8ef6 | 374 | 'arguments' => array('message' => NULL), |
| 5605b147 | 375 | 'template' => variable_get('private_message_view_template', 'privatemsg-view'), // 'privatemsg', |
| 3be9375b OT |
376 | ), |
| 377 | 'privatemsg_from' => array( | |
| 129e8ef6 OT |
378 | 'arguments' => array('author' => NULL), |
| 379 | 'template' => 'privatemsg-from', | |
| 3be9375b | 380 | ), |
| 129e8ef6 OT |
381 | 'privatemsg_to' => array( |
| 382 | 'arguments' => array('message' => NULL), | |
| 383 | 'template' => 'privatemsg-recipients', | |
| 3be9375b | 384 | ), |
| 129e8ef6 OT |
385 | 'privatemsg_between' => array( |
| 386 | 'arguments' => array('recipients' => NULL), | |
| 387 | 'template' => 'privatemsg-between', | |
| 388 | ), | |
| 4ba95ee6 OT |
389 | 'privatemsg_list' => array( |
| 390 | 'file' => 'privatemsg.theme.inc', | |
| 391 | 'path' => drupal_get_path('module', 'privatemsg'), | |
| 392 | 'arguments' => array('form'), | |
| 393 | ), | |
| 394 | // Define pattern for header/field templates. The theme system will register all | |
| 395 | // theme functions that start with the defined pattern. | |
| 396 | 'privatemsg_list_header' => array( | |
| 397 | 'file' => 'privatemsg.theme.inc', | |
| 398 | 'path' => drupal_get_path('module', 'privatemsg'), | |
| 399 | 'pattern' => 'privatemsg_list_header__', | |
| 400 | 'arguments' => array(), | |
| 401 | ), | |
| 402 | 'privatemsg_list_field' => array( | |
| 403 | 'file' => 'privatemsg.theme.inc', | |
| 404 | 'path' => drupal_get_path('module', 'privatemsg'), | |
| 405 | 'pattern' => 'privatemsg_list_field__', | |
| 406 | 'arguments' => array('thread'), | |
| 3be9375b | 407 | ), |
| 20b4f5d2 | 408 | 'privatemsg_new_block' => array( |
| 4ba95ee6 OT |
409 | 'file' => 'privatemsg.theme.inc', |
| 410 | 'path' => drupal_get_path('module', 'privatemsg'), | |
| 20b4f5d2 OT |
411 | 'arguments' => array('count'), |
| 412 | ), | |
| c1ab6ef9 | 413 | ); |
| c1ab6ef9 | 414 | } |
| 129e8ef6 | 415 | |
| 3be9375b | 416 | function privatemsg_preprocess_privatemsg_view(&$vars) { |
| 129e8ef6 OT |
417 | // drupal_set_message('<pre>'. print_r($vars,1 ) . '</pre>'); |
| 418 | ||
| 3be9375b | 419 | $message = $vars['message']; |
| 129e8ef6 | 420 | $vars['mid'] = isset($message['mid']) ? $message['mid']:null; |
| 3be9375b OT |
421 | $vars['author_picture'] = theme('user_picture', $message['author']); |
| 422 | $vars['author_name_link'] = theme('username', $message['author']); | |
| 129e8ef6 OT |
423 | /** |
| 424 | * @todo perhaps make this timestamp configurable via admin UI? | |
| 425 | */ | |
| 426 | $vars['message_timestamp'] = format_date($message['timestamp'], 'small'); | |
| 3be9375b | 427 | $vars['message_body'] = check_markup($message['body']); |
| 93a1235e | 428 | if (isset($vars['mid'])) { |
| 328f2c62 | 429 | $vars['message_actions'][] = array('title' => t('Delete message'), 'href' => 'messages/delete/'. $vars['mid']); |
| 129e8ef6 | 430 | } |
| 93a1235e OT |
431 | |
| 432 | // call hook_privatemsg_message_view_alter | |
| 433 | drupal_alter('privatemsg_message_view', $vars); | |
| 328f2c62 | 434 | |
| efb7face | 435 | $vars['message_actions'] = !empty($vars['message_actions']) ? theme('links', $vars['message_actions'], array('class' => 'message-actions')) : ''; |
| e50464be | 436 | } |
| 129e8ef6 | 437 | |
| 3be9375b | 438 | function privatemsg_preprocess_privatemsg_to(&$vars) { |
| 5605b147 | 439 | $vars['participants'] = ''; // assign a default empty value |
| fbbe3e72 OT |
440 | if (isset($vars['message']['participants'])) { |
| 441 | $vars['participants'] = _privatemsg_format_participants($vars['message']['participants']); | |
| e50464be MM |
442 | } |
| 443 | } | |
| fb8f4982 OT |
444 | |
| 445 | /** | |
| 129e8ef6 | 446 | * List messages. |
| fb8f4982 | 447 | * |
| c277e471 OT |
448 | * @param $form_state |
| 449 | * Form state array | |
| 450 | * @param $argument | |
| 451 | * An argument to pass through to the query builder. | |
| 5605b147 | 452 | * @param $uid |
| c277e471 OT |
453 | * User id messages of another user should be displayed |
| 454 | * | |
| 347e66c9 | 455 | * @return |
| c277e471 | 456 | * Form array |
| fb8f4982 | 457 | */ |
| c277e471 | 458 | function privatemsg_list(&$form_state, $argument = 'list', $uid = NULL) { |
| fb8f4982 | 459 | global $user; |
| 129e8ef6 OT |
460 | |
| 461 | // Setting default behavior... | |
| fb8f4982 | 462 | $account = $user; |
| 4ba95ee6 OT |
463 | // Because uid is submitted by the menu system, it's a string not a integer. |
| 464 | if ((int)$uid > 0 && $uid != $user->uid) { | |
| 129e8ef6 | 465 | // Trying to view someone else's messages... |
| bc4689a7 | 466 | if (!privatemsg_user_access('read all private messages')) { |
| 129e8ef6 | 467 | drupal_set_message(t("You do not have sufficient rights to view someone else's messages"), 'warning'); |
| fb8f4982 | 468 | } |
| 129e8ef6 OT |
469 | elseif ($account_check = user_load(array('uid' => $uid))) { |
| 470 | // Has rights and user_load return an array so user does exist | |
| 471 | $account = $account_check; | |
| fb8f4982 | 472 | } |
| 129e8ef6 OT |
473 | } |
| 474 | // By this point we have figured out for which user we are listing messages and now it is safe to use $account->uid in the listing query. | |
| c277e471 OT |
475 | |
| 476 | $query = _privatemsg_assemble_query('list', $account, $argument); | |
| 129e8ef6 | 477 | $result = pager_query($query['query'], variable_get('privatemsg_per_page', 25), 0, $query['count']); |
| fb8f4982 | 478 | |
| 4ba95ee6 OT |
479 | $threads = array(); |
| 480 | $form['#data'] = array(); | |
| 481 | while ($row = db_fetch_array($result)) { | |
| 482 | // Store the raw row data. | |
| 483 | $form['#data'][$row['thread_id']] = $row; | |
| 484 | // Store the themed row data. | |
| 485 | $form['#rows'][$row['thread_id']] = _privatemsg_list_thread($row); | |
| 486 | // store thread id for the checkboxes array | |
| 487 | $threads[$row['thread_id']] = ''; | |
| 129e8ef6 | 488 | } |
| 4ba95ee6 OT |
489 | if (empty($form['#data'])) { |
| 490 | // If no threads are displayed, use these default columns. | |
| 491 | $keys = array('subject', 'author', 'last_updated'); | |
| 129e8ef6 OT |
492 | } |
| 493 | else { | |
| 4ba95ee6 OT |
494 | // Load the keys of the first row in data, we don't know the key |
| 495 | $keys = array_keys($form['#data'][key($form['#data'])]); | |
| 496 | $form['actions'] = _privatemsg_action_form(); | |
| fb8f4982 | 497 | } |
| 4ba95ee6 OT |
498 | // Load the themed list headers based on the available data |
| 499 | $form['#headers'] = _privatemsg_list_headers(!empty($form['#data']), $keys); | |
| fb8f4982 | 500 | |
| 4ba95ee6 OT |
501 | // Define checkboxes, pager and theme |
| 502 | $form['threads'] = array('#type' => 'checkboxes', '#options' => $threads); | |
| 503 | $form['pager'] = array('#value' => theme('pager'), '#weight' => 20); | |
| 504 | $form['#theme'] = 'privatemsg_list'; | |
| 20b4f5d2 | 505 | |
| 4ba95ee6 OT |
506 | // Store the account for which the threads are displayed. |
| 507 | $form['#account'] = $account; | |
| 508 | return $form; | |
| 20b4f5d2 OT |
509 | } |
| 510 | ||
| 3be9375b | 511 | /** |
| 4ba95ee6 | 512 | * Changes the read/new status of a single message. |
| 3be9375b | 513 | * |
| 5605b147 OT |
514 | * @param $pmid |
| 515 | * Message id | |
| 516 | * @param $status | |
| 517 | * Either PRIVATEMSG_READ or PRIVATEMSG_UNREAD | |
| 518 | * @param $account | |
| 519 | * User object, defaults to the current user | |
| 3be9375b | 520 | */ |
| 4ba95ee6 OT |
521 | function privatemsg_message_change_status($pmid, $status, $account = NULL) { |
| 522 | if (!$account) { | |
| 523 | global $user; | |
| 524 | $account = $user; | |
| 129e8ef6 | 525 | } |
| 4ba95ee6 OT |
526 | $query = "UPDATE {pm_index} SET is_new = %d WHERE mid = %d AND uid = %d"; |
| 527 | db_query($query, $status, $pmid, $account->uid); | |
| 129e8ef6 OT |
528 | } |
| 529 | ||
| 530 | /** | |
| 129e8ef6 | 531 | * Return number of unread messages for an account. |
| 5605b147 OT |
532 | * |
| 533 | * @param $account | |
| 534 | * Specifiy the user for which the unread count should be loaded. | |
| 535 | * | |
| 536 | * @ingroup api | |
| 129e8ef6 OT |
537 | */ |
| 538 | function privatemsg_unread_count($account = NULL) { | |
| 539 | static $counts = array(); | |
| 129e8ef6 OT |
540 | if (!$account || $account->uid == 0) { |
| 541 | global $user; | |
| 3be9375b | 542 | $account = $user; |
| 129e8ef6 OT |
543 | } |
| 544 | if ( !isset($counts[$account->uid])) { | |
| f2161b8c | 545 | $query = _privatemsg_assemble_query('unread_count', $account); |
| 129e8ef6 OT |
546 | $counts[$account->uid] = db_result(db_query($query['query'])); |
| 547 | } | |
| 548 | return $counts[$account->uid]; | |
| 549 | } | |
| 550 | ||
| 053a2f78 OT |
551 | /** |
| 552 | * Menu callback for viewing a thread. | |
| 553 | * | |
| 554 | * @param $thread | |
| 555 | * A array containing all information about a specific thread, generated by | |
| 556 | * privatemsg_thread_load(). | |
| 557 | * @return | |
| 558 | * The page content. | |
| 559 | * @see privatemsg_thread_load(). | |
| 560 | */ | |
| 561 | function privatemsg_view($thread) { | |
| 562 | drupal_set_title(check_plain($thread['subject'])); | |
| 35a8a46e | 563 | |
| 053a2f78 OT |
564 | // Render the participants. |
| 565 | $content['participants']['#value'] = theme('privatemsg_to', $thread); | |
| 129e8ef6 OT |
566 | $content['participants']['#weight'] = -5; |
| 567 | ||
| 053a2f78 OT |
568 | // Render the messages. |
| 569 | $output = ''; | |
| 570 | foreach ($thread['messages'] as $pmid => $message) { | |
| 571 | // Set message as read and theme it. | |
| 82b71e87 OT |
572 | if (!empty($message['is_new'])) { |
| 573 | privatemsg_message_change_status($pmid, PRIVATEMSG_READ, $thread['user']); | |
| 574 | } | |
| 129e8ef6 | 575 | $output .= theme('privatemsg_view', $message); |
| 129e8ef6 | 576 | } |
| 053a2f78 | 577 | $content['messages']['#value'] = $output; |
| 129e8ef6 OT |
578 | $content['messages']['#weight'] = 0; |
| 579 | ||
| 053a2f78 OT |
580 | // Display the reply form if user is allowed to use it. |
| 581 | if (privatemsg_user_access('write privatemsg')) { | |
| 68847a38 | 582 | $content['reply']['#value'] = drupal_get_form('privatemsg_new', $thread['participants'], $thread['subject'], $thread['thread_id']); |
| 129e8ef6 OT |
583 | $content['reply']['#weight'] = 5; |
| 584 | } | |
| 585 | ||
| 053a2f78 OT |
586 | //allow other modules to hook into the $content array and alter it |
| 587 | drupal_alter('privatemsg_view_messages', $content, $thread); | |
| 588 | return drupal_render($content); | |
| e50464be MM |
589 | } |
| 590 | ||
| 129e8ef6 | 591 | |
| 68847a38 | 592 | function privatemsg_new(&$form_state, $recipients = array(), $subject = '', $thread_id = NULL) { |
| e50464be | 593 | global $user; |
| 129e8ef6 | 594 | |
| 68847a38 | 595 | $recipients_string = ''; |
| 3be9375b | 596 | $body = ''; |
| 129e8ef6 | 597 | |
| 68847a38 OT |
598 | // convert recipients to array of user objects |
| 599 | if (!empty($recipients) && is_string($recipients) || is_int($recipients)) { | |
| 600 | $recipients = _privatemsg_generate_user_array($recipients); | |
| 601 | } | |
| 602 | elseif (is_object($recipients)) { | |
| 603 | $recipients = array($recipients); | |
| 604 | } | |
| 605 | elseif (empty($recipients) && is_string($recipients)) { | |
| 606 | $recipients = array(); | |
| 607 | } | |
| 608 | ||
| 609 | $usercount = 0; | |
| 610 | $to = array(); | |
| 611 | foreach ($recipients as $recipient) { | |
| 612 | if (in_array($recipient->name, $to)) { | |
| 613 | // We already added the recipient to the list, skip him. | |
| 614 | continue; | |
| 615 | } | |
| 616 | // Check if another module is blocking the sending of messages to the recipient by current user. | |
| 617 | $user_blocked = module_invoke_all('privatemsg_block_message', $user, array($recipient)); | |
| 618 | if (!count($user_blocked) <> 0 && $recipient->uid) { | |
| 619 | if ($recipient->uid == $user->uid) { | |
| 620 | $usercount++; | |
| 621 | // Skip putting author in the recipients list for now. | |
| 622 | continue; | |
| 623 | } | |
| 624 | $to[] = $recipient->name; | |
| 625 | } | |
| 626 | } | |
| 627 | ||
| 628 | if (empty($to) && $usercount >= 1) { | |
| 629 | // 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. | |
| 630 | $to[] = $user->name; | |
| 631 | } | |
| 632 | ||
| 633 | ||
| 634 | if (!empty($to)) { | |
| 635 | $recipients_string = implode(', ', $to); | |
| 129e8ef6 | 636 | } |
| 3be9375b | 637 | if (isset($form_state['values'])) { |
| 68847a38 | 638 | $recipients_string = $form_state['values']['recipient']; |
| 129e8ef6 OT |
639 | $subject = $form_state['values']['subject']; |
| 640 | $body = $form_state['values']['body']; | |
| 496acb83 | 641 | } |
| 68847a38 OT |
642 | if (!$thread_id && !empty($recipients_string)) { |
| 643 | drupal_set_title(t('Write new message to %recipient', array('%recipient' => $recipients_string))); | |
| 644 | } elseif (!$thread_id) { | |
| 645 | drupal_set_title(t('Write new message')); | |
| 646 | } | |
| e50464be | 647 | |
| 3be9375b OT |
648 | $form = array(); |
| 649 | if (isset($form_state['privatemsg_preview'])) { | |
| 650 | $form['message_header'] = array( | |
| 651 | '#type' => 'fieldset', | |
| 129e8ef6 | 652 | '#attributes' => array('class' => 'preview'), |
| 3be9375b OT |
653 | ); |
| 654 | $form['message_header']['message_preview'] = array( | |
| 655 | '#value' => $form_state['privatemsg_preview'], | |
| 656 | ); | |
| 29001b19 | 657 | } |
| 129e8ef6 OT |
658 | $form['privatemsg'] = array( |
| 659 | '#type' => 'fieldset', | |
| bc4689a7 | 660 | '#access' => privatemsg_user_access('write privatemsg'), |
| 129e8ef6 OT |
661 | ); |
| 662 | $form['privatemsg']['author'] = array( | |
| 663 | '#type' => 'value', | |
| 664 | '#value' => $user, | |
| 3be9375b | 665 | ); |
| 129e8ef6 | 666 | $form['privatemsg']['recipient'] = array( |
| 3be9375b OT |
667 | '#type' => 'textfield', |
| 668 | '#title' => t('To'), | |
| 669 | '#description' => t('Separate multiple names with commas.'), | |
| 68847a38 | 670 | '#default_value' => $recipients_string, |
| 129e8ef6 | 671 | '#required' => TRUE, |
| 93a1235e | 672 | '#weight' => -10, |
| 3be9375b | 673 | '#size' => 50, |
| 129e8ef6 OT |
674 | '#autocomplete_path' => 'messages/user-name-autocomplete', |
| 675 | // Do not hardcode #maxlength, make it configurable by number of recipients, not their name length. | |
| 3be9375b | 676 | ); |
| 129e8ef6 | 677 | $form['privatemsg']['subject'] = array( |
| 3be9375b OT |
678 | '#type' => 'textfield', |
| 679 | '#title' => t('Subject'), | |
| 680 | '#size' => 50, | |
| 681 | '#maxlength' => 255, | |
| 682 | '#default_value' => $subject, | |
| 93a1235e | 683 | '#weight' => -5, |
| 3be9375b | 684 | ); |
| 129e8ef6 | 685 | $form['privatemsg']['body'] = array( |
| 3be9375b OT |
686 | '#type' => 'textarea', |
| 687 | '#title' => t('Message'), | |
| 688 | '#cols' => 10, | |
| 689 | '#rows' => 6, | |
| 93a1235e | 690 | '#weight' => 0, |
| 3be9375b OT |
691 | '#default_value' => $body, |
| 692 | ); | |
| 129e8ef6 | 693 | $form['privatemsg']['preview'] = array( |
| 3be9375b | 694 | '#type' => 'submit', |
| 129e8ef6 | 695 | '#value' => t('Preview message'), |
| 3be9375b | 696 | '#submit' => array('pm_preview'), |
| 93a1235e | 697 | '#weight' => 10, |
| 3be9375b | 698 | ); |
| 129e8ef6 | 699 | $form['privatemsg']['submit'] = array( |
| 3be9375b | 700 | '#type' => 'submit', |
| 129e8ef6 | 701 | '#value' => t('Send message'), |
| 3be9375b | 702 | '#submit' => array('pm_send'), |
| 93a1235e | 703 | '#weight' => 15, |
| 3be9375b | 704 | ); |
| 12a9da26 OT |
705 | $url = 'messages'; |
| 706 | if (isset($_REQUEST['destination'])) { | |
| 707 | $url = $_REQUEST['destination']; | |
| 708 | } | |
| 68847a38 OT |
709 | elseif (!is_null($thread_id)) { |
| 710 | $url = $_GET['q']; | |
| 711 | } | |
| 12a9da26 | 712 | |
| 129e8ef6 | 713 | $form['privatemsg']['cancel'] = array( |
| 12a9da26 | 714 | '#value' => l(t('Cancel'), $url, array('attributes' => array('id' => 'edit-cancel'))), |
| 93a1235e | 715 | '#weight' => 20, |
| 3be9375b | 716 | ); |
| 3be9375b | 717 | $form['#validate'][] = 'pm_send_validate'; |
| 68847a38 OT |
718 | |
| 719 | if (!is_null($thread_id)) { | |
| 720 | $form['privatemsg']['thread_id'] = array( | |
| 721 | '#type' => 'value', | |
| 722 | '#value' => $thread_id, | |
| 723 | ); | |
| 724 | $form['privatemsg']['subject'] = array( | |
| 725 | '#type' => 'value', | |
| 726 | '#default_value' => $subject, | |
| 727 | ); | |
| 728 | $form['privatemsg']['recipient_display'] = array( | |
| 729 | '#value' => '<p>'. t('<b>Reply to thread</b>:<br /> Recipients: %to', array('%to' => $recipients_string)) .'</p>', | |
| 730 | '#weight' => -10, | |
| 731 | ); | |
| 732 | $form['privatemsg']['recipient'] = array( | |
| 733 | '#type' => 'value', | |
| 734 | '#default_value' => $recipients_string, | |
| 735 | ); | |
| 736 | if (empty($recipients_string)) { | |
| 737 | // If there are no valid recipients, unset the message reply form. | |
| 738 | $form['privatemsg']['#access'] = FALSE; | |
| 739 | } | |
| 740 | } | |
| 3be9375b | 741 | return $form; |
| 29001b19 | 742 | } |
| 129e8ef6 | 743 | |
| 3be9375b | 744 | function pm_send_validate($form, &$form_state) { |
| 129e8ef6 OT |
745 | // The actual message that is being sent, we create this during validation and pass to submit to send out. |
| 746 | $message = array(); | |
| 93a1235e | 747 | |
| 129e8ef6 OT |
748 | $message['body'] = $form_state['values']['body']; |
| 749 | $message['subject'] = $form_state['values']['subject']; | |
| 750 | $message['author'] = $form_state['values']['author']; | |
| 3be9375b | 751 | $message['timestamp'] = time(); |
| 129e8ef6 OT |
752 | if (isset($form_state['values']['thread_id']) && $form_state['values']['thread_id']) { |
| 753 | $message['thread_id'] = $form_state['values']['thread_id']; | |
| 754 | } | |
| 3be9375b | 755 | |
| 58f02933 OT |
756 | $trimed_body = trim(truncate_utf8(strip_tags($message['body']), 50, TRUE, TRUE)); |
| 757 | if (empty($message['subject']) && !empty($trimed_body)) { | |
| 758 | $message['subject'] = $trimed_body; | |
| 759 | } | |
| 129e8ef6 OT |
760 | |
| 761 | // Verify that recipient's name syntax is correct. | |
| 762 | $fragments = explode(',', $form_state['values']['recipient']); | |
| 3be9375b OT |
763 | $invalid = array(); |
| 764 | $valid = array(); | |
| 765 | foreach ($fragments as $index => $name) { | |
| 766 | $name = trim($name); | |
| 129e8ef6 | 767 | if (!empty($name)) { // We don't care about white space names. |
| 3be9375b | 768 | if (empty($name) || $error = module_invoke('user', 'validate_name', $name)) { |
| 129e8ef6 | 769 | // These names are invalid due to incorrect user name syntax. |
| 3be9375b | 770 | $invalid[$name] = $name; |
| c9696a92 Z |
771 | } |
| 772 | else { | |
| 129e8ef6 | 773 | $valid[$name] = $name; // These are valid only due to user name syntax. We still need to check if the user exists and accepts messages. |
| c9696a92 Z |
774 | } |
| 775 | } | |
| c1ab6ef9 | 776 | } |
| 129e8ef6 OT |
777 | |
| 778 | // Verify users exist and load their accounts. | |
| 779 | foreach ($valid as $index => $name) { | |
| 780 | if ($recipient = user_load(array('name' => $name))) { | |
| 93a1235e | 781 | $message['recipients'][$recipient->uid] = $recipient; |
| 3be9375b OT |
782 | } |
| 783 | else { | |
| 129e8ef6 | 784 | // Here we add more invalid names due to the fact that they don't exist. |
| 3be9375b OT |
785 | $invalid[$name] = $name; |
| 786 | } | |
| c1ab6ef9 | 787 | } |
| c1ab6ef9 | 788 | |
| 4fa130d7 | 789 | $validated = _privatemsg_validate_message($message, TRUE); |
| 3be9375b OT |
790 | $form_state['validate_built_message'] = $message; |
| 791 | if (!empty($invalid)) { | |
| b9fca179 | 792 | drupal_set_message(t('The following users will not receive this private message: !invalid', array('!invalid' => implode(", ", $invalid))), 'error'); |
| 3be9375b OT |
793 | } |
| 794 | } | |
| 129e8ef6 | 795 | |
| 3be9375b | 796 | function pm_send($form, &$form_state) { |
| 3f51bb2b OT |
797 | if (_privatemsg_send($form_state['validate_built_message'])) { // Load usernames to which the message was sent to |
| 798 | $recipient_names = array(); | |
| 799 | foreach ($form_state['validate_built_message']['recipients'] as $recipient) { | |
| 800 | $recipient_names[] = theme('username', $recipient); | |
| 801 | } | |
| 802 | drupal_set_message(t('A message has been sent to !recipients.', array('!recipients' => implode(', ', $recipient_names)))); | |
| 6c04b224 | 803 | } |
| c1ab6ef9 | 804 | } |
| fb8f4982 | 805 | |
| 3be9375b | 806 | function pm_preview($form, &$form_state) { |
| 3e0c9a83 | 807 | |
| 3be9375b OT |
808 | drupal_validate_form($form['form_id']['#value'], $form, $form_state); |
| 809 | if (!form_get_errors()) { | |
| 129e8ef6 | 810 | $form_state['privatemsg_preview'] = theme('privatemsg_view', $form_state['validate_built_message']); |
| 3be9375b | 811 | } |
| 129e8ef6 | 812 | |
| 5605b147 | 813 | $form_state['rebuild'] = TRUE; // this forces our form to be rebuilt instead of being submitted. |
| 06203012 | 814 | } |
| 129e8ef6 | 815 | |
| c277e471 | 816 | function privatemsg_sql_list(&$fragments, $account, $argument = 'list') { |
| 3be9375b | 817 | $fragments['primary_table'] = '{pm_message} pm'; |
| 129e8ef6 | 818 | |
| 4ba95ee6 | 819 | // Load enabled columns |
| c277e471 | 820 | $fields = array_filter(variable_get('privatemsg_display_fields', array('participants'))); |
| 4ba95ee6 OT |
821 | |
| 822 | // Required columns | |
| 129e8ef6 OT |
823 | $fragments['select'][] = 'pmi.thread_id'; |
| 824 | $fragments['select'][] = 'MIN(pm.subject) as subject'; | |
| fbbe3e72 | 825 | $fragments['select'][] = 'MAX(pm.timestamp) as last_updated'; |
| 129e8ef6 | 826 | $fragments['select'][] = 'MAX(pmi.is_new) as is_new'; |
| b9fca179 | 827 | |
| 4ba95ee6 OT |
828 | if (in_array('count', $fields)) { |
| 829 | $fragments['select'][] = 'COUNT(pmi.thread_id) as count'; | |
| 830 | } | |
| c277e471 | 831 | if (in_array('participants', $fields)) { |
| 4ba95ee6 OT |
832 | // Query for a string with uid's, for example "1,6,7". This needs a subquery on PostgreSQL. |
| 833 | if ($GLOBALS['db_type'] == 'pgsql') { | |
| c277e471 OT |
834 | $fragments['select'][] = "array_to_string(array(SELECT DISTINCT textin(int4out(pmia.uid)) |
| 835 | FROM {pm_index} pmia | |
| 836 | WHERE pmia.thread_id = pmi.thread_id), ',') AS participants"; | |
| 4ba95ee6 OT |
837 | } |
| 838 | else { | |
| c277e471 OT |
839 | $fragments['select'][] = '(SELECT GROUP_CONCAT(DISTINCT pmia.uid SEPARATOR ",") |
| 840 | FROM {pm_index} pmia | |
| 841 | WHERE pmia.thread_id = pmi.thread_id) AS participants'; | |
| 4ba95ee6 OT |
842 | } |
| 843 | } | |
| 844 | if (in_array('thread_started', $fields)) { | |
| 845 | $fragments['select'][] = 'MIN(pm.timestamp) as thread_started'; | |
| 846 | } | |
| 129e8ef6 | 847 | // pm_index needs to be the first join. |
| f2161b8c | 848 | $fragments['inner_join'][] = 'INNER JOIN {pm_index} pmi ON pm.mid = pmi.mid'; |
| 129e8ef6 | 849 | $fragments['where'][] = 'pmi.uid = %d'; |
| 19ee9333 | 850 | $fragments['query_args']['where'][] = $account->uid; |
| 129e8ef6 OT |
851 | $fragments['where'][] = 'pmi.deleted = 0'; |
| 852 | $fragments['group_by'][] = 'pmi.thread_id'; | |
| 129e8ef6 | 853 | |
| 4ba95ee6 OT |
854 | // We can use tablesort_sql now, but we don't need the ORDER BY part of the query. |
| 855 | // Because of that, we need to cut off the first 9 characters of the generated string | |
| 856 | $order_by = drupal_substr(tablesort_sql(_privatemsg_list_headers( FALSE, array('subject', 'last_updated') + $fields), 'is_new DESC,'), 9); | |
| 857 | $fragments['order_by'][] = $order_by; | |
| c1ab6ef9 KN |
858 | } |
| 859 | ||
| 5605b147 OT |
860 | /** |
| 861 | * @addtogroup sql | |
| 862 | * @{ | |
| 863 | */ | |
| 864 | ||
| 865 | /** | |
| 866 | * Query function for load. | |
| 867 | */ | |
| 93a1235e | 868 | function privatemsg_sql_load(&$fragments, $pmid, $account) { |
| 3be9375b | 869 | // drupal_set_message('<pre>'. print_r(func_get_args(), 1) . '</pre>'); |
| 129e8ef6 OT |
870 | $fragments['primary_table'] = '{pm_message} pm'; // Our primary table |
| 871 | ||
| 872 | $fragments['select'][] = "pm.mid"; | |
| 873 | $fragments['select'][] = "pm.author"; | |
| 874 | $fragments['select'][] = "pm.subject"; | |
| 875 | $fragments['select'][] = "pm.body"; | |
| 876 | $fragments['select'][] = "pm.timestamp"; | |
| 877 | $fragments['select'][] = "pmi.is_new"; | |
| 878 | ||
| 879 | $fragments['inner_join'][] = 'INNER JOIN {pm_index} pmi ON pm.mid = pmi.mid'; | |
| 880 | $fragments['where'][] = 'pmi.mid = %d'; | |
| 19ee9333 | 881 | $fragments['query_args']['where'][] = $pmid; |
| 129e8ef6 | 882 | $fragments['where'][] = 'pmi.uid = %d'; |
| 19ee9333 | 883 | $fragments['query_args']['where'][] = $account->uid; |
| 129e8ef6 | 884 | } |
| 4ba95ee6 OT |
885 | /** |
| 886 | * Query definition to load messages of one or multiple threads. | |
| 887 | * | |
| 888 | * @param $fragments | |
| 889 | * Query fragments array. | |
| 890 | * @param $threads | |
| 891 | * Array with one or multiple thread id's. | |
| 892 | * @param $account | |
| ebf57264 | 893 | * User object for which the messages are being loaded. |
| 4ba95ee6 | 894 | * @param $load_all |
| ebf57264 | 895 | * Deleted messages are only loaded if this is set to TRUE. |
| 4ba95ee6 OT |
896 | */ |
| 897 | function privatemsg_sql_messages(&$fragments, $threads, $account, $load_all = FALSE) { | |
| 129e8ef6 OT |
898 | $fragments['primary_table'] = '{pm_index} pmi'; |
| 899 | ||
| 900 | $fragments['select'][] = 'DISTINCT(pmi.mid) as mid'; | |
| 4ba95ee6 | 901 | $fragments['where'][] = 'pmi.thread_id IN ('. db_placeholders($threads) .')'; |
| 19ee9333 | 902 | $fragments['query_args']['where'] += $threads; |
| 129e8ef6 | 903 | $fragments['where'][] = 'pmi.uid = %d'; |
| 19ee9333 | 904 | $fragments['query_args']['where'][] = $account->uid; |
| 4ba95ee6 OT |
905 | if (!$load_all) { |
| 906 | $fragments['where'][] = 'pmi.deleted = 0'; | |
| 907 | } | |
| 129e8ef6 | 908 | $fragments['order_by'][] = 'pmi.mid ASC'; |
| c1ab6ef9 | 909 | } |
| 04b84abf | 910 | |
| f2161b8c | 911 | function privatemsg_sql_participants(&$fragments, $thread_id) { |
| 3be9375b | 912 | $fragments['primary_table'] = '{pm_index} pmi'; |
| 129e8ef6 OT |
913 | |
| 914 | $fragments['select'][] = 'DISTINCT(pmi.uid) as uid'; | |
| 915 | $fragments['where'][] = 'pmi.thread_id = %d'; | |
| 19ee9333 | 916 | $fragments['query_args']['where'][] = $thread_id; |
| fb8f4982 OT |
917 | } |
| 918 | ||
| 919 | ||
| f2161b8c | 920 | function privatemsg_sql_unread_count(&$fragments, $account) { |
| 129e8ef6 OT |
921 | $fragments['primary_table'] = '{pm_index} pmi'; |
| 922 | ||
| 923 | $fragments['select'][] = 'COUNT(DISTINCT thread_id) as unread_count'; | |
| 924 | $fragments['where'][] = 'pmi.deleted = 0'; | |
| 925 | $fragments['where'][] = 'pmi.is_new = 1'; | |
| 926 | $fragments['where'][] = 'pmi.uid = %d'; | |
| 19ee9333 | 927 | $fragments['query_args']['where'][] = $account->uid; |
| 129e8ef6 OT |
928 | } |
| 929 | ||
| afbd3810 OT |
930 | function privatemsg_sql_autocomplete(&$fragments, $search, $names) { |
| 931 | $fragments['primary_table'] = '{users} u'; | |
| 932 | $fragments['select'][] = 'u.name'; | |
| 933 | $fragments['where'][] = "u.name LIKE '%s'"; | |
| 19ee9333 | 934 | $fragments['query_args']['where'][] = $search .'%%'; |
| afbd3810 OT |
935 | if (!empty($names)) { |
| 936 | $fragments['where'][] = "u.name NOT IN (". db_placeholders($names, 'text') .")"; | |
| 19ee9333 | 937 | $fragments['query_args']['where'] += $names; |
| afbd3810 OT |
938 | } |
| 939 | $fragments['where'][] = 'u.status <> 0'; | |
| 940 | $fragments['order_by'][] = 'u.name ASC'; | |
| 941 | } | |
| 942 | ||
| fb8f4982 | 943 | /** |
| 5605b147 OT |
944 | * @} |
| 945 | */ | |
| 946 | ||
| 947 | /** | |
| fb8f4982 | 948 | * Return autocomplete results for usernames. |
| 5605b147 | 949 | * |
| 129e8ef6 | 950 | * Prevents usernames from being used and/or suggested twice. |
| fb8f4982 OT |
951 | */ |
| 952 | function privatemsg_user_name_autocomplete($string) { | |
| 953 | $names = array(); | |
| 129e8ef6 | 954 | // 1: Parse $string and build list of valid user names. |
| fb8f4982 OT |
955 | $fragments = explode(',', $string); |
| 956 | foreach ($fragments as $index => $name) { | |
| 957 | $name = trim($name); | |
| 958 | if ($error = module_invoke('user', 'validate_name', $name)) { | |
| 129e8ef6 | 959 | // Do nothing if this name does not validate. |
| fb8f4982 OT |
960 | } |
| 961 | else { | |
| 962 | $names[$name] = $name; | |
| 963 | } | |
| 964 | } | |
| 129e8ef6 OT |
965 | |
| 966 | // By using user_validate_user we can ensure that names included in $names are at least logisticaly possible. | |
| 967 | // 2: Find the next user name suggestion. | |
| fb8f4982 | 968 | $fragment = array_pop($names); |
| 56c677a0 | 969 | $matches = array(); |
| fb8f4982 | 970 | if (!empty($fragment)) { |
| afbd3810 OT |
971 | $query = _privatemsg_assemble_query('autocomplete', $fragment, $names); |
| 972 | $result = db_query_range($query['query'], $fragment, 0, 10); | |
| 129e8ef6 OT |
973 | $prefix = count($names) ? implode(", ", $names) .", " : ''; |
| 974 | // 3: Build proper suggestions and print. | |
| fb8f4982 | 975 | while ($user = db_fetch_object($result)) { |
| 129e8ef6 | 976 | $matches[$prefix . $user->name .", "] = $user->name; |
| fb8f4982 | 977 | } |
| 93a1235e | 978 | } |
| 56c677a0 OT |
979 | // convert to object to prevent drupal bug, see http://drupal.org/node/175361 |
| 980 | drupal_json((object)$matches); | |
| fb8f4982 OT |
981 | } |
| 982 | ||
| 129e8ef6 OT |
983 | function privatemsg_user($op, &$edit, &$account, $category = NULL) { |
| 984 | global $user; | |
| 985 | ||
| 986 | ||
| 987 | switch ($op) { | |
| 988 | case 'view': | |
| 68847a38 | 989 | if ($url = privatemsg_get_link(array($account))) { |
| 129e8ef6 OT |
990 | $account->content['privatemsg_send_new_message'] = array( |
| 991 | '#type' => 'markup', | |
| 93a1235e | 992 | '#value' => l(t('Send this user a message'), $url, array('query' => drupal_get_destination())), |
| 129e8ef6 OT |
993 | '#weight' => 10, |
| 994 | ); | |
| 995 | } | |
| 996 | break; | |
| 997 | case 'login': | |
| bc4689a7 | 998 | if (variable_get('privatemsg_display_loginmessage', TRUE) && privatemsg_user_access()) { |
| 20b4f5d2 OT |
999 | $count = privatemsg_unread_count(); |
| 1000 | if ($count) { | |
| 47cbdd37 | 1001 | drupal_set_message(t('You have <a href="@messages">%unread</a>.', array('@messages' => url('messages'), '%unread' => format_plural($count, '1 unread message', '@count unread messages')))); |
| 20b4f5d2 | 1002 | } |
| 129e8ef6 OT |
1003 | } |
| 1004 | break; | |
| 1005 | } | |
| 1006 | } | |
| 1007 | ||
| 1008 | function privatemsg_block($op = 'list', $delta = 0, $edit = array()) { | |
| 1009 | if ('list' == $op) { | |
| 1010 | $blocks = array(); | |
| 1011 | $blocks['privatemsg-menu'] = array( | |
| 1012 | 'info' => t('Privatemsg links'), | |
| 7deb0c62 | 1013 | 'cache' => BLOCK_NO_CACHE, |
| 129e8ef6 | 1014 | ); |
| 20b4f5d2 OT |
1015 | $blocks['privatemsg-new'] = array( |
| 1016 | 'info' => t('New message indication'), | |
| 7deb0c62 | 1017 | 'cache' => BLOCK_NO_CACHE, |
| 20b4f5d2 | 1018 | ); |
| 129e8ef6 OT |
1019 | |
| 1020 | return $blocks; | |
| 1021 | } | |
| 5605b147 | 1022 | elseif ('view' == $op) { |
| 129e8ef6 OT |
1023 | $block = array(); |
| 1024 | switch ($delta) { | |
| 1025 | case 'privatemsg-menu': | |
| 1026 | $block = _privatemsg_block_menu(); | |
| 1027 | break; | |
| 20b4f5d2 OT |
1028 | case 'privatemsg-new': |
| 1029 | $block = _privatemsg_block_new(); | |
| 1030 | break; | |
| 129e8ef6 OT |
1031 | } |
| 1032 | return $block; | |
| 1033 | } | |
| 1034 | } | |
| 1035 | ||
| 8960261c | 1036 | function privatemsg_title_callback($title = NULL) { |
| 129e8ef6 | 1037 | $count = privatemsg_unread_count(); |
| 129e8ef6 | 1038 | |
| b1d8b30e | 1039 | if ($count > 0) { |
| 924b247b | 1040 | return format_plural($count, 'Messages (1 new)', 'Messages (@count new)'); |
| b1d8b30e OT |
1041 | } |
| 1042 | return t('Messages'); | |
| 129e8ef6 OT |
1043 | } |
| 1044 | ||
| 1045 | ||
| 20b4f5d2 OT |
1046 | function _privatemsg_block_new() { |
| 1047 | $block = array(); | |
| 1048 | ||
| bc4689a7 | 1049 | if (!privatemsg_user_access()) { |
| 20b4f5d2 OT |
1050 | return $block; |
| 1051 | } | |
| 1052 | ||
| 1053 | $count = privatemsg_unread_count(); | |
| 1054 | if ($count) { | |
| 1055 | $block = array( | |
| 1056 | 'subject' => format_plural($count, 'New message', 'New messages'), | |
| 1057 | 'content' => theme('privatemsg_new_block', $count), | |
| 1058 | ); | |
| 1059 | return $block; | |
| 1060 | } | |
| 1061 | return array(); | |
| 1062 | } | |
| 1063 | ||
| 129e8ef6 OT |
1064 | function _privatemsg_block_menu() { |
| 1065 | $block = array(); | |
| 1066 | ||
| 129e8ef6 | 1067 | $links = array(); |
| bc4689a7 | 1068 | if (privatemsg_user_access('write privatemsg')) { |
| 129e8ef6 OT |
1069 | $links[] = l(t('Write new message'), 'messages/new'); |
| 1070 | } | |
| bc4689a7 | 1071 | if (privatemsg_user_access('read privatemsg') || privatemsg_user_access('read all private messages') ) { |
| 8960261c | 1072 | $links[] = l(privatemsg_title_callback(), 'messages'); |
| 129e8ef6 OT |
1073 | } |
| 1074 | if ( count( $links ) ) { | |
| 1075 | $block = array( | |
| 8c6d3b74 | 1076 | 'subject' => t('Private messages'), |
| 129e8ef6 OT |
1077 | 'content' => theme('item_list', $links), |
| 1078 | ); | |
| 1079 | } | |
| 1080 | return $block; | |
| 1081 | } | |
| 1082 | ||
| 129e8ef6 OT |
1083 | function privatemsg_delete($form_state, $pmid) { |
| 1084 | global $user; | |
| 1085 | ||
| 1086 | $form['pmid'] = array( | |
| 1087 | '#type' => 'value', | |
| 1088 | '#value' => $pmid, | |
| 1089 | ); | |
| 1090 | return confirm_form($form, | |
| 1091 | t('Are you sure you want to delete'), | |
| 1092 | isset($_GET['destination']) ? $_GET['destination'] : 'messages/view/'. $pmid, | |
| 1093 | t('This action cannot be undone.'), | |
| 1094 | t('Delete'), | |
| 1095 | t('Cancel') | |
| 1096 | ); | |
| 1097 | } | |
| 1098 | ||
| 5605b147 OT |
1099 | /** |
| 1100 | * Delete or restore a message. | |
| 1101 | * | |
| 1102 | * @param $pmid | |
| 1103 | * Message id, pm.mid field. | |
| 1104 | * @param $delete | |
| 1105 | * Either deletes or restores the thread (1 => delete, 0 => restore) | |
| 1106 | * @param $account | |
| 1107 | * User acccount for which the message should be deleted. | |
| 1108 | * | |
| 1109 | * @ingroup api | |
| 1110 | */ | |
| 4ba95ee6 | 1111 | function privatemsg_message_change_delete($pmid, $delete, $account = NULL) { |
| 93a1235e OT |
1112 | if (is_null($account)) { |
| 1113 | global $user; | |
| 1114 | $account = drupal_clone($user); | |
| 1115 | } | |
| 1116 | $message = _privatemsg_load($pmid, $account); | |
| 1117 | ||
| 4ba95ee6 | 1118 | db_query('UPDATE {pm_index} SET deleted = %d WHERE mid = %d AND uid = %d', $delete, $pmid, $account->uid); |
| 93a1235e OT |
1119 | |
| 1120 | $result = db_query("SELECT MIN(deleted) AS deleted_by_all FROM {pm_index} WHERE mid = %d", $pmid); | |
| 1121 | $deleted = db_fetch_array($result); | |
| 1122 | ||
| 1123 | $deleted_by_all = FALSE; | |
| 1124 | if ($deleted['deleted_by_all'] == 0) { | |
| 1125 | $deleted_by_all = TRUE; | |
| 1126 | } | |
| 1127 | ||
| 1128 | module_invoke_all('privatemsg_message_delete', $message, $deleted_by_all); | |
| 1129 | } | |
| 1130 | ||
| 129e8ef6 | 1131 | function privatemsg_delete_submit($form, &$form_state) { |
| 129e8ef6 | 1132 | if ($form_state['values']['confirm']) { |
| 4ba95ee6 | 1133 | privatemsg_message_change_delete($form_state['values']['pmid'], 1); |
| 0f7e1e50 | 1134 | drupal_set_message(t('Message has been deleted')); |
| 129e8ef6 OT |
1135 | } |
| 1136 | $form_state['redirect'] = 'messages'; | |
| 1137 | } | |
| 93a1235e | 1138 | /** |
| 5605b147 | 1139 | * Send a new message. |
| 93a1235e OT |
1140 | * |
| 1141 | * This functions does send a message in a new thread. | |
| 5605b147 OT |
1142 | * Example: |
| 1143 | * @code | |
| cb86482d | 1144 | * privatemsg_new_thread(array(user_load(5)), 'The subject', 'The body text'); |
| 5605b147 OT |
1145 | * @endcode |
| 1146 | * | |
| 4fa130d7 OT |
1147 | * @param $recipients |
| 1148 | * Array of recipients (user objects) | |
| 5605b147 OT |
1149 | * @param $subject |
| 1150 | * The subject of the new message | |
| 1151 | * @param $body | |
| 1152 | * The body text of the new message | |
| 4fa130d7 OT |
1153 | * @param $options |
| 1154 | * Additional options, possible keys: | |
| 1155 | * author => User object of the author | |
| 1156 | * timestamp => Time when the message was sent | |
| 93a1235e | 1157 | * |
| 5605b147 OT |
1158 | * @return |
| 1159 | * Either true or an array with validation errors | |
| 1160 | * | |
| 1161 | * @ingroup api | |
| 93a1235e | 1162 | */ |
| 4fa130d7 OT |
1163 | function privatemsg_new_thread($recipients, $subject, $body = NULL, $options = array()) { |
| 1164 | global $user; | |
| 1165 | $author = drupal_clone($user); | |
| 129e8ef6 | 1166 | |
| 93a1235e OT |
1167 | $message = array(); |
| 1168 | $message['subject'] = $subject; | |
| 93a1235e | 1169 | $message['body'] = $body; |
| 93a1235e OT |
1170 | $message['recipients'] = $recipients; |
| 1171 | ||
| cb86482d | 1172 | // Set custom options, if any. |
| 4fa130d7 OT |
1173 | if (!empty($options)) { |
| 1174 | $message += $options; | |
| 93a1235e | 1175 | } |
| cb86482d | 1176 | // Apply defaults - this will not overwrite existing keys. |
| 4fa130d7 OT |
1177 | $message += array( |
| 1178 | 'author' => $author, | |
| 1179 | 'timestamp' => time(), | |
| 1180 | ); | |
| 1181 | ||
| 1182 | $validated = _privatemsg_validate_message($message); | |
| 1183 | if ($validated['success']) { | |
| 1184 | $validated['success'] = _privatemsg_send($message); | |
| 93a1235e | 1185 | } |
| 4fa130d7 OT |
1186 | |
| 1187 | return $validated; | |
| 93a1235e OT |
1188 | } |
| 1189 | /** | |
| 1190 | * Send a reply message | |
| 1191 | * | |
| 1192 | * This functions replies on an existing thread. | |
| 1193 | * | |
| 5605b147 OT |
1194 | * @param $thread_id |
| 1195 | * Thread id | |
| 1196 | * @param $body | |
| 1197 | * The body text of the new message | |
| 4fa130d7 OT |
1198 | * @param $options |
| 1199 | * Additional options, possible keys: | |
| 1200 | * author => User object of the author | |
| 1201 | * timestamp => Time when the message was sent | |
| 5605b147 OT |
1202 | * |
| 1203 | * @return | |
| 1204 | * Either true or an array with validation errors | |
| 93a1235e | 1205 | * |
| 5605b147 | 1206 | * @ingroup api |
| 93a1235e | 1207 | */ |
| 4fa130d7 OT |
1208 | function privatemsg_reply($thread_id, $body = NULL, $options = array()) { |
| 1209 | global $user; | |
| 1210 | $author = drupal_clone($user); | |
| 93a1235e OT |
1211 | |
| 1212 | $message = array(); | |
| 93a1235e | 1213 | $message['body'] = $body; |
| 4fa130d7 OT |
1214 | |
| 1215 | // set custom options, if any | |
| 1216 | if (!empty($options)) { | |
| 1217 | $message += $options; | |
| 1218 | } | |
| 1219 | // apply defaults | |
| 1220 | $message += array( | |
| 1221 | 'author' => $author, | |
| 1222 | 'timestamp' => time(), | |
| 1223 | ); | |
| 93a1235e OT |
1224 | |
| 1225 | // We don't know the subject and the recipients, so we need to load them.. | |
| 1226 | // thread_id == mid on the first message of the thread | |
| 4fa130d7 | 1227 | $first_message = _privatemsg_load($thread_id, $message['author']); |
| 93a1235e OT |
1228 | if (!$first_message) { |
| 1229 | return array(t('Thread %thread_id not found, unable to answer', array('%thread_id' => $thread_id))); | |
| 1230 | } | |
| 1231 | ||
| 89f2c1af | 1232 | $message['thread_id'] = $thread_id; |
| 93a1235e OT |
1233 | |
| 1234 | $query = _privatemsg_assemble_query('participants', $thread_id); | |
| 1235 | $participants = db_query($query['query']); | |
| 1236 | while ($result = db_fetch_object($participants)) { | |
| 1237 | $recipient = user_load($result->uid); | |
| 1238 | $message['recipients'][$recipient->uid] = $recipient; | |
| 1239 | } | |
| 1240 | ||
| 1241 | $message['subject'] = $first_message['subject']; | |
| 1242 | ||
| 4fa130d7 OT |
1243 | $validated = _privatemsg_validate_message($message); |
| 1244 | if ($validated['success']) { | |
| 1245 | $validated['success'] = _privatemsg_send($message); | |
| 93a1235e | 1246 | } |
| 4fa130d7 | 1247 | return $validated; |
| 93a1235e OT |
1248 | } |
| 1249 | ||
| 4fa130d7 OT |
1250 | function _privatemsg_validate_message(&$message, $form = FALSE) { |
| 1251 | $messages = array('error' => array(), 'warning' => array()); | |
| 1252 | if (!privatemsg_user_access('write privatemsg', $message['author'])) { | |
| 93a1235e | 1253 | // no need to do further checks in this case... |
| 4fa130d7 OT |
1254 | if ($form) { |
| 1255 | form_set_error('author', t('User @user is not allowed to write messages', array('@user' => $message['author']->name))); | |
| 1256 | return array( | |
| 1257 | 'success' => FALSE, | |
| 1258 | 'messages' => $messages, | |
| 1259 | ); | |
| 1260 | } | |
| 1261 | else { | |
| 1262 | $messages['error'][] = t('User @user is not allowed to write messages', array('@user' => $message['author']->name)); | |
| 1263 | return array( | |
| 1264 | 'success' => FALSE, | |
| 1265 | 'messages' => $messages, | |
| 1266 | ); | |
| 1267 | } | |
| 129e8ef6 OT |
1268 | } |
| 1269 | ||
| 93a1235e | 1270 | if (empty($message['subject'])) { |
| 4fa130d7 OT |
1271 | if ($form) { |
| 1272 | form_set_error('subject', t('Disallowed to send a message without subject')); | |
| 1273 | } | |
| 1274 | else { | |
| 1275 | $messages['error'][] = t('Disallowed to send a message without subject'); | |
| 1276 | } | |
| 93a1235e OT |
1277 | } |
| 1278 | ||
| 93a1235e | 1279 | if (empty($message['recipients']) || !is_array($message['recipients'])) { |
| 4fa130d7 OT |
1280 | if ($form) { |
| 1281 | form_set_error('to', t('Disallowed to send a message without atleast one valid recipient')); | |
| 1282 | } | |
| 1283 | else { | |
| 1284 | $messages['error'][] = t('Disallowed to send a message without atleast one valid recipient'); | |
| 1285 | } | |
| 93a1235e OT |
1286 | } |
| 1287 | ||
| 1288 | if (!empty($message['recipients']) && is_array($message['recipients'])) { | |
| 4fa130d7 | 1289 | foreach(module_invoke_all('privatemsg_block_message', $message['author'], $message['recipients']) as $blocked) { |
| b9fca179 | 1290 | unset($message['recipients'][$blocked['uid']]); |
| 6f9a6e13 OT |
1291 | if ($form) { |
| 1292 | drupal_set_message($blocked['message'], 'warning'); | |
| 1293 | } else { | |
| 1294 | $messages['warning'][] = $blocked['message']; | |
| 1295 | } | |
| 93a1235e OT |
1296 | } |
| 1297 | } | |
| 1298 | ||
| 1299 | // Check again, give another error message if all recipients are blocked | |
| 1300 | if (empty($message['recipients'])) { | |
| 4fa130d7 OT |
1301 | if ($form) { |
| 1302 | form_set_error('to', t('Disallowed to send message because all recipients are blocked')); | |
| 1303 | } | |
| 1304 | else { | |
| 1305 | $messages['error'][] = t('Disallowed to send message because all recipients are blocked'); | |
| 1306 | } | |
| 93a1235e OT |
1307 | } |
| 1308 | ||
| 4fa130d7 OT |
1309 | $messages += module_invoke_all('privatemsg_message_validate', $message, $form); |
| 1310 | $success = empty($messages['error']); | |
| 1311 | return array( | |
| 1312 | 'success' => $success, | |
| 1313 | 'messages' => $messages, | |
| 1314 | ); | |
| 129e8ef6 OT |
1315 | } |
| 1316 | ||
| 93a1235e OT |
1317 | function _privatemsg_send($message) { |
| 1318 | ||
| 1319 | drupal_alter('privatemsg_message_presave', $message); | |
| 1320 | ||
| 1321 | // 1) Save the message body first. | |
| 1322 | $args = array(); | |
| 1323 | $args[] = $message['subject']; | |
| 1324 | $args[] = $message['author']->uid; | |
| 1325 | $args[] = $message['body']; | |
| 1326 | $args[] = $message['timestamp']; | |
| 1327 | $query = "INSERT INTO {pm_message} (subject, author, body, timestamp) VALUES ('%s', %d, '%s', %d)"; | |
| 1328 | $resuld = db_query($query, $args); | |
| 1329 | $mid = db_last_insert_id('pm_message', 'mid'); | |
| 1330 | $message['mid'] = $mid; | |
| 1331 | ||
| 1332 | // Thread ID is the same as the mid if it's the first message in the thread. | |
| 1333 | if (!isset($message['thread_id'])) { | |
| 1334 | $message['thread_id'] = $mid; | |
| 1335 | } | |
| 1336 | ||
| 1337 | // 2) Save message to recipients. | |
| 1338 | // Each recipient gets a record in the pm_index table. | |
| 1339 | ||
| 1340 | $query = "INSERT INTO {pm_index} (mid, thread_id, uid, is_new, deleted) VALUES (%d, %d, %d, %d, 0)"; | |
| 1341 | foreach ($message['recipients'] as $recipient) { | |
| 1342 | ||
| 1343 | db_query($query, $mid, $message['thread_id'], $recipient->uid, 1); | |
| 1344 | } | |
| 1345 | // Also add a record for tha author to the pm_index table - set column "new" to 0. | |
| 1346 | db_query($query, $mid, $message['thread_id'], $message['author']->uid, 0); | |
| 1347 | ||
| 1348 | module_invoke_all('privatemsg_message_insert', $message); | |
| 1349 | ||
| 1350 | return TRUE; | |
| 129e8ef6 OT |
1351 | } |
| 1352 | ||
| 93a1235e OT |
1353 | /** |
| 1354 | * Returns a link to send message form for a specific users. | |
| 1355 | * | |
| 1356 | * Contains permission checks of author/recipient, blocking and | |
| 1357 | * if a anonymous user is involved. | |
| 1358 | * | |
| 5605b147 OT |
1359 | * @param $recipient |
| 1360 | * Recipient of the message | |
| 1361 | * @param $account | |
| 1362 | * Sender of the message, defaults to the current user | |
| 1363 | * | |
| 1364 | * @return | |
| 1365 | * Either FALSE or a URL string | |
| 93a1235e | 1366 | * |
| 5605b147 | 1367 | * @ingroup api |
| 93a1235e | 1368 | */ |
| 68847a38 | 1369 | function privatemsg_get_link($recipients, $account = array(), $subject = NULL) { |
| 93a1235e OT |
1370 | if ($account == NULL) { |
| 1371 | global $user; | |
| 1372 | $account = $user; | |
| 1373 | } | |
| 76d28f2a | 1374 | |
| 68847a38 OT |
1375 | if (!is_array($recipients)) { |
| 1376 | $recipients = array($recipients); | |
| 1377 | } | |
| 93a1235e | 1378 | |
| 68847a38 | 1379 | if (!privatemsg_user_access('write privatemsg', $account) || $account->uid == 0) { |
| 93a1235e OT |
1380 | return FALSE; |
| 1381 | } | |
| 1382 | ||
| 68847a38 OT |
1383 | $validated = array(); |
| 1384 | foreach ($recipients as $recipient) { | |
| 1385 | if (!privatemsg_user_access('read privatemsg', $recipient)) { | |
| 1386 | continue; | |
| 1387 | } | |
| 1388 | if (count(module_invoke_all('privatemsg_block_message', $account, array($recipient))) > 0) { | |
| 1389 | continue; | |
| 1390 | } | |
| 1391 | $validated[] = $recipient->uid; | |
| 1392 | } | |
| 1393 | if (empty($validated)) { | |
| 93a1235e OT |
1394 | return FALSE; |
| 1395 | } | |
| 68847a38 OT |
1396 | $url = 'messages/new/'. implode(',', $validated); |
| 1397 | if (!is_null($subject)) { | |
| 1398 | $url .= '/'. $subject; | |
| 1399 | } | |
| 1400 | return $url; | |
| 93a1235e | 1401 | } |
| efb7face OT |
1402 | |
| 1403 | /** | |
| 5605b147 | 1404 | * Load a single message. |
| efb7face | 1405 | * |
| 5605b147 OT |
1406 | * @param $pmid |
| 1407 | * Message id, pm.mid field | |
| 1408 | * @param $account | |
| 1409 | * For which account the message should be loaded. | |
| 1410 | * Defaults to the current user. | |
| 1411 | * | |
| 1412 | * @ingroup api | |
| efb7face OT |
1413 | */ |
| 1414 | function _privatemsg_load($pmid, $account = NULL) { | |
| 1415 | if (empty($account)) { | |
| 1416 | global $user; | |
| 1417 | $account = drupal_clone($user); | |
| 1418 | } | |
| 1419 | ||
| 1420 | $query = _privatemsg_assemble_query('load', $pmid, $account); | |
| 1421 | ||
| 1422 | $result = db_query($query['query']); | |
| 1423 | $message = db_fetch_array($result); | |
| 1424 | $message['user'] = $account; | |
| 053a2f78 OT |
1425 | // Load author of message. |
| 1426 | $message['author'] = user_load($message['author']); | |
| efb7face OT |
1427 | $returned = module_invoke_all('privatemsg_message_load', $message); |
| 1428 | if (!empty($returned)) { | |
| 1429 | $message = array_merge_recursive($returned, $message); | |
| 1430 | } | |
| 1431 | return $message; | |
| 1432 | } | |
| 1433 | ||
| 5605b147 OT |
1434 | /** |
| 1435 | * Generates a query based on a query id. | |
| 1436 | * | |
| 1437 | * @param $query | |
| 1438 | * Either be a string ('some_id') or an array('group_name', 'query_id'), | |
| 1439 | * if a string is supplied, group_name defaults to 'privatemsg'. | |
| 1440 | * | |
| 1441 | * @return | |
| 1442 | * Array with the keys query and count. count can be used to count the | |
| 1443 | * elements which would be returned by query. count can be used together | |
| 1444 | * with pager_query(). | |
| 1445 | * | |
| 1446 | * @ingroup sql | |
| 1447 | */ | |
| efb7face OT |
1448 | function _privatemsg_assemble_query($query) { |
| 1449 | ||
| 1450 | // Modules will be allowed to choose the prefix for the querybuilder, but if there is not one supplied, 'privatemsg' will be taken by default. | |
| 1451 | if (is_array($query)) { | |
| 1452 | $query_id = $query[0]; | |
| 1453 | $query_group = $query[1]; | |
| 1454 | } | |
| 1455 | else { | |
| 1456 | $query_id = $query; | |
| 1457 | $query_group = 'privatemsg'; | |
| 1458 | } | |
| 1459 | ||
| 1460 | $SELECT = array(); | |
| 1461 | $INNER_JOIN = array(); | |
| 1462 | $WHERE = array(); | |
| 1463 | $GROUP_BY = array(); | |
| c277e471 | 1464 | $HAVING = array(); |
| efb7face | 1465 | $ORDER_BY = array(); |
| 19ee9333 | 1466 | $QUERY_ARGS = array('where' => array(), 'join' => array(), 'having' => array()); |
| efb7face OT |
1467 | $primary_table = ''; |
| 1468 | ||
| 1469 | $fragments = array( | |
| 1470 | 'select' => $SELECT, | |
| 1471 | 'inner_join' => $INNER_JOIN, | |
| 1472 | 'where' => $WHERE, | |
| 1473 | 'group_by' => $GROUP_BY, | |
| c277e471 | 1474 | 'having' => $HAVING, |
| efb7face OT |
1475 | 'order_by' => $ORDER_BY, |
| 1476 | 'query_args' => $QUERY_ARGS, | |
| 1477 | 'primary_table' => $primary_table, | |
| 1478 | ); | |
| 1479 | ||
| 1480 | /** | |
| 1481 | * Begin: dynamic arguments | |
| 1482 | */ | |
| 1483 | $args = func_get_args(); | |
| 1484 | unset($args[0]); | |
| 5605b147 OT |
1485 | // we do the merge because we call call_user_func_array and not drupal_alter |
| 1486 | // this is necessary because otherwise we would not be able to use $args correctly (otherwise it doesnt unfold) | |
| efb7face OT |
1487 | $alterargs = array(&$fragments); |
| 1488 | $query_function = $query_group .'_sql_'. $query_id; | |
| 1489 | if (!empty($args)) { | |
| 1490 | $alterargs = array_merge($alterargs, $args); | |
| 1491 | } | |
| 1492 | /** | |
| 1493 | * END: Dynamic arguments | |
| 1494 | */ | |
| 1495 | if (!function_exists($query_function)) { | |
| 1496 | drupal_set_message(t('Query function %function does not exist', array('%function' => $query_function)), 'error'); | |
| 1497 | return FALSE; | |
| 1498 | } | |
| 1499 | call_user_func_array($query_function, $alterargs); | |
| 1500 | ||
| 1501 | array_unshift($alterargs, $query_function); | |
| 1502 | call_user_func_array('drupal_alter', $alterargs); | |
| 1503 | ||
| 1504 | $SELECT = $fragments['select']; | |
| 1505 | $INNER_JOIN = $fragments['inner_join']; | |
| 1506 | $WHERE = $fragments['where']; | |
| 1507 | $GROUP_BY = $fragments['group_by']; | |
| c277e471 | 1508 | $HAVING = $fragments['having']; |
| efb7face OT |
1509 | $ORDER_BY = $fragments['order_by']; |
| 1510 | $QUERY_ARGS = $fragments['query_args']; | |
| 1511 | $primary_table = $fragments['primary_table']; | |
| 1512 | ||
| d3e3d31e OT |
1513 | // pgsql has a case sensitive LIKE - replace it with ILIKE. see http://drupal.org/node/462982 |
| 1514 | if ($GLOBALS['db_type'] == 'pgsql') { | |
| 1515 | $WHERE = str_replace('LIKE', 'ILIKE', $WHERE); | |
| 1516 | } | |
| 1517 | ||
| efb7face OT |
1518 | if (empty($primary_table)) { |
| 1519 | $primary_table = '{privatemsg} pm'; | |
| 1520 | } | |
| 1521 | ||
| 1522 | // Perform the whole query assembly only if we have something to select. | |
| 1523 | if (!empty($SELECT)) { | |
| 1524 | $str_select = implode(", ", $SELECT); | |
| 1525 | $query = "SELECT {$str_select} FROM ". $primary_table; | |
| 1526 | ||
| 1527 | // Also build a count query which can be passed to pager_query to get a "page count" as that does not play well with queries including "GROUP BY". | |
| 1528 | // In most cases, "COUNT(*)" is enough to get the count query, but in queries involving a GROUP BY, we want a count of the number of groups we have, not the count of elements inside each group. | |
| 1529 | // So we test if there is GROUP BY and if there is, count the number of distinct groups. If not, we go the normal wal and do a plain COUNT(*). | |
| 1530 | if (!empty($GROUP_BY)) { | |
| 1531 | // PostgreSQL does not support COUNT(sometextfield, someintfield), so I'm only using the first one | |
| 1532 | // Works fine for thread_id/list but may generate an error when a more complex GROUP BY is used. | |
| 1533 | $str_group_by_count = current($GROUP_BY); | |
| 1534 | $count = "SELECT COUNT(DISTINCT {$str_group_by_count}) FROM ". $primary_table; | |
| 1535 | } | |
| 1536 | else { | |
| 1537 | $count = "SELECT COUNT(*) FROM ". $primary_table; | |
| 1538 | } | |
| 1539 | ||
| 1540 | if (!empty($INNER_JOIN)) { | |
| 1541 | $str_inner_join = implode(' ', $INNER_JOIN); | |
| 1542 | $query .= " {$str_inner_join}"; | |
| 1543 | $count .= " {$str_inner_join}"; | |
| 1544 | } | |
| 1545 | if (!empty($WHERE)) { | |
| 1546 | $str_where = '('. implode(') AND (', $WHERE) .')'; | |
| 1547 | $query .= " WHERE {$str_where}"; | |
| 1548 | $count .= " WHERE {$str_where}"; | |
| 1549 | } | |
| 1550 | if (!empty($GROUP_BY)) { | |
| 1551 | $str_group_by = ' GROUP BY '. implode(", ", $GROUP_BY) ; | |
| 1552 | $query .= " {$str_group_by}"; | |
| 1553 | } | |
| c277e471 OT |
1554 | if (!empty($HAVING)) { |
| 1555 | $str_having = '('. implode(') AND (', $HAVING) .')'; | |
| 1556 | $query .= " HAVING {$str_having}"; | |
| 1557 | // queries containing a HAVING break the count query on pgsql. | |
| 1558 | // In this case, use the subquery method as outlined in http://drupal.org/node/303087#comment-1370752 . | |
| 1559 | // The subquery method will work for all COUNT queries, but it is thought to be much slower, so we are only using it where other cross database approaches fail. | |
| 1560 | $count = 'SELECT COUNT(*) FROM ('. $query .') as count'; | |
| 1561 | } | |
| efb7face OT |
1562 | if (!empty($ORDER_BY)) { |
| 1563 | $str_order_by = ' ORDER BY '. implode(", ", $ORDER_BY) ; | |
| 1564 | $query .= " {$str_order_by}"; | |
| 1565 | } | |
| 19ee9333 | 1566 | $QUERY_ARGS = array_merge($QUERY_ARGS['join'], $QUERY_ARGS['where'], $QUERY_ARGS['having']); |
| efb7face OT |
1567 | if (!empty($QUERY_ARGS)) { |
| 1568 | _db_query_callback($QUERY_ARGS, TRUE); | |
| 1569 | $query = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $query); | |
| 1570 | _db_query_callback($QUERY_ARGS, TRUE); | |
| 1571 | $count = preg_replace_callback(DB_QUERY_REGEXP, '_db_query_callback', $count); | |
| 1572 | } | |
| 1573 | return array('query' => $query, 'count' => $count); | |
| 1574 | } | |
| 1575 | return FALSE; | |
| 1576 | } | |
| 4ba95ee6 | 1577 | |
| a926640f OT |
1578 | /** |
| 1579 | * Returns a form which handles and displays thread actions. | |
| 1580 | * | |
| 1581 | * Additional actions can be added with the privatemsg_thread_operations hook. | |
| 1582 | * It is also possible to extend this form with additional buttons or other | |
| 1583 | * elements, in that case, the definitions in the above hook need no label tag, | |
| 1584 | * instead, the submit button key needs to match with the key of the operation. | |
| 1585 | * | |
| 1586 | * @see hook_privatemsg_thread_operations() | |
| 1587 | * | |
| 1588 | * @return | |
| 1589 | * The FAPI definitions for the thread action form. | |
| 1590 | */ | |
| 4ba95ee6 OT |
1591 | function _privatemsg_action_form() { |
| 1592 | $form = array( | |
| 1593 | '#type' => 'fieldset', | |
| 1594 | '#title' => t('Actions'), | |
| 1595 | '#prefix' => '<div class="container-inline">', | |
| 1596 | '#suffix' => '</div>', | |
| 1597 | '#collapsible' => TRUE, | |
| 1598 | '#collapsed' => FALSE, | |
| 1599 | '#weight' => 15, | |
| 1600 | ); | |
| 1601 | $form['delete'] = array( | |
| 1602 | '#type' => 'submit', | |
| 1603 | '#value' => t('Delete'), | |
| 1604 | ); | |
| 1605 | // Display all operations which have a label. | |
| 68940e1a | 1606 | $options = array(0 => t('More actions...')); |
| 4ba95ee6 OT |
1607 | foreach (module_invoke_all('privatemsg_thread_operations') as $operation => $array) { |
| 1608 | if (isset($array['label'])) { | |
| 1609 | $options[$operation] = $array['label']; | |
| 1610 | } | |
| 1611 | } | |
| 1612 | $form['operation'] = array( | |
| 1613 | '#type' => 'select', | |
| 1614 | '#options' => $options, | |
| 1615 | '#default_value' => 0, | |
| 1616 | // Execute the submit button if a operation has been selected. | |
| 1617 | '#attributes' => array('onchange' => "$('#edit-submit').click()"), | |
| 1618 | ); | |
| 1619 | $form['submit'] = array( | |
| 1620 | '#type' => 'submit', | |
| 1621 | '#value' => t('Execute'), | |
| 1622 | '#submit' => array('privatemsg_list_submit'), | |
| 1623 | '#attributes' => array('class' => 'privatemsg-action-button'), | |
| 1624 | ); | |
| 1625 | // JS for hiding the execute button(s) | |
| 1626 | drupal_add_js(drupal_get_path('module', 'privatemsg') .'/privatemsg-list.js'); | |
| 1627 | return $form; | |
| 1628 | } | |
| 1629 | ||
| 1630 | /** | |
| 7608a25a | 1631 | * Marks one or multiple threads as (un)read. |
| 4ba95ee6 OT |
1632 | * |
| 1633 | * @param $threads | |
| 7608a25a | 1634 | * Array with thread id's or a single thread id. |
| 4ba95ee6 | 1635 | * @param $status |
| 7608a25a | 1636 | * Either PRIVATEMSG_READ or PRIVATEMSG_UNREAD, sets the new status. |
| 4ba95ee6 | 1637 | * @param $account |
| 7608a25a | 1638 | * User object for which the threads should be deleted, defaults to the current user. |
| 4ba95ee6 OT |
1639 | */ |
| 1640 | function privatemsg_thread_change_status($threads, $status, $account = NULL) { | |
| 1641 | if (!is_array($threads)) { | |
| 1642 | $threads = array($threads); | |
| 1643 | } | |
| 1644 | if (empty($account)) { | |
| 1645 | global $user; | |
| 1646 | $account = drupal_clone($user); | |
| 1647 | } | |
| 1648 | // Merge status and uid with the threads list. array_merge() will not overwrite/ignore thread_id 1. | |
| 1649 | $params = array_merge(array($status, $account->uid), $threads); | |
| 1650 | db_query('UPDATE {pm_index} SET is_new = %d WHERE uid = %d AND thread_id IN ('. db_placeholders($threads) .')', $params); | |
| 1651 | ||
| 1652 | if ($status == PRIVATEMSG_UNREAD) { | |
| 1653 | drupal_set_message(t('Marked %count threads as unread.', array('%count' => count($threads)))); | |
| 1654 | } | |
| 1655 | else { | |
| 1656 | drupal_set_message(t('Marked %count threads as read.', array('%count' => count($threads)))); | |
| 1657 | } | |
| 1658 | } | |
| 1659 | /** | |
| 1660 | * Returns a table header definition based on the submitted keys. | |
| 1661 | * | |
| 7bb3f078 OT |
1662 | * Uses @link theming theme patterns @endlink to theme single headers. |
| 1663 | * | |
| 4ba95ee6 | 1664 | * @param $has_posts |
| 7608a25a OT |
1665 | * TRUE when there is at least one row. Decides if the select all checkbox should be displayed. |
| 1666 | * @param $keys | |
| 4ba95ee6 OT |
1667 | * Array with the keys which are present in the query/should be displayed. |
| 1668 | * @return | |
| 1669 | * Array with header defintions for tablesort_sql and theme('table'). | |
| 1670 | */ | |
| 1671 | function _privatemsg_list_headers($has_posts, $keys) { | |
| 1672 | $select_header = $has_posts ? theme('table_select_header_cell') : ''; | |
| 1673 | $select_header['#weight'] = -50; | |
| 1674 | ||
| 1675 | // theme() doesn't include the theme file for patterns, we need to do it manually. | |
| 1676 | include_once drupal_get_path('module', 'privatemsg') .'/privatemsg.theme.inc'; | |
| 1677 | ||
| 1678 | $header = array($select_header); | |
| 1679 | foreach ($keys as $key) { | |
| 1680 | // First, try to load a specific theme for that header, if not present, use the default. | |
| 1681 | if ($return = theme(array('privatemsg_list_header__'. $key, 'privatemsg_list_header'))) { | |
| 1682 | // The default theme returns nothing, only store the value if we have something. | |
| 1683 | $header[$key] = $return; | |
| 1684 | } | |
| 1685 | } | |
| 1686 | return $header; | |
| 1687 | } | |
| 1688 | ||
| 1689 | /** | |
| 1690 | * Formats a row in the message list. | |
| 1691 | * | |
| 7bb3f078 | 1692 | * Uses @link theming theme patterns @endlink to theme single fields. |
| b9fca179 | 1693 | * |
| 4ba95ee6 OT |
1694 | * @param $thread |
| 1695 | * Array with the row data returned by the database. | |
| 1696 | * @return | |
| 1697 | * Row definition for use with theme('table') | |
| 1698 | */ | |
| 1699 | function _privatemsg_list_thread($thread) { | |
| 1700 | $row = array('data' => array()); | |
| 1701 | ||
| 1702 | if (!empty($thread['is_new'])) { | |
| 1703 | // Set the css class in the tr tag. | |
| 1704 | $row['class'] = 'privatemsg-unread'; | |
| 1705 | } | |
| 1706 | foreach ($thread as $key => $data) { | |
| 1707 | // First, try to load a specific theme for that field, if not present, use the default. | |
| 1708 | if ($return = theme(array('privatemsg_list_field__'. $key, 'privatemsg_list_field'), $thread)) { | |
| 1709 | // The default theme returns nothing, only store the value if we have something. | |
| 1710 | $row['data'][$key] = $return; | |
| 1711 | } | |
| 1712 | } | |
| 1713 | return $row; | |
| 1714 | } | |
| 1715 | ||
| 1716 | /** | |
| 1717 | * Menu callback for messages/undo/action. | |
| 1718 | * | |
| ad541119 | 1719 | * This function will test if an undo callback is stored in SESSION and execute it. |
| 4ba95ee6 OT |
1720 | */ |
| 1721 | function privatemsg_undo_action() { | |
| 1722 | // Check if a undo callback for that user exists. | |
| 1723 | if (isset($_SESSION['privatemsg']['undo callback']) && is_array($_SESSION['privatemsg']['undo callback'])) { | |
| 1724 | $undo = $_SESSION['privatemsg']['undo callback']; | |
| 1725 | // If the defined undo callback exists, execute it | |
| 1726 | if (isset($undo['function']) && isset($undo['args'])) { | |
| 1727 | call_user_func_array($undo['function'], $undo['args']); | |
| 1728 | } | |
| 1729 | // Return back to the site defined by the destination GET param. | |
| 1730 | drupal_goto(); | |
| 1731 | } | |
| 1732 | } | |
| 1733 | ||
| 1734 | /** | |
| 1735 | * Process privatemsg_list form submissions. | |
| 1736 | * | |
| 1737 | * Execute the chosen action on the selected messages. This function is | |
| 1738 | * based on node_admin_nodes_submit(). | |
| 1739 | */ | |
| 1740 | function privatemsg_list_submit($form, &$form_state) { | |
| 1741 | // Load all available operation definitions. | |
| 1742 | $operations = module_invoke_all('privatemsg_thread_operations'); | |
| 1743 | ||
| 1744 | // Default "default" operation, which won't do anything. | |
| 1745 | $operation = array('callback' => 0); | |
| 1746 | ||
| 1747 | // Check if a valid operation has been submitted. | |
| 1748 | if (isset($form_state['values']['operation']) && isset($operations[$form_state['values']['operation']])) { | |
| 1749 | $operation = $operations[$form_state['values']['operation']]; | |
| 1750 | } | |
| 1751 | ||
| 1752 | // Load all keys where the value is the current op. | |
| 1753 | $keys = array_keys($form_state['values'], $form_state['values']['op']); | |
| 1754 | ||
| 1755 | // The first one is op itself, we need to use the second. | |
| 1756 | if (isset($keys[1]) && isset($operations[$keys[1]])) { | |
| 1757 | $operation = $operations[$keys[1]]; | |
| 1758 | } | |
| 1759 | ||
| ad541119 | 1760 | // Filter out unchecked threads, this gives us an array of "checked" threads. |
| 4ba95ee6 OT |
1761 | $threads = array_filter($form_state['values']['threads']); |
| 1762 | ||
| 1763 | // Only execute something if we have a valid callback and atleast one checked thread. | |
| 1764 | if (!empty($operation['callback']) && !empty($threads)) { | |
| 1765 | // Add in callback arguments if present. | |
| 1766 | if (isset($operation['callback arguments'])) { | |
| 1767 | $args = array_merge(array($threads), $operation['callback arguments']); | |
| 1768 | } | |
| 1769 | else { | |
| 1770 | $args = array($threads); | |
| 1771 | } | |
| 1772 | // Execute the chosen action and pass the defined arguments. | |
| 1773 | call_user_func_array($operation['callback'], $args); | |
| 1774 | ||
| 1775 | // Check if that operation has defined a undo callback | |
| 1776 | if (isset($operation['undo callback']) && $undo_function = $operation['undo callback']) { | |
| 1777 | // Add in callback arguments if present. | |
| 1778 | if (isset($operation['undo callback arguments'])) { | |
| 1779 | $undo_args = array_merge(array($threads), $operation['undo callback arguments']); | |
| 1780 | } | |
| 1781 | else { | |
| 1782 | $undo_args = array($threads); | |
| 1783 | } | |
| 1784 | // Store the undo callback in the session and display a "Undo" link. | |
| 1785 | // @todo: Provide a more flexible solution for such an undo action, operation defined string for example. | |
| 1786 | $_SESSION['privatemsg']['undo callback'] = array('function' => $undo_function, 'args' => $undo_args); | |
| 1787 | $undo = l(t('undone'), 'messages/undo/action', array('query' => drupal_get_destination())); | |
| 1788 | ||
| 1789 | drupal_set_message(t('The previous action can be !undo.', array('!undo' => $undo))); | |
| 1790 | } | |
| 1791 | } | |
| 1792 | } | |
| 1793 | ||
| 1794 | /** | |
| 22107330 | 1795 | * Delete or restore one or multiple threads. |
| 4ba95ee6 OT |
1796 | * |
| 1797 | * @param $threads | |
| 22107330 | 1798 | * Array with thread id's or a single thread id. |
| 4ba95ee6 | 1799 | * @param $delete |
| 22107330 | 1800 | * Indicates if the threads should be deleted or restored. 1 => delete, 0 => restore. |
| 4ba95ee6 OT |
1801 | * @param $account |
| 1802 | * User object for which the threads should be deleted, defaults to the current user. | |
| 1803 | */ | |
| 1804 | function privatemsg_thread_change_delete($threads, $delete, $account = NULL) { | |
| 1805 | if (!is_array($threads)) { | |
| 1806 | $threads = array($threads); | |
| 1807 | } | |
| 1808 | if (empty($account)) { | |
| 1809 | global $user; | |
| 1810 | $account = drupal_clone($user); | |
| 1811 | } | |
| 1812 | ||
| 1813 | // Merge status and uid with the threads list. array_merge() will not overwrite/ignore thread_id 1. | |
| 1814 | $params = array_merge(array($delete, $account->uid), $threads); | |
| 1815 | ||
| 1816 | // Load all messages of those threads including the deleted. | |
| 1817 | $query = _privatemsg_assemble_query('messages', $threads, $account, TRUE); | |
| 1818 | $result = db_query($query['query']); | |
| 1819 | ||
| 1820 | // Delete each message. We need to do that to trigger the delete hook. | |
| 1821 | while ($row = db_fetch_array($result)) { | |
| 1822 | privatemsg_message_change_delete($row['mid'], $delete, $account); | |
| 1823 | } | |
| 1824 | ||
| 1825 | if ($delete) { | |
| 1826 | drupal_set_message(t('Deleted %count threads.', array('%count' => count($threads)))); | |
| 1827 | } | |
| 1828 | else { | |
| 1829 | drupal_set_message(t('Restored %count threads.', array('%count' => count($threads)))); | |
| 1830 | } | |
| 1831 | } | |
| 1832 | ||
| 1833 | /** | |
| 1834 | * Implementation of hook_privatemsg_thread_operations(). | |
| 1835 | */ | |
| 1836 | function privatemsg_privatemsg_thread_operations() { | |
| 1837 | $operations = array( | |
| 1838 | 'mark as read' => array( | |
| 1839 | 'label' => t('Mark as read'), | |
| 1840 | 'callback' => 'privatemsg_thread_change_status', | |
| 1841 | 'callback arguments' => array('status' => PRIVATEMSG_READ), | |
| 1842 | 'undo callback' => 'privatemsg_thread_change_status', | |
| 1843 | 'undo callback arguments' => array('status' => PRIVATEMSG_UNREAD), | |
| 1844 | ), | |
| 1845 | 'mark as unread' => array( | |
| 1846 | 'label' => t('Mark as unread'), | |
| 1847 | 'callback' => 'privatemsg_thread_change_status', | |
| 1848 | 'callback arguments' => array('status' => PRIVATEMSG_UNREAD), | |
| 1849 | 'undo callback' => 'privatemsg_thread_change_status', | |
| 1850 | 'undo callback arguments' => array('status' => PRIVATEMSG_READ), | |
| 1851 | ), | |
| 1852 | 'delete' => array( | |
| 1853 | 'callback' => 'privatemsg_thread_change_delete', | |
| 1854 | 'callback arguments' => array('delete' => 1), | |
| 1855 | 'undo callback' => 'privatemsg_thread_change_delete', | |
| 1856 | 'undo callback arguments' => array('delete' => 0), | |
| 1857 | ), | |
| 1858 | ); | |
| 1859 | return $operations; | |
| 1860 | } |