|
Server : Apache/2.2.2 (Fedora) System : Linux App1.pathumtani.go.th 2.6.20-1.2320.fc5smp #1 SMP Tue Jun 12 19:40:16 EDT 2007 i686 User : apache ( 48) PHP Version : 5.2.9 Disable Function : NONE Directory : /usr/share/printconf/util/ |
Upload File : |
#!/usr/bin/python
## system-config-printer
## Add Queue druid implementation
## Copyright (C) 2001-2006 Red Hat, Inc.
## Copyright (C) 2002-2005 Tim Waugh <twaugh@redhat.com>
## 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 2 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., 675 Mass Ave, Cambridge, MA 02139, USA.
import gettext
import gnome
import gtk
import gtk.glade
import gobject
import os
import re
import signal
import string
import time
import pysmb
domain = 'printconf'
from rhpl.translate import _, N_
gtk.glade.bindtextdomain (domain, '/usr/share/locale')
busy_cursor = gtk.gdk.Cursor(gtk.gdk.WATCH)
ready_cursor = gtk.gdk.Cursor(gtk.gdk.LEFT_PTR)
def complain (window, msg):
"""Put up an error dialog."""
d = gtk.MessageDialog (window, 0, gtk.MESSAGE_ERROR, gtk.BUTTONS_OK, msg)
d.set_transient_for (window)
d.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
d.run ()
d.destroy ()
class addQueue:
"""The GNOME druid implementation for adding a new queue."""
def __init__ (self, parent, xml):
self.parent = parent
self.xml = xml
# Widgets.
self.window = xml.get_widget ('addQueueWindow')
self.druid = xml.get_widget ('add_queue_druid')
self.type_menu = xml.get_widget ('add_queue_type_menu')
self.notebook = xml.get_widget ('add_queue_type_notebook')
self.name_entry = xml.get_widget ('add_queue_name_entry')
self.desc_entry = xml.get_widget ('add_queue_description_entry')
self.device_view = xml.get_widget ('add_queue_device_view')
self.custom_dialog = xml.get_widget ('customDeviceDialog')
self.custom_device_entry = xml.get_widget ('device_entry')
self.ipp_server_entry = xml.get_widget ('add_queue_ipp_server_entry')
self.ipp_path_entry = xml.get_widget ('add_queue_ipp_path_entry')
self.lpd_server_entry = xml.get_widget ('add_queue_lpd_server_entry')
self.lpd_queue_entry = xml.get_widget ('add_queue_lpd_queue_entry')
self.smb_view = xml.get_widget ('add_queue_smb_view')
self.passwd_dialog = xml.get_widget ('passwdDialog')
self.smb_workgroup_entry = xml.get_widget ('smb_workgroup_entry')
self.smb_server_entry = xml.get_widget ('smb_server_entry')
self.smb_share_entry = xml.get_widget ('smb_share_entry')
self.smb_user_entry = xml.get_widget ('smb_user_entry')
self.smb_passwd_entry = xml.get_widget ('smb_passwd_entry')
self.ncp_server_entry = xml.get_widget ('add_queue_ncp_server_entry')
self.ncp_user_entry = xml.get_widget ('add_queue_ncp_user_entry')
self.ncp_queue_entry = xml.get_widget ('add_queue_ncp_queue_entry')
self.ncp_passwd_entry = xml.get_widget ('add_queue_ncp_passwd_entry')
self.jd_printer_entry = xml.get_widget ('add_queue_jd_printer_entry')
self.jd_port_entry = xml.get_widget ('add_queue_jd_port_entry')
self.select_model_label = xml.get_widget ('add_queue_model_label')
self.mfr_menu = xml.get_widget ('add_queue_mfr_menu')
self.printer_view = xml.get_widget ('add_queue_printer_view')
self.notes_button = xml.get_widget ('add_queue_notes_button')
# Storage for the device list.
self.device_store = gtk.TreeStore (str, str)
self.device_store.set_sort_column_id (0, gtk.SORT_ASCENDING)
self.device_view.set_model (self.device_store)
self.device_view.set_search_column (0)
# Device list columns.
col = gtk.TreeViewColumn (_("Device"), gtk.CellRendererText (),
text=0)
col.set_resizable (True)
col.set_sort_column_id (0)
self.device_view.append_column (col)
col = gtk.TreeViewColumn (_("Description"), gtk.CellRendererText (),
text=1)
col.set_resizable (True)
col.set_sort_column_id (1)
self.device_view.append_column (col)
# Storage for the SMB list.
self.smb_store = gtk.TreeStore (str, # host or share
str, # comment
gobject.TYPE_PYOBJECT, # domain dict
gobject.TYPE_PYOBJECT, # host dict
str, # username
str) # password)
self.smb_view.set_model (self.smb_store)
self.device_store.set_sort_column_id (0, gtk.SORT_ASCENDING)
# SMB list columns.
col = gtk.TreeViewColumn (_("Share"), gtk.CellRendererText (),
text=0)
col.set_resizable (True)
col.set_sort_column_id (0)
self.smb_view.append_column (col)
col = gtk.TreeViewColumn (_("Comment"), gtk.CellRendererText (),
text=1)
self.smb_view.append_column (col)
# Storage for the printer list.
self.printer_store = gtk.TreeStore (str, gobject.TYPE_PYOBJECT)
self.printer_view.set_model (self.printer_store)
# Printer list columns.
col = gtk.TreeViewColumn (_("Model"), gtk.CellRendererText (),
text=0)
col.set_resizable (True)
col.set_sort_column_id (0)
self.printer_view.append_column (col)
# Printer select function.
slct = self.printer_view.get_selection ()
slct.set_select_function (self.printer_select_function)
# Signals.
self.window.connect ('destroy', self.destroy)
xml.signal_connect ('on_add_queue_start_page_prepare',
self.prepare_start_page)
xml.signal_connect ('on_add_queue_druid_cancel', self.destroy)
xml.signal_connect ('on_add_queue_druid_help', self.help)
xml.signal_connect ('on_add_queue_rescan_button_clicked',
self.rescan_button_clicked)
xml.signal_connect ('on_add_queue_custom_button_clicked',
self.custom_button_clicked)
xml.signal_connect ('on_add_queue_type_menu_changed',
self.type_menu_changed)
xml.signal_connect ('on_add_queue_notes_button_clicked',
self.notes_button_clicked)
xml.signal_connect ('on_add_queue_name_page_prepare',
self.prepare_name_page)
xml.signal_connect ('on_add_queue_name_page_next',
self.validate_name_page)
xml.signal_connect ('on_add_queue_type_page_prepare',
self.prepare_type_page)
xml.signal_connect ('on_add_queue_smb_view_row_activated',
self.smb_view_row_activated)
xml.signal_connect ('on_add_queue_smb_view_row_expanded',
self.smb_view_row_expanded)
xml.signal_connect ('on_add_queue_smb_specify_clicked',
self.smb_specify_clicked)
xml.signal_connect ('on_add_queue_type_page_next',
self.validate_type_page)
xml.signal_connect ('on_add_queue_model_page_prepare',
self.prepare_model_page)
xml.signal_connect ('on_add_queue_mfr_menu_changed',
self.mfr_menu_changed)
xml.signal_connect ('on_add_queue_model_page_next',
self.validate_model_page)
xml.signal_connect ('on_add_queue_finish_page_prepare',
self.prepare_finish_page)
xml.signal_connect ('on_add_queue_finish_page_finish', self.finish)
# Re-label the finish screen (bug 71725).
self.druid.finish.set_label (_("Finish"))
# -------------------------------
# Handle the window being deleted
# -------------------------------
def destroy (self, druid):
"""Callback for the window being deleted."""
self.window.hide ()
if self.parent.hidden:
gtk.main_quit ()
# ---------------------------
# Greying-out the main window
# ---------------------------
def busy (self):
"""Set the druid window insensitive."""
self.window.set_sensitive (False)
self.window.window.set_cursor (busy_cursor)
while gtk.events_pending():
gtk.main_iteration()
def ready (self):
"""Set the druid window sensitive."""
self.window.window.set_cursor (ready_cursor)
self.window.set_sensitive (True)
#-----------------------------
# Make up a name to start with
#-----------------------------
def make_up_name (self):
"""Make up a name to start with."""
base = "printer"
ext = ""
(name_dict_dict, alias_dict_dict) = self.parent.conf.get_queues ()
while (name_dict_dict.has_key (base + ext) or
alias_dict_dict.has_key (base + ext)):
if ext == "":
ext = "1"
else:
ext = str (int (ext) + 1)
return base + ext
#----------------
# Start the druid
#----------------
def addQueueDruid (self, url = None):
"""Run the druid."""
# Set the druid page to the start.
self.druid.set_page (self.xml.get_widget ('add_queue_start_page'))
# Context help tracking.
self.help_page = "printconf-local-printer.html"
# Set up the name page.
self.name_entry.set_text (self.make_up_name ())
self.desc_entry.set_text ('')
# Set up the type page.
self.type_menu.set_history (0)
self.type_menu_changed (self.type_menu)
# Local printer device tab
self.populate_device_view ()
# IPP tab
self.ipp_server_entry.set_text ('')
self.ipp_path_entry.set_text ('/printers/queue1')
self.ipp_server_entry.grab_focus ()
# LPD tab
self.lpd_server_entry.set_text ('')
self.lpd_queue_entry.set_text ('')
self.lpd_server_entry.grab_focus ()
# SMB tab
# If samba isn't installed, but the user wants to proceed anyway,
# smb_forced is set.
self.smb_forced = False
# NCP tab
self.ncp_server_entry.set_text ('')
self.ncp_user_entry.set_text ('')
self.ncp_queue_entry.set_text ('')
self.ncp_passwd_entry.set_text ('')
self.ncp_server_entry.grab_focus ()
# JetDirect tab
self.jd_printer_entry.set_text ('')
self.jd_port_entry.set_text ('9100')
self.jd_printer_entry.grab_focus ()
# Set up the printer model page.
self.mfr_list = self.parent.populate_mfr_optionmenu (self.mfr_menu)
self.id_to_iter = {}
self.parent.populate_model_store (self.printer_store,
id_dict = self.id_to_iter,
window = self.window.window)
store = self.printer_store
path = store.get_path (store.get_iter_first ())
col = self.printer_view.get_column (0)
self.printer_view.scroll_to_cell (path, col, True, 0.5, 0)
self.notes_button.set_sensitive (False)
# If we have a URL for the printer, pre-populate some of the forms.
if url:
if url.startswith ("smb:"):
# Try to make sense of the URL. It looks like this:
#
# smb://[[username:]password@][workgroup/]server/printer
type1 = "^smb://([^:]+:)?([^@]+@)?([^/]+)/([^/]+)$"
type2 = "^smb://([^:]+:)?([^@]+@)?([^/]+)/([^/]+)/([^/]+)$"
type1_re = re.compile (type1)
type2_re = re.compile (type2)
match = type1_re.match (url)
if match:
(user, password, server, share) = match.groups ()
workgroup = None
else:
match = type2_re.match (url)
if match:
(user, password, workgroup,
server, share) = match.groups ()
if not match:
# Couldn't understand the URL
return
if user:
user = user.rstrip (":")
if password:
password = password.rstrip ("@")
smb_type = self.parent.queue_types.\
index (self.parent.conf.queue_types.smb)
self.type_menu.set_history (smb_type)
t = self.type_menu.get_history ()
if t != smb_type:
# smbclient not installed
return
# Look for the right one already browsed
store = self.smb_store
found = 0
for row in store:
server_iter = store.get_iter (row.path)
if (store.get_value (server_iter, 0).lower () ==
server.lower ()):
dict = store.get_value (server_iter, 3)
if (not workgroup or
not dict['GROUP'] or
dict['GROUP'].lower () == workgroup.lower ()):
found = 1
break
if found:
while store.iter_has_child (server_iter):
i = store.iter_nth_child (server_iter, 0)
store.remove (i)
dict = store.get_value (server_iter, 3)
if not dict['GROUP']:
dict['GROUP'] = workgroup
store.set_value (server_iter, 3, dict)
else:
dict = pysmb.get_host_info (server)
if workgroup:
dict['GROUP'] = workgroup
server_iter = store.append (None)
store.set_value (server_iter, 0, server)
store.set_value (server_iter, 3, dict)
iter = store.append (server_iter)
store.set_value (iter, 0, share)
store.set_value (iter, 1, _("(Specified)"))
store.set_value (iter, 4, user)
store.set_value (iter, 5, password)
view = self.smb_view
self.expanding_row = 1
view.expand_row (store.get_path (server_iter), True)
del self.expanding_row
view.get_selection ().select_iter (iter)
col = view.get_column (0)
view.scroll_to_cell (store.get_path (iter), col,
True, 0.5, 0)
# Run the druid.
self.window.set_transient_for (self.parent.toplevel)
self.window.set_position (gtk.WIN_POS_NONE)
self.parent.ready ()
self.window.show_all ()
#----------
# Show help
#----------
def help (self, druid):
"""Help button handler. Shows help page self.help_page."""
gnome.url_show ("file://%s/%s" %
(self.parent.conf.conf.printconf_help_dir,
self.help_page))
#-----------
# Start page
#-----------
def prepare_start_page (self, page, druid):
"""Prepare the start page. Set the help context."""
self.help_page = "printconf-local-printer.html"
#----------
# Name page
#----------
def prepare_name_page (self, page, druid):
"""Prepare the name page. Set the help context."""
self.help_page = "printconf-local-printer.html"
self.name_entry.grab_focus ()
def validate_name_page (self, page, druid):
"""
Validate the name page.
Return value: whether there is a problem with the page.
"""
name = self.name_entry.get_text ()
# Is the name valid at all?
if not self.parent.conf.valid_queue_name (name):
complain (self.window, _("Invalid name"))
self.name_entry.grab_focus ()
return True
# Is there already a queue (or alias) of that name?
(name_dict_dict, alias_dict_dict) = self.parent.conf.get_queues ()
if name_dict_dict.has_key (name):
complain (self.window,
_("There is already a queue with that name."))
self.name_entry.grab_focus ()
return True
if alias_dict_dict.has_key (name):
complain (self.window,
_("An existing queue has an alias of that name."))
self.name_entry.grab_focus ()
return True
return False
#----------
# Type page
#----------
def prepare_type_page (self, page, druid):
"""Prepare the type page. Set the help context."""
self.help_page = "printconf-local-printer.html"
def rescan_button_clicked (self, button):
"""Handler for the rescan button."""
self.populate_device_view (force = 1)
def custom_button_clicked (self, button):
"""Handle the custom device button."""
dialog = self.custom_dialog
self.custom_device_entry.set_text ('')
dialog.set_transient_for (self.window)
dialog.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
response = dialog.run ()
device = self.custom_device_entry.get_text ()
dialog.hide ()
if response != gtk.RESPONSE_OK or not device:
return
if not os.access (device, os.W_OK):
complain (self.window,
_("'%s' does not exist, or is not writable.") % device)
return
iter = self.device_store.append (None)
self.device_store.set_value (iter, 0, device)
self.device_store.set_value (iter, 1, _("Custom device"))
self.device_view.get_selection ().select_iter (iter)
path = self.device_store.get_path (iter)
col = self.device_view.get_column (0)
self.device_view.scroll_to_cell (path, col, True, 0.5, 0)
def populate_device_view (self, force = None):
"""Find local printer devices and populate self.device_store."""
self.local_devs = self.parent.conf.scan_local_printer_devices (force)
store = self.device_store
autoiter = []
store.clear ()
for dev in self.local_devs.keys ():
iter = store.append (None)
store.set_value (iter, 0, dev)
try:
auto = self.local_devs[dev]["auto"]
description = auto.get("desc")
if not description:
description = "%s %s" % (auto["manufacturer"],
auto["model"])
except:
description = ""
store.set_value (iter, 1, description)
if description:
autoiter.append (iter)
if len (autoiter) == 1:
# We can only see one printer; that might be the one the
# user wants. Select it.
iter = autoiter[0]
self.device_view.get_selection ().select_iter (iter)
path = store.get_path (iter)
col = self.device_view.get_column (0)
self.device_view.scroll_to_cell (path, col, True, 0.5, 0)
def type_menu_changed (self, optionmenu):
"""
Handler for the type optionmenu. Set the notepad page appropriately,
as well as the help context.
"""
which = self.type_menu.get_history ()
self.help_page = self.parent.queue_type_help_pages[which]
self.notebook.set_current_page (which)
if which == self.parent.smb_page_index:
type_space = self.parent.queue_types[which]
if not type_space.check ():
ask = gtk.MessageDialog (self.window, 0, gtk.MESSAGE_WARNING,
gtk.BUTTONS_YES_NO,
type_space.message)
ask.set_transient_for (self.window)
ask.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
response = ask.run ()
ask.destroy ()
if response == gtk.RESPONSE_YES:
self.smb_forced = True
else:
self.type_menu.set_history (0)
self.browse_smb_hosts ()
def validate_type_page (self, page, druid):
"""
Validate the type page.
Return value: whether there is a problem with the page.
"""
type_space = self.parent.queue_types[self.type_menu.get_history ()]
if (not (type_space == self.parent.conf.queue_types.smb
and self.smb_forced)
and not type_space.check ()):
ask = gtk.MessageDialog (self.window, 0, gtk.MESSAGE_WARNING,
gtk.BUTTONS_YES_NO, type_space.message)
ask.set_transient_for (self.window)
ask.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
response = ask.run ()
ask.destroy ()
if response != gtk.RESPONSE_YES:
self.type_menu.grab_focus ()
return True
types = self.parent.conf.queue_types
if type_space == types.local:
if self.validate_local_type ():
return True
elif type_space == types.ipp:
if self.validate_ipp_type ():
return True
elif type_space == types.lpd:
if self.validate_lpd_type ():
return True
elif type_space == types.smb:
if self.validate_smb_type ():
return True
elif type_space == types.ncp:
if self.validate_ncp_type ():
return True
elif type_space == types.jetdirect:
if self.validate_jetdirect_type ():
return True
if type_space == types.jetdirect:
# This is a JetDirect printer. Let's look for an SNMP
# system.sysDescr.0 string in case we can automatically
# detect which driver to use.
self.busy ()
id = self.detect_snmp_printer (self.jd_printer_entry.get_text ())
self.ready ()
if id == None:
return False
elif type_space == types.local:
# This is a local printer. If it has an IEEE 1284 Device ID,
# see if we can find the right printer driver.
selection = self.device_view.get_selection ()
store, iter = selection.get_selected ()
dev = store.get_value (iter, 0)
try:
auto = self.local_devs[dev]["auto"]
mfr = string.lower (auto["manufacturer"])
mdl = string.lower (auto["model"])
id = self.parent.conf.foomatic_match_printer (mfr, mdl).id
if not id:
ps_capable = 0
cmdset = string.lower (auto["cmdset"])
for each in cmdset.split (","):
if each.strip () == "postscript":
ps_capable = 1
break
if ps_capable:
make_model = self.parent.conf.foomatic.\
make_model_dict_dict
id = make_model["Generic"]["PostScript Printer"].id
print "Printer is PostScript-capable:" \
"selecting generic PS"
except:
return False
else: # all other types
return False
# We have foomatic information for a local or JetDirect printer.
# We know the manufacturer and model names,
# so choose the right manufacturer, select the
# right model, and scroll the treeview to it.
mfr = self.parent.conf.foomatic.id_dict[id].make
self.mfr_menu.set_history (self.mfr_list.index (mfr))
self.id_to_iter = {}
iter = self.parent.populate_model_store (self.printer_store,
id_dict = self.id_to_iter,
mfr = mfr,
id = id,
window = self.window.window)
self.printer_view.get_selection ().select_iter (iter)
path = self.printer_store.get_path (iter)
col = self.printer_view.get_column (0)
self.printer_view.scroll_to_cell (path, col, True, 0.5, 0)
# Shouldn't be needed.
while gtk.events_pending ():
gtk.main_iteration ()
return False
def validate_local_type (self):
"""
Validate the local type data.
Return value: whether there is a problem.
"""
selection = self.device_view.get_selection ()
store, iter = selection.get_selected ()
if not iter:
complain (self.window, _("You must select a device."))
return True
return False
def validate_ipp_type (self):
"""Validate the IPP type data.
Return value: whether there is a problem.
"""
ipp_server = self.ipp_server_entry.get_text ()
ipp_path = self.ipp_path_entry.get_text ()
if not ipp_server:
complain (self.window, _("You must specify a server."))
self.ipp_server_entry.grab_focus ()
return True
if not ipp_path:
complain (self.window, _("You must specify a path."))
self.ipp_path_entry.grab_focus ()
return True
return False
def validate_lpd_type (self):
"""Validate the LPD type data.
Return value: whether there is a problem.
"""
lpd_server = self.lpd_server_entry.get_text ()
lpd_queue = self.lpd_queue_entry.get_text ()
if not lpd_server:
complain (self.window, _("You must specify a server."))
self.lpd_server_entry.grab_focus ()
return True
if not lpd_queue:
complain (self.window, _("You must specify a queue."))
self.lpd_queue_entry.grab_focus ()
return True
return False
def validate_smb_type (self):
"""
Validate the SMB data.
Return value: whether there is a problem.
"""
store, iter = self.smb_view.get_selection ().get_selected ()
if not iter:
complain (self.window,
_("You must choose an SMB share to print to."))
return True
parent_iter = store.iter_parent (iter)
if not parent_iter:
complain (self.window,
_("You must choose a share, not a host."))
return True
smb_share = "//%s/%s" % (store.get_value (parent_iter, 0),
store.get_value (iter, 0))
if not smb_share:
complain (self.window,
_("You must specify an SMB share to print to."))
self.smb_share_entry.grab_focus ()
return True
try:
group = store.get_value (parent_iter, 2)['GROUP']
except:
group = ''
user = store.get_value (iter, 4)
passwd = store.get_value (iter, 5)
orig_group = group
server = store.get_value (parent_iter, 0)
orig_share = store.get_value (iter, 0)
self.smb_workgroup_entry.set_text (group)
self.smb_server_entry.set_text (server)
self.smb_server_entry.set_editable (False)
self.smb_share_entry.set_text (orig_share)
self.smb_user_entry.set_text ('')
self.smb_passwd_entry.set_text ('')
if user:
self.smb_user_entry.set_text (user)
if passwd:
self.smb_passwd_entry.set_text (passwd)
self.passwd_dialog.set_transient_for (self.window)
self.passwd_dialog.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
while 1:
if self.smb_forced:
accessible = True
break
# Check we can actually connect, and if not collect the
# username and password to use.
self.window.window.set_cursor (busy_cursor)
while gtk.events_pending ():
gtk.main_iteration ()
accessible = pysmb.printer_share_accessible (smb_share,
group = group,
user = user,
passwd = passwd)
self.window.window.set_cursor (ready_cursor)
if accessible:
break
if not user:
self.smb_user_entry.grab_focus ()
else:
self.smb_passwd_entry.grab_focus ()
response = self.passwd_dialog.run ()
self.passwd_dialog.hide ()
if (response == gtk.RESPONSE_CANCEL or
response == gtk.RESPONSE_DELETE_EVENT):
break
group = self.smb_workgroup_entry.get_text ()
if group != orig_group:
dict = store.get_value (parent_iter, 3)
dict['GROUP'] = group
store.set_value (parent_iter, 3, dict)
sharename = self.smb_share_entry.get_text ()
if sharename.startswith ("//"):
# If sharename is like //machine/share, reduce it to
# just the share name (bug #127348).
q = sharename[2:].find ("/")
if q != -1:
sharename = sharename[3 + q:]
store.set_value (iter, 0, sharename)
smb_share = "//%s/%s" % (server, sharename)
user = self.smb_user_entry.get_text ()
passwd = self.smb_passwd_entry.get_text ()
store.set_value (iter, 4, user)
store.set_value (iter, 5, passwd)
# Validate them!
return not accessible
def validate_ncp_type (self):
"""
Validate NCP data.
Return value: whether there is a problem.
"""
ncp_server = self.ncp_server_entry.get_text ()
ncp_queue = self.ncp_queue_entry.get_text ()
if not ncp_server:
complain (self.window,
_("You must specify an NCP server to print to."))
self.ncp_server_entry.grab_focus ()
return True
if not ncp_queue:
complain (self.window,
_("You must specify a queue on the NCP server."))
self.ncp_queue_entry.grab_focus ()
return True
return False
def validate_jetdirect_type (self):
"""
Validate JetDirect data.
Return value: Whether there is a problem.
"""
jetdirect_ip = self.jd_printer_entry.get_text ()
port = self.jd_port_entry.get_text ()
if not jetdirect_ip:
complain (self.window,
_("You must specify a JetDirect printer to print to."))
self.jd_printer_entry.grab_focus ()
return True
try:
jetdirect_port = int (port)
except:
complain (self.window, _("You must specify an IP port number."))
self.jd_port_entry.grab_focus ()
return True
return False
#-------------
# SMB browsing
#-------------
def browse_smb_hosts (self):
"""Initialise the SMB tree store."""
store = self.smb_store
store.clear ()
try:
self.window.window.set_cursor (busy_cursor)
except:
pass
while gtk.events_pending ():
gtk.main_iteration ()
domains = pysmb.get_domain_list()
iter = None
for domain in domains.keys():
d = domains[domain]
iter = store.append (None)
store.set_value (iter, 0, d['DOMAIN'])
store.set_value (iter, 2, d)
if iter:
dummy = store.append (iter)
try:
self.window.window.set_cursor (ready_cursor)
except:
pass
def smb_view_row_activated (self, view, path, column):
"""Handle double-clicks in the SMB tree view."""
store = self.smb_store
iter = store.get_iter (path)
if store.iter_depth (iter) == 2:
# This is a share, not a host.
return
if view.row_expanded (path):
view.collapse_row (path)
else:
self.smb_view_row_expanded (view, iter, path)
return
def smb_view_row_expanded (self, view, iter, path):
"""Handler for expanding a row in the SMB tree view."""
store = self.smb_store
try:
l_path = list(path)
except:
l_path = None
if len(l_path) == 2:
try:
if self.expanding_row:
return
except:
self.expanding_row = 1
host = store.get_value(iter, 3)
if host:
self.window.window.set_cursor (busy_cursor)
printers = pysmb.get_printer_list (host)
while store.iter_has_child (iter):
i = store.iter_nth_child (iter, 0)
store.remove (i)
for printer in printers.keys ():
i = store.append (iter)
store.set_value (i, 0, printer)
store.set_value (i, 1, printers[printer])
store.set_value (i, 4, '')
store.set_value (i, 5, '')
self.window.window.set_cursor (ready_cursor)
view.expand_row (path, 1)
del self.expanding_row
else:
# click on domain, look for hosts
try:
if self.expanding_row:
return
except:
self.expanding_row = 1
domain = store.get_value(iter, 2)
if domain:
self.window.window.set_cursor (busy_cursor)
while gtk.events_pending ():
gtk.main_iteration ()
hosts = []
hosts = pysmb.get_host_list(domain['IP'])
while store.iter_has_child (iter):
i = store.iter_nth_child (iter, 0)
store.remove (i)
for host in hosts.keys():
h = hosts[host]
i = store.append (iter)
store.set_value (i, 0, h['NAME'])
store.set_value (i, 3, h)
self.window.window.set_cursor (ready_cursor)
view.expand_row (path, 0)
del self.expanding_row
def smb_specify_clicked (self, button):
"""Allow the user to specify the share."""
share_re = re.compile ("^//([^/]+)/(.*)$")
self.smb_workgroup_entry.set_text ('')
self.smb_server_entry.set_text ('MACHINE')
self.smb_server_entry.set_editable (True)
self.smb_share_entry.set_text ('share')
self.smb_user_entry.set_text ('')
self.smb_passwd_entry.set_text ('')
self.smb_share_entry.grab_focus ()
self.passwd_dialog.set_transient_for (self.window)
self.passwd_dialog.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
while 1:
response = self.passwd_dialog.run ()
self.passwd_dialog.hide ()
if (response == gtk.RESPONSE_CANCEL or
response == gtk.RESPONSE_DELETE_EVENT):
break
group = self.smb_workgroup_entry.get_text ()
server = self.smb_server_entry.get_text ()
share = self.smb_share_entry.get_text ()
user = self.smb_user_entry.get_text ()
passwd = self.smb_passwd_entry.get_text ()
share = share.replace ("\\", "/")
match = share_re.match (share)
if not match:
share = '//' + server + '/' + share
self.window.window.set_cursor (busy_cursor)
while gtk.events_pending ():
gtk.main_iteration ()
accessible = pysmb.printer_share_accessible (share,
group = group,
user = user,
passwd = passwd)
self.window.window.set_cursor (ready_cursor)
if accessible or self.smb_forced:
# Add it to the tree view.
match = share_re.match (share)
machine, sharename = match.groups ()
store = self.smb_store
found = 0
for row in store:
parent_iter = store.get_iter (row.path)
if store.get_value (parent_iter, 0) == machine:
found = 1
break
if found:
while store.iter_has_child (parent_iter):
i = store.iter_nth_child (parent_iter, 0)
store.remove (i)
else:
dict = pysmb.get_host_info (machine)
if accessible and not dict['GROUP']:
dict['GROUP'] = accessible['GROUP']
parent_iter = store.append (None)
store.set_value (parent_iter, 0, machine)
store.set_value (parent_iter, 3, dict)
iter = store.append (parent_iter)
store.set_value (iter, 0, sharename)
store.set_value (iter, 1, _("(Specified)"))
store.set_value (iter, 4, user)
store.set_value (iter, 5, passwd)
view = self.smb_view
self.expanding_row = 1
view.expand_row (store.get_path (parent_iter), True)
del self.expanding_row
view.get_selection ().select_iter (iter)
col = view.get_column (0)
view.scroll_to_cell (store.get_path (iter), col,
True, 0.5, 0)
break
return True
#-----------
# Model page
#-----------
def prepare_model_page (self, page, druid):
"""Prepare the model page. Set the help context."""
self.help_page = "printconf-select-model.html"
label = _("Select the printer manufacturer and model.")
type_space = self.parent.queue_types[self.type_menu.get_history ()]
types = self.parent.conf.queue_types
if type_space == types.lpd:
label = _("Select the printer manufacturer and model. "
"Depending on how the remote queue is configured, "
"you may need to select the generic PostScript "
"option here.")
self.select_model_label.set_text (label)
def mfr_menu_changed (self, menu):
"""Update the model list."""
try:
mfr = self.mfr_list[menu.get_history ()]
except:
return
self.id_to_iter = {}
self.parent.populate_model_store (self.printer_store,
id_dict = self.id_to_iter,
mfr = mfr,
window = self.window.window)
col = self.printer_view.get_column (0)
self.printer_view.scroll_to_cell ((0,), col, True, 0.5, 0)
def printer_select_function (self, path):
"""Don't allow this path to be selected unless it is a leaf."""
iter = self.printer_store.get_iter (path)
d, id = self.printer_store.get_value (iter, 1)
if id:
notes_available = True
else:
notes_available = False
self.notes_button.set_sensitive (notes_available)
return not self.printer_store.iter_has_child (iter)
def notes_button_clicked (self, button):
"""Handler for the notes button."""
selection = self.printer_view.get_selection ()
(store, iter) = selection.get_selected ()
if not iter:
return
(type, printer_id) = store.get_value (iter, 1)
if printer_id:
try:
driver = self.parent.conf.foomatic.id_dict[printer_id].driver
except:
driver = (self.parent.conf.foomatic.id_dict[printer_id].
drivers[0])
self.parent.show_notes (printer_id, driver, self)
def validate_model_page (self, page, druid):
"""
Validate model page.
Return value: whether there is a problem.
"""
selection = self.printer_view.get_selection ()
store, iter = selection.get_selected ()
if not iter:
complain (self.window, _("You must select a printer model."))
return True
driver, id = store.get_value (iter, 1)
if driver != self.parent.conf.drivers.foomatic:
return False
id_dict = self.parent.conf.foomatic.id_dict
try:
foomatic_driver = id_dict[id].driver
# Cope with inconsistencies.
if not foomatic_driver in id_dict[id].drivers:
foomatic_driver = id_dict[id].drivers[0]
except:
foomatic_driver = id_dict[id].drivers[0]
blacklist = self.parent.conf.driver_blacklist
try:
black = blacklist.dict[foomatic_driver]
except:
return False
if not black.check ():
ask = gtk.MessageDialog (self.window, 0, gtk.MESSAGE_WARNING,
gtk.BUTTONS_YES_NO, black.message)
ask.set_transient_for (self.window)
ask.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
response = ask.run ()
ask.destroy ()
if response != gtk.RESPONSE_YES:
return True
return False
#------------
# Finish page
#------------
def prepare_finish_page (self, pageedge, druid):
"""Prepare finish page text, and set context help."""
self.help_page = "printconf-select-model.html#S2-PRINTING-CONFIRM"
text = _("About to create the following queue:\n\n")
text += _("Type: ")
type_index = self.type_menu.get_history ()
self.queue_type_space = self.parent.queue_types[type_index]
text += self.queue_type_space.long_pretty_name + "\n"
text += self.pull ()
pageedge.set_text (text)
def pull (self):
"""Pull in the (validated) data from all of the pages."""
types = self.parent.conf.queue_types
rerender = 0
locale = "C"
if os.environ.has_key ("LANG"):
lang = os.environ["LANG"]
if (lang[0:2] == "zh" or lang[0:2] == "ko" or
lang[0:2] == "ja" or lang[0:2] == "ru"):
rerender = 1
if lang[0:2] == "ja":
locale = "ja_JP"
if lang[0:2] == "ko":
locale = "ko_KR"
if lang[0:5] == "zh_CN":
locale = "zh_CN"
if lang[0:5] == "zh_TW":
locale = "zh_TW"
data = {}
flags = { "convert_text_to_Postscript" : 1,
"assume_data_is_text" : rerender,
"rerender_Postscript" : rerender}
data["mf_flags"] = flags
if locale != "C":
data["filter_locale"] = locale
data["queue_name"] = self.name_entry.get_text ()
data["queue_description"] = self.desc_entry.get_text ()
if self.queue_type_space == types.local:
text = self.pull_local (data)
elif self.queue_type_space == types.ipp:
text = self.pull_ipp (data)
elif self.queue_type_space == types.lpd:
text = self.pull_lpd (data)
elif self.queue_type_space == types.smb:
text = self.pull_smb (data)
elif self.queue_type_space == types.ncp:
text = self.pull_ncp (data)
elif self.queue_type_space == types.jetdirect:
text = self.pull_jetdirect (data)
text += "\n" + _("Printer: ")
selection = self.printer_view.get_selection ()
store, iter = selection.get_selected ()
driver, id = store.get_value (iter, 1)
self.driver_tuple = (driver, id)
if id:
f = self.parent.conf.foomatic.id_dict[id]
text += f.make + " " + f.model
else:
text += driver.label
self.queue_data = data
return text
def pull_local (self, data):
"""Pull local data."""
selection = self.device_view.get_selection ()
store, iter = selection.get_selected ()
dev = store.get_value (iter, 0)
data["local_printer_device"] = dev
return _("Device: ") + dev
def pull_ipp (self, data):
"""Pull IPP data."""
data["ipp_server"] = self.ipp_server_entry.get_text ()
data["ipp_port"] = "631"
data["ipp_path"] = self.ipp_path_entry.get_text ()
text = "ipp://%s:%s%s" % (data["ipp_server"],
data["ipp_port"],
data["ipp_path"])
return text
def pull_lpd (self, data):
"""Pull LPD data."""
data["lpd_server"] = self.lpd_server_entry.get_text ()
data["lpd_queue"] = self.lpd_queue_entry.get_text ()
text = _("Queue: ") + data["lpd_queue"] + "@" + data["lpd_server"]
return text
def pull_smb (self, data):
"""Pull SMB data."""
store, iter = self.smb_view.get_selection ().get_selected ()
parent_iter = store.iter_parent (iter)
smb_share = "//%s/%s" % (store.get_value (parent_iter, 0),
store.get_value (iter, 0))
h = store.get_value (parent_iter, 3)
smb_user = store.get_value (iter, 4)
smb_passwd = store.get_value (iter, 5)
data["smb_share"] = smb_share
if h.has_key('IP'):
data["smb_ip"] = h['IP']
else:
data["smb_ip"] = ''
if h.has_key ('GROUP'):
data["smb_workgroup"] = h['GROUP']
else:
data["smb_workgroup"] = ''
data["smb_user"] = smb_user
data["smb_password"] = smb_passwd
return _("Share: ") + data["smb_share"]
def pull_ncp (self, data):
"""Pull NCP data."""
data["ncp_server"] = self.ncp_server_entry.get_text ()
data["ncp_queue"] = self.ncp_queue_entry.get_text ()
data["ncp_user"] = self.ncp_user_entry.get_text ()
data["ncp_password"] = self.ncp_passwd_entry.get_text ()
return _("Queue: ") + data["ncp_queue"] + "@" + data["ncp_server"]
def pull_jetdirect (self, data):
"""Pull JetDirect data."""
data["jetdirect_ip"] = self.jd_printer_entry.get_text ()
data["jetdirect_port"] = self.jd_port_entry.get_text ()
return _("Port: ") + data["jetdirect_ip"] + \
":" + data["jetdirect_port"]
#----------------------
# Finish button pressed
#----------------------
def finish (self, pageedge, druid):
"""Handler for the finish button. Add the queue."""
driver, id = self.driver_tuple
foomatic_tuple = None
if driver == self.parent.conf.drivers.foomatic:
id_dict = self.parent.conf.foomatic.id_dict
printer = id_dict[id]
try:
foomatic_driver = printer.driver
except:
foomatic_driver = printer.drivers[0]
foomatic_tuple = (printer, foomatic_driver)
driver_tuple = (driver, foomatic_tuple)
self.parent.conf.construct_queue (self.queue_type_space,
self.queue_data, driver_tuple)
queue_store = self.parent.queue_store
iter = queue_store.append (None)
name = self.queue_data["queue_name"]
queue_store.set_value (iter, 1, name)
queue_store.set_value (iter, 2, self.queue_data["queue_description"])
self.parent.name_dict, self.parent.alias_dict = \
self.parent.conf.get_queues ()
queue_store.set_value (iter, 3, self.parent.name_dict[name])
self.parent.queue_view.get_selection ().select_iter (iter)
self.parent.default_queue_name = self.parent.conf.\
get_default_queue_name ()
self.parent.fix_default_marker ()
self.parent.queue_chosen (self.parent.queue_view)
self.parent.need_to_apply_changes (True)
self.window.hide ()
if os.access ("/usr/share/cups/data/testprint.ps", os.R_OK):
if self.parent.hidden:
# For --add-with-url we apply the changes anyway.
self.parent.apply ()
msg = _("Would you like to print a test page?")
else:
msg = _("Would you like to print a test page?\n"
"Answering 'yes' will apply all changes\n"
"and print a test page to this printer.")
d = gtk.MessageDialog (self.parent.toplevel, 0,
gtk.MESSAGE_QUESTION, gtk.BUTTONS_YES_NO,
msg)
d.set_transient_for (self.parent.toplevel)
d.set_position (gtk.WIN_POS_CENTER_ON_PARENT)
response = d.run ()
d.destroy ()
if response == gtk.RESPONSE_YES:
if not self.parent.hidden:
self.parent.apply ()
# Give the print spooler a moment to sort itself out.
# FIXME: This should be done in the initscript instead.
time.sleep (10)
if driver == self.parent.conf.drivers.text:
self.parent.test (self.parent.ascii_test)
else:
self.parent.test (self.parent.cups_test)
#-----------------------
# SNMP printer detection
#-----------------------
def detect_snmp_printer (self, agent):
"""Detect an SNMP printer by name."""
def snmpwalk (agent, oid):
opts = '-v 1 -c public -Ov'
c = '/usr/bin/snmpwalk %s "$AGENT" "$OID" 2>/dev/null' % opts
os.environ['AGENT'] = agent
os.environ['OID'] = oid
signal.signal (signal.SIGCHLD, signal.SIG_DFL)
f = os.popen (c)
return f.readlines ()
id = None
ps_capable = 0
ls = snmpwalk (agent, 'system.sysObjectID.0')
oid = None
lookfor = "OID: "
for l in ls:
if l.startswith (lookfor):
oid = l[len (lookfor):].rstrip ('\n')
break
if oid:
ls = snmpwalk (agent, oid)
# Look for an IEEE 1284 ID
lookfor = "STRING: "
for l in ls:
if not l.startswith (lookfor):
continue
# IEEE 1284 ID fields are separated by semi-colons
if not l.find (";") != -1:
continue
l = l[len (lookfor):].rstrip ('\n').strip ('"')
deviceid = self.parent.conf.parse_ieee1284_deviceid (l)
mfr = None
mdl = None
try:
mfr = deviceid["manufacturer"].lower().strip (' ')
mdl = deviceid["model"].lower ().strip (' ')
tuple = (mfr, mdl)
id = self.parent.conf.foomatic.autodetect_dict[tuple].id
break
except KeyError:
print "No IEEE 1284 match:", deviceid
print "Please report this message in Bugzilla:"
print " https://bugzilla.redhat.com/bugzilla"
print "Choose 'foomatic' as the component."
if mfr and mdl:
p = self.parent.conf.foomatic_match_printer (mfr, mdl)
if p:
id = p.id
print "Guessing at %s for match" % id
try:
cmdset = deviceid["cmdset"]
for each in cmdset.split (","):
if each.lower ().strip () == "postscript":
ps_capable = 1
break
except:
pass
if not id:
ls = snmpwalk (agent, 'HOST-RESOURCES-MIB::hrDeviceDescr')
lookfor = "STRING: "
for l in ls:
if not l.startswith (lookfor):
continue
descr = l[len (lookfor):].rstrip ('\n')
try:
id = self.parent.conf.foomatic.snmp_dict[descr].id
break
except:
print "No SNMP match: '%s'" % descr
print "Please report this message in Bugzilla:"
print " https://bugzilla.redhat.com/bugzilla"
print "Choose 'foomatic' as the component."
if not id and ps_capable:
try:
make_model = self.parent.conf.foomatic.make_model_dict_dict
id = make_model["Generic"]["PostScript Printer"].id
print "Printer is PostScript-capable: selecting generic PS"
except:
pass
return id
# Local Variables:
# py-indent-offset: 4
# End: