flatpak_dir_modify_remote (FlatpakDir   *self,
                           const char   *remote_name,
                           GKeyFile     *config,
                           GBytes       *gpg_data,
                           GCancellable *cancellable,
                           GError      **error)
{
  g_autofree char *group = g_strdup_printf ("remote \"%s\"", remote_name);
  g_autofree char *url = NULL;
  g_autofree char *metalink = NULL;
  g_autoptr(GKeyFile) new_config = NULL;
  g_autofree gchar *filter_path = NULL;
  gboolean has_remote;

  if (strchr (remote_name, '/') != NULL)
    return flatpak_fail_error (error, FLATPAK_ERROR_REMOTE_NOT_FOUND, _("Invalid character '/' in remote name: %s"),
                               remote_name);

  has_remote = flatpak_dir_has_remote (self, remote_name, NULL);

  if (!g_key_file_has_group (config, group))
    return flatpak_fail_error (error, FLATPAK_ERROR_INVALID_DATA, _("No configuration for remote %s specified"),
                               remote_name);

  if (!flatpak_dir_check_add_remotes_config_dir (self, error))
    return FALSE;

  if (flatpak_dir_use_system_helper (self, NULL))
    {
      g_autofree char *config_data = g_key_file_to_data (config, NULL, NULL);
      g_autoptr(GVariant) gpg_data_v = NULL;
      const char *installation = flatpak_dir_get_id (self);

      if (gpg_data != NULL)
        gpg_data_v = variant_new_ay_bytes (gpg_data);
      else
        gpg_data_v = g_variant_ref_sink (g_variant_new_from_data (G_VARIANT_TYPE ("ay"), "", 0, TRUE, NULL, NULL));

      if (!flatpak_dir_system_helper_call_configure_remote (self,
                                                            0, remote_name,
                                                            config_data,
                                                            gpg_data_v,
                                                            installation ? installation : "",
                                                            cancellable, error))
        return FALSE;

      /* If we e.g. changed url or gpg config the cached summary may be invalid */
      if (!flatpak_dir_remote_clear_cached_summary (self, remote_name, cancellable, error))
        return FALSE;

      return TRUE;
    }

  metalink = g_key_file_get_string (config, group, "metalink", NULL);
  if (metalink != NULL && *metalink != 0)
    url = g_strconcat ("metalink=", metalink, NULL);
  else
    url = g_key_file_get_string (config, group, "url", NULL);

  /* No url => disabled */
  if (url == NULL)
    url = g_strdup ("");

  if (!flatpak_dir_cleanup_remote_for_url_change (self, remote_name, url, cancellable, error))
    return FALSE;

  /* Add it if its not there yet */
  if (!ostree_repo_remote_change (self->repo, NULL,
                                  OSTREE_REPO_REMOTE_CHANGE_ADD_IF_NOT_EXISTS,
                                  remote_name,
                                  url, NULL, cancellable, error))
    return FALSE;

  new_config = ostree_repo_copy_config (self->repo);

  copy_remote_config (new_config, config, remote_name);

  if (!ostree_repo_write_config (self->repo, new_config, error))
    return FALSE;

  if (gpg_data != NULL)
    {
      g_autoptr(GInputStream) input_stream = g_memory_input_stream_new_from_bytes (gpg_data);
      guint imported = 0;

      if (!ostree_repo_remote_gpg_import (self->repo, remote_name, input_stream,
                                          NULL, &imported, cancellable, error))
        return FALSE;

      /* XXX If we ever add internationalization, use ngettext() here. */
      g_debug ("Imported %u GPG key%s to remote \"%s\"",
               imported, (imported == 1) ? "" : "s", remote_name);
    }

  filter_path = g_key_file_get_value (new_config, group, "xa.filter", NULL);
  if (filter_path && *filter_path && g_file_test (filter_path, G_FILE_TEST_EXISTS))
    {
      /* Make a backup filter copy in case it goes away later */
      g_autofree char *filter_name = g_strconcat (remote_name, ".filter", NULL);
      g_autoptr(GFile) filter_file = g_file_new_for_path (filter_path);
      g_autoptr(GFile) filter_copy = flatpak_build_file (self->basedir, "repo", filter_name, NULL);
      g_autoptr(GError) local_error = NULL;
      g_autofree char *backup_data = NULL;
      gsize backup_data_size;

      if (g_file_load_contents (filter_file, cancellable, &backup_data, &backup_data_size, NULL, &local_error))
        {
          g_autofree char *backup_data_copy =
            g_strdup_printf ("# backup copy of %s, do not edit!\n%s", filter_path, backup_data);

          if (!g_file_replace_contents (filter_copy, backup_data_copy, strlen (backup_data_copy),
                                        NULL, FALSE, G_FILE_CREATE_REPLACE_DESTINATION, NULL, cancellable, &local_error))
            g_debug ("Failed to save backup copy of filter file %s: %s\n", filter_path, local_error->message);
        }
      else
        {
          g_debug ("Failed to read filter %s file while making a backup copy: %s\n", filter_path, local_error->message);
        }
    }

  /* If we e.g. changed url or gpg config the cached summary may be invalid */
  if (!flatpak_dir_remote_clear_cached_summary (self, remote_name, cancellable, error))
    return FALSE;

  if (!flatpak_dir_mark_changed (self, error))
    return FALSE;

  if (has_remote)
    flatpak_dir_log (self, "modify remote", remote_name, NULL, NULL, NULL, url,
                     "Modified remote %s to %s", remote_name, url);
  else
    flatpak_dir_log (self, "add remote", remote_name, NULL, NULL, NULL, url,
                     "Added remote %s to %s", remote_name, url);

  return TRUE;
}