static void update_property(const gchar *name, GVariant *value, void *user_data)
{
	struct ofono_sim_manager *sim = user_data;
	gchar *pin_type_str = NULL;
	gchar *subscriber_number = NULL;
	int n;
	GVariant *child, *prop_value, *prop_key;
	enum ofono_sim_pin pin_type;

	g_message("[SIM:%s] property %s changed", sim->path, name);

	if (g_str_equal(name, "Present"))
		sim->present = g_variant_get_boolean(value);
	else if (g_str_equal(name, "SubscriberIdentity"))
		sim->imsi = g_variant_dup_string(value, NULL);
	else if (g_str_equal(name, "MobileCountryCode"))
		sim->mcc = g_variant_dup_string(value, NULL);
	else if (g_str_equal(name, "MobileNetworkCode"))
		sim->mnc = g_variant_dup_string(value, NULL);
	else if (g_str_equal(name, "PinRequired")) {
		pin_type_str = g_variant_dup_string(value, NULL);
		sim->pin_required = parse_ofono_sim_pin_type(pin_type_str);
		g_free(pin_type_str);
	}
	else if (g_str_equal(name, "LockedPins")) {
		for (n = 0; n < g_variant_n_children(value); n++) {
			child = g_variant_get_child_value(value, n);

			pin_type_str = g_variant_dup_string(child, NULL);
			pin_type = parse_ofono_sim_pin_type(pin_type_str);
			g_free(pin_type_str);

			sim->locked_pins[pin_type] = (pin_type != OFONO_SIM_PIN_TYPE_INVALID);
		}
	}
	else if (g_str_equal(name, "Retries")) {
		memset(sim->pin_retries, 0, sizeof(sim->pin_retries));

		for (n = 0; n < g_variant_n_children(value); n++) {
			child = g_variant_get_child_value(value, n);

			prop_key = g_variant_get_child_value(child, 0);
			prop_value = g_variant_get_child_value(child, 1);

			pin_type_str = g_variant_dup_string(prop_key, NULL);
			pin_type = parse_ofono_sim_pin_type(pin_type_str);
			g_free(pin_type_str);

			sim->pin_retries[pin_type] = (int) g_variant_get_byte(prop_value);
		}
	}
	else if (g_str_equal(name, "FixedDialing")) {
		sim->fixed_dialing = g_variant_get_boolean(value);
	}
	else if (g_str_equal(name, "MobileCountryCode")) {
		if (sim->mcc)
			g_free(sim->mcc);
		sim->mcc = g_variant_dup_string(value, NULL);
	}
	else if (g_str_equal(name, "MobileNetworkCode")) {
		if (sim->mnc)
			g_free(sim->mnc);
		sim->mnc = g_variant_dup_string(value, NULL);
	}
	else if (g_str_equal(name, "CardIdentifier")) {
		if (sim->card_identifier)
			g_free(sim->card_identifier);
		sim->card_identifier = g_variant_dup_string(value, NULL);
	}
	else if (g_str_equal(name, "SubscriberIdentity")) {
		if (sim->subscriber_identity)
			g_free(sim->subscriber_identity);
		sim->subscriber_identity = g_variant_dup_string(value, NULL);
	}
	else if (g_str_equal(name, "SubscriberNumbers")) {
		if (sim->subscriber_numbers) {
			g_slist_free_full(sim->subscriber_numbers, g_free);
			sim->subscriber_numbers = NULL;
		}

		for (n = 0; n < g_variant_n_children(value); n++) {
			child = g_variant_get_child_value(value, n);
			subscriber_number = g_variant_dup_string(child, NULL);
			sim->subscriber_numbers = g_slist_append(sim->subscriber_numbers, subscriber_number);
		}
	}

	if (sim->prop_changed_cb)
		sim->prop_changed_cb(name, sim->prop_changed_data);
}
Beispiel #2
0
void show_dev_detail(void)
{
	struct sr_dev_inst *sdi;
	const struct sr_config_info *srci;
	struct sr_channel *ch;
	struct sr_channel_group *channel_group, *cg;
	GSList *devices, *cgl, *chl;
	GVariant *gvar_opts, *gvar_dict, *gvar_list, *gvar;
	gsize num_opts, num_elements;
	double dlow, dhigh, dcur_low, dcur_high;
	const uint64_t *uint64, p, q, low, high;
	uint64_t cur_low, cur_high;
	const int32_t *int32, *opts;
	unsigned int num_devices, o, i;
	char *tmp_str;
	char *s, c;
	const char **stropts;

	if (!(devices = device_scan())) {
		g_critical("No devices found.");
		return;
	}

	num_devices = g_slist_length(devices);
	if (num_devices > 1) {
		g_critical("%d devices found. Use --scan to show them, "
				"and select one to show.", num_devices);
		return;
	}

	sdi = devices->data;
	print_dev_line(sdi);

	if (sr_dev_open(sdi) != SR_OK) {
		g_critical("Failed to open device.");
		return;
	}

	if ((sr_config_list(sdi->driver, NULL, NULL, SR_CONF_SCAN_OPTIONS,
			&gvar_opts) == SR_OK)) {
		opts = g_variant_get_fixed_array(gvar_opts, &num_elements,
				sizeof(int32_t));
		printf("Supported driver options:\n");
		for (i = 0; i < num_elements; i++) {
			if (!(srci = sr_config_info_get(opts[i])))
				continue;
			printf("    %s\n", srci->id);
		}
		g_variant_unref(gvar_opts);
	}

	/* Selected channels and channel group may affect which options are
	 * returned, or which values for them. */
	select_channels(sdi);
	channel_group = select_channel_group(sdi);

	if ((sr_config_list(sdi->driver, sdi, channel_group, SR_CONF_DEVICE_OPTIONS,
			&gvar_opts)) != SR_OK)
		/* Driver supports no device instance options. */
		return;

	if (sdi->channel_groups) {
		printf("Channel groups:\n");
		for (cgl = sdi->channel_groups; cgl; cgl = cgl->next) {
			cg = cgl->data;
			printf("    %s: channel%s", cg->name,
					g_slist_length(cg->channels) > 1 ? "s" : "");
			for (chl = cg->channels; chl; chl = chl->next) {
				ch = chl->data;
				printf(" %s", ch->name);
			}
			printf("\n");
		}
	}

	printf("Supported configuration options");
	if (sdi->channel_groups) {
		if (!channel_group)
			printf(" across all channel groups");
		else
			printf(" on channel group %s", channel_group->name);
	}
	printf(":\n");
	opts = g_variant_get_fixed_array(gvar_opts, &num_opts, sizeof(int32_t));
	for (o = 0; o < num_opts; o++) {
		if (!(srci = sr_config_info_get(opts[o])))
			continue;

		if (srci->key == SR_CONF_TRIGGER_MATCH) {
			if (sr_config_list(sdi->driver, sdi, channel_group, srci->key,
					&gvar_list) != SR_OK) {
				printf("\n");
				continue;
			}
			int32 = g_variant_get_fixed_array(gvar_list,
					&num_elements, sizeof(int32_t));
			printf("    Supported triggers: ");
			for (i = 0; i < num_elements; i++) {
				switch(int32[i]) {
				case SR_TRIGGER_ZERO:
					c = '0';
					break;
				case SR_TRIGGER_ONE:
					c = '1';
					break;
				case SR_TRIGGER_RISING:
					c = 'r';
					break;
				case SR_TRIGGER_FALLING:
					c = 'f';
					break;
				case SR_TRIGGER_EDGE:
					c = 'e';
					break;
				case SR_TRIGGER_OVER:
					c = 'o';
					break;
				case SR_TRIGGER_UNDER:
					c = 'u';
					break;
				default:
					c = 0;
					break;
				}
				if (c)
					printf("%c ", c);
			}
			printf("\n");
			g_variant_unref(gvar_list);

		} else if (srci->key == SR_CONF_LIMIT_SAMPLES) {
			/* If implemented in config_list(), this denotes the
			 * maximum number of samples a device can send. This
			 * really applies only to logic analyzers, and then
			 * only to those that don't support compression, or
			 * have it turned off by default. The values returned
			 * are the low/high limits. */
			if (sr_config_list(sdi->driver, sdi, channel_group, srci->key,
					&gvar) != SR_OK) {
				continue;
			}
			g_variant_get(gvar, "(tt)", &low, &high);
			g_variant_unref(gvar);
			printf("    Maximum number of samples: %"PRIu64"\n", high);

		} else if (srci->key == SR_CONF_SAMPLERATE) {
			/* Supported samplerates */
			printf("    %s", srci->id);
			if (sr_config_list(sdi->driver, sdi, channel_group, SR_CONF_SAMPLERATE,
					&gvar_dict) != SR_OK) {
				printf("\n");
				continue;
			}
			if ((gvar_list = g_variant_lookup_value(gvar_dict,
					"samplerates", G_VARIANT_TYPE("at")))) {
				uint64 = g_variant_get_fixed_array(gvar_list,
						&num_elements, sizeof(uint64_t));
				printf(" - supported samplerates:\n");
				for (i = 0; i < num_elements; i++) {
					if (!(s = sr_samplerate_string(uint64[i])))
						continue;
					printf("      %s\n", s);
					g_free(s);
				}
				g_variant_unref(gvar_list);
			} else if ((gvar_list = g_variant_lookup_value(gvar_dict,
					"samplerate-steps", G_VARIANT_TYPE("at")))) {
				uint64 = g_variant_get_fixed_array(gvar_list,
						&num_elements, sizeof(uint64_t));
				/* low */
				if (!(s = sr_samplerate_string(uint64[0])))
					continue;
				printf(" (%s", s);
				g_free(s);
				/* high */
				if (!(s = sr_samplerate_string(uint64[1])))
					continue;
				printf(" - %s", s);
				g_free(s);
				/* step */
				if (!(s = sr_samplerate_string(uint64[2])))
					continue;
				printf(" in steps of %s)\n", s);
				g_free(s);
				g_variant_unref(gvar_list);
			}
			g_variant_unref(gvar_dict);

		} else if (srci->key == SR_CONF_BUFFERSIZE) {
			/* Supported buffer sizes */
			printf("    %s", srci->id);
			if (sr_config_list(sdi->driver, sdi, channel_group,
					SR_CONF_BUFFERSIZE, &gvar_list) != SR_OK) {
				printf("\n");
				continue;
			}
			uint64 = g_variant_get_fixed_array(gvar_list,
					&num_elements, sizeof(uint64_t));
			printf(" - supported buffer sizes:\n");
			for (i = 0; i < num_elements; i++)
				printf("      %"PRIu64"\n", uint64[i]);
			g_variant_unref(gvar_list);

		} else if (srci->key == SR_CONF_TIMEBASE) {
			/* Supported time bases */
			printf("    %s", srci->id);
			if (sr_config_list(sdi->driver, sdi, channel_group,
					SR_CONF_TIMEBASE, &gvar_list) != SR_OK) {
				printf("\n");
				continue;
			}
			printf(" - supported time bases:\n");
			num_elements = g_variant_n_children(gvar_list);
			for (i = 0; i < num_elements; i++) {
				gvar = g_variant_get_child_value(gvar_list, i);
				g_variant_get(gvar, "(tt)", &p, &q);
				s = sr_period_string(p * q);
				printf("      %s\n", s);
				g_free(s);
			}
			g_variant_unref(gvar_list);

		} else if (srci->key == SR_CONF_VDIV) {
			/* Supported volts/div values */
			printf("    %s", srci->id);
			if (sr_config_list(sdi->driver, sdi, channel_group,
					SR_CONF_VDIV, &gvar_list) != SR_OK) {
				printf("\n");
				continue;
			}
			printf(" - supported volts/div:\n");
			num_elements = g_variant_n_children(gvar_list);
			for (i = 0; i < num_elements; i++) {
				gvar = g_variant_get_child_value(gvar_list, i);
				g_variant_get(gvar, "(tt)", &p, &q);
				s = sr_voltage_string(p, q);
				printf("      %s\n", s);
				g_free(s);
			}
			g_variant_unref(gvar_list);

		} else if (srci->datatype == SR_T_STRING) {
			printf("    %s: ", srci->id);
			if (sr_config_get(sdi->driver, sdi, channel_group, srci->key,
					&gvar) == SR_OK) {
				tmp_str = g_strdup(g_variant_get_string(gvar, NULL));
				g_variant_unref(gvar);
			} else
				tmp_str = NULL;

			if (sr_config_list(sdi->driver, sdi, channel_group, srci->key,
					&gvar) != SR_OK) {
				printf("\n");
				continue;
			}

			stropts = g_variant_get_strv(gvar, &num_elements);
			for (i = 0; i < num_elements; i++) {
				if (i)
					printf(", ");
				printf("%s", stropts[i]);
				if (tmp_str && !strcmp(tmp_str, stropts[i]))
					printf(" (current)");
			}
			printf("\n");
			g_free(stropts);
			g_free(tmp_str);
			g_variant_unref(gvar);

		} else if (srci->datatype == SR_T_UINT64_RANGE) {
			printf("    %s: ", srci->id);
			if (sr_config_list(sdi->driver, sdi, channel_group, srci->key,
					&gvar_list) != SR_OK) {
				printf("\n");
				continue;
			}

			if (sr_config_get(sdi->driver, sdi, NULL, srci->key, &gvar) == SR_OK) {
				g_variant_get(gvar, "(tt)", &cur_low, &cur_high);
				g_variant_unref(gvar);
			} else {
				cur_low = 0;
				cur_high = 0;
			}

			num_elements = g_variant_n_children(gvar_list);
			for (i = 0; i < num_elements; i++) {
				gvar = g_variant_get_child_value(gvar_list, i);
				g_variant_get(gvar, "(tt)", &low, &high);
				g_variant_unref(gvar);
				if (i)
					printf(", ");
				printf("%"PRIu64"-%"PRIu64, low, high);
				if (low == cur_low && high == cur_high)
					printf(" (current)");
			}
			printf("\n");
			g_variant_unref(gvar_list);

		} else if (srci->datatype == SR_T_BOOL) {
			printf("    %s: ", srci->id);
			if (sr_config_get(sdi->driver, sdi, NULL, srci->key,
					&gvar) == SR_OK) {
				if (g_variant_get_boolean(gvar))
					printf("on (current), off\n");
				else
					printf("on, off (current)\n");
				g_variant_unref(gvar);
			} else
				printf("on, off\n");

		} else if (srci->datatype == SR_T_DOUBLE_RANGE) {
			printf("    %s: ", srci->id);
			if (sr_config_list(sdi->driver, sdi, channel_group, srci->key,
					&gvar_list) != SR_OK) {
				printf("\n");
				continue;
			}

			if (sr_config_get(sdi->driver, sdi, NULL, srci->key, &gvar) == SR_OK) {
				g_variant_get(gvar, "(dd)", &dcur_low, &dcur_high);
				g_variant_unref(gvar);
			} else {
				dcur_low = 0;
				dcur_high = 0;
			}

			num_elements = g_variant_n_children(gvar_list);
			for (i = 0; i < num_elements; i++) {
				gvar = g_variant_get_child_value(gvar_list, i);
				g_variant_get(gvar, "(dd)", &dlow, &dhigh);
				g_variant_unref(gvar);
				if (i)
					printf(", ");
				printf("%.1f-%.1f", dlow, dhigh);
				if (dlow == dcur_low && dhigh == dcur_high)
					printf(" (current)");
			}
			printf("\n");
			g_variant_unref(gvar_list);

		} else {

			/* Everything else */
			printf("    %s\n", srci->id);
		}
	}
	g_variant_unref(gvar_opts);

	sr_dev_close(sdi);
	g_slist_free(devices);

}
// Get the (key,value) pairs back from KWallet.
GHashTable *dt_pwstorage_kwallet_get(const backend_kwallet_context_t *context, const gchar *slot)
{
  GHashTable *table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
  GError *error = NULL;

  // Is there an entry in the wallet?
  gboolean has_entry = FALSE;
  int wallet_handle = get_wallet_handle(context);

  /* signature:
   *
   * in  i handle,
   * in  s folder,
   * in  s key,
   * in  s appid,
   *
   * out b arg_0
   */
  GVariant *ret = g_dbus_proxy_call_sync(context->proxy, "hasEntry",
                                         g_variant_new("(isss)", wallet_handle, kwallet_folder, slot, app_id),
                                         G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);

  if(check_error(error))
  {
    g_variant_unref(ret);
    return table;
  }

  GVariant *child = g_variant_get_child_value(ret, 0);
  has_entry = g_variant_get_boolean(child);
  g_variant_unref(child);
  g_variant_unref(ret);

  if(!has_entry) return table;

  /* signature:
   *
   * in  i handle,
   * in  s folder,
   * in  s key,
   * in  s appid,
   *
   * out a{sv} arg_0)
   */
  ret = g_dbus_proxy_call_sync(context->proxy, "readMapList",
                               g_variant_new("(isss)", wallet_handle, kwallet_folder, slot, app_id),
                               G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);

  if(check_error(error))
  {
    g_variant_unref(ret);
    return table;
  }

  child = g_variant_get_child_value(ret, 0);

  // we are only interested in the first child. i am not even sure that there can legally be more than one
  if(g_variant_n_children(child) < 1)
  {
    g_variant_unref(child);
    g_variant_unref(ret);
    return table;
  }

  GVariant *element = g_variant_get_child_value(child, 0);
  GVariant *v = NULL;
  g_variant_get(element, "{sv}", NULL, &v);

  const gchar *byte_array = g_variant_get_data(v);
  if(!byte_array)
  {
    g_variant_unref(v);
    g_variant_unref(element);
    g_variant_unref(child);
    g_variant_unref(ret);
    return table;
  }

  int entries = GINT_FROM_BE(*((int *)byte_array));
  byte_array += sizeof(gint);

  for(int i = 0; i < entries; i++)
  {
    guint length;
    gchar *key = array2string(byte_array, &length);

    byte_array += length;

    gchar *value = array2string(byte_array, &length);

    byte_array += length;

    dt_print(DT_DEBUG_PWSTORAGE, "[pwstorage_kwallet_get] reading (%s, %s)\n", (gchar *)key, (gchar *)value);

    g_hash_table_insert(table, key, value);
  }

  g_variant_unref(v);
  g_variant_unref(element);
  g_variant_unref(child);
  g_variant_unref(ret);

  return table;
}
Beispiel #4
0
  static void sGetEntries(cDBusObject *Object, GVariant *Parameters, GDBusMethodInvocation *Invocation, eMode mode)
  {
#if VDRVERSNUM > 20300
    LOCK_CHANNELS_READ;
    const cChannels *channels = Channels;
#else
    cChannels *channels = &Channels;
#endif
    const cChannel *channel = NULL;
    guint64 atTime = 0;
    GVariant *first = g_variant_get_child_value(Parameters, 0);
    
    const char *c = NULL;
    if (!sGetChannel(first, &c, channels, &channel)) {
       cString reply = cString::sprintf("channel \"%s\" not defined", c);
       esyslog("dbus2vdr: %s.GetEntries: %s", DBUS_VDR_EPG_INTERFACE, *reply);
       sReturnError(Invocation, 501, *reply);
       g_variant_unref(first);
       return;
       }
    if (mode == dmmAtTime) {
       GVariant *second = g_variant_get_child_value(Parameters, 1);
       g_variant_get(second, "t", &atTime);
       g_variant_unref(second);
       if (atTime == 0) {
          cString reply = cString::sprintf("missing time");
          esyslog("dbus2vdr: %s.GetEntries: %s", DBUS_VDR_EPG_INTERFACE, *reply);
          sReturnError(Invocation, 501, *reply);
          g_variant_unref(first);
          return;
          }
       }
    g_variant_unref(first);

    const cSchedules *scheds = NULL;
#if VDRVERSNUM > 20300
    cStateKey StateKey;
    scheds = cSchedules::GetSchedulesRead(StateKey, 1000);
#else
    cSchedulesLock sl(false, 1000);
    if (!sl.Locked()) {
       sReturnError(Invocation, 550, "got no lock on schedules");
       return;
       }

    scheds = cSchedules::Schedules(sl);
#endif
    if (scheds == NULL) {
       sReturnError(Invocation, 550, "got no schedules");
       return;
       }

    GVariantBuilder *builder = g_variant_builder_new(G_VARIANT_TYPE("(isaa(sv))"));
    g_variant_builder_add(builder, "i", 250);
    g_variant_builder_add(builder, "s", "");
    GVariantBuilder *array = g_variant_builder_new(G_VARIANT_TYPE("aa(sv)"));

    bool next = false;
    if (channel == NULL) {
       channel = channels->First();
       next = true;
       }

    while (channel) {
          const cSchedule *s = scheds->GetSchedule(channel, false);
          if (s != NULL) {
             const cEvent *e = NULL;
             switch (mode) {
               case dmmPresent:
                 e = s->GetPresentEvent();
                 break;
               case dmmFollowing:
                 e = s->GetFollowingEvent();
                 break;
               case dmmAtTime:
                 e = s->GetEventAround(atTime);
                 break;
               default:
                 e = NULL;
                 break;
               }
             if (e != NULL)
                sAddEvent(array, *e);
             }
          if (next)
             channel = channels->Next(channel);
          else
             break;
          }

#if VDRVERSNUM > 20300
    StateKey.Remove();
#endif
    g_variant_builder_add_value(builder, g_variant_builder_end(array));
    g_dbus_method_invocation_return_value(Invocation, g_variant_builder_end(builder));
    g_variant_builder_unref(array);
    g_variant_builder_unref(builder);
  };
// get the handle for connections to KWallet
static int get_wallet_handle(const backend_kwallet_context_t *context)
{
  // Open the wallet.
  int handle = invalid_kwallet_handle;
  GError *error = NULL;

  /* signature:
   *
   * in  s wallet,
   * in  x wId,
   * in  s appid,
   *
   * out i arg_0
   */
  GVariant *ret = g_dbus_proxy_call_sync(context->proxy, "open",
                                         g_variant_new("(sxs)", context->wallet_name, 0LL, app_id),
                                         G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);

  if(check_error(error))
  {
    g_variant_unref(ret);
    return invalid_kwallet_handle;
  }

  GVariant *child = g_variant_get_child_value(ret, 0);
  handle = g_variant_get_int32(child);
  g_variant_unref(child);
  g_variant_unref(ret);

  // Check if our folder exists.
  gboolean has_folder = FALSE;

  /* signature:
   *
   * in  i handle,
   * in  s folder,
   * in  s appid,
   *
   * out b arg_0
   */
  ret = g_dbus_proxy_call_sync(context->proxy, "hasFolder",
                               g_variant_new("(iss)", handle, kwallet_folder, app_id), G_DBUS_CALL_FLAGS_NONE,
                               -1, NULL, &error);

  if(check_error(error))
  {
    g_variant_unref(ret);
    return invalid_kwallet_handle;
  }

  child = g_variant_get_child_value(ret, 0);
  has_folder = g_variant_get_boolean(child);
  g_variant_unref(child);
  g_variant_unref(ret);

  // Create it if it didn't.
  if(!has_folder)
  {

    gboolean success = FALSE;

    /* signature:
     *
     * in  i handle,
     * in  s folder,
     * in  s appid,
     *
     * out b arg_0
     */
    ret = g_dbus_proxy_call_sync(context->proxy, "createFolder",
                                 g_variant_new("(iss)", handle, kwallet_folder, app_id),
                                 G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);

    if(check_error(error))
    {
      g_variant_unref(ret);
      return invalid_kwallet_handle;
    }

    GVariant *child = g_variant_get_child_value(ret, 0);
    success = g_variant_get_boolean(child);
    g_variant_unref(child);
    g_variant_unref(ret);

    if(!success) return invalid_kwallet_handle;
  }

  return handle;
}
// Store (key,value) pairs from a GHashTable in the kwallet.
// Every 'slot' has to take care of it's own data.
gboolean dt_pwstorage_kwallet_set(const backend_kwallet_context_t *context, const gchar *slot,
                                  GHashTable *table)
{
  printf("slot %s\n", slot);

  GArray *byte_array = g_array_new(FALSE, FALSE, sizeof(gchar));

  GHashTableIter iter;
  g_hash_table_iter_init(&iter, table);
  gpointer key, value;

  guint size = g_hash_table_size(table);

  size = GINT_TO_BE(size);

  g_array_append_vals(byte_array, &size, sizeof(guint) / sizeof(gchar));

  while(g_hash_table_iter_next(&iter, &key, &value))
  {
    dt_print(DT_DEBUG_PWSTORAGE, "[pwstorage_kwallet_set] storing (%s, %s)\n", (gchar *)key, (gchar *)value);
    gsize length;
    gchar *new_key = char2qstring(key, &length);
    if(new_key == NULL)
    {
      g_free(g_array_free(byte_array, FALSE));
      return FALSE;
    }
    g_array_append_vals(byte_array, new_key, length);
    g_free(new_key);

    gchar *new_value = char2qstring(value, &length);
    if(new_value == NULL)
    {
      g_free(g_array_free(byte_array, FALSE));
      return FALSE;
    }
    g_array_append_vals(byte_array, new_value, length);
    g_free(new_value);
  }

  int wallet_handle = get_wallet_handle(context);
  GError *error = NULL;

  /* signature:
   *
   * in  i handle,
   * in  s folder,
   * in  s key,
   * in  ay value,
   * in  s appid,
   *
   * out i arg_0
   */
  GVariant *ret = g_dbus_proxy_call_sync(
      context->proxy, "writeMap",
      g_variant_new("(iss@ays)", wallet_handle, kwallet_folder, slot,
                    g_variant_new_from_data(G_VARIANT_TYPE_BYTESTRING, byte_array->data, byte_array->len,
                                            TRUE, g_free, byte_array->data),
                    app_id),
      G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error);

  g_array_free(byte_array, FALSE);

  if(check_error(error))
  {
    g_variant_unref(ret);
    return FALSE;
  }

  GVariant *child = g_variant_get_child_value(ret, 0);
  int return_code = g_variant_get_int32(child);
  g_variant_unref(child);
  g_variant_unref(ret);

  if(return_code != 0)
    dt_print(DT_DEBUG_PWSTORAGE, "[pwstorage_kwallet_set] Warning: bad return code %d from kwallet\n",
             return_code);

  return return_code == 0;
}
static void
flickr_credentials_mgr_goa_on_managed_objects(GObject* mgr_proxy, GAsyncResult* result, gpointer user_data) {
/* UserCode on_managed_objects { */

    FlickrCredentialsLoadClosure *closure = (FlickrCredentialsLoadClosure *) user_data;
    FlickrCredentialsManagerGOA *self = FLICKR_CREDENTIALS_MANAGER_GOA (closure->credentials);
    gboolean error_occurred = FALSE;
    GError *error = NULL;

    if (!result) {
        error_occurred = TRUE;
        goto exit;
    }

    GVariant *result_data = g_dbus_proxy_call_finish ((GDBusProxy *) mgr_proxy, result, NULL);

    if (!result_data) {
        error_occurred = TRUE;
        goto exit;
    }

    GVariant *content = g_variant_get_child_value (result_data, 0);
    g_variant_unref (result_data);
   
    GVariantIter iter;
    GVariant *child;
    GVariant *object_path;
    GVariant *interfaces;
    GVariant *account;
    GVariant *provider_type;
    gboolean done = FALSE;
        
    g_variant_iter_init (&iter, content);

    while ((child = g_variant_iter_next_value(&iter))) {

        /* Check whether child is an account: */
        interfaces = g_variant_get_child_value (child, 1);

        account = g_variant_lookup_value (
            interfaces, 
            "org.gnome.OnlineAccounts.Account",
            NULL
            );

        if (account) {
              
            /* Is account a flickr account? */
            provider_type = g_variant_lookup_value (account, "ProviderType", NULL);

            if (provider_type) {

                if (g_strcmp0 (g_variant_get_string (provider_type, NULL), "flickr") == 0) {

                    object_path = g_variant_get_child_value (child, 0);
                    self->priv->object_path = g_strdup (g_variant_get_string (object_path, NULL));
                    g_variant_unref (object_path);
                
                    flickr_credentials_mgr_goa_get_access_data (
                        self, 
                        interfaces,
                        closure,
                        &error
                        );
                
                    error_occurred = error ? TRUE : FALSE;
                    done = TRUE;

                }

                g_variant_unref (provider_type);
            }

            g_variant_unref (account);

        }

        g_variant_unref (interfaces);

        if (done) {
            break;
        }

    }

    g_variant_unref (content);

    exit:

    g_object_unref (mgr_proxy);

    if (error_occurred) {
        closure->callback (closure->credentials, FALSE, error, closure->user_data);
        flickr_credentials_load_closure_free (closure);
    }

    if (error) {
        g_error_free (error);
    }

/* } UserCode */
}
Beispiel #8
0
static gint64
arv_rtkit_get_int_property (GDBusConnection *connection, const char* propname, GError **error) {

	GDBusMessage *message;
	GDBusMessage *reply;
	GError *local_error = NULL;
	GVariant *body;
	GVariant *parameter;
	GVariant *variant;
	const GVariantType *variant_type;
	gint64 value;

	message = g_dbus_message_new_method_call (RTKIT_SERVICE_NAME,
						  RTKIT_OBJECT_PATH,
						  "org.freedesktop.DBus.Properties",
						  "Get");
	g_dbus_message_set_body (message, g_variant_new ("(ss)", "org.freedesktop.RealtimeKit1", propname));

	reply = g_dbus_connection_send_message_with_reply_sync (connection, message,
								G_DBUS_SEND_MESSAGE_FLAGS_NONE, 1000, NULL, NULL,
								&local_error);
	g_object_unref (message);

	if (local_error != NULL) {
		g_propagate_error (error, local_error);
		return 0;
	}

	if (g_dbus_message_get_message_type (reply) != G_DBUS_MESSAGE_TYPE_METHOD_RETURN) {
		local_error = g_error_new (ARV_RTKIT_ERROR, ARV_RTKIT_ERROR_PERMISSION_DENIED,
					   "%s", g_dbus_message_get_error_name (reply));
		g_propagate_error (error, local_error);
		g_object_unref (reply);
		return 0;
	}

	if (!g_variant_type_equal ("v", g_dbus_message_get_signature (reply))) {
		local_error = g_error_new (ARV_RTKIT_ERROR, ARV_RTKIT_ERROR_WRONG_REPLY,
					   "Invalid reply signature");
		g_propagate_error (error, local_error);
		g_object_unref (reply);
		return 0;
	}

	body = g_dbus_message_get_body (reply);
	parameter = g_variant_get_child_value (body, 0);
	variant = g_variant_get_variant (parameter);

	variant_type = g_variant_get_type (variant);

	if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT32))
		value = g_variant_get_int32 (variant);
	else if (g_variant_type_equal (variant_type, G_VARIANT_TYPE_INT64))
		value = g_variant_get_int64 (variant);
	else
		value = 0;

	g_variant_unref (parameter);
	g_variant_unref (variant);
	g_object_unref (reply);

	return value;
}
gboolean
flatpak_builtin_build_commit_from (int argc, char **argv, GCancellable *cancellable, GError **error)
{
  g_autoptr(GOptionContext) context = NULL;
  g_autoptr(GFile) dst_repofile = NULL;
  g_autoptr(OstreeRepo) dst_repo = NULL;
  g_autoptr(GFile) src_repofile = NULL;
  g_autoptr(OstreeRepo) src_repo = NULL;
  g_autofree char *src_repo_uri = NULL;
  const char *dst_repo_arg;
  const char **dst_refs;
  int n_dst_refs = 0;
  g_autoptr(FlatpakRepoTransaction) transaction = NULL;
  g_autoptr(GPtrArray) src_refs = NULL;
  g_autoptr(GPtrArray) resolved_src_refs = NULL;
  OstreeRepoCommitState src_commit_state;
  struct timespec ts;
  guint64 timestamp;
  int i;

  context = g_option_context_new (_("DST-REPO [DST-REF…] - Make a new commit from existing commits"));
  g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);

  if (!flatpak_option_context_parse (context, options, &argc, &argv, FLATPAK_BUILTIN_FLAG_NO_DIR, NULL, cancellable, error))
    return FALSE;

  if (argc < 2)
    return usage_error (context, _("DST-REPO must be specified"), error);

  dst_repo_arg = argv[1];

  dst_refs = (const char **) argv + 2;
  n_dst_refs = argc - 2;

  if (opt_src_repo == NULL && n_dst_refs != 1)
    return usage_error (context, _("If --src-repo is not specified, exactly one destination ref must be specified"), error);

  if (opt_src_ref != NULL && n_dst_refs != 1)
    return usage_error (context, _("If --src-ref is specified, exactly one destination ref must be specified"), error);

  if (opt_src_repo == NULL && opt_src_ref == NULL)
    return flatpak_fail (error, _("Either --src-repo or --src-ref must be specified."));

  if (opt_timestamp)
    {
      if (!parse_datetime (&ts, opt_timestamp, NULL))
        return flatpak_fail (error, _("Could not parse '%s'"), opt_timestamp);
    }

  dst_repofile = g_file_new_for_commandline_arg (dst_repo_arg);
  if (!g_file_query_exists (dst_repofile, cancellable))
    return flatpak_fail (error, _("'%s' is not a valid repository"), dst_repo_arg);

  dst_repo = ostree_repo_new (dst_repofile);
  if (!ostree_repo_open (dst_repo, cancellable, error))
    return FALSE;

  if (opt_disable_fsync)
    ostree_repo_set_disable_fsync (dst_repo, TRUE);

  if (opt_src_repo)
    {
      src_repofile = g_file_new_for_commandline_arg (opt_src_repo);
      if (!g_file_query_exists (src_repofile, cancellable))
        return flatpak_fail (error, _("'%s' is not a valid repository"), opt_src_repo);

      src_repo_uri = g_file_get_uri (src_repofile);
      src_repo = ostree_repo_new (src_repofile);
      if (!ostree_repo_open (src_repo, cancellable, error))
        return FALSE;
    }
  else
    {
      src_repo = g_object_ref (dst_repo);
    }

  src_refs = g_ptr_array_new_with_free_func (g_free);
  if (opt_src_ref)
    {
      g_assert (n_dst_refs == 1);
      g_ptr_array_add (src_refs, g_strdup (opt_src_ref));
    }
  else
    {
      g_assert (opt_src_repo != NULL);
      if (n_dst_refs == 0)
        {
          g_autofree const char **keys = NULL;
          g_autoptr(GHashTable) all_src_refs = NULL;

          if (!ostree_repo_list_refs (src_repo, NULL, &all_src_refs,
                                      cancellable, error))
            return FALSE;

          keys = (const char **) g_hash_table_get_keys_as_array (all_src_refs, NULL);

          for (i = 0; keys[i] != NULL; i++)
            {
              if (g_str_has_prefix (keys[i], "runtime/") ||
                  g_str_has_prefix (keys[i], "app/"))
                g_ptr_array_add (src_refs, g_strdup (keys[i]));
            }
          n_dst_refs = src_refs->len;
          dst_refs = (const char **) src_refs->pdata;
        }
      else
        {
          for (i = 0; i < n_dst_refs; i++)
            g_ptr_array_add (src_refs, g_strdup (dst_refs[i]));
        }
    }

  resolved_src_refs = g_ptr_array_new_with_free_func (g_free);
  for (i = 0; i < src_refs->len; i++)
    {
      const char *src_ref = g_ptr_array_index (src_refs, i);
      char *resolved_ref;

      if (!ostree_repo_resolve_rev (src_repo, src_ref, FALSE, &resolved_ref, error))
        return FALSE;

      g_ptr_array_add (resolved_src_refs, resolved_ref);
    }

  if (src_repo_uri != NULL)
    {
      OstreeRepoPullFlags pullflags = 0;
      GVariantBuilder builder;
      g_autoptr(OstreeAsyncProgress) progress = NULL;
      g_auto(GLnxConsoleRef) console = { 0, };
      g_autoptr(GVariant) options = NULL;
      gboolean res;

      if (opt_untrusted)
        pullflags |= OSTREE_REPO_PULL_FLAGS_UNTRUSTED;

      glnx_console_lock (&console);
      if (console.is_tty)
        progress = ostree_async_progress_new_and_connect (ostree_repo_pull_default_console_progress_changed, &console);

      g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
      g_variant_builder_add (&builder, "{s@v}", "flags",
                             g_variant_new_variant (g_variant_new_int32 (pullflags)));
      g_variant_builder_add (&builder, "{s@v}", "refs",
                             g_variant_new_variant (g_variant_new_strv ((const char * const *) resolved_src_refs->pdata,
                                                                        resolved_src_refs->len)));
      g_variant_builder_add (&builder, "{s@v}", "depth",
                             g_variant_new_variant (g_variant_new_int32 (0)));

      options = g_variant_ref_sink (g_variant_builder_end (&builder));
      res = ostree_repo_pull_with_options (dst_repo, src_repo_uri,
                                           options,
                                           progress,
                                           cancellable, error);

      if (progress)
        ostree_async_progress_finish (progress);

      if (!res)
        return FALSE;
    }

  /* By now we have the commit with commit_id==resolved_ref and dependencies in dst_repo. We now create a new
   * commit based on the toplevel tree ref from that commit.
   * This is equivalent to:
   *   ostree commit --skip-if-unchanged --repo=${destrepo} --tree=ref=${resolved_ref}
   */

  transaction = flatpak_repo_transaction_start (dst_repo, cancellable, error);
  if (transaction == NULL)
    return FALSE;

  for (i = 0; i < resolved_src_refs->len; i++)
    {
      const char *dst_ref = dst_refs[i];
      const char *resolved_ref = g_ptr_array_index (resolved_src_refs, i);
      g_autofree char *dst_parent = NULL;
      g_autoptr(GFile) dst_parent_root = NULL;
      g_autoptr(GFile) src_ref_root = NULL;
      g_autoptr(GVariant) src_commitv = NULL;
      g_autoptr(GVariant) dst_commitv = NULL;
      g_autoptr(OstreeMutableTree) mtree = NULL;
      g_autoptr(GFile) dst_root = NULL;
      g_autoptr(GVariant) commitv_metadata = NULL;
      g_autoptr(GVariant) metadata = NULL;
      const char *subject;
      const char *body;
      g_autofree char *commit_checksum = NULL;
      GVariantBuilder metadata_builder;
      gint j;
      const char *dst_collection_id = NULL;
      const char *main_collection_id = NULL;
      g_autoptr(GPtrArray) collection_ids = NULL;

      if (!ostree_repo_resolve_rev (dst_repo, dst_ref, TRUE, &dst_parent, error))
        return FALSE;

      if (dst_parent != NULL &&
          !ostree_repo_read_commit (dst_repo, dst_parent, &dst_parent_root, NULL, cancellable, error))
        return FALSE;

      if (!ostree_repo_read_commit (dst_repo, resolved_ref, &src_ref_root, NULL, cancellable, error))
        return FALSE;

      if (!ostree_repo_load_commit (dst_repo, resolved_ref, &src_commitv, &src_commit_state, error))
        return FALSE;

      if (src_commit_state & OSTREE_REPO_COMMIT_STATE_PARTIAL)
        return flatpak_fail (error, _("Can't commit from partial source commit."));

      /* Don't create a new commit if this is the same tree */
      if (!opt_force && dst_parent_root != NULL && g_file_equal (dst_parent_root, src_ref_root))
        {
          g_print (_("%s: no change\n"), dst_ref);
          continue;
        }

      mtree = ostree_mutable_tree_new ();
      if (!ostree_repo_write_directory_to_mtree (dst_repo, src_ref_root, mtree, NULL,
                                                 cancellable, error))
        return FALSE;

      if (!ostree_repo_write_mtree (dst_repo, mtree, &dst_root, cancellable, error))
        return FALSE;

      commitv_metadata = g_variant_get_child_value (src_commitv, 0);

      g_variant_get_child (src_commitv, 3, "&s", &subject);
      if (opt_subject)
        subject = (const char *) opt_subject;
      g_variant_get_child (src_commitv, 4, "&s", &body);
      if (opt_body)
        body = (const char *) opt_body;

      dst_collection_id = ostree_repo_get_collection_id (dst_repo);

      collection_ids = g_ptr_array_new_with_free_func (g_free);
      if (dst_collection_id)
        {
          main_collection_id = dst_collection_id;
          g_ptr_array_add (collection_ids, g_strdup (dst_collection_id));
        }

      if (opt_extra_collection_ids != NULL)
        {
          for (j = 0; opt_extra_collection_ids[j] != NULL; j++)
            {
              const char *cid = opt_extra_collection_ids[j];
              if (main_collection_id == NULL)
                main_collection_id = cid; /* Fall back to first arg */

              if (g_strcmp0 (cid, dst_collection_id) != 0)
                g_ptr_array_add (collection_ids, g_strdup (cid));
            }
        }

      g_ptr_array_sort (collection_ids, (GCompareFunc)flatpak_strcmp0_ptr);

      /* Copy old metadata */
      g_variant_builder_init (&metadata_builder, G_VARIANT_TYPE ("a{sv}"));

      /* Bindings. xa.ref is deprecated but added anyway for backwards compatibility. */
      g_variant_builder_add (&metadata_builder, "{sv}", "ostree.collection-binding",
                             g_variant_new_string (main_collection_id ? main_collection_id : ""));
      if (collection_ids->len > 0)
        {
          g_autoptr(GVariantBuilder) cr_builder = g_variant_builder_new (G_VARIANT_TYPE ("a(ss)"));

          for (j = 0; j < collection_ids->len; j++)
            g_variant_builder_add (cr_builder, "(ss)", g_ptr_array_index (collection_ids, j), dst_ref);

          g_variant_builder_add (&metadata_builder, "{sv}", "ostree.collection-refs-binding",
                                 g_variant_builder_end (cr_builder));
        }
      g_variant_builder_add (&metadata_builder, "{sv}", "ostree.ref-binding",
                             g_variant_new_strv (&dst_ref, 1));
      g_variant_builder_add (&metadata_builder, "{sv}", "xa.ref", g_variant_new_string (dst_ref));

      /* Record the source commit. This is nice to have, but it also
         means the commit-from gets a different commit id, which
         avoids problems with e.g.  sharing .commitmeta files
         (signatures) */
      g_variant_builder_add (&metadata_builder, "{sv}", "xa.from_commit", g_variant_new_string (resolved_ref));

      for (j = 0; j < g_variant_n_children (commitv_metadata); j++)
        {
          g_autoptr(GVariant) child = g_variant_get_child_value (commitv_metadata, j);
          g_autoptr(GVariant) keyv = g_variant_get_child_value (child, 0);
          const char *key = g_variant_get_string (keyv, NULL);

          if (strcmp (key, "xa.ref") == 0 ||
              strcmp (key, "xa.from_commit") == 0 ||
              strcmp (key, "ostree.collection-binding") == 0 ||
              strcmp (key, "ostree.collection-refs-binding") == 0 ||
              strcmp (key, "ostree.ref-binding") == 0)
            continue;

          if (opt_endoflife &&
              strcmp (key, OSTREE_COMMIT_META_KEY_ENDOFLIFE) == 0)
            continue;

          g_variant_builder_add_value (&metadata_builder, child);
        }

      if (opt_endoflife && *opt_endoflife)
        g_variant_builder_add (&metadata_builder, "{sv}", OSTREE_COMMIT_META_KEY_ENDOFLIFE,
                               g_variant_new_string (opt_endoflife));

      timestamp = ostree_commit_get_timestamp (src_commitv);
      if (opt_timestamp)
        timestamp = ts.tv_sec;

      metadata = g_variant_ref_sink (g_variant_builder_end (&metadata_builder));
      if (!ostree_repo_write_commit_with_time (dst_repo, dst_parent, subject, body, metadata,
                                               OSTREE_REPO_FILE (dst_root),
                                               timestamp,
                                               &commit_checksum, cancellable, error))
        return FALSE;

      g_print ("%s: %s\n", dst_ref, commit_checksum);

      if (!ostree_repo_load_commit (dst_repo, commit_checksum, &dst_commitv, NULL, error))
        return FALSE;

      /* This doesn't copy the detached metadata. I'm not sure if this is a problem.
       * The main thing there is commit signatures, and we can't copy those, as the commit hash changes.
       */

      if (opt_gpg_key_ids)
        {
          char **iter;

          for (iter = opt_gpg_key_ids; iter && *iter; iter++)
            {
              const char *keyid = *iter;
              g_autoptr(GError) my_error = NULL;

              if (!ostree_repo_sign_commit (dst_repo,
                                            commit_checksum,
                                            keyid,
                                            opt_gpg_homedir,
                                            cancellable,
                                            &my_error) &&
                  !g_error_matches (my_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
                {
                  g_propagate_error (error, g_steal_pointer (&my_error));
                  return FALSE;
                }
            }
        }

      if (dst_collection_id != NULL)
        {
          OstreeCollectionRef ref = { (char *) dst_collection_id, (char *) dst_ref };
          ostree_repo_transaction_set_collection_ref (dst_repo, &ref, commit_checksum);
        }
      else
        {
          ostree_repo_transaction_set_ref (dst_repo, NULL, dst_ref, commit_checksum);
        }

      if (opt_extra_collection_ids)
        {
          for (j = 0; opt_extra_collection_ids[j] != NULL; j++)
            {
              OstreeCollectionRef ref = { (char *) opt_extra_collection_ids[j], (char *) dst_ref };
              ostree_repo_transaction_set_collection_ref (dst_repo, &ref, commit_checksum);
            }
        }

      /* Copy + Rewrite any deltas */
      {
        const char *from[2];
        gsize j, n_from = 0;

        if (dst_parent != NULL)
          from[n_from++] = dst_parent;
        from[n_from++] = NULL;

        for (j = 0; j < n_from; j++)
          {
            g_autoptr(GError) local_error = NULL;
            if (!rewrite_delta (src_repo, resolved_ref, dst_repo, commit_checksum, dst_commitv, from[j], &local_error))
              g_debug ("Failed to copy delta: %s", local_error->message);
          }
      }
    }

  if (!ostree_repo_commit_transaction (dst_repo, NULL, cancellable, error))
    return FALSE;

  if (opt_update_appstream &&
      !flatpak_repo_generate_appstream (dst_repo, (const char **) opt_gpg_key_ids, opt_gpg_homedir, 0, cancellable, error))
    return FALSE;

  if (!opt_no_update_summary &&
      !flatpak_repo_update (dst_repo,
                            (const char **) opt_gpg_key_ids,
                            opt_gpg_homedir,
                            cancellable,
                            error))
    return FALSE;

  return TRUE;
}
static gboolean
rewrite_delta (OstreeRepo *src_repo,
               const char *src_commit,
               OstreeRepo *dst_repo,
               const char *dst_commit,
               GVariant   *dst_commitv,
               const char *from,
               GError    **error)
{
  g_autoptr(GFile) src_delta_file = NULL;
  g_autoptr(GFile) dst_delta_file = NULL;
  g_autofree char *src_detached_key = _ostree_get_relative_static_delta_path (from, src_commit, "commitmeta");
  g_autofree char *dst_detached_key = _ostree_get_relative_static_delta_path (from, dst_commit, "commitmeta");
  g_autofree char *src_delta_dir = _ostree_get_relative_static_delta_path (from, src_commit, NULL);
  g_autofree char *dst_delta_dir = _ostree_get_relative_static_delta_path (from, dst_commit, NULL);
  g_autofree char *src_superblock_path = _ostree_get_relative_static_delta_path (from, src_commit, "superblock");
  g_autofree char *dst_superblock_path = _ostree_get_relative_static_delta_path (from, dst_commit, "superblock");
  GMappedFile *mfile = NULL;
  g_auto(GVariantBuilder) superblock_builder = FLATPAK_VARIANT_BUILDER_INITIALIZER;
  g_autoptr(GVariant) src_superblock = NULL;
  g_autoptr(GVariant) dst_superblock = NULL;
  g_autoptr(GBytes) bytes = NULL;
  g_autoptr(GVariant) dst_detached = NULL;
  g_autoptr(GVariant) src_metadata = NULL;
  g_autoptr(GVariant) src_recurse = NULL;
  g_autoptr(GVariant) src_parts = NULL;
  g_auto(GVariantDict) dst_metadata_dict = FLATPAK_VARIANT_DICT_INITIALIZER;
  int i;

  src_delta_file = g_file_resolve_relative_path (ostree_repo_get_path (src_repo), src_superblock_path);
  mfile = g_mapped_file_new (flatpak_file_get_path_cached (src_delta_file), FALSE, NULL);
  if (mfile == NULL)
    return TRUE; /* No superblock, not an error */

  bytes = g_mapped_file_get_bytes (mfile);
  g_mapped_file_unref (mfile);

  src_superblock = g_variant_ref_sink (g_variant_new_from_bytes (G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT), bytes, FALSE));

  src_metadata = g_variant_get_child_value (src_superblock, 0);
  src_recurse = g_variant_get_child_value (src_superblock, 5);
  src_parts = g_variant_get_child_value (src_superblock, 6);

  if (g_variant_n_children (src_recurse) != 0)
    return flatpak_fail (error, "Recursive deltas not supported, ignoring");

  g_variant_builder_init (&superblock_builder, G_VARIANT_TYPE (OSTREE_STATIC_DELTA_SUPERBLOCK_FORMAT));

  g_variant_dict_init (&dst_metadata_dict, src_metadata);
  g_variant_dict_remove (&dst_metadata_dict, src_detached_key);
  if (ostree_repo_read_commit_detached_metadata (dst_repo, dst_commit, &dst_detached, NULL, NULL) &&
      dst_detached != NULL)
    g_variant_dict_insert_value (&dst_metadata_dict, dst_detached_key, dst_detached);

  g_variant_builder_add_value (&superblock_builder, g_variant_dict_end (&dst_metadata_dict));
  g_variant_builder_add_value (&superblock_builder, g_variant_get_child_value (src_superblock, 1)); /* timestamp */
  g_variant_builder_add_value (&superblock_builder, from ? ostree_checksum_to_bytes_v (from) : new_bytearray ((guchar *) "", 0));
  g_variant_builder_add_value (&superblock_builder, ostree_checksum_to_bytes_v (dst_commit));
  g_variant_builder_add_value (&superblock_builder, dst_commitv);
  g_variant_builder_add_value (&superblock_builder, src_recurse);
  g_variant_builder_add_value (&superblock_builder, src_parts);
  g_variant_builder_add_value (&superblock_builder, g_variant_get_child_value (src_superblock, 7)); /* fallback */

  dst_superblock = g_variant_ref_sink (g_variant_builder_end (&superblock_builder));

  if (!glnx_shutil_mkdir_p_at (ostree_repo_get_dfd (dst_repo), dst_delta_dir, 0755, NULL, error))
    return FALSE;

  for (i = 0; i < g_variant_n_children (src_parts); i++)
    {
      g_autofree char *src_part_path = g_strdup_printf ("%s/%d", src_delta_dir, i);
      g_autofree char *dst_part_path = g_strdup_printf ("%s/%d", dst_delta_dir, i);

      if (!glnx_file_copy_at (ostree_repo_get_dfd (src_repo),
                              src_part_path,
                              NULL,
                              ostree_repo_get_dfd (dst_repo),
                              dst_part_path,
                              GLNX_FILE_COPY_OVERWRITE | GLNX_FILE_COPY_NOXATTRS,
                              NULL, error))
        return FALSE;
    }

  dst_delta_file = g_file_resolve_relative_path (ostree_repo_get_path (dst_repo), dst_superblock_path);
  if (!flatpak_variant_save (dst_delta_file, dst_superblock, NULL, error))
    return FALSE;

  return TRUE;
}
JSValueRef dbus_to_js(JSContextRef ctx, GVariant *dbus)
{
    JSValueRef jsvalue = NULL;
    GVariantClass type = g_variant_classify(dbus);
    switch (type) {
        case G_VARIANT_CLASS_STRING:
        case G_VARIANT_CLASS_OBJECT_PATH:
        case G_VARIANT_CLASS_SIGNATURE: {
                JSStringRef js_string = JSStringCreateWithUTF8CString(
                      g_variant_get_string(dbus, NULL));
                jsvalue = JSValueMakeString(ctx, js_string);
                JSStringRelease(js_string);
                return jsvalue;
            }

        case G_VARIANT_CLASS_BYTE:
            return JSValueMakeNumber(ctx, g_variant_get_byte(dbus));

        case G_VARIANT_CLASS_DOUBLE:
            return JSValueMakeNumber(ctx, g_variant_get_double(dbus));

        case G_VARIANT_CLASS_INT16:
            return JSValueMakeNumber(ctx, g_variant_get_int16(dbus));

        case G_VARIANT_CLASS_UINT16:
            return JSValueMakeNumber(ctx, g_variant_get_uint16(dbus));

        case G_VARIANT_CLASS_INT32:
            return JSValueMakeNumber(ctx, g_variant_get_int32(dbus));

        case G_VARIANT_CLASS_UINT32:
            return JSValueMakeNumber(ctx, g_variant_get_uint32(dbus));

        case G_VARIANT_CLASS_INT64:
            return JSValueMakeNumber(ctx, g_variant_get_int64(dbus));

        case G_VARIANT_CLASS_UINT64:
            return JSValueMakeNumber(ctx, g_variant_get_uint64(dbus));

        case G_VARIANT_CLASS_BOOLEAN:
            return JSValueMakeBoolean(ctx, g_variant_get_boolean(dbus));

        case G_VARIANT_CLASS_HANDLE:
            g_warning("[%s] does not support FD type\n", __func__);
            return JSValueMakeNumber(ctx, g_variant_get_uint32(dbus));

        case G_VARIANT_CLASS_VARIANT: {
                GVariant* v = g_variant_get_variant(dbus);
                jsvalue = dbus_to_js(ctx, v);
                g_variant_unref(v);
                return jsvalue;
            }

        case G_VARIANT_CLASS_DICT_ENTRY:
            /*g_assert_not_reached();*/
            break;

        case G_VARIANT_CLASS_ARRAY: {
                if (g_variant_type_is_dict_entry(
                        g_variant_type_element(g_variant_get_type(dbus)))) {
                    jsvalue = JSObjectMake(ctx, NULL, NULL);
                    for (size_t i=0; i<g_variant_n_children(dbus); i++) {
                        GVariant *dic = g_variant_get_child_value(dbus, i);
                        GVariant *key= g_variant_get_child_value (dic, 0);
                        GVariant *value = g_variant_get_child_value (dic, 1);

                        JSValueRef js_key = dbus_to_js(ctx, key);
                        JSValueRef js_value = dbus_to_js(ctx, value);

                        JSStringRef key_str = JSValueToStringCopy(ctx, js_key,
                                                                  NULL);
                        JSObjectSetProperty(ctx, (JSObjectRef)jsvalue,
                                            key_str, js_value, 0, NULL);
                        JSStringRelease(key_str);

                        g_variant_unref(key);
                        g_variant_unref(value);
                        g_variant_unref(dic);
                    }
                    return jsvalue;
                } else {
                    int n = g_variant_n_children(dbus);
                    JSValueRef *args = g_new(JSValueRef, n);
                    for (int i=0; i < n; i++) {
                        GVariant* v = g_variant_get_child_value(dbus, i);
                        args[i] = dbus_to_js(ctx, v);
                        g_variant_unref(v);
                    }
                    jsvalue = JSObjectMakeArray(ctx, n, args, NULL);
                    g_free(args);
                    return jsvalue;
                }
            }

        case G_VARIANT_CLASS_TUPLE: {
                int n = g_variant_n_children(dbus);
                jsvalue = JSObjectMakeArray(ctx, 0, NULL, NULL);
                for (int i=0; i < n; i++) {
                    GVariant* v = g_variant_get_child_value(dbus, i);
                    JSObjectSetPropertyAtIndex(ctx, (JSObjectRef)jsvalue,
                                               i, dbus_to_js(ctx, v), NULL);
                    g_variant_unref(v);
                }
                return jsvalue;
            }

        case G_VARIANT_CLASS_MAYBE:
            g_assert_not_reached();
    }
    g_warning("[%s] does not  support signature type:%c\n", __func__, type);
    return JSValueMakeUndefined(ctx);
}