From e6b7d6967212eb63be2e4cebe687ca391c677e17 Mon Sep 17 00:00:00 2001 From: TheJayas Date: Wed, 30 Oct 2024 01:05:33 +0530 Subject: [PATCH] Adding features of IPP Service Discovery --- Makefile.am | 3 ++ ipp_pd_async.py | 82 ++++++++++++++++++++++++++++++++++ system-config-printer.py | 55 ++++++++++++++++++++++- ui/DiscoveredPrintersDialog.ui | 55 +++++++++++++++++++++++ ui/PrinterItem.ui | 57 +++++++++++++++++++++++ ui/PrintersWindow.ui | 15 +++++++ 6 files changed, 265 insertions(+), 2 deletions(-) create mode 100644 ipp_pd_async.py create mode 100644 ui/DiscoveredPrintersDialog.ui create mode 100644 ui/PrinterItem.ui diff --git a/Makefile.am b/Makefile.am index 9993ca0db..b2d56649f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -113,6 +113,7 @@ nobase_pkgdata_DATA= \ gui.py \ gtkinklevel.py \ installpackage.py \ + ipp_pd_async.py \ jobviewer.py \ killtimer.py \ monitor.py \ @@ -135,6 +136,8 @@ nobase_pkgdata_DATA= \ userdefault.py \ ui/AboutDialog.ui \ ui/ConnectDialog.ui \ + ui/DiscoveredPrintersDialog.ui \ + ui/PrinterItem.ui \ ui/ConnectingDialog.ui \ ui/InstallDialog.ui \ ui/JobsWindow.ui \ diff --git a/ipp_pd_async.py b/ipp_pd_async.py new file mode 100644 index 000000000..37d7067ec --- /dev/null +++ b/ipp_pd_async.py @@ -0,0 +1,82 @@ +import dbus +import dbus.mainloop.glib +import gi +from gi.repository import GLib +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk +import avahi + +SERVICE_TYPES = [ + "_http._tcp", "_https._tcp" + # "_ipp._tcp", "_ipps-system._tcp", + # "_nvstream._tcp", "_nvstream_dbd._tcp", "_airplay._tcp", "_raop._tcp" +] + +class AvahiServiceBrowser: + def __init__(self): + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + self.bus = dbus.SystemBus() + self.discovered_services = [] # List to store unique discovered services + + def get_all_discovered_services(self): + return self.discovered_services + + def on_service_found(self, interface, protocol, name, stype, domain, adminurl=None): + # Check for duplicates before adding + if not any(service['name'] == name and service['link'] == adminurl for service in self.discovered_services): + # print(f"Service found: {name}, type: {stype}, domain: {domain}, admin URL: {adminurl}") + service_info = { + "name": name, + "link": adminurl + } + self.discovered_services.append(service_info) + + def resolve_service(self, interface, protocol, name, stype, domain, flags): + server = self.bus.get_object(avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER) + + try: + # Resolve the service to obtain its host and port + resolved = server.ResolveService( + interface, protocol, name, stype, domain, + avahi.PROTO_UNSPEC, dbus.UInt32(0), + dbus_interface=avahi.DBUS_INTERFACE_SERVER + ) + + # Construct the admin URL + host = resolved[5] # The resolved hostname + port = resolved[8] # The resolved port + adminurl = f"http://{host}:{port}" + + # Pass all information to `on_service_found` + self.on_service_found(interface, protocol, name, stype, domain, adminurl) + + except dbus.DBusException as e: + print(f"Failed to resolve service {name}: {e}") + + def get_services(self, service_type): + try: + server = dbus.Interface( + self.bus.get_object(avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER), + avahi.DBUS_INTERFACE_SERVER + ) + sbrowser = dbus.Interface( + self.bus.get_object(avahi.DBUS_NAME, server.ServiceBrowserNew( + avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, service_type, 'local', dbus.UInt32(0))), + avahi.DBUS_INTERFACE_SERVICE_BROWSER + ) + # Connect ItemNew to resolve service when a new item is found + sbrowser.connect_to_signal("ItemNew", self.resolve_service) + print(f"Started service browser for: {service_type}") + + except dbus.DBusException as e: + print(f"DBusException: {e}") + + def run(self): + for service_type in SERVICE_TYPES: + self.get_services(service_type) + loop = GLib.MainLoop() + loop.run() + +if __name__ == "__main__": + browser = AvahiServiceBrowser() + browser.run() diff --git a/system-config-printer.py b/system-config-printer.py index c9689de07..e1c7ea5f1 100755 --- a/system-config-printer.py +++ b/system-config-printer.py @@ -28,6 +28,9 @@ import _thread import dbus import gi +import webbrowser +import asyncio +from ipp_pd_async import AvahiServiceBrowser try: gi.require_version('Polkit', '1.0') from gi.repository import Polkit @@ -216,11 +219,21 @@ def __init__(self): "btnAddFirstPrinter", "btnStartService", "btnConnectNoService", + "btnDiscoverPrinters", "statusbarMain", "toolbar", "server_menubar_item", "printer_menubar_item", "view_discovered_printers"], + "DiscoveredPrintersDialog": + ["DiscoveredPrintersDialog", + "printers-flowbox", + "buttonOk"], + "PrinterItem": [ + "printer-item", + "printer-icon", + "printer-name", + "open-link-button"], "AboutDialog": ["AboutDialog"], "ConnectDialog": @@ -516,6 +529,7 @@ def __init__(self): self.dests_iconview_drag_data_get) self.btnStartService.connect ('clicked', self.on_start_service_clicked) self.btnConnectNoService.connect ('clicked', self.on_connect_activate) + self.btnDiscoverPrinters.connect ('clicked', self.on_discover_printers_button_click) self.btnAddFirstPrinter.connect ('clicked', self.on_new_printer_activate) @@ -543,9 +557,13 @@ def __init__(self): elif len (self.printers) > 1: self.PrintersWindow.set_default_size (500, 180) - self.PrintersWindow.show() + self.builder = Gtk.Builder() + self.service_browser = AvahiServiceBrowser() + self.service_browser.run() + self.discovered_services = self.service_browser.get_all_discovered_services() # To store discovered services + def display_properties_dialog_for (self, queue): model = self.dests_iconview.get_model () iter = model.get_iter_first () @@ -614,6 +632,39 @@ def dests_iconview_item_activated (self, iconview, path): self.monitor.update () return + def on_discover_printers_button_click(self, widget): + self.builder.add_from_file("ui/DiscoveredPrintersDialog.ui") + self.discovered_printers_dialog = self.builder.get_object("DiscoveredPrintersDialog") + self.discovered_services = self.service_browser.get_all_discovered_services() + printers = self.discovered_services + printers_flowbox = self.builder.get_object("printers-flowbox") + for printer in printers: + item_builder = Gtk.Builder() + item_builder.add_from_file("ui/PrinterItem.ui") + + # Configure each printer item + printer_item = item_builder.get_object("printer-item") + printer_name_label = item_builder.get_object("printer-name") + open_link_button = item_builder.get_object("open-link-button") + + printer_name_label.set_text(printer["name"]) + open_link_button.connect("clicked", self.on_open_link_clicked, printer["link"]) + + # Add the item to the flowbox + printers_flowbox.add(printer_item) + printer_item.show_all() + + # Display the dialog + self.discovered_printers_dialog.set_transient_for(self.PrintersWindow) + self.discovered_printers_dialog.show_all() + + def on_open_link_clicked(self, widget, link): + # Open the provided link in the web browser + webbrowser.open(link) + + def on_discovered_printers_dialog_close(self, widget): + self.discovered_printers_dialog.hide() + def on_properties_dialog_closed (self, obj): self.sensitise_main_window_widgets () @@ -2278,4 +2329,4 @@ def main(show_jobs): if opt == "--embedded": PlugWindowId = int(optarg) - main(show_jobs) + main(show_jobs) \ No newline at end of file diff --git a/ui/DiscoveredPrintersDialog.ui b/ui/DiscoveredPrintersDialog.ui new file mode 100644 index 000000000..4e256aad8 --- /dev/null +++ b/ui/DiscoveredPrintersDialog.ui @@ -0,0 +1,55 @@ + + + + + + Discovered Printers + True + center-on-parent + 400 + 300 + + + + + True + vertical + 6 + + + + + True + True + True + + + + True + 1 + none + True + True + + + + + + + + + + + True + end + + + _OK + True + + + + + + + diff --git a/ui/PrinterItem.ui b/ui/PrinterItem.ui new file mode 100644 index 000000000..0276511be --- /dev/null +++ b/ui/PrinterItem.ui @@ -0,0 +1,57 @@ + + + + + + vertical + 6 + True + True + + + + + horizontal + 10 + True + + + + + printer-symbolic + True + 48 + + + + + + + Printer Name + True + True + + + + + + + Website + True + + + + + + + + + + horizontal + True + 5 + 5 + + + + diff --git a/ui/PrintersWindow.ui b/ui/PrintersWindow.ui index 22f337fd3..b5f6f9ca7 100644 --- a/ui/PrintersWindow.ui +++ b/ui/PrintersWindow.ui @@ -280,6 +280,21 @@ 0 + + + _Discover Printers + True + True + True + + + + + True + True + 1 + + Connect