Revision: 1997
          http://mrbs.svn.sourceforge.net/mrbs/?rev=1997&view=rev
Author:   cimorrison
Date:     2011-09-22 16:51:18 +0000 (Thu, 22 Sep 2011)
Log Message:
-----------
Merged in latest changes from the trunk

Modified Paths:
--------------
    mrbs/branches/datatables/AUTHENTICATION
    mrbs/branches/datatables/web/auth_ldap.inc
    mrbs/branches/datatables/web/functions.inc
    mrbs/branches/datatables/web/systemdefaults.inc.php

Property Changed:
----------------
    mrbs/branches/datatables/
    mrbs/branches/datatables/web/upgrade/5/pgsql.sql


Property changes on: mrbs/branches/datatables
___________________________________________________________________
Modified: svn:mergeinfo
   - /mrbs/branches/custom_entry_fields:1374-1396
/mrbs/branches/datepicker:1409-1416
/mrbs/branches/disabled_rooms:1601-1634
/mrbs/branches/from_to_bookings:1491-1587
/mrbs/branches/ics_attachments:1652-1741
/mrbs/branches/improve_css_2008_06:804-872
/mrbs/branches/only_unicode:1747-1749
/mrbs/branches/provisional_bookings:1242-1280
/mrbs/branches/provisional_bookings_new_style:1407-1570
/mrbs/trunk:1863-1994
   + /mrbs/branches/custom_entry_fields:1374-1396
/mrbs/branches/datepicker:1409-1416
/mrbs/branches/disabled_rooms:1601-1634
/mrbs/branches/from_to_bookings:1491-1587
/mrbs/branches/ics_attachments:1652-1741
/mrbs/branches/improve_css_2008_06:804-872
/mrbs/branches/only_unicode:1747-1749
/mrbs/branches/provisional_bookings:1242-1280
/mrbs/branches/provisional_bookings_new_style:1407-1570
/mrbs/trunk:1863-1996

Modified: mrbs/branches/datatables/AUTHENTICATION
===================================================================
--- mrbs/branches/datatables/AUTHENTICATION     2011-09-22 14:41:57 UTC (rev 
1996)
+++ mrbs/branches/datatables/AUTHENTICATION     2011-09-22 16:51:18 UTC (rev 
1997)
@@ -690,9 +690,10 @@
 the supplied password and a distinguished name, which is formed from the
 base distinguished name, the user attribute and the user name. 
 
-This method supports multiple $ldap_base_dn entries and $ldap_user_attrib
-values.  The authentication is attempted with each base dn in turn until it
-succeeds or it fails to authenticate the user.
+This method supports multiple values for most of the configuration
+parameters, including $ldap_base_dn entries and $ldap_user_attrib
+values.  The authentication is attempted with each set of configuration
+parameters in turn until it succeeds or it fails to authenticate the user.
 
 Multiple base distinguished names with the same user attribute for each
 base dn:

Modified: mrbs/branches/datatables/web/auth_ldap.inc
===================================================================
--- mrbs/branches/datatables/web/auth_ldap.inc  2011-09-22 14:41:57 UTC (rev 
1996)
+++ mrbs/branches/datatables/web/auth_ldap.inc  2011-09-22 16:51:18 UTC (rev 
1997)
@@ -8,6 +8,7 @@
   $auth['session']='http';
 }
 
+
 /* authLdapAction($callback, $user, &$object)
  * 
  * Connects/binds to all configured LDAP servers/base DNs and
@@ -34,6 +35,10 @@
   global $ldap_dn_search_attrib;
   global $ldap_dn_search_dn;
   global $ldap_dn_search_password;
+  global $ldap_filter;
+  global $ldap_group_member_attrib;
+  global $ldap_admin_group_dn;
+  global $ldap_email_attrib;
 
   if (!function_exists("ldap_connect"))
   {
@@ -41,83 +46,109 @@
         "Please check your MRBS and web server configuration.</b></p><hr>\n");
   }
 
-  $all_ldap_base_dn     = array();
-  $all_ldap_user_attrib = array();
+  // Transfer the values from the config variables into a local
+  // associative array, turning them all into arrays
+  
+  $config_items = array(
+                        'ldap_host',
+                        'ldap_port',
+                        'ldap_base_dn',
+                        'ldap_user_attrib',
+                        'ldap_dn_search_attrib',
+                        'ldap_dn_search_dn',
+                        'ldap_dn_search_password',
+                        'ldap_filter',
+                        'ldap_group_member_attrib',
+                        'ldap_admin_group_dn',
+                        'ldap_v3',
+                        'ldap_tls',
+                        'ldap_email_attrib'
+                       );
 
-  // Check that if there is an array of hosts and an array of ports
-  // then the number of each must be the same or the authenication
-  // is forced to fail.
-  if (is_array( $ldap_base_dn ) && is_array( $ldap_user_attrib ) &&
-      count($ldap_user_attrib) != count($ldap_base_dn) )
-  {
-    return 0;
-  }
+  $all_ldap_opts = array();
 
-  // Transfer the based dn(s) to an new value to ensure that
-  // an array is always used.
-  // If a single value is passed then turn it into an array
-  if (is_array( $ldap_base_dn ) )
+  
+  foreach ($config_items as $item)
   {
-    $all_ldap_base_dn = $ldap_base_dn;
+    if (!isset($$item))
+    {
+      continue;
+    }
+    if (is_array($$item))
+    {
+      $all_ldap_opts[$item] = $$item;
+    }
+    // The case where the config item _isn't_ an array is handled
+    // further down
   }
-  else
-  {
-    $all_ldap_base_dn = array($ldap_base_dn);
-  }
 
-  // Transfer the array of user attributes to a new value.
-  // Create an array of the user attributes to match the number of
-  // base dn's if a single user attribute has been passed.
-  if (is_array( $ldap_user_attrib ) )
+  $count = null;
+  foreach ($all_ldap_opts as $key => $value)
   {
-    $all_ldap_user_attrib = $ldap_user_attrib;
-  }
-  else
-  {
-    while ( each($all_ldap_base_dn ) )
+    if (isset($count))
     {
-      $all_ldap_user_attrib[] = $ldap_user_attrib;
+      if (count($value) != $count)
+      {
+        authLdapDebug("Count of LDAP array config variables doesn't match, 
aborting!");
+        fatal_error(TRUE,
+                    "MRBS configuration error: Count of LDAP array config 
variables doesn't match, aborting!",
+                    false);
+        return 0;
+      }
     }
+    $count = count($value);
   }
 
-  // establish ldap connection
-  // the '@' suppresses errors
-  if (isset($ldap_port))
+  // Turn any non-array config items into arrays in $all_ldap_opts
+  foreach ($config_items as $item)
   {
-    $ldap = @ldap_connect($ldap_host, $ldap_port);
+    if (!isset($$item))
+    {
+      continue;
+    }
+    if (!is_array($$item))
+    {
+      $all_ldap_opts[$item] = array_fill(0, $count, $$item);
+    }
   }
-  else
-  {
-    $ldap = @ldap_connect($ldap_host);
-  }
 
-  // Check that connection was established
-  if ($ldap)
+  foreach ($all_ldap_opts['ldap_host'] as $idx => $host)
   {
-    authLdapDebug("authLdapAction: Got LDAP connection");
-
-    if ($ldap_v3)
+    // establish ldap connection
+    // the '@' suppresses errors
+    if (isset($all_ldap_opts['ldap_port'][$idx]))
     {
-      ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
+      $ldap = @ldap_connect($host, $all_ldap_opts['ldap_port'][$idx]);
     }
-    if ($ldap_tls)
+    else
     {
-      ldap_start_tls($ldap);
+      $ldap = @ldap_connect($host);
     }
 
-    // now process all base dn's until authentication is achieved
-    // or fail
-    foreach ( $all_ldap_base_dn as $idx => $base_dn)
+    // Check that connection was established
+    if ($ldap)
     {
-      authLdapDebug("authLdapAction: start of foreach $base_dn");
-      if (isset($ldap_dn_search_attrib))
+      authLdapDebug("authLdapAction: Got LDAP connection");
+
+      if (isset($all_ldap_opts['ldap_v3'][$idx]) &&
+          $all_ldap_opts['ldap_v3'][$idx])
       {
-        if (isset($ldap_dn_search_dn) &&
-            isset($ldap_dn_search_password))
+        ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
+      }
+      if (isset($all_ldap_opts['ldap_tls'][$idx]) &&
+          $all_ldap_opts['ldap_tls'][$idx])
+      {
+        ldap_start_tls($ldap);
+      }
+
+      if (isset($all_ldap_opts['ldap_dn_search_attrib'][$idx]))
+      {
+        if (isset($all_ldap_opts['ldap_dn_search_dn'][$idx]) &&
+            isset($all_ldap_opts['ldap_dn_search_password'][$idx]))
         {
           // Bind with DN and password
-          $res = @ldap_bind($ldap, $ldap_dn_search_dn,
-                            $ldap_dn_search_password);
+          $res = @ldap_bind($ldap, $all_ldap_opts['ldap_dn_search_dn'][$idx],
+                            $all_ldap_opts['ldap_dn_search_password'][$idx]);
         }
         else
         {
@@ -129,47 +160,57 @@
         if ($res)
         {
           $res = @ldap_search($ldap,
-                              $base_dn,
-                              "(". $ldap_dn_search_attrib ."=$user)");
+                              $all_ldap_opts['ldap_base_dn'][$idx],
+                              "(". 
$all_ldap_opts['ldap_dn_search_attrib'][$idx] ."=$user)");
 
           if (@ldap_count_entries($ldap, $res) == 1)
           {
-            authLdapDebug("authLdapAction: Found one entry using ".
-                          "$ldap_dn_search_attrib");
+            authLdapDebug("authLdapAction: Found one entry using '".
+                          $all_ldap_opts['ldap_dn_search_attrib'][$idx]."'");
             $entries = ldap_get_entries($ldap, $res);
             $dn = $entries[0]["dn"];
             $user_search = "distinguishedName=" . $dn;
           }
           else
           {
-            authLdapDebug("authLdapAction: Didn't find entry using ".
-                          "$ldap_dn_search_attrib");
+            authLdapDebug("authLdapAction: Didn't find entry using '".
+                          $all_ldap_opts['ldap_dn_search_attrib'][$idx]."'");
           }
-          authLdapDebug("authLdapAction: base_dn $base_dn user $user ".
-                        "dn $dn");
+          authLdapDebug("authLdapAction: base_dn '".
+                        $all_ldap_opts['ldap_base_dn'][$idx].
+                        "' user $user dn $dn");
         }
       }
       else
       {
         // construct dn for user
-        $user_search = $all_ldap_user_attrib[$idx] . "=" . $user;
-        $dn = $user_search . "," . $base_dn;
+        $user_search = $all_ldap_opts['ldap_user_attrib'][$idx] . "=" . $user;
+        $dn = $user_search . "," . $all_ldap_opts['ldap_base_dn'][$idx];
 
-        authLdapDebug("authLdapAction: Constructed dn $dn and ".
-                      "user_search $user_search using ".
-                      "\$ldap_user_attrib");
+        authLdapDebug("authLdapAction: Constructed dn '$dn' and ".
+                      "user_search '$user_search' using '".
+                      $all_ldap_opts['ldap_user_attrib'][$idx]."'");
       }
 
-      $res = $callback($ldap, $base_dn, $dn, $user_search, $user, $object);
+      foreach ($config_items as $item)
+      {
+        if (isset($all_ldap_opts[$item][$idx]))
+        {
+          $object['config'][$item] = $all_ldap_opts[$item][$idx];
+        }
+      }
+
+      $res = $callback($ldap, $all_ldap_opts['ldap_base_dn'][$idx], $dn,
+                       $user_search, $user, $object);
       if ($res)
       {
         return $res;
       }
 
-    } // foreach
+    } // if ($ldap)
 
     @ldap_unbind($ldap);
-  } // if ($ldap)
+  } // foreach
 }
 
 
@@ -216,23 +257,24 @@
 function authLdapGetEmailCallback(&$ldap, $base_dn, $dn, $user_search,
                                   $user, &$object)
 {
-  global $ldap_email_attrib;
+  $email_attrib = $object['config']['ldap_email_attrib'];
 
-  authLdapDebug("authLdapGetEmailCallback: base_dn $base_dn dn $dn ".
-                "user_search $user_search user $user");
+  authLdapDebug("authLdapGetEmailCallback: base_dn '$base_dn' dn '$dn' ".
+                "user_search '$user_search' user '$user'");
 
   if ($ldap && $base_dn && $dn && $user_search)
   {
-  $res = @ldap_read($ldap,
-                        $dn,
-                        "(objectclass=*)",
-                        array($ldap_email_attrib)
-                       );
+    $res = @ldap_read(
+                      $ldap,
+                      $dn,
+                      "(objectclass=*)",
+                      array(strtolower($email_attrib))
+                     );
     if (@ldap_count_entries($ldap, $res) > 0)
     {
       authLdapDebug("authLdapGetEmailCallback: search successful");
       $entries = ldap_get_entries($ldap, $res);
-      $object['email'] = $entries[0][$ldap_email_attrib][0];
+      $object['email'] = $entries[0][strtolower($email_attrib)][0];
 
       authLdapDebug("authLdapGetEmailCallback: email is '".
                     $object['email']."'");
@@ -243,6 +285,7 @@
   return 0;
 }
 
+
 /* authValidateUser($user, $pass)
  * 
  * Checks if the specified username/password pair are valid
@@ -291,19 +334,20 @@
 function authValidateUserCallback(&$ldap, $base_dn, $dn, $user_search,
                                   $user, &$object)
 {
-  global $ldap_filter;
+  authLdapDebug("authValidateUserCallback: base_dn '$base_dn' ".
+                "dn '$dn' user '$user'");
 
-  authLdapDebug("authValidateUserCallback: base_dn $base_dn dn $dn user 
$user");
-
   $pass = $object['pass'];
 
   // try an authenticated bind
   // use this to confirm that the user/password pair
   if ($dn && @ldap_bind($ldap, $dn, $pass))
   {
+    $filter = $object['config']['ldap_filter'];
+
     // however if there is a filter check that the
     // user is part of the group defined by the filter
-    if (! $ldap_filter)
+    if (! $filter)
     {
       authLdapDebug("authValidateUserCallback: Successful authenticated ".
                     "bind with no \$ldap_filter");
@@ -312,11 +356,11 @@
     else
     {
       authLdapDebug("authValidateUserCallback: Successful authenticated ".
-                    "bind checking $ldap_filter");
+                    "bind checking '$filter'");
 
       $res = @ldap_read($ldap,
                         $dn,
-                        "($ldap_filter)",
+                        "($filter)",
                         array()
                        );
       if (@ldap_count_entries($ldap, $res) > 0)
@@ -329,7 +373,7 @@
   }
   else
   {
-    authLdapDebug("authValidateUserCallback: Bind to $dn failed");
+    authLdapDebug("authValidateUserCallback: Bind to '$dn' failed");
   }
 
   if ($ldap_unbind_between_attempts)
@@ -341,6 +385,58 @@
   return 0;
 }
 
+
+/* authLdapCheckAdminGroupCallback(&$ldap, $base_dn, $dn, $user_search,
+                            $user, &$object)
+ * 
+ * Checks if the specified username is in an admin group
+ *
+ * &$ldap       - Reference to the LDAP object
+ * $base_dn     - The base DN
+ * $dn          - The user's DN
+ * $user_search - The LDAP filter to find the user
+ * $user        - The user name
+ * &$object     - Reference to the generic object
+ * 
+ * Returns:
+ *   0        - Not in the admin group
+ *   non-zero - In the admin group
+ */
+function authLdapCheckAdminGroupCallback(&$ldap, $base_dn, $dn, $user_search,
+                                         $user, &$object)
+{
+  $admin_group_dn = $object['config']['ldap_admin_group_dn'];
+  $group_member_attrib = $object['config']['ldap_group_member_attrib'];
+
+  authLdapDebug("authLdapCheckAdminGroupCallback: base_dn '$base_dn' ".
+                "dn '$dn' user_search '$user_search' user '$user'");
+
+  if ($ldap && $base_dn && $dn && $user_search)
+  {
+  $res = @ldap_read(
+                    $ldap,
+                    $dn,
+                    "(objectclass=*)",
+                    array(strtolower($group_member_attrib))
+                   );
+    if (@ldap_count_entries($ldap, $res) > 0)
+    {
+      authLdapDebug("authCheckAdminGroupCallback: search successful".
+                    " $group_member_attrib");
+      $entries = ldap_get_entries($ldap, $res);
+      foreach ($entries[0][strtolower($group_member_attrib)] as $group)
+      {
+        if (strcasecmp($group, $admin_group_dn) == 0)
+        {
+          return 1;
+        }
+      }
+    }
+  }
+  return 0;
+}
+
+
 /* authGetUserLevel($user)
  *
  * Determines the users access level
@@ -353,17 +449,32 @@
 function authGetUserLevel($user)
 {
   global $auth;
+  global $ldap_admin_group_dn;
+
   $admins = $auth['admin'];
   // User not logged in, user level '0'
   if (!isset($user))
   {
     return 0;
   }
+  
+  if ($ldap_admin_group_dn)
+  {
+    $res = authLdapAction("authLdapCheckAdminGroupCallback", $user, $object);
+    if ($res)
+    {
+      return 2;
+    }
+    else
+    {
+      return 1;
+    }
+  }
     
-  // Check if the user is can modify
-  for ($i = 0; $admins[$i]; $i++)
+  // Check if the user is an admin
+  foreach ($admins as $admin)
   {
-    if (strcasecmp($user, $admins[$i]) == 0)
+    if (strcasecmp($user, $admin) == 0)
     {
       return 2;
     }
@@ -373,6 +484,7 @@
   return 1;
 }
 
+
 /* authLdapDebug($message)
  *
  * Output LDAP debugging, if the configuration variable

Modified: mrbs/branches/datatables/web/functions.inc
===================================================================
--- mrbs/branches/datatables/web/functions.inc  2011-09-22 14:41:57 UTC (rev 
1996)
+++ mrbs/branches/datatables/web/functions.inc  2011-09-22 16:51:18 UTC (rev 
1997)
@@ -567,7 +567,7 @@
 // errors which "should never happen", not those caused by bad inputs.
 // If $need_header!=0 output the top of the page too, else assume the
 // caller did that. Alway outputs the bottom of the page and exits.
-function fatal_error($need_header, $message)
+function fatal_error($need_header, $message, $show_form_data = true)
 {
   global $simple_trailer, $weekstarts, $view_week_number, $strftime_format;
   
@@ -576,12 +576,22 @@
     print_header(0, 0, 0, 0, "");
   }
   error_log("MRBS: ".$message);
-  if (!empty($_GET))
-    error_log("MRBS GET: ".print_r($_GET, true));
-  if (!empty($_POST))
-    error_log("MRBS POST: ".print_r($_POST, true));
+
+  if ($show_form_data)
+  {
+    if (!empty($_GET))
+    {
+      error_log("MRBS GET: ".print_r($_GET, true));
+    }
+    if (!empty($_POST))
+    {
+      error_log("MRBS POST: ".print_r($_POST, true));
+    }
+  }
   if (!empty($_SESSION))
+  {
     error_log("MRBS SESSION: ".print_r($_SESSION, true));
+  }
   echo "<p>$message</p>";
   require_once "trailer.inc";
   exit;

Modified: mrbs/branches/datatables/web/systemdefaults.inc.php
===================================================================
--- mrbs/branches/datatables/web/systemdefaults.inc.php 2011-09-22 14:41:57 UTC 
(rev 1996)
+++ mrbs/branches/datatables/web/systemdefaults.inc.php 2011-09-22 16:51:18 UTC 
(rev 1997)
@@ -604,43 +604,77 @@
 $auth['db_ext']['password_format'] = 'md5';
 
 // 'auth_ldap' configuration settings
-// Where is the LDAP server
+
+// Many of the LDAP parameters can be specified as arrays, in order to
+// specify multiple LDAP directories to search within. Each item below
+// will specify whether the item can be specified as an array. If any
+// parameter is specified as an array, then EVERY array configuration
+// parameter must have the same number of elements. You can specify a
+// parameter as an array as in the following example:
+//
+// $ldap_host = array('localhost', 'otherhost.example.com');
+
+// Where is the LDAP server.
+// This can be an array.
 //$ldap_host = "localhost";
-// If you have a non-standard LDAP port, you can define it here
+
+// If you have a non-standard LDAP port, you can define it here.
+// This can be an array.
 //$ldap_port = 389;
-// If you do not want to use LDAP v3, change the following to false
+
+// If you do not want to use LDAP v3, change the following to false.
+// This can be an array.
 $ldap_v3 = true;
-// If you want to use TLS, change the following to true
+
+// If you want to use TLS, change the following to true.
+// This can be an array.
 $ldap_tls = false;
-// LDAP base distinguish name
-// See AUTHENTICATION for details of how check against multiple base dn's
+
+// LDAP base distinguish name.
+// This can be an array.
 //$ldap_base_dn = "ou=organizationalunit,dc=my-domain,dc=com";
+
 // Attribute within the base dn that contains the username
+// This can be an array.
 //$ldap_user_attrib = "uid";
+
 // If you need to search the directory to find the user's DN to bind
 // with, set the following to the attribute that holds the user's
 // "username". In Microsoft AD directories this is "sAMAccountName"
+// This can be an array.
 //$ldap_dn_search_attrib = "sAMAccountName";
+
 // If you need to bind as a particular user to do the search described
 // above, specify the DN and password in the variables below
+// These two parameters can be arrays.
 // $ldap_dn_search_dn = "cn=Search User,ou=Users,dc=some,dc=company";
 // $ldap_dn_search_password = "some-password";
 
 // 'auth_ldap' extra configuration for ldap configuration of who can use
 // the system
-// If it's set, the $ldap_filter will be combined with the value of
-// $ldap_user_attrib like this:
-//   (&($ldap_user_attrib=username)($ldap_filter))
-// After binding to check the password, this check is used to see that
-// they are a valid user of mrbs.
-//$ldap_filter = "mrbsuser=y";
+// If it's set, the $ldap_filter will be used to determine whether a
+// user will be granted access to MRBS
+// This can be an array.
+// An example for Microsoft AD:
+//$ldap_filter = "memberof=cn=whater,ou=whatver,dc=example,dc=com";
 
 // Set to TRUE to tell MRBS to look up a user's email address in LDAP.
 // Utilises $ldap_email_attrib below
 $ldap_get_user_email = FALSE;
 // The LDAP attribute which holds a user's email address
+// This can be an array.
 $ldap_email_attrib = 'mail';
 
+// The DN of the LDAP group that MRBS admins must be in. If this is defined
+// then the $auth["admin"] is not used.
+// This can be an array.
+// $ldap_admin_group_dn = 'cn=admins,ou=whoever,dc=example,dc=com';
+
+// The LDAP attribute that holds group membership details. Used with
+// $ldap_admin_group_dn, above.
+// This can be an array.
+$ldap_group_member_attrib = 'memberof';
+  
 // Set to TRUE if you want MRBS to call ldap_unbind() between successive
 // attempts to bind. Unbinding while still connected upsets some
 // LDAP servers


Property changes on: mrbs/branches/datatables/web/upgrade/5/pgsql.sql
___________________________________________________________________
Modified: svn:mergeinfo
   - /mrbs/branches/custom_entry_fields/web/upgrade/5/pgsql.sql:1374-1396
/mrbs/branches/datepicker/web/upgrade/5/pgsql.sql:1409-1416
/mrbs/branches/disabled_rooms/web/upgrade/5/pgsql.sql:1601-1634
/mrbs/branches/from_to_bookings/web/upgrade/5/pgsql.sql:1491-1587
/mrbs/branches/ics_attachments/web/upgrade/5/pgsql.sql:1652-1741
/mrbs/branches/only_unicode/web/upgrade/5/pgsql.sql:1747-1749
/mrbs/branches/provisional_bookings/web/upgrade/5/pgsql.sql:1242-1280
/mrbs/branches/provisional_bookings_new_style/web/upgrade/5/pgsql.sql:1407-1570
/mrbs/trunk/web/upgrade/5/pgsql.sql:1863-1994
   + /mrbs/branches/custom_entry_fields/web/upgrade/5/pgsql.sql:1374-1396
/mrbs/branches/datepicker/web/upgrade/5/pgsql.sql:1409-1416
/mrbs/branches/disabled_rooms/web/upgrade/5/pgsql.sql:1601-1634
/mrbs/branches/from_to_bookings/web/upgrade/5/pgsql.sql:1491-1587
/mrbs/branches/ics_attachments/web/upgrade/5/pgsql.sql:1652-1741
/mrbs/branches/only_unicode/web/upgrade/5/pgsql.sql:1747-1749
/mrbs/branches/provisional_bookings/web/upgrade/5/pgsql.sql:1242-1280
/mrbs/branches/provisional_bookings_new_style/web/upgrade/5/pgsql.sql:1407-1570
/mrbs/trunk/web/upgrade/5/pgsql.sql:1863-1996

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.


------------------------------------------------------------------------------
All the data continuously generated in your IT infrastructure contains a
definitive record of customers, application performance, security
threats, fraudulent activity and more. Splunk takes this data and makes
sense of it. Business sense. IT sense. Common sense.
http://p.sf.net/sfu/splunk-d2dcopy1
_______________________________________________
Mrbs-commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mrbs-commits

Reply via email to