[ Index ]

PHP Cross Reference of MantisBT

title

Body

[close]

/core/ -> access_api.php (source)

   1  <?php
   2  # MantisBT - A PHP based bugtracking system
   3  
   4  # MantisBT is free software: you can redistribute it and/or modify
   5  # it under the terms of the GNU General Public License as published by
   6  # the Free Software Foundation, either version 2 of the License, or
   7  # (at your option) any later version.
   8  #
   9  # MantisBT is distributed in the hope that it will be useful,
  10  # but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  # GNU General Public License for more details.
  13  #
  14  # You should have received a copy of the GNU General Public License
  15  # along with MantisBT.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Access API
  19   *
  20   * @package CoreAPI
  21   * @subpackage AccessAPI
  22   * @copyright Copyright (C) 2000 - 2002  Kenzaburo Ito - kenito@300baud.org
  23   * @copyright Copyright (C) 2002 - 2011  MantisBT Team - mantisbt-dev@lists.sourceforge.net
  24   * @link http://www.mantisbt.org
  25   *
  26   * @uses authentication_api.php
  27   * @uses bug_api.php
  28   * @uses bugnote_api.php
  29   * @uses config_api.php
  30   * @uses constant_inc.php
  31   * @uses current_user_api.php
  32   * @uses database_api.php
  33   * @uses error_api.php
  34   * @uses helper_api.php
  35   * @uses lang_api.php
  36   * @uses print_api.php
  37   * @uses project_api.php
  38   * @uses string_api.php
  39   * @uses user_api.php
  40   */
  41  
  42  require_api( 'authentication_api.php' );
  43  require_api( 'bug_api.php' );
  44  require_api( 'bugnote_api.php' );
  45  require_api( 'config_api.php' );
  46  require_api( 'constant_inc.php' );
  47  require_api( 'current_user_api.php' );
  48  require_api( 'database_api.php' );
  49  require_api( 'error_api.php' );
  50  require_api( 'helper_api.php' );
  51  require_api( 'lang_api.php' );
  52  require_api( 'print_api.php' );
  53  require_api( 'project_api.php' );
  54  require_api( 'string_api.php' );
  55  require_api( 'user_api.php' );
  56  
  57  /**
  58   *
  59   * @global array $g_cache_access_matrix
  60   */
  61  $g_cache_access_matrix = array();
  62  
  63  /**
  64   *
  65   * @global array $g_cache_access_matrix_project_ids
  66   */
  67  $g_cache_access_matrix_project_ids = array();
  68  
  69  /**
  70   *
  71   * @global array $g_cache_access_matrix_user_ids
  72   */
  73  $g_cache_access_matrix_user_ids = array();
  74  
  75  /**
  76   * Function to be called when a user is attempting to access a page that
  77   * he/she is not authorised to.  This outputs an access denied message then
  78   * re-directs to the mainpage.
  79   */
  80  function access_denied() {
  81      if( !auth_is_user_authenticated() ) {
  82          if( basename( $_SERVER['SCRIPT_NAME'] ) != 'login_page.php' ) {
  83              $t_return_page = $_SERVER['SCRIPT_NAME'];
  84              if( isset( $_SERVER['QUERY_STRING'] ) ) {
  85                  $t_return_page .= '?' . $_SERVER['QUERY_STRING'];
  86              }
  87              $t_return_page = string_url( string_sanitize_url( $t_return_page ) );
  88              print_header_redirect( 'login_page.php' . '?return=' . $t_return_page );
  89          }
  90      } else {
  91          if( current_user_is_anonymous() ) {
  92              if( basename( $_SERVER['SCRIPT_NAME'] ) != 'login_page.php' ) {
  93                  $t_return_page = $_SERVER['SCRIPT_NAME'];
  94                  if( isset( $_SERVER['QUERY_STRING'] ) ) {
  95                      $t_return_page .= '?' . $_SERVER['QUERY_STRING'];
  96                  }
  97                  $t_return_page = string_url( string_sanitize_url( $t_return_page ) );
  98                  echo '<p class="center">' . error_string( ERROR_ACCESS_DENIED ) . '</p><p class="center">';
  99                  print_bracket_link( helper_mantis_url( 'login_page.php' ) . '?return=' . $t_return_page, lang_get( 'click_to_login' ) );
 100                  echo '</p><p class="center">';
 101                  print_bracket_link( helper_mantis_url( 'main_page.php' ), lang_get( 'proceed' ) );
 102                  echo '</p>';
 103              }
 104          } else {
 105              echo '<p class="center">' . error_string( ERROR_ACCESS_DENIED ) . '</p>';
 106              echo '<p class="center">';
 107              print_bracket_link( helper_mantis_url( 'main_page.php' ), lang_get( 'proceed' ) );
 108              echo '</p>';
 109          }
 110      }
 111      exit;
 112  }
 113  
 114  /**
 115   * retrieves and returns access matrix for a project from cache or caching if required.
 116   * @param int $p_project_id integer representing project id
 117   * @return  array returns an array of users->accesslevel for the given user
 118   * @access private
 119   */
 120  function access_cache_matrix_project( $p_project_id ) {
 121      global $g_cache_access_matrix, $g_cache_access_matrix_project_ids;
 122  
 123      if( ALL_PROJECTS == (int)$p_project_id ) {
 124          return array();
 125      }
 126  
 127      if( !in_array( (int) $p_project_id, $g_cache_access_matrix_project_ids ) ) {
 128          $t_project_user_list_table = db_get_table( 'project_user_list' );
 129  
 130          $query = "SELECT user_id, access_level
 131                        FROM $t_project_user_list_table
 132                        WHERE project_id=" . db_param();
 133          $result = db_query_bound( $query, Array( (int)$p_project_id ) );
 134          $count = db_num_rows( $result );
 135          for( $i = 0;$i < $count;$i++ ) {
 136              $row = db_fetch_array( $result );
 137  
 138              $g_cache_access_matrix[(int) $row['user_id']][(int) $p_project_id] = (int) $row['access_level'];
 139          }
 140  
 141          $g_cache_access_matrix_project_ids[] = (int) $p_project_id;
 142      }
 143  
 144      $t_results = array();
 145  
 146      foreach( $g_cache_access_matrix as $t_user ) {
 147          if( isset( $t_user[(int) $p_project_id] ) ) {
 148              $t_results[(int) $p_project_id] = $t_user[(int) $p_project_id];
 149          }
 150      }
 151  
 152      return $t_results;
 153  }
 154  
 155  /**
 156   * retrieves and returns access matrix for a user from cache or caching if required.
 157   * @param int $p_user_id integer representing user id
 158   * @return  array returns an array of projects->accesslevel for the given user
 159   * @access private
 160   */
 161  function access_cache_matrix_user( $p_user_id ) {
 162      global $g_cache_access_matrix, $g_cache_access_matrix_user_ids;
 163  
 164      if( !in_array( (int) $p_user_id, $g_cache_access_matrix_user_ids ) ) {
 165          $t_project_user_list_table = db_get_table( 'project_user_list' );
 166  
 167          $query = "SELECT project_id, access_level
 168                        FROM $t_project_user_list_table
 169                        WHERE user_id=" . db_param();
 170          $result = db_query_bound( $query, Array( (int)$p_user_id ) );
 171  
 172          $count = db_num_rows( $result );
 173  
 174          # make sure we always have an array to return
 175          $g_cache_access_matrix[(int) $p_user_id] = array();
 176  
 177          for( $i = 0;$i < $count;$i++ ) {
 178              $row = db_fetch_array( $result );
 179              $g_cache_access_matrix[(int) $p_user_id][(int) $row['project_id']] = (int) $row['access_level'];
 180          }
 181  
 182          $g_cache_access_matrix_user_ids[] = (int) $p_user_id;
 183      }
 184  
 185      return $g_cache_access_matrix[(int) $p_user_id];
 186  }
 187  
 188  /**
 189   * Check the a user's access against the given "threshold" and return true
 190   * if the user can access, false otherwise.
 191   * $p_access_level may be a single value, or an array. If it is a single
 192   * value, treat it as a threshold so return true if user is >= threshold.
 193   * If it is an array, look for exact matches to one of the values
 194   * @param int $p_user_access_level user access level
 195   * @param int|array $p_threshold access threshold, defaults to NOBODY
 196   * @return bool true or false depending on whether given access level matches the threshold
 197   * @access public
 198   */
 199  function access_compare_level( $p_user_access_level, $p_threshold = NOBODY ) {
 200      if( is_array( $p_threshold ) ) {
 201          return( in_array( $p_user_access_level, $p_threshold ) );
 202      } else {
 203          return( $p_user_access_level >= $p_threshold );
 204      }
 205  }
 206  
 207  /**
 208   * This function only checks the user's global access level, ignoring any
 209   * overrides they might have at a project level
 210   * @param int|null $p_user_id integer representing user id, defaults to null to use current user
 211   * @return int global access level
 212   * @access public
 213   */
 214  function access_get_global_level( $p_user_id = null ) {
 215      if( $p_user_id === null ) {
 216          $p_user_id = auth_get_current_user_id();
 217      }
 218  
 219      # Deal with not logged in silently in this case
 220      # @@@ we may be able to remove this and just error
 221      #     and once we default to anon login, we can remove it for sure
 222      if( !auth_is_user_authenticated() ) {
 223          return false;
 224      }
 225  
 226      return user_get_field( $p_user_id, 'access_level' );
 227  }
 228  
 229  /**
 230   * Check the current user's access against the given value and return true
 231   * if the user's access is equal to or higher, false otherwise.
 232   * @param int $p_access_level integer representing access level
 233   * @param int|null $p_user_id integer representing user id, defaults to null to use current user
 234   * @return bool whether user has access level specified
 235   * @access public
 236   */
 237  function access_has_global_level( $p_access_level, $p_user_id = null ) {
 238      # Short circuit the check in this case
 239      if( NOBODY == $p_access_level ) {
 240          return false;
 241      }
 242  
 243      if( $p_user_id === null ) {
 244          $p_user_id = auth_get_current_user_id();
 245      }
 246  
 247      $t_access_level = access_get_global_level( $p_user_id );
 248  
 249      return access_compare_level( $t_access_level, $p_access_level );
 250  }
 251  
 252  /**
 253   * Check if the user has the specified global access level
 254   * and deny access to the page if not
 255   * @see access_has_global_level
 256   * @param int $p_access_level integer representing access level
 257   * @param int|null $p_user_id integer representing user id, defaults to null to use current user
 258   * @access public
 259   */
 260  function access_ensure_global_level( $p_access_level, $p_user_id = null ) {
 261      if( !access_has_global_level( $p_access_level, $p_user_id ) ) {
 262          access_denied();
 263      }
 264  }
 265  
 266  /**
 267   * This function checks the project access level first (for the current project
 268   * if none is specified) and if the user is not listed, it falls back on the
 269   * user's global access level.
 270   * @param int $p_project_id integer representing project id to check access against
 271   * @param int|null $p_user_id integer representing user id, defaults to null to use current user
 272   * @return int access level user has to given project
 273   * @access public
 274   */
 275  function access_get_project_level( $p_project_id = null, $p_user_id = null ) {
 276      # Deal with not logged in silently in this case
 277      /** @todo we may be able to remove this and just error and once we default to anon login, we can remove it for sure */
 278      if( !auth_is_user_authenticated() ) {
 279          return ANYBODY;
 280      }
 281  
 282      if( null === $p_user_id ) {
 283          $p_user_id = auth_get_current_user_id();
 284      }
 285  
 286      if( null === $p_project_id ) {
 287          $p_project_id = helper_get_current_project();
 288      }
 289  
 290      $t_global_access_level = access_get_global_level( $p_user_id );
 291  
 292      if( ALL_PROJECTS == $p_project_id || user_is_administrator( $p_user_id ) ) {
 293          return $t_global_access_level;
 294      } else {
 295          $t_project_access_level = access_get_local_level( $p_user_id, $p_project_id );
 296          $t_project_view_state = project_get_field( $p_project_id, 'view_state' );
 297  
 298          # Try to use the project access level.
 299          # If the user is not listed in the project, then try to fall back
 300          #  to the global access level
 301          if( false === $t_project_access_level ) {
 302              # If the project is private and the user isn't listed, then they
 303              # must have the private_project_threshold access level to get in.
 304              if( VS_PRIVATE == $t_project_view_state ) {
 305                  if( access_compare_level( $t_global_access_level, config_get( 'private_project_threshold', null, null, ALL_PROJECTS ) ) ) {
 306                      return $t_global_access_level;
 307                  } else {
 308                      return ANYBODY;
 309                  }
 310              } else {
 311                  # project access not set, but the project is public
 312                  return $t_global_access_level;
 313              }
 314          } else {
 315              # project specific access was set
 316              return $t_project_access_level;
 317          }
 318      }
 319  }
 320  
 321  /**
 322   * Check the current user's access against the given value and return true
 323   * if the user's access is equal to or higher, false otherwise.
 324   * @param int $p_access_level integer representing access level
 325   * @param int $p_project_id integer representing project id to check access against
 326   * @param int|null $p_user_id integer representing user id, defaults to null to use current user
 327   * @return bool whether user has access level specified
 328   * @access public
 329   */
 330  function access_has_project_level( $p_access_level, $p_project_id = null, $p_user_id = null ) {
 331      # Short circuit the check in this case
 332      if( NOBODY == $p_access_level ) {
 333          return false;
 334      }
 335  
 336      if( null === $p_user_id ) {
 337          $p_user_id = auth_get_current_user_id();
 338      }
 339      if( null === $p_project_id ) {
 340          $p_project_id = helper_get_current_project();
 341      }
 342  
 343      $t_access_level = access_get_project_level( $p_project_id, $p_user_id );
 344  
 345      return access_compare_level( $t_access_level, $p_access_level );
 346  }
 347  
 348  /**
 349   * Check if the user has the specified access level for the given project
 350   * and deny access to the page if not
 351   * @see access_has_project_level
 352   * @param int $p_access_level integer representing access level
 353   * @param int|null $p_project_id integer representing project id to check access against, defaults to null to use current project
 354   * @param int|null $p_user_id integer representing user id, defaults to null to use current user
 355   * @access public
 356   */
 357  function access_ensure_project_level( $p_access_level, $p_project_id = null, $p_user_id = null ) {
 358      if( !access_has_project_level( $p_access_level, $p_project_id, $p_user_id ) ) {
 359          access_denied();
 360      }
 361  }
 362  
 363  /**
 364   * Check whether the user has the specified access level for any project project
 365   * @param int $p_access_level integer representing access level
 366   * @param int|null $p_user_id integer representing user id, defaults to null to use current user
 367   * @return bool whether user has access level specified
 368   * @access public
 369   */
 370  function access_has_any_project( $p_access_level, $p_user_id = null ) {
 371      # Short circuit the check in this case
 372  
 373      if( NOBODY == $p_access_level ) {
 374          return false;
 375      }
 376  
 377      if( null === $p_user_id ) {
 378          $p_user_id = auth_get_current_user_id();
 379      }
 380  
 381      $t_projects = project_get_all_rows();
 382      foreach( $t_projects as $t_project ) {
 383          if ( access_has_project_level( $p_access_level, $t_project['id'], $p_user_id ) ) {
 384              return true;
 385          }
 386      }
 387  
 388      return false;
 389  }
 390  
 391  /**
 392   * Check the current user's access against the given value and return true
 393   * if the user's access is equal to or higher, false otherwise.
 394   * This function looks up the bug's project and performs an access check
 395   * against that project
 396   * @param int $p_access_level integer representing access level
 397   * @param int $p_bug_id integer representing bug id to check access against
 398   * @param int|null $p_user_id integer representing user id, defaults to null to use current user
 399   * @return bool whether user has access level specified
 400   * @access public
 401   */
 402  function access_has_bug_level( $p_access_level, $p_bug_id, $p_user_id = null ) {
 403      # Deal with not logged in silently in this case
 404      # @@@ we may be able to remove this and just error
 405      #     and once we default to anon login, we can remove it for sure
 406      if( !auth_is_user_authenticated() ) {
 407          return false;
 408      }
 409  
 410      if( $p_user_id === null ) {
 411          $p_user_id = auth_get_current_user_id();
 412      }
 413  
 414      $t_project_id = bug_get_field( $p_bug_id, 'project_id' );
 415  
 416      # check limit_Reporter (Issue #4769)
 417      # reporters can view just issues they reported
 418      $t_limit_reporters = config_get( 'limit_reporters' );
 419      if(( ON === $t_limit_reporters ) && ( !bug_is_user_reporter( $p_bug_id, $p_user_id ) ) && ( !access_has_project_level( REPORTER + 1, $t_project_id, $p_user_id ) ) ) {
 420          return false;
 421      }
 422  
 423      # If the bug is private and the user is not the reporter, then the
 424      #  the user must also have higher access than private_bug_threshold
 425      if( VS_PRIVATE == bug_get_field( $p_bug_id, 'view_state' ) && !bug_is_user_reporter( $p_bug_id, $p_user_id ) ) {
 426          $p_access_level = max( $p_access_level, config_get( 'private_bug_threshold' ) );
 427      }
 428  
 429      return access_has_project_level( $p_access_level, $t_project_id, $p_user_id );
 430  }
 431  
 432  /**
 433   * Check if the user has the specified access level for the given bug
 434   * and deny access to the page if not
 435   * @see access_has_bug_level
 436   * @param int $p_access_level integer representing access level
 437   * @param int $p_bug_id integer representing bug id to check access against
 438   * @param int|null $p_user_id integer representing user id, defaults to null to use current user
 439   * @return bool whether user has access level specified
 440   * @access public
 441   */
 442  function access_ensure_bug_level( $p_access_level, $p_bug_id, $p_user_id = null ) {
 443      if( !access_has_bug_level( $p_access_level, $p_bug_id, $p_user_id ) ) {
 444          access_denied();
 445      }
 446  }
 447  
 448  /**
 449   * Check the current user's access against the given value and return true
 450   * if the user's access is equal to or higher, false otherwise.
 451   * This function looks up the bugnote's bug and performs an access check
 452   * against that bug
 453   * @param int $p_access_level integer representing access level
 454   * @param int $p_bugnote_id integer representing bugnote id to check access against
 455   * @param int|null $p_user_id integer representing user id, defaults to null to use current user
 456   * @return bool whether user has access level specified
 457   * @access public
 458   */
 459  function access_has_bugnote_level( $p_access_level, $p_bugnote_id, $p_user_id = null ) {
 460      if( null === $p_user_id ) {
 461          $p_user_id = auth_get_current_user_id();
 462      }
 463  
 464      # If the bug is private and the user is not the reporter, then the
 465      #  the user must also have higher access than private_bug_threshold
 466      if( VS_PRIVATE == bugnote_get_field( $p_bugnote_id, 'view_state' ) && !bugnote_is_user_reporter( $p_bugnote_id, $p_user_id ) ) {
 467          $p_access_level = max( $p_access_level, config_get( 'private_bugnote_threshold' ) );
 468      }
 469  
 470      $t_bug_id = bugnote_get_field( $p_bugnote_id, 'bug_id' );
 471  
 472      return access_has_bug_level( $p_access_level, $t_bug_id, $p_user_id );
 473  }
 474  
 475  /**
 476   * Check if the user has the specified access level for the given bugnote
 477   * and deny access to the page if not
 478   * @see access_has_bugnote_level
 479   * @param int $p_access_level integer representing access level
 480   * @param int $p_bugnote_id integer representing bugnote id to check access against
 481   * @param int|null $p_user_id integer representing user id, defaults to null to use current user
 482   * @access public
 483   */
 484   function access_ensure_bugnote_level( $p_access_level, $p_bugnote_id, $p_user_id = null ) {
 485      if( !access_has_bugnote_level( $p_access_level, $p_bugnote_id, $p_user_id ) ) {
 486          access_denied();
 487      }
 488  }
 489  
 490  /**
 491   * Check if the current user can close the specified bug
 492   * @param int $p_bug_id integer representing bug id to check access against
 493   * @param int|null $p_user_id integer representing user id, defaults to null to use current user
 494   * @return bool whether user has access to close bugs
 495   * @access public
 496   */
 497   function access_can_close_bug( $p_bug_id, $p_user_id = null ) {
 498      if( null === $p_user_id ) {
 499          $p_user_id = auth_get_current_user_id();
 500      }
 501  
 502      # If allow_reporter_close is enabled, then reporters can always close their own bugs
 503      if( ON == config_get( 'allow_reporter_close' ) && bug_is_user_reporter( $p_bug_id, $p_user_id ) ) {
 504          return true;
 505      }
 506  
 507      $t_bug = bug_get( $p_bug_id );
 508  
 509      $t_closed_status_threshold = access_get_status_threshold( config_get( 'bug_closed_status_threshold' ), $t_bug->project_id );
 510  
 511      return access_has_bug_level( $t_closed_status_threshold, $p_bug_id, $p_user_id );
 512  }
 513  
 514  /**
 515   * Make sure that the current user can close the specified bug
 516   * @see access_can_close_bug
 517   * @param int $p_bug_id integer representing bug id to check access against
 518   * @param int|null $p_user_id integer representing user id, defaults to null to use current user
 519   * @access public
 520   */
 521   function access_ensure_can_close_bug( $p_bug_id, $p_user_id = null ) {
 522      if( !access_can_close_bug( $p_bug_id, $p_user_id ) ) {
 523          access_denied();
 524      }
 525  }
 526  
 527  /**
 528   * Check if the current user can reopen the specified bug
 529   * @param int $p_bug_id integer representing bug id to check access against
 530   * @param int|null $p_user_id integer representing user id, defaults to null to use current user
 531   * @return bool whether user has access to reopen bugs
 532   * @access public
 533   */
 534   function access_can_reopen_bug( $p_bug_id, $p_user_id = null ) {
 535      if( $p_user_id === null ) {
 536          $p_user_id = auth_get_current_user_id();
 537      }
 538  
 539      # If allow_reporter_reopen is enabled, then reporters can always reopen their own bugs
 540      if( ON == config_get( 'allow_reporter_reopen' ) && bug_is_user_reporter( $p_bug_id, $p_user_id ) ) {
 541          return true;
 542      }
 543  
 544      return access_has_bug_level( config_get( 'reopen_bug_threshold' ), $p_bug_id, $p_user_id );
 545  }
 546  
 547  /**
 548   * Make sure that the current user can reopen the specified bug.
 549   * Calls access_denied if user has no access to terminate script
 550   * @see access_can_reopen_bug
 551   * @param int $p_bug_id integer representing bug id to check access against
 552   * @param int|null $p_user_id integer representing user id, defaults to null to use current user
 553   * @access public
 554   */
 555   function access_ensure_can_reopen_bug( $p_bug_id, $p_user_id = null ) {
 556      if( !access_can_reopen_bug( $p_bug_id, $p_user_id ) ) {
 557          access_denied();
 558      }
 559  }
 560  
 561  /**
 562   * get the user's access level specific to this project.
 563   * return false (0) if the user has no access override here
 564   * @param int $p_user_id Integer representing user id
 565   * @param int $p_project_id integer representing project id
 566   * @return bool|int returns false (if no access) or an integer representing level of access
 567   * @access public
 568   */
 569  function access_get_local_level( $p_user_id, $p_project_id ) {
 570      global $g_cache_access_matrix, $g_cache_access_matrix_project_ids;
 571  
 572      $p_project_id = (int) $p_project_id;
 573      $p_user_id = (int) $p_user_id;
 574  
 575      if( in_array( $p_project_id, $g_cache_access_matrix_project_ids ) ) {
 576          if( isset( $g_cache_access_matrix[$p_user_id][$p_project_id] ) ) {
 577              return $g_cache_access_matrix[$p_user_id][$p_project_id];
 578          } else {
 579              return false;
 580          }
 581      }
 582  
 583      $t_project_level = access_cache_matrix_user( $p_user_id );
 584  
 585      if( isset( $t_project_level[$p_project_id] ) ) {
 586          return $t_project_level[$p_project_id];
 587      } else {
 588          return false;
 589      }
 590  }
 591  
 592  /**
 593   * get the access level required to change the issue to the new status
 594   * If there is no specific differentiated access level, use the
 595   * generic update_bug_status_threshold.
 596   * @param int $p_status
 597   * @param int $p_project_id Default value ALL_PROJECTS
 598   * @return int integer representing user level e.g. DEVELOPER
 599   * @access public
 600   */
 601  function access_get_status_threshold( $p_status, $p_project_id = ALL_PROJECTS ) {
 602      $t_thresh_array = config_get( 'set_status_threshold', null, null, $p_project_id );
 603      if( isset( $t_thresh_array[(int)$p_status] ) ) {
 604          return (int)$t_thresh_array[(int)$p_status];
 605      } else {
 606          return config_get( 'update_bug_status_threshold', null, null, $p_project_id );
 607      }
 608  }


Generated: Thu Jul 28 15:48:31 2011 Cross-referenced by PHPXref 0.7