-
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add D-Bus interface to interact with fwupd * Get device names * Add class for devices * Split into separate views * Add view for firmware devices * Add more information to view * Add function of verify button * Add function to get releases * Add page for releases * Add reference on how to decode device flags * Check if releases are available for device * Get releases * Show list of releases * Show install duration * Catch error * Decode device flags * Show icon and text for device flags * Save releases as property of device * Add update error * Satisfy linter * Show release information * Pretty print file size and time * Add dialog to install release * Format release description * Add todo * Add support to install upgrade or reinstall * Add support to install downgrade * List device only if updatable * Separate operating system and hardware views * Add list of available firmware updates * Download update * Remove unused code * Refactor * Make calls async * Refactor handle * Refactor handle * Refactor handle * Show feedback during update * Remove dummy update all button * Update layout * Refactor * Remove unused code * Update src/Interfaces/FwupdManager.vala Co-authored-by: Daniel Foré <[email protected]> * Update src/Plug.vala Co-authored-by: Daniel Foré <[email protected]> * Update src/Plug.vala Co-authored-by: Daniel Foré <[email protected]> * Update src/Views/FirmwareView.vala Co-authored-by: Daniel Foré <[email protected]> * Refactor reference type * Update src/Widgets/FirmwareUpdateWidget.vala Co-authored-by: Daniel Foré <[email protected]> * Update src/Widgets/FirmwareUpdateWidget.vala Co-authored-by: Daniel Foré <[email protected]> * Show placeholder when no devices are available * Show error dialog * Update src/Views/FirmwareView.vala Co-authored-by: Cassidy James Blaede <[email protected]> * Add GetDetails * Show dialog if manual steps are required * Set transient_for * Use listbox placeholder (#167) * Get rid of page header * Add icon to list placeholder * Show dialog to shutdown or reboot if needed * Refactor * Provide specifc error text * Rename to FirmwareUpdateRow * Be more verbose for shutdown and reboot * Reduce number of iterations * Provide a hopefully more understandable text * Apply suggestions from code review Co-authored-by: Cassidy James Blaede <[email protected]> * Update icons * Show name of device during update * Update button label Co-authored-by: Cassidy James Blaede <[email protected]> * Apply suggestions from code review Co-authored-by: Daniel Foré <[email protected]> * Use device icon if possible * Always provide device on error * Reload when new device is plugged in * Reload when device is removed * Remove unused signal * Use flags properly * Refactor get_devices (#168) * Refactor get_releases * Refactor install * Refactor get_details * Remove unnecessary async * Use Posix.open * Refactor namespace * Refactor warning messages * Make interface private * Refactor to use different variables * Refactor translator comments * Add cancel button for details view * Get rid of singleton * Always download file * Rename to get_release_details * Refactor get path of file * Add TODO * Close filedescriptor * Refactor to use property * Refactor dialog to decide if we want to continue the update Co-authored-by: Daniel Foré <[email protected]> Co-authored-by: Cassidy James Blaede <[email protected]> Co-authored-by: David Hewitt <[email protected]>
- Loading branch information
1 parent
5ace95e
commit 932d4f1
Showing
11 changed files
with
1,087 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,304 @@ | ||
/* | ||
* Copyright (c) 2020 elementary, Inc. (https://elementary.io) | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public | ||
* License as published by the Free Software Foundation; either | ||
* version 3 of the License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public | ||
* License along with this program; if not, write to the | ||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
* Boston, MA 02110-1301 USA | ||
* | ||
* Authored by: Marius Meisenzahl <[email protected]> | ||
*/ | ||
|
||
public class About.FwupdManager : Object { | ||
[DBus (name = "org.freedesktop.fwupd")] | ||
private interface FwupdInterface : Object { | ||
public abstract signal void device_added (GLib.HashTable<string, Variant> device); | ||
public abstract signal void device_removed (GLib.HashTable<string, Variant> device); | ||
|
||
public abstract async GLib.HashTable<string, Variant>[] get_devices () throws GLib.Error; | ||
public abstract async GLib.HashTable<string, Variant>[] get_releases (string device_id) throws GLib.Error; | ||
public abstract async void install (string id, UnixInputStream handle, GLib.HashTable<string, Variant> options) throws GLib.Error; | ||
public abstract async GLib.HashTable<string, Variant>[] get_details (UnixInputStream handle) throws GLib.Error; | ||
} | ||
|
||
private FwupdInterface fwupd; | ||
|
||
public signal void on_device_added (Fwupd.Device device); | ||
public signal void on_device_error (Fwupd.Device device, string error); | ||
public signal void on_device_removed (Fwupd.Device device); | ||
|
||
public async List<Fwupd.Device> get_devices () { | ||
var devices_list = new List<Fwupd.Device> (); | ||
|
||
try { | ||
var result = yield fwupd.get_devices (); | ||
foreach (unowned GLib.HashTable<string, Variant> device in result) { | ||
devices_list.append (yield parse_device (device)); | ||
} | ||
} catch (Error e) { | ||
warning ("Could not get devices: %s", e.message); | ||
} | ||
|
||
return devices_list; | ||
} | ||
|
||
private async List<Fwupd.Release> get_releases (string id) { | ||
var releases_list = new List<Fwupd.Release> (); | ||
|
||
try { | ||
var result = yield fwupd.get_releases (id); | ||
foreach (unowned GLib.HashTable<string, Variant> release in result) { | ||
releases_list.append (parse_release (release)); | ||
} | ||
} catch (Error e) { | ||
warning ("Could not get releases for “%s”: %s", id, e.message); | ||
} | ||
|
||
return releases_list; | ||
} | ||
|
||
private async Fwupd.Device parse_device (GLib.HashTable<string, Variant> serialized_device) { | ||
var device = new Fwupd.Device (); | ||
|
||
serialized_device.@foreach ((key, val) => { | ||
switch (key) { | ||
case "DeviceId": | ||
device.id = val.get_string (); | ||
break; | ||
case "Flags": | ||
device.flags = (Fwupd.DeviceFlag) val.get_uint64 (); | ||
break; | ||
case "Name": | ||
device.name = val.get_string (); | ||
break; | ||
case "Summary": | ||
device.summary = val.get_string (); | ||
break; | ||
case "Vendor": | ||
device.vendor = val.get_string (); | ||
break; | ||
case "VendorId": | ||
if (device.vendor == null) { | ||
device.vendor = val.get_string (); | ||
} | ||
break; | ||
case "Version": | ||
device.version = val.get_string (); | ||
break; | ||
case "Icon": | ||
var icons = val.get_strv (); | ||
device.icon = icons.length > 0 ? icons[0] : "application-x-firmware"; | ||
break; | ||
case "Guid": | ||
device.guids = val.get_strv (); | ||
break; | ||
case "InstallDuration": | ||
device.install_duration = val.get_uint32 (); | ||
break; | ||
case "UpdateError": | ||
device.update_error = val.get_string (); | ||
break; | ||
default: | ||
break; | ||
} | ||
}); | ||
|
||
if (device.id.length > 0 && device.has_flag (Fwupd.DeviceFlag.UPDATABLE)) { | ||
device.releases = yield get_releases (device.id); | ||
} else { | ||
device.releases = new List<Fwupd.Release> (); | ||
} | ||
|
||
return device; | ||
} | ||
|
||
private Fwupd.Release parse_release (GLib.HashTable<string, Variant> serialized_release) { | ||
var release = new Fwupd.Release () { | ||
icon = "security-high" | ||
}; | ||
|
||
serialized_release.@foreach ((key, val) => { | ||
switch (key) { | ||
case "Filename": | ||
release.filename = val.get_string (); | ||
break; | ||
case "Name": | ||
release.name = val.get_string (); | ||
break; | ||
case "Summary": | ||
release.summary = val.get_string (); | ||
break; | ||
case "Version": | ||
release.version = val.get_string (); | ||
break; | ||
case "Description": | ||
release.description = val.get_string () | ||
.replace ("<p>", "") | ||
.replace ("</p>", "\n\n") | ||
.replace ("<li>", " • ") | ||
.replace ("</li>", "\n") | ||
.replace ("<ul>", "") | ||
.replace ("</ul>", "\n") | ||
.replace ("<ol>", "") // TODO: add support for ordered lists | ||
.replace ("</ol>", "\n") | ||
.strip (); | ||
break; | ||
case "Protocol": | ||
release.protocol = val.get_string (); | ||
break; | ||
case "RemoteId": | ||
release.remote_id = val.get_string (); | ||
break; | ||
case "AppstreamId": | ||
release.appstream_id = val.get_string (); | ||
break; | ||
case "Checksum": | ||
release.checksum = val.get_string (); | ||
break; | ||
case "Vendor": | ||
release.vendor = val.get_string (); | ||
break; | ||
case "Size": | ||
release.size = val.get_uint64 (); | ||
break; | ||
case "License": | ||
release.license = val.get_string (); | ||
break; | ||
case "TrustFlags": | ||
release.flag = (Fwupd.ReleaseFlag) val.get_uint64 (); | ||
break; | ||
case "InstallDuration": | ||
release.install_duration = val.get_uint32 (); | ||
break; | ||
case "Uri": | ||
release.uri = val.get_string (); | ||
break; | ||
default: | ||
break; | ||
} | ||
}); | ||
|
||
return release; | ||
} | ||
|
||
public async string? download_file (Fwupd.Device device, string uri) { | ||
File server_file = File.new_for_uri (uri); | ||
var path = Path.build_filename (Environment.get_tmp_dir (), server_file.get_basename ()); | ||
File local_file = File.new_for_path (path); | ||
|
||
bool result; | ||
try { | ||
result = yield server_file.copy_async (local_file, FileCopyFlags.OVERWRITE, Priority.DEFAULT, null, (current_num_bytes, total_num_bytes) => { | ||
// TODO: provide useful information for user | ||
}); | ||
} catch (Error e) { | ||
on_device_error (device, "Could not download file: %s".printf (e.message)); | ||
return null; | ||
} | ||
|
||
if (!result) { | ||
on_device_error (device, "Download of %s was not succesfull".printf (uri)); | ||
return null; | ||
} | ||
|
||
return path; | ||
} | ||
|
||
public async bool install (Fwupd.Device device, string path) { | ||
int fd; | ||
|
||
try { | ||
// https://github.com/fwupd/fwupd/blob/c0d4c09a02a40167e9de57f82c0033bb92e24167/libfwupd/fwupd-client.c#L2045 | ||
var options = new GLib.HashTable<string, Variant> (str_hash, str_equal); | ||
options.insert ("reason", new Variant.string ("user-action")); | ||
options.insert ("filename", new Variant.string (path)); | ||
options.insert ("allow-older", new Variant.boolean (true)); | ||
options.insert ("allow-reinstall", new Variant.boolean (true)); | ||
options.insert ("no-history", new Variant.boolean (true)); | ||
|
||
fd = Posix.open (path, Posix.O_RDONLY); | ||
var handle = new UnixInputStream (fd, true); | ||
|
||
yield fwupd.install (device.id, handle, options); | ||
} catch (Error e) { | ||
warning ("Could not install release for “%s”: %s", device.id, e.message); | ||
on_device_error (device, device.update_error != null ? device.update_error : e.message); | ||
return false; | ||
} finally { | ||
Posix.close (fd); | ||
} | ||
|
||
return true; | ||
} | ||
|
||
public async Fwupd.Details get_release_details (Fwupd.Device device, string path) { | ||
var details = new Fwupd.Details (); | ||
|
||
int fd; | ||
try { | ||
fd = Posix.open (path, Posix.O_RDONLY); | ||
var handle = new UnixInputStream (fd, true); | ||
|
||
var result = yield fwupd.get_details (handle); | ||
foreach (unowned GLib.HashTable<string, Variant> serialized_details in result) { | ||
serialized_details.@foreach ((key, val) => { | ||
if (key == "Release") { | ||
var iter = val.iterator ().next_value ().iterator (); | ||
string details_key; | ||
Variant details_val; | ||
while (iter.next ("{sv}", out details_key, out details_val)) { | ||
if (details_key == "DetachCaption") { | ||
details.caption = details_val.get_string (); | ||
} else if (details_key == "DetachImage") { | ||
details.image = details_val.get_string (); | ||
} | ||
} | ||
} | ||
}); | ||
} | ||
} catch (Error e) { | ||
warning ("Could not get details for “%s”: %s", device.id, e.message); | ||
on_device_error (device, device.update_error); | ||
} finally { | ||
Posix.close (fd); | ||
} | ||
|
||
if (details.image != null) { | ||
details.image = yield download_file (device, details.image); | ||
} | ||
|
||
return details; | ||
} | ||
|
||
construct { | ||
try { | ||
fwupd = Bus.get_proxy_sync (BusType.SYSTEM, "org.freedesktop.fwupd", "/"); | ||
|
||
fwupd.device_added.connect ((serialized_device) => { | ||
parse_device.begin (serialized_device, (obj, res) => { | ||
var device = parse_device.end (res); | ||
on_device_added (device); | ||
}); | ||
}); | ||
|
||
fwupd.device_removed.connect ((serialized_device) => { | ||
parse_device.begin (serialized_device, (obj, res) => { | ||
var device = parse_device.end (res); | ||
on_device_removed (device); | ||
}); | ||
}); | ||
} catch (Error e) { | ||
warning ("Could not connect to system bus: %s", e.message); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
/* | ||
* Copyright (c) 2021 elementary, Inc. (https://elementary.io) | ||
* | ||
* This program is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU General Public | ||
* License as published by the Free Software Foundation; either | ||
* version 3 of the License, or (at your option) any later version. | ||
* | ||
* This program is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* General Public License for more details. | ||
* | ||
* You should have received a copy of the GNU General Public | ||
* License along with this program; if not, write to the | ||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
* Boston, MA 02110-1301 USA | ||
* | ||
* Authored by: Marius Meisenzahl <[email protected]> | ||
*/ | ||
|
||
[DBus (name = "org.freedesktop.login1.Manager")] | ||
public interface About.LoginInterface : Object { | ||
public abstract void reboot (bool interactive) throws GLib.Error; | ||
public abstract void power_off (bool interactive) throws GLib.Error; | ||
} | ||
|
||
public class About.LoginManager : Object { | ||
private LoginInterface interface; | ||
|
||
static LoginManager? instance = null; | ||
public static LoginManager get_instance () { | ||
if (instance == null) { | ||
instance = new LoginManager (); | ||
} | ||
|
||
return instance; | ||
} | ||
|
||
private LoginManager () {} | ||
|
||
construct { | ||
try { | ||
interface = Bus.get_proxy_sync (BusType.SYSTEM, "org.freedesktop.login1", "/org/freedesktop/login1"); | ||
} catch (Error e) { | ||
warning ("Could not connect to login interface: %s", e.message); | ||
} | ||
} | ||
|
||
public bool shutdown () { | ||
try { | ||
interface.power_off (true); | ||
} catch (Error e) { | ||
warning ("Could not connect to login interface: %s", e.message); | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
|
||
public bool reboot () { | ||
try { | ||
interface.reboot (true); | ||
} catch (Error e) { | ||
warning ("Could not connect to login interface: %s", e.message); | ||
return false; | ||
} | ||
|
||
return true; | ||
} | ||
} |
Oops, something went wrong.