2569 lines
72 KiB
Diff
2569 lines
72 KiB
Diff
|
diff -up system-config-printer-1.1.10/aclocal.m4.525e996 system-config-printer-1.1.10/aclocal.m4
|
||
|
--- system-config-printer-1.1.10/aclocal.m4.525e996 2009-07-22 13:54:02.000000000 +0100
|
||
|
+++ system-config-printer-1.1.10/aclocal.m4 2009-07-26 19:01:45.683356020 +0100
|
||
|
@@ -1867,6 +1867,162 @@ AC_DEFUN([AM_NLS],
|
||
|
AC_SUBST(USE_NLS)
|
||
|
])
|
||
|
|
||
|
+# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
|
||
|
+#
|
||
|
+# Copyright © 2004 Scott James Remnant <scott@netsplit.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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||
|
+#
|
||
|
+# As a special exception to the GNU General Public License, if you
|
||
|
+# distribute this file as part of a program that contains a
|
||
|
+# configuration script generated by Autoconf, you may include it under
|
||
|
+# the same distribution terms that you use for the rest of that program.
|
||
|
+
|
||
|
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
|
||
|
+# ----------------------------------
|
||
|
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
|
||
|
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
|
||
|
+m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
|
||
|
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
|
||
|
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
|
||
|
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
|
||
|
+fi
|
||
|
+if test -n "$PKG_CONFIG"; then
|
||
|
+ _pkg_min_version=m4_default([$1], [0.9.0])
|
||
|
+ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
|
||
|
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
|
||
|
+ AC_MSG_RESULT([yes])
|
||
|
+ else
|
||
|
+ AC_MSG_RESULT([no])
|
||
|
+ PKG_CONFIG=""
|
||
|
+ fi
|
||
|
+
|
||
|
+fi[]dnl
|
||
|
+])# PKG_PROG_PKG_CONFIG
|
||
|
+
|
||
|
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
|
||
|
+#
|
||
|
+# Check to see whether a particular set of modules exists. Similar
|
||
|
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
|
||
|
+#
|
||
|
+#
|
||
|
+# Similar to PKG_CHECK_MODULES, make sure that the first instance of
|
||
|
+# this or PKG_CHECK_MODULES is called, or make sure to call
|
||
|
+# PKG_CHECK_EXISTS manually
|
||
|
+# --------------------------------------------------------------
|
||
|
+AC_DEFUN([PKG_CHECK_EXISTS],
|
||
|
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||
|
+if test -n "$PKG_CONFIG" && \
|
||
|
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
|
||
|
+ m4_ifval([$2], [$2], [:])
|
||
|
+m4_ifvaln([$3], [else
|
||
|
+ $3])dnl
|
||
|
+fi])
|
||
|
+
|
||
|
+
|
||
|
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
|
||
|
+# ---------------------------------------------
|
||
|
+m4_define([_PKG_CONFIG],
|
||
|
+[if test -n "$$1"; then
|
||
|
+ pkg_cv_[]$1="$$1"
|
||
|
+ elif test -n "$PKG_CONFIG"; then
|
||
|
+ PKG_CHECK_EXISTS([$3],
|
||
|
+ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
|
||
|
+ [pkg_failed=yes])
|
||
|
+ else
|
||
|
+ pkg_failed=untried
|
||
|
+fi[]dnl
|
||
|
+])# _PKG_CONFIG
|
||
|
+
|
||
|
+# _PKG_SHORT_ERRORS_SUPPORTED
|
||
|
+# -----------------------------
|
||
|
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
|
||
|
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
|
||
|
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
|
||
|
+ _pkg_short_errors_supported=yes
|
||
|
+else
|
||
|
+ _pkg_short_errors_supported=no
|
||
|
+fi[]dnl
|
||
|
+])# _PKG_SHORT_ERRORS_SUPPORTED
|
||
|
+
|
||
|
+
|
||
|
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
|
||
|
+# [ACTION-IF-NOT-FOUND])
|
||
|
+#
|
||
|
+#
|
||
|
+# Note that if there is a possibility the first call to
|
||
|
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
|
||
|
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
|
||
|
+#
|
||
|
+#
|
||
|
+# --------------------------------------------------------------
|
||
|
+AC_DEFUN([PKG_CHECK_MODULES],
|
||
|
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
|
||
|
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
|
||
|
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
|
||
|
+
|
||
|
+pkg_failed=no
|
||
|
+AC_MSG_CHECKING([for $1])
|
||
|
+
|
||
|
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
|
||
|
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
|
||
|
+
|
||
|
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
|
||
|
+and $1[]_LIBS to avoid the need to call pkg-config.
|
||
|
+See the pkg-config man page for more details.])
|
||
|
+
|
||
|
+if test $pkg_failed = yes; then
|
||
|
+ _PKG_SHORT_ERRORS_SUPPORTED
|
||
|
+ if test $_pkg_short_errors_supported = yes; then
|
||
|
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "$2" 2>&1`
|
||
|
+ else
|
||
|
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors "$2" 2>&1`
|
||
|
+ fi
|
||
|
+ # Put the nasty error message in config.log where it belongs
|
||
|
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
|
||
|
+
|
||
|
+ ifelse([$4], , [AC_MSG_ERROR(dnl
|
||
|
+[Package requirements ($2) were not met:
|
||
|
+
|
||
|
+$$1_PKG_ERRORS
|
||
|
+
|
||
|
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
|
||
|
+installed software in a non-standard prefix.
|
||
|
+
|
||
|
+_PKG_TEXT
|
||
|
+])],
|
||
|
+ [AC_MSG_RESULT([no])
|
||
|
+ $4])
|
||
|
+elif test $pkg_failed = untried; then
|
||
|
+ ifelse([$4], , [AC_MSG_FAILURE(dnl
|
||
|
+[The pkg-config script could not be found or is too old. Make sure it
|
||
|
+is in your PATH or set the PKG_CONFIG environment variable to the full
|
||
|
+path to pkg-config.
|
||
|
+
|
||
|
+_PKG_TEXT
|
||
|
+
|
||
|
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])],
|
||
|
+ [$4])
|
||
|
+else
|
||
|
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
|
||
|
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
|
||
|
+ AC_MSG_RESULT([yes])
|
||
|
+ ifelse([$3], , :, [$3])
|
||
|
+fi[]dnl
|
||
|
+])# PKG_CHECK_MODULES
|
||
|
+
|
||
|
# po.m4 serial 15 (gettext-0.17)
|
||
|
dnl Copyright (C) 1995-2007 Free Software Foundation, Inc.
|
||
|
dnl This file is free software; the Free Software Foundation
|
||
|
diff -up system-config-printer-1.1.10/configure.in.525e996 system-config-printer-1.1.10/configure.in
|
||
|
--- system-config-printer-1.1.10/configure.in.525e996 2009-07-22 13:53:25.000000000 +0100
|
||
|
+++ system-config-printer-1.1.10/configure.in 2009-07-26 19:01:45.685355364 +0100
|
||
|
@@ -40,6 +40,9 @@ AC_ARG_WITH(udev-rules,
|
||
|
AM_CONDITIONAL([UDEV_RULES], [test x$with_udev_rules != xno])
|
||
|
|
||
|
if test x$with_udev_rules != xno; then
|
||
|
+ PKG_CHECK_MODULES(DBUS_GLIB, [dbus-glib-1 >= 0.76])
|
||
|
+ AC_SUBST(DBUS_GLIB_CFLAGS)
|
||
|
+ AC_SUBST(DBUS_GLIB_LIBS)
|
||
|
AM_PROG_CC_C_O
|
||
|
fi
|
||
|
|
||
|
diff -up system-config-printer-1.1.10/cupshelpers/ppds.py.525e996 system-config-printer-1.1.10/cupshelpers/ppds.py
|
||
|
--- system-config-printer-1.1.10/cupshelpers/ppds.py.525e996 2009-07-22 13:22:49.000000000 +0100
|
||
|
+++ system-config-printer-1.1.10/cupshelpers/ppds.py 2009-07-26 19:01:45.686355890 +0100
|
||
|
@@ -159,29 +159,32 @@ def ppdMakeModelSplit (ppd_make_and_mode
|
||
|
# HP PPDs give NickNames like:
|
||
|
# *NickName: "HP LaserJet 4 Plus v2013.111 Postscript (recommended)"
|
||
|
# Find the version number.
|
||
|
- v = model.find (" v")
|
||
|
+ modell = model.lower ()
|
||
|
+ v = modell.find (" v")
|
||
|
if v != -1 and (model[v + 2].isdigit () or
|
||
|
(model[v + 2] == '.' and
|
||
|
model[v + 3].isdigit ())):
|
||
|
# Truncate at that point.
|
||
|
model = model[:v]
|
||
|
+ modell = modell[:v]
|
||
|
|
||
|
for suffix in [" hpijs",
|
||
|
- " Foomatic/",
|
||
|
+ " foomatic/",
|
||
|
" - ",
|
||
|
" w/",
|
||
|
" (",
|
||
|
- " PostScript",
|
||
|
- " PS",
|
||
|
- " PS1",
|
||
|
- " PS2",
|
||
|
- " PS3",
|
||
|
- " PXL",
|
||
|
- " series"
|
||
|
+ " postscript",
|
||
|
+ " ps",
|
||
|
+ " ps1",
|
||
|
+ " ps2",
|
||
|
+ " ps3",
|
||
|
+ " pxl",
|
||
|
+ " series",
|
||
|
","]:
|
||
|
- s = model.find (suffix)
|
||
|
+ s = modell.find (suffix)
|
||
|
if s != -1:
|
||
|
model = model[:s]
|
||
|
+ modell = modell[:s]
|
||
|
|
||
|
if makel == "hp":
|
||
|
modelnames = {"dj": "DeskJet",
|
||
|
@@ -190,10 +193,10 @@ def ppdMakeModelSplit (ppd_make_and_mode
|
||
|
"color lj": "Color LaserJet",
|
||
|
"ps ": "PhotoSmart",
|
||
|
"hp ": ""}
|
||
|
- modell = model.lower ()
|
||
|
for (name, fullname) in modelnames.iteritems ():
|
||
|
if modell.startswith (name):
|
||
|
model = fullname + model[len (name):]
|
||
|
+ modell = model.lower ()
|
||
|
|
||
|
for mfr in [ "Apple", "Canon", "Epson", "Lexmark", "Oki" ]:
|
||
|
if makel == mfr.lower ():
|
||
|
diff -up system-config-printer-1.1.10/Makefile.am.525e996 system-config-printer-1.1.10/Makefile.am
|
||
|
--- system-config-printer-1.1.10/Makefile.am.525e996 2009-07-22 15:11:41.000000000 +0100
|
||
|
+++ system-config-printer-1.1.10/Makefile.am 2009-07-26 19:01:45.680355779 +0100
|
||
|
@@ -152,14 +152,65 @@ bin_SCRIPTS=\
|
||
|
if UDEV_RULES
|
||
|
udevrulesdir=$(sysconfdir)/udev/rules.d
|
||
|
udevrules_DATA=udev/70-printers.rules
|
||
|
-udev_udev_configure_printer_SOURCES=\
|
||
|
- udev/udev-configure-printer.c
|
||
|
-udev_udev_configure_printer_LDADD=-lcups -ludev -lusb
|
||
|
+
|
||
|
+udev_printer_config_daemon_SOURCES= \
|
||
|
+ udev/printer-config-daemon.c \
|
||
|
+ udev/printer-config-main.c \
|
||
|
+ udev/printer-config.h
|
||
|
+udev_printer_config_daemon_DEPENDENCIES= \
|
||
|
+ udev/printer-config-server-bindings.h
|
||
|
+udev_printer_config_daemon_CPPFLAGS= \
|
||
|
+ $(DBUS_GLIB_CFLAGS)
|
||
|
+udev_printer_config_daemon_LDADD= \
|
||
|
+ $(DBUS_GLIB_LIBS) \
|
||
|
+ -lcups -ludev -lusb
|
||
|
+
|
||
|
+udev_udev_usb_printer_SOURCES= \
|
||
|
+ udev/udev-usb-printer.c
|
||
|
+udev_udev_usb_printer_DEPENDENCIES= \
|
||
|
+ udev/printer-config-client-bindings.h
|
||
|
+udev_udev_usb_printer_CPPFLAGS= \
|
||
|
+ $(DBUS_GLIB_CFLAGS)
|
||
|
+udev_udev_usb_printer_LDADD= \
|
||
|
+ $(DBUS_GLIB_LIBS) \
|
||
|
+ -ludev -lusb
|
||
|
udevhelperdir=/lib/udev
|
||
|
udevhelper_PROGRAMS=\
|
||
|
- udev/udev-configure-printer
|
||
|
-udevhelper_SCRIPTS=\
|
||
|
+ udev/udev-usb-printer
|
||
|
+
|
||
|
+udev/printer-config-server-bindings.h: udev/com.redhat.PrinterConfig.xml \
|
||
|
+ Makefile
|
||
|
+ dbus-binding-tool --prefix=printer_config_daemon \
|
||
|
+ --mode=glib-server \
|
||
|
+ --output=$@ $<
|
||
|
+
|
||
|
+udev/printer-config-client-bindings.h: udev/com.redhat.PrinterConfig.xml \
|
||
|
+ Makefile
|
||
|
+ dbus-binding-tool --prefix=printer_config_daemon \
|
||
|
+ --mode=glib-client \
|
||
|
+ --output=$@ $<
|
||
|
+
|
||
|
+BUILT_SOURCES= \
|
||
|
+ udev/printer-config-server-bindings.h \
|
||
|
+ udev/printer-config-client-bindings.h
|
||
|
+
|
||
|
+libexec_PROGRAMS=\
|
||
|
+ udev/printer-config-daemon
|
||
|
+libexec_SCRIPTS=\
|
||
|
udev/udev-add-printer
|
||
|
+
|
||
|
+dbusifdir = $(datadir)/dbus-1/interfaces
|
||
|
+dbusif_DATA = udev/com.redhat.PrinterConfig.xml
|
||
|
+
|
||
|
+servicedir = $(datadir)/dbus-1/system-services
|
||
|
+service_in_files = udev/com.redhat.PrinterConfig.service.in
|
||
|
+service_DATA = $(service_in_files:.service.in=.service)
|
||
|
+
|
||
|
+$(service_DATA): $(service_in_files) Makefile
|
||
|
+ @sed -e "s,\@libexecdir\@,$(libexecdir)," $< > $@
|
||
|
+
|
||
|
+dbusconfdir = $(sysconfdir)/dbus-1/system.d
|
||
|
+dbusconf_DATA = udev/com.redhat.PrinterConfig.conf
|
||
|
endif
|
||
|
|
||
|
man_MANS= \
|
||
|
@@ -238,7 +289,10 @@ EXTRA_DIST=\
|
||
|
intltool-merge.in \
|
||
|
intltool-update.in \
|
||
|
config.py.in \
|
||
|
- udev/70-printers.rules
|
||
|
+ udev/70-printers.rules \
|
||
|
+ udev/com.redhat.PrinterConfig.xml \
|
||
|
+ udev/com.redhat.PrinterConfig.service.in \
|
||
|
+ udev/com.redhat.PrinterConfig.conf
|
||
|
|
||
|
desktop_in_files = $(desktop_DATA:.desktop=.desktop.in)
|
||
|
|
||
|
@@ -293,12 +347,17 @@ test-ppd-module.sh:
|
||
|
|
||
|
TESTS = test-ppd-module.sh
|
||
|
|
||
|
+CLEANFILES = \
|
||
|
+ $(BUILT_SOURCES) \
|
||
|
+ udev/*.o
|
||
|
+
|
||
|
DISTCLEANFILES=*.pyc *.pyo *~ *.bak \
|
||
|
troubleshoot/*.pyc troubleshoot/*.pyo troubleshoot/*~ \
|
||
|
intltool-extract intltool-merge intltool-update \
|
||
|
*.desktop man/*.1 \
|
||
|
test-ppd-module.sh pickled-ppds \
|
||
|
- config.py
|
||
|
+ config.py \
|
||
|
+ $(service_DATA)
|
||
|
|
||
|
distclean-local:
|
||
|
rm -rf html
|
||
|
diff -up system-config-printer-1.1.10/system-config-printer.py.525e996 system-config-printer-1.1.10/system-config-printer.py
|
||
|
--- system-config-printer-1.1.10/system-config-printer.py.525e996 2009-07-21 15:16:35.000000000 +0100
|
||
|
+++ system-config-printer-1.1.10/system-config-printer.py 2009-07-26 19:01:45.690356122 +0100
|
||
|
@@ -3377,7 +3377,7 @@ class GUI(GtkGUI, monitor.Watcher):
|
||
|
name = name.replace ("#", "-")
|
||
|
if not self.checkNPName (name):
|
||
|
suffix=2
|
||
|
- while not self.checkNPName (name + str (suffix)):
|
||
|
+ while not self.checkNPName (name + "-" + str (suffix)):
|
||
|
suffix += 1
|
||
|
if suffix == 100:
|
||
|
break
|
||
|
diff -up system-config-printer-1.1.10/udev/70-printers.rules.525e996 system-config-printer-1.1.10/udev/70-printers.rules
|
||
|
--- system-config-printer-1.1.10/udev/70-printers.rules.525e996 2009-07-22 13:22:49.000000000 +0100
|
||
|
+++ system-config-printer-1.1.10/udev/70-printers.rules 2009-07-26 19:01:45.698481110 +0100
|
||
|
@@ -1,7 +1,7 @@
|
||
|
# Low-level USB device add trigger
|
||
|
-ACTION=="add", SUBSYSTEM=="usb", ATTR{bInterfaceClass}=="07", ATTR{bInterfaceSubClass}=="01", RUN+="udev-configure-printer add %p"
|
||
|
+ACTION=="add", SUBSYSTEM=="usb", ATTR{bInterfaceClass}=="07", ATTR{bInterfaceSubClass}=="01", RUN+="udev-usb-printer add %p"
|
||
|
# usblp device add trigger (needed when usblp is already loaded)
|
||
|
-ACTION=="add", KERNEL=="lp*", RUN+="udev-configure-printer add %p"
|
||
|
+ACTION=="add", KERNEL=="lp*", RUN+="udev-usb-printer add %p"
|
||
|
|
||
|
# Low-level USB device remove trigger
|
||
|
-ACTION=="remove", SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="*:0701*:*", RUN+="udev-configure-printer remove %p"
|
||
|
+ACTION=="remove", SUBSYSTEM=="usb", ENV{ID_USB_INTERFACES}=="*:0701*:*", RUN+="udev-usb-printer remove %p"
|
||
|
diff -up /dev/null system-config-printer-1.1.10/udev/com.redhat.PrinterConfig.conf
|
||
|
--- /dev/null 2009-07-26 12:31:15.305032486 +0100
|
||
|
+++ system-config-printer-1.1.10/udev/com.redhat.PrinterConfig.conf 2009-07-26 19:01:45.698481110 +0100
|
||
|
@@ -0,0 +1,16 @@
|
||
|
+<?xml version="1.0" encoding="UTF-8"?> <!-- -*- XML -*- -->
|
||
|
+
|
||
|
+<!DOCTYPE busconfig PUBLIC
|
||
|
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
|
||
|
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
|
||
|
+<busconfig>
|
||
|
+ <!-- Only root can own the service -->
|
||
|
+ <policy user="root">
|
||
|
+ <allow own="com.redhat.PrinterConfig"/>
|
||
|
+ <allow send_destination="com.redhat.PrinterConfig"/>
|
||
|
+ </policy>
|
||
|
+
|
||
|
+ <policy context="default">
|
||
|
+ <deny send_destination="com.redhat.PrinterConfig"/>
|
||
|
+ </policy>
|
||
|
+</busconfig>
|
||
|
diff -up /dev/null system-config-printer-1.1.10/udev/com.redhat.PrinterConfig.service.in
|
||
|
--- /dev/null 2009-07-26 12:31:15.305032486 +0100
|
||
|
+++ system-config-printer-1.1.10/udev/com.redhat.PrinterConfig.service.in 2009-07-26 19:01:45.699481020 +0100
|
||
|
@@ -0,0 +1,4 @@
|
||
|
+[D-BUS Service]
|
||
|
+Name=com.redhat.PrinterConfig
|
||
|
+Exec=@libexecdir@/printer-config-daemon
|
||
|
+User=root
|
||
|
diff -up /dev/null system-config-printer-1.1.10/udev/com.redhat.PrinterConfig.xml
|
||
|
--- /dev/null 2009-07-26 12:31:15.305032486 +0100
|
||
|
+++ system-config-printer-1.1.10/udev/com.redhat.PrinterConfig.xml 2009-07-26 19:01:45.699481020 +0100
|
||
|
@@ -0,0 +1,71 @@
|
||
|
+<!DOCTYPE node PUBLIC
|
||
|
+"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||
|
+"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||
|
+<node name="/com/redhat/PrinterConfig" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd">
|
||
|
+
|
||
|
+ <interface name="com.redhat.PrinterConfig">
|
||
|
+ <doc:doc>
|
||
|
+ <doc:description>
|
||
|
+ <doc:para>The PrinterConfig service is available via the
|
||
|
+ system message bus. To access the service, use the
|
||
|
+ <doc:tt>com.redhat.PrinterConfig</doc:tt> interface
|
||
|
+ on the <doc:tt>/com/redhat/PrinterConfig</doc:tt>
|
||
|
+ object on the D-Bus system bus service with the well-known
|
||
|
+ name
|
||
|
+ <doc:tt>com.redhat.PrinterConfig</doc:tt>.</doc:para>
|
||
|
+
|
||
|
+ <doc:para>It is intended to be used by udev when USB printers
|
||
|
+ are connected and disconnected.</doc:para>
|
||
|
+ </doc:description>
|
||
|
+ </doc:doc>
|
||
|
+
|
||
|
+ <method name="UsbPrinterAdd">
|
||
|
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||
|
+ <arg name="devpath" direction="in" type="s">
|
||
|
+ <doc:doc>
|
||
|
+ <doc:summary>
|
||
|
+ <doc:para>The udev devpath of the device with subsystem
|
||
|
+ usb and devtype usb_device referring to the USB printer
|
||
|
+ device.</doc:para>
|
||
|
+ </doc:summary>
|
||
|
+ </doc:doc>
|
||
|
+ </arg>
|
||
|
+
|
||
|
+ <arg name="deviceid" direction="in" type="s">
|
||
|
+ <doc:doc>
|
||
|
+ <doc:summary>
|
||
|
+ <doc:para>The IEEE 1284 Device ID (not including length
|
||
|
+ field) of the device.</doc:para>
|
||
|
+ </doc:summary>
|
||
|
+ </doc:doc>
|
||
|
+ </arg>
|
||
|
+
|
||
|
+ <doc:doc>
|
||
|
+ <doc:description>
|
||
|
+ <doc:para>This method informs the PrinterConfig service that
|
||
|
+ a USB printer is now connected.</doc:para>
|
||
|
+ </doc:description>
|
||
|
+ </doc:doc>
|
||
|
+ </method>
|
||
|
+
|
||
|
+ <method name="UsbPrinterRemove">
|
||
|
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||
|
+ <arg name="devpath" direction="in" type="s">
|
||
|
+ <doc:doc>
|
||
|
+ <doc:summary>
|
||
|
+ <doc:para>The udev devpath of the device with subsystem
|
||
|
+ usb and devtype usb_device referring to the USB printer
|
||
|
+ device.</doc:para>
|
||
|
+ </doc:summary>
|
||
|
+ </doc:doc>
|
||
|
+ </arg>
|
||
|
+
|
||
|
+ <doc:doc>
|
||
|
+ <doc:description>
|
||
|
+ <doc:para>This method informs the PrinterConfig service that
|
||
|
+ a USB printer has been disconnected.</doc:para>
|
||
|
+ </doc:description>
|
||
|
+ </doc:doc>
|
||
|
+ </method>
|
||
|
+ </interface>
|
||
|
+</node>
|
||
|
diff -up /dev/null system-config-printer-1.1.10/udev/printer-config-daemon.c
|
||
|
--- /dev/null 2009-07-26 12:31:15.305032486 +0100
|
||
|
+++ system-config-printer-1.1.10/udev/printer-config-daemon.c 2009-07-26 19:01:45.701480595 +0100
|
||
|
@@ -0,0 +1,1248 @@
|
||
|
+/* -*- Mode: C; c-file-style: "gnu" -*-
|
||
|
+ * printer-config-daemon - a D-Bus service for configuring printers
|
||
|
+ * Copyright (C) 2009 Red Hat, Inc.
|
||
|
+ * Author: 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
+ *
|
||
|
+ */
|
||
|
+
|
||
|
+#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE 1
|
||
|
+#include "printer-config.h"
|
||
|
+#include "printer-config-server-bindings.h"
|
||
|
+#include <cups/cups.h>
|
||
|
+#include <cups/http.h>
|
||
|
+#include <dbus/dbus-glib-bindings.h>
|
||
|
+#include <fcntl.h>
|
||
|
+#include <libudev.h>
|
||
|
+#include <limits.h>
|
||
|
+#include <stdio.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <string.h>
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+#include <sys/wait.h>
|
||
|
+#include <syslog.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <usb.h>
|
||
|
+
|
||
|
+#define DISABLED_REASON "Unplugged or turned off"
|
||
|
+#define MATCH_ONLY_DISABLED 1
|
||
|
+#define USB_URI_MAP "/var/run/udev-configure-printer/usb-uris"
|
||
|
+
|
||
|
+struct children
|
||
|
+{
|
||
|
+ struct children *next;
|
||
|
+ GPid pid;
|
||
|
+};
|
||
|
+
|
||
|
+struct device_uris
|
||
|
+{
|
||
|
+ size_t n_uris;
|
||
|
+ char **uri;
|
||
|
+};
|
||
|
+
|
||
|
+struct usb_uri_map_entry
|
||
|
+{
|
||
|
+ struct usb_uri_map_entry *next;
|
||
|
+
|
||
|
+ /* The devpath of the ("usb","usb_device") device. */
|
||
|
+ char *devpath;
|
||
|
+
|
||
|
+ /* List of matching device URIs. */
|
||
|
+ struct device_uris uris;
|
||
|
+};
|
||
|
+
|
||
|
+struct usb_uri_map
|
||
|
+{
|
||
|
+ struct usb_uri_map_entry *entries;
|
||
|
+
|
||
|
+ /* Open file descriptor for the map, or -1 if it has already been
|
||
|
+ * written. */
|
||
|
+ int fd;
|
||
|
+};
|
||
|
+
|
||
|
+struct device_id
|
||
|
+{
|
||
|
+ char *full_device_id;
|
||
|
+ char *mfg;
|
||
|
+ char *mdl;
|
||
|
+ char *sern;
|
||
|
+};
|
||
|
+
|
||
|
+/* Device URI schemes in decreasing order of preference. */
|
||
|
+static const char *device_uri_types[] =
|
||
|
+ {
|
||
|
+ "hp",
|
||
|
+ "usb",
|
||
|
+ };
|
||
|
+
|
||
|
+static int
|
||
|
+device_uri_type (const char *uri)
|
||
|
+{
|
||
|
+ int slen = strcspn (uri, ":");
|
||
|
+ int i;
|
||
|
+ int n = sizeof (device_uri_types) / sizeof (device_uri_types[0]);
|
||
|
+ for (i = 0; i < n; i++)
|
||
|
+ if (!strncmp (uri, device_uri_types[i], slen) &&
|
||
|
+ device_uri_types[i][slen] == '\0')
|
||
|
+ break;
|
||
|
+
|
||
|
+ return i;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+add_device_uri (struct device_uris *uris,
|
||
|
+ const char *uri)
|
||
|
+{
|
||
|
+ char *uri_copy = strdup (uri);
|
||
|
+ if (!uri_copy)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "out of memory");
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (uris->n_uris == 0)
|
||
|
+ {
|
||
|
+ uris->uri = malloc (sizeof (char *));
|
||
|
+ if (uris->uri)
|
||
|
+ {
|
||
|
+ uris->n_uris = 1;
|
||
|
+ uris->uri[0] = uri_copy;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ char **old = uris->uri;
|
||
|
+ if (++uris->n_uris < UINT_MAX / sizeof (char *))
|
||
|
+ {
|
||
|
+ uris->uri = realloc (uris->uri,
|
||
|
+ sizeof (char *) * uris->n_uris);
|
||
|
+ if (uris->uri)
|
||
|
+ uris->uri[uris->n_uris - 1] = uri_copy;
|
||
|
+ else
|
||
|
+ {
|
||
|
+ uris->uri = old;
|
||
|
+ uris->n_uris--;
|
||
|
+ free (uri_copy);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ else
|
||
|
+ {
|
||
|
+ uris->n_uris--;
|
||
|
+ free (uri_copy);
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+free_device_uris (struct device_uris *uris)
|
||
|
+{
|
||
|
+ size_t i;
|
||
|
+ for (i = 0; i < uris->n_uris; i++)
|
||
|
+ free (uris->uri[i]);
|
||
|
+ free (uris->uri);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+add_usb_uri_mapping (struct usb_uri_map **map,
|
||
|
+ const char *devpath,
|
||
|
+ const struct device_uris *uris)
|
||
|
+{
|
||
|
+ struct usb_uri_map_entry *entry, **prev;
|
||
|
+ size_t i;
|
||
|
+ prev = &(*map)->entries;
|
||
|
+ while (*prev)
|
||
|
+ prev = &((*prev)->next);
|
||
|
+
|
||
|
+ entry = malloc (sizeof (struct usb_uri_map_entry));
|
||
|
+ if (!entry)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "out of memory");
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ entry->devpath = strdup (devpath);
|
||
|
+ entry->uris.n_uris = uris->n_uris;
|
||
|
+ entry->uris.uri = malloc (sizeof (char *) * uris->n_uris);
|
||
|
+ for (i = 0; i < uris->n_uris; i++)
|
||
|
+ entry->uris.uri[i] = strdup (uris->uri[i]);
|
||
|
+ entry->next = NULL;
|
||
|
+ *prev = entry;
|
||
|
+}
|
||
|
+
|
||
|
+static struct usb_uri_map *
|
||
|
+read_usb_uri_map (void)
|
||
|
+{
|
||
|
+ int fd = open (USB_URI_MAP, O_RDWR);
|
||
|
+ struct usb_uri_map *map = NULL;
|
||
|
+ struct flock lock;
|
||
|
+ struct stat st;
|
||
|
+ char *buf, *line;
|
||
|
+
|
||
|
+ if (fd == -1)
|
||
|
+ {
|
||
|
+ char dir[] = USB_URI_MAP;
|
||
|
+ char *p = strrchr (dir, '/');
|
||
|
+ if (p)
|
||
|
+ {
|
||
|
+ *p = '\0';
|
||
|
+ mkdir (dir, 0755);
|
||
|
+ fd = open (USB_URI_MAP, O_RDWR | O_TRUNC | O_CREAT, 0644);
|
||
|
+ if (fd == -1)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "failed to create " USB_URI_MAP);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ map = malloc (sizeof (struct usb_uri_map));
|
||
|
+ if (!map)
|
||
|
+ {
|
||
|
+ close (fd);
|
||
|
+ syslog (LOG_ERR, "out of memory");
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ lock.l_type = F_WRLCK;
|
||
|
+ lock.l_whence = SEEK_SET;
|
||
|
+ lock.l_start = 0;
|
||
|
+ lock.l_len = 0;
|
||
|
+ if (fcntl (fd, F_SETLKW, &lock) == -1)
|
||
|
+ {
|
||
|
+ close (fd);
|
||
|
+ free (map);
|
||
|
+ syslog (LOG_ERR, "failed to lock " USB_URI_MAP);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ map->entries = NULL;
|
||
|
+ map->fd = fd;
|
||
|
+ if (fstat (fd, &st) == -1)
|
||
|
+ {
|
||
|
+ close (fd);
|
||
|
+ free (map);
|
||
|
+ syslog (LOG_ERR, "failed to fstat " USB_URI_MAP " (fd %d)", fd);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Read the entire file into memory. */
|
||
|
+ buf = malloc (1 + (sizeof (char) * st.st_size));
|
||
|
+ if (!buf)
|
||
|
+ {
|
||
|
+ close (fd);
|
||
|
+ free (map);
|
||
|
+ syslog (LOG_ERR, "out of memory");
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (read (fd, buf, st.st_size) < 0)
|
||
|
+ {
|
||
|
+ close (fd);
|
||
|
+ free (map);
|
||
|
+ free (buf);
|
||
|
+ syslog (LOG_ERR, "failed to read " USB_URI_MAP);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ buf[st.st_size] = '\0';
|
||
|
+ line = buf;
|
||
|
+ while (line)
|
||
|
+ {
|
||
|
+ char *saveptr = NULL;
|
||
|
+ const char *devpath, *uri;
|
||
|
+ struct device_uris uris;
|
||
|
+ char *nextline = strchr (line, '\n');
|
||
|
+ if (!nextline)
|
||
|
+ break;
|
||
|
+
|
||
|
+ *nextline++ = '\0';
|
||
|
+ if (nextline >= buf + st.st_size)
|
||
|
+ nextline = NULL;
|
||
|
+
|
||
|
+ devpath = strtok_r (line, "\t", &saveptr);
|
||
|
+ uri = strtok_r (NULL, "\t", &saveptr);
|
||
|
+ if (!devpath || !uri)
|
||
|
+ {
|
||
|
+ syslog (LOG_DEBUG, "Incorrect line in " USB_URI_MAP ": %s",
|
||
|
+ line);
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ uris.n_uris = 1;
|
||
|
+ uris.uri = malloc (sizeof (char *));
|
||
|
+ if (uris.uri == NULL)
|
||
|
+ break;
|
||
|
+
|
||
|
+ uris.uri[0] = strdup (uri);
|
||
|
+ while ((uri = strtok_r (NULL, "\t", &saveptr)) != NULL)
|
||
|
+ add_device_uri (&uris, uri);
|
||
|
+
|
||
|
+ add_usb_uri_mapping (&map, devpath, &uris);
|
||
|
+
|
||
|
+ line = nextline;
|
||
|
+ }
|
||
|
+
|
||
|
+ free (buf);
|
||
|
+ return map;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+write_usb_uri_map (struct usb_uri_map *map)
|
||
|
+{
|
||
|
+ struct usb_uri_map_entry *entry;
|
||
|
+ int fd = map->fd;
|
||
|
+ FILE *f;
|
||
|
+
|
||
|
+ lseek (fd, SEEK_SET, 0);
|
||
|
+ ftruncate (fd, 0);
|
||
|
+ f = fdopen (fd, "w");
|
||
|
+ if (!f)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "failed to fdopen " USB_URI_MAP " (fd %d)", fd);
|
||
|
+ close (fd);
|
||
|
+ map->fd = -1;
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (entry = map->entries; entry; entry = entry->next)
|
||
|
+ {
|
||
|
+ size_t i;
|
||
|
+ fprintf (f, "%s\t%s", entry->devpath, entry->uris.uri[0]);
|
||
|
+ for (i = 1; i < entry->uris.n_uris; i++)
|
||
|
+ fprintf (f, "\t%s", entry->uris.uri[i]);
|
||
|
+ fwrite ("\n", 1, 1, f);
|
||
|
+ }
|
||
|
+
|
||
|
+ fclose (f);
|
||
|
+ map->fd = -1;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+free_usb_uri_map (struct usb_uri_map *map)
|
||
|
+{
|
||
|
+ struct usb_uri_map_entry *entry, *next;
|
||
|
+ for (entry = map->entries; entry; entry = next)
|
||
|
+ {
|
||
|
+ next = entry->next;
|
||
|
+ free (entry->devpath);
|
||
|
+ free_device_uris (&entry->uris);
|
||
|
+ free (entry);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (map->fd != -1)
|
||
|
+ close (map->fd);
|
||
|
+
|
||
|
+ free (map);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+free_device_id (struct device_id *id)
|
||
|
+{
|
||
|
+ free (id->full_device_id);
|
||
|
+ free (id->mfg);
|
||
|
+ free (id->mdl);
|
||
|
+ free (id->sern);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+parse_device_id (const char *device_id,
|
||
|
+ struct device_id *id)
|
||
|
+{
|
||
|
+ char *fieldname;
|
||
|
+ char *start, *end;
|
||
|
+ size_t len;
|
||
|
+
|
||
|
+ len = strlen (device_id);
|
||
|
+ if (len == 0)
|
||
|
+ return;
|
||
|
+
|
||
|
+ if (device_id[len - 1] == '\n')
|
||
|
+ len--;
|
||
|
+
|
||
|
+ id->full_device_id = malloc (len + 1);
|
||
|
+ fieldname = malloc (len + 1);
|
||
|
+ if (!id->full_device_id || !fieldname)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "out of memory");
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ memcpy (id->full_device_id, device_id, len);
|
||
|
+ id->full_device_id[len] = '\0';
|
||
|
+ fieldname[0] = '\0';
|
||
|
+ start = id->full_device_id;
|
||
|
+ while (*start != '\0')
|
||
|
+ {
|
||
|
+ /* New field. */
|
||
|
+
|
||
|
+ end = start;
|
||
|
+ while (*end != '\0' && *end != ':')
|
||
|
+ end++;
|
||
|
+
|
||
|
+ if (*end == '\0')
|
||
|
+ break;
|
||
|
+
|
||
|
+ len = end - start;
|
||
|
+ memcpy (fieldname, start, len);
|
||
|
+ fieldname[len] = '\0';
|
||
|
+
|
||
|
+ start = end + 1;
|
||
|
+ while (*end != '\0' && *end != ';')
|
||
|
+ end++;
|
||
|
+
|
||
|
+ len = end - start;
|
||
|
+
|
||
|
+ if (!id->mfg &&
|
||
|
+ (!strncasecmp (fieldname, "MANUFACTURER", 12) ||
|
||
|
+ !strncasecmp (fieldname, "MFG", 3)))
|
||
|
+ id->mfg = strndup (start, len);
|
||
|
+ else if (!id->mdl &&
|
||
|
+ (!strncasecmp (fieldname, "MODEL", 5) ||
|
||
|
+ !strncasecmp (fieldname, "MDL", 3)))
|
||
|
+ id->mdl = strndup (start, len);
|
||
|
+ else if (!id->sern &&
|
||
|
+ (!strncasecmp (fieldname, "SERIALNUMBER", 12) ||
|
||
|
+ !strncasecmp (fieldname, "SERN", 4) ||
|
||
|
+ !strncasecmp (fieldname, "SN", 2)))
|
||
|
+ id->sern = strndup (start, len);
|
||
|
+
|
||
|
+ if (*end != '\0')
|
||
|
+ start = end + 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ free (fieldname);
|
||
|
+}
|
||
|
+
|
||
|
+static const char *
|
||
|
+no_password (const char *prompt)
|
||
|
+{
|
||
|
+ return "";
|
||
|
+}
|
||
|
+
|
||
|
+static http_t *
|
||
|
+cups_connection (void)
|
||
|
+{
|
||
|
+ http_t *cups = NULL;
|
||
|
+ static int first_time = 1;
|
||
|
+
|
||
|
+ if (first_time)
|
||
|
+ {
|
||
|
+ cupsSetPasswordCB (no_password);
|
||
|
+ first_time = 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ cups = httpConnectEncrypt ("localhost", 631,
|
||
|
+ HTTP_ENCRYPT_IF_REQUESTED);
|
||
|
+ if (cups == NULL)
|
||
|
+ {
|
||
|
+ /* Don't bother retrying here. Instead, the CUPS initscript
|
||
|
+ should run these commands after cupsd is started:
|
||
|
+
|
||
|
+ rmmod usblp
|
||
|
+ udevadm trigger --subsystem-match=usb \
|
||
|
+ --attr-match=bInterfaceClass=07 \
|
||
|
+ --attr-match=bInterfaceSubClass=01
|
||
|
+ */
|
||
|
+
|
||
|
+ syslog (LOG_DEBUG, "failed to connect to CUPS server; giving up");
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ return cups;
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+find_matching_device_uris (struct device_id *id,
|
||
|
+ const char *usbserial,
|
||
|
+ struct device_uris *uris,
|
||
|
+ const char *devpath,
|
||
|
+ struct usb_uri_map *map)
|
||
|
+{
|
||
|
+ http_t *cups;
|
||
|
+ ipp_t *request, *answer;
|
||
|
+ ipp_attribute_t *attr;
|
||
|
+ struct device_uris uris_noserial;
|
||
|
+ struct device_uris all_uris;
|
||
|
+ size_t i, n;
|
||
|
+ const char *exclude_schemes[] = {
|
||
|
+ "beh",
|
||
|
+ "bluetooth",
|
||
|
+ "http",
|
||
|
+ "https",
|
||
|
+ "ipp",
|
||
|
+ "lpd",
|
||
|
+ "ncp",
|
||
|
+ "parallel",
|
||
|
+ "scsi",
|
||
|
+ "smb",
|
||
|
+ "snmp",
|
||
|
+ "socket",
|
||
|
+ };
|
||
|
+
|
||
|
+ uris->n_uris = uris_noserial.n_uris = all_uris.n_uris = 0;
|
||
|
+ uris->uri = uris_noserial.uri = all_uris.uri = NULL;
|
||
|
+
|
||
|
+ /* Leave the bus to settle. */
|
||
|
+ sleep (1);
|
||
|
+
|
||
|
+ cups = cups_connection ();
|
||
|
+ request = ippNewRequest (CUPS_GET_DEVICES);
|
||
|
+ ippAddStrings (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "exclude-schemes",
|
||
|
+ sizeof (exclude_schemes) / sizeof(exclude_schemes[0]),
|
||
|
+ NULL, exclude_schemes);
|
||
|
+
|
||
|
+ answer = cupsDoRequest (cups, request, "/");
|
||
|
+ httpClose (cups);
|
||
|
+
|
||
|
+ if (answer == NULL)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "failed to send IPP request %d",
|
||
|
+ request->request.op.operation_id);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (answer->request.status.status_code > IPP_OK_CONFLICT)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "IPP request %d failed (%d)",
|
||
|
+ request->request.op.operation_id,
|
||
|
+ answer->request.status.status_code);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (attr = answer->attrs; attr; attr = attr->next)
|
||
|
+ {
|
||
|
+ const char *device_uri = NULL;
|
||
|
+ struct device_id this_id;
|
||
|
+ this_id.full_device_id = this_id.mfg = this_id.mdl = this_id.sern = NULL;
|
||
|
+
|
||
|
+ while (attr && attr->group_tag != IPP_TAG_PRINTER)
|
||
|
+ attr = attr->next;
|
||
|
+
|
||
|
+ if (!attr)
|
||
|
+ break;
|
||
|
+
|
||
|
+ for (; attr && attr->group_tag == IPP_TAG_PRINTER; attr = attr->next)
|
||
|
+ {
|
||
|
+ if (attr->value_tag == IPP_TAG_URI &&
|
||
|
+ !strcmp (attr->name, "device-uri"))
|
||
|
+ device_uri = attr->values[0].string.text;
|
||
|
+ else if (attr->value_tag == IPP_TAG_TEXT &&
|
||
|
+ !strcmp (attr->name, "device-id"))
|
||
|
+ parse_device_id (attr->values[0].string.text, &this_id);
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Only use device schemes in our preference order for matching
|
||
|
+ * against the IEEE 1284 Device ID. */
|
||
|
+
|
||
|
+ for (i = 0;
|
||
|
+ device_uri &&
|
||
|
+ i < sizeof (device_uri_types) / sizeof (device_uri_types[0]);
|
||
|
+ i++)
|
||
|
+ {
|
||
|
+ size_t len = strlen (device_uri_types[i]);
|
||
|
+ if (!strncmp (device_uri_types[i], device_uri, len) &&
|
||
|
+ device_uri[len] == ':')
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (device_uri)
|
||
|
+ add_device_uri (&all_uris, device_uri);
|
||
|
+
|
||
|
+ if (i == sizeof (device_uri_types) / sizeof (device_uri_types[0]))
|
||
|
+ /* Not what we want to match against. Ignore this one. */
|
||
|
+ device_uri = NULL;
|
||
|
+
|
||
|
+ /* Now check the manufacturer and model names. */
|
||
|
+ if (device_uri && this_id.mfg && this_id.mdl &&
|
||
|
+ !strcmp (this_id.mfg, id->mfg) &&
|
||
|
+ !strcmp (this_id.mdl, id->mdl))
|
||
|
+ {
|
||
|
+ /* We've checked everything except the serial numbers. This
|
||
|
+ * is more complicated. Some devices include a serial
|
||
|
+ * number (SERN) field in their IEEE 1284 Device ID. Others
|
||
|
+ * don't -- this was not a mandatory field in the
|
||
|
+ * specification.
|
||
|
+ *
|
||
|
+ * If the device includes SERN field in its, it must match
|
||
|
+ * what the device-id attribute has.
|
||
|
+ *
|
||
|
+ * Otherwise, the only means we have of knowing which device
|
||
|
+ * is meant is the USB serial number.
|
||
|
+ *
|
||
|
+ * CUPS backends may choose to insert the USB serial number
|
||
|
+ * into the SERN field when reporting a device-id attribute.
|
||
|
+ * HPLIP does this, and it seems not to stray too far from
|
||
|
+ * the intent of that field. We accommodate this.
|
||
|
+ *
|
||
|
+ * Alternatively, CUPS backends may include the USB serial
|
||
|
+ * number somewhere in their reported device-uri attributes.
|
||
|
+ * For instance, the CUPS 1.4 usb backend, when compiled
|
||
|
+ * with libusb support, gives device URIs containing the USB
|
||
|
+ * serial number for devices without a SERN field, like
|
||
|
+ * this: usb://HP/DESKJET%20990C?serial=US05M1D20CIJ
|
||
|
+ *
|
||
|
+ * To accommodate this we examine tokens between '?', '='
|
||
|
+ * and '&' delimiters to check for USB serial number
|
||
|
+ * matches.
|
||
|
+ *
|
||
|
+ * CUPS 1.3, and CUPS 1.4 without libusb support, doesn't do this.
|
||
|
+ * As a result we also need to deal with devices that don't report a
|
||
|
+ * SERN field where the backends that don't add a SERN field from
|
||
|
+ * the USB serial number and also don't include the USB serial
|
||
|
+ * number in the URI.
|
||
|
+ */
|
||
|
+
|
||
|
+ int match = 0;
|
||
|
+ if ((id->sern && this_id.sern && !strcmp (id->sern, this_id.sern)))
|
||
|
+ {
|
||
|
+ syslog (LOG_DEBUG, "SERN fields match");
|
||
|
+ match = 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!match && usbserial[0] != '\0')
|
||
|
+ {
|
||
|
+ if (!id->sern)
|
||
|
+ {
|
||
|
+ if (this_id.sern && !strcmp (usbserial, this_id.sern))
|
||
|
+ {
|
||
|
+ syslog (LOG_DEBUG,
|
||
|
+ "SERN field matches USB serial number");
|
||
|
+ match = 1;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!match)
|
||
|
+ {
|
||
|
+ char *saveptr, *uri = strdup (device_uri);
|
||
|
+ const char *token;
|
||
|
+ const char *sep = "?=&/";
|
||
|
+ for (token = strtok_r (uri, sep, &saveptr);
|
||
|
+ token;
|
||
|
+ token = strtok_r (NULL, sep, &saveptr))
|
||
|
+ if (!strcmp (token, usbserial))
|
||
|
+ {
|
||
|
+ syslog (LOG_DEBUG, "URI contains USB serial number");
|
||
|
+ match = 1;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ free (uri);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (match)
|
||
|
+ {
|
||
|
+ syslog (LOG_DEBUG, "URI match: %s", device_uri);
|
||
|
+ add_device_uri (uris, device_uri);
|
||
|
+ }
|
||
|
+ else if (!id->sern)
|
||
|
+ {
|
||
|
+ syslog (LOG_DEBUG, "URI matches without serial number: %s",
|
||
|
+ device_uri);
|
||
|
+ add_device_uri (&uris_noserial, device_uri);
|
||
|
+ }
|
||
|
+ else
|
||
|
+ syslog (LOG_DEBUG, "No match: %s", device_uri);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!attr)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ ippDelete (answer);
|
||
|
+
|
||
|
+ /* Decide what to do about device URIs that did not match a serial
|
||
|
+ * number. The device had no SERN field, and the USB serial number
|
||
|
+ * was nowhere to be found from the device URI or device-id field.
|
||
|
+ *
|
||
|
+ * Device URIs with no reference to serial number can only each ever
|
||
|
+ * work when only one printer of that model is connected.
|
||
|
+ * Accordingly, it is safe to disable queues using such URIs, as we
|
||
|
+ * know the removed/added device is that lone printer.
|
||
|
+ *
|
||
|
+ * When adding queues it is best to avoid URIs that don't
|
||
|
+ * distinguish serial numbers.
|
||
|
+ *
|
||
|
+ * What we'll do, then, is concatenate the list of "non-serial" URIs
|
||
|
+ * onto the end of the list of "serial" URIs.
|
||
|
+ */
|
||
|
+
|
||
|
+ if (uris->n_uris == 0 && uris_noserial.n_uris > 0)
|
||
|
+ {
|
||
|
+ syslog (LOG_DEBUG, "No serial number URI matches so using those without");
|
||
|
+ uris->n_uris = uris_noserial.n_uris;
|
||
|
+ uris->uri = uris_noserial.uri;
|
||
|
+ uris_noserial.n_uris = 0;
|
||
|
+ uris_noserial.uri = NULL;
|
||
|
+ }
|
||
|
+ else if (uris_noserial.n_uris > 0)
|
||
|
+ {
|
||
|
+ char **old = uris->uri;
|
||
|
+ uris->uri = realloc (uris->uri,
|
||
|
+ sizeof (char *) * (uris->n_uris +
|
||
|
+ uris_noserial.n_uris));
|
||
|
+ if (!uris->uri)
|
||
|
+ uris->uri = old;
|
||
|
+ else
|
||
|
+ {
|
||
|
+ for (i = 0; i < uris_noserial.n_uris; i++)
|
||
|
+ uris->uri[uris->n_uris + i] = uris_noserial.uri[i];
|
||
|
+ uris->n_uris += uris_noserial.n_uris;
|
||
|
+ }
|
||
|
+
|
||
|
+ uris_noserial.n_uris = 0;
|
||
|
+ uris_noserial.uri = NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ free_device_uris (&uris_noserial);
|
||
|
+
|
||
|
+ /* Having decided which device URIs match based on IEEE 1284 Device
|
||
|
+ * ID, we now need to look for "paired" URIs for other functions of
|
||
|
+ * a multi-function device. This are the same except for the
|
||
|
+ * scheme. */
|
||
|
+
|
||
|
+ n = uris->n_uris;
|
||
|
+ for (i = 0; i < n; i++)
|
||
|
+ {
|
||
|
+ size_t j;
|
||
|
+ char *me = uris->uri[i];
|
||
|
+ char *my_rest = strchr (me, ':');
|
||
|
+ size_t my_schemelen;
|
||
|
+ if (!my_rest)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ my_schemelen = my_rest - me;
|
||
|
+ for (j = 0; j < all_uris.n_uris; j++)
|
||
|
+ {
|
||
|
+ char *twin = all_uris.uri[j];
|
||
|
+ char *twin_rest = strchr (twin, ':');
|
||
|
+ size_t twin_schemelen;
|
||
|
+ if (!twin_rest)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ twin_schemelen = twin_rest - twin;
|
||
|
+ if (my_schemelen == twin_schemelen &&
|
||
|
+ !strncmp (me, twin, my_schemelen))
|
||
|
+ /* This is the one we are looking for the twin of. */
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (!strcmp (my_rest, twin_rest))
|
||
|
+ {
|
||
|
+ syslog (LOG_DEBUG, "%s twinned with %s", me, twin);
|
||
|
+ add_device_uri (uris, twin);
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ free_device_uris (&all_uris);
|
||
|
+ if (uris->n_uris > 0)
|
||
|
+ {
|
||
|
+ add_usb_uri_mapping (&map, devpath, uris);
|
||
|
+ write_usb_uri_map (map);
|
||
|
+ free_usb_uri_map (map);
|
||
|
+ }
|
||
|
+
|
||
|
+ return uris->n_uris;
|
||
|
+}
|
||
|
+
|
||
|
+/* Call a function for each queue with the given device-uri and printer-state.
|
||
|
+ * Returns the number of queues with a matching device-uri. */
|
||
|
+static size_t
|
||
|
+for_each_matching_queue (struct device_uris *device_uris,
|
||
|
+ int flags,
|
||
|
+ void (*fn) (const char *, void *),
|
||
|
+ void *context)
|
||
|
+{
|
||
|
+ size_t matched = 0;
|
||
|
+ http_t *cups = cups_connection ();
|
||
|
+ ipp_t *request, *answer;
|
||
|
+ ipp_attribute_t *attr;
|
||
|
+ const char *attributes[] = {
|
||
|
+ "printer-uri-supported",
|
||
|
+ "device-uri",
|
||
|
+ "printer-state",
|
||
|
+ "printer-state-message",
|
||
|
+ };
|
||
|
+
|
||
|
+ request = ippNewRequest (CUPS_GET_PRINTERS);
|
||
|
+ ippAddStrings (request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
|
||
|
+ "requested-attributes",
|
||
|
+ sizeof (attributes) / sizeof (attributes[0]),
|
||
|
+ NULL, attributes);
|
||
|
+ answer = cupsDoRequest (cups, request, "/");
|
||
|
+ httpClose (cups);
|
||
|
+ if (answer == NULL)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "failed to send CUPS-Get-Printers request");
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (answer->request.status.status_code > IPP_OK_CONFLICT)
|
||
|
+ {
|
||
|
+ if (answer->request.status.status_code == IPP_NOT_FOUND)
|
||
|
+ {
|
||
|
+ /* No printer queues configured. */
|
||
|
+ ippDelete (answer);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ syslog (LOG_ERR, "CUPS-Get-Printers request failed (%d)",
|
||
|
+ answer->request.status.status_code);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (attr = answer->attrs; attr; attr = attr->next)
|
||
|
+ {
|
||
|
+ const char *this_printer_uri = NULL;
|
||
|
+ const char *this_device_uri = NULL;
|
||
|
+ const char *printer_state_message = NULL;
|
||
|
+ int state = 0;
|
||
|
+ size_t i;
|
||
|
+
|
||
|
+ while (attr && attr->group_tag != IPP_TAG_PRINTER)
|
||
|
+ attr = attr->next;
|
||
|
+
|
||
|
+ if (!attr)
|
||
|
+ break;
|
||
|
+
|
||
|
+ for (; attr && attr->group_tag == IPP_TAG_PRINTER; attr = attr->next)
|
||
|
+ {
|
||
|
+ if (attr->value_tag == IPP_TAG_URI)
|
||
|
+ {
|
||
|
+ if (!strcmp (attr->name, "device-uri"))
|
||
|
+ this_device_uri = attr->values[0].string.text;
|
||
|
+ else if (!strcmp (attr->name, "printer-uri-supported"))
|
||
|
+ this_printer_uri = attr->values[0].string.text;
|
||
|
+ }
|
||
|
+ else if (attr->value_tag == IPP_TAG_TEXT &&
|
||
|
+ !strcmp (attr->name, "printer-state-message"))
|
||
|
+ printer_state_message = attr->values[0].string.text;
|
||
|
+ else if (attr->value_tag == IPP_TAG_ENUM &&
|
||
|
+ !strcmp (attr->name, "printer-state"))
|
||
|
+ state = attr->values[0].integer;
|
||
|
+ }
|
||
|
+
|
||
|
+ for (i = 0; i < device_uris->n_uris; i++)
|
||
|
+ if (!strcmp (device_uris->uri[i], this_device_uri))
|
||
|
+ {
|
||
|
+ matched++;
|
||
|
+ if (((flags & MATCH_ONLY_DISABLED) &&
|
||
|
+ state == IPP_PRINTER_STOPPED &&
|
||
|
+ !strcmp (printer_state_message, DISABLED_REASON)) ||
|
||
|
+ (flags & MATCH_ONLY_DISABLED) == 0)
|
||
|
+ {
|
||
|
+ syslog (LOG_DEBUG ,"Queue %s has matching device URI",
|
||
|
+ this_printer_uri);
|
||
|
+ (*fn) (this_printer_uri, context);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!attr)
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ ippDelete (answer);
|
||
|
+ return matched;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+enable_queue (const char *printer_uri, void *context)
|
||
|
+{
|
||
|
+ /* Disable it. */
|
||
|
+ http_t *cups = cups_connection ();
|
||
|
+ ipp_t *request, *answer;
|
||
|
+ request = ippNewRequest (IPP_RESUME_PRINTER);
|
||
|
+ ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
|
||
|
+ "printer-uri", NULL, printer_uri);
|
||
|
+ answer = cupsDoRequest (cups, request, "/admin/");
|
||
|
+ if (!answer)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "Failed to send IPP-Resume-Printer request");
|
||
|
+ httpClose (cups);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (answer->request.status.status_code > IPP_OK_CONFLICT)
|
||
|
+ syslog (LOG_ERR, "IPP-Resume-Printer request failed");
|
||
|
+ else
|
||
|
+ syslog (LOG_INFO, "Re-enabled printer %s", printer_uri);
|
||
|
+
|
||
|
+ ippDelete (answer);
|
||
|
+ httpClose (cups);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+disable_queue (const char *printer_uri, void *context)
|
||
|
+{
|
||
|
+ /* Disable it. */
|
||
|
+ http_t *cups = cups_connection ();
|
||
|
+ ipp_t *request, *answer;
|
||
|
+ request = ippNewRequest (IPP_PAUSE_PRINTER);
|
||
|
+ ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_URI,
|
||
|
+ "printer-uri", NULL, printer_uri);
|
||
|
+ ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_TEXT,
|
||
|
+ "printer-state-message", NULL, DISABLED_REASON);
|
||
|
+ answer = cupsDoRequest (cups, request, "/admin/");
|
||
|
+ if (!answer)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "Failed to send IPP-Pause-Printer request");
|
||
|
+ httpClose (cups);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (answer->request.status.status_code > IPP_OK_CONFLICT)
|
||
|
+ syslog (LOG_ERR, "IPP-Pause-Printer request failed");
|
||
|
+ else
|
||
|
+ syslog (LOG_INFO, "Disabled printer %s as the corresponding device "
|
||
|
+ "was unplugged or turned off", printer_uri);
|
||
|
+
|
||
|
+ ippDelete (answer);
|
||
|
+ httpClose (cups);
|
||
|
+}
|
||
|
+
|
||
|
+static char *
|
||
|
+syspath_from_devpath (struct udev *udev, const char *devpath)
|
||
|
+{
|
||
|
+ const char *sys;
|
||
|
+ char *syspath;
|
||
|
+ size_t syslen, devpathlen = strlen (devpath);
|
||
|
+ sys = udev_get_sys_path (udev);
|
||
|
+ syslen = strlen (sys);
|
||
|
+ syspath = malloc (syslen + devpathlen + 1);
|
||
|
+ if (syspath == NULL)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ memcpy (syspath, sys, syslen);
|
||
|
+ memcpy (syspath + syslen, devpath, devpathlen);
|
||
|
+ syspath[syslen + devpathlen] = '\0';
|
||
|
+ return syspath;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+reap_child (GPid pid, gint status, gpointer context)
|
||
|
+{
|
||
|
+ PrinterConfigDaemon *self = context;
|
||
|
+ struct children *child, **prev = &self->children;
|
||
|
+ g_debug ("PID %d has exited", pid);
|
||
|
+ for (child = self->children; child; prev = &child->next, child = child->next)
|
||
|
+ if (child->pid == pid)
|
||
|
+ {
|
||
|
+ *prev = child->next;
|
||
|
+ free (child);
|
||
|
+ g_debug ("self->children is now %p", self->children);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+G_DEFINE_TYPE (PrinterConfigDaemon, printer_config_daemon, G_TYPE_OBJECT)
|
||
|
+
|
||
|
+static gboolean
|
||
|
+kill_timeout (gpointer context)
|
||
|
+{
|
||
|
+ PrinterConfigDaemon *self = context;
|
||
|
+ if (self->children == NULL)
|
||
|
+ {
|
||
|
+ g_debug ("Time to go");
|
||
|
+ main_quit ();
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+
|
||
|
+ g_debug ("children is %p", self->children);
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+static gboolean
|
||
|
+reset_killtimer (PrinterConfigDaemon *self)
|
||
|
+{
|
||
|
+ if (self->killtimer != 0)
|
||
|
+ {
|
||
|
+ g_debug ("Remove killtimer %d", self->killtimer);
|
||
|
+ g_source_remove (self->killtimer);
|
||
|
+ }
|
||
|
+
|
||
|
+ self->killtimer = g_timeout_add (1000, kill_timeout, self);
|
||
|
+ g_debug ("Set killtimer %d", self->killtimer);
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+printer_config_daemon_dispose (GObject *gobject)
|
||
|
+{
|
||
|
+ PrinterConfigDaemon *self = PRINTER_CONFIG_DAEMON (gobject);
|
||
|
+ g_debug ("dispose %p", self);
|
||
|
+ G_OBJECT_CLASS (printer_config_daemon_parent_class)->dispose (gobject);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+printer_config_daemon_finalize (GObject *gobject)
|
||
|
+{
|
||
|
+ PrinterConfigDaemon *self = PRINTER_CONFIG_DAEMON (gobject);
|
||
|
+ g_debug ("finalize %p", self);
|
||
|
+ if (self->killtimer != 0)
|
||
|
+ {
|
||
|
+ g_debug ("Remove killtimer %d", self->killtimer);
|
||
|
+ g_source_remove (self->killtimer);
|
||
|
+ }
|
||
|
+
|
||
|
+ G_OBJECT_CLASS (printer_config_daemon_parent_class)->finalize (gobject);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+printer_config_daemon_class_init (PrinterConfigDaemonClass *klass)
|
||
|
+{
|
||
|
+ GError *error = NULL;
|
||
|
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
||
|
+ gobject_class->dispose = printer_config_daemon_dispose;
|
||
|
+ gobject_class->finalize = printer_config_daemon_finalize;
|
||
|
+ g_debug ("class init");
|
||
|
+ klass->connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
|
||
|
+ if (klass->connection == NULL)
|
||
|
+ {
|
||
|
+ g_warning ("Unable to connect to D-Bus: %s", error->message);
|
||
|
+ g_error_free (error);
|
||
|
+ return;
|
||
|
+ }
|
||
|
+
|
||
|
+ dbus_g_object_type_install_info(PRINTER_CONFIG_TYPE_DAEMON,
|
||
|
+ &dbus_glib_printer_config_daemon_object_info);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+printer_config_daemon_init (PrinterConfigDaemon *self)
|
||
|
+{
|
||
|
+ DBusGProxy *driver_proxy;
|
||
|
+ GError *error = NULL;
|
||
|
+ PrinterConfigDaemonClass *klass = PRINTER_CONFIG_DAEMON_GET_CLASS (self);
|
||
|
+ guint request_ret;
|
||
|
+
|
||
|
+ dbus_g_connection_register_g_object (klass->connection,
|
||
|
+ "/com/redhat/PrinterConfig",
|
||
|
+ G_OBJECT (self));
|
||
|
+ driver_proxy = dbus_g_proxy_new_for_name (klass->connection,
|
||
|
+ DBUS_SERVICE_DBUS,
|
||
|
+ DBUS_PATH_DBUS,
|
||
|
+ DBUS_INTERFACE_DBUS);
|
||
|
+
|
||
|
+ g_debug ("daemon init %p", self);
|
||
|
+ if (!org_freedesktop_DBus_request_name (driver_proxy,
|
||
|
+ "com.redhat.PrinterConfig",
|
||
|
+ 0, &request_ret,
|
||
|
+ &error))
|
||
|
+ {
|
||
|
+ g_warning ("Unable to register service: %s", error->message);
|
||
|
+ g_error_free (error);
|
||
|
+ }
|
||
|
+
|
||
|
+ self->children = NULL;
|
||
|
+ g_object_unref (driver_proxy);
|
||
|
+}
|
||
|
+
|
||
|
+gboolean
|
||
|
+printer_config_daemon_usb_printer_add (PrinterConfigDaemon *self,
|
||
|
+ const char *usb_device_devpath,
|
||
|
+ const char *deviceid,
|
||
|
+ DBusGMethodInvocation *context)
|
||
|
+{
|
||
|
+ struct device_id id;
|
||
|
+ struct device_uris device_uris;
|
||
|
+ struct usb_uri_map *map;
|
||
|
+ struct usb_uri_map_entry *entry;
|
||
|
+ struct udev *udev;
|
||
|
+ struct udev_device *dev;
|
||
|
+ const char *usbserial;
|
||
|
+ char *syspath;
|
||
|
+
|
||
|
+ syslog (LOG_DEBUG, "add %s", usb_device_devpath);
|
||
|
+ dbus_g_method_return (context);
|
||
|
+
|
||
|
+ reset_killtimer (self);
|
||
|
+ udev = udev_new ();
|
||
|
+ if (!udev)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "failed to init libudev");
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+
|
||
|
+ map = read_usb_uri_map ();
|
||
|
+ if (!map)
|
||
|
+ return TRUE;
|
||
|
+
|
||
|
+ for (entry = map->entries; entry; entry = entry->next)
|
||
|
+ if (!strcmp (entry->devpath, usb_device_devpath))
|
||
|
+ break;
|
||
|
+
|
||
|
+ if (entry != NULL)
|
||
|
+ /* The map already had an entry so has already been dealt
|
||
|
+ * with. This can happen because there are two "add"
|
||
|
+ * triggers: one for the usb_device device and the other for
|
||
|
+ * the usblp device. We have most likely been triggered by
|
||
|
+ * the usblp device, so the usb_device rule got there before
|
||
|
+ * us and succeeded.
|
||
|
+ *
|
||
|
+ * Pretend we didn't find any device URIs that matched, and
|
||
|
+ * exit.
|
||
|
+ */
|
||
|
+ return TRUE;
|
||
|
+
|
||
|
+ id.full_device_id = id.mfg = id.mdl = id.sern = NULL;
|
||
|
+ parse_device_id (deviceid, &id);
|
||
|
+ if (!id.mfg || !id.mdl)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "invalid IEEE 1284 Device ID %s",
|
||
|
+ id.full_device_id);
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+
|
||
|
+ syspath = syspath_from_devpath (udev, usb_device_devpath);
|
||
|
+ if (!syspath)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "unable to get syspath from devpath");
|
||
|
+ return FALSE;
|
||
|
+ }
|
||
|
+
|
||
|
+ dev = udev_device_new_from_syspath (udev, syspath);
|
||
|
+ if (!dev)
|
||
|
+ {
|
||
|
+ udev_device_unref (dev);
|
||
|
+ udev_unref (udev);
|
||
|
+ syslog (LOG_ERR, "unable to access %s", syspath);
|
||
|
+ free (syspath);
|
||
|
+ return TRUE;
|
||
|
+ }
|
||
|
+
|
||
|
+ free (syspath);
|
||
|
+ usbserial = udev_device_get_sysattr_value (dev, "serial");
|
||
|
+ syslog (LOG_DEBUG, "MFG:%s MDL:%s SERN:%s serial:%s", id.mfg, id.mdl,
|
||
|
+ id.sern ? id.sern : "-", usbserial ? usbserial : "-");
|
||
|
+
|
||
|
+ find_matching_device_uris (&id, usbserial, &device_uris, usb_device_devpath,
|
||
|
+ map);
|
||
|
+ udev_device_unref (dev);
|
||
|
+ udev_unref (udev);
|
||
|
+ if (device_uris.n_uris == 0)
|
||
|
+ {
|
||
|
+ free_device_id (&id);
|
||
|
+ return TRUE;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Re-enable any queues we'd previously disabled. */
|
||
|
+ if (for_each_matching_queue (&device_uris, MATCH_ONLY_DISABLED,
|
||
|
+ enable_queue, NULL) == 0)
|
||
|
+ {
|
||
|
+ size_t i;
|
||
|
+ int type;
|
||
|
+ GPid child_pid;
|
||
|
+ GError *error = NULL;
|
||
|
+ char **argv = malloc (sizeof (char *) * (3 + device_uris.n_uris));
|
||
|
+
|
||
|
+ /* No queue is configured for this device yet.
|
||
|
+ Decide on a URI to use. */
|
||
|
+ type = device_uri_type (device_uris.uri[0]);
|
||
|
+ for (i = 1; i < device_uris.n_uris; i++)
|
||
|
+ {
|
||
|
+ int new_type = device_uri_type (device_uris.uri[i]);
|
||
|
+ if (new_type < type)
|
||
|
+ {
|
||
|
+ char *swap = device_uris.uri[0];
|
||
|
+ device_uris.uri[0] = device_uris.uri[i];
|
||
|
+ device_uris.uri[i] = swap;
|
||
|
+ type = new_type;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ argv[0] = "/usr/libexec/udev-add-printer";
|
||
|
+ argv[1] = id.full_device_id;
|
||
|
+ for (i = 0; i < device_uris.n_uris; i++)
|
||
|
+ argv[i + 2] = device_uris.uri[i];
|
||
|
+ argv[i + 2] = NULL;
|
||
|
+
|
||
|
+ syslog (LOG_DEBUG, "About to add queue for %s", argv[2]);
|
||
|
+ if (g_spawn_async ("/", argv, NULL,
|
||
|
+ G_SPAWN_STDOUT_TO_DEV_NULL |
|
||
|
+ G_SPAWN_STDERR_TO_DEV_NULL |
|
||
|
+ G_SPAWN_DO_NOT_REAP_CHILD,
|
||
|
+ NULL, NULL,
|
||
|
+ &child_pid,
|
||
|
+ &error) == FALSE)
|
||
|
+ syslog (LOG_ERR, "Failed to execute %s", argv[0]);
|
||
|
+ else
|
||
|
+ {
|
||
|
+ struct children *child = malloc (sizeof (struct children));
|
||
|
+ child->next = self->children;
|
||
|
+ child->pid = child_pid;
|
||
|
+ self->children = child;
|
||
|
+ g_child_watch_add (child_pid, reap_child, self);
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ free_device_id (&id);
|
||
|
+ free_device_uris (&device_uris);
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+gboolean
|
||
|
+printer_config_daemon_usb_printer_remove (PrinterConfigDaemon *self,
|
||
|
+ const char *devpath,
|
||
|
+ DBusGMethodInvocation *context)
|
||
|
+{
|
||
|
+ struct usb_uri_map *map;
|
||
|
+ struct usb_uri_map_entry *entry, **prev;
|
||
|
+ struct device_uris *uris = NULL;
|
||
|
+
|
||
|
+ syslog (LOG_DEBUG, "remove %s", devpath);
|
||
|
+ dbus_g_method_return (context);
|
||
|
+
|
||
|
+ reset_killtimer (self);
|
||
|
+ map = read_usb_uri_map ();
|
||
|
+ if (!map)
|
||
|
+ return TRUE;
|
||
|
+
|
||
|
+ prev = &map->entries;
|
||
|
+ for (entry = map->entries; entry; entry = entry->next)
|
||
|
+ {
|
||
|
+ if (!strcmp (entry->devpath, devpath))
|
||
|
+ {
|
||
|
+ uris = &entry->uris;
|
||
|
+ break;
|
||
|
+ }
|
||
|
+
|
||
|
+ prev = &(entry->next);
|
||
|
+ }
|
||
|
+
|
||
|
+ if (uris)
|
||
|
+ {
|
||
|
+ /* Find the relevant queues and disable them if they are enabled. */
|
||
|
+ for_each_matching_queue (uris, 0, disable_queue, NULL);
|
||
|
+ *prev = entry->next;
|
||
|
+ write_usb_uri_map (map);
|
||
|
+ }
|
||
|
+
|
||
|
+ free_usb_uri_map (map);
|
||
|
+ return TRUE;
|
||
|
+}
|
||
|
+
|
||
|
+PrinterConfigDaemon *
|
||
|
+printer_config_daemon_new (void)
|
||
|
+{
|
||
|
+ PrinterConfigDaemon *self;
|
||
|
+ self = PRINTER_CONFIG_DAEMON (g_object_new (PRINTER_CONFIG_TYPE_DAEMON,
|
||
|
+ NULL));
|
||
|
+ self->children = NULL;
|
||
|
+ self->killtimer = 0;
|
||
|
+ g_debug ("New daemon %p", self);
|
||
|
+ return self;
|
||
|
+}
|
||
|
diff -up /dev/null system-config-printer-1.1.10/udev/printer-config.h
|
||
|
--- /dev/null 2009-07-26 12:31:15.305032486 +0100
|
||
|
+++ system-config-printer-1.1.10/udev/printer-config.h 2009-07-26 19:01:45.703480670 +0100
|
||
|
@@ -0,0 +1,76 @@
|
||
|
+/* -*- Mode: C; c-file-style: "gnu" -*-
|
||
|
+ * printer-config - a D-Bus service for configuring printers
|
||
|
+ * Copyright (C) 2009 Red Hat, Inc.
|
||
|
+ * Author: 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
+ *
|
||
|
+ */
|
||
|
+
|
||
|
+#ifndef PRINTER_CONFIG_H
|
||
|
+#define PRINTER_CONFIG_H
|
||
|
+
|
||
|
+#include <glib-object.h>
|
||
|
+#include <dbus/dbus-glib.h>
|
||
|
+
|
||
|
+#define PRINTER_CONFIG_TYPE_DAEMON (printer_config_daemon_get_type ())
|
||
|
+#define PRINTER_CONFIG_DAEMON(obj) \
|
||
|
+ (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
|
||
|
+ PRINTER_CONFIG_TYPE_DAEMON, \
|
||
|
+ PrinterConfigDaemon))
|
||
|
+#define PRINTER_CONFIG_IS_DAEMON_CLASS(klass) \
|
||
|
+ (G_TYPE_CHECK_CLASS_CAST ((klass), PRINTER_CONFIG_TYPE_DAEMON, \
|
||
|
+ PrinterConfigDaemonClass))
|
||
|
+#define PRINTER_CONFIG_DAEMON_GET_CLASS(obj) \
|
||
|
+ (G_TYPE_INSTANCE_GET_CLASS ((obj), PRINTER_CONFIG_TYPE_DAEMON, \
|
||
|
+ PrinterConfigDaemonClass))
|
||
|
+
|
||
|
+typedef struct _PrinterConfigDaemon PrinterConfigDaemon;
|
||
|
+typedef struct _PrinterConfigDaemonClass PrinterConfigDaemonClass;
|
||
|
+
|
||
|
+struct children;
|
||
|
+struct _PrinterConfigDaemon
|
||
|
+{
|
||
|
+ GObject parent_instance;
|
||
|
+
|
||
|
+ /* instance members */
|
||
|
+ struct children *children;
|
||
|
+ guint killtimer;
|
||
|
+};
|
||
|
+
|
||
|
+struct _PrinterConfigDaemonClass
|
||
|
+{
|
||
|
+ GObjectClass parent_class;
|
||
|
+
|
||
|
+ /* class members */
|
||
|
+ DBusGConnection *connection;
|
||
|
+};
|
||
|
+
|
||
|
+/* used by PRINTER_CONFIG_TYPE_DAEMON */
|
||
|
+GType printer_config_daemon_get_type (void);
|
||
|
+
|
||
|
+PrinterConfigDaemon *printer_config_daemon_new (void);
|
||
|
+gboolean printer_config_daemon_usb_printer_add (PrinterConfigDaemon *d,
|
||
|
+ const char *devpath,
|
||
|
+ const char *deviceid,
|
||
|
+ DBusGMethodInvocation *ctx);
|
||
|
+
|
||
|
+gboolean printer_config_daemon_usb_printer_remove (PrinterConfigDaemon *d,
|
||
|
+ const char *devpath,
|
||
|
+ DBusGMethodInvocation *ctx);
|
||
|
+
|
||
|
+void main_quit (void);
|
||
|
+
|
||
|
+#endif /* PRINTER_CONFIG_H */
|
||
|
diff -up /dev/null system-config-printer-1.1.10/udev/printer-config-main.c
|
||
|
--- /dev/null 2009-07-26 12:31:15.305032486 +0100
|
||
|
+++ system-config-printer-1.1.10/udev/printer-config-main.c 2009-07-26 19:01:45.702480595 +0100
|
||
|
@@ -0,0 +1,159 @@
|
||
|
+/* -*- Mode: C; c-file-style: "gnu" -*-
|
||
|
+ *
|
||
|
+ * Copyright (C) 2007 David Zeuthen <davidz@redhat.com>
|
||
|
+ * Copyright (C) 2009 Red Hat, Inc.
|
||
|
+ *
|
||
|
+ * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||
|
+ *
|
||
|
+ */
|
||
|
+
|
||
|
+#ifdef HAVE_CONFIG_H
|
||
|
+# include "config.h"
|
||
|
+#endif
|
||
|
+
|
||
|
+#include <stdlib.h>
|
||
|
+#include <stdio.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <signal.h>
|
||
|
+#include <errno.h>
|
||
|
+#include <string.h>
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+#include <fcntl.h>
|
||
|
+#include <pwd.h>
|
||
|
+#include <grp.h>
|
||
|
+
|
||
|
+#include <glib.h>
|
||
|
+#include <glib-object.h>
|
||
|
+
|
||
|
+#define DBUS_API_SUBJECT_TO_CHANGE
|
||
|
+#include <dbus/dbus-glib.h>
|
||
|
+#include <dbus/dbus-glib-lowlevel.h>
|
||
|
+
|
||
|
+#include "printer-config.h"
|
||
|
+
|
||
|
+#define NAME_TO_CLAIM "com.redhat.PrinterConfig"
|
||
|
+
|
||
|
+static gboolean
|
||
|
+acquire_name_on_proxy (DBusGProxy *bus_proxy)
|
||
|
+{
|
||
|
+ GError *error;
|
||
|
+ guint result;
|
||
|
+ gboolean res;
|
||
|
+ gboolean ret;
|
||
|
+
|
||
|
+ ret = FALSE;
|
||
|
+
|
||
|
+ if (bus_proxy == NULL) {
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ error = NULL;
|
||
|
+ res = dbus_g_proxy_call (bus_proxy,
|
||
|
+ "RequestName",
|
||
|
+ &error,
|
||
|
+ G_TYPE_STRING, NAME_TO_CLAIM,
|
||
|
+ G_TYPE_UINT, 0,
|
||
|
+ G_TYPE_INVALID,
|
||
|
+ G_TYPE_UINT, &result,
|
||
|
+ G_TYPE_INVALID);
|
||
|
+ if (! res) {
|
||
|
+ if (error != NULL) {
|
||
|
+ g_warning ("Failed to acquire %s: %s", NAME_TO_CLAIM, error->message);
|
||
|
+ g_error_free (error);
|
||
|
+ } else {
|
||
|
+ g_warning ("Failed to acquire %s", NAME_TO_CLAIM);
|
||
|
+ }
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
|
||
|
+ if (error != NULL) {
|
||
|
+ g_warning ("Failed to acquire %s: %s", NAME_TO_CLAIM, error->message);
|
||
|
+ g_error_free (error);
|
||
|
+ } else {
|
||
|
+ g_warning ("Failed to acquire %s", NAME_TO_CLAIM);
|
||
|
+ }
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = TRUE;
|
||
|
+
|
||
|
+ out:
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static GMainLoop *loop;
|
||
|
+
|
||
|
+void main_quit (void);
|
||
|
+
|
||
|
+void
|
||
|
+main_quit (void)
|
||
|
+{
|
||
|
+ g_main_loop_quit (loop);
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+main (int argc, char **argv)
|
||
|
+{
|
||
|
+ PrinterConfigDaemon *daemon;
|
||
|
+ GError *error;
|
||
|
+ DBusGProxy *bus_proxy;
|
||
|
+ DBusGConnection *bus;
|
||
|
+ int ret = 1;
|
||
|
+
|
||
|
+ g_type_init ();
|
||
|
+
|
||
|
+ error = NULL;
|
||
|
+ bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
|
||
|
+ if (bus == NULL) {
|
||
|
+ g_warning ("Couldn't connect to system bus: %s", error->message);
|
||
|
+ g_error_free (error);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ bus_proxy = dbus_g_proxy_new_for_name (bus,
|
||
|
+ DBUS_SERVICE_DBUS,
|
||
|
+ DBUS_PATH_DBUS,
|
||
|
+ DBUS_INTERFACE_DBUS);
|
||
|
+ if (bus_proxy == NULL) {
|
||
|
+ g_warning ("Could not construct bus_proxy object; bailing out");
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (!acquire_name_on_proxy (bus_proxy) ) {
|
||
|
+ g_warning ("Could not acquire name; bailing out");
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ g_debug ("Starting printer-config-daemon version %s", VERSION);
|
||
|
+
|
||
|
+ daemon = printer_config_daemon_new ();
|
||
|
+
|
||
|
+ if (daemon == NULL) {
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ loop = g_main_loop_new (NULL, FALSE);
|
||
|
+
|
||
|
+ g_main_loop_run (loop);
|
||
|
+
|
||
|
+ g_object_unref (daemon);
|
||
|
+ g_main_loop_unref (loop);
|
||
|
+ ret = 0;
|
||
|
+
|
||
|
+ out:
|
||
|
+ return ret;
|
||
|
+}
|
||
|
diff -up system-config-printer-1.1.10/udev/udev-add-printer.525e996 system-config-printer-1.1.10/udev/udev-add-printer
|
||
|
--- system-config-printer-1.1.10/udev/udev-add-printer.525e996 2009-07-22 13:22:49.000000000 +0100
|
||
|
+++ system-config-printer-1.1.10/udev/udev-add-printer 2009-07-26 19:01:45.703480670 +0100
|
||
|
@@ -27,17 +27,28 @@ import sys
|
||
|
import traceback
|
||
|
from syslog import *
|
||
|
|
||
|
-def create_queue (c, name, device_uri, ppdname, info):
|
||
|
+def create_queue (c, printers, name, device_uri, ppdname, info):
|
||
|
# Make sure the name is unique.
|
||
|
- printers = cupshelpers.getPrinters (c)
|
||
|
- names = printers.keys ()
|
||
|
- if name in names:
|
||
|
- suffix = 2
|
||
|
- while (name + "-" + str (suffix)) in names:
|
||
|
+ namel = unicode (name.lower ())
|
||
|
+ unique = False
|
||
|
+ suffix = 1
|
||
|
+ while not unique:
|
||
|
+ unique = True
|
||
|
+ for printer in printers.values ():
|
||
|
+ if (not printer.discovered and
|
||
|
+ ((suffix == 1 and printer.name.lower () == namel) or
|
||
|
+ (suffix > 1 and
|
||
|
+ printer.name.lower () == namel + "-" + str (suffix)))):
|
||
|
+ unique = False
|
||
|
+ break
|
||
|
+
|
||
|
+ if not unique:
|
||
|
suffix += 1
|
||
|
if suffix == 100:
|
||
|
break
|
||
|
- name += str (suffix)
|
||
|
+
|
||
|
+ if suffix > 1:
|
||
|
+ name += "-" + str (suffix)
|
||
|
|
||
|
c.addPrinter (name,
|
||
|
device=device_uri,
|
||
|
@@ -45,14 +56,19 @@ def create_queue (c, name, device_uri, p
|
||
|
info=info,
|
||
|
location=os.uname ()[1])
|
||
|
cupshelpers.activateNewPrinter (c, name)
|
||
|
+ return name
|
||
|
|
||
|
-def add_queue (device_id, device_uris, is_fax=False):
|
||
|
+def add_queue (device_id, device_uris, fax_basename=False):
|
||
|
"""
|
||
|
Create a CUPS queue.
|
||
|
+
|
||
|
+ device_id: the IEEE 1284 Device ID of the device to add a queue for.
|
||
|
+ device_uris: device URIs, best first, for this device
|
||
|
+ fax_basename: False if this is not a fax queue, else name prefix
|
||
|
"""
|
||
|
|
||
|
syslog (LOG_DEBUG, "add_queue: URIs=%s" % device_uris)
|
||
|
- if is_fax:
|
||
|
+ if fax_basename != False:
|
||
|
notification = None
|
||
|
else:
|
||
|
try:
|
||
|
@@ -83,34 +99,22 @@ def add_queue (device_id, device_uris, i
|
||
|
name = name.replace ("/", "-")
|
||
|
name = name.replace ("#", "-")
|
||
|
|
||
|
- create_queue (c, name, device_uris[0], ppdname,
|
||
|
- "%s %s" % (id_dict["MFG"], id_dict["MDL"]))
|
||
|
+ if fax_basename != False:
|
||
|
+ name = fax_basename + "-" + name
|
||
|
|
||
|
- if not is_fax:
|
||
|
+ printers = cupshelpers.getPrinters (c)
|
||
|
+ uniquename = create_queue (c, printers, name, device_uris[0], ppdname,
|
||
|
+ "%s %s" % (id_dict["MFG"], id_dict["MDL"]))
|
||
|
+
|
||
|
+ if fax_basename == False:
|
||
|
# Look for a corresponding fax queue. We can only
|
||
|
# identify these by looking for device URIs that are the
|
||
|
# same as this one but with a different scheme. If we
|
||
|
# find one whose scheme ends in "fax", use that as a fax
|
||
|
# queue. Note that the HPLIP backends do follow this
|
||
|
# pattern (hp and hpfax).
|
||
|
- not_fax_schemes=["beh",
|
||
|
- "bluetooth",
|
||
|
- "http",
|
||
|
- "https",
|
||
|
- "ipp",
|
||
|
- "lpd",
|
||
|
- "parallel",
|
||
|
- "serial",
|
||
|
- "smb",
|
||
|
- "snmp",
|
||
|
- "socket",
|
||
|
- "scsi",
|
||
|
- "usb"]
|
||
|
- devices = c.getDevices (exclude_schemes=not_fax_schemes)
|
||
|
- for uri, device_dict in devices.iteritems ():
|
||
|
- if uri in device_uris:
|
||
|
- continue
|
||
|
-
|
||
|
+ used_uris = map (lambda x: x.device_uri, printers.values ())
|
||
|
+ for uri in device_uris[1:]:
|
||
|
if uri.find (":") == -1:
|
||
|
continue
|
||
|
|
||
|
@@ -119,17 +123,34 @@ def add_queue (device_id, device_uris, i
|
||
|
# Now see if the non-scheme parts of the URI match
|
||
|
# any of the URIs we were given.
|
||
|
for each_uri in device_uris:
|
||
|
+ if each_uri == uri:
|
||
|
+ continue
|
||
|
(s, device_uri_rest) = each_uri.split (":", 1)
|
||
|
if rest == device_uri_rest:
|
||
|
+ # This one matches. Check there is not
|
||
|
+ # already a queue using this URI.
|
||
|
+ if uri in used_uris:
|
||
|
+ break
|
||
|
+
|
||
|
+ try:
|
||
|
+ devices = c.getDevices(include_schemes=[scheme])
|
||
|
+ except TypeError:
|
||
|
+ # include_schemes requires pycups 1.9.46
|
||
|
+ devices = c.getDevices ()
|
||
|
+
|
||
|
+ device_dict = devices.get (uri)
|
||
|
+ if device_dict == None:
|
||
|
+ break
|
||
|
+
|
||
|
add_queue (device_dict.get ("device-id", ""),
|
||
|
- [uri], is_fax=True)
|
||
|
+ [uri], fax_basename=uniquename)
|
||
|
else:
|
||
|
# Not an exact match.
|
||
|
- name = device_uris[0]
|
||
|
+ uniquename = device_uris[0]
|
||
|
|
||
|
if notification:
|
||
|
try:
|
||
|
- notification.NewPrinter (status, name, id_dict["MFG"],
|
||
|
+ notification.NewPrinter (status, uniquename, id_dict["MFG"],
|
||
|
id_dict["MDL"], id_dict["DES"],
|
||
|
reduce(lambda x, y: x + ',' + y,
|
||
|
id_dict["CMD"]))
|
||
|
diff -up system-config-printer-1.1.10/udev/udev-configure-printer.c.525e996 system-config-printer-1.1.10/udev/udev-configure-printer.c
|
||
|
diff -up /dev/null system-config-printer-1.1.10/udev/udev-usb-printer.c
|
||
|
--- /dev/null 2009-07-26 12:31:15.305032486 +0100
|
||
|
+++ system-config-printer-1.1.10/udev/udev-usb-printer.c 2009-07-26 19:01:45.711481093 +0100
|
||
|
@@ -0,0 +1,454 @@
|
||
|
+/* -*- Mode: C; c-file-style: "gnu" -*-
|
||
|
+ * udev-usb-printer - a udev callout to configure print queues
|
||
|
+ * Copyright (C) 2009 Red Hat, Inc.
|
||
|
+ * Author: 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
+ *
|
||
|
+ */
|
||
|
+
|
||
|
+/*
|
||
|
+ * The protocol for this program is:
|
||
|
+ *
|
||
|
+ * udev-usb-printer add {DEVPATH}
|
||
|
+ * udev-usb-printer remove {DEVPATH}
|
||
|
+ *
|
||
|
+ * where DEVPATH is the path (%p) of the device
|
||
|
+ */
|
||
|
+
|
||
|
+#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE 1
|
||
|
+
|
||
|
+#include <dbus/dbus-glib-bindings.h>
|
||
|
+#include <fcntl.h>
|
||
|
+#include <libudev.h>
|
||
|
+#include <limits.h>
|
||
|
+#include <stdio.h>
|
||
|
+#include <stdlib.h>
|
||
|
+#include <string.h>
|
||
|
+#include <sys/types.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+#include <syslog.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <usb.h>
|
||
|
+
|
||
|
+#include "printer-config-client-bindings.h"
|
||
|
+
|
||
|
+struct device_id
|
||
|
+{
|
||
|
+ char *full_device_id;
|
||
|
+ char *mfg;
|
||
|
+ char *mdl;
|
||
|
+ char *sern;
|
||
|
+};
|
||
|
+
|
||
|
+static void
|
||
|
+free_device_id (struct device_id *id)
|
||
|
+{
|
||
|
+ free (id->full_device_id);
|
||
|
+ free (id->mfg);
|
||
|
+ free (id->mdl);
|
||
|
+ free (id->sern);
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+parse_device_id (const char *device_id,
|
||
|
+ struct device_id *id)
|
||
|
+{
|
||
|
+ char *fieldname;
|
||
|
+ char *start, *end;
|
||
|
+ size_t len;
|
||
|
+
|
||
|
+ len = strlen (device_id);
|
||
|
+ if (len == 0)
|
||
|
+ return;
|
||
|
+
|
||
|
+ if (device_id[len - 1] == '\n')
|
||
|
+ len--;
|
||
|
+
|
||
|
+ id->full_device_id = malloc (len + 1);
|
||
|
+ fieldname = malloc (len + 1);
|
||
|
+ if (!id->full_device_id || !fieldname)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "out of memory");
|
||
|
+ exit (1);
|
||
|
+ }
|
||
|
+
|
||
|
+ memcpy (id->full_device_id, device_id, len);
|
||
|
+ id->full_device_id[len] = '\0';
|
||
|
+ fieldname[0] = '\0';
|
||
|
+ start = id->full_device_id;
|
||
|
+ while (*start != '\0')
|
||
|
+ {
|
||
|
+ /* New field. */
|
||
|
+
|
||
|
+ end = start;
|
||
|
+ while (*end != '\0' && *end != ':')
|
||
|
+ end++;
|
||
|
+
|
||
|
+ if (*end == '\0')
|
||
|
+ break;
|
||
|
+
|
||
|
+ len = end - start;
|
||
|
+ memcpy (fieldname, start, len);
|
||
|
+ fieldname[len] = '\0';
|
||
|
+
|
||
|
+ start = end + 1;
|
||
|
+ while (*end != '\0' && *end != ';')
|
||
|
+ end++;
|
||
|
+
|
||
|
+ len = end - start;
|
||
|
+
|
||
|
+ if (!id->mfg &&
|
||
|
+ (!strncasecmp (fieldname, "MANUFACTURER", 12) ||
|
||
|
+ !strncasecmp (fieldname, "MFG", 3)))
|
||
|
+ id->mfg = strndup (start, len);
|
||
|
+ else if (!id->mdl &&
|
||
|
+ (!strncasecmp (fieldname, "MODEL", 5) ||
|
||
|
+ !strncasecmp (fieldname, "MDL", 3)))
|
||
|
+ id->mdl = strndup (start, len);
|
||
|
+ else if (!id->sern &&
|
||
|
+ (!strncasecmp (fieldname, "SERIALNUMBER", 12) ||
|
||
|
+ !strncasecmp (fieldname, "SERN", 4) ||
|
||
|
+ !strncasecmp (fieldname, "SN", 2)))
|
||
|
+ id->sern = strndup (start, len);
|
||
|
+
|
||
|
+ if (*end != '\0')
|
||
|
+ start = end + 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ free (fieldname);
|
||
|
+}
|
||
|
+
|
||
|
+static char *
|
||
|
+syspath_from_devpath (struct udev *udev, const char *devpath)
|
||
|
+{
|
||
|
+ const char *sys;
|
||
|
+ char *syspath;
|
||
|
+ size_t syslen, devpathlen = strlen (devpath);
|
||
|
+ sys = udev_get_sys_path (udev);
|
||
|
+ syslen = strlen (sys);
|
||
|
+ syspath = malloc (syslen + devpathlen + 1);
|
||
|
+ if (syspath == NULL)
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ memcpy (syspath, sys, syslen);
|
||
|
+ memcpy (syspath + syslen, devpath, devpathlen);
|
||
|
+ syspath[syslen + devpathlen] = '\0';
|
||
|
+ return syspath;
|
||
|
+}
|
||
|
+
|
||
|
+static char *
|
||
|
+device_id_from_devpath (const char *devpath,
|
||
|
+ struct device_id *id,
|
||
|
+ char *usbserial, size_t usbseriallen)
|
||
|
+{
|
||
|
+ struct udev *udev;
|
||
|
+ struct udev_device *dev, *parent_dev = NULL;
|
||
|
+ const char *idVendorStr, *idProductStr, *serial;
|
||
|
+ char *end;
|
||
|
+ unsigned long idVendor, idProduct;
|
||
|
+ struct usb_bus *bus;
|
||
|
+ struct usb_dev_handle *handle = NULL;
|
||
|
+ char ieee1284_id[1024];
|
||
|
+ const char *device_id = NULL;
|
||
|
+ char *syspath;
|
||
|
+ int conf = 0, iface = 0;
|
||
|
+ int got = 0;
|
||
|
+ char *usb_device_devpath;
|
||
|
+
|
||
|
+ id->full_device_id = id->mfg = id->mdl = id->sern = NULL;
|
||
|
+
|
||
|
+ udev = udev_new ();
|
||
|
+ if (udev == NULL)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "udev_new failed");
|
||
|
+ exit (1);
|
||
|
+ }
|
||
|
+
|
||
|
+ syspath = syspath_from_devpath (udev, devpath);
|
||
|
+ if (syspath == NULL)
|
||
|
+ {
|
||
|
+ udev_unref (udev);
|
||
|
+ exit (1);
|
||
|
+ }
|
||
|
+
|
||
|
+ dev = udev_device_new_from_syspath (udev, syspath);
|
||
|
+ if (dev == NULL)
|
||
|
+ {
|
||
|
+ udev_device_unref (dev);
|
||
|
+ udev_unref (udev);
|
||
|
+ syslog (LOG_ERR, "unable to access %s", syspath);
|
||
|
+ free (syspath);
|
||
|
+ exit (1);
|
||
|
+ }
|
||
|
+
|
||
|
+ free (syspath);
|
||
|
+ parent_dev = udev_device_get_parent_with_subsystem_devtype (dev,
|
||
|
+ "usb",
|
||
|
+ "usb_device");
|
||
|
+ if (!parent_dev)
|
||
|
+ {
|
||
|
+ udev_unref (udev);
|
||
|
+ syslog (LOG_ERR, "Failed to get parent");
|
||
|
+ exit (1);
|
||
|
+ }
|
||
|
+
|
||
|
+ usb_device_devpath = strdup (udev_device_get_devpath (parent_dev));
|
||
|
+ syslog (LOG_DEBUG, "parent devpath is %s", usb_device_devpath);
|
||
|
+
|
||
|
+ serial = udev_device_get_sysattr_value (parent_dev, "serial");
|
||
|
+ if (serial)
|
||
|
+ {
|
||
|
+ strncpy (usbserial, serial, usbseriallen);
|
||
|
+ usbserial[usbseriallen - 1] = '\0';
|
||
|
+ }
|
||
|
+ else
|
||
|
+ usbserial[0] = '\0';
|
||
|
+
|
||
|
+ /* See if we were triggered by a usblp add event. */
|
||
|
+ device_id = udev_device_get_sysattr_value (dev, "device/ieee1284_id");
|
||
|
+ if (device_id)
|
||
|
+ {
|
||
|
+ got = 1;
|
||
|
+ goto got_deviceid;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* This is a low-level USB device. Use libusb to fetch the Device ID. */
|
||
|
+ idVendorStr = udev_device_get_sysattr_value (parent_dev, "idVendor");
|
||
|
+ idProductStr = udev_device_get_sysattr_value (parent_dev, "idProduct");
|
||
|
+
|
||
|
+ if (!idVendorStr || !idProductStr)
|
||
|
+ {
|
||
|
+ udev_device_unref (dev);
|
||
|
+ udev_unref (udev);
|
||
|
+ syslog (LOG_ERR, "Missing sysattr %s",
|
||
|
+ idVendorStr ?
|
||
|
+ (idProductStr ? "serial" : "idProduct") : "idVendor");
|
||
|
+ exit (1);
|
||
|
+ }
|
||
|
+
|
||
|
+ idVendor = strtoul (idVendorStr, &end, 16);
|
||
|
+ if (end == idVendorStr)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "Invalid idVendor: %s", idVendorStr);
|
||
|
+ exit (1);
|
||
|
+ }
|
||
|
+
|
||
|
+ idProduct = strtoul (idProductStr, &end, 16);
|
||
|
+ if (end == idProductStr)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "Invalid idProduct: %s", idProductStr);
|
||
|
+ exit (1);
|
||
|
+ }
|
||
|
+
|
||
|
+ syslog (LOG_DEBUG, "Device vendor/product is %04zX:%04zX",
|
||
|
+ idVendor, idProduct);
|
||
|
+
|
||
|
+ usb_init ();
|
||
|
+ usb_find_busses ();
|
||
|
+ usb_find_devices ();
|
||
|
+ for (bus = usb_get_busses (); bus && !got; bus = bus->next)
|
||
|
+ {
|
||
|
+ struct usb_device *device;
|
||
|
+ for (device = bus->devices; device && !got; device = device->next)
|
||
|
+ {
|
||
|
+ struct usb_config_descriptor *confptr;
|
||
|
+ if (device->descriptor.idVendor != idVendor ||
|
||
|
+ device->descriptor.idProduct != idProduct ||
|
||
|
+ !device->config)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ conf = 0;
|
||
|
+ for (confptr = device->config;
|
||
|
+ conf < device->descriptor.bNumConfigurations && !got;
|
||
|
+ conf++, confptr++)
|
||
|
+ {
|
||
|
+ struct usb_interface *ifaceptr;
|
||
|
+ iface = 0;
|
||
|
+ for (ifaceptr = confptr->interface;
|
||
|
+ iface < confptr->bNumInterfaces && !got;
|
||
|
+ iface++, ifaceptr++)
|
||
|
+ {
|
||
|
+ struct usb_interface_descriptor *altptr;
|
||
|
+ int altset = 0;
|
||
|
+ for (altptr = ifaceptr->altsetting;
|
||
|
+ altset < ifaceptr->num_altsetting && !got;
|
||
|
+ altset++, altptr++)
|
||
|
+ {
|
||
|
+ if (altptr->bInterfaceClass == USB_CLASS_PRINTER &&
|
||
|
+ altptr->bInterfaceSubClass == 1)
|
||
|
+ {
|
||
|
+ int n;
|
||
|
+ handle = usb_open (device);
|
||
|
+ if (!handle)
|
||
|
+ {
|
||
|
+ syslog (LOG_DEBUG, "failed to open device");
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ n = altptr->bInterfaceNumber;
|
||
|
+ if (usb_claim_interface (handle, n) < 0)
|
||
|
+ {
|
||
|
+ usb_close (handle);
|
||
|
+ handle = NULL;
|
||
|
+ syslog (LOG_DEBUG, "failed to claim interface");
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (n != 0 && usb_claim_interface (handle, 0) < 0)
|
||
|
+ {
|
||
|
+ usb_close (handle);
|
||
|
+ handle = NULL;
|
||
|
+ syslog (LOG_DEBUG, "failed to claim interface 0");
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ n = altptr->bAlternateSetting;
|
||
|
+ if (usb_set_altinterface (handle, n) < 0)
|
||
|
+ {
|
||
|
+ usb_close (handle);
|
||
|
+ handle = NULL;
|
||
|
+ syslog (LOG_DEBUG, "failed set altinterface");
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ memset (ieee1284_id, '\0', sizeof (ieee1284_id));
|
||
|
+ if (usb_control_msg (handle,
|
||
|
+ USB_TYPE_CLASS |
|
||
|
+ USB_ENDPOINT_IN |
|
||
|
+ USB_RECIP_INTERFACE,
|
||
|
+ 0, conf, iface,
|
||
|
+ ieee1284_id,
|
||
|
+ sizeof (ieee1284_id),
|
||
|
+ 5000) < 0)
|
||
|
+ {
|
||
|
+ usb_close (handle);
|
||
|
+ handle = NULL;
|
||
|
+ syslog (LOG_ERR, "Failed to fetch Device ID");
|
||
|
+ continue;
|
||
|
+ }
|
||
|
+
|
||
|
+ got = 1;
|
||
|
+ usb_close (handle);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ got_deviceid:
|
||
|
+ if (got)
|
||
|
+ {
|
||
|
+ if (!device_id)
|
||
|
+ device_id = ieee1284_id + 2;
|
||
|
+ parse_device_id (device_id, id);
|
||
|
+ }
|
||
|
+
|
||
|
+ udev_device_unref (dev);
|
||
|
+ udev_unref (udev);
|
||
|
+ return usb_device_devpath;
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+do_add (DBusGProxy *proxy, const char *devpath)
|
||
|
+{
|
||
|
+ GError *error = NULL;
|
||
|
+ struct device_id id;
|
||
|
+ char *usb_device_devpath;
|
||
|
+ char usbserial[256];
|
||
|
+
|
||
|
+ syslog (LOG_DEBUG, "add %s", devpath);
|
||
|
+
|
||
|
+ usb_device_devpath = device_id_from_devpath (devpath, &id,
|
||
|
+ usbserial, sizeof (usbserial));
|
||
|
+
|
||
|
+ if (!id.mfg || !id.mdl)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "invalid or missing IEEE 1284 Device ID%s%s",
|
||
|
+ id.full_device_id ? " " : "",
|
||
|
+ id.full_device_id ? id.full_device_id : "");
|
||
|
+ exit (1);
|
||
|
+ }
|
||
|
+
|
||
|
+ syslog (LOG_DEBUG, "MFG:%s MDL:%s SERN:%s serial:%s", id.mfg, id.mdl,
|
||
|
+ id.sern ? id.sern : "-", usbserial);
|
||
|
+
|
||
|
+ com_redhat_PrinterConfig_usb_printer_add (proxy,
|
||
|
+ usb_device_devpath,
|
||
|
+ id.full_device_id,
|
||
|
+ &error);
|
||
|
+ free (usb_device_devpath);
|
||
|
+ free_device_id (&id);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+do_remove (DBusGProxy *proxy, const char *devpath)
|
||
|
+{
|
||
|
+ GError *error = NULL;
|
||
|
+ syslog (LOG_DEBUG, "remove %s", devpath);
|
||
|
+
|
||
|
+ com_redhat_PrinterConfig_usb_printer_remove (proxy,
|
||
|
+ devpath,
|
||
|
+ &error);
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+main (int argc, char **argv)
|
||
|
+{
|
||
|
+ DBusGConnection *connection;
|
||
|
+ DBusGProxy *proxy;
|
||
|
+ GError *error = NULL;
|
||
|
+ int add;
|
||
|
+
|
||
|
+ g_type_init ();
|
||
|
+
|
||
|
+ if (argc != 3 ||
|
||
|
+ !((add = !strcmp (argv[1], "add")) ||
|
||
|
+ !strcmp (argv[1], "remove")))
|
||
|
+ {
|
||
|
+ fprintf (stderr,
|
||
|
+ "Syntax: %s add {USB device path}\n"
|
||
|
+ " %s remove {USB device path}\n",
|
||
|
+ argv[0], argv[0]);
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ openlog ("udev-usb-printer", 0, LOG_LPR);
|
||
|
+
|
||
|
+ connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
|
||
|
+ if (connection == NULL)
|
||
|
+ {
|
||
|
+ syslog (LOG_ERR, "unable to connect to D-Bus: %s", error->message);
|
||
|
+ g_error_free (error);
|
||
|
+ exit (1);
|
||
|
+ }
|
||
|
+
|
||
|
+ proxy = dbus_g_proxy_new_for_name (connection,
|
||
|
+ "com.redhat.PrinterConfig",
|
||
|
+ "/com/redhat/PrinterConfig",
|
||
|
+ "com.redhat.PrinterConfig");
|
||
|
+
|
||
|
+ if (add)
|
||
|
+ do_add (proxy, argv[2]);
|
||
|
+ else
|
||
|
+ do_remove (proxy, argv[2]);
|
||
|
+
|
||
|
+ g_object_unref (proxy);
|
||
|
+ return 0;
|
||
|
+}
|