@@ -239,6 +239,7 @@ def __init__(self):
239239 self .recommended_model_selected = False
240240 self ._searchdialog = None
241241 self ._installdialog = None
242+ self .web_interface_device = None
242243
243244 self .getWidgets ({"NewPrinterWindow" :
244245 ["NewPrinterWindow" ,
@@ -464,7 +465,7 @@ def protect_toggle (toggle_widget):
464465 self .expNPDeviceURIs .connect ("notify::expanded" ,
465466 self .on_expNPDeviceURIs_expanded )
466467 self .expNPDeviceURIs .set_expanded (1 )
467- self .btnNPOpenWebInterface .set_sensitive (False )
468+ # self.btnNPOpenWebInterface.set_sensitive (False)
468469
469470 # SMB browser
470471 self .smb_store = Gtk .TreeStore (GObject .TYPE_PYOBJECT )
@@ -2249,33 +2250,33 @@ def fillDeviceTab(self, current_uri=None):
22492250 network_iter = model .append (None , row = [_ ("Network Printer" ),
22502251 None ,
22512252 False ])
2253+ network_dict = { 'device-class' : 'network' ,
2254+ 'device-info' : _ ("Find Network Printer" ) }
2255+ network = cupshelpers .Device ('network' , ** network_dict )
2256+ find_nw_iter = model .append (network_iter ,
2257+ row = [self ._manual_network_device_label (network ),
2258+ PhysicalDevice (network ), False ])
22522259 model .append (network_iter , row = ['' , None , True ])
22532260 ipp_group_iter = model .append (network_iter ,
22542261 row = [_ ("IPP Destinations" ),
22552262 None ,
22562263 False ])
22572264 model .append (network_iter , row = ['' , None , True ])
2258- queue_group_iter = model .append (network_iter ,
2259- row = [_ ("Queues & Others" ),
2260- None ,
2261- False ])
2262- network_dict = { 'device-class' : 'network' ,
2263- 'device-info' : _ ("Find Network Printer" ) }
2264- network = cupshelpers .Device ('network' , ** network_dict )
2265- find_nw_iter = model .append (queue_group_iter ,
2266- row = [self ._manual_network_device_label (network ),
2267- PhysicalDevice (network ), False ])
2265+ legacy_group_iter = model .append (network_iter ,
2266+ row = [_ ("Legacy Protocols" ),
2267+ None ,
2268+ False ])
22682269 smbdev_dict = { 'device-class' : 'network' ,
22692270 'device-info' : _ ("Windows Printer via SAMBA" ) }
22702271 smbdev = cupshelpers .Device ('smb' , ** smbdev_dict )
2271- model .append (queue_group_iter ,
2272+ model .append (legacy_group_iter ,
22722273 row = [self ._manual_network_device_label (smbdev ),
22732274 PhysicalDevice (smbdev ), False ])
22742275 self .devices_uri_iter = uri_iter
22752276 self .devices_find_nw_iter = find_nw_iter
22762277 self .devices_network_iter = network_iter
22772278 self .devices_network_ipp_group_iter = ipp_group_iter
2278- self .devices_network_queue_group_iter = queue_group_iter
2279+ self .devices_network_legacy_group_iter = legacy_group_iter
22792280 self .devices_network_fetched = False
22802281 self .tvNPDevices .set_model (model )
22812282 self .entNPTDevice .set_text ('' )
@@ -2978,8 +2979,10 @@ def device_uri_select_function (self, selection, model, path, *UNUSED):
29782979 return model .get_value (iter , 2 ) == "device"
29792980
29802981 def _classify_connection_device (self , device ):
2981- if device .type == "ipp" :
2982+
2983+ if device .type in ["ipp" , "ipps" , "https" ]:
29822984 parsed = urllib .parse .urlparse (device .uri )
2985+ print (device .type ,"dtttt" ,parsed .path .startswith ("/printers/" ))
29832986 if parsed .path .startswith ("/printers/" ):
29842987 return "queue"
29852988 return "ipp"
@@ -3029,7 +3032,7 @@ def _set_default_connection_selection (self, model):
30293032
30303033 iter = model .iter_next (iter )
30313034
3032- self .btnNPOpenWebInterface .set_sensitive (False )
3035+ # self.btnNPOpenWebInterface.set_sensitive (False)
30333036
30343037 def _get_connection_path_for_uri (self , uri ):
30353038 model = self .tvNPDeviceURIs .get_model ()
@@ -3051,7 +3054,7 @@ def _network_group_for_manual_device (self, device):
30513054 if device .type in ["ipp" , "ipps" , "https" ]:
30523055 return self .devices_network_ipp_group_iter
30533056
3054- return self .devices_network_queue_group_iter
3057+ return self .devices_network_legacy_group_iter
30553058
30563059 def _manual_network_device_label (self , device ):
30573060 labels = {
@@ -3066,6 +3069,144 @@ def _manual_network_device_label (self, device):
30663069 }
30673070 return labels .get (device .type ,
30683071 getattr (device , "info" , None ) or device .uri )
3072+
3073+ def _get_adminurl_from_avahi (self , device ):
3074+ import subprocess
3075+ import re
3076+
3077+ try :
3078+ output = subprocess .check_output (
3079+ ["avahi-browse" , "-rt" , "_ipps._tcp" ],
3080+ text = True
3081+ )
3082+
3083+ matches = re .findall (r'adminurl=([^\s"]+)' , output )
3084+
3085+ if matches :
3086+ return matches [0 ].replace (".local./" , ".local/" )
3087+
3088+ except Exception as e :
3089+ print ("Avahi error:" , e )
3090+
3091+ return None
3092+ def _get_device_web_interface_url (self , device , physicaldevice = None ):
3093+ import urllib .parse
3094+
3095+ attrs = getattr (device , "other_attributes" , {})
3096+
3097+ for key in ["printer-more-info" , "device-more-info" , "adminurl" ]:
3098+ url = attrs .get (key )
3099+ if isinstance (url , list ):
3100+ url = url [0 ] if url else None
3101+ if url :
3102+ return url .replace (".local./" , ".local/" )
3103+
3104+ if physicaldevice :
3105+ txt = getattr (physicaldevice , "txt" , None ) or \
3106+ getattr (physicaldevice , "dnssd_txt" , None )
3107+
3108+ if txt :
3109+ for entry in txt :
3110+ if isinstance (entry , bytes ):
3111+ entry = entry .decode (errors = "ignore" )
3112+
3113+ if isinstance (entry , str ) and entry .startswith ("adminurl=" ):
3114+ url = entry .split ("=" , 1 )[1 ]
3115+ return url .replace (".local./" , ".local/" )
3116+
3117+ parsed = urllib .parse .urlparse (device .uri )
3118+ raw_host = parsed .hostname or ""
3119+
3120+ if "._tcp" in raw_host :
3121+ url = self ._get_adminurl_from_avahi (device )
3122+ print ("ggg" ,url )
3123+ if url :
3124+ return url
3125+
3126+ host = raw_host
3127+
3128+ if not host or "._tcp" in host :
3129+ host = (
3130+ attrs .get ("hostname" ) or
3131+ attrs .get ("host" ) or
3132+ attrs .get ("address" ) or
3133+ attrs .get ("ip-address" )
3134+ )
3135+
3136+ if not host and physicaldevice :
3137+ host = (
3138+ getattr (physicaldevice , "dnssd_hostname" , None ) or
3139+ getattr (physicaldevice , "_network_host" , None ) or
3140+ getattr (physicaldevice , "address" , None )
3141+ )
3142+
3143+ if not host :
3144+ return None
3145+
3146+ host = urllib .parse .unquote (host ).rstrip ("." )
3147+
3148+ scheme = "https" if parsed .scheme in ["ipps" , "https" ] else "http"
3149+
3150+ port = parsed .port
3151+ if port and port not in [80 , 443 ]:
3152+ return f"{ scheme } ://{ host } :{ port } /"
3153+
3154+ return f"{ scheme } ://{ host } /"
3155+
3156+ def _get_preferred_ipp_device (self , physicaldevice ):
3157+ for device in physicaldevice .get_devices ():
3158+ if (self ._classify_connection_device (device ) == "ipp" and
3159+ self ._get_device_web_interface_url (device ,
3160+ physicaldevice = physicaldevice ) is not None ):
3161+ return device
3162+
3163+ return None
3164+
3165+ def _get_selected_physical_device (self ):
3166+ path , column = self .tvNPDevices .get_cursor ()
3167+ if path is None :
3168+ return None
3169+
3170+ model = self .tvNPDevices .get_model ()
3171+ if model is None :
3172+ return None
3173+
3174+ iter = model .get_iter (path )
3175+ if iter is None :
3176+ return None
3177+
3178+ return model .get_value (iter , 1 )
3179+
3180+ def _get_selected_connection_device (self ):
3181+ path , column = self .tvNPDeviceURIs .get_cursor ()
3182+ if path is None :
3183+ return None
3184+
3185+ model = self .tvNPDeviceURIs .get_model ()
3186+ if model is None :
3187+ return None
3188+
3189+ iter = model .get_iter (path )
3190+ if iter is None :
3191+ return None
3192+
3193+ return model .get_value (iter , 1 )
3194+
3195+ def _update_web_interface_button (self , device = None , physicaldevice = None ):
3196+ if device is None :
3197+ device = self ._get_selected_connection_device ()
3198+ if (device is None or
3199+ self ._classify_connection_device (device ) != "ipp" or
3200+ self ._get_device_web_interface_url (device ,
3201+ physicaldevice = physicaldevice ) is None ):
3202+ if physicaldevice is None :
3203+ physicaldevice = self ._get_selected_physical_device ()
3204+ if physicaldevice is not None :
3205+ device = self ._get_preferred_ipp_device (physicaldevice )
3206+ else :
3207+ device = None
3208+ self .web_interface_device = device
3209+ self .btnNPOpenWebInterface .set_sensitive (device is not None )
30693210
30703211 def device_row_separator_fn (self , model , iter , data ):
30713212 return model .get_value (iter , 2 )
@@ -3152,14 +3293,12 @@ def on_tvNPDevices_cursor_changed(self, widget):
31523293 self .device_selected += 1
31533294 path , column = widget .get_cursor ()
31543295 if path is None :
3155- self .btnNPOpenWebInterface .set_sensitive (False )
31563296 return
31573297
31583298 model = widget .get_model ()
31593299 iter = model .get_iter (path )
31603300 physicaldevice = model .get_value (iter , 1 )
31613301 if physicaldevice is None :
3162- self .btnNPOpenWebInterface .set_sensitive (False )
31633302 return
31643303 show_uris = True
31653304 for device in physicaldevice .get_devices ():
@@ -3345,28 +3484,27 @@ def on_tvNPDevices_cursor_changed(self, widget):
33453484 model , self ._connection_group_title (group ),
33463485 grouped_devices [group ])
33473486 self ._set_default_connection_selection (model )
3487+ # Keep main selection in sync with the default connection row.
3488+ self .device = self ._get_selected_connection_device ()
3489+ self ._update_web_interface_button (physicaldevice = physicaldevice )
33483490 if show_uris :
33493491 self .expNPDeviceURIs .show_all ()
33503492 else :
33513493 self .expNPDeviceURIs .hide ()
3352- self .btnNPOpenWebInterface .set_sensitive (False )
33533494
33543495 def on_tvNPDeviceURIs_cursor_changed (self , widget ):
33553496 path , column = widget .get_cursor ()
33563497 if path is None :
3357- self .btnNPOpenWebInterface .set_sensitive (False )
33583498 return
33593499
33603500 model = widget .get_model ()
33613501 iter = model .get_iter (path )
33623502 device = model .get_value (iter , 1 )
33633503 if device is None :
3364- self .btnNPOpenWebInterface .set_sensitive (False )
33653504 return
33663505
33673506 self .device = device
3368- self .btnNPOpenWebInterface .set_sensitive (
3369- self ._classify_connection_device (device ) == "ipp" )
3507+ self ._update_web_interface_button (device = device )
33703508 self .lblNPDeviceDescription .set_text ('' )
33713509 page = self .new_printer_device_tabs .get (device .type , self .PAGE_SELECT_DEVICE )
33723510 self .ntbkNPType .set_current_page (page )
@@ -3523,16 +3661,32 @@ def on_tvNPDeviceURIs_cursor_changed(self, widget):
35233661
35243662 self .setNPButtons ()
35253663
3526- def on_btnNPOpenWebInterface_clicked (self , button ):
3527- try :
3528- Gtk .show_uri_on_window (self .NewPrinterWindow ,
3529- "http://localhost:8000" ,
3530- Gdk .CURRENT_TIME )
3531- except GLib .GError as e :
3532- show_error_dialog (_ ("Unable to Open Web Interface" ),
3533- str (e ),
3534- parent = self .NewPrinterWindow )
3664+ def on_btnNPOpenWebInterface_clicked (self , button ):
3665+ import subprocess
3666+
3667+ url = self ._get_device_web_interface_url (
3668+ self .web_interface_device ,
3669+ physicaldevice = self ._get_selected_physical_device ()
3670+ )
35353671
3672+ print (url )
3673+
3674+ if not url :
3675+ show_error_dialog (
3676+ _ ("Unable to Open Web Interface" ),
3677+ _ ("No web interface URL was provided by the printer." ),
3678+ parent = self .NewPrinterWindow
3679+ )
3680+ return
3681+
3682+ try :
3683+ subprocess .Popen (["xdg-open" , url ])
3684+ except Exception as e :
3685+ show_error_dialog (
3686+ _ ("Unable to Open Web Interface" ),
3687+ str (e ),
3688+ parent = self .NewPrinterWindow
3689+ )
35363690 def on_entNPTLpdHost_changed (self , ent ):
35373691 hostname = ent .get_text ()
35383692 self .btnNPTLpdProbe .set_sensitive (len (hostname ) > 0 )
@@ -3664,6 +3818,8 @@ def found_network_printer_callback (self, new_device):
36643818 ###
36653819
36663820 def getDeviceURI (self ):
3821+ if self .device is None :
3822+ raise AttributeError
36673823 if self .dialog_mode in ['printer_with_uri' , 'ppd' ]:
36683824 return self .device .uri
36693825
0 commit comments