b2evolution PHP Cross Reference Blogging Systems

Source: /inc/messaging/model/_messaging.funcs.php - 2063 lines - 62865 bytes - Summary - Text - Print

Description: This file is part of b2evolution - {@link http://b2evolution.net/} See also {@link http://sourceforge.net/projects/evocms/}.

   1  <?php
   2  /**
   3   * This file is part of b2evolution - {@link http://b2evolution.net/}
   4   * See also {@link http://sourceforge.net/projects/evocms/}.
   5   *
   6   * @copyright (c)2009-2014 by Francois PLANQUE - {@link http://fplanque.net/}
   7   * Parts of this file are copyright (c)2009 by The Evo Factory - {@link http://www.evofactory.com/}.
   8   *
   9   * Released under GNU GPL License - {@link http://b2evolution.net/about/license.html}
  10   *
  11   * {@internal Open Source relicensing agreement:
  12   * The Evo Factory grants Francois PLANQUE the right to license
  13   * The Evo Factory's contributions to this file and the b2evolution project
  14   * under any OSI approved OSS license (http://www.opensource.org/licenses/).
  15   * }}
  16   *
  17   * @package messaging
  18   *
  19   * {@internal Below is a list of authors who have contributed to design/coding of this file: }}
  20   * @author efy-maxim: Evo Factory / Maxim.
  21   * @author fplanque: Francois Planque.
  22   *
  23   * @version $Id: _messaging.funcs.php 6136 2014-03-08 07:59:48Z manuel $
  24   */
  25  if( !defined('EVO_MAIN_INIT') ) die( 'Please, do not access this page directly.' );
  26  
  27  
  28  /**
  29   * Load all of the recipients of current thread into the UserCache
  30   *
  31   * @param current thread ID
  32   */
  33  function load_messaging_thread_recipients( $thrd_ID )
  34  {
  35      global $DB;
  36  
  37      $SQL = new SQL();
  38  
  39      $SQL->SELECT( 'u.*' );
  40  
  41      $SQL->FROM( 'T_messaging__threadstatus ts
  42                      INNER JOIN T_users u
  43                          ON ts.tsta_user_ID = u.user_ID' );
  44  
  45      $SQL->WHERE( 'ts.tsta_thread_ID = '.$thrd_ID );
  46  
  47      $UserCache = & get_UserCache();
  48  
  49      foreach( $DB->get_results( $SQL->get() ) as $row )
  50      {
  51          if( !isset($UserCache->cache[$row->user_ID]) )
  52          {
  53              $UserCache->add( new User( $row ) );
  54          }
  55      }
  56  }
  57  
  58  
  59  /**
  60   * Check blocked contacts in recipients list.
  61   * Note: If current User has only reply permission then users who didn't have the current User in their contact list will be considerated as blocked contacts!
  62   *
  63   * @param array recipients list
  64   * @return array blocked contacts
  65   */
  66  function check_blocked_contacts( $recipients_list )
  67  {
  68      global $DB, $current_User;
  69  
  70      if( empty( $recipients_list ) )
  71      { // there are no recipients to check
  72          return NULL;
  73      }
  74  
  75      if( $current_User->check_perm( 'perm_messaging', 'delete' ) )
  76      { // user with delete messaging permission are allowed to send private messages to anyone who has access to read them.
  77          return NULL;
  78      }
  79  
  80      $SQL = new SQL();
  81  
  82      $SQL->SELECT( 'u.user_login' );
  83  
  84      if( $current_User->check_perm( 'perm_messaging', 'write', false ) )
  85      { // get blocked contacts for user with write permission
  86          $sub_SQL = new SQL();
  87  
  88          // Select users who has blocked current_User
  89          $sub_SQL->SELECT( 'mct_from_user_ID as user_ID' );
  90          $sub_SQL->FROM( 'T_messaging__contact' );
  91          $sub_SQL->WHERE( 'mct_to_user_ID = '.$current_User->ID );
  92          $sub_SQL->WHERE_and( 'mct_blocked = 1' );
  93  
  94          // Select users from sub query result
  95          $SQL->FROM( 'T_users u' );
  96          $SQL->WHERE( 'u.user_ID IN ( '.$sub_SQL->get().' )' );
  97      }
  98      else
  99      { // get every user, except non blocked contacts, for users with only reply permission
 100          // This will select users who has blocked current user, and users blocked by current User won't be selected, and this is OK!
 101          $SQL->FROM( 'T_users u
 102                          LEFT OUTER JOIN T_messaging__contact mcu
 103                              ON u.user_ID = mcu.mct_from_user_ID
 104                              AND mcu.mct_to_user_ID = '.$current_User->ID.'
 105                              AND mcu.mct_blocked = 0' );
 106  
 107          $SQL->WHERE( 'u.user_ID <> '.$current_User->ID );
 108          $SQL->WHERE_and( 'mcu.mct_from_user_ID IS NULL' );
 109      }
 110  
 111      // check if recipient list contains blocked contacts, if yes return them
 112      $SQL->WHERE_and( 'u.user_ID IN ('.implode( ',', $recipients_list ).')' );
 113      $SQL->ORDER_BY( 'u.user_login' );
 114  
 115      $blocked_contacts = array();
 116      foreach( $DB->get_results( $SQL->get() ) as $row )
 117      {
 118          $blocked_contacts[] = $row->user_login;
 119      }
 120  
 121      return $blocked_contacts;
 122  }
 123  
 124  
 125  /**
 126   * Block or unblock contact
 127   *
 128   * @param integer contact user id
 129   * @param boolean true to block | false to unblock
 130   * @result mixed 1 on success, 0 if the given user was not in the current user contact list, false on error
 131   */
 132  function set_contact_blocked( $user_ID, $blocked )
 133  {
 134      global $current_User, $DB;
 135  
 136      $sql = 'UPDATE T_messaging__contact
 137                  SET mct_blocked = '.$blocked.'
 138                      WHERE mct_from_user_ID = '.$current_User->ID.'
 139                      AND mct_to_user_ID = '.$user_ID;
 140  
 141      return $DB->query( $sql );
 142  }
 143  
 144  
 145  /**
 146   * Create new messaging thread from request
 147   *
 148   * @return boolean true on success
 149   */
 150  function create_new_thread()
 151  {
 152      global $Settings, $current_User, $Messages, $edited_Thread, $edited_Message;
 153  
 154      // Insert new thread:
 155      $edited_Thread = new Thread();
 156      $edited_Message = new Message();
 157      $edited_Message->Thread = & $edited_Thread;
 158  
 159      // Check permission:
 160      $current_User->check_perm( 'perm_messaging', 'reply', true );
 161  
 162      if( $Settings->get('system_lock') )
 163      { // System is locked for maintenance, All users cannot send a message
 164          $Messages->add( T_('You cannot send a message at this time because the system is under maintenance. Please try again in a few moments.'), 'error' );
 165          return false;
 166      }
 167  
 168      param( 'thrd_recipients', 'string' );
 169      param( 'thrd_recipients_array', 'array' );
 170  
 171      // Load data from request
 172      if( $edited_Message->load_from_Request() )
 173      { // We could load data from form without errors:
 174          // Insert in DB:
 175          if( param( 'thrdtype', 'string', 'discussion' ) == 'discussion' )
 176          {
 177              $edited_Message->dbinsert_discussion();
 178              // update author user last new thread setting
 179              update_todays_thread_settings( 1 );
 180          }
 181          else
 182          {
 183              $edited_Message->dbinsert_individual();
 184              // update author user last new thread setting
 185              if( empty( $edited_Thread->recipients_list ) )
 186              {
 187                  $edited_Thread->load_recipients();
 188              }
 189              update_todays_thread_settings( count( $edited_Thread->recipients_list ) );
 190          }
 191  
 192          $Messages->add( T_('Message sent.'), 'success' );
 193  
 194          return true;
 195      }
 196      return false;
 197  }
 198  
 199  
 200  /**
 201   * Create a new message from request in the given thread
 202   *
 203   * @param integer thread ID
 204   * @return boolean true on success
 205   */
 206  function create_new_message( $thrd_ID )
 207  {
 208      global $Settings, $current_User, $Messages, $edited_Message;
 209  
 210      // Insert new message:
 211      $edited_Message = new Message();
 212      $edited_Message->thread_ID = $thrd_ID;
 213  
 214      // Check permission:
 215      $current_User->check_perm( 'perm_messaging', 'reply', true );
 216  
 217      if( $Settings->get('system_lock') )
 218      { // System is locked for maintenance, All users cannot send a message
 219          $Messages->add( T_('You cannot send a message at this time because the system is under maintenance. Please try again in a few moments.'), 'error' );
 220          return false;
 221      }
 222  
 223      // Load data from request
 224      if( $edited_Message->load_from_Request() )
 225      { // We could load data from form without errors:
 226          // Insert in DB:
 227          $edited_Message->dbinsert_message();
 228          $Messages->add( T_('Message sent.'), 'success' );
 229  
 230          return true;
 231      }
 232  
 233      return false;
 234  }
 235  
 236  
 237  /**
 238   * User leave a thread
 239   *
 240   * @param integer thread ID
 241   * @param integer user ID
 242   * @param boolean set true to close the thread, which means no one can reply, leave false if thread must remain open
 243   * @return mixed number 1 on success, false otherwise
 244   */
 245  function leave_thread( $thread_ID, $user_ID, $close_thread = false )
 246  {
 247      global $DB;
 248  
 249      $ThreadCache = & get_ThreadCache();
 250      $edited_Thread = & $ThreadCache->get_by_ID( $thread_ID );
 251  
 252      if( !$edited_Thread->check_thread_recipient( $user_ID ) )
 253      { // user is not between the thread recipients
 254          debug_die( 'Invalid request, current User is not recipient of the selected thread!' );
 255      }
 256  
 257      // create subquery to select the last message ID in this thread. This will be the last visible message for the user from this thread.
 258      $msg_subquery = 'SELECT msg_ID FROM T_messaging__message
 259                          WHERE msg_thread_ID = '.$DB->quote( $thread_ID ).'
 260                          ORDER BY msg_datetime DESC
 261                          LIMIT 1';
 262      // set last visible thread ID query
 263      $query = 'UPDATE T_messaging__threadstatus
 264              SET tsta_thread_leave_msg_ID = ( '.$msg_subquery.' )
 265          WHERE tsta_thread_ID = '.$DB->quote( $thread_ID ).'
 266              AND tsta_thread_leave_msg_ID IS NULL';
 267      if( ! $close_thread )
 268      { // don't close the thread for all user only the given user wants to leave
 269          $query .= ' AND tsta_user_ID = '.$DB->quote( $user_ID );
 270      }
 271  
 272      return $DB->query( $query );
 273  }
 274  
 275  
 276  /**
 277   * Get messaging menu urls
 278   *
 279   * @param string specific sub entry url, possible values: 'threads', 'contacts', 'messages'
 280   */
 281  function get_messaging_url( $disp = 'threads' )
 282  {
 283      global $admin_url, $is_admin_page, $Blog;
 284      if( $is_admin_page || empty( $Blog ) )
 285      {
 286          return $admin_url.'?ctrl='.$disp;
 287      }
 288      return url_add_param( $Blog->gen_blogurl(), 'disp='.$disp );
 289  }
 290  
 291  
 292  /**
 293   * Get messaging urls for the messaging notification emails
 294   *
 295   * @param integer thread ID the corresponding thread ID to display messages, and null to display all threads
 296   * @return array( threads/messages url, messaging preferences url )
 297   */
 298  function get_messages_link_to( $thread_ID = NULL )
 299  {
 300      global $Settings, $admin_url;
 301  
 302      if( empty( $thread_ID ) )
 303      {
 304          $link_tail = 'threads';
 305      }
 306      else
 307      {
 308          $link_tail = 'messages&thrd_ID='.$thread_ID;
 309      }
 310      $messages_link_to = $Settings->get( 'messages_link_to' );
 311      if( $messages_link_to != 'admin' )
 312      {
 313          $BlogCache = & get_BlogCache();
 314          /*
 315           * @var Blog
 316           */
 317          $link_to_Blog = $BlogCache->get_by_ID( $messages_link_to, false, false );
 318          if( $link_to_Blog )
 319          {
 320              $message_link = url_add_param( $link_to_Blog->gen_blogurl(), 'disp='.$link_tail );
 321              $prefs_link =  url_add_param( $link_to_Blog->gen_blogurl(), 'disp=userprefs' );
 322              return array( $message_link, $prefs_link );
 323          }
 324      }
 325  
 326      // link to admin
 327      $message_link = $admin_url.'?ctrl='.$link_tail;
 328      $prefs_link = $admin_url.'?ctrl=user&user_tab=userprefs';
 329  
 330      return array( $message_link, $prefs_link );
 331  }
 332  
 333  
 334  /**
 335   * Get messaging menu sub entries
 336   *
 337   * @param boolean true to get admin interface messaging sub menu entries, false to get front office messaging sub menu entries
 338   * @param integer owner user ID
 339   * @return array user sub entries
 340   */
 341  function get_messaging_sub_entries( $is_admin )
 342  {
 343      global $Blog, $current_User;
 344  
 345      if( $is_admin )
 346      {
 347          $url = '?ctrl=';
 348      }
 349      else
 350      {
 351          $url = url_add_param( $Blog->gen_blogurl(), 'disp=' );
 352      }
 353  
 354      $messaging_sub_entries = array(
 355                                  'threads' => array(
 356                                      'text' => T_('Messages'),
 357                                      'href' => $url.'threads' ),
 358                                  'contacts' => array(
 359                                      'text' => T_('Contacts'),
 360                                      'href' => $url.'contacts' ),
 361                              );
 362  
 363      if( $is_admin && $current_User->check_perm( 'options', 'edit' ) )
 364      {
 365          $messaging_sub_entries[ 'msgsettings' ] = array(
 366                                                      'text' => T_('Settings'),
 367                                                      'href' => $url.'msgsettings'
 368                                                  );
 369      }
 370      if( $current_User->check_perm( 'perm_messaging', 'abuse' ) )
 371      {
 372          $messaging_sub_entries[ 'abuse' ] = array(
 373                                                      'text' => T_('Abuse Management'),
 374                                                      'href' => $url.'abuse'
 375                                                  );
 376      }
 377  
 378      return $messaging_sub_entries;
 379  }
 380  
 381  
 382  /**
 383   * Save message form params into the current Session
 384   *
 385   * @param Array message form params
 386   */
 387  function save_message_params_to_session( $unsaved_message_Array )
 388  {
 389      global $Session;
 390      $Session->set( 'core.unsaved_message_Array', $unsaved_message_Array );
 391  }
 392  
 393  
 394  /**
 395   * Get message form params from the current Session
 396   *
 397   * @return Array|NULL message form params array if Session core.unsaved_message_Array is set, NULL otherwise
 398   */
 399  function get_message_params_from_session()
 400  {
 401      global $Session;
 402      if( ( $unsaved_message_Array = $Session->get( 'core.unsaved_message_Array' ) ) && is_array( $unsaved_message_Array ) )
 403      {
 404          $Session->delete( 'core.unsaved_message_Array' );
 405          return $unsaved_message_Array;
 406      }
 407      return NULL;
 408  }
 409  
 410  
 411  /**
 412   * Get threads recipients SQL
 413   *
 414   * @param integer Thread ID
 415   * @return SQL object
 416   */
 417  function get_threads_recipients_sql( $thread_ID = 0 )
 418  {
 419      global $perm_abuse_management, $current_User;
 420  
 421      $read_user_sql_limit = '';
 422      $unread_user_sql_limit = '';
 423      $left_user_sql_limit = '';
 424      if( ! $perm_abuse_management )
 425      {    // Non abuse management
 426          $read_user_sql_limit = ' AND ur.user_ID <> '.$current_User->ID;
 427          $unread_user_sql_limit = ' AND uu.user_ID <> '.$current_User->ID;
 428          $left_user_sql_limit = ' AND ul.user_ID <> '.$current_User->ID;
 429      }
 430  
 431      $recipients_SQL = new SQL();
 432  
 433      $recipients_SQL->SELECT( 'ts.tsta_thread_ID AS thr_ID,
 434                                  GROUP_CONCAT(DISTINCT ur.user_login ORDER BY ur.user_login SEPARATOR \', \') AS thr_read,
 435                                  GROUP_CONCAT(DISTINCT uu.user_login ORDER BY uu.user_login SEPARATOR \', \') AS thr_unread,
 436                                  GROUP_CONCAT(DISTINCT ul.user_login ORDER BY ul.user_login SEPARATOR \', \') AS thr_left' );
 437  
 438      $recipients_SQL->FROM( 'T_messaging__threadstatus ts
 439                                  LEFT OUTER JOIN T_messaging__threadstatus tsr
 440                                      ON ts.tsta_thread_ID = tsr.tsta_thread_ID AND tsr.tsta_first_unread_msg_ID IS NULL
 441                                          AND tsr.tsta_thread_leave_msg_ID IS NULL
 442                                  LEFT OUTER JOIN T_users ur
 443                                      ON tsr.tsta_user_ID = ur.user_ID'.$read_user_sql_limit.'
 444                                  LEFT OUTER JOIN T_messaging__threadstatus tsu
 445                                      ON ts.tsta_thread_ID = tsu.tsta_thread_ID AND tsu.tsta_first_unread_msg_ID IS NOT NULL
 446                                          AND tsu.tsta_thread_leave_msg_ID IS NULL
 447                                  LEFT OUTER JOIN T_users uu
 448                                      ON tsu.tsta_user_ID = uu.user_ID'.$unread_user_sql_limit.'
 449                                  LEFT OUTER JOIN T_messaging__threadstatus tsl
 450                                      ON ts.tsta_thread_ID = tsl.tsta_thread_ID AND tsl.tsta_thread_leave_msg_ID IS NOT NULL
 451                                  LEFT OUTER JOIN T_users ul
 452                                      ON tsl.tsta_user_ID = ul.user_ID'.$left_user_sql_limit );
 453  
 454      if( $thread_ID > 0 )
 455      {    // Limit with thread ID
 456          $recipients_SQL->WHERE( 'ts.tsta_thread_ID = '.$thread_ID );
 457      }
 458  
 459      if( ! $perm_abuse_management )
 460      {    // Get a messages only of current user
 461          $recipients_SQL->WHERE_and( 'ts.tsta_user_ID ='.$current_User->ID );
 462      }
 463  
 464      $recipients_SQL->GROUP_BY( 'ts.tsta_thread_ID' );
 465  
 466      return $recipients_SQL;
 467  }
 468  
 469  
 470  /**
 471   * Get all those user threads and their recipients where the corresponding users have unread messages.
 472   * This function is used for the different email notifications.
 473   *
 474   * @param array required user id list
 475   * @param integer a thread ID that should be skipped from the result list. Leave it to NULL if you don't want to skip any thread.
 476   * @param string Threads format ( string | array )
 477   * @param string User logins format ( text | html )
 478   * @return array ( user_ID -> (string or array) ) pairs, the string contains the users unread threads titles and their recipients list
 479   */
 480  function get_users_unread_threads( $userid_list, $skip_thread_ID = NULL, $threads_format = 'string', $login_format = 'text' )
 481  {
 482      global $DB;
 483      $result = array();
 484  
 485      if( empty( $userid_list ) )
 486      { // requested user id list is empty, return empty result
 487          return $result;
 488      }
 489  
 490      // Get all those user threads where the corresponding user has unread messages, and sort descending by last modifiaction date
 491      $query = 'SELECT DISTINCT tsta_user_ID, GROUP_CONCAT( CONVERT( thrd_ID, CHAR(10) ) ORDER BY thrd_datemodified DESC SEPARATOR "," ) as threads
 492              FROM T_messaging__threadstatus
 493              LEFT JOIN T_messaging__thread ON thrd_ID = tsta_thread_ID
 494              WHERE tsta_first_unread_msg_ID IS NOT NULL AND tsta_user_ID IN ( '.implode( ',', $userid_list ).')
 495              GROUP BY tsta_user_ID';
 496      $user_unread_threads = $DB->get_assoc( $query, 'Get all threads where the corresponding users have unread messages' );
 497  
 498      if( empty( $user_unread_threads ) )
 499      { // requested users have no unread threads
 500          return $result;
 501      }
 502  
 503      $all_involved_threads = array();
 504      $user_threads = array();
 505      // create an all involved threads array
 506      foreach( $user_unread_threads as $key => $threads )
 507      {
 508          $user_threads[ $key ] = explode( ',', $threads );
 509          $all_involved_threads = array_merge( $all_involved_threads, $user_threads[ $key ] );
 510      }
 511      $all_involved_threads = array_unique( $all_involved_threads );
 512  
 513      // Get all required threads recipients and titles
 514      $recipients_query = 'SELECT tsta_thread_ID as thread_ID, thrd_title, user_login
 515              FROM T_messaging__threadstatus
 516              LEFT JOIN T_users ON user_ID = tsta_user_ID
 517              LEFT JOIN T_messaging__thread ON thrd_ID = tsta_thread_ID
 518                  WHERE tsta_thread_ID IN ( '.implode( ',', $all_involved_threads ).' )';
 519      $all_threads_recipients = $DB->get_results( $recipients_query, OBJECT, 'Load all required threads title and recipients' );
 520      $thread_recipients = array();
 521      $thread_titles = array();
 522      foreach( $all_threads_recipients as $row )
 523      {
 524          if( !isset( $thread_recipients[ $row->thread_ID ] ) )
 525          {
 526              $thread_recipients[ $row->thread_ID ] = array();
 527          }
 528          if( empty( $row->user_login ) )
 529          { // User was deleted
 530              $thread_recipients[$row->thread_ID][] = 'Deleted user';
 531          }
 532          else
 533          { // User exists
 534              if( $login_format == 'text' )
 535              { // Use simple login as text
 536                  $thread_recipients[$row->thread_ID][] = $row->user_login;
 537              }
 538              else // 'html'
 539              { // Use a colored login with avatar
 540                  $thread_recipients[$row->thread_ID][] = get_user_colored_login( $row->user_login );
 541              }
 542          }
 543          if( !isset( $thread_titles[ $row->thread_ID ] ) )
 544          {
 545              $thread_titles[ $row->thread_ID ] = $row->thrd_title;
 546          }
 547      }
 548  
 549      foreach( $userid_list as $user_ID )
 550      {
 551          if( !isset( $user_threads[ $user_ID ] ) )
 552          {
 553              $result[ $user_ID ] = NULL;
 554              continue;
 555          }
 556          $threads = $user_threads[ $user_ID ];
 557          $unread_threads = $threads_format == 'string' ? '' : array();
 558          // List all unread threads, starting with the most recent updated threads,
 559          // so that each new reminder looks as different as possible from the one from 72 hours before
 560          foreach( $threads as $thread_ID )
 561          {
 562              if( $skip_thread_ID == $thread_ID )
 563              {
 564                  continue;
 565              }
 566              $recipient_names = implode( ', ', $thread_recipients[ $thread_ID ] );
 567              if( $threads_format == 'string' )
 568              {    // Store all threads in one string
 569                  $unread_threads .= "\t - ".sprintf( '"%s" ( %s )', $thread_titles[ $thread_ID ], $recipient_names )."\n";
 570              }
 571              else
 572              {    // Store all threads in array
 573                  $unread_threads[] = sprintf( '"%s" ( %s )', $thread_titles[ $thread_ID ], $recipient_names );
 574              }
 575          }
 576          $result[$user_ID] = $unread_threads;
 577      }
 578  
 579      return $result;
 580  }
 581  
 582  
 583  /**
 584   * Get threads SQL
 585   *
 586   * @param array Params
 587   * @return Results object
 588   */
 589  function get_threads_results( $params = array() )
 590  {
 591      global $perm_abuse_management, $current_User, $DB;
 592  
 593      // Make sure we are not missing any param:
 594      $params = array_merge( array(
 595              'results_param_prefix' => 'thrd_', // Param prefix for results list
 596              'user_ID' => $current_User->ID,    // To limit messages only by this user's ID
 597              'sent_user_ID' => '',              // To limit messages only for sent by given user ID
 598              'search_word' => '',               // Filter by this keyword
 599              'search_user' => '',               // Filter by this user name
 600              'show_closed_threads' => NULL,     // Show closed conversations
 601              'only_sql' => false,               // TRUE - to return only SQL object, FALSE - Results object
 602          ), $params );
 603  
 604  
 605      $filter_sql = '';
 606      if( !empty( $params['search_word'] ) || !empty( $params['search_user'] ) || !empty( $params['sent_user_ID'] ) )
 607      {    // We want to filter on search keyword:
 608          $filter_sql = array();
 609          if( !empty( $params['search_word'] ) )
 610          { // Search by title
 611              $filter_sql[] = 'thrd_title LIKE "%'.$DB->escape( $params['search_word'] ).'%"';
 612          }
 613          if( !empty( $params['search_user'] ) )
 614          { // Search by user names
 615  
 616              // Get all threads IDs with searching user name
 617              $threads_SQL = new SQL();
 618              $threads_SQL->SELECT( 'tsta_thread_ID' );
 619              $threads_SQL->FROM( 'T_users' );
 620              $threads_SQL->FROM_add( 'INNER JOIN T_messaging__threadstatus ON tsta_user_ID = user_ID' );
 621              $threads_SQL->WHERE( 'user_login LIKE "%'.$DB->escape( $params['search_user'] ).'%"' );
 622              $threads_SQL->WHERE_or( 'user_firstname LIKE "%'.$DB->escape( $params['search_user'] ).'%"' );
 623              $threads_SQL->WHERE_or( 'user_lastname LIKE "%'.$DB->escape( $params['search_user'] ).'%"' );
 624              $threads_SQL->WHERE_or( 'user_nickname LIKE "%'.$DB->escape( $params['search_user'] ).'%"' );
 625              $threads_IDs = $DB->get_col( $threads_SQL->get() );
 626  
 627              if( empty( $threads_IDs ) )
 628              {    // No found related threads
 629                  $threads_IDs[] = '-1';
 630              }
 631  
 632              $filter_sql[] = 'tsta_thread_ID IN ( '.implode( ',', $threads_IDs ).' )';
 633          }
 634          if( !empty( $params[ 'sent_user_ID' ] ) )
 635          {
 636              // Get all threads IDs with searching user name
 637              $threads_SQL = new SQL();
 638              $threads_SQL->SELECT( 'DISTINCT( msg_thread_ID )' );
 639              $threads_SQL->FROM( 'T_messaging__message' );
 640              $threads_SQL->WHERE( 'msg_author_user_ID = '.$DB->quote( $params[ 'sent_user_ID' ] ) );
 641              $threads_IDs = $DB->get_col( $threads_SQL->get() );
 642  
 643              if( empty( $threads_IDs ) )
 644              {    // No found related threads
 645                  $threads_IDs[] = '-1';
 646              }
 647  
 648              $filter_sql[] = 'tsta_thread_ID IN ( '.implode( ',', $threads_IDs ).' )';
 649          }
 650          $filter_sql = ( count( $filter_sql ) > 0 ) ? implode( ' OR ', $filter_sql) : '';
 651      }
 652  
 653      $thrd_msg_ID = $perm_abuse_management ? '"abuse"' : 'tsta_first_unread_msg_ID';
 654  
 655      // Create SELECT SQL query
 656      $select_SQL = new SQL();
 657      $select_SQL->SELECT( 'thrd_ID, thrd_title, thrd_datemodified, '.$thrd_msg_ID.' AS thrd_msg_ID, tsta_thread_leave_msg_ID, msg_datetime AS thrd_unread_since' );
 658      $select_SQL->FROM( 'T_messaging__threadstatus' );
 659      $select_SQL->FROM_add( 'INNER JOIN T_messaging__thread ON tsta_thread_ID = thrd_ID' );
 660      $select_SQL->FROM_add( 'LEFT OUTER JOIN T_messaging__message ON tsta_first_unread_msg_ID = msg_ID' );
 661      if( ! $perm_abuse_management )
 662      { // Limit threads by current user
 663          $select_SQL->WHERE( 'tsta_user_ID = '.$params['user_ID'] );
 664          if( $params['show_closed_threads'] === NULL )
 665          { // Explicit param value was not set, use the default
 666              // Show closed messages by default only if there are unread messages in closed conversations
 667              $params['show_closed_threads'] = $DB->get_var(
 668                  'SELECT COUNT( tsta_thread_ID )
 669                      FROM T_messaging__threadstatus
 670                      WHERE tsta_thread_leave_msg_ID IS NOT NULL AND tsta_first_unread_msg_ID IS NOT NULL
 671                      AND tsta_first_unread_msg_ID <= tsta_thread_leave_msg_ID AND tsta_user_ID = '.$params['user_ID']
 672              );
 673              // Set 'show_closed' param value, so the checkobx filter can be displayed correctly
 674              set_param( 'show_closed', $params['show_closed_threads'] ? true : false );
 675          }
 676          if( ! $params['show_closed_threads'] )
 677          { // Don't show the closed conversations
 678              $select_SQL->WHERE_and( '( tsta_thread_leave_msg_ID IS NULL )' );
 679          }
 680      }
 681      if( !empty( $filter_sql ) )
 682      {    // Filter
 683          $select_SQL->WHERE_and( $filter_sql );
 684      }
 685      $select_SQL->ORDER_BY( 'tsta_first_unread_msg_ID DESC, thrd_datemodified DESC' );
 686      if( $perm_abuse_management )
 687      {
 688          $select_SQL->GROUP_BY( 'tsta_thread_ID' );
 689      }
 690  
 691      // Create COUNT SQL query
 692      $count_SQL = new SQL();
 693      $count_SQL->SELECT( 'COUNT( DISTINCT tsta_thread_ID )' );
 694      $count_SQL->FROM( 'T_messaging__threadstatus' );
 695      if( ! empty( $filter_sql ) )
 696      { // Filter
 697          $count_SQL->FROM_add( 'INNER JOIN T_messaging__thread ON tsta_thread_ID = thrd_ID' );
 698      }
 699      if( ! $perm_abuse_management )
 700      { // Limit threads by current user
 701          $count_SQL->WHERE( 'tsta_user_ID = '.$params['user_ID'] );
 702          if( ! $params['show_closed_threads'] )
 703          { // Don't show the closed conversations
 704              $count_SQL->WHERE_and( '( tsta_thread_leave_msg_ID IS NULL )' );
 705          }
 706      }
 707      if( !empty( $filter_sql ) )
 708      { // Filter
 709          $count_SQL->WHERE_and( $filter_sql );
 710      }
 711  
 712      if( $params['only_sql'] )
 713      { // Return only SQL object
 714          return $select_SQL;
 715      }
 716  
 717      // Create result set:
 718      $Results = new Results( $select_SQL->get(), $params['results_param_prefix'], '', NULL, $count_SQL->get() );
 719  
 720      return $Results;
 721  }
 722  
 723  
 724  /**
 725   * Insert user to contacts
 726   *
 727   * @param integer User ID
 728   * @param boolean set true to add as a blocked contact
 729   * @return true if success, else false
 730   */
 731  function create_contacts_user( $user_ID, $blocked = false )
 732  {
 733      global $DB, $current_User, $localtimenow;
 734  
 735      $contact = check_contact( $user_ID );
 736      if( !is_null( $contact ) )
 737      { // This user already exists in the contact list for current user
 738          return true;
 739      }
 740  
 741      $datetime = date( 'Y-m-d H:i:s', $localtimenow );
 742      $blocked = $blocked ? 1 : 0;
 743  
 744      $sql = 'INSERT INTO T_messaging__contact
 745                 ( mct_from_user_ID, mct_to_user_ID, mct_blocked, mct_last_contact_datetime )
 746          VALUES ( '.$current_User->ID.', '.$user_ID.', '.$blocked.', '.$DB->quote( $datetime ).' )';
 747  
 748      return $DB->query( $sql, 'Insert contacts' );
 749  }
 750  
 751  
 752  /**
 753   * Insert contacts group into database
 754   *
 755   * @param string Group name
 756   * @return integer Group ID if success, else false
 757   */
 758  function create_contacts_group( $group_name )
 759  {
 760      global $DB, $current_User, $Messages;
 761  
 762      if( $group_name != '' )
 763      {    // Check new group name for duplicates
 764          $SQL = new SQL();
 765          $SQL->SELECT( 'cgr_ID' );
 766          $SQL->FROM( 'T_messaging__contact_groups' );
 767          $SQL->WHERE( 'cgr_user_ID = '.$current_User->ID );
 768          $SQL->WHERE_and( 'cgr_name = '.$DB->quote( $group_name ) );
 769  
 770          $group = $DB->get_var( $SQL->get() );
 771          if( !is_null( $group ) )
 772          {    // Duplicate group
 773              $Messages->add( T_('You already have a group with this name.'), 'error' );
 774          }
 775      }
 776  
 777      if( param_errors_detected() )
 778      {    // Errors exist, Exit here
 779          return false;
 780      }
 781  
 782      $sql = 'INSERT INTO T_messaging__contact_groups
 783                   ( cgr_user_ID, cgr_name )
 784          VALUES ( '.$current_User->ID.', '.$DB->quote( $group_name ).' )';
 785  
 786      if( $DB->query( $sql, 'Insert contacts group' ) )
 787      {    // Success query, Return ID of new group
 788          return $DB->insert_id;
 789      }
 790      else
 791      {    // Failed query
 792          return false;
 793      }
 794  }
 795  
 796  
 797  /**
 798   * Rename contacts group
 799   *
 800   * @param integer Group ID
 801   * @param string Name of input with new group name
 802   * @return boolean TRUE if group was renamed successfully
 803   */
 804  function rename_contacts_group( $group_ID, $field_name = 'name' )
 805  {
 806      global $DB, $current_User, $Messages;
 807  
 808      $name = param( $field_name, 'string', '' );
 809      param_check_not_empty( $field_name, T_('Please enter group name') );
 810  
 811      // Check if user is owner of this group
 812      $SQL = new SQL();
 813      $SQL->SELECT( 'cgr_ID' );
 814      $SQL->FROM( 'T_messaging__contact_groups' );
 815      $SQL->WHERE( 'cgr_user_ID = '.$current_User->ID );
 816      $SQL->WHERE_and( 'cgr_ID = '.$DB->quote( $group_ID ) );
 817  
 818      if( $DB->get_var( $SQL->get() ) == NULL )
 819      {
 820          $Messages->add( 'You don\'t have this group', 'error' );
 821          return false;
 822      }
 823  
 824      // Rename a group
 825      $sql = 'UPDATE T_messaging__contact_groups
 826            SET cgr_name = '.$DB->quote( $name ).'
 827          WHERE cgr_ID = '.$DB->quote( $group_ID ).'
 828            AND cgr_user_ID = '.$current_User->ID;
 829  
 830      $DB->query( $sql, 'Rename contacts group' );
 831  
 832      return true;
 833  }
 834  
 835  
 836  /**
 837   * Delete contacts group
 838   *
 839   * @param integer Group ID
 840   * @return boolean TRUE if group was renamed successfully
 841   */
 842  function delete_contacts_group( $group_ID )
 843  {
 844      global $DB, $current_User, $Messages;
 845  
 846      // Check if user is owner of this group
 847      $SQL = new SQL();
 848      $SQL->SELECT( 'cgr_ID' );
 849      $SQL->FROM( 'T_messaging__contact_groups' );
 850      $SQL->WHERE( 'cgr_user_ID = '.$current_User->ID );
 851      $SQL->WHERE_and( 'cgr_ID = '.$DB->quote( $group_ID ) );
 852  
 853      if( $DB->get_var( $SQL->get() ) == NULL )
 854      {
 855          $Messages->add( 'You don\'t have this group', 'error' );
 856          return false;
 857      }
 858  
 859      // Delete a group
 860      $sql_groups = 'DELETE FROM T_messaging__contact_groups
 861          WHERE cgr_ID = '.$DB->quote( $group_ID ).'
 862            AND cgr_user_ID = '.$current_User->ID;
 863      $DB->query( $sql_groups, 'Delete contacts group' );
 864  
 865      // Delete users from this group
 866      $sql_users = 'DELETE FROM T_messaging__contact_groupusers
 867          WHERE cgu_cgr_ID = '.$DB->quote( $group_ID );
 868      $DB->query( $sql_users, 'Delete users from contacts group' );
 869  
 870      return true;
 871  }
 872  
 873  
 874  /**
 875   * Insert users for contacts group into database
 876   *
 877   * @param integer/string Group ID or 'new'
 878   * @param string Users IDs separated with comma
 879   * @param string Name of input element with new group name
 880   * @return array/boolean Array( 'count_users', 'group_name' ) if success, else false
 881   */
 882  function create_contacts_group_users( $group, $users, $new_group_field_name = 'group_combo' )
 883  {
 884      global $DB, $current_User, $Messages;
 885  
 886      $users_IDs = explode( ',', $users );
 887      if( count( $users_IDs ) == 0 || strlen( $users ) == 0 )
 888      {    // No selected users
 889          $Messages->add( T_('Please select at least one user.'), 'error' );
 890          return false;
 891      }
 892  
 893      if( $group == 'new' || (int)$group < 0 )
 894      {    // Add new group
 895          if( (int)$group < 0 )
 896          {    // Default group
 897              $default_groups = get_contacts_groups_default();
 898              if( isset( $default_groups[$group] ) )
 899              {    // Get group name
 900                  $group_name = $default_groups[$group];
 901              }
 902              else
 903              {    // Error
 904                  $Messages->add( 'No found this group.', 'error' );
 905                  return false;
 906              }
 907          }
 908          else
 909          {    // New entered group
 910              $group_name = param( $new_group_field_name, 'string', true );
 911              param_check_not_empty( $new_group_field_name, T_('Please enter name for new group.') );
 912          }
 913  
 914          if( $group_ID = create_contacts_group( $group_name ) )
 915          {    // Create group
 916              $Messages->add( T_('New contacts group has been created.'), 'success' );
 917          }
 918          else
 919          {    // Errors
 920              return false;
 921          }
 922      }
 923      else
 924      {    // Existing group
 925          $group_ID = (int)$group;
 926  
 927          if( $group_ID == 0 )
 928          {    // No defined group ID
 929              return false;
 930          }
 931  
 932          $SQL = new SQL();
 933          $SQL->SELECT( 'cgr_name AS name' );
 934          $SQL->FROM( 'T_messaging__contact_groups' );
 935          $SQL->WHERE( 'cgr_user_ID = '.$current_User->ID );
 936          $SQL->WHERE_and( 'cgr_ID = '.$DB->quote( $group_ID ) );
 937  
 938          $group = $DB->get_row( $SQL->get() );
 939          if( is_null( $group ) )
 940          {    // User try use a group of another user
 941              return false;
 942          }
 943          $group_name = $group->name;
 944      }
 945  
 946      // Get all Users IDs of selected group in order to exclude duplicates
 947      $SQL = new SQL();
 948      $SQL->SELECT( 'cgu_user_ID, cgu_cgr_ID' );
 949      $SQL->FROM( 'T_messaging__contact_groupusers' );
 950      $SQL->WHERE_and( 'cgu_cgr_ID = '.$DB->quote( $group_ID ) );
 951      $users_already_grouped = $DB->get_assoc( $SQL->get() );
 952  
 953      $sql = 'INSERT INTO T_messaging__contact_groupusers ( cgu_user_ID, cgu_cgr_ID ) VALUES ';
 954  
 955      $records = array();
 956      foreach( $users_IDs as $user_ID )
 957      {
 958          $user_ID = (int)trim( $user_ID );
 959          if( $user_ID == 0 )
 960          {    // User ID is empty
 961              continue;
 962          }
 963          else if( isset( $users_already_grouped[$user_ID] ) )
 964          {
 965              if( $users_already_grouped[$user_ID] == $group_ID )
 966              {    // This user already is added in selected group
 967                  continue;
 968              }
 969          }
 970          $records[] = '( '.$user_ID.', '.$DB->quote( $group_ID ).' )';
 971      }
 972      $sql .= implode( ', ', $records );
 973  
 974      if( count( $records ) == 0 )
 975      {    // No data to add
 976          return false;
 977      }
 978  
 979      if( $DB->query( $sql, 'Insert users for contacts group' ) )
 980      {    // Success query
 981          return array(
 982              'count_users' => count( $records ),
 983              'group_name'  => $group_name );
 984      }
 985      else
 986      {    // Failed query
 987          return false;
 988      }
 989  }
 990  
 991  
 992  /**
 993   * Remove user from contacts group
 994   *
 995   * @param integer/string Group ID or 'new'
 996   * @param string Users IDs separated with comma
 997   * @param string Name of input element with new group name
 998   * @return boolean true if success
 999   */
1000  function remove_contacts_group_user( $group_ID, $user_ID )
1001  {
1002      global $DB, $current_User, $Messages;
1003  
1004      $SQL = new SQL();
1005      $SQL->SELECT( 'cgr_name AS name' );
1006      $SQL->FROM( 'T_messaging__contact_groups' );
1007      $SQL->FROM_add( 'LEFT JOIN T_messaging__contact_groupusers ON cgr_ID = cgu_cgr_ID' );
1008      $SQL->WHERE( 'cgr_user_ID = '.$current_User->ID );
1009      $SQL->WHERE_and( 'cgu_user_ID = '.$DB->quote( $user_ID ) );
1010      $SQL->WHERE_and( 'cgu_cgr_ID = '.$DB->quote( $group_ID ) );
1011  
1012      $group = $DB->get_row( $SQL->get() );
1013      if( is_null( $group ) )
1014      {    // User try use a group of another user
1015          return false;
1016      }
1017  
1018      $sql = 'DELETE FROM T_messaging__contact_groupusers
1019          WHERE cgu_user_ID = '.$DB->quote( $user_ID ).'
1020            AND cgu_cgr_ID = '.$DB->quote( $group_ID );
1021  
1022      if( $DB->query( $sql, 'Remove user from contacts group' ) )
1023      {    // Success query
1024          $UserCache = & get_UserCache();
1025          $User = & $UserCache->get_by_ID( $user_ID );
1026  
1027          $Messages->add( sprintf( T_('User &laquo;%s&raquo; has been removed from the &laquo;%s&raquo; group.'), $User->get_preferred_name(), $group->name ), 'success' );
1028          return true;
1029      }
1030      else
1031      {    // Failed query
1032          return false;
1033      }
1034  }
1035  
1036  
1037  /**
1038   * Get default groups for user contacts
1039   *
1040   * @return array Groups
1041   */
1042  function get_contacts_groups_default()
1043  {
1044      $default_groups = array(
1045              '-1' => T_('Close Friends'),
1046              '-2' => T_('Acquaintances'),
1047          );
1048  
1049      return $default_groups;
1050  }
1051  
1052  
1053  /**
1054   * Get tags <option> for contacts groups of current User
1055   *
1056   * @param integer Selected group ID
1057   * @param boolean TRUE if we need in null option, else FALSE
1058   * @return string Tags <option>
1059   */
1060  function get_contacts_groups_options( $selected_group_ID = NULL, $value_null = true )
1061  {
1062      global $DB, $current_User;
1063  
1064      $default_groups = get_contacts_groups_default();
1065      $selected_default_group_name = $default_groups[-1]; // Close Friends
1066  
1067      // Get user groups
1068      $SQL = new SQL();
1069      $SQL->SELECT( 'cgr_ID AS ID, cgr_name AS name' );
1070      $SQL->FROM( 'T_messaging__contact_groups' );
1071      $SQL->WHERE( 'cgr_user_ID = '.$current_User->ID );
1072      $SQL->ORDER_BY( 'cgr_name' );
1073      $user_groups = $DB->get_assoc( $SQL->get() );
1074  
1075      // Merge default and user groups (don't use a function array_merge() because it clears the keys)
1076      $groups = array();
1077      foreach( $default_groups as $group_ID => $group_name )
1078      {
1079          if( !in_array( $group_name, $user_groups ) )
1080          {    // Set this default group If it doesn't exist in DB
1081              $groups[$group_ID] = $group_name;
1082          }
1083      }
1084      foreach( $user_groups as $group_ID => $group_name )
1085      {
1086          $groups[$group_ID] = $group_name;
1087          if( $selected_default_group_name == $group_name )
1088          {    // To know group ID of selected default group
1089              $selected_default_group_ID = $group_ID;
1090          }
1091      }
1092  
1093      if( isset( $selected_default_group_ID ) && $selected_group_ID == -1 )
1094      {    // If default group already exists in DB we should use this group ID
1095          $selected_group_ID = $selected_default_group_ID;
1096      }
1097  
1098      $options = '';
1099  
1100      if( $value_null )
1101      {    // Null option
1102          $options .= '<option value="0">'.T_('All').'</option>'."\n";
1103      }
1104  
1105      foreach( $groups as $group_ID => $group_name )
1106      {
1107          $selected = '';
1108          if( $selected_group_ID == $group_ID )
1109          {    // Group is selected
1110              $selected = ' selected="selected"';
1111          }
1112          $options .= '<option value="'.$group_ID.'"'.$selected.'>'.$group_name.'</option>'."\n";
1113      }
1114  
1115      return $options;
1116  }
1117  
1118  
1119  /**
1120   * Get list with contacts groups of current User
1121   *
1122   * @param integer User ID
1123   * @param array Params
1124   * @return string HTML list
1125   */
1126  function get_contacts_groups_list( $user_ID, $params = array() )
1127  {
1128      global $DB, $current_User, $Blog;
1129  
1130      $params = array_merge( array(
1131              'list_start'  => '<table cellspacing="0" class="user_contacts_groups">',
1132              'col1_header' => '<tr><th class="col1">'.T_('In these groups').'</th>',
1133              'col2_header' => '<th>'.T_('Not in these groups').'</th></tr>',
1134              'col1_start'  => '<tr><td class="col1">',
1135              'col1_end'    => '</td>',
1136              'col2_start'  => '<td>',
1137              'col2_end'    => '</tr>',
1138              'list_end'    => '</table>',
1139          ) );
1140  
1141      $default_groups = get_contacts_groups_default();
1142  
1143      // Get all groups of current User
1144      $SQL = new SQL();
1145      $SQL->SELECT( 'cgr_ID AS ID, cgr_name AS name' );
1146      $SQL->FROM( 'T_messaging__contact_groups' );
1147      $SQL->WHERE( 'cgr_user_ID = '.$current_User->ID );
1148      $SQL->ORDER_BY( 'cgr_name' );
1149      $all_groups = $DB->get_assoc( $SQL->get() );
1150  
1151      // Merge default and user groups (don't use a function array_merge() because it clears the keys)
1152      $groups = array();
1153      foreach( $default_groups as $group_ID => $group_name )
1154      {
1155          if( !in_array( $group_name, $all_groups ) )
1156          {    // Set this default group If it doesn't exist in DB
1157              $groups[$group_ID] = $group_name;
1158          }
1159      }
1160      foreach( $all_groups as $group_ID => $group_name )
1161      {
1162          $groups[$group_ID] = $group_name;
1163      }
1164      $all_groups = $groups;
1165      unset( $groups );
1166  
1167      if( count( $all_groups ) == 0 )
1168      {    // No groups
1169          return;
1170      }
1171  
1172      // Get groups of selected User
1173      $SQL = new SQL();
1174      $SQL->SELECT( 'cgu_cgr_ID, cgu_user_ID' );
1175      $SQL->FROM( 'T_messaging__contact_groupusers' );
1176      $SQL->WHERE( 'cgu_user_ID = '.$user_ID );
1177      $user_groups = $DB->get_assoc( $SQL->get() );
1178  
1179      if( !empty( $Blog ) )
1180      {    // Set url to contacts list
1181          $contacts_url = url_add_param( $Blog->gen_blogurl(), 'disp=contacts' );
1182      }
1183  
1184      $groups_1st = array();
1185      $groups_2nd = array();
1186      foreach( $all_groups as $group_ID => $group_name )
1187      {
1188          if( !empty( $contacts_url ) && $group_ID > 0 )
1189          {    // Set link to contacts list with filtered by current group
1190              $group_link = '<a href="'.url_add_param( $contacts_url, 'g='.$group_ID ).'">'.$group_name.'</a>';
1191          }
1192          else
1193          {    // No link, use name
1194              $group_link = $group_name;
1195          }
1196          if( isset( $user_groups[$group_ID] ) )
1197          {    // User is in this group
1198              $groups_1st[] = '<th><strong>'.$group_link.'</strong></th>'.
1199                      '<td>'.action_icon( T_('Remove from group'), 'move_right', get_dispctrl_url( 'contacts', 'action=remove_user&amp;user_ID='.$user_ID.'&amp;group_ID='.$group_ID.'&amp;'.url_crumb( 'messaging_contacts' ) ) ).'</td>';
1200          }
1201          else
1202          {
1203              $groups_2nd[] = '<td>'.action_icon( T_('Add to group'), 'move_left', get_dispctrl_url( 'contacts', 'action=add_user&amp;user_ID='.$user_ID.'&amp;group_ID='.$group_ID.'&amp;'.url_crumb( 'messaging_contacts' ) ) ).'</td>'.
1204                      '<th>'.$group_link.'</th>';
1205          }
1206      }
1207  
1208      $groups_list = $params['list_start'];
1209  
1210      $groups_list .= $params['col1_header'];
1211      $groups_list .= $params['col2_header'];
1212  
1213      $groups_list .= $params['col1_start'];
1214      if( count( $groups_1st ) >0 )
1215      {
1216          $groups_list .= '<table cellspacing="0"><tr>'.implode( '</tr><tr>', $groups_1st ).'</tr></table>';
1217      }
1218      else
1219      {
1220          $groups_list .= '&nbsp;';
1221      }
1222      $groups_list .= $params['col1_end'];
1223  
1224      $groups_list .= $params['col2_start'];
1225      if( count( $groups_2nd ) >0 )
1226      {
1227          $groups_list .= '<table cellspacing="0"><tr>'.implode( '</tr><tr>', $groups_2nd ).'</tr></table>';
1228      }
1229      else
1230      {
1231          $groups_list .= '&nbsp;';
1232      }
1233      $groups_list .= $params['col2_end'];
1234  
1235      $groups_list .= $params['list_end'];
1236  
1237      return $groups_list;
1238  }
1239  
1240  
1241  /**
1242   * Check contact for current user with selected user
1243   *
1244   * @param integer User ID
1245   * @return mixed NULL if contact was not found, boolean TRUE if contact is not blocked, FALSE otherwise
1246   */
1247  function check_contact( $to_user_ID )
1248  {
1249      global $DB, $current_User;
1250  
1251      $is_blocked = $DB->get_var( 'SELECT mct_blocked
1252           FROM T_messaging__contact
1253          WHERE mct_from_user_ID = '.$current_User->ID.'
1254            AND mct_to_user_ID = '.$to_user_ID );
1255  
1256      if( is_null( $is_blocked ) )
1257      {
1258          return NULL;
1259      }
1260      return !$is_blocked;
1261  }
1262  
1263  
1264  /**
1265   * Update current User last new thread timestamp, and today's new thread count
1266   *
1267   * @param integer how many new thread was just created
1268   */
1269  function update_todays_thread_settings( $new_threads_count )
1270  {
1271      global $current_User, $UserSettings, $servertimenow;
1272  
1273      $last_new_thread_ts = $UserSettings->get( 'last_new_thread',  $current_User->ID );
1274      if( empty( $last_new_thread_ts ) )
1275      { // this is the current User first new thread
1276          $UserSettings->set( 'last_new_thread', $servertimenow, $current_User->ID );
1277          $UserSettings->set( 'new_thread_count', $new_threads_count, $current_User->ID );
1278      }
1279      else
1280      {
1281          $today = date( 'Y-m-d', $servertimenow );
1282          $last_new_thread_date = date( 'Y-m-d', $last_new_thread_ts );
1283          if( $last_new_thread_date < $today )
1284          { // this is the current User first new thread today
1285              $UserSettings->set( 'new_thread_count', $new_threads_count, $current_User->ID );
1286          }
1287          else
1288          { // current User has already created other new threads today
1289              $new_thread_count = $UserSettings->get( 'new_thread_count', $current_User->ID );
1290              $UserSettings->set( 'new_thread_count', $new_thread_count + $new_threads_count, $current_User->ID );
1291          }
1292          // update last new thread timestamp
1293          $UserSettings->set( 'last_new_thread', $servertimenow, $current_User->ID );
1294      }
1295      // update User Settings
1296      $UserSettings->dbupdate();
1297  }
1298  
1299  
1300  /**
1301   * Get current User max new threads settings for today
1302   *
1303   * @return array ( max new threads per day, how many threads has already created today )
1304   */
1305  function get_todays_thread_settings()
1306  {
1307      global $current_User, $UserSettings, $servertimenow;
1308  
1309      $user_Group = & $current_User->get_Group();
1310      $user_GroupSettings = & $user_Group->get_GroupSettings();
1311      $max_new_threads = $user_GroupSettings->get( 'max_new_threads', $user_Group->ID );
1312      if( $max_new_threads === '0' )
1313      { // user limit is 0, user must not be able to create new threads
1314          return array( '0', 0 );
1315      }
1316  
1317      $last_new_thread_ts = $UserSettings->get( 'last_new_thread', $current_User->ID );
1318      if( empty( $last_new_thread_ts ) )
1319      { // user has not created any new threads yet
1320          return array( $max_new_threads, 0 );
1321      }
1322  
1323      $today = date( 'Y-m-d', $servertimenow );
1324      $last_new_thread_date = date( 'Y-m-d', $last_new_thread_ts );
1325      if( $last_new_thread_date < $today )
1326      { // user's last new thread was not created today, it's older
1327          return array( $max_new_threads, 0 );
1328      }
1329  
1330      // User has already created at least one new thread today
1331      $new_thread_count = $UserSettings->get( 'new_thread_count', $current_User->ID );
1332      return array( $max_new_threads, $new_thread_count );
1333  }
1334  
1335  
1336  /**
1337   * Check if current User already reached his 'create new thread' limit for today or not.
1338   * Important: The current User messaging permission is not checked here!
1339   *
1340   * @param boolean true to add a success/error message to $Messages about the current User thread limit, false otherwise
1341   * @return boolean true if current user already reached his limit, false otherwise
1342   */
1343  function check_create_thread_limit( $add_message = false )
1344  {
1345      global $Messages;
1346  
1347      list( $max_new_threads, $new_threads_count ) = get_todays_thread_settings();
1348      if( $max_new_threads === '0' )
1349      { // user new conversation limit is 0
1350          if( $add_message )
1351          {
1352              $Messages->add( T_( 'You are not allowed to start a new conversation, because your limit is 0.' ) );
1353          }
1354          return true;
1355      }
1356  
1357      if( empty( $max_new_threads ) )
1358      { // user has no limit
1359          return false;
1360      }
1361  
1362      if( $max_new_threads > $new_threads_count )
1363      { // user didn't reach his limit yet
1364          if( $add_message )
1365          {
1366              $Messages->add( sprintf( T_( 'You can still start %d new conversations today.' ), $max_new_threads - $new_threads_count ), 'success' );
1367          }
1368          return false;
1369      }
1370  
1371      if( $add_message )
1372      { // user has already reached his limit
1373          $Messages->add( sprintf( T_( 'You have reached the limit of %d new conversations today. You can start new conversations again tomorrow.' ), $max_new_threads ) );
1374      }
1375      return true;
1376  }
1377  
1378  
1379  /**
1380   * Get a count of unread messages for the user
1381   *
1382   * @param integer User ID (0 - current user)
1383   * @return integer A count of unread messages
1384   */
1385  function get_unread_messages_count( $user_ID = 0 )
1386  {
1387      if( empty( $user_ID ) )
1388      {    // Current user
1389          if( !is_logged_in() )
1390          {
1391              return 0;
1392          }
1393          global $current_User;
1394          $user_ID = $current_User->ID;
1395      }
1396  
1397      global $DB;
1398  
1399      $SQL = new SQL();
1400      $SQL->SELECT( 'COUNT(*)' );
1401      $SQL->FROM( 'T_messaging__threadstatus ts' );
1402      $SQL->FROM_add( 'LEFT OUTER JOIN T_messaging__message mu
1403                  ON ts.tsta_first_unread_msg_ID = mu.msg_ID' );
1404      $SQL->FROM_add( 'INNER JOIN T_messaging__message mm
1405                  ON ts.tsta_thread_ID = mm.msg_thread_ID
1406                  AND mm.msg_datetime >= mu.msg_datetime' );
1407      $SQL->WHERE( 'ts.tsta_first_unread_msg_ID IS NOT NULL' );
1408      $SQL->WHERE_and( 'ts.tsta_thread_leave_msg_ID IS NULL OR ts.tsta_first_unread_msg_ID <= tsta_thread_leave_msg_ID' );
1409      $SQL->WHERE_and( 'ts.tsta_user_ID = '.$DB->quote( $user_ID ) );
1410  
1411      return (int) $DB->get_var( $SQL->get() );
1412  }
1413  
1414  
1415  /**
1416   * Get the first ( oldest ) unread message of the user
1417   *
1418   * @param integer user ID
1419   * @return mixed NULL if the user doesn't have unread messages, or the oldest unread message datetime otherwise
1420   */
1421  function get_first_unread_message_date( $user_ID )
1422  {
1423      if( empty( $user_ID ) )
1424      {    // Current user
1425          if( !is_logged_in() )
1426          {
1427              return NULL;
1428          }
1429          global $current_User;
1430          $user_ID = $current_User->ID;
1431      }
1432  
1433      global $DB;
1434  
1435      $SQL = new SQL();
1436      $SQL->SELECT( 'min( msg_datetime )' );
1437      $SQL->FROM( 'T_messaging__threadstatus ts' );
1438      $SQL->FROM_add( 'INNER JOIN T_messaging__message mu
1439                  ON ts.tsta_first_unread_msg_ID = mu.msg_ID' );
1440      $SQL->WHERE( 'ts.tsta_first_unread_msg_ID IS NOT NULL' );
1441      $SQL->WHERE_and( 'ts.tsta_thread_leave_msg_ID IS NULL OR ts.tsta_first_unread_msg_ID <= ts.tsta_thread_leave_msg_ID' );
1442      $SQL->WHERE_and( 'ts.tsta_user_ID = '.$DB->quote( $user_ID ) );
1443  
1444      return $DB->get_var( $SQL->get() );
1445  }
1446  
1447  
1448  /**
1449   * Get next 'Unread message reminder' datetime information for the given user. This is used on the user admin settings form.
1450   *
1451   * @param integer user ID
1452   * @result mixed string with the info field content if additional note is not required, and array( info, note ) otherwise
1453   */
1454  function get_next_reminder_info( $user_ID )
1455  {
1456      global $UserSettings, $DB, $servertimenow, $unread_message_reminder_delay, $unread_messsage_reminder_threshold;
1457  
1458      if( ! $UserSettings->get( 'notify_unread_messages', $user_ID ) )
1459      { // The user doesn't want to recive unread messages reminders
1460          return T_('This user doesn\'t want to receive notification emails about unread messages.');
1461      }
1462  
1463      $first_unread_message_date = get_first_unread_message_date( $user_ID );
1464      if( empty( $first_unread_message_date ) )
1465      { // The user doesn't have unread messages
1466          return T_('This user doesn\'t have unread messages.');
1467      }
1468  
1469      // We assume that reminder is not delayed because of the user was not logged in since too many days
1470      $reminder_is_delayed = false;
1471      $last_unread_messages_reminder = $UserSettings->get( 'last_unread_messages_reminder', $user_ID );
1472      if( empty( $last_unread_messages_reminder ) )
1473      { // User didn't get new message notification or unread message reminder yet
1474          // Set reminder issue timestamp to one day after the first unread message was received
1475          $reminder_issue_ts = strtotime( '+1 day', strtotime( $first_unread_message_date ) );
1476      }
1477      else
1478      { // Count next unread message reminder date, this can be delayed if the edited User didn't logged in since many days
1479          $UserCache = & get_UserCache();
1480          $edited_User = & $UserCache->get_by_ID( $user_ID );
1481          $lastseen_ts = strtotime( $edited_User->get( 'lastseen_ts' ) );
1482          $days_since_lastseen = floor(( $servertimenow - $lastseen_ts )/(60*60*24));
1483          // Presuppose that the User was not logged in since so many days, that should not get reminder any more
1484          $dont_send_reminder = true;
1485          // Get the number of delayed days for that case when we have to space out the notifications
1486          foreach( $unread_message_reminder_delay as $lastseen => $delay )
1487          { // Get the corresponding number of delay for the edited User
1488              if( $days_since_lastseen < $lastseen )
1489              { // We have found the correct delay value, reminders should be sent
1490                  $dont_send_reminder = false;
1491                  break;
1492              }
1493              // The reminder is delayed because the user was not logged in since more days then the first key of the delay array
1494              $reminder_is_delayed = true;
1495          }
1496          if( $dont_send_reminder )
1497          { // User was not logged in since too long
1498              return sprintf( T_('The user has not logged in for %d days, so we will not send him notifications any more'), $days_since_lastseen );
1499          }
1500  
1501          // Set reminder issue timestamp to x days after the last unread message notification date, where x is the delay from the configuration array
1502          $reminder_issue_ts = strtotime( '+'.$delay.' day', strtotime( $last_unread_messages_reminder ) );
1503      }
1504  
1505      if( $reminder_issue_ts > $servertimenow )
1506      { // The next reminder issue date is in the future
1507          $time_left = seconds_to_period( $reminder_issue_ts - $servertimenow );
1508          $info = sprintf( T_('%s left before next notification - sent by "Send reminders about unread messages" scheduled job'), $time_left );
1509      }
1510      else
1511      { // The next reminder issue date was in the past
1512          $time_since = seconds_to_period( $servertimenow - $reminder_issue_ts );
1513          $info = sprintf( T_('next notification pending since %s - check the "Send reminders about unread messages" scheduled job'), $time_since );
1514      }
1515  
1516      if( $reminder_is_delayed )
1517      { // Reminder is delayed, add a note about this
1518          $note = sprintf( T_('The user has not logged in for %d days, so we will space out notifications by %d days.'), $days_since_lastseen, $delay );
1519      }
1520      elseif( empty( $last_unread_messages_reminder ) )
1521      { // The user didn't get unread messages reminder emails before
1522          $note = sprintf( T_('The user has never received a notification yet, so the first notification is sent with %s delay'), seconds_to_period( $unread_messsage_reminder_threshold ) );
1523      }
1524      else
1525      { // Reminder is not delayed
1526          reset( $unread_message_reminder_delay );
1527          $lasstseen_threshold = key( $unread_message_reminder_delay );
1528          $delay = $unread_message_reminder_delay[$lasstseen_threshold];
1529          $note = sprintf( T_('The user has logged in in the last %d days, so we will space out notifications by %d days.'), $lasstseen_threshold, $delay );
1530      }
1531  
1532      return array( $info, $note );
1533  }
1534  
1535  
1536  /**
1537   * Mark a thread as read by the given user.
1538   *
1539   * @param integer thread ID
1540   * @param integer user ID
1541   */
1542  function mark_as_read_by_user( $thrd_ID, $user_ID )
1543  {
1544      global $DB;
1545  
1546      // Update user unread message status in the given thread
1547      $DB->query( 'UPDATE T_messaging__threadstatus
1548                      SET tsta_first_unread_msg_ID = NULL
1549                      WHERE tsta_thread_ID = '.$thrd_ID.'
1550                      AND tsta_user_ID = '.$user_ID );
1551  }
1552  
1553  
1554  /**
1555   * Delete orphan threads
1556   *
1557   * @param integer user_ID - to delete those orphan threads where this user was involved, leave it to NULL to delete all orphan threads
1558   * @return boolean true on success
1559   */
1560  function delete_orphan_threads( $user_ID = NULL )
1561  {
1562      global $DB;
1563  
1564      $DB->begin();
1565  
1566      // get orphan thread ids
1567      $SQL = new SQL();
1568      $SQL->SELECT( 'DISTINCT( tsta_thread_ID )' );
1569      $SQL->FROM( 'T_messaging__threadstatus' );
1570      // sub query to select not orphan thread ids
1571      $sub_query = 'SELECT DISTINCT ( tsta_thread_ID )
1572                      FROM T_messaging__threadstatus
1573                      INNER JOIN T_users ON user_ID = tsta_user_ID';
1574      if( empty( $user_ID ) )
1575      {
1576          $SQL->WHERE( 'tsta_thread_ID NOT IN ( '.$sub_query.' )' );
1577      }
1578      else
1579      {
1580          $SQL->WHERE( 'tsta_user_ID = '.$user_ID );
1581          $SQL->WHERE_and( 'tsta_thread_ID NOT IN ( '.$sub_query.' AND tsta_user_ID <> '.$user_ID.' )' );
1582      }
1583  
1584      $thread_ids = implode( ', ', $DB->get_col( $SQL->get(), 0, 'Get orphan threads' ) );
1585      if( empty( $thread_ids ) )
1586      { // orphan threads not exists
1587          $DB->commit();
1588          return true;
1589      }
1590  
1591      // Delete Messages
1592      $ret = $DB->query( 'DELETE FROM T_messaging__message WHERE msg_thread_ID IN ( '.$thread_ids.')' );
1593  
1594      // Delete Statuses
1595      $ret = $ret && $DB->query( 'DELETE FROM T_messaging__threadstatus WHERE tsta_thread_ID IN ( '.$thread_ids.')' );
1596  
1597      // Delete Threads
1598      $ret = $ret && $DB->query( 'DELETE FROM T_messaging__thread WHERE thrd_ID IN ( '.$thread_ids.')' );
1599  
1600      if( $ret )
1601      {
1602          $DB->commit();
1603          return true;
1604      }
1605  
1606      $DB->rollback();
1607      return false;
1608  }
1609  
1610  
1611  /**
1612   * Get ID of previous/next thread
1613   *
1614   * @param integer Current thread ID
1615   * @param string Type of url ('prev', 'next')
1616   * @return integer Thread ID
1617   */
1618  function get_thread_prevnext_ID( $current_thread_ID, $type = 'prev' )
1619  {
1620      global $thread_prevnext_ids_cache;
1621  
1622      if( empty( $current_thread_ID ) )
1623      {
1624          return false;
1625      }
1626  
1627      if( !isset( $thread_prevnext_ids_cache ) )
1628      {    // Initialize list with threads IDs
1629          global $DB;
1630  
1631          $threads_SQL = get_threads_results( array(
1632                  'only_sql' => true
1633              ) );
1634  
1635          $threads_SQL->SELECT( 'thrd_ID' );
1636          $thread_prevnext_ids_cache = $DB->get_col( $threads_SQL->get() );
1637      }
1638  
1639      $side_thread_i = ( $type == 'prev' ) ? 1 : -1;
1640      foreach( $thread_prevnext_ids_cache as $t => $thread_ID )
1641      {
1642          if( isset( $thread_prevnext_ids_cache[ $t + $side_thread_i ] ) && $thread_prevnext_ids_cache[ $t + $side_thread_i ] == $current_thread_ID )
1643          {    // This thread is previous/next for current thread
1644              return $thread_ID;
1645          }
1646      }
1647  }
1648  
1649  
1650  /**
1651   * Get the links for previous/next threads
1652   *
1653   * @param integer Current thread ID
1654   * @param string Type of url ('prev', 'next')
1655   * @return integer Thread ID
1656   */
1657  function get_thread_prevnext_links( $current_thread_ID, $params = array() )
1658  {
1659      $params = array_merge( array(
1660              'before'        => '<div class="floatright">',
1661              'after'         => '</div>',
1662              'title_text'    => T_('Conversations').': ',
1663              'separator'     => ' :: ',
1664              'previous_text' => '&laquo; '.T_('Previous'),
1665              'next_text'     => T_('Next').' &raquo;',
1666          ), $params );
1667  
1668      $prev_thread_ID = get_thread_prevnext_ID( $current_thread_ID, 'prev' );
1669      if( !empty( $prev_thread_ID ) )
1670      {    // Link to previous thread
1671          $prev_link = '<a href="'.get_dispctrl_url( 'messages', 'thrd_ID='.$prev_thread_ID ).'">'.$params['previous_text'].'</a>';
1672      }
1673  
1674      $next_thread_ID = get_thread_prevnext_ID( $current_thread_ID, 'next' );
1675      if( !empty( $next_thread_ID ) )
1676      {    // Link to previous thread
1677          $next_link = '<a href="'.get_dispctrl_url( 'messages', 'thrd_ID='.$next_thread_ID ).'">'.$params['next_text'].'</a>';
1678      }
1679  
1680      if( empty( $prev_link ) && empty( $next_link ) )
1681      {    // No found previous and next threads
1682          return;
1683      }
1684  
1685      $r = $params['before'];
1686      $r .= $params['title_text'];
1687  
1688      if( !empty( $prev_link ) )
1689      {
1690          $r .= $prev_link;
1691      }
1692  
1693      if( !empty( $prev_link ) && !empty( $next_link ) )
1694      {
1695          $r .= $params['separator'];
1696      }
1697  
1698      if( !empty( $next_link ) )
1699      {
1700          $r .= $next_link;
1701      }
1702  
1703      $r .= $params['after'];
1704  
1705      return $r;
1706  }
1707  
1708  
1709  /**
1710   * Display threads results table
1711   *
1712   * @param array Params
1713   */
1714  function threads_results_block( $params = array() )
1715  {
1716      // Make sure we are not missing any param:
1717      $params = array_merge( array(
1718              'edited_User'          => NULL,
1719              'results_param_prefix' => 'actv_thrd_',
1720              'results_title'        => T_('Threads with private messages sent by the user'),
1721              'results_no_text'      => T_('User has not sent any private messages'),
1722          ), $params );
1723  
1724      if( !is_logged_in() )
1725      {    // Only logged in users can access to this function
1726          return;
1727      }
1728  
1729      global $current_User;
1730      if( !$current_User->check_perm( 'users', 'edit' ) || !$current_User->check_perm( 'perm_messaging', 'reply' ) )
1731      {    // Check minimum permission:
1732          return;
1733      }
1734  
1735      $edited_User = $params['edited_User'];
1736      if( !$edited_User )
1737      {    // No defined User, probably the function is calling from AJAX request
1738          $user_ID = param( 'user_ID', 'integer', 0 );
1739          if( empty( $user_ID ) )
1740          {    // Bad request, Exit here
1741              return;
1742          }
1743          $UserCache = & get_UserCache();
1744          if( ( $edited_User = & $UserCache->get_by_ID( $user_ID, false ) ) === false )
1745          {    // Bad request, Exit here
1746              return;
1747          }
1748      }
1749  
1750      global $DB, $current_User;
1751  
1752      param( 'user_tab', 'string', '', true );
1753      param( 'user_ID', 'integer', 0, true );
1754  
1755  
1756      // Check permission:
1757      if( $current_User->check_perm( 'perm_messaging', 'abuse' ) )
1758      {
1759          // Create result set:
1760          $threads_Results = get_threads_results( array(
1761                  'results_param_prefix' => $params['results_param_prefix'],
1762                  'user_ID' => $edited_User->ID,
1763                  'sent_user_ID' => $edited_User->ID
1764              ) );
1765          $threads_Results->Cache = & get_ThreadCache();
1766          $threads_Results->title = $params['results_title'];
1767          $threads_Results->no_results_text = $params['results_no_text'];
1768  
1769          if( $threads_Results->total_rows > 0 )
1770          {    // Display action icon to delete all records if at least one record exists
1771              $threads_Results->global_icon( sprintf( T_('Delete all private messages sent by %s'), $edited_User->login ), 'delete', '?ctrl=user&amp;user_tab=activity&amp;action=delete_all_messages&amp;user_ID='.$edited_User->ID.'&amp;'.url_crumb('user'), ' '.T_('Delete all'), 3, 4 );
1772          }
1773  
1774          // Load classes
1775          load_class( 'messaging/model/_thread.class.php', 'Thread' );
1776  
1777          // Initialize Results object
1778          threads_results( $threads_Results, array(
1779                  'abuse_management' => 1,
1780                  'show_only_date' => 1,
1781              ) );
1782  
1783          if( is_ajax_content() )
1784          { // init results param by template name
1785              if( !isset( $params[ 'skin_type' ] ) || ! isset( $params[ 'skin_name' ] ) )
1786              {
1787                  debug_die( 'Invalid ajax results request!' );
1788              }
1789              $threads_Results->init_params_by_skin( $params[ 'skin_type' ], $params[ 'skin_name' ] );
1790          }
1791  
1792          $display_params = array(
1793              'before' => '<div class="results" style="margin-top:25px" id="threads_result">'
1794          );
1795          $threads_Results->display( $display_params );
1796  
1797          if( !is_ajax_content() )
1798          {    // Create this hidden div to get a function name for AJAX request
1799              echo '<div id="'.$params['results_param_prefix'].'ajax_callback" style="display:none">'.__FUNCTION__.'</div>';
1800          }
1801      }
1802      else
1803      {    // No permission for abuse management
1804          echo '<div style="margin-top:25px;font-weight:bold">'.sprintf( T_('User has sent %s private messages'), $edited_User->get_num_messages( 'sent' ) ).'</div>';
1805      }
1806  }
1807  
1808  
1809  /**
1810   * Initialize Results object for threads list
1811   *
1812   * @param object Results
1813   * @param array Params
1814   */
1815  function threads_results( & $threads_Results, $params = array() )
1816  {
1817      global $current_User;
1818  
1819      // Make sure we are not missing any param:
1820      $params = array_merge( array(
1821              'abuse_management' => 0, // 1 - abuse management mode
1822              'display_recipients' => true,
1823              'display_subject' => true,
1824              'display_date' => true,
1825              'display_read' => true,
1826              'display_actions' => true,
1827              'show_only_date' => 0,
1828          ), $params );
1829  
1830      if( $params['display_recipients'] )
1831      {    // Display Recipients column
1832          $threads_Results->cols[] = array(
1833                  'th' => $params['abuse_management'] ? T_('Between') : T_('With'),
1834                  'th_class' => 'thread_with shrinkwrap',
1835                  'td_class' => 'thread_with',
1836                  'td' => '%col_thread_recipients( #thrd_ID#, '.(int)$params['abuse_management'].' )%',
1837              );
1838      }
1839  
1840      if( $params['display_subject'] )
1841      {    // Display Subject column
1842          $threads_Results->cols[] = array(
1843                  'th' => T_('Subject'),
1844                  'th_class' => 'thread_subject',
1845                  'td_class' => 'thread_subject',
1846                  'td' => '%col_thread_subject_link( #thrd_ID#, #thrd_title#, #thrd_msg_ID#, #tsta_thread_leave_msg_ID#, '.(int)$params['abuse_management'].' )%',
1847              );
1848      }
1849  
1850      if( $params['display_date'] )
1851      {    // Display Date column
1852          $show_only_date = $params[ 'show_only_date' ];
1853          $threads_Results->cols[] = array(
1854                  'th' => T_('Last msg'),
1855                  'th_class' => 'shrinkwrap',
1856                  'td_class' => 'shrinkwrap',
1857                  'td' => '~conditional( #thrd_msg_ID#>0 && #thrd_msg_ID#!="abuse", \'%col_thread_date(#thrd_unread_since#,'.$show_only_date.')%\', \'%col_thread_date(#thrd_datemodified#,'.$show_only_date.')%\')~'
1858              );
1859      }
1860  
1861      if( $params['display_read'] )
1862      {    // Display Read column
1863          $threads_Results->cols[] = array(
1864                  'th' => T_('Read?'),
1865                  'th_class' => 'shrinkwrap',
1866                  'td_class' => 'center',
1867                  'td' => '%col_thread_read_by( #thrd_ID# )%',
1868              );
1869      }
1870  
1871      if( $params['display_actions'] )
1872      {    // Display Actions column
1873          if( $current_User->check_perm( 'perm_messaging', 'delete' ) )
1874          {    // We have permission to modify:
1875              $threads_Results->cols[] = array(
1876                      'th' => T_('Del'),
1877                      'th_class' => 'shrinkwrap',
1878                      'td_class' => 'shrinkwrap',
1879                      'td' => '%col_thread_delete_action(  #thrd_ID#  )%',
1880                  );
1881          }
1882      }
1883  }
1884  
1885  
1886  /**
1887   * Helper functions to display Threads results.
1888   * New ( not display helper ) functions must be created above threads_results function
1889   */
1890  
1891  /**
1892   * Get thread's recipients
1893   *
1894   * @param integer Thread ID
1895   * @param boolean TRUE for abuse management mode
1896   * @return string Recipients (avatar + login)
1897   */
1898  function col_thread_recipients( $thread_ID, $abuse_management )
1899  {
1900      global $DB, $Blog;
1901  
1902      $SQL = new SQL();
1903      $SQL->SELECT( 'user_login' );
1904      $SQL->FROM( 'T_messaging__threadstatus mts' );
1905      $SQL->FROM_add( 'LEFT JOIN T_users u ON user_ID = tsta_user_ID' );
1906      $SQL->WHERE( 'tsta_thread_ID = '.$thread_ID );
1907      if( !$abuse_management )
1908      {    // Show current user only in abuse management
1909          global $current_User;
1910          $SQL->WHERE_and( 'tsta_user_ID != '.$current_User->ID );
1911      }
1912      $recipients = $DB->get_col( $SQL->get() );
1913  
1914      $image_size = isset( $Blog ) ? $Blog->get_setting( 'image_size_messaging' ) : 'crop-top-32x32';
1915  
1916      return get_avatar_imgtags( $recipients, true, true, $image_size, 'avatar_before_login_middle mb1', '', NULL, true, '<br />', true );
1917  }
1918  
1919  
1920  /**
1921   * Get subject as link with icon (read or unread)
1922   *
1923   * @param thread ID
1924   * @param thread title
1925   * @param message ID (If ID > 0 - message is still unread)
1926   * @param message ID
1927   * @param boolean TRUE for abuse management mode
1928   * @return string link with subject
1929   */
1930  function col_thread_subject_link( $thrd_ID, $thrd_title, $thrd_msg_ID, $thrd_leave_msg_ID, $abuse_management )
1931  {
1932      $messages_url = get_dispctrl_url( 'messages' );
1933      if( $thrd_title == '' )
1934      {
1935          $thrd_title = '<i>(no subject)</i>';
1936      }
1937  
1938      $read_icon = '';
1939      if( $thrd_msg_ID != 'abuse' )
1940      {    // Don't show the read status for abuse management
1941          if( !empty( $thrd_leave_msg_ID ) )
1942          { // Conversation is left
1943              $read_icon = get_icon( 'bullet_black', 'imgtag', array( 'style' => 'margin:0 2px', 'alt' => T_( "Conversation left" ) ) );
1944              if( $thrd_msg_ID > 0 )
1945              { // also show unread messages icon, because user has not seen all messages yet
1946                  $read_icon .= get_icon( 'bullet_red', 'imgtag', array( 'style' => 'margin:0 2px', 'alt' => T_( "You have unread messages" ) ) );
1947              }
1948          }
1949          elseif( $thrd_msg_ID > 0 )
1950          { // Message is unread OR Show all messages in Abuse Management as unread
1951              $read_icon = get_icon( 'bullet_red', 'imgtag', array( 'style' => 'margin:0 2px', 'alt' => T_( "You have unread messages" ) ) );
1952          }
1953          else
1954          { // Message is read
1955              $read_icon = get_icon( 'allowback', 'imgtag', array( 'alt' => "You have read all messages" ) );
1956          }
1957      }
1958  
1959      $tab = '';
1960      if( $abuse_management )
1961      { // We are in Abuse Management
1962          $tab = '&amp;tab=abuse';
1963      }
1964  
1965      $link = $read_icon.'<a href="'.$messages_url.'&amp;thrd_ID='.$thrd_ID.$tab.'" title="'.T_('Show messages...').'">';
1966      $link .= '<strong>'.$thrd_title.'</strong>';
1967      $link .= '</a>';
1968  
1969      return $link;
1970  }
1971  
1972  
1973  /**
1974   * Return the given date in the correct date format
1975   *
1976   * @param string Date
1977   * @param boolean TRUE to show only date
1978   * @return string Date
1979  */
1980  function col_thread_date( $date, $show_only_date )
1981  {
1982      if( $show_only_date )
1983      {
1984          return mysql2localedate( $date );
1985      }
1986  
1987      return mysql2localedatetime( $date );
1988  }
1989  
1990  
1991  /**
1992   * Read? column
1993   *
1994   * @param integer Thread ID
1995   * @return string Status icons
1996   */
1997  function col_thread_read_by( $thread_ID )
1998  {
1999      global $DB;
2000  
2001      // Select read/unread users for this thread
2002      $recipients_SQL = get_threads_recipients_sql( $thread_ID );
2003  
2004      $read_by = '';
2005  
2006      if( $row = $DB->get_row( $recipients_SQL->get() ) )
2007      {
2008          if( !empty( $row->thr_read ) )
2009          {
2010              $read_by .= get_avatar_imgtags( $row->thr_read, false, false, 'crop-top-15x15', '', '', true, false );
2011          }
2012  
2013          if( !empty( $row->thr_unread ) )
2014          {
2015              if( !empty( $read_by ) )
2016              {
2017                  $read_by .= '<br />';
2018              }
2019              $read_by .= get_avatar_imgtags( $row->thr_unread, false, false, 'crop-top-15x15', '', '', false, false );
2020          }
2021  
2022          if( !empty( $row->thr_left ) )
2023          {
2024              if( !empty( $read_by ) )
2025              {
2026                  $read_by .= '<br />';
2027              }
2028              $read_by .= get_avatar_imgtags( $row->thr_left, false, false, 'crop-top-15x15', '', '', 'left', false );
2029          }
2030      }
2031  
2032      return $read_by;
2033  }
2034  
2035  
2036  /**
2037   * Get action icons to delete thread
2038   *
2039   * @param integer Thread ID
2040   * @return string Action icon
2041   */
2042  function col_thread_delete_action( $thread_ID )
2043  {
2044      global $Blog, $samedomain_htsrv_url, $admin_url;
2045  
2046      if( is_admin_page() )
2047      {
2048          $redirect_to = rawurlencode( regenerate_url( '', '', '', '&' ) );
2049          return action_icon( T_( 'Delete'), 'delete', $admin_url.'?ctrl=threads&amp;thrd_ID='.$thread_ID.'&amp;action=delete&amp;'.url_crumb( 'messaging_threads' ).'&amp;redirect_to='.$redirect_to );
2050      }
2051      else
2052      {
2053          $redirect_to = get_dispctrl_url( 'threads' );
2054          return action_icon( T_( 'Delete'), 'delete', $samedomain_htsrv_url.'action.php?mname=messaging&thrd_ID='.$thread_ID.'&action=delete&redirect_to='.$redirect_to.'&'.url_crumb( 'messaging_threads' ) );
2055      }
2056  }
2057  
2058  /**
2059   * Helper functions to display Threads results.
2060   * New ( not display helper ) functions must be created above threads_results function
2061   */
2062  
2063  ?>

title

Description

title

Description

title

Description

title

title

Body