#!/usr/bin/env python3 import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk, Gdk, GObject,GLib import os import xmlrpc.client import ssl import sys import pwd import time import gettext _=gettext.gettext gettext.textdomain('printa') import signal signal.signal(signal.SIGINT, signal.SIG_DFL) RSRC_PATH="/usr/share/printa-printer-config/rsrc/" DEBUG=True def dprint(data): if DEBUG: print("[PPC] %s"%data) class PrintaPrinterConfig: def __init__(self): self.user=os.environ["USER"] context=ssl._create_unverified_context() self.n4d=xmlrpc.client.ServerProxy("https://localhost:9779",allow_none=True,context=context) # LETS TRY TO RELY ON N4D TICKETS self.get_n4d_ticket() self.start_gui() Gtk.main() #def init def get_n4d_key(self): try: f=open("/etc/n4d/key") self.n4d_key=f.readline().strip("\n") f.close() except: dprint("[!] You need root privileges [!]") dialog.run() sys.exit(0) #def get_n4d_key def get_n4d_ticket(self): self.n4d_ticket=None ret=self.n4d.create_ticket(self.user) if ret["status"]==0: f=open("/run/n4d/tickets/%s"%self.user) self.n4d_ticket=f.readline().strip("\n") f.close() #def get_n4d_ticket def start_gui(self): builder=Gtk.Builder() builder.set_translation_domain("printa") builder.add_from_file(RSRC_PATH+"printa-printer-config-gui.ui") self.window=builder.get_object("window1") self.add_button=builder.get_object("add_button") self.apply_button=builder.get_object("apply_button") self.treeview=builder.get_object("treeview") self.add_button.connect("clicked",self.add_printer) self.apply_button.connect("clicked",self.apply_changes_clicked) self.window.connect("delete-event",self.delete_event) self.window.show_all() self.set_values() #def start_gui def set_values(self): self.printers_store=Gtk.ListStore(str,bool) self.treeview.set_model(self.printers_store) column=Gtk.TreeViewColumn(_("Printer")) renderer=Gtk.CellRendererText() column.pack_start(renderer,False) column.add_attribute(renderer,"text",0) column.set_expand(True) self.treeview.append_column(column) column=Gtk.TreeViewColumn(_("Controlled")) renderer=Gtk.CellRendererToggle() column.pack_end(renderer,True) column.add_attribute(renderer,"active",1) self.treeview.append_column(column) renderer.connect("toggled",self.printer_toggled) self.populate_treeview() #def set_values def populate_treeview(self,init=True): self.printers_store.clear() if init: self.states={} ret=self.n4d.get_controlled_printers("","PrintaServer") controlled=[] non_controlled=[] if ret["status"]==0: controlled=ret["return"] ret=self.n4d.get_non_controlled_printers("","PrintaServer") if ret["status"]==0: non_controlled=ret["return"] for printer in controlled: self.printers_store.append([printer,True]) if init: self.states[printer]=True for printer in non_controlled: self.printers_store.append([printer,False]) if init: self.states[printer]=False #def populate_treeview def printer_toggled(self, widget, path): self.printers_store[path][1] = not self.printers_store[path][1] self.check_changes(False) if not self.apply_button.get_sensitive(): self.apply_button.set_sensitive(True) #def printer_toggled def add_printer(self,widget): self.window.set_sensitive(False) GLib.timeout_add(500,self.execute,"system-config-printer") self.window.show() #def add_printer def execute(self,cmd): os.system(cmd) self.populate_treeview(True) self.window.set_sensitive(True) return False def apply_changes_clicked(self,widget): dprint("Apply changes without exiting.") self.apply_changes() #def apply_changes_clicked def apply_changes(self): failed=False for item in self.printers_store: printer,status=item[:] if status != self.states[printer]: dprint("Setting '%s' printer control to %s"%(printer,status)) if status: ret=self.n4d.enable_control((self.user,self.n4d_ticket),"PrintaServer",printer) else: ret=self.n4d.disable_control((self.user,self.n4d_ticket),"PrintaServer",printer) if ret["status"]==0: self.states[printer]=status else: failed=True dialog = Gtk.MessageDialog(parent=None, flags=0, message_type=Gtk.MessageType.ERROR, buttons=Gtk.ButtonsType.CANCEL, text=_("Error executing command:")+" %s"%ret["msg"]) dialog.format_secondary_text(str(ret)) dialog.run() dialog.close() if not failed: self.apply_button.set_sensitive(False) dprint("Done applying changes") #def apply_changes def check_changes(self,show_dialog=True): for data in self.printers_store: printer,status=data[:] if status !=self.states[printer]: dprint("Changes have been made") if show_dialog: dialog = Gtk.MessageDialog(parent=self.window,flags=0, message_type=Gtk.MessageType.WARNING,text=_("Configuration has changed")) dialog.add_buttons(Gtk.STOCK_APPLY, Gtk.ResponseType.OK,Gtk.STOCK_DISCARD,Gtk.ResponseType.CLOSE,Gtk.STOCK_CANCEL,Gtk.ResponseType.CANCEL) dialog.format_secondary_text(_("Do you want to apply changes or discard them?")) # DEPRECATION WARNING. GNOME WANTS ICONLESS DIALOGS ''' # SET BREEZE ICON IF POSSIBLE breeze_icon_path="/usr/share/icons/breeze/status/64/dialog-warning.svg" if os.path.exists(breeze_icon_path): image=Gtk.Image() image.set_from_file(breeze_icon_path) image.show() dialog.set_image(image) ''' ''' # HACK TO SHOW THE CORRECT ICON bbox=dialog.get_children()[0].get_children()[1].get_children()[0] discard_button=bbox.get_children()[1] button_image,button_label=discard_button.get_children()[0].get_children()[0].get_children() button_image.set_from_stock(Gtk.STOCK_DELETE,Gtk.IconSize.BUTTON) # ###### # ''' ret=dialog.run() dialog.hide() if ret == Gtk.ResponseType.OK: dprint("Apply changes and exit") self.apply_changes() return False if ret == Gtk.ResponseType.CLOSE: dprint("Close without saving") return False if ret == Gtk.ResponseType.CANCEL: dprint("Cancel") return True return False #def check_for_changes def delete_event(self,widget,event): if self.check_changes(): return True Gtk.main_quit() #def check_changes #class PrintaGUI if __name__=="__main__": p=PrintaPrinterConfig()