static void
modem_get_sim_ready (MMModem *modem,
                     GAsyncResult *res,
                     BroadbandDeviceInfo *info)
{
	GHashTable *attrs;

	info->mm_sim = mm_modem_get_sim_finish (modem, res, NULL);
	if (!info->mm_sim)
		/* Ok, the modem may not need it actually */
		return;

	/* Do nothing if we're not locked */
	if (mm_modem_get_state (info->mm_modem) != MM_MODEM_STATE_LOCKED)
		return;

	/* If we have a device ID ask the keyring for any saved SIM-PIN codes */
	if (mm_modem_get_device_identifier (info->mm_modem) &&
	    mm_modem_get_unlock_required (info->mm_modem) == MM_MODEM_LOCK_SIM_PIN) {
		attrs = secret_attributes_build (&mobile_secret_schema, "devid",
		                                 mm_modem_get_device_identifier (info->mm_modem),
		                                 NULL);
		secret_service_search (NULL, &mobile_secret_schema, attrs,
		                       SECRET_SEARCH_UNLOCK | SECRET_SEARCH_LOAD_SECRETS,
		                       info->cancellable, keyring_pin_check_cb, info);
		g_hash_table_unref (attrs);
	} else {
		/* Couldn't get a device ID, but unlock required; present dialog */
		unlock_dialog_new (info->device, info);
	}

	/* Couldn't get a device ID, but unlock required; present dialog */
	unlock_dialog_new (info->device, info);
}
static void
modem_get_sim_ready (MMModem *modem,
                     GAsyncResult *res,
                     BroadbandDeviceInfo *info)
{
	info->mm_sim = mm_modem_get_sim_finish (modem, res, NULL);
	if (!info->mm_sim)
		/* Ok, the modem may not need it actually */
		return;

	/* Do nothing if we're not locked */
	if (mm_modem_get_state (info->mm_modem) != MM_MODEM_STATE_LOCKED)
		return;

	/* If we have a device ID ask the keyring for any saved SIM-PIN codes */
	if (mm_modem_get_device_identifier (info->mm_modem) &&
	    mm_modem_get_unlock_required (info->mm_modem) == MM_MODEM_LOCK_SIM_PIN) {
		g_warn_if_fail (info->keyring_id == NULL);
		info->keyring_id = gnome_keyring_find_itemsv (GNOME_KEYRING_ITEM_GENERIC_SECRET,
		                                              keyring_pin_check_cb,
		                                              info,
		                                              NULL,
		                                              "devid",
		                                              GNOME_KEYRING_ATTRIBUTE_TYPE_STRING,
		                                              mm_modem_get_device_identifier (info->mm_modem),
		                                              NULL);
		return;
	}

	/* Couldn't get a device ID, but unlock required; present dialog */
	unlock_dialog_new (info->device, info);
}
static void
dialog_sim_send_pin_ready (MMSim *sim,
                           GAsyncResult *res,
                           BroadbandDeviceInfo *info)
{
	GError *error = NULL;

	if (!mm_sim_send_pin_finish (sim, res, &error)) {
		if (g_error_matches (error,
		                     MM_MOBILE_EQUIPMENT_ERROR,
		                     MM_MOBILE_EQUIPMENT_ERROR_SIM_PUK)) {
			/* Destroy previous dialog and launch a new one rebuilt to ask for PUK */
			unlock_dialog_destroy (info);
			unlock_dialog_new (info->device, info);
		} else {
			const gchar *msg = NULL;

			/* Report error and re-try PIN request */
			if (g_error_matches (error,
			                     MM_MOBILE_EQUIPMENT_ERROR,
			                     MM_MOBILE_EQUIPMENT_ERROR_INCORRECT_PASSWORD))
				msg = _("Wrong PIN code; please contact your provider.");
			else {
				g_dbus_error_strip_remote_error (error);
				msg = error ? error->message : NULL;
			}

			applet_mobile_pin_dialog_stop_spinner (info->dialog, msg);
		}

		g_warning ("Failed to send PIN to devid: '%s' simid: '%s' : %s",
		           mm_modem_get_device_identifier (info->mm_modem),
		           mm_sim_get_identifier (info->mm_sim),
		           error->message);

		g_error_free (error);
		return;
	}

	/* Good */

	if (applet_mobile_pin_dialog_get_auto_unlock (info->dialog)) {
		const gchar *code1;

		code1 = applet_mobile_pin_dialog_get_entry1 (info->dialog);
		mobile_helper_save_pin_in_keyring (mm_modem_get_device_identifier (info->mm_modem),
		                                   mm_sim_get_identifier (info->mm_sim),
		                                   code1);
	} else
		mobile_helper_delete_pin_in_keyring (mm_modem_get_device_identifier (info->mm_modem));

	unlock_dialog_destroy (info);
}
static void
autounlock_sim_send_pin_ready (MMSim *sim,
                               GAsyncResult *res,
                               BroadbandDeviceInfo *info)
{
	GError *error = NULL;

	if (!mm_sim_send_pin_finish (sim, res, &error)) {
		g_warning ("Failed to auto-unlock devid: '%s' simid: '%s' : %s",
		           mm_modem_get_device_identifier (info->mm_modem),
		           mm_sim_get_identifier (info->mm_sim),
		           error->message);
		g_error_free (error);

		/* Remove PIN from keyring right away */
		mobile_helper_delete_pin_in_keyring (mm_modem_get_device_identifier (info->mm_modem));

		/* Ask the user */
		unlock_dialog_new (info->device, info);
	}
}
static void
keyring_pin_check_cb (GnomeKeyringResult result,
                      GList *list,
                      gpointer user_data)
{
	BroadbandDeviceInfo *info = user_data;
	GList *iter;
	const char *pin = NULL;
	const char *simid;

	info->keyring_id = NULL;

	if (result != GNOME_KEYRING_RESULT_OK) {
		/* No saved PIN, just ask the user */
		unlock_dialog_new (info->device, info);
		return;
	}

	/* Look for a result with a matching "simid" attribute since that's
	 * better than just using a matching "devid".  The PIN is really tied
	 * to the SIM, not the modem itself.
	 */
	simid = mm_sim_get_identifier (info->mm_sim);
	if (simid) {
		for (iter = list;
		     (pin == NULL) && iter;
		     iter = g_list_next (iter)) {
			GnomeKeyringFound *found = iter->data;
			int i;

			/* Look for a matching "simid" attribute */
			for (i = 0; (pin == NULL) && i < found->attributes->len; i++) {
				GnomeKeyringAttribute attr = gnome_keyring_attribute_list_index (found->attributes, i);

				if (g_strcmp0 (attr.name, "simid") == 0 &&
				    attr.type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING &&
				    g_strcmp0 (attr.value.string, simid) == 0) {
					pin = found->secret;
					break;
				}
			}
		}
	}

	if (pin == NULL) {
		/* Fall back to the first result's PIN */
		pin = ((GnomeKeyringFound *) list->data)->secret;
		if (pin == NULL) {
			/* Should never get here */
			g_warn_if_fail (pin != NULL);
			unlock_dialog_new (info->device, info);
			return;
		}
	}

	mm_sim_send_pin (info->mm_sim,
	                 pin,
	                 NULL, /* cancellable */
	                 (GAsyncReadyCallback)autounlock_sim_send_pin_ready,
	                 info);
}
static void
keyring_pin_check_cb (GObject *source,
                      GAsyncResult *result,
                      gpointer user_data)
{
	BroadbandDeviceInfo *info = user_data;
	GList *iter;
	GList *list;
	SecretItem *item;
	SecretValue *pin = NULL;
	GHashTable *attributes;
	GError *error = NULL;
	const char *simid;

	list = secret_service_search_finish (NULL, result, &error);

	if (error != NULL) {
		/* No saved PIN, just ask the user */
		unlock_dialog_new (info->device, info);
		g_error_free (error);
		return;
	}

	/* Look for a result with a matching "simid" attribute since that's
	 * better than just using a matching "devid".  The PIN is really tied
	 * to the SIM, not the modem itself.
	 */
	simid = mm_sim_get_identifier (info->mm_sim);
	if (simid) {
		for (iter = list;
		     (pin == NULL) && iter;
		     iter = g_list_next (iter)) {
			item = iter->data;

			/* Look for a matching "simid" attribute */
			attributes = secret_item_get_attributes (item);
			if (g_strcmp0 (simid, g_hash_table_lookup (attributes, "simid")))
				pin = secret_item_get_secret (item);
			else
				pin = NULL;
			g_hash_table_unref (attributes);

			if (pin != NULL)
				break;
		}
	}

	if (pin == NULL) {
		/* Fall back to the first result's PIN if we have one */
		if (list)
			pin = secret_item_get_secret (list->data);
		if (pin == NULL) {
			unlock_dialog_new (info->device, info);
			return;
		}
	}

	/* Send the PIN code to ModemManager */
	mm_sim_send_pin (info->mm_sim,
	                 secret_value_get (pin, NULL),
	                 NULL, /* cancellable */
	                 (GAsyncReadyCallback)autounlock_sim_send_pin_ready,
	                 info);
	secret_value_unref (pin);
}