private function synchMappingsFromForm($values, $storage) {

    $mappings = array();
    foreach ($values as $field => $value) {

      $parts = explode('__', $field);
      // since synch mapping fields are in n-tuples, process entire n-tuple at once
      if (count($parts) != 4 || $parts[1] !== 'sm') {
        continue;
      }

      list($direction, $discard, $column_name, $i) = $parts;
      $action = $storage['synch_mapping_fields'][$direction][$i]['action'];

      $row_mappings = array();
      foreach (array('remove', 'configurable_to_drupal', 'configurable_to_ldap', 'convert', 'ldap_attr', 'user_attr', 'user_tokens') as $column_name) {
        $input_name = join('__', array($direction, 'sm', $column_name, $i));
        $row_mappings[$column_name] = isset($values[$input_name]) ? $values[$input_name] : NULL;
      }

      if ($row_mappings['remove']) {
        continue;
      }

      $key = ($direction == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER) ? $row_mappings['user_attr'] : $row_mappings['ldap_attr'];
      if ($row_mappings['configurable_to_drupal'] && $row_mappings['ldap_attr'] && $row_mappings['user_attr']) {
        $mappings[$direction][$key] = array(
          'ldap_attr' => $row_mappings['ldap_attr'],
          'user_attr' => $row_mappings['user_attr'],
          'convert' => $row_mappings['convert'],
          'direction' => $direction,
          'user_tokens' => $row_mappings['user_tokens'],
          'config_module' => 'ldap_user',
          'prov_module' => 'ldap_user',
          'enabled' => 1,
          );

        $synchEvents = ($direction == LDAP_USER_PROV_DIRECTION_TO_DRUPAL_USER) ? $this->provisionsDrupalEvents : $this->provisionsLdapEvents;
        foreach ($synchEvents as $prov_event => $discard) {
          $input_name = join('__', array($direction, 'sm', $prov_event, $i));
          if (isset($values[$input_name]) && $values[$input_name]) {
            $mappings[$direction][$key]['prov_events'][] = $prov_event;
          }
        }
      }
    }

    return $mappings;
  }