iTx Technologies offre gratuitement
cet espace pour SugarCRM !

title

Body

[fermer]

/soap/ -> SoapSugarUsers.php (source)

   1  <?php
   2  if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
   3  /*********************************************************************************
   4   * SugarCRM is a customer relationship management program developed by
   5   * SugarCRM, Inc. Copyright (C) 2004 - 2009 SugarCRM Inc.
   6   * 
   7   * This program is free software; you can redistribute it and/or modify it under
   8   * the terms of the GNU General Public License version 3 as published by the
   9   * Free Software Foundation with the addition of the following permission added
  10   * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
  11   * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
  12   * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
  13   * 
  14   * This program is distributed in the hope that it will be useful, but WITHOUT
  15   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  16   * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
  17   * details.
  18   * 
  19   * You should have received a copy of the GNU General Public License along with
  20   * this program; if not, see http://www.gnu.org/licenses or write to the Free
  21   * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  22   * 02110-1301 USA.
  23   * 
  24   * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
  25   * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
  26   * 
  27   * The interactive user interfaces in modified source and object code versions
  28   * of this program must display Appropriate Legal Notices, as required under
  29   * Section 5 of the GNU General Public License version 3.
  30   * 
  31   * In accordance with Section 7(b) of the GNU General Public License version 3,
  32   * these Appropriate Legal Notices must retain the display of the "Powered by
  33   * SugarCRM" logo. If the display of the logo is not reasonably feasible for
  34   * technical reasons, the Appropriate Legal Notices must display the words
  35   * "Powered by SugarCRM".
  36   ********************************************************************************/
  37  require_once ('soap/SoapHelperFunctions.php');
  38  require_once ('soap/SoapTypes.php');
  39  
  40  
  41  
  42  
  43  
  44  /*************************************************************************************
  45  
  46  THIS IS FOR SUGARCRM USERS
  47  
  48  
  49  *************************************************************************************/
  50  $disable_date_format = true;
  51  
  52  $server->register(
  53      'is_user_admin',
  54      array('session'=>'xsd:string'),
  55      array('return'=>'xsd:int'),
  56      $NAMESPACE);
  57  
  58  /**
  59   * Return if the user is an admin or not
  60   *
  61   * @param String $session -- Session ID returned by a previous call to login.
  62   * @return int 1 or 0 depending on if the user is an admin
  63   */
  64  function is_user_admin($session){
  65      if(validate_authenticated($session)){
  66          global $current_user;
  67          return is_admin($current_user);
  68  
  69      }else{
  70          return 0;
  71      }
  72  }
  73  
  74  
  75  $server->register(
  76          'login',
  77          array('user_auth'=>'tns:user_auth', 'application_name'=>'xsd:string'),
  78          array('return'=>'tns:set_entry_result'),
  79          $NAMESPACE);
  80  
  81  /**
  82   * Log the user into the application
  83   *
  84   * @param UserAuth array $user_auth -- Set user_name and password (password needs to be
  85   *      in the right encoding for the type of authentication the user is setup for.  For Base
  86   *      sugar validation, password is the MD5 sum of the plain text password.
  87   * @param String $application -- The name of the application you are logging in from.  (Currently unused).
  88   * @return Array(session_id, error) -- session_id is the id of the session that was
  89   *      created.  Error is set if there was any error during creation.
  90   */
  91  function login($user_auth, $application){
  92      global $sugar_config, $system_config;
  93  
  94      $error = new SoapError();
  95      $user = new User();
  96      $success = false;
  97      //rrs
  98          $system_config = new Administration();
  99      $system_config->retrieveSettings('system');
 100      $authController = new AuthenticationController((!empty($sugar_config['authenticationClass'])? $sugar_config['authenticationClass'] : 'SugarAuthenticate'));
 101      //rrs
 102      $isLoginSuccess = $authController->login($user_auth['user_name'], $user_auth['password'], array('passwordEncrypted' => true));
 103      $usr_id=$user->retrieve_user_id($user_auth['user_name']);
 104      if($usr_id) {
 105          $user->retrieve($usr_id);    
 106      }
 107          
 108      if ($isLoginSuccess) {
 109          if ($_SESSION['hasExpiredPassword'] =='1') {
 110              $error->set_error('password_expired');
 111              $GLOBALS['log']->fatal('password expired for user ' . $user_auth['user_name']);
 112              LogicHook::initialize();
 113              $GLOBALS['logic_hook']->call_custom_logic('Users', 'login_failed');
 114              return array('id'=>-1, 'error'=>$error);
 115          } // if
 116          if(!empty($user) && !empty($user->id) && !$user->is_group) {
 117              $success = true;
 118              global $current_user;
 119              $current_user = $user;
 120          } // if
 121      } else if($usr_id && isset($user->user_name) && ($user->getPreference('lockout') == '1')) {
 122              $error->set_error('lockout_reached');
 123              $GLOBALS['log']->fatal('Lockout reached for user ' . $user_auth['user_name']);
 124              LogicHook::initialize();
 125              $GLOBALS['logic_hook']->call_custom_logic('Users', 'login_failed');
 126              return array('id'=>-1, 'error'=>$error);
 127      } else if(function_exists('mcrypt_cbc')){
 128          $password = decrypt_string($user_auth['password']);
 129          if($authController->login($user_auth['user_name'], $password) && isset($_SESSION['authenticated_user_id'])){
 130              $success = true;
 131          } // if
 132      } // else if
 133  
 134      if($success){
 135          session_start();
 136          global $current_user;
 137          //$current_user = $user;
 138          login_success();
 139          $current_user->loadPreferences();
 140          $_SESSION['is_valid_session']= true;
 141          $_SESSION['ip_address'] = query_client_ip();
 142          $_SESSION['user_id'] = $current_user->id;
 143          $_SESSION['type'] = 'user';
 144          $_SESSION['avail_modules']= get_user_module_list($current_user);
 145          $_SESSION['authenticated_user_id'] = $current_user->id;
 146          $_SESSION['unique_key'] = $sugar_config['unique_key'];
 147  
 148          $current_user->call_custom_logic('after_login');
 149          return array('id'=>session_id(), 'error'=>$error);
 150      }
 151      $error->set_error('invalid_login');
 152      $GLOBALS['log']->fatal('SECURITY: User authentication for '. $user_auth['user_name']. ' failed');
 153      LogicHook::initialize();
 154      $GLOBALS['logic_hook']->call_custom_logic('Users', 'login_failed');
 155      return array('id'=>-1, 'error'=>$error);
 156  
 157  }
 158  
 159  //checks if the soap server and client are running on the same machine
 160  $server->register(
 161          'is_loopback',
 162          array(),
 163          array('return'=>'xsd:int'),
 164          $NAMESPACE);
 165  
 166  /**
 167   * Check to see if the soap server and client are on the same machine.
 168   * We don't allow a server to sync to itself.
 169   *
 170   * @return true -- if the SOAP server and client are on the same machine
 171   * @return false -- if the SOAP server and client are not on the same machine.
 172   */
 173  function is_loopback(){
 174      if(query_client_ip() == $_SERVER['SERVER_ADDR'])
 175          return 1;
 176      return 0;
 177  }
 178  
 179  /**
 180   * Validate the provided session information is correct and current.  Load the session.
 181   *
 182   * @param String $session_id -- The session ID that was returned by a call to login.
 183   * @return true -- If the session is valid and loaded.
 184   * @return false -- if the session is not valid.
 185   */
 186  function validate_authenticated($session_id){
 187      if(!empty($session_id)){
 188          session_id($session_id);
 189          session_start();
 190  
 191          if(!empty($_SESSION['is_valid_session']) && is_valid_ip_address('ip_address') && $_SESSION['type'] == 'user'){
 192  
 193              global $current_user;
 194              
 195              $current_user = new User();
 196              $current_user->retrieve($_SESSION['user_id']);
 197              login_success();
 198              return true;
 199          }
 200  
 201          session_destroy();
 202      }
 203      LogicHook::initialize();
 204      $GLOBALS['log']->fatal('SECURITY: The session ID is invalid');
 205      $GLOBALS['logic_hook']->call_custom_logic('Users', 'login_failed');
 206      return false;
 207  }
 208  
 209  /**
 210   * Use the same logic as in SugarAuthenticate to validate the ip address
 211   *
 212   * @param string $session_var
 213   * @return bool - true if the ip address is valid, false otherwise.
 214   */
 215  function is_valid_ip_address($session_var){
 216      global $sugar_config;
 217      // grab client ip address
 218      $clientIP = query_client_ip();
 219      $classCheck = 0;
 220      // check to see if config entry is present, if not, verify client ip
 221      if (!isset ($sugar_config['verify_client_ip']) || $sugar_config['verify_client_ip'] == true) {
 222          // check to see if we've got a current ip address in $_SESSION
 223          // and check to see if the session has been hijacked by a foreign ip
 224          if (isset ($_SESSION[$session_var])) {
 225              $session_parts = explode(".", $_SESSION[$session_var]);
 226              $client_parts = explode(".", $clientIP);
 227              if(count($session_parts) < 4) {
 228                   $classCheck = 0;
 229              }else {
 230                  // match class C IP addresses
 231                  for ($i = 0; $i < 3; $i ++) {
 232                      if ($session_parts[$i] == $client_parts[$i]) {
 233                          $classCheck = 1;
 234                              continue;
 235                      } else {
 236                          $classCheck = 0;
 237                          break;
 238                          }
 239                      }
 240                  }
 241                  // we have a different IP address
 242                  if ($_SESSION[$session_var] != $clientIP && empty ($classCheck)) {
 243                      $GLOBALS['log']->fatal("IP Address mismatch: SESSION IP: {$_SESSION[$session_var]} CLIENT IP: {$clientIP}");
 244                      return false;
 245                  }
 246              } else {
 247                  return false;
 248              }
 249      }
 250      return true;
 251  }
 252  
 253  $server->register(
 254      'seamless_login',
 255      array('session'=>'xsd:string'),
 256      array('return'=>'xsd:int'),
 257      $NAMESPACE);
 258  
 259  /**
 260   * Perform a seamless login.  This is used internally during the sync process.
 261   *
 262   * @param String $session -- Session ID returned by a previous call to login.
 263   * @return true -- if the session was authenticated
 264   * @return false -- if the session could not be authenticated
 265   */
 266  function seamless_login($session){
 267          if(!validate_authenticated($session)){
 268              return 0;
 269          }
 270          $_SESSION['seamless_login'] = true;
 271          return 1;
 272  }
 273  
 274  $server->register(
 275      'get_entry_list',
 276      array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'query'=>'xsd:string', 'order_by'=>'xsd:string','offset'=>'xsd:int', 'select_fields'=>'tns:select_fields', 'max_results'=>'xsd:int', 'deleted'=>'xsd:int'),
 277      array('return'=>'tns:get_entry_list_result'),
 278      $NAMESPACE);
 279  
 280  /**
 281   * Retrieve a list of beans.  This is the primary method for getting list of SugarBeans from Sugar using the SOAP API.
 282   *
 283   * @param String $session -- Session ID returned by a previous call to login.
 284   * @param String $module_name -- The name of the module to return records from.  This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
 285   * @param String $query -- SQL where clause without the word 'where'
 286   * @param String $order_by -- SQL order by clause without the phrase 'order by'
 287   * @param String $offset -- The record offset to start from.
 288   * @param Array  $select_fields -- A list of the fields to be included in the results. This optional parameter allows for only needed fields to be retrieved.
 289   * @param String $max_results -- The maximum number of records to return.  The default is the sugar configuration value for 'list_max_entries_per_page'
 290   * @param Number $deleted -- false if deleted records should not be include, true if deleted records should be included.
 291   * @return Array 'result_count' -- The number of records returned
 292   *               'next_offset' -- The start of the next page (This will always be the previous offset plus the number of rows returned.  It does not indicate if there is additional data unless you calculate that the next_offset happens to be closer than it should be.
 293   *               'field_list' -- The vardef information on the selected fields.
 294   *                      Array -- 'field'=>  'name' -- the name of the field
 295   *                                          'type' -- the data type of the field
 296   *                                          'label' -- the translation key for the label of the field
 297   *                                          'required' -- Is the field required?
 298   *                                          'options' -- Possible values for a drop down field
 299   *               'entry_list' -- The records that were retrieved
 300   *               'error' -- The SOAP error, if any
 301   */
 302  function get_entry_list($session, $module_name, $query, $order_by,$offset, $select_fields, $max_results, $deleted ){
 303      global  $beanList, $beanFiles;
 304      $error = new SoapError();
 305      if(!validate_authenticated($session)){
 306          $error->set_error('invalid_login');
 307          return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
 308      }
 309      $using_cp = false;
 310      if($module_name == 'CampaignProspects'){
 311          $module_name = 'Prospects';
 312          $using_cp = true;
 313      }
 314      if(empty($beanList[$module_name])){
 315          $error->set_error('no_module');
 316          return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
 317      }
 318      global $current_user;
 319      if(!check_modules_access($current_user, $module_name, 'read')){
 320          $error->set_error('no_access');
 321          return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
 322      }
 323  
 324      // If the maximum number of entries per page was specified, override the configuration value.
 325      if($max_results > 0){
 326          global $sugar_config;
 327          $sugar_config['list_max_entries_per_page'] = $max_results;
 328      }
 329  
 330  
 331      $class_name = $beanList[$module_name];
 332      require_once($beanFiles[$class_name]);
 333      $seed = new $class_name();
 334      if(! ($seed->ACLAccess('Export') && $seed->ACLAccess('list')))
 335      {
 336          $error->set_error('no_access');
 337          return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
 338      }
 339      if($query == ''){
 340          $where = '';
 341      }
 342      if($offset == '' || $offset == -1){
 343          $offset = 0;
 344      }
 345      if($using_cp){
 346          $response = $seed->retrieveTargetList($query, $select_fields, $offset,-1,-1,$deleted);
 347      }else{
 348         $response = $seed->get_list($order_by, $query, $offset,-1,-1,$deleted,true);
 349      }
 350      $list = $response['list'];
 351  
 352  
 353      $output_list = array();
 354  
 355      // retrieve the vardef information on the bean's fields.
 356      $field_list = array();
 357      foreach($list as $value)
 358      {
 359          if(isset($value->emailAddress)){
 360              $value->emailAddress->handleLegacyRetrieve($value);
 361          }
 362          $value->fill_in_additional_detail_fields();
 363          $output_list[] = get_return_value($value, $module_name);
 364          if(empty($field_list)){
 365              $field_list = get_field_list($value);
 366          }
 367      }
 368  
 369      // Filter the search results to only include the requested fields.
 370      $output_list = filter_return_list($output_list, $select_fields, $module_name);
 371  
 372      // Filter the list of fields to only include information on the requested fields.
 373      $field_list = filter_return_list($field_list,$select_fields, $module_name);
 374  
 375      // Calculate the offset for the start of the next page
 376      $next_offset = $offset + sizeof($output_list);
 377  
 378      return array('result_count'=>sizeof($output_list), 'next_offset'=>$next_offset,'field_list'=>$field_list, 'entry_list'=>$output_list, 'error'=>$error->get_soap_array());
 379  }
 380  
 381  $server->register(
 382      'get_entry',
 383      array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'id'=>'xsd:string', 'select_fields'=>'tns:select_fields'),
 384      array('return'=>'tns:get_entry_result'),
 385      $NAMESPACE);
 386  
 387  /**
 388   * Retrieve a single SugarBean based on ID.
 389   *
 390   * @param String $session -- Session ID returned by a previous call to login.
 391   * @param String $module_name -- The name of the module to return records from.  This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
 392   * @param String $id -- The SugarBean's ID value.
 393   * @param Array  $select_fields -- A list of the fields to be included in the results. This optional parameter allows for only needed fields to be retrieved.
 394   * @return unknown
 395   */
 396  function get_entry($session, $module_name, $id,$select_fields ){
 397      return get_entries($session, $module_name, array($id), $select_fields);
 398  }
 399  
 400  $server->register(
 401      'get_entries',
 402      array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'ids'=>'tns:select_fields', 'select_fields'=>'tns:select_fields'),
 403      array('return'=>'tns:get_entry_result'),
 404      $NAMESPACE);
 405  
 406  /**
 407   * Retrieve a list of SugarBean's based on provided IDs.
 408   *
 409   * @param String $session -- Session ID returned by a previous call to login.
 410   * @param String $module_name -- The name of the module to return records from.  This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
 411   * @param Array $ids -- An array of SugarBean IDs.
 412   * @param Array $select_fields -- A list of the fields to be included in the results. This optional parameter allows for only needed fields to be retrieved.
 413   * @return Array 'field_list' -- Var def information about the returned fields
 414   *               'entry_list' -- The records that were retrieved
 415   *               'error' -- The SOAP error, if any
 416   */
 417  function get_entries($session, $module_name, $ids,$select_fields ){
 418      global  $beanList, $beanFiles;
 419      $error = new SoapError();
 420      $field_list = array();
 421      $output_list = array();
 422      if(!validate_authenticated($session)){
 423          $error->set_error('invalid_login');
 424          return array('field_list'=>$field_list, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
 425      }
 426      $using_cp = false;
 427      if($module_name == 'CampaignProspects'){
 428          $module_name = 'Prospects';
 429          $using_cp = true;
 430      }
 431      if(empty($beanList[$module_name])){
 432          $error->set_error('no_module');
 433          return array('field_list'=>$field_list, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
 434      }
 435      global $current_user;
 436      if(!check_modules_access($current_user, $module_name, 'read')){
 437          $error->set_error('no_access');
 438          return array('field_list'=>$field_list, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
 439      }
 440  
 441      $class_name = $beanList[$module_name];
 442      require_once($beanFiles[$class_name]);
 443  
 444      //todo can modify in there to call bean->get_list($order_by, $where, 0, -1, -1, $deleted);
 445      //that way we do not have to call retrieve for each bean
 446      //perhaps also add a select_fields to this, so we only get the fields we need
 447      //and not do a select *
 448      foreach($ids as $id){
 449          $seed = new $class_name();
 450  
 451      if($using_cp){
 452          $seed = $seed->retrieveTarget($id);
 453      }else{
 454          if ($seed->retrieve($id) == null)
 455              $seed->deleted = 1;
 456      }
 457      
 458      if ($seed->deleted == 1) {
 459          $list = array();
 460          $list[] = array('name'=>'warning', 'value'=>'Access to this object is denied since it has been deleted or does not exist');
 461          $list[] = array('name'=>'deleted', 'value'=>'1');
 462          $output_list[] = Array('id'=>$id,
 463                                  'module_name'=> $module_name,
 464                                  'name_value_list'=>$list,
 465                                  );
 466          continue;
 467      }
 468      if(! $seed->ACLAccess('DetailView')){
 469          $error->set_error('no_access');
 470          return array('field_list'=>$field_list, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
 471      }
 472  
 473  
 474  
 475  
 476  
 477  
 478  
 479          $output_list[] = get_return_value($seed, $module_name);
 480  
 481  
 482  
 483  
 484          if(empty($field_list)){
 485                  $field_list = get_field_list($seed);
 486  
 487          }
 488      }
 489  
 490          $output_list = filter_return_list($output_list, $select_fields, $module_name);
 491          $field_list = filter_field_list($field_list,$select_fields, $module_name);
 492  
 493      return array( 'field_list'=>$field_list, 'entry_list'=>$output_list, 'error'=>$error->get_soap_array());
 494  }
 495  
 496  $server->register(
 497      'set_entry',
 498      array('session'=>'xsd:string', 'module_name'=>'xsd:string',  'name_value_list'=>'tns:name_value_list'),
 499      array('return'=>'tns:set_entry_result'),
 500      $NAMESPACE);
 501  
 502  /**
 503   * Update or create a single SugarBean.
 504   *
 505   * @param String $session -- Session ID returned by a previous call to login.
 506   * @param String $module_name -- The name of the module to return records from.  This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
 507   * @param Array $name_value_list -- The keys of the array are the SugarBean attributes, the values of the array are the values the attributes should have.
 508   * @return Array    'id' -- the ID of the bean that was written to (-1 on error)
 509   *                  'error' -- The SOAP error if any.
 510   */
 511  function set_entry($session,$module_name, $name_value_list){
 512      global  $beanList, $beanFiles;
 513  
 514      $error = new SoapError();
 515      if(!validate_authenticated($session)){
 516          $error->set_error('invalid_login');
 517          return array('id'=>-1, 'error'=>$error->get_soap_array());
 518      }
 519      if(empty($beanList[$module_name])){
 520          $error->set_error('no_module');
 521          return array('id'=>-1, 'error'=>$error->get_soap_array());
 522      }
 523      global $current_user;
 524      if(!check_modules_access($current_user, $module_name, 'write')){
 525          $error->set_error('no_access');
 526          return array('id'=>-1, 'error'=>$error->get_soap_array());
 527      }
 528  
 529      $class_name = $beanList[$module_name];
 530      require_once($beanFiles[$class_name]);
 531      $seed = new $class_name();
 532  
 533      foreach($name_value_list as $value){
 534          if($value['name'] == 'id'){
 535              $seed->retrieve($value['value']);
 536              break;
 537          }
 538      }
 539      foreach($name_value_list as $value){
 540          $GLOBALS['log']->debug($value['name']." : ".$value['value']);
 541          $seed->$value['name'] = $value['value'];
 542      }
 543      if(! $seed->ACLAccess('Save') || ($seed->deleted == 1  &&  !$seed->ACLAccess('Delete')))
 544      {
 545          $error->set_error('no_access');
 546          return array('id'=>-1, 'error'=>$error->get_soap_array());
 547      }
 548      $seed->save();
 549      if($seed->deleted == 1){
 550              $seed->mark_deleted($seed->id);
 551      }
 552      return array('id'=>$seed->id, 'error'=>$error->get_soap_array());
 553  
 554  }
 555  
 556  $server->register(
 557      'set_entries',
 558      array('session'=>'xsd:string', 'module_name'=>'xsd:string',  'name_value_lists'=>'tns:name_value_lists'),
 559      array('return'=>'tns:set_entries_result'),
 560      $NAMESPACE);
 561  
 562  /**
 563   * Update or create a list of SugarBeans
 564   *
 565   * @param String $session -- Session ID returned by a previous call to login.
 566   * @param String $module_name -- The name of the module to return records from.  This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
 567   * @param Array $name_value_lists -- Array of Bean specific Arrays where the keys of the array are the SugarBean attributes, the values of the array are the values the attributes should have.
 568   * @return Array    'ids' -- Array of the IDs of the beans that was written to (-1 on error)
 569   *                  'error' -- The SOAP error if any.
 570   */
 571  function set_entries($session,$module_name, $name_value_lists){
 572      $error = new SoapError();
 573  
 574      if(!validate_authenticated($session)){
 575          $error->set_error('invalid_login');
 576  
 577          return array(
 578              'ids' => array(),
 579              'error' => $error->get_soap_array()
 580          );
 581      }
 582  
 583      return handle_set_entries($module_name, $name_value_lists, FALSE);
 584  }
 585  
 586  /*
 587  NOTE SPECIFIC CODE
 588  */
 589  $server->register(
 590          'set_note_attachment',
 591          array('session'=>'xsd:string','note'=>'tns:note_attachment'),
 592          array('return'=>'tns:set_entry_result'),
 593          $NAMESPACE);
 594  
 595  /**
 596   * Add or replace the attachment on a Note.
 597   *
 598   * @param String $session -- Session ID returned by a previous call to login.
 599   * @param Binary $note -- The flie contents of the attachment.
 600   * @return Array 'id' -- The ID of the new note or -1 on error
 601   *               'error' -- The SOAP error if any.
 602   */
 603  function set_note_attachment($session,$note)
 604  {
 605  
 606      $error = new SoapError();
 607      if(!validate_authenticated($session)){
 608          $error->set_error('invalid_login');
 609          return array('id'=>-1, 'error'=>$error->get_soap_array());
 610      }
 611  
 612      require_once ('modules/Notes/NoteSoap.php');
 613      $ns = new NoteSoap();
 614      return array('id'=>$ns->saveFile($note), 'error'=>$error->get_soap_array());
 615  
 616  }
 617  
 618  $server->register(
 619      'get_note_attachment',
 620      array('session'=>'xsd:string', 'id'=>'xsd:string'),
 621      array('return'=>'tns:return_note_attachment'),
 622      $NAMESPACE);
 623  
 624  /**
 625   * Retrieve an attachment from a note
 626   * @param String $session -- Session ID returned by a previous call to login.
 627   * @param Binary $note -- The flie contents of the attachment.
 628   * @return Array 'id' -- The ID of the new note or -1 on error
 629   *               'error' -- The SOAP error if any.
 630   *
 631   * @param String $session -- Session ID returned by a previous call to login.
 632   * @param String $id -- The ID of the appropriate Note.
 633   * @return Array 'note_attachment' -- Array String 'id' -- The ID of the Note containing the attachment
 634   *                                          String 'filename' -- The file name of the attachment
 635   *                                          Binary 'file' -- The binary contents of the file.
 636   *               'error' -- The SOAP error if any.
 637   */
 638  function get_note_attachment($session,$id)
 639  {
 640      $error = new SoapError();
 641      if(!validate_authenticated($session)){
 642          $error->set_error('invalid_login');
 643          return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
 644      }
 645      
 646      $note = new Note();
 647  
 648      $note->retrieve($id);
 649      if(!$note->ACLAccess('DetailView')){
 650          $error->set_error('no_access');
 651          return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
 652      }
 653      require_once ('modules/Notes/NoteSoap.php');
 654      $ns = new NoteSoap();
 655      if(!isset($note->filename)){
 656          $note->filename = '';
 657      }
 658      $file= $ns->retrieveFile($id,$note->filename);
 659      if($file == -1){
 660          $error->set_error('no_file');
 661          $file = '';
 662      }
 663  
 664      return array('note_attachment'=>array('id'=>$id, 'filename'=>$note->filename, 'file'=>$file), 'error'=>$error->get_soap_array());
 665  
 666  }
 667  $server->register(
 668      'relate_note_to_module',
 669      array('session'=>'xsd:string', 'note_id'=>'xsd:string', 'module_name'=>'xsd:string', 'module_id'=>'xsd:string'),
 670      array('return'=>'tns:error_value'),
 671      $NAMESPACE);
 672  
 673  /**
 674   * Attach a note to another bean.  Once you have created a note to store an
 675   * attachment, the note needs to be related to the bean.
 676   *
 677   * @param String $session -- Session ID returned by a previous call to login.
 678   * @param String $note_id -- The ID of the note that you want to associate with a bean
 679   * @param String $module_name -- The name of the module to return records from.  This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
 680   * @param String $module_id -- The ID of the bean that you want to associate the note with
 681   * @return no error for success, error for failure
 682   */
 683  function relate_note_to_module($session,$note_id, $module_name, $module_id){
 684      global  $beanList, $beanFiles;
 685      $error = new SoapError();
 686      if(!validate_authenticated($session)){
 687          $error->set_error('invalid_login');
 688          return $error->get_soap_array();
 689      }
 690      if(empty($beanList[$module_name])){
 691          $error->set_error('no_module');
 692          return $error->get_soap_array();
 693      }
 694      global $current_user;
 695      if(!check_modules_access($current_user, $module_name, 'read')){
 696          $error->set_error('no_access');
 697          return $error->get_soap_array();
 698      }
 699      $class_name = $beanList['Notes'];
 700      require_once($beanFiles[$class_name]);
 701      $seed = new $class_name();
 702      $seed->retrieve($note_id);
 703      if(!$seed->ACLAccess('ListView')){
 704          $error->set_error('no_access');
 705          return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
 706      }
 707  
 708      if($module_name != 'Contacts'){
 709          $seed->parent_type=$module_name;
 710          $seed->parent_id = $module_id;
 711  
 712      }else{
 713  
 714          $seed->contact_id=$module_id;
 715  
 716      }
 717  
 718      $seed->save();
 719  
 720      return $error->get_soap_array();
 721  
 722  }
 723  $server->register(
 724      'get_related_notes',
 725      array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'module_id'=>'xsd:string', 'select_fields'=>'tns:select_fields'),
 726      array('return'=>'tns:get_entry_result'),
 727      $NAMESPACE);
 728  
 729  /**
 730   * Retrieve the collection of notes that are related to a bean.
 731   *
 732   * @param String $session -- Session ID returned by a previous call to login.
 733   * @param String $module_name -- The name of the module to return records from.  This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
 734   * @param String $module_id -- The ID of the bean that you want to associate the note with
 735   * @param Array  $select_fields -- A list of the fields to be included in the results. This optional parameter allows for only needed fields to be retrieved.
 736   * @return Array    'result_count' -- The number of records returned (-1 on error)
 737   *                  'next_offset' -- The start of the next page (This will always be the previous offset plus the number of rows returned.  It does not indicate if there is additional data unless you calculate that the next_offset happens to be closer than it should be.
 738   *                  'field_list' -- The vardef information on the selected fields.
 739   *                  'entry_list' -- The records that were retrieved
 740   *                  'error' -- The SOAP error, if any
 741   */
 742  function get_related_notes($session,$module_name, $module_id, $select_fields){
 743      global  $beanList, $beanFiles;
 744      $error = new SoapError();
 745      if(!validate_authenticated($session)){
 746          $error->set_error('invalid_login');
 747          return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
 748      }
 749      if(empty($beanList[$module_name])){
 750          $error->set_error('no_module');
 751          return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
 752      }
 753      global $current_user;
 754      if(!check_modules_access($current_user, $module_name, 'read')){
 755          $error->set_error('no_access');
 756          return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
 757      }
 758  
 759      $class_name = $beanList[$module_name];
 760      require_once($beanFiles[$class_name]);
 761      $seed = new $class_name();
 762      $seed->retrieve($module_id);
 763      if(!$seed->ACLAccess('DetailView')){
 764          $error->set_error('no_access');
 765          return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
 766      }
 767      $list = $seed->get_linked_beans('notes','Note', array(), 0, -1, 0);
 768  
 769      $output_list = Array();
 770      $field_list = Array();
 771      foreach($list as $value)
 772      {
 773          $output_list[] = get_return_value($value, 'Notes');
 774          if(empty($field_list))
 775          {
 776              $field_list = get_field_list($value);
 777          }
 778      }
 779      $output_list = filter_return_list($output_list, $select_fields, $module_name);
 780      $field_list = filter_field_list($field_list,$select_fields, $module_name);
 781  
 782      return array('result_count'=>sizeof($output_list), 'next_offset'=>0,'field_list'=>$field_list, 'entry_list'=>$output_list, 'error'=>$error->get_soap_array());
 783  }
 784  
 785  $server->register(
 786          'logout',
 787          array('session'=>'xsd:string'),
 788          array('return'=>'tns:error_value'),
 789          $NAMESPACE);
 790  
 791  /**
 792   * Log out of the session.  This will destroy the session and prevent other's from using it.
 793   *
 794   * @param String $session -- Session ID returned by a previous call to login.
 795   * @return Empty error on success, Error on failure
 796   */
 797  function logout($session){
 798      global $current_user;
 799  
 800      $error = new SoapError();
 801      LogicHook::initialize();
 802      if(validate_authenticated($session)){
 803          $current_user->call_custom_logic('before_logout');
 804          session_destroy();
 805          $GLOBALS['logic_hook']->call_custom_logic('Users', 'after_logout');
 806          return $error->get_soap_array();
 807      }
 808      $error->set_error('no_session');
 809      $GLOBALS['logic_hook']->call_custom_logic('Users', 'after_logout');
 810      return $error->get_soap_array();
 811  }
 812  
 813  $server->register(
 814      'get_module_fields',
 815      array('session'=>'xsd:string', 'module_name'=>'xsd:string'),
 816      array('return'=>'tns:module_fields'),
 817      $NAMESPACE);
 818  
 819  /**
 820   * Retrieve vardef information on the fields of the specified bean.
 821   *
 822   * @param String $session -- Session ID returned by a previous call to login.
 823   * @param String $module_name -- The name of the module to return records from.  This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
 824   * @return Array    'module_fields' -- The vardef information on the selected fields.
 825   *                  'error' -- The SOAP error, if any
 826   */
 827  function get_module_fields($session, $module_name){
 828      global  $beanList, $beanFiles;
 829      $error = new SoapError();
 830      $module_fields = array();
 831      if(! validate_authenticated($session)){
 832          $error->set_error('invalid_session');
 833          return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
 834      }
 835      if(empty($beanList[$module_name])){
 836          $error->set_error('no_module');
 837          return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
 838      }
 839      global $current_user;
 840      if(!check_modules_access($current_user, $module_name, 'read')){
 841          $error->set_error('no_access');
 842          return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
 843      }
 844      $class_name = $beanList[$module_name];
 845      require_once($beanFiles[$class_name]);
 846      $seed = new $class_name();
 847      if($seed->ACLAccess('ListView', true) || $seed->ACLAccess('DetailView', true) ||     $seed->ACLAccess('EditView', true) )
 848      {
 849          return get_return_module_fields($seed, $module_name, $error);
 850      }
 851      else
 852      {
 853          $error->set_error('no_access');
 854          return array('module_fields'=>$module_fields, 'error'=>$error->get_soap_array());
 855      }
 856  }
 857  
 858  $server->register(
 859      'get_available_modules',
 860      array('session'=>'xsd:string'),
 861      array('return'=>'tns:module_list'),
 862      $NAMESPACE);
 863  
 864  /**
 865   * Retrieve the list of available modules on the system available to the currently logged in user.
 866   *
 867   * @param String $session -- Session ID returned by a previous call to login.
 868   * @return Array    'modules' -- An array of module names
 869   *                  'error' -- The SOAP error, if any
 870   */
 871  function get_available_modules($session){
 872      $error = new SoapError();
 873      $modules = array();
 874      if(! validate_authenticated($session)){
 875          $error->set_error('invalid_session');
 876          return array('modules'=> $modules, 'error'=>$error->get_soap_array());
 877      }
 878      $modules = array_keys($_SESSION['avail_modules']);
 879  
 880      return array('modules'=> $modules, 'error'=>$error->get_soap_array());
 881  }
 882  
 883  
 884  $server->register(
 885      'update_portal_user',
 886      array('session'=>'xsd:string', 'portal_name'=>'xsd:string', 'name_value_list'=>'tns:name_value_list'),
 887      array('return'=>'tns:error_value'),
 888      $NAMESPACE);
 889  
 890  /**
 891   * Update the properties of a contact that is portal user.  Add the portal user name to the user's properties.
 892   *
 893   * @param String $session -- Session ID returned by a previous call to login.
 894   * @param String $portal_name -- The portal user_name of the contact
 895   * @param Array $name_value_list -- collection of 'name'=>'value' pairs for finding the contact
 896   * @return Empty error on success, Error on failure
 897   */
 898  function update_portal_user($session,$portal_name, $name_value_list){
 899      global  $beanList, $beanFiles;
 900      $error = new SoapError();
 901      if(! validate_authenticated($session)){
 902          $error->set_error('invalid_session');
 903          return $error->get_soap_array();
 904      }
 905      $contact = new Contact();
 906  
 907      $searchBy = array('deleted'=>0);
 908      foreach($name_value_list as $name_value){
 909              $searchBy[$name_value['name']] = $name_value['value'];
 910      }
 911      if($contact->retrieve_by_string_fields($searchBy) != null){
 912          if(!$contact->duplicates_found){
 913              $contact->portal_name = $portal_name;
 914              $contact->portal_active = 1;
 915              if($contact->ACLAccess('Save')){
 916                  $contact->save();
 917              }else{
 918                  $error->set_error('no_access');
 919              }
 920              return $error->get_soap_array();
 921          }
 922          $error->set_error('duplicates');
 923          return $error->get_soap_array();
 924      }
 925      $error->set_error('no_records');
 926      return $error->get_soap_array();
 927  }
 928  
 929  $server->register(
 930      'get_user_id',
 931      array('session'=>'xsd:string'),
 932      array('return'=>'xsd:string'),
 933      $NAMESPACE);
 934  
 935  /**
 936   * Return the user_id of the user that is logged into the current session.
 937   *
 938   * @param String $session -- Session ID returned by a previous call to login.
 939   * @return String -- the User ID of the current session
 940   *                  -1 on error.
 941   */
 942  function get_user_id($session){
 943      if(validate_authenticated($session)){
 944          global $current_user;
 945          return $current_user->id;
 946  
 947      }else{
 948          return '-1';
 949      }
 950  }
 951  
 952  $server->register(
 953      'get_user_team_id',
 954      array('session'=>'xsd:string'),
 955      array('return'=>'xsd:string'),
 956      $NAMESPACE);
 957  
 958  /**
 959   * Return the ID of the default team for the user that is logged into the current session.
 960   *
 961   * @param String $session -- Session ID returned by a previous call to login.
 962   * @return String -- the Team ID of the current user's default team
 963   *                  1 for Community Edition
 964   *                  -1 on error.
 965   */
 966  function get_user_team_id($session){
 967      if(validate_authenticated($session))
 968      {
 969  
 970  
 971  
 972  
 973  
 974           return 1;
 975  
 976  
 977  
 978      }else{
 979          return '-1';
 980      }
 981  }
 982  
 983  $server->register(
 984      'get_server_time',
 985      array(),
 986      array('return'=>'xsd:string'),
 987      $NAMESPACE);
 988  
 989  /**
 990   * Return the current time on the server in the format 'Y-m-d H:i:s'.  This time is in the server's default timezone.
 991   *
 992   * @return String -- The current date/time 'Y-m-d H:i:s'
 993   */
 994  function get_server_time(){
 995      return date('Y-m-d H:i:s');
 996  }
 997  
 998  $server->register(
 999      'get_gmt_time',
1000      array(),
1001      array('return'=>'xsd:string'),
1002      $NAMESPACE);
1003  
1004  /**
1005   * Return the current time on the server in the format 'Y-m-d H:i:s'.  This time is in GMT.
1006   *
1007   * @return String -- The current date/time 'Y-m-d H:i:s'
1008   */
1009  function get_gmt_time(){
1010      return gmdate('Y-m-d H:i:s');
1011  }
1012  
1013  $server->register(
1014      'get_sugar_flavor',
1015      array(),
1016      array('return'=>'xsd:string'),
1017      $NAMESPACE);
1018  
1019  /**
1020   * Retrieve the specific flavor of sugar.
1021   *
1022   * @return String   'CE' -- For Community Edition
1023   *                  'PRO' -- For Professional
1024   *                  'ENT' -- For Enterprise
1025   */
1026  function get_sugar_flavor(){
1027   global $sugar_flavor;
1028   
1029   return $sugar_flavor;
1030  }
1031  
1032  
1033  $server->register(
1034      'get_server_version',
1035      array(),
1036      array('return'=>'xsd:string'),
1037      $NAMESPACE);
1038  
1039  /**
1040   * Retrieve the version number of Sugar that the server is running.
1041   *
1042   * @return String -- The current sugar version number.
1043   *                   '1.0' on error.
1044   */
1045  function get_server_version(){
1046      
1047      $admin  = new Administration();
1048      $admin->retrieveSettings('info');
1049      if(isset($admin->settings['info_sugar_version'])){
1050          return $admin->settings['info_sugar_version'];
1051      }else{
1052          return '1.0';
1053      }
1054  
1055  }
1056  
1057  $server->register(
1058      'get_relationships',
1059      array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'module_id'=>'xsd:string', 'related_module'=>'xsd:string', 'related_module_query'=>'xsd:string', 'deleted'=>'xsd:int'),
1060      array('return'=>'tns:get_relationships_result'),
1061      $NAMESPACE);
1062  
1063  /**
1064   * Retrieve a collection of beans tha are related to the specified bean.
1065   * As of 4.5.1c, all combinations of related modules are supported
1066   *
1067   * @param String $session -- Session ID returned by a previous call to login.
1068   * @param String $module_name -- The name of the module that the primary record is from.  This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
1069   * @param String $module_id -- The ID of the bean in the specified module
1070   * @param String $related_module -- The name of the related module to return records from.  This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
1071   * @param String $related_module_query -- A portion of the where clause of the SQL statement to find the related items.  The SQL query will already be filtered to only include the beans that are related to the specified bean.
1072   * @param Number $deleted -- false if deleted records should not be include, true if deleted records should be included.
1073   * @return unknown
1074   */
1075  function get_relationships($session, $module_name, $module_id, $related_module, $related_module_query, $deleted){
1076          $error = new SoapError();
1077      $ids = array();
1078      if(!validate_authenticated($session)){
1079          $error->set_error('invalid_login');
1080          return array('ids'=>$ids,'error'=> $error->get_soap_array());
1081      }
1082      global  $beanList, $beanFiles;
1083      $error = new SoapError();
1084  
1085      if(empty($beanList[$module_name]) || empty($beanList[$related_module])){
1086          $error->set_error('no_module');
1087          return array('ids'=>$ids, 'error'=>$error->get_soap_array());
1088      }
1089      $class_name = $beanList[$module_name];
1090      require_once($beanFiles[$class_name]);
1091      $mod = new $class_name();
1092      $mod->retrieve($module_id);
1093      if(!$mod->ACLAccess('DetailView')){
1094          $error->set_error('no_access');
1095          return array('ids'=>$ids, 'error'=>$error->get_soap_array());
1096      }
1097  
1098      $id_list = get_linked_records($related_module, $module_name, $module_id);
1099  
1100      if ($id_list === FALSE) {
1101          $error->set_error('no_relationship_support');
1102          return array('ids'=>$ids, 'error'=>$error->get_soap_array());
1103      }
1104      elseif (count($id_list) == 0) {
1105          return array('ids'=>$ids, 'error'=>$error->get_soap_array());
1106      }
1107  
1108      $list = array();
1109  
1110      $id_list_quoted = array_map("add_squotes", $id_list);
1111      $in = implode(", ", $id_list_quoted);
1112  
1113      $related_class_name = $beanList[$related_module];
1114      require_once($beanFiles[$related_class_name]);
1115      $related_mod = new $related_class_name();
1116  
1117      $sql = "SELECT {$related_mod->table_name}.id FROM {$related_mod->table_name} ";
1118  
1119  
1120  
1121  
1122  
1123      $sql .= " WHERE {$related_mod->table_name}.id IN ({$in}) ";
1124  
1125      if (!empty($related_module_query)) {
1126          $sql .= " AND ( {$related_module_query} )";
1127      }
1128  
1129      $result = $related_mod->db->query($sql);
1130      while ($row = $related_mod->db->fetchByAssoc($result)) {
1131          $list[] = $row['id'];
1132      }
1133  
1134      $return_list = array();
1135  
1136      foreach($list as $id) {
1137          $related_class_name = $beanList[$related_module];
1138          $related_mod = new $related_class_name();
1139          $related_mod->retrieve($id);
1140  
1141          $return_list[] = array(
1142              'id' => $id,
1143              'date_modified' => $related_mod->date_modified,
1144              'deleted' => $related_mod->deleted
1145          );
1146      }
1147  
1148      return array('ids' => $return_list, 'error' => $error->get_soap_array());
1149  }
1150  
1151  
1152  $server->register(
1153      'set_relationship',
1154      array('session'=>'xsd:string','set_relationship_value'=>'tns:set_relationship_value'),
1155      array('return'=>'tns:error_value'),
1156      $NAMESPACE);
1157  
1158  /**
1159   * Set a single relationship between two beans.  The items are related by module name and id.
1160   *
1161   * @param String $session -- Session ID returned by a previous call to login.
1162   * @param Array $set_relationship_value --
1163   *      'module1' -- The name of the module that the primary record is from.  This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
1164   *      'module1_id' -- The ID of the bean in the specified module
1165   *      'module2' -- The name of the module that the related record is from.  This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
1166   *      'module2_id' -- The ID of the bean in the specified module
1167   * @return Empty error on success, Error on failure
1168   */
1169  function set_relationship($session, $set_relationship_value){
1170      $error = new SoapError();
1171      if(!validate_authenticated($session)){
1172          $error->set_error('invalid_login');
1173          return $error->get_soap_array();
1174      }
1175      return handle_set_relationship($set_relationship_value);
1176  }
1177  
1178  $server->register(
1179      'set_relationships',
1180      array('session'=>'xsd:string','set_relationship_list'=>'tns:set_relationship_list'),
1181      array('return'=>'tns:set_relationship_list_result'),
1182      $NAMESPACE);
1183  
1184  /**
1185   * Setup several relationships between pairs of beans.  The items are related by module name and id.
1186   *
1187   * @param String $session -- Session ID returned by a previous call to login.
1188   * @param Array $set_relationship_list -- One for each relationship to setup.  Each entry is itself an array.
1189   *      'module1' -- The name of the module that the primary record is from.  This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
1190   *      'module1_id' -- The ID of the bean in the specified module
1191   *      'module2' -- The name of the module that the related record is from.  This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
1192   *      'module2_id' -- The ID of the bean in the specified module
1193   * @return Empty error on success, Error on failure
1194   */
1195  function set_relationships($session, $set_relationship_list){
1196      $error = new SoapError();
1197      if(!validate_authenticated($session)){
1198          $error->set_error('invalid_login');
1199          return -1;
1200      }
1201      $count = 0;
1202      $failed = 0;
1203      foreach($set_relationship_list as $set_relationship_value){
1204          $reter = handle_set_relationship($set_relationship_value);
1205          if($reter['number'] == 0){
1206              $count++;
1207          }else{
1208              $failed++;
1209          }
1210      }
1211      return array('created'=>$count , 'failed'=>$failed, 'error'=>$error);
1212  }
1213  
1214  
1215  
1216  //INTERNAL FUNCTION NOT EXPOSED THROUGH SOAP
1217  /**
1218   * (Internal) Create a relationship between two beans.
1219   *
1220   * @param Array $set_relationship_value --
1221   *      'module1' -- The name of the module that the primary record is from.  This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
1222   *      'module1_id' -- The ID of the bean in the specified module
1223   *      'module2' -- The name of the module that the related record is from.  This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
1224   *      'module2_id' -- The ID of the bean in the specified module
1225   * @return Empty error on success, Error on failure
1226   */
1227  function handle_set_relationship($set_relationship_value)
1228  {
1229      global  $beanList, $beanFiles;
1230      $error = new SoapError();
1231  
1232      $module1 = $set_relationship_value['module1'];
1233      $module1_id = $set_relationship_value['module1_id'];
1234      $module2 = $set_relationship_value['module2'];
1235      $module2_id = $set_relationship_value['module2_id'];
1236  
1237      if(empty($beanList[$module1]) || empty($beanList[$module2]) )
1238      {
1239          $error->set_error('no_module');
1240          return $error->get_soap_array();
1241      }
1242      $class_name = $beanList[$module1];
1243      require_once($beanFiles[$class_name]);
1244      $mod = new $class_name();
1245      $mod->retrieve($module1_id);
1246      if(!$mod->ACLAccess('DetailView')){
1247          $error->set_error('no_access');
1248          return $error->get_soap_array();
1249      }
1250      if($module1 == "Contacts" && $module2 == "Users"){
1251          $key = 'contacts_users_id';
1252      }
1253      else{
1254          $key = array_search(strtolower($module2),$mod->relationship_fields);
1255          if (!$key) {
1256              
1257              $key = Relationship::retrieve_by_modules($module1, $module2, $GLOBALS['db']);
1258              if (!empty($key)) {
1259                  $mod->load_relationship($key);
1260                  $mod->$key->add($module2_id);
1261                  return $error->get_soap_array();
1262              } // if
1263          } // if
1264      }
1265  
1266      if(!$key)
1267      {
1268          $error->set_error('no_module');
1269          return $error->get_soap_array();
1270      }
1271  
1272      if(($module1 == 'Meetings' || $module1 == 'Calls') && ($module2 == 'Contacts' || $module2 == 'Users')){
1273          $key = strtolower($module2);
1274          $mod->load_relationship($key);
1275          $mod->$key->add($module2_id);
1276      }else{
1277          $mod->$key = $module2_id;
1278          $mod->save_relationship_changes(false);
1279      }
1280  
1281      return $error->get_soap_array();
1282  }
1283  
1284  
1285  $server->register(
1286          'set_document_revision',
1287          array('session'=>'xsd:string','note'=>'tns:document_revision'),
1288          array('return'=>'tns:set_entry_result'),
1289          $NAMESPACE);
1290  
1291  /**
1292   * Enter description here...
1293   *
1294   * @param String $session -- Session ID returned by a previous call to login.
1295   * @param unknown_type $document_revision
1296   * @return unknown
1297   */
1298  function set_document_revision($session,$document_revision)
1299  {
1300  
1301      $error = new SoapError();
1302      if(!validate_authenticated($session)){
1303          $error->set_error('invalid_login');
1304          return array('id'=>-1, 'error'=>$error->get_soap_array());
1305      }
1306  
1307      require_once ('modules/Documents/DocumentSoap.php');
1308      $dr = new DocumentSoap();
1309      return array('id'=>$dr->saveFile($document_revision), 'error'=>$error->get_soap_array());
1310  
1311  }
1312  
1313  $server->register(
1314          'search_by_module',
1315          array('user_name'=>'xsd:string','password'=>'xsd:string','search_string'=>'xsd:string', 'modules'=>'tns:select_fields', 'offset'=>'xsd:int', 'max_results'=>'xsd:int'),
1316          array('return'=>'tns:get_entry_list_result'),
1317          $NAMESPACE);
1318  
1319  /**
1320   * Given a list of modules to search and a search string, return the id, module_name, along with the fields
1321   * as specified in the $query_array
1322   *
1323   * @param string $user_name         - username of the Sugar User
1324   * @param string $password            - password of the Sugar User
1325   * @param string $search_string     - string to search
1326   * @param string[] $modules            - array of modules to query
1327   * @param int $offset                - a specified offset in the query
1328   * @param int $max_results            - max number of records to return
1329   * @return get_entry_list_result     - id, module_name, and list of fields from each record
1330   */
1331  function search_by_module($user_name, $password, $search_string, $modules, $offset, $max_results){
1332      global  $beanList, $beanFiles;
1333  
1334      $error = new SoapError();
1335      if(!validate_user($user_name, $password)){
1336          $error->set_error('invalid_login');
1337          return array('result_count'=>-1, 'entry_list'=>array(), 'error'=>$error->get_soap_array());
1338      }
1339      global $current_user;
1340      if($max_results > 0){
1341          global $sugar_config;
1342          $sugar_config['list_max_entries_per_page'] = $max_results;
1343      }
1344      //  MRF - BUG:19552 - added a join for accounts' emails below
1345      $query_array = array('Accounts'=>array('where'=>array('Accounts' => array(0 => "accounts.name like '{0}%'"), 'EmailAddresses' => array(0 => "ea.email_address like '{0}%'")),'fields'=>"accounts.id, accounts.name"),
1346                              'Bugs'=>array('where'=>array('Bugs' => array(0 => "bugs.name like '{0}%'", 1 => "bugs.bug_number = {0}")),'fields'=>"bugs.id, bugs.name, bugs.bug_number"),
1347                              'Cases'=>array('where'=>array('Cases' => array(0 => "cases.name like '{0}%'", 1 => "cases.case_number = {0}")),'fields'=>"cases.id, cases.name, cases.case_number"),
1348                              'Contacts'=>array('where'=>array('Contacts' => array(0 => "contacts.first_name like '{0}%'", 1 => "contacts.last_name like '{0}%'"), 'EmailAddresses' => array(0 => "ea.email_address like '{0}%'")),'fields'=>"contacts.id, contacts.first_name, contacts.last_name"),
1349                              'Leads'=>array('where'=>array('Leads' => array(0 => "leads.first_name like '{0}%'",1 => "leads.last_name like '{0}%'"), 'EmailAddresses' => array(0 => "ea.email_address like '{0}%'")), 'fields'=>"leads.id, leads.first_name, leads.last_name, leads.status"),
1350                              'Opportunities'=>array('where'=>array('Opportunities' => array(0 => "opportunities.name like '{0}%'")), 'fields'=>"opportunities.id, opportunities.name"),
1351                              'Project'=>array('where'=>array('Project' => array(0 => "project.name like '{0}%'")), 'fields'=>"project.id, project.name"),
1352                              'ProjectTask'=>array('where'=>array('ProjectTask' => array(0 => "project.id = '{0}'")), 'fields'=>"project_task.id, project_task.name"),
1353                              'Users'=>array('where'=>array('EmailAddresses' => array(0 => "ea.email_address like '{0}%'")),'fields'=>"users.id, users.user_name, users.first_name, ea.email_address"),
1354                          );
1355  
1356      if(!empty($search_string) && isset($search_string)){
1357          foreach($modules as $module_name){
1358              $class_name = $beanList[$module_name];
1359              require_once($beanFiles[$class_name]);
1360              $seed = new $class_name();
1361              if(empty($beanList[$module_name])){
1362                  continue;
1363              }
1364              if(!check_modules_access($current_user, $module_name, 'read')){
1365                  continue;
1366              }
1367              if(! $seed->ACLAccess('ListView'))
1368              {
1369                  continue;
1370              }
1371  
1372              if(isset($query_array[$module_name])){
1373                  $query = '';
1374                  $tmpQuery = '';
1375                  //split here to do while loop
1376                  foreach($query_array[$module_name]['where'] as $key => $value){
1377                      foreach($value as $where_clause){
1378                          $addQuery = true;
1379                          if(!empty($query))
1380                              $tmpQuery = ' UNION ';
1381                          $tmpQuery .= "SELECT ".$query_array[$module_name]['fields']." FROM $seed->table_name ";
1382                          // We need to confirm that the user is a member of the team of the item.
1383  
1384  
1385  
1386  
1387  
1388  
1389                          if($module_name == 'ProjectTask'){
1390                              $tmpQuery .= "INNER JOIN project ON $seed->table_name.project_id = project.id ";
1391                          }
1392                             if(isset($seed->emailAddress) && $key == 'EmailAddresses'){
1393                                 $tmpQuery .= " INNER JOIN email_addr_bean_rel eabl  ON eabl.bean_id = $seed->table_name.id and eabl.deleted=0";
1394                                $tmpQuery .= " INNER JOIN email_addresses ea ON (ea.id = eabl.email_address_id) ";
1395                          }
1396                          $where = "WHERE (";
1397                          $search_terms = explode(", ", $search_string);
1398                          $termCount = count($search_terms);
1399                          $count = 1;
1400                          if($key != 'EmailAddresses'){
1401                              foreach($search_terms as $term){
1402                                  if(!strpos($where_clause, 'number')){
1403                                      $where .= string_format($where_clause,array($term));
1404                                  }elseif(is_numeric($term)){
1405                                      $where .= string_format($where_clause,array($term));
1406                                  }else{
1407                                      $addQuery = false;
1408                                  }
1409                                  if($count < $termCount){
1410                                      $where .= " OR ";
1411                                  }
1412                                  $count++;
1413                              }
1414                          }else{
1415                              $where .= 'ea.email_address IN (';
1416                              foreach($search_terms as $term){
1417                                  $where .= "'".$GLOBALS['db']->quote($term)."'";
1418                                  if($count < $termCount){
1419                                      $where .= ",";
1420                                  }
1421                                  $count++;
1422                              }
1423                              $where .= ')';
1424                          }
1425                          $tmpQuery .= $where;
1426                          $tmpQuery .= ") AND $seed->table_name.deleted = 0";
1427                          if($addQuery)
1428                              $query .= $tmpQuery;
1429                      }
1430                  }
1431                  //grab the items from the db
1432                  $result = $seed->db->query($query, $offset, $max_results);
1433  
1434                  $list = Array();
1435                  if(empty($rows_found)){
1436                            $rows_found =  $seed->db->getRowCount($result);
1437                  }//fi
1438  
1439                  $row_offset = 0;
1440  
1441                  while(($row = $seed->db->fetchByAssoc($result)) != null){
1442                      $list = array();
1443                      $fields = explode(", ", $query_array[$module_name]['fields']);
1444                      foreach($fields as $field){
1445                          $field_names = explode(".", $field);
1446                          $list[$field] = array('name'=>$field_names[1], 'value'=>$row[$field_names[1]]);
1447                      }
1448  
1449                      $output_list[] = array('id'=>$row['id'],
1450                                         'module_name'=>$module_name,
1451                                         'name_value_list'=>$list);
1452                      if(empty($field_list)){
1453                          $field_list = get_field_list($row);
1454                      }
1455                  }//end while
1456              }
1457          }//end foreach
1458      }
1459  
1460      $next_offset = $offset + sizeof($output_list);
1461  
1462      return array('result_count'=>sizeof($output_list), 'next_offset'=>$next_offset,'field_list'=>$field_list, 'entry_list'=>$output_list, 'error'=>$error->get_soap_array());
1463  
1464  }//end function
1465  
1466  
1467  $server->register(
1468  'get_mailmerge_document',
1469  array('session'=>'xsd:string','file_name'=>'xsd:string', 'fields' => 'tns:select_fields'),
1470  array('return'=>'tns:get_sync_result_encoded'),
1471  $NAMESPACE);
1472  
1473  /**
1474   * Enter description here...
1475   *
1476   * @param String $session -- Session ID returned by a previous call to login.
1477   * @param unknown_type $file_name
1478   * @param unknown_type $fields
1479   * @return unknown
1480   */
1481  function get_mailmerge_document($session, $file_name, $fields)
1482  {
1483      global  $beanList, $beanFiles, $app_list_strings;
1484      $error = new SoapError();
1485      if(!validate_authenticated($session))
1486      {
1487          $error->set_error('invalid_login');
1488          return array('result'=>'', 'error'=>$error->get_soap_array());
1489      }
1490      $html = '';
1491      $file_name = $GLOBALS['sugar_config']['cache_dir'].'MergedDocuments/'.$file_name;
1492  
1493      $master_fields = array();
1494      $related_fields = array();
1495  
1496      if(file_exists($file_name))
1497      {
1498          require_once($file_name);
1499  
1500          $class1 = $merge_array['master_module'];
1501          $beanL = $beanList[$class1];
1502          $bean1 = $beanFiles[$beanL];
1503          require_once($bean1);
1504          $seed1 = new $beanL();
1505  
1506          if(isset($merge_array['related_module']))
1507          {
1508              $class2 = $merge_array['related_module'];
1509              $beanR = $beanList[$class2];
1510              $bean2 = $beanFiles[$beanR];
1511              require_once($bean2);
1512              $seed2 = new $beanR();
1513          }
1514  
1515          //parse fields
1516          //$token1 = strtolower($class1);
1517          if($class1 == 'Prospects'){
1518              $class1 = 'CampaignProspects';
1519          }
1520          foreach($fields as $field)
1521          {
1522              $split_fields = split('_', $field);
1523              if(count($split_fields) > 1)
1524              {
1525                  $name = '';
1526                  $index = 1;
1527                  for($i = 1; $i < count($split_fields); $i++)
1528                  {
1529                      $name .= $split_fields[$i];
1530                      $index++;
1531                      if($index < count($split_fields))
1532                          $name .= '_';
1533                  }
1534                  if(strtolower($split_fields[0]) == strtolower($class1))
1535                  {
1536                      array_push($master_fields, $name);
1537                  }
1538                  else if(strtolower($split_fields[0]) == strtolower($class2))
1539                  {
1540                      array_push($related_fields, $name);
1541                  }
1542              }
1543          }
1544  
1545          $html = '<html><body><table border = 1><tr>';
1546  
1547          foreach($master_fields as $master_field){
1548              $html .= '<td>'.$class1.'_'.$master_field.'</td>';
1549          }
1550          foreach($related_fields as $related_field){
1551              $html .= '<td>'.$class2.'_'.$related_field.'</td>';
1552          }
1553          $html .= '</tr>';
1554  
1555          $ids = $merge_array['ids'];
1556          $is_prospect_merge = ($seed1->object_name == 'Prospect');
1557          foreach($ids as $key=>$value){
1558              if($is_prospect_merge){
1559                  $seed1 = $seed1->retrieveTarget($key);
1560              }else{
1561                  $seed1->retrieve($key);
1562              }
1563              $html .= '<tr>';
1564              foreach($master_fields as $master_field){
1565                  if(isset($seed1->$master_field)){
1566                      if($seed1->field_name_map[$master_field]['type'] == 'enum'){
1567                          //pull in the translated dom
1568                           $html .='<td>'.$app_list_strings[$seed1->field_name_map[$master_field]['options']][$seed1->$master_field].'</td>';
1569                      }else{
1570                          $html .='<td>'.$seed1->$master_field.'</td>';
1571                      }
1572                  }
1573                  else{
1574                      $html .= '<td></td>';
1575                      }
1576              }
1577              if(isset($value) && !empty($value)){
1578                  $seed2->retrieve($value);
1579                  foreach($related_fields as $related_field){
1580                      if(isset($seed2->$related_field)){
1581                          if($seed2->field_name_map[$related_field]['type'] == 'enum'){
1582                              //pull in the translated dom
1583                              $html .='<td>'.$app_list_strings[$seed2->field_name_map[$related_field]['options']][$seed2->$related_field].'</td>';
1584                          }else{
1585                              $html .= '<td>'.$seed2->$related_field.'</td>';
1586                          }
1587                      }
1588                      else{
1589                          $html .= '<td></td>';
1590                      }
1591                  }
1592              }
1593              $html .= '</tr>';
1594          }
1595          $html .= "</table></body></html>";
1596       }
1597  
1598      $result = base64_encode($html);
1599      return array('result' => $result, 'error' => $error);
1600  }
1601  
1602  $server->register(
1603  'get_mailmerge_document2',
1604  array('session'=>'xsd:string','file_name'=>'xsd:string', 'fields' => 'tns:select_fields'),
1605  array('return'=>'tns:get_mailmerge_document_result'),
1606  $NAMESPACE);
1607  
1608  /**
1609   * Enter description here...
1610   *
1611   * @param String $session -- Session ID returned by a previous call to login.
1612   * @param unknown_type $file_name
1613   * @param unknown_type $fields
1614   * @return unknown
1615   */
1616  function get_mailmerge_document2($session, $file_name, $fields)
1617  {
1618      global  $beanList, $beanFiles, $app_list_strings;
1619      $error = new SoapError();
1620      if(!validate_authenticated($session))
1621      {
1622          $error->set_error('invalid_login');
1623          return array('result'=>'', 'error'=>$error->get_soap_array());
1624      }
1625      $html = '';
1626      $file_name = $GLOBALS['sugar_config']['cache_dir'].'MergedDocuments/'.$file_name;
1627  
1628      $master_fields = array();
1629      $related_fields = array();
1630  
1631      if(file_exists($file_name))
1632      {
1633          require_once($file_name);
1634  
1635          $class1 = $merge_array['master_module'];
1636          $beanL = $beanList[$class1];
1637          $bean1 = $beanFiles[$beanL];
1638          require_once($bean1);
1639          $seed1 = new $beanL();
1640  
1641          if(!empty($merge_array['related_module']))
1642          {
1643              $class2 = $merge_array['related_module'];
1644              $beanR = $beanList[$class2];
1645              $bean2 = $beanFiles[$beanR];
1646              require_once($bean2);
1647              $seed2 = new $beanR();
1648          }
1649  
1650          //parse fields
1651          //$token1 = strtolower($class1);
1652          if($class1 == 'Prospects'){
1653              $class1 = 'CampaignProspects';
1654          }
1655          foreach($fields as $field)
1656          {
1657              $split_fields = split('_', $field);
1658              if(count($split_fields) > 1)
1659              {
1660                  $name = '';
1661                  $index = 1;
1662                  for($i = 1; $i < count($split_fields); $i++)
1663                  {
1664                      $name .= $split_fields[$i];
1665                      $index++;
1666                      if($index < count($split_fields))
1667                          $name .= '_';
1668                  }
1669                  if(strtolower($split_fields[0]) == strtolower($class1))
1670                  {
1671                      array_push($master_fields, $name);
1672                  }
1673                  else if(strtolower($split_fields[0]) == strtolower($class2))
1674                  {
1675                      array_push($related_fields, $name);
1676                  }
1677              }
1678          }
1679  
1680          $html = '<html><body><table border = 1><tr>';
1681  
1682          foreach($master_fields as $master_field){
1683              $html .= '<td>'.$class1.'_'.$master_field.'</td>';
1684          }
1685          foreach($related_fields as $related_field){
1686              $html .= '<td>'.$class2.'_'.$related_field.'</td>';
1687          }
1688          $html .= '</tr>';
1689  
1690          $ids = $merge_array['ids'];
1691          $resultIds = array();
1692          $is_prospect_merge = ($seed1->object_name == 'Prospect');
1693          if($is_prospect_merge){
1694              $pSeed = $seed1;
1695          }
1696          foreach($ids as $key=>$value){
1697  
1698              if($is_prospect_merge){
1699                  $seed1 = $pSeed->retrieveTarget($key);
1700              }else{
1701                  $seed1->retrieve($key);
1702              }
1703               $resultIds[] = array('name' => $seed1->module_name, 'value' => $key);
1704              $html .= '<tr>';
1705              foreach($master_fields as $master_field){
1706                  if(isset($seed1->$master_field)){
1707                      if($seed1->field_name_map[$master_field]['type'] == 'enum'){
1708                          //pull in the translated dom
1709                           $html .='<td>'.$app_list_strings[$seed1->field_name_map[$master_field]['options']][$seed1->$master_field].'</td>';
1710                      }else{
1711                          $html .='<td>'.$seed1->$master_field.'</td>';
1712                      }
1713                  }
1714                  else{
1715                      $html .= '<td></td>';
1716                      }
1717              }
1718              if(isset($value) && !empty($value)){
1719                  $resultIds[] = array('name' => $seed2->module_name, 'value' => $value);
1720                  $seed2->retrieve($value);
1721                  foreach($related_fields as $related_field){
1722                      if(isset($seed2->$related_field)){
1723                          if($seed2->field_name_map[$related_field]['type'] == 'enum'){
1724                              //pull in the translated dom
1725                              $html .='<td>'.$app_list_strings[$seed2->field_name_map[$related_field]['options']][$seed2->$related_field].'</td>';
1726                          }else{
1727                              $html .= '<td>'.$seed2->$related_field.'</td>';
1728                          }
1729                      }
1730                      else{
1731                          $html .= '<td></td>';
1732                      }
1733                  }
1734              }
1735              $html .= '</tr>';
1736          }
1737          $html .= "</table></body></html>";
1738       }
1739  
1740      $result = base64_encode($html);
1741      return array('html' => $result, 'name_value_list' => $resultIds, 'error' => $error);
1742  }
1743  
1744  $server->register(
1745          'get_document_revision',
1746          array('session'=>'xsd:string','i'=>'xsd:string'),
1747          array('return'=>'tns:return_document_revision'),
1748          $NAMESPACE);
1749  
1750  /**
1751   * This method is used as a result of the .htaccess lock down on the cache directory. It will allow a
1752   * properly authenticated user to download a document that they have proper rights to download.
1753   *
1754   * @param String $session -- Session ID returned by a previous call to login.
1755   * @param String $id      -- ID of the document revision to obtain
1756   * @return return_document_revision - this is a complex type as defined in SoapTypes.php
1757   */
1758  function get_document_revision($session,$id)
1759  {
1760      global $sugar_config;
1761  
1762      $error = new SoapError();
1763      if(!validate_authenticated($session)){
1764          $error->set_error('invalid_login');
1765          return array('id'=>-1, 'error'=>$error->get_soap_array());
1766      }
1767  
1768      
1769      $dr = new DocumentRevision();
1770      $dr->retrieve($id);
1771      if(!empty($dr->filename)){
1772          $filename = $sugar_config['upload_dir']."/".$dr->id;
1773          $handle = sugar_fopen($filename, "r");
1774          $contents = fread($handle, filesize($filename));
1775          fclose($handle);
1776          $contents = base64_encode($contents);
1777  
1778          $fh = sugar_fopen($sugar_config['upload_dir']."/rogerrsmith.doc", 'w');
1779          fwrite($fh, base64_decode($contents));
1780          return array('document_revision'=>array('id' => $dr->id, 'document_name' => $dr->document_name, 'revision' => $dr->revision, 'filename' => $dr->filename, 'file' => $contents), 'error'=>$error->get_soap_array());
1781      }else{
1782          $error->set_error('no_records');
1783          return array('id'=>-1, 'error'=>$error->get_soap_array());
1784      }
1785  
1786  }
1787  
1788  $server->register(
1789      'set_campaign_merge',
1790      array('session'=>'xsd:string', 'targets'=>'tns:select_fields', 'campaign_id'=>'xsd:string'),
1791      array('return'=>'tns:error_value'),
1792      $NAMESPACE);
1793  /**
1794  *   Once we have successfuly done a mail merge on a campaign, we need to notify Sugar of the targets
1795  *   and the campaign_id for tracking purposes
1796  *
1797  * @param session        the session id of the authenticated user
1798  * @param targets        a string array of ids identifying the targets used in the merge
1799  * @param campaign_id    the campaign_id used for the merge
1800  *
1801  * @return error_value
1802  */
1803  function set_campaign_merge($session,$targets, $campaign_id){
1804      $error = new SoapError();
1805      if(!validate_authenticated($session)){
1806          $error->set_error('invalid_login');
1807          return $error->get_soap_array();
1808      }
1809      if (empty($campaign_id) or !is_array($targets) or count($targets) == 0) {
1810          $GLOBALS['log']->debug('set_campaign_merge: Merge action status will not be updated, because, campaign_id is null or no targets were selected.');
1811      } else {
1812          require_once ('modules/Campaigns/utils.php');
1813          campaign_log_mail_merge($campaign_id,$targets);
1814      }
1815  
1816      return $error->get_soap_array();
1817  }
1818  
1819  $server->register(
1820      'get_entries_count',
1821      array('session'=>'xsd:string', 'module_name'=>'xsd:string', 'query'=>'xsd:string', 'deleted' => 'xsd:int'),
1822      array('return'=>'tns:get_entries_count_result'),
1823      $NAMESPACE);
1824  
1825  /**
1826  *   Retrieve number of records in a given module
1827  *
1828  * @param session        the session id of the authenticated user
1829  * @param module_name    module to retrieve number of records from
1830  * @param query          allows webservice user to provide a WHERE clause
1831  * @param deleted        specify whether or not to include deleted records
1832  *
1833  @return get_entries_count_result - this is a complex type as defined in SoapTypes.php
1834  */
1835  function get_entries_count($session, $module_name, $query, $deleted) {
1836      global $beanList, $beanFiles, $current_user;
1837  
1838      $error = new SoapError();
1839  
1840      if (!validate_authenticated($session)) {
1841          $error->set_error('invalid_login');
1842          return array(
1843              'result_count' => -1,
1844              'error' => $error->get_soap_array()
1845          );
1846      }
1847  
1848      if (empty($beanList[$module_name])) {
1849          $error->set_error('no_module');
1850          return array(
1851              'result_count' => -1,
1852              'error' => $error->get_soap_array()
1853          );
1854      }
1855  
1856      if(!check_modules_access($current_user, $module_name, 'list')){
1857          $error->set_error('no_access');
1858          return array(
1859              'result_count' => -1,
1860              'error' => $error->get_soap_array()
1861          );
1862      }
1863  
1864      $class_name = $beanList[$module_name];
1865      require_once($beanFiles[$class_name]);
1866      $seed = new $class_name();
1867  
1868      if (!$seed->ACLAccess('ListView')) {
1869          $error->set_error('no_access');
1870          return array(
1871              'result_count' => -1,
1872              'error' => $error->get_soap_array()
1873          );
1874      }
1875  
1876      $sql = 'SELECT COUNT(*) result_count FROM ' . $seed->table_name . ' ';
1877  
1878  
1879  
1880  
1881  
1882      // build WHERE clauses, if any
1883      $where_clauses = array();
1884      if (!empty($query)) {
1885          $where_clauses[] = $query;
1886      }
1887      if ($deleted == 0) {
1888          $where_clauses[] = $seed->table_name . '.deleted = 0';
1889      }
1890  
1891      // if WHERE clauses exist, add them to query
1892      if (!empty($where_clauses)) {
1893          $sql .= ' WHERE ' . implode(' AND ', $where_clauses);
1894      }
1895  
1896      $res = $GLOBALS['db']->query($sql);
1897      $row = $GLOBALS['db']->fetchByAssoc($res);
1898  
1899      return array(
1900          'result_count' => $row['result_count'],
1901          'error' => $error->get_soap_array()
1902      );
1903  }
1904  
1905  $server->register(
1906      'set_entries_details',
1907      array('session'=>'xsd:string', 'module_name'=>'xsd:string',  'name_value_lists'=>'tns:name_value_lists', 'select_fields' => 'tns:select_fields'),
1908      array('return'=>'tns:set_entries_detail_result'),
1909      $NAMESPACE);
1910  
1911  /**
1912   * Update or create a list of SugarBeans, returning details about the records created/updated
1913   *
1914   * @param String $session -- Session ID returned by a previous call to login.
1915   * @param String $module_name -- The name of the module to return records from.  This name should be the name the module was developed under (changing a tab name is studio does not affect the name that should be passed into this method)..
1916   * @param Array $name_value_lists -- Array of Bean specific Arrays where the keys of the array are the SugarBean attributes, the values of the array are the values the attributes should have.
1917   * @param Array  $select_fields -- A list of the fields to be included in the results. This optional parameter allows for only needed fields to be retrieved.
1918   * @return Array    'name_value_lists' --  Array of Bean specific Arrays where the keys of the array are the SugarBean attributes, the values of the array are the values the attributes should have.
1919   *                  'error' -- The SOAP error if any.
1920   */
1921  function set_entries_details($session, $module_name, $name_value_lists, $select_fields) {
1922      $error = new SoapError();
1923  
1924      if(!validate_authenticated($session)){
1925          $error->set_error('invalid_login');
1926  
1927          return array(
1928              'ids' => array(),
1929              'error' => $error->get_soap_array()
1930          );
1931      }
1932  
1933      return handle_set_entries($module_name, $name_value_lists, $select_fields);
1934  }
1935  
1936  // INTERNAL FUNCTION NOT EXPOSED THROUGH API
1937  function handle_set_entries($module_name, $name_value_lists, $select_fields = FALSE) {
1938      global $beanList, $beanFiles, $app_list_strings;
1939  
1940      $error = new SoapError();
1941      $ret_values = array();
1942  
1943      if(empty($beanList[$module_name])){
1944          $error->set_error('no_module');
1945          return array('ids'=>array(), 'error'=>$error->get_soap_array());
1946      }
1947      global $current_user;
1948      if(!check_modules_access($current_user, $module_name, 'write')){
1949          $error->set_error('no_access');
1950          return array('ids'=>-1, 'error'=>$error->get_soap_array());
1951      }
1952  
1953      $class_name = $beanList[$module_name];
1954      require_once($beanFiles[$class_name]);
1955      $ids = array();
1956      $count = 1;
1957      $total = sizeof($name_value_lists);
1958      foreach($name_value_lists as $name_value_list){
1959          $seed = new $class_name();
1960  
1961          $seed->update_vcal = false;
1962          foreach($name_value_list as $value){
1963              if($value['name'] == 'id'){
1964                  $seed->retrieve($value['value']);
1965                  break;
1966              }
1967          }
1968  
1969          foreach($name_value_list as $value) {
1970              $val = $value['value'];
1971              if($seed->field_name_map[$value['name']]['type'] == 'enum' ||$seed->field_name_map[$value['name']]['type'] == 'radioenum'){
1972                  $vardef = $seed->field_name_map[$value['name']];
1973                  if(isset($app_list_strings[$vardef['options']]) && !isset($app_list_strings[$vardef['options']][$value]) ) {
1974                      if ( in_array($val,$app_list_strings[$vardef['options']]) ){
1975                          $val = array_search($val,$app_list_strings[$vardef['options']]);
1976                      }
1977                  }
1978              } else if($seed->field_name_map[$value['name']]['type'] == 'multienum') {
1979                  $vardef = $seed->field_name_map[$value['name']];
1980                  if(isset($app_list_strings[$vardef['options']]) && !isset($app_list_strings[$vardef['options']][$value]) ) {
1981                      $items = split(",", $val);
1982                      $parsedItems = array();
1983                      foreach ($items as $item) {
1984                          if ( in_array($item, $app_list_strings[$vardef['options']]) ){
1985                              $keyVal = array_search($item,$app_list_strings[$vardef['options']]);
1986                              array_push($parsedItems, $keyVal);
1987                          }
1988                      }
1989                         if (!empty($parsedItems)) {
1990                          $val = encodeMultienumValue($parsedItems);
1991                         }
1992                  }                    
1993              }
1994              $seed->$value['name'] = $val;
1995          }
1996  
1997          if($count == $total){
1998              $seed->update_vcal = false;
1999          }
2000          $count++;
2001  
2002          //Add the account to a contact
2003          if($module_name == 'Contacts'){
2004              $GLOBALS['log']->debug('Creating Contact Account');
2005              add_create_account($seed);
2006              $duplicate_id = check_for_duplicate_contacts($seed);
2007              if($duplicate_id == null){
2008                  if($seed->ACLAccess('Save') && ($seed->deleted != 1 || $seed->ACLAccess('Delete'))){
2009                      $seed->save();
2010                      if($seed->deleted == 1){
2011                          $seed->mark_deleted($seed->id);
2012                      }
2013                      $ids[] = $seed->id;
2014                  }
2015              }
2016              else{
2017                  //since we found a duplicate we should set the sync flag
2018                  if( $seed->ACLAccess('Save')){
2019                      $seed->id = $duplicate_id;
2020                      $seed->contacts_users_id = $current_user->id;
2021                      $seed->save();
2022                      $ids[] = $duplicate_id;//we have a conflict
2023                  }
2024              }
2025          }
2026          else if($module_name == 'Meetings' || $module_name == 'Calls'){
2027              //we are going to check if we have a meeting in the system
2028              //with the same outlook_id. If we do find one then we will grab that
2029              //id and save it
2030              if( $seed->ACLAccess('Save') && ($seed->deleted != 1 || $seed->ACLAccess('Delete'))){
2031                  if(empty($seed->id) && !isset($seed->id)){
2032                      if(!empty($seed->outlook_id) && isset($seed->outlook_id)){
2033                          //at this point we have an object that does not have
2034                          //the id set, but does have the outlook_id set
2035                          //so we need to query the db to find if we already
2036                          //have an object with this outlook_id, if we do
2037                          //then we can set the id, otherwise this is a new object
2038                          $order_by = "";
2039                          $query = $seed->table_name.".outlook_id = '".$seed->outlook_id."'";
2040                          $response = $seed->get_list($order_by, $query, 0,-1,-1,0);
2041                          $list = $response['list'];
2042                          if(count($list) > 0){
2043                              foreach($list as $value)
2044                              {
2045                                  $seed->id = $value->id;
2046                                  break;
2047                              }
2048                          }//fi
2049                      }//fi
2050                  }//fi
2051                  if (empty($seed->reminder_time)) {
2052                      $seed->reminder_time = -1;
2053                  }
2054                  if($seed->reminder_time == -1){
2055                      $defaultRemindrTime = $current_user->getPreference('reminder_time');
2056                      if ($defaultRemindrTime != -1){
2057                          $seed->reminder_checked = '1';
2058                          $seed->reminder_time = $defaultRemindrTime;
2059                      }
2060                  }
2061                  $seed->save();
2062                  $ids[] = $seed->id;
2063              }//fi
2064          }
2065          else
2066          {
2067              if( $seed->ACLAccess('Save') && ($seed->deleted != 1 || $seed->ACLAccess('Delete'))){
2068                  $seed->save();
2069                  $ids[] = $seed->id;
2070              }
2071          }
2072  
2073          // if somebody is calling set_entries_detail() and wants fields returned...
2074          if ($select_fields !== FALSE) {
2075              $ret_values[$count] = array();
2076  
2077              foreach ($select_fields as $select_field) {
2078                  if (isset($seed->$select_field)) {
2079                      $ret_values[$count][] = get_name_value($select_field, $seed->$select_field);
2080                  }
2081              }
2082          }
2083      }
2084  
2085      // handle returns for set_entries_detail() and set_entries()
2086      if ($select_fields !== FALSE) {
2087          return array(
2088              'name_value_lists' =>