Merge rpm-4.0.4 changes.
authorjbj <devnull@localhost>
Wed, 1 Jan 1997 01:30:08 +0000 (01:30 +0000)
committerjbj <devnull@localhost>
Wed, 1 Jan 1997 01:30:08 +0000 (01:30 +0000)
CVS patchset: 1256
CVS date: 1997/01/01 01:30:08

python/Makefile.am [new file with mode: 0644]
python/Makefile.in [new file with mode: 0644]
python/db-py.c [new file with mode: 0644]
python/db-py.h [new file with mode: 0644]
python/header-py.c [new file with mode: 0644]
python/header-py.h [new file with mode: 0644]
python/rpmmodule.c [new file with mode: 0644]

diff --git a/python/Makefile.am b/python/Makefile.am
new file mode 100644 (file)
index 0000000..45c82d3
--- /dev/null
@@ -0,0 +1,47 @@
+# Makefile for rpm library.
+
+AUTOMAKE_OPTIONS = 1.4 foreign
+
+PYVER= @WITH_PYTHON_VERSION@
+
+INCLUDES = \
+       -I$(top_srcdir) \
+       -I$(top_srcdir)/lib \
+       -I$(top_srcdir)/rpmdb \
+       -I$(top_srcdir)/rpmio \
+       -I$(top_srcdir)/beecrypt \
+       -I$(top_srcdir)/popt \
+       -I/usr/include/python${PYVER} \
+       @INCPATH@
+
+EXTRA_DIST = db-py.h hash.h header-py.h upgrade.h
+
+mylibs= \
+       $(top_builddir)/lib/librpm.la \
+       $(top_builddir)/rpmdb/librpmdb.la \
+       $(top_builddir)/rpmio/librpmio.la \
+       $(top_builddir)/popt/libpopt.la
+
+LDADD =
+
+pythondir = $(prefix)/lib/python${PYVER}/site-packages
+python_PROGRAMS = rpmmodule.so poptmodule.so
+
+rpmmodule_so_SOURCES =
+rpmmodule_so_LDFLAGS = $(mylibs) $(LIBS) -shared -Wl,-soname,rpmmodule.so
+
+poptmodule_so_SOURCES = poptmodule.c
+poptmodule_so_LDFLAGS = $(mylibs) $(LIBS) -shared -Wl,-soname,poptmodule.so
+
+noinst_LTLIBRARIES = librpmmodule.la
+librpmmodule_la_SOURCES = rpmmodule.c hash.c upgrade.c header-py.c db-py.c
+
+rpmmodule.so$(EXEEXT): $(librpmmodule_la_OBJECTS)
+       $(LINK) -o $@ $(librpmmodule_la_OBJECTS) $(rpmmodule_so_LDFLAGS)
+
+poptmodule.so$(EXEEXT): $(poptmodule_so_OBJECTS)
+       $(LINK) -o $@ $(poptmodule_so_OBJECTS) $(poptmodule_so_LDFLAGS)
+
+.PHONY:        lclint
+lclint:
+       lclint $(DEFS) $(INCLUDES) $(librpmmodule_la_SOURCES)
diff --git a/python/Makefile.in b/python/Makefile.in
new file mode 100644 (file)
index 0000000..e762016
--- /dev/null
@@ -0,0 +1,509 @@
+# Makefile.in generated automatically by automake 1.5 from Makefile.am.
+
+# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001
+# Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+# Makefile for rpm library.
+
+SHELL = @SHELL@
+
+srcdir = @srcdir@
+top_srcdir = @top_srcdir@
+VPATH = @srcdir@
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+
+bindir = @bindir@
+sbindir = @sbindir@
+libexecdir = @libexecdir@
+datadir = @datadir@
+sysconfdir = @sysconfdir@
+sharedstatedir = @sharedstatedir@
+localstatedir = @localstatedir@
+libdir = @libdir@
+infodir = @infodir@
+mandir = @mandir@
+includedir = @includedir@
+oldincludedir = /usr/include
+pkgdatadir = $(datadir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+top_builddir = ..
+
+ACLOCAL = @ACLOCAL@
+AUTOCONF = @AUTOCONF@
+AUTOMAKE = @AUTOMAKE@
+AUTOHEADER = @AUTOHEADER@
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = @program_transform_name@
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_alias = @build_alias@
+build_triplet = @build@
+host_alias = @host_alias@
+host_triplet = @host@
+target_alias = @target_alias@
+target_triplet = @target@
+AMTAR = @AMTAR@
+AR = @AR@
+AS = @AS@
+AWK = @AWK@
+BUILD_INCLUDED_LIBINTL = @BUILD_INCLUDED_LIBINTL@
+BUILD_RPMNLSTOOLS = @BUILD_RPMNLSTOOLS@
+BZIP2BIN = @BZIP2BIN@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CPP = @CPP@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
+CXX = @CXX@
+DATADIRNAME = @DATADIRNAME@
+DBLIBOBJS = @DBLIBOBJS@
+DBLIBSRCS = @DBLIBSRCS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+ECHO = @ECHO@
+EXEEXT = @EXEEXT@
+FINDPROVIDES = @FINDPROVIDES@
+FINDREQUIRES = @FINDREQUIRES@
+FIXPERMS = @FIXPERMS@
+GENCAT = @GENCAT@
+GLIBC21 = @GLIBC21@
+GMSGFMT = @GMSGFMT@
+GZIPBIN = @GZIPBIN@
+HAVE_LIB = @HAVE_LIB@
+INCPATH = @INCPATH@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLBISON = @INTLBISON@
+INTLLIBS = @INTLLIBS@
+INTLOBJS = @INTLOBJS@
+INTL_LIBTOOL_SUFFIX_PREFIX = @INTL_LIBTOOL_SUFFIX_PREFIX@
+LDFLAGS_STATIC = @LDFLAGS_STATIC@
+LIB = @LIB@
+LIBDIR = @LIBDIR@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBMISC = @LIBMISC@
+LIBOBJS = @LIBOBJS@
+LIBRPMALIAS_FILENAME = @LIBRPMALIAS_FILENAME@
+LIBRPMRC_FILENAME = @LIBRPMRC_FILENAME@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LN_S = @LN_S@
+LOCALEDIR = @LOCALEDIR@
+LTLIB = @LTLIB@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+MACROFILES = @MACROFILES@
+MKDIR = @MKDIR@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PGPBIN = @PGPBIN@
+POSUB = @POSUB@
+RANLIB = @RANLIB@
+ROOT_GROUP = @ROOT_GROUP@
+RPM = @RPM@
+RPMCANONARCH = @RPMCANONARCH@
+RPMCANONOS = @RPMCANONOS@
+RPMCANONVENDOR = @RPMCANONVENDOR@
+RPMCONFIGDIR = @RPMCONFIGDIR@
+RPMGID = @RPMGID@
+RPMGROUP = @RPMGROUP@
+RPMUID = @RPMUID@
+RPMUSER = @RPMUSER@
+STRIP = @STRIP@
+SYSCONFIGDIR = @SYSCONFIGDIR@
+U = @U@
+UNZIPBIN = @UNZIPBIN@
+USE_INCLUDED_LIBINTL = @USE_INCLUDED_LIBINTL@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WITH_APIDOCS = @WITH_APIDOCS@
+WITH_APIDOCS_TARGET = @WITH_APIDOCS_TARGET@
+WITH_BZIP2 = @WITH_BZIP2@
+WITH_DB_SUBDIR = @WITH_DB_SUBDIR@
+WITH_INTERNAL_DB = @WITH_INTERNAL_DB@
+WITH_PYTHON_SUBDIR = @WITH_PYTHON_SUBDIR@
+WITH_PYTHON_SUBPACKAGE = @WITH_PYTHON_SUBPACKAGE@
+WITH_PYTHON_VERSION = @WITH_PYTHON_VERSION@
+WITH_ZLIB_INCLUDE = @WITH_ZLIB_INCLUDE@
+WITH_ZLIB_LIB = @WITH_ZLIB_LIB@
+WITH_ZLIB_SUBDIR = @WITH_ZLIB_SUBDIR@
+__CAT = @__CAT@
+__CHGRP = @__CHGRP@
+__CHGRP_RHF = @__CHGRP_RHF@
+__CHMOD = @__CHMOD@
+__CHOWN = @__CHOWN@
+__CHOWN_RHF = @__CHOWN_RHF@
+__CP = @__CP@
+__CPIO = @__CPIO@
+__DOXYGEN = @__DOXYGEN@
+__FILE = @__FILE@
+__GPG = @__GPG@
+__GREP = @__GREP@
+__ID = @__ID@
+__ID_U = @__ID_U@
+__INSTALL = @__INSTALL@
+__LD = @__LD@
+__MAKE = @__MAKE@
+__MKDIR = @__MKDIR@
+__MV = @__MV@
+__NM = @__NM@
+__OBJCOPY = @__OBJCOPY@
+__OBJDUMP = @__OBJDUMP@
+__PATCH = @__PATCH@
+__PERL = @__PERL@
+__PYTHON = @__PYTHON@
+__RM = @__RM@
+__RSH = @__RSH@
+__SED = @__SED@
+__SSH = @__SSH@
+__STRIP = @__STRIP@
+__TAR = @__TAR@
+am__include = @am__include@
+am__quote = @am__quote@
+install_sh = @install_sh@
+libdb3 = @libdb3@
+libdb3a = @libdb3a@
+testdir = @testdir@
+tmpdir = @tmpdir@
+varprefix = @varprefix@
+
+AUTOMAKE_OPTIONS = 1.4 foreign
+
+PYVER = @WITH_PYTHON_VERSION@
+
+INCLUDES = \
+       -I$(top_srcdir) \
+       -I$(top_srcdir)/lib \
+       -I$(top_srcdir)/rpmdb \
+       -I$(top_srcdir)/rpmio \
+       -I$(top_srcdir)/beecrypt \
+       -I$(top_srcdir)/popt \
+       -I/usr/include/python${PYVER} \
+       @INCPATH@
+
+
+EXTRA_DIST = db-py.h hash.h header-py.h upgrade.h
+
+mylibs = \
+       $(top_builddir)/lib/librpm.la \
+       $(top_builddir)/rpmdb/librpmdb.la \
+       $(top_builddir)/rpmio/librpmio.la \
+       $(top_builddir)/popt/libpopt.la
+
+
+LDADD = 
+
+pythondir = $(prefix)/lib/python${PYVER}/site-packages
+python_PROGRAMS = rpmmodule.so poptmodule.so
+
+rpmmodule_so_SOURCES = 
+rpmmodule_so_LDFLAGS = $(mylibs) $(LIBS) -shared -Wl,-soname,rpmmodule.so
+
+poptmodule_so_SOURCES = poptmodule.c
+poptmodule_so_LDFLAGS = $(mylibs) $(LIBS) -shared -Wl,-soname,poptmodule.so
+
+noinst_LTLIBRARIES = librpmmodule.la
+librpmmodule_la_SOURCES = rpmmodule.c hash.c upgrade.c header-py.c db-py.c
+subdir = python
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+
+librpmmodule_la_LDFLAGS =
+librpmmodule_la_LIBADD =
+am_librpmmodule_la_OBJECTS = rpmmodule.lo hash.lo upgrade.lo \
+       header-py.lo db-py.lo
+librpmmodule_la_OBJECTS = $(am_librpmmodule_la_OBJECTS)
+python_PROGRAMS = rpmmodule.so$(EXEEXT) poptmodule.so$(EXEEXT)
+PROGRAMS = $(python_PROGRAMS)
+
+am_poptmodule_so_OBJECTS = poptmodule.$(OBJEXT)
+poptmodule_so_OBJECTS = $(am_poptmodule_so_OBJECTS)
+poptmodule_so_LDADD = $(LDADD)
+poptmodule_so_DEPENDENCIES =
+am_rpmmodule_so_OBJECTS =
+rpmmodule_so_OBJECTS = $(am_rpmmodule_so_OBJECTS)
+rpmmodule_so_LDADD = $(LDADD)
+rpmmodule_so_DEPENDENCIES =
+
+DEFS = @DEFS@
+DEFAULT_INCLUDES =  -I. -I$(srcdir) -I$(top_builddir)
+CPPFLAGS = @CPPFLAGS@
+LDFLAGS = @LDFLAGS@
+LIBS = @LIBS@
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+@AMDEP_TRUE@DEP_FILES = $(DEPDIR)/db-py.Plo $(DEPDIR)/hash.Plo \
+@AMDEP_TRUE@   $(DEPDIR)/header-py.Plo $(DEPDIR)/poptmodule.Po \
+@AMDEP_TRUE@   $(DEPDIR)/rpmmodule.Plo $(DEPDIR)/upgrade.Plo
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+       $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \
+       $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+CCLD = $(CC)
+LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(AM_LDFLAGS) $(LDFLAGS) -o $@
+CFLAGS = @CFLAGS@
+DIST_SOURCES = $(librpmmodule_la_SOURCES) $(poptmodule_so_SOURCES) \
+       $(rpmmodule_so_SOURCES)
+DIST_COMMON = ChangeLog Makefile.am Makefile.in
+SOURCES = $(librpmmodule_la_SOURCES) $(poptmodule_so_SOURCES) $(rpmmodule_so_SOURCES)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+
+mostlyclean-libtool:
+       -rm -f *.lo
+
+clean-libtool:
+       -rm -rf .libs _libs
+
+distclean-libtool:
+       -rm -f libtool
+$(srcdir)/Makefile.in:  Makefile.am  $(top_srcdir)/configure.in $(ACLOCAL_M4)
+       cd $(top_srcdir) && \
+         $(AUTOMAKE) --foreign  python/Makefile
+Makefile:  $(srcdir)/Makefile.in  $(top_builddir)/config.status
+       cd $(top_builddir) && \
+         CONFIG_HEADERS= CONFIG_LINKS= \
+         CONFIG_FILES=$(subdir)/$@ $(SHELL) ./config.status
+
+clean-noinstLTLIBRARIES:
+       -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+librpmmodule.la: $(librpmmodule_la_OBJECTS) $(librpmmodule_la_DEPENDENCIES) 
+       $(LINK)  $(librpmmodule_la_LDFLAGS) $(librpmmodule_la_OBJECTS) $(librpmmodule_la_LIBADD) $(LIBS)
+install-pythonPROGRAMS: $(python_PROGRAMS)
+       @$(NORMAL_INSTALL)
+       $(mkinstalldirs) $(DESTDIR)$(pythondir)
+       @list='$(python_PROGRAMS)'; for p in $$list; do \
+         p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
+         if test -f $$p \
+            || test -f $$p1 \
+         ; then \
+           f=`echo $$p1|sed '$(transform);s/$$/$(EXEEXT)/'`; \
+          echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pythondir)/$$f"; \
+          $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(INSTALL_PROGRAM) $$p $(DESTDIR)$(pythondir)/$$f; \
+         else :; fi; \
+       done
+
+uninstall-pythonPROGRAMS:
+       @$(NORMAL_UNINSTALL)
+       @list='$(python_PROGRAMS)'; for p in $$list; do \
+         f=`echo $$p|sed 's/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
+         echo " rm -f $(DESTDIR)$(pythondir)/$$f"; \
+         rm -f $(DESTDIR)$(pythondir)/$$f; \
+       done
+
+clean-pythonPROGRAMS:
+       -test -z "$(python_PROGRAMS)" || rm -f $(python_PROGRAMS)
+
+mostlyclean-compile:
+       -rm -f *.$(OBJEXT) core *.core
+
+distclean-compile:
+       -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/db-py.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/hash.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/header-py.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/poptmodule.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/rpmmodule.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@$(DEPDIR)/upgrade.Plo@am__quote@
+
+distclean-depend:
+       -rm -rf $(DEPDIR)
+
+.c.o:
+@AMDEP_TRUE@   source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@   depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@   $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+       $(COMPILE) -c `test -f $< || echo '$(srcdir)/'`$<
+
+.c.obj:
+@AMDEP_TRUE@   source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@   depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@   $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+       $(COMPILE) -c `cygpath -w $<`
+
+.c.lo:
+@AMDEP_TRUE@   source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@   depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@
+@AMDEP_TRUE@   $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+       $(LTCOMPILE) -c -o $@ `test -f $< || echo '$(srcdir)/'`$<
+CCDEPMODE = @CCDEPMODE@
+uninstall-info-am:
+
+tags: TAGS
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+       list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       mkid -fID $$unique $(LISP)
+
+TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
+               $(TAGS_FILES) $(LISP)
+       tags=; \
+       here=`pwd`; \
+       list='$(SOURCES) $(HEADERS) $(TAGS_FILES)'; \
+       unique=`for i in $$list; do \
+           if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+         done | \
+         $(AWK) '    { files[$$0] = 1; } \
+              END { for (i in files) print i; }'`; \
+       test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \
+         || etags $(ETAGS_ARGS) $$tags  $$unique $(LISP)
+
+GTAGS:
+       here=`CDPATH=: && cd $(top_builddir) && pwd` \
+         && cd $(top_srcdir) \
+         && gtags -i $(GTAGS_ARGS) $$here
+
+distclean-tags:
+       -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH
+
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+
+top_distdir = ..
+distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
+
+distdir: $(DISTFILES)
+       @for file in $(DISTFILES); do \
+         if test -f $$file; then d=.; else d=$(srcdir); fi; \
+         dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
+         if test "$$dir" != "$$file" && test "$$dir" != "."; then \
+           $(mkinstalldirs) "$(distdir)/$$dir"; \
+         fi; \
+         if test -d $$d/$$file; then \
+           cp -pR $$d/$$file $(distdir) \
+           || exit 1; \
+         else \
+           test -f $(distdir)/$$file \
+           || cp -p $$d/$$file $(distdir)/$$file \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS)
+
+installdirs:
+       $(mkinstalldirs) $(DESTDIR)$(pythondir)
+
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+         `test -z '$(STRIP)' || \
+           echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+       -rm -f Makefile $(CONFIG_CLEAN_FILES) stamp-h stamp-h[0-9]*
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+       clean-pythonPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+
+distclean-am: clean-am distclean-compile distclean-depend \
+       distclean-generic distclean-libtool distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pythonPROGRAMS
+
+install-exec-am:
+
+install-info: install-info-am
+
+install-man:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+       mostlyclean-libtool
+
+uninstall-am: uninstall-info-am uninstall-pythonPROGRAMS
+
+.PHONY: GTAGS all all-am check check-am clean clean-generic \
+       clean-libtool clean-noinstLTLIBRARIES clean-pythonPROGRAMS \
+       distclean distclean-compile distclean-depend distclean-generic \
+       distclean-libtool distclean-tags distdir dvi dvi-am info \
+       info-am install install-am install-data install-data-am \
+       install-exec install-exec-am install-info install-info-am \
+       install-man install-pythonPROGRAMS install-strip installcheck \
+       installcheck-am installdirs maintainer-clean \
+       maintainer-clean-generic mostlyclean mostlyclean-compile \
+       mostlyclean-generic mostlyclean-libtool tags uninstall \
+       uninstall-am uninstall-info-am uninstall-pythonPROGRAMS
+
+
+rpmmodule.so$(EXEEXT): $(librpmmodule_la_OBJECTS)
+       $(LINK) -o $@ $(librpmmodule_la_OBJECTS) $(rpmmodule_so_LDFLAGS)
+
+poptmodule.so$(EXEEXT): $(poptmodule_so_OBJECTS)
+       $(LINK) -o $@ $(poptmodule_so_OBJECTS) $(poptmodule_so_LDFLAGS)
+
+.PHONY:        lclint
+lclint:
+       lclint $(DEFS) $(INCLUDES) $(librpmmodule_la_SOURCES)
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/python/db-py.c b/python/db-py.c
new file mode 100644 (file)
index 0000000..74aeb9b
--- /dev/null
@@ -0,0 +1,499 @@
+/** \ingroup python
+ * \file python/db-py.c
+ */
+
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "Python.h"
+#include "rpmio_internal.h"
+#include "rpmcli.h"    /* XXX for rpmCheckSig */
+#include "misc.h"
+#include "header_internal.h"
+#include "upgrade.h"
+
+#include "db-py.h"
+#include "header-py.h"
+
+/** \ingroup python
+ */
+typedef struct rpmdbMIObject_s rpmdbMIObject;
+
+/** \ingroup python
+ * \class rpmdbMatchIterator
+ * \brief A python rpmdbMatchIterator object represents the result of an RPM
+ *     database query.
+ */
+
+/** \ingroup python
+ * \name Class: rpmdbMatchIterator
+ */
+/*@{*/
+
+/** \ingroup python
+ */
+struct rpmdbMIObject_s {
+    PyObject_HEAD;
+    rpmdbObject *db;
+    rpmdbMatchIterator mi;
+} ;
+
+/** \ingroup python
+ */
+static PyObject *
+rpmdbMINext(rpmdbMIObject * s, PyObject * args) {
+    /* XXX assume header? */
+    Header h;
+    hdrObject * ho;
+    
+    if (!PyArg_ParseTuple (args, "")) return NULL;
+
+    h = rpmdbNextIterator(s->mi);
+    if (!h) {
+       Py_INCREF(Py_None);
+       return Py_None;
+    }
+
+    ho = createHeaderObject(h);
+    
+    return (PyObject *) ho;
+}
+
+/** \ingroup python
+ */
+static PyObject *
+rpmdbMIpattern(rpmdbMIObject * s, PyObject * args) {
+    PyObject *index = NULL;
+    int type;
+    char * pattern;
+    int tag;
+    
+    if (!PyArg_ParseTuple(args, "Ois", &index, &type, &pattern))
+       return NULL;
+
+    if (index == NULL)
+       tag = 0;
+    else if ((tag = tagNumFromPyObject (index)) == -1) {
+       PyErr_SetString(PyExc_TypeError, "unknown tag type");
+       return NULL;
+    }
+
+    rpmdbSetIteratorRE(s->mi, tag, type, pattern);
+
+    Py_INCREF (Py_None);
+    return Py_None;
+    
+}
+
+/** \ingroup python
+ */
+static struct PyMethodDef rpmdbMIMethods[] = {
+       {"next",            (PyCFunction) rpmdbMINext,  1 },
+       {"pattern",         (PyCFunction) rpmdbMIpattern, 1 },
+       {NULL,          NULL}           /* sentinel */
+};
+
+/** \ingroup python
+ */
+static PyObject * rpmdbMIGetAttr (rpmdbObject *s, char *name) {
+    return Py_FindMethod (rpmdbMIMethods, (PyObject *) s, name);
+}
+
+/** \ingroup python
+ */
+static void rpmdbMIDealloc(rpmdbMIObject * s) {
+    if (s && s->mi) {
+       rpmdbFreeIterator(s->mi);
+    }
+    Py_DECREF (s->db);
+    PyMem_DEL(s);
+}
+
+/** \ingroup python
+ */
+PyTypeObject rpmdbMIType = {
+       PyObject_HEAD_INIT(NULL)
+       0,                              /* ob_size */
+       "rpmdbMatchIterator",           /* tp_name */
+       sizeof(rpmdbMIObject),  /* tp_size */
+       0,                              /* tp_itemsize */
+       (destructor) rpmdbMIDealloc,    /* tp_dealloc */
+       0,                              /* tp_print */
+       (getattrfunc) rpmdbMIGetAttr,   /* tp_getattr */
+       0,                              /* tp_setattr */
+       0,                              /* tp_compare */
+       0,                              /* tp_repr */
+       0,                              /* tp_as_number */
+       0,                              /* tp_as_sequence */
+       0,                              /* tp_as_mapping */
+};
+
+/*@}*/
+
+/** \ingroup python
+ * \class rpmdb
+ * \brief A python rpmdb object represents an RPM database.
+ * 
+ * Instances of the rpmdb object provide access to the records of a
+ * RPM database.  The records are accessed by index number.  To
+ * retrieve the header data in the RPM database, the rpmdb object is
+ * subscripted as you would access members of a list.
+ * 
+ * The rpmdb class contains the following methods:
+ * 
+ * - firstkey()        Returns the index of the first record in the database.
+ * @deprecated Legacy, use rpmdbMatchIterator instead.
+ * 
+ * - nextkey(index) Returns the index of the next record after "index" in the
+ *             database.
+ * @param index        current rpmdb location
+ * @deprecated Legacy, use rpmdbMatchIterator instead.
+ * 
+ * - findbyfile(file) Returns a list of the indexes to records that own file
+ *             "file".
+ * @param file absolute path to file
+ * 
+ * - findbyname(name) Returns a list of the indexes to records for packages
+ *             named "name".
+ * @param name package name
+ * 
+ * - findbyprovides(dep) Returns a list of the indexes to records for packages
+ *             that provide "dep".
+ * @param dep  provided dependency string
+ * 
+ * To obtain a rpmdb object, the opendb function in the rpm module
+ * must be called.  The opendb function takes two optional arguments.
+ * The first optional argument is a boolean flag that specifies if the
+ * database is to be opened for read/write access or read-only access.
+ * The second argument specifies an alternate root directory for RPM
+ * to use.
+ * 
+ * An example of opening a database and retrieving the first header in
+ * the database, then printing the name of the package that the header
+ * represents:
+ * \code
+ *     import rpm
+ *     rpmdb = rpm.opendb()
+ *     index = rpmdb.firstkey()
+ *     header = rpmdb[index]
+ *     print header[rpm.RPMTAG_NAME]
+ * \endcode
+ * To print all of the packages in the database that match a package
+ * name, the code will look like this:
+ * \code
+ *     import rpm
+ *     rpmdb = rpm.opendb()
+ *     indexes = rpmdb.findbyname("foo")
+ *     for index in indexes:
+ *         header = rpmdb[index]
+ *         print "%s-%s-%s" % (header[rpm.RPMTAG_NAME],
+ *                             header[rpm.RPMTAG_VERSION],
+ *                             header[rpm.RPMTAG_RELEASE])
+ * \endcode
+ */
+
+/** \ingroup python
+ * \name Class: rpmdb
+ */
+/*@{*/
+
+/**
+ */
+static PyObject * rpmdbFirst(rpmdbObject * s, PyObject * args) {
+    int first;
+
+    if (!PyArg_ParseTuple (args, "")) return NULL;
+
+    /* Acquire all offsets in one fell swoop. */
+    if (s->offsets == NULL || s->noffs <= 0) {
+       rpmdbMatchIterator mi;
+       Header h;
+
+       if (s->offsets)
+           free(s->offsets);
+       s->offsets = NULL;
+       s->noffs = 0;
+       mi = rpmdbInitIterator(s->db, RPMDBI_PACKAGES, NULL, 0);
+       while ((h = rpmdbNextIterator(mi)) != NULL) {
+           s->noffs++;
+           s->offsets = realloc(s->offsets, s->noffs * sizeof(s->offsets[0]));
+           s->offsets[s->noffs-1] = rpmdbGetIteratorOffset(mi);
+       }
+       rpmdbFreeIterator(mi);
+    }
+
+    s->offx = 0;
+    if (s->offsets != NULL && s->offx < s->noffs)
+       first = s->offsets[s->offx++];
+    else
+       first = 0;
+
+    if (!first) {
+       PyErr_SetString(pyrpmError, "cannot find first entry in database\n");
+       return NULL;
+    }
+
+    return Py_BuildValue("i", first);
+}
+
+/**
+ */
+static PyObject * rpmdbNext(rpmdbObject * s, PyObject * args) {
+    int where;
+
+    if (!PyArg_ParseTuple (args, "i", &where)) return NULL;
+
+    if (s->offsets == NULL || s->offx >= s->noffs) {
+       Py_INCREF(Py_None);
+       return Py_None;
+    }
+
+    where = s->offsets[s->offx++];
+
+    if (!where) {
+       Py_INCREF(Py_None);
+       return Py_None;
+    }
+
+    return Py_BuildValue("i", where);
+}
+
+/**
+ */
+static PyObject * handleDbResult(rpmdbMatchIterator mi) {
+    PyObject * list, *o;
+
+    list = PyList_New(0);
+
+    /* XXX FIXME: unnecessary header mallocs are side effect here */
+    if (mi != NULL) {
+       while (rpmdbNextIterator(mi)) {
+           PyList_Append(list, o=PyInt_FromLong(rpmdbGetIteratorOffset(mi)));
+           Py_DECREF(o);
+       }
+       rpmdbFreeIterator(mi);
+    }
+
+    return list;
+}
+
+/**
+ */
+static PyObject * rpmdbByFile(rpmdbObject * s, PyObject * args) {
+    char * str;
+
+    if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
+
+    return handleDbResult(rpmdbInitIterator(s->db, RPMTAG_BASENAMES, str, 0));
+}
+
+/**
+ */
+static PyObject * rpmdbByName(rpmdbObject * s, PyObject * args) {
+    char * str;
+
+    if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
+
+    return handleDbResult(rpmdbInitIterator(s->db, RPMTAG_NAME, str, 0));
+}
+
+/**
+ */
+static PyObject * rpmdbByProvides(rpmdbObject * s, PyObject * args) {
+    char * str;
+
+    if (!PyArg_ParseTuple(args, "s", &str)) return NULL;
+
+    return handleDbResult(rpmdbInitIterator(s->db, RPMTAG_PROVIDENAME, str, 0));
+}
+
+/**
+ */
+static rpmdbMIObject *
+py_rpmdbInitIterator (rpmdbObject * s, PyObject * args) {
+    PyObject *index = NULL;
+    char *key = NULL;
+    int len = 0, tag = -1;
+    rpmdbMIObject * mio;
+    
+    if (!PyArg_ParseTuple(args, "|Ozi", &index, &key, &len))
+       return NULL;
+
+    if (index == NULL)
+       tag = 0;
+    else if ((tag = tagNumFromPyObject (index)) == -1) {
+       PyErr_SetString(PyExc_TypeError, "unknown tag type");
+       return NULL;
+    }
+    
+    mio = (rpmdbMIObject *) PyObject_NEW(rpmdbMIObject, &rpmdbMIType);
+    if (mio == NULL) {
+       PyErr_SetString(pyrpmError, "out of memory creating rpmdbMIObject");
+       return NULL;
+    }
+    
+    mio->mi = rpmdbInitIterator(s->db, tag, key, len);
+    mio->db = s;
+    Py_INCREF (mio->db);
+    
+    return mio;
+}
+
+/**
+ */
+static struct PyMethodDef rpmdbMethods[] = {
+       {"firstkey",        (PyCFunction) rpmdbFirst,   1 },
+       {"nextkey",         (PyCFunction) rpmdbNext,    1 },
+       {"findbyfile",      (PyCFunction) rpmdbByFile, 1 },
+       {"findbyname",      (PyCFunction) rpmdbByName, 1 },
+       {"findbyprovides",  (PyCFunction) rpmdbByProvides, 1 },
+       {"match",           (PyCFunction) py_rpmdbInitIterator, 1 },
+       {NULL,          NULL}           /* sentinel */
+};
+
+/**
+ */
+static PyObject * rpmdbGetAttr(rpmdbObject * s, char * name) {
+    return Py_FindMethod(rpmdbMethods, (PyObject * ) s, name);
+}
+
+/**
+ */
+static void rpmdbDealloc(rpmdbObject * s) {
+    if (s->offsets) {
+       free(s->offsets);
+    }
+    if (s->db) {
+       rpmdbClose(s->db);
+    }
+    PyMem_DEL(s);
+}
+
+#ifndef DYINGSOON      /* XXX OK, when? */
+/**
+ */
+static int
+rpmdbLength(rpmdbObject * s) {
+    int count = 0;
+
+    {  rpmdbMatchIterator mi;
+
+       /* RPMDBI_PACKAGES */
+       mi = rpmdbInitIterator(s->db, RPMDBI_PACKAGES, NULL, 0);
+       while (rpmdbNextIterator(mi) != NULL)
+           count++;
+       rpmdbFreeIterator(mi);
+    }
+
+    return count;
+}
+
+/**
+ */
+static hdrObject *
+rpmdbSubscript(rpmdbObject * s, PyObject * key) {
+    int offset;
+    hdrObject * ho;
+    Header h;
+    rpmdbMatchIterator mi;
+
+    if (!PyInt_Check(key)) {
+       PyErr_SetString(PyExc_TypeError, "integer expected");
+       return NULL;
+    }
+
+    offset = (int) PyInt_AsLong(key);
+
+    mi = rpmdbInitIterator(s->db, RPMDBI_PACKAGES, &offset, sizeof(offset));
+    if (!(h = rpmdbNextIterator(mi))) {
+       rpmdbFreeIterator(mi);
+       PyErr_SetString(pyrpmError, "cannot read rpmdb entry");
+       return NULL;
+    }
+
+    ho = createHeaderObject(h);
+    headerFree(h, NULL);
+
+    return ho;
+}
+
+/**
+ */
+static PyMappingMethods rpmdbAsMapping = {
+       (inquiry) rpmdbLength,          /* mp_length */
+       (binaryfunc) rpmdbSubscript,    /* mp_subscript */
+       (objobjargproc)0,               /* mp_ass_subscript */
+};
+#endif
+
+/**
+ */
+PyTypeObject rpmdbType = {
+       PyObject_HEAD_INIT(NULL)
+       0,                              /* ob_size */
+       "rpmdb",                        /* tp_name */
+       sizeof(rpmdbObject),            /* tp_size */
+       0,                              /* tp_itemsize */
+       (destructor) rpmdbDealloc,      /* tp_dealloc */
+       0,                              /* tp_print */
+       (getattrfunc) rpmdbGetAttr,     /* tp_getattr */
+       0,                              /* tp_setattr */
+       0,                              /* tp_compare */
+       0,                              /* tp_repr */
+       0,                              /* tp_as_number */
+       0,                              /* tp_as_sequence */
+#ifndef DYINGSOON
+       &rpmdbAsMapping,                /* tp_as_mapping */
+#else
+       0,
+#endif
+};
+
+rpmdb dbFromDb(rpmdbObject * db) {
+    return db->db;
+}
+
+/**
+ */
+rpmdbObject * rpmOpenDB(PyObject * self, PyObject * args) {
+    rpmdbObject * o;
+    char * root = "";
+    int forWrite = 0;
+
+    if (!PyArg_ParseTuple(args, "|is", &forWrite, &root)) return NULL;
+
+    o = PyObject_NEW(rpmdbObject, &rpmdbType);
+    o->db = NULL;
+    o->offx = 0;
+    o->noffs = 0;
+    o->offsets = NULL;
+
+    if (rpmdbOpen(root, &o->db, forWrite ? O_RDWR | O_CREAT: O_RDONLY, 0644)) {
+       char * errmsg = "cannot open database in %s";
+       char * errstr = NULL;
+       int errsize;
+
+       Py_DECREF(o);
+       /* PyErr_SetString should take varargs... */
+       errsize = strlen(errmsg) + *root == '\0' ? 15 /* "/var/lib/rpm" */ : strlen(root);
+       errstr = alloca(errsize);
+       snprintf(errstr, errsize, errmsg, *root == '\0' ? "/var/lib/rpm" : root);
+       PyErr_SetString(pyrpmError, errstr);
+       return NULL;
+    }
+
+    return o;
+}
+
+/**
+ */
+PyObject * rebuildDB (PyObject * self, PyObject * args) {
+    char * root = "";
+
+    if (!PyArg_ParseTuple(args, "s", &root)) return NULL;
+
+    return Py_BuildValue("i", rpmdbRebuild(root));
+}
+
+/*@}*/
+
diff --git a/python/db-py.h b/python/db-py.h
new file mode 100644 (file)
index 0000000..c2265ff
--- /dev/null
@@ -0,0 +1,29 @@
+#ifndef RPMPYTHON_DB
+#define RPMPYTHON_DB
+
+/** \ingroup python
+ * \file python/db-py.h
+ */
+
+/** \ingroup python
+ */
+struct rpmdbObject_s {
+    PyObject_HEAD;
+    rpmdb db;
+    int offx;
+    int noffs;
+    int *offsets;
+} ;
+
+/** \ingroup python
+ */
+typedef struct rpmdbObject_s rpmdbObject;
+
+extern PyTypeObject rpmdbType;
+PyTypeObject rpmdbMIType;
+
+rpmdb dbFromDb(rpmdbObject * db);
+rpmdbObject * rpmOpenDB(PyObject * self, PyObject * args);
+PyObject * rebuildDB (PyObject * self, PyObject * args);
+
+#endif
diff --git a/python/header-py.c b/python/header-py.c
new file mode 100644 (file)
index 0000000..49144b7
--- /dev/null
@@ -0,0 +1,1116 @@
+/** \ingroup python
+ * \file python/header-py.c
+ */
+
+#include "Python.h"
+#include "rpmio_internal.h"
+#include "rpmcli.h"    /* XXX for rpmCheckSig */
+#include "depends.h"   /* XXX for ts->rpmdb */
+#include "legacy.h"
+#include "misc.h"
+#include "header_internal.h"
+
+#include "header-py.h"
+
+/** \ingroup python
+ * \class header
+ * \brief A python header object represents an RPM package header.
+ * 
+ * All RPM packages have headers that provide metadata for the package.
+ * Header objects can be returned by database queries or loaded from a
+ * binary package on disk.
+ * 
+ * The headerFromPackage function loads the package header from a
+ * package on disk.  It returns a tuple of a "isSource" flag and the
+ * header object.  The "isSource" flag is set to 1 if the package
+ * header was read from a source rpm or to 0 if the package header was
+ * read from a binary rpm.
+ * 
+ * For example:
+ * \code
+ *     import os, rpm
+ *  
+ *     fd = os.open("/tmp/foo-1.0-1.i386.rpm", os.O_RDONLY)
+ *     (header, isSource) = rpm.headerFromPackage(fd)
+ *     fd.close()
+ * \endcode
+ * The Python interface to the header data is quite elegant.  It
+ * presents the data in a dictionary form.  We'll take the header we
+ * just loaded and access the data within it:
+ * \code
+ *     print header[rpm.RPMTAG_NAME]
+ *     print header[rpm.RPMTAG_VERSION]
+ *     print header[rpm.RPMTAG_RELEASE]
+ * \endcode
+ * in the case of our "foor-1.0-1.i386.rpm" package, this code would
+ * output:
+\verbatim
+       foo
+       1.0
+       1
+\endverbatim
+ * You make also access the header data by string name:
+ * \code
+ *     print header['name']
+ * \endcode
+ * This method of access is a bit slower because the name must be
+ * translated into the tag number dynamically. You also must make sure
+ * the strings in header lookups don't get translated, or the lookups
+ * will fail.
+ */
+
+/** \ingroup python
+ * \name Class: header
+ */
+/*@{*/
+
+/** \ingroup python
+ */
+struct hdrObject_s {
+    PyObject_HEAD;
+    Header h;
+    char ** md5list;
+    char ** fileList;
+    char ** linkList;
+    int_32 * fileSizes;
+    int_32 * mtimes;
+    int_32 * uids, * gids;     /* XXX these tags are not used anymore */
+    unsigned short * rdevs;
+    unsigned short * modes;
+} ;
+
+/*@unused@*/ static inline Header headerAllocated(Header h) {
+    h->flags |= HEADERFLAG_ALLOCATED;
+    return 0;
+}
+
+/** \ingroup python
+ */
+static PyObject * hdrKeyList(hdrObject * s, PyObject * args) {
+    PyObject * list, *o;
+    HeaderIterator iter;
+    int tag, type;
+
+    if (!PyArg_ParseTuple(args, "")) return NULL;
+
+    list = PyList_New(0);
+
+    iter = headerInitIterator(s->h);
+    while (headerNextIterator(iter, &tag, &type, NULL, NULL)) {
+        if (tag == HEADER_I18NTABLE) continue;
+
+       switch (type) {
+         case RPM_BIN_TYPE:
+         case RPM_INT32_TYPE:
+         case RPM_CHAR_TYPE:
+         case RPM_INT8_TYPE:
+         case RPM_INT16_TYPE:
+         case RPM_STRING_ARRAY_TYPE:
+         case RPM_STRING_TYPE:
+           PyList_Append(list, o=PyInt_FromLong(tag));
+           Py_DECREF(o);
+       }
+    }
+
+    headerFreeIterator(iter);
+
+    return list;
+}
+
+/** \ingroup python
+ */
+static PyObject * hdrUnload(hdrObject * s, PyObject * args, PyObject *keywords) {
+    char * buf;
+    PyObject * rc;
+    int len, legacy = 0;
+    Header h;
+    static char *kwlist[] = { "legacyHeader", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, keywords, "|i", kwlist, &legacy))
+       return NULL; 
+
+    h = headerLink(s->h, "hdrUnload h");
+    /* XXX this legacy switch is a hack, needs to be removed. */
+    if (legacy) {
+       h = headerCopy(s->h);   /* XXX strip region tags, etc */
+       headerFree(s->h, "hdrUnload s->h");
+    }
+    len = headerSizeof(h, 0);
+    buf = headerUnload(h);
+    h = headerFree(h, "hdrUnload h");
+
+    if (buf == NULL || len == 0) {
+       PyErr_SetString(pyrpmError, "can't unload bad header\n");
+       return NULL;
+    }
+
+    rc = PyString_FromStringAndSize(buf, len);
+    free(buf);
+
+    return rc;
+}
+
+/** \ingroup python
+ * Returns a list of these tuples for each item that failed:
+ *     (attr_name, correctValue, currentValue)
+ * It should be passed the file number to verify.
+ */
+static PyObject * hdrVerifyFile(hdrObject * s, PyObject * args) {
+    int fileNumber;
+    rpmVerifyAttrs verifyResult = 0;
+    PyObject * list, * tuple, * attrName;
+    int type, count;
+    struct stat sb;
+    char buf[2048];
+    int i;
+    time_t timeInt;
+    struct tm * timeStruct;
+
+    if (!PyInt_Check(args)) {
+       PyErr_SetString(PyExc_TypeError, "integer expected");
+       return NULL;
+    }
+
+    fileNumber = (int) PyInt_AsLong(args);
+
+    {  rpmTransactionSet ts;
+       int scareMem = 1;
+       TFI_t fi;
+       int rc;
+
+       ts = rpmtransCreateSet(NULL, NULL);
+       fi = fiNew(ts, NULL, s->h, RPMTAG_BASENAMES, scareMem);
+       fi = tfiInit(fi, fileNumber);
+       if (fi != NULL && tfiNext(fi) >= 0) {
+           /* XXX this routine might use callbacks intelligently. */
+           rc = rpmVerifyFile(ts, fi, &verifyResult, RPMVERIFY_NONE);
+       } else
+           rc = 1;
+
+       fi = fiFree(fi, 1);
+       rpmtransFree(ts);
+
+       if (rc) {
+           Py_INCREF(Py_None);
+           return Py_None;
+       }
+    }
+
+    list = PyList_New(0);
+
+    if (!verifyResult) return list;
+
+    /* XXX Legacy tag needs to go away. */
+    if (!s->fileList) {
+       headerGetEntry(s->h, RPMTAG_OLDFILENAMES, &type, (void **) &s->fileList,
+                &count);
+    }
+
+    lstat(s->fileList[fileNumber], &sb);
+
+    if (verifyResult & RPMVERIFY_MD5) {
+       if (!s->md5list) {
+           headerGetEntry(s->h, RPMTAG_FILEMD5S, &type, (void **) &s->md5list,
+                    &count);
+       }
+
+       if (domd5(s->fileList[fileNumber], buf, 1)) {
+           strcpy(buf, "00000000000000000000000000000000");
+       }
+
+       tuple = PyTuple_New(3);
+       attrName = PyString_FromString("checksum");
+       PyTuple_SetItem(tuple, 0, attrName);
+       PyTuple_SetItem(tuple, 1, PyString_FromString(s->md5list[fileNumber]));
+       PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
+       PyList_Append(list, tuple);
+       Py_DECREF(tuple);
+    }
+
+    if (verifyResult & RPMVERIFY_FILESIZE) {
+       if (!s->fileSizes) {
+           headerGetEntry(s->h, RPMTAG_FILESIZES, &type, (void **) &s->fileSizes,
+                    &count);
+
+       }
+
+       tuple = PyTuple_New(3);
+       attrName = PyString_FromString("size");
+       PyTuple_SetItem(tuple, 0, attrName);
+
+       sprintf(buf, "%d", 100);
+       PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
+       sprintf(buf, "%ld", (long)sb.st_size);
+       PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
+       PyList_Append(list, tuple);
+       Py_DECREF(tuple);
+    }
+
+    if (verifyResult & RPMVERIFY_LINKTO) {
+       if (!s->linkList) {
+           headerGetEntry(s->h, RPMTAG_FILELINKTOS, &type, (void **) &s->linkList,
+                    &count);
+       }
+
+       i = readlink(s->fileList[fileNumber], buf, sizeof(buf));
+       if (i <= 0)
+           strcpy(buf, "(unknown)");
+       else
+           buf[i] = '\0';
+
+       tuple = PyTuple_New(3);
+       attrName = PyString_FromString("link");
+       PyTuple_SetItem(tuple, 0, attrName);
+       PyTuple_SetItem(tuple, 1, PyString_FromString(s->linkList[fileNumber]));
+       PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
+       PyList_Append(list, tuple);
+       Py_DECREF(tuple);
+    }
+
+    if (verifyResult & RPMVERIFY_MTIME) {
+       if (!s->mtimes) {
+           headerGetEntry(s->h, RPMTAG_FILEMTIMES, &type, (void **) &s->mtimes,
+                    &count);
+       }
+
+       tuple = PyTuple_New(3);
+       attrName = PyString_FromString("time");
+       PyTuple_SetItem(tuple, 0, attrName);
+
+       timeInt = sb.st_mtime;
+       timeStruct = localtime(&timeInt);
+       strftime(buf, sizeof(buf) - 1, "%c", timeStruct);
+       PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
+
+       timeInt = s->mtimes[fileNumber];
+       timeStruct = localtime(&timeInt);
+       strftime(buf, sizeof(buf) - 1, "%c", timeStruct);
+
+       PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
+
+       PyList_Append(list, tuple);
+       Py_DECREF(tuple);
+    }
+
+    if (verifyResult & RPMVERIFY_RDEV) {
+       if (!s->rdevs) {
+           headerGetEntry(s->h, RPMTAG_FILERDEVS, &type, (void **) &s->rdevs,
+                    &count);
+       }
+
+       tuple = PyTuple_New(3);
+       attrName = PyString_FromString("device");
+
+       PyTuple_SetItem(tuple, 0, attrName);
+       sprintf(buf, "0x%-4x", s->rdevs[fileNumber]);
+       PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
+       sprintf(buf, "0x%-4x", (unsigned int) sb.st_rdev);
+       PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
+       PyList_Append(list, tuple);
+       Py_DECREF(tuple);
+    }
+
+    /*
+     * RPMVERIFY_USER and RPM_VERIFY_GROUP are handled wrong here, but rpmlib.a
+     * doesn't do these correctly either. At least this is consistent.
+     *
+     * XXX Consistent? rpmlib.a verifies user/group quite well, thank you.
+     * XXX The code below does nothing useful. FILEUSERNAME needs to be
+     * XXX retrieved and looked up.
+     */
+    if (verifyResult & RPMVERIFY_USER) {
+       if (!s->uids) {
+           headerGetEntry(s->h, RPMTAG_FILEUIDS, &type, (void **) &s->uids,
+                    &count);
+       }
+
+       tuple = PyTuple_New(3);
+       attrName = PyString_FromString("uid");
+       PyTuple_SetItem(tuple, 0, attrName);
+       sprintf(buf, "%d", s->uids[fileNumber]);
+       PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
+       sprintf(buf, "%d", sb.st_uid);
+       PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
+       PyList_Append(list, tuple);
+       Py_DECREF(tuple);
+    }
+
+    /*
+     * XXX The code below does nothing useful. FILEGROUPNAME needs to be
+     * XXX retrieved and looked up.
+     */
+    if (verifyResult & RPMVERIFY_GROUP) {
+       if (!s->gids) {
+           headerGetEntry(s->h, RPMTAG_FILEGIDS, &type, (void **) &s->gids,
+                    &count);
+       }
+
+       tuple = PyTuple_New(3);
+       attrName = PyString_FromString("gid");
+       PyTuple_SetItem(tuple, 0, attrName);
+       sprintf(buf, "%d", s->gids[fileNumber]);
+       PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
+       sprintf(buf, "%d", sb.st_gid);
+       PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
+       PyList_Append(list, tuple);
+       Py_DECREF(tuple);
+    }
+
+    if (verifyResult & RPMVERIFY_MODE) {
+       if (!s->modes) {
+           headerGetEntry(s->h, RPMTAG_FILEMODES, &type, (void **) &s->modes,
+                    &count);
+       }
+
+       tuple = PyTuple_New(3);
+       attrName = PyString_FromString("permissions");
+       PyTuple_SetItem(tuple, 0, attrName);
+       sprintf(buf, "0%-4o", s->modes[fileNumber]);
+       PyTuple_SetItem(tuple, 1, PyString_FromString(buf));
+       sprintf(buf, "0%-4o", sb.st_mode);
+       PyTuple_SetItem(tuple, 2, PyString_FromString(buf));
+       PyList_Append(list, tuple);
+       Py_DECREF(tuple);
+    }
+
+    return list;
+}
+
+/** \ingroup python
+ */
+static PyObject * hdrExpandFilelist(hdrObject * s, PyObject * args) {
+    expandFilelist (s->h);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+/** \ingroup python
+ */
+static PyObject * hdrCompressFilelist(hdrObject * s, PyObject * args) {
+    compressFilelist (s->h);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+/* make a header with _all_ the tags we need */
+/** \ingroup python
+ */
+static void mungeFilelist(Header h)
+{
+    const char ** fileNames = NULL;
+    int count = 0;
+
+    if (!headerIsEntry (h, RPMTAG_BASENAMES)
+       || !headerIsEntry (h, RPMTAG_DIRNAMES)
+       || !headerIsEntry (h, RPMTAG_DIRINDEXES))
+       compressFilelist(h);
+    
+    rpmBuildFileList(h, &fileNames, &count);
+
+    if (fileNames == NULL || count <= 0)
+       return;
+
+    /* XXX Legacy tag needs to go away. */
+    headerAddEntry(h, RPMTAG_OLDFILENAMES, RPM_STRING_ARRAY_TYPE,
+                       fileNames, count);
+
+    free((void *)fileNames);
+}
+
+/** 
+ */
+static PyObject * rhnUnload(hdrObject * s, PyObject * args) {
+    int len;
+    char * uh;
+    PyObject * rc;
+    Header h;
+
+    if (!PyArg_ParseTuple(args, ""))
+        return NULL;
+
+    h = headerLink(s->h, "rhnUnload h");
+
+    /* Retrofit a RHNPlatform: tag. */
+    if (!headerIsEntry(h, RPMTAG_RHNPLATFORM)) {
+       const char * arch;
+       int_32 at;
+       if (headerGetEntry(h, RPMTAG_ARCH, &at, (void **)&arch, NULL))
+           headerAddEntry(h, RPMTAG_RHNPLATFORM, at, arch, 1);
+    }
+
+    /* Legacy headers are forced into immutable region. */
+    if (!headerIsEntry(h, RPMTAG_HEADERIMMUTABLE)) {
+       Header nh = headerReload(h, RPMTAG_HEADERIMMUTABLE);
+       /* XXX Another unload/load cycle to "seal" the immutable region. */
+       uh = headerUnload(nh);
+       headerFree(nh, "rhnUnload nh");
+       h = headerLoad(uh);
+       headerAllocated(h);
+    }
+
+    /* All headers have SHA1 digest, compute and add if necessary. */
+    if (!headerIsEntry(h, RPMTAG_SHA1HEADER)) {
+       int_32 uht, uhc;
+       const char * digest;
+        size_t digestlen;
+        DIGEST_CTX ctx;
+
+       headerGetEntry(h, RPMTAG_HEADERIMMUTABLE, &uht, (void **)&uh, &uhc);
+
+       ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
+        rpmDigestUpdate(ctx, uh, uhc);
+        rpmDigestFinal(ctx, (void **)&digest, &digestlen, 1);
+
+       headerAddEntry(h, RPMTAG_SHA1RHN, RPM_STRING_TYPE, digest, 1);
+
+       uh = headerFreeData(uh, uht);
+       digest = _free(digest);
+    }
+
+    len = headerSizeof(h, 0);
+    uh = headerUnload(h);
+    headerFree(h, "rhnUnload h");
+
+    rc = PyString_FromStringAndSize(uh, len);
+    free(uh);
+
+    return rc;
+}
+
+/** \ingroup python
+ */
+static PyObject * hdrFullFilelist(hdrObject * s, PyObject * args) {
+    if (!PyArg_ParseTuple(args, ""))
+       return NULL;
+
+    mungeFilelist (s->h);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+/** \ingroup python
+ */
+static PyObject * hdrSprintf(hdrObject * s, PyObject * args) {
+    char * fmt;
+    char * r;
+    errmsg_t err;
+    PyObject * result;
+
+    if (!PyArg_ParseTuple(args, "s", &fmt))
+       return NULL;
+
+    r = headerSprintf(s->h, fmt, rpmTagTable, rpmHeaderFormats, &err);
+    if (!r) {
+       PyErr_SetString(pyrpmError, err);
+       return NULL;
+    }
+
+    result = Py_BuildValue("s", r);
+    free(r);
+
+    return result;
+}
+
+
+/** \ingroup python
+ */
+static struct PyMethodDef hdrMethods[] = {
+       {"keys",        (PyCFunction) hdrKeyList,       1 },
+       {"unload",      (PyCFunction) hdrUnload,        METH_VARARGS|METH_KEYWORDS },
+       {"verifyFile",  (PyCFunction) hdrVerifyFile,    1 },
+       {"expandFilelist",      (PyCFunction) hdrExpandFilelist,        1 },
+       {"compressFilelist",    (PyCFunction) hdrCompressFilelist,      1 },
+       {"fullFilelist",        (PyCFunction) hdrFullFilelist,  1 },
+       {"rhnUnload",   (PyCFunction) rhnUnload, METH_VARARGS },
+       {"sprintf",     (PyCFunction) hdrSprintf, METH_VARARGS },
+       {NULL,          NULL}           /* sentinel */
+};
+
+/** \ingroup python
+ */
+static PyObject * hdrGetAttr(hdrObject * s, char * name) {
+    return Py_FindMethod(hdrMethods, (PyObject * ) s, name);
+}
+
+/** \ingroup python
+ */
+static void hdrDealloc(hdrObject * s) {
+    if (s->h) headerFree(s->h, "hdrDealloc s->h");
+    if (s->md5list) free(s->md5list);
+    if (s->fileList) free(s->fileList);
+    if (s->linkList) free(s->linkList);
+    PyMem_DEL(s);
+}
+
+/** \ingroup python
+ */
+long tagNumFromPyObject (PyObject *item)
+{
+    char * str;
+    int i;
+
+    if (PyInt_Check(item)) {
+       return PyInt_AsLong(item);
+    } else if (PyString_Check(item)) {
+       str = PyString_AsString(item);
+       for (i = 0; i < rpmTagTableSize; i++)
+           if (!xstrcasecmp(rpmTagTable[i].name + 7, str)) break;
+       if (i < rpmTagTableSize) return rpmTagTable[i].val;
+    }
+    return -1;
+}
+
+/** \ingroup python
+ */
+static PyObject * hdrSubscript(hdrObject * s, PyObject * item) {
+    int type, count, i, tag = -1;
+    void * data;
+    PyObject * o, * metao;
+    char ** stringArray;
+    int forceArray = 0;
+    int freeData = 0;
+    char * str;
+    struct headerSprintfExtension_s * ext = NULL;
+    const struct headerSprintfExtension_s * extensions = rpmHeaderFormats;
+
+    if (PyCObject_Check (item))
+        ext = PyCObject_AsVoidPtr(item);
+    else
+       tag = tagNumFromPyObject (item);
+    if (tag == -1 && PyString_Check(item)) {
+       /* if we still don't have the tag, go looking for the header
+          extensions */
+       str = PyString_AsString(item);
+       while (extensions->name) {
+           if (extensions->type == HEADER_EXT_TAG
+               && !xstrcasecmp(extensions->name + 7, str)) {
+               (const struct headerSprintfExtension *) ext = extensions;
+           }
+           extensions++;
+       }
+    }
+
+    if (ext) {
+        ext->u.tagFunction(s->h, &type, (const void **) &data, &count, &freeData);
+    } else {
+        if (tag == -1) {
+            PyErr_SetString(PyExc_KeyError, "unknown header tag");
+            return NULL;
+        }
+        
+        if (!rpmHeaderGetEntry(s->h, tag, &type, &data, &count)) {
+            Py_INCREF(Py_None);
+            return Py_None;
+        }
+    }
+
+    switch (tag) {
+      case RPMTAG_OLDFILENAMES:
+      case RPMTAG_FILESIZES:
+      case RPMTAG_FILESTATES:
+      case RPMTAG_FILEMODES:
+      case RPMTAG_FILEUIDS:
+      case RPMTAG_FILEGIDS:
+      case RPMTAG_FILERDEVS:
+      case RPMTAG_FILEMTIMES:
+      case RPMTAG_FILEMD5S:
+      case RPMTAG_FILELINKTOS:
+      case RPMTAG_FILEFLAGS:
+      case RPMTAG_ROOT:
+      case RPMTAG_FILEUSERNAME:
+      case RPMTAG_FILEGROUPNAME:
+       forceArray = 1;
+       break;
+      case RPMTAG_SUMMARY:
+      case RPMTAG_GROUP:
+      case RPMTAG_DESCRIPTION:
+       freeData = 1;
+       break;
+      default:
+        break;
+    }
+
+    switch (type) {
+      case RPM_BIN_TYPE:
+       o = PyString_FromStringAndSize(data, count);
+       break;
+
+      case RPM_INT32_TYPE:
+       if (count != 1 || forceArray) {
+           metao = PyList_New(0);
+           for (i = 0; i < count; i++) {
+               o = PyInt_FromLong(((int *) data)[i]);
+               PyList_Append(metao, o);
+               Py_DECREF(o);
+           }
+           o = metao;
+       } else {
+           o = PyInt_FromLong(*((int *) data));
+       }
+       break;
+
+      case RPM_CHAR_TYPE:
+      case RPM_INT8_TYPE:
+       if (count != 1 || forceArray) {
+           metao = PyList_New(0);
+           for (i = 0; i < count; i++) {
+               o = PyInt_FromLong(((char *) data)[i]);
+               PyList_Append(metao, o);
+               Py_DECREF(o);
+           }
+           o = metao;
+       } else {
+           o = PyInt_FromLong(*((char *) data));
+       }
+       break;
+
+      case RPM_INT16_TYPE:
+       if (count != 1 || forceArray) {
+           metao = PyList_New(0);
+           for (i = 0; i < count; i++) {
+               o = PyInt_FromLong(((short *) data)[i]);
+               PyList_Append(metao, o);
+               Py_DECREF(o);
+           }
+           o = metao;
+       } else {
+           o = PyInt_FromLong(*((short *) data));
+       }
+       break;
+
+      case RPM_STRING_ARRAY_TYPE:
+       stringArray = data;
+
+       metao = PyList_New(0);
+       for (i = 0; i < count; i++) {
+           o = PyString_FromString(stringArray[i]);
+           PyList_Append(metao, o);
+           Py_DECREF(o);
+       }
+       free (stringArray);
+       o = metao;
+       break;
+
+      case RPM_STRING_TYPE:
+       if (count != 1 || forceArray) {
+           stringArray = data;
+
+           metao = PyList_New(0);
+           for (i=0; i < count; i++) {
+               o = PyString_FromString(stringArray[i]);
+               PyList_Append(metao, o);
+               Py_DECREF(o);
+           }
+           o = metao;
+       } else {
+           o = PyString_FromString(data);
+           if (freeData)
+               free (data);
+       }
+       break;
+
+      default:
+       PyErr_SetString(PyExc_TypeError, "unsupported type in header");
+       return NULL;
+    }
+
+    return o;
+}
+
+/** \ingroup python
+ */
+static PyMappingMethods hdrAsMapping = {
+       (inquiry) 0,                    /* mp_length */
+       (binaryfunc) hdrSubscript,      /* mp_subscript */
+       (objobjargproc)0,               /* mp_ass_subscript */
+};
+
+/** \ingroup python
+ */
+PyTypeObject hdrType = {
+       PyObject_HEAD_INIT(NULL)
+       0,                              /* ob_size */
+       "header",                       /* tp_name */
+       sizeof(hdrObject),              /* tp_size */
+       0,                              /* tp_itemsize */
+       (destructor) hdrDealloc,        /* tp_dealloc */
+       0,                              /* tp_print */
+       (getattrfunc) hdrGetAttr,       /* tp_getattr */
+       0,                              /* tp_setattr */
+       0,                              /* tp_compare */
+       0,                              /* tp_repr */
+       0,                              /* tp_as_number */
+       0,                              /* tp_as_sequence */
+       &hdrAsMapping,                  /* tp_as_mapping */
+};
+
+hdrObject * createHeaderObject(Header h) {
+    hdrObject * ho;
+
+    ho = PyObject_NEW(hdrObject, &hdrType);
+    ho->h = headerLink(h, NULL);
+    ho->fileList = ho->linkList = ho->md5list = NULL;
+    ho->uids = ho->gids = ho->mtimes = ho->fileSizes = NULL;
+    ho->modes = ho->rdevs = NULL;
+
+    return ho;
+}
+
+Header hdrGetHeader(hdrObject * h) {
+    return h->h;
+}
+
+/**
+ */
+PyObject * rpmHeaderFromPackage(PyObject * self, PyObject * args) {
+    hdrObject * h;
+    Header header;
+    FD_t fd;
+    int rawFd;
+    int isSource = 0;
+    rpmRC rc;
+
+    if (!PyArg_ParseTuple(args, "i", &rawFd)) return NULL;
+
+    fd = fdDup(rawFd);
+    {  rpmTransactionSet ts;
+       ts = rpmtransCreateSet(NULL, NULL);
+       rc = rpmReadPackageFile(ts, fd, "rpmHeaderFromPackage", &header);
+       rpmtransFree(ts);
+    }
+    Fclose(fd);
+
+    switch (rc) {
+    case RPMRC_BADSIZE:
+    case RPMRC_OK:
+       h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
+       h->h = header;
+       h->fileList = h->linkList = h->md5list = NULL;
+       h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
+       h->modes = h->rdevs = NULL;
+       isSource = headerIsEntry(header, RPMTAG_SOURCEPACKAGE);
+       break;
+
+    case RPMRC_BADMAGIC:
+       Py_INCREF(Py_None);
+       h = (hdrObject *) Py_None;
+       break;
+
+    case RPMRC_FAIL:
+    case RPMRC_SHORTREAD:
+    default:
+       PyErr_SetString(pyrpmError, "error reading package");
+       return NULL;
+    }
+
+    return Py_BuildValue("(Ni)", h, isSource);
+}
+
+/**
+ */
+PyObject * hdrLoad(PyObject * self, PyObject * args) {
+    char * obj, * copy=NULL;
+    Header hdr;
+    hdrObject * h;
+    int len;
+
+    if (!PyArg_ParseTuple(args, "s#", &obj, &len)) return NULL;
+    
+    /* malloc is needed to avoid surprises from data swab in headerLoad(). */
+    copy = malloc(len);
+    if (copy == NULL) {
+       PyErr_SetString(pyrpmError, "out of memory");
+       return NULL;
+    }
+    memcpy (copy, obj, len);
+
+    hdr = headerLoad(copy);
+    if (!hdr) {
+       PyErr_SetString(pyrpmError, "bad header");
+       return NULL;
+    }
+    headerAllocated(hdr);
+    compressFilelist (hdr);
+    providePackageNVR (hdr);
+
+    h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
+    h->h = hdr;
+    h->fileList = h->linkList = h->md5list = NULL;
+    h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
+    h->modes = h->rdevs = NULL;
+
+    return (PyObject *) h;
+}
+
+/**
+ */
+PyObject * rhnLoad(PyObject * self, PyObject * args) {
+    char * obj, * copy=NULL;
+    Header hdr;
+    hdrObject * h;
+    int len;
+
+    if (!PyArg_ParseTuple(args, "s#", &obj, &len)) return NULL;
+    
+    /* malloc is needed to avoid surprises from data swab in headerLoad(). */
+    copy = malloc(len);
+    if (copy == NULL) {
+       PyErr_SetString(pyrpmError, "out of memory");
+       return NULL;
+    }
+    memcpy (copy, obj, len);
+
+    hdr = headerLoad(copy);
+    if (!hdr) {
+       PyErr_SetString(pyrpmError, "bad header");
+       return NULL;
+    }
+    headerAllocated(hdr);
+
+    /* XXX avoid the false OK's from rpmverifyDigest() with missing tags. */
+    if (!headerIsEntry(hdr, RPMTAG_HEADERIMMUTABLE)) {
+       PyErr_SetString(pyrpmError, "bad header, not immutable");
+       headerFree(hdr, "rhnLoad hdr #1");
+       return NULL;
+    }
+
+    /* XXX avoid the false OK's from rpmverifyDigest() with missing tags. */
+    if (!headerIsEntry(hdr, RPMTAG_SHA1HEADER)
+    &&  !headerIsEntry(hdr, RPMTAG_SHA1RHN)) {
+       PyErr_SetString(pyrpmError, "bad header, no digest");
+       headerFree(hdr, "rhnLoad hdr #2");
+       return NULL;
+    }
+
+    if (rpmVerifyDigest(hdr)) {
+       PyErr_SetString(pyrpmError, "bad header, digest check failed");
+       headerFree(hdr, "rhnLoad hdr #3");
+       return NULL;
+    }
+
+    /* Retrofit a RHNPlatform: tag. */
+    if (!headerIsEntry(hdr, RPMTAG_RHNPLATFORM)) {
+       const char * arch;
+       int_32 at;
+       if (headerGetEntry(hdr, RPMTAG_ARCH, &at, (void **)&arch, NULL))
+           headerAddEntry(hdr, RPMTAG_RHNPLATFORM, at, arch, 1);
+    }
+
+    h = createHeaderObject(hdr);
+
+    return (PyObject *) h;
+}
+
+/**
+ */
+PyObject * rpmReadHeaders (FD_t fd) {
+    PyObject * list;
+    Header header;
+    hdrObject * h;
+
+    if (!fd) {
+       PyErr_SetFromErrno(pyrpmError);
+       return NULL;
+    }
+
+    list = PyList_New(0);
+    Py_BEGIN_ALLOW_THREADS
+    header = headerRead(fd, HEADER_MAGIC_YES);
+
+    Py_END_ALLOW_THREADS
+    while (header) {
+       compressFilelist (header);
+       providePackageNVR (header);
+       h = (hdrObject *) PyObject_NEW(PyObject, &hdrType);
+       h->h = header;
+       h->fileList = h->linkList = h->md5list = NULL;
+       h->uids = h->gids = h->mtimes = h->fileSizes = NULL;
+       h->modes = h->rdevs = NULL;
+       if (PyList_Append(list, (PyObject *) h)) {
+           Py_DECREF(list);
+           Py_DECREF(h);
+           return NULL;
+       }
+
+       Py_DECREF(h);
+
+       Py_BEGIN_ALLOW_THREADS
+       header = headerRead(fd, HEADER_MAGIC_YES);
+       Py_END_ALLOW_THREADS
+    }
+
+    return list;
+}
+
+/**
+ */
+PyObject * rpmHeaderFromFD(PyObject * self, PyObject * args) {
+    FD_t fd;
+    int fileno;
+    PyObject * list;
+
+    if (!PyArg_ParseTuple(args, "i", &fileno)) return NULL;
+    fd = fdDup(fileno);
+
+    list = rpmReadHeaders (fd);
+    Fclose(fd);
+
+    return list;
+}
+
+/**
+ */
+PyObject * rpmHeaderFromFile(PyObject * self, PyObject * args) {
+    char * filespec;
+    FD_t fd;
+    PyObject * list;
+
+    if (!PyArg_ParseTuple(args, "s", &filespec)) return NULL;
+    fd = Fopen(filespec, "r.fdio");
+
+    if (!fd) {
+       PyErr_SetFromErrno(pyrpmError);
+       return NULL;
+    }
+
+    list = rpmReadHeaders (fd);
+    Fclose(fd);
+
+    return list;
+}
+
+/**
+ * This assumes the order of list matches the order of the new headers, and
+ * throws an exception if that isn't true.
+ */
+int rpmMergeHeaders(PyObject * list, FD_t fd, int matchTag) {
+    Header newH;
+    HeaderIterator iter;
+    int_32 * newMatch, * oldMatch;
+    hdrObject * ho;
+    int count = 0;
+    int type, c, tag;
+    void * p;
+
+    Py_BEGIN_ALLOW_THREADS
+    newH = headerRead(fd, HEADER_MAGIC_YES);
+
+    Py_END_ALLOW_THREADS
+    while (newH) {
+       if (!headerGetEntry(newH, matchTag, NULL, (void **) &newMatch, NULL)) {
+           PyErr_SetString(pyrpmError, "match tag missing in new header");
+           return 1;
+       }
+
+       ho = (hdrObject *) PyList_GetItem(list, count++);
+       if (!ho) return 1;
+
+       if (!headerGetEntry(ho->h, matchTag, NULL, (void **) &oldMatch, NULL)) {
+           PyErr_SetString(pyrpmError, "match tag missing in new header");
+           return 1;
+       }
+
+       if (*newMatch != *oldMatch) {
+           PyErr_SetString(pyrpmError, "match tag mismatch");
+           return 1;
+       }
+
+       if (ho->md5list) free(ho->md5list);
+       if (ho->fileList) free(ho->fileList);
+       if (ho->linkList) free(ho->linkList);
+
+       ho->md5list = NULL;
+       ho->fileList = NULL;
+       ho->linkList = NULL;
+
+       iter = headerInitIterator(newH);
+
+       while (headerNextIterator(iter, &tag, &type, (void *) &p, &c)) {
+           /* could be dupes */
+           headerRemoveEntry(ho->h, tag);
+           headerAddEntry(ho->h, tag, type, p, c);
+           headerFreeData(p, type);
+       }
+
+       headerFreeIterator(iter);
+
+       Py_BEGIN_ALLOW_THREADS
+       newH = headerRead(fd, HEADER_MAGIC_YES);
+       Py_END_ALLOW_THREADS
+    }
+
+    return 0;
+}
+
+PyObject * rpmMergeHeadersFromFD(PyObject * self, PyObject * args) {
+    FD_t fd;
+    int fileno;
+    PyObject * list;
+    int rc;
+    int matchTag;
+
+    if (!PyArg_ParseTuple(args, "Oii", &list, &fileno, &matchTag)) return NULL;
+
+    if (!PyList_Check(list)) {
+       PyErr_SetString(PyExc_TypeError, "first parameter must be a list");
+       return NULL;
+    }
+
+    fd = fdDup(fileno);
+
+    rc = rpmMergeHeaders (list, fd, matchTag);
+    Fclose(fd);
+
+    if (rc) {
+       return NULL;
+    }
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+/**
+ */
+PyObject * versionCompare (PyObject * self, PyObject * args) {
+    hdrObject * h1, * h2;
+
+    if (!PyArg_ParseTuple(args, "O!O!", &hdrType, &h1, &hdrType, &h2)) return NULL;
+
+    return Py_BuildValue("i", rpmVersionCompare(h1->h, h2->h));
+}
+
+/**
+ */
+PyObject * labelCompare (PyObject * self, PyObject * args) {
+    char *v1, *r1, *e1, *v2, *r2, *e2;
+    int rc;
+
+    if (!PyArg_ParseTuple(args, "(zzz)(zzz)",
+                         &e1, &v1, &r1,
+                         &e2, &v2, &r2)) return NULL;
+
+    if (e1 && !e2)
+       return Py_BuildValue("i", 1);
+    else if (!e1 && e2)
+       return Py_BuildValue("i", -1);
+    else if (e1 && e2) {
+       int ep1, ep2;
+       ep1 = atoi (e1);
+       ep2 = atoi (e2);
+       if (ep1 < ep2)
+           return Py_BuildValue("i", -1);
+       else if (ep1 > ep2)
+           return Py_BuildValue("i", 1);
+    }
+
+    rc = rpmvercmp(v1, v2);
+    if (rc)
+       return Py_BuildValue("i", rc);
+
+    return Py_BuildValue("i", rpmvercmp(r1, r2));
+}
+
+/*@}*/
diff --git a/python/header-py.h b/python/header-py.h
new file mode 100644 (file)
index 0000000..c5d3d4a
--- /dev/null
@@ -0,0 +1,31 @@
+#ifndef RPMPYTHON_HEADER
+#define RPMPYTHON_HEADER
+
+/** \ingroup python
+ * \file python/header-py.h
+ */
+
+/** \ingroup python
+ */
+typedef struct hdrObject_s hdrObject;
+extern PyTypeObject hdrType;
+
+/** \ingroup python
+ */
+PyObject * pyrpmError;
+
+hdrObject * createHeaderObject(Header h);
+Header hdrGetHeader(hdrObject * h);
+PyObject * labelCompare (PyObject * self, PyObject * args);
+PyObject * versionCompare (PyObject * self, PyObject * args);
+PyObject * rpmMergeHeadersFromFD(PyObject * self, PyObject * args);
+int rpmMergeHeaders(PyObject * list, FD_t fd, int matchTag);
+PyObject * rpmHeaderFromFile(PyObject * self, PyObject * args);
+PyObject * rpmHeaderFromFD(PyObject * self, PyObject * args);
+PyObject * rpmReadHeaders (FD_t fd);
+PyObject * rhnLoad(PyObject * self, PyObject * args);
+PyObject * hdrLoad(PyObject * self, PyObject * args);
+PyObject * rpmHeaderFromPackage(PyObject * self, PyObject * args);
+long tagNumFromPyObject (PyObject *item);
+
+#endif
diff --git a/python/rpmmodule.c b/python/rpmmodule.c
new file mode 100644 (file)
index 0000000..c0c1f5f
--- /dev/null
@@ -0,0 +1,1170 @@
+/** \ingroup python
+ * \file python/rpmmodule.c
+ */
+
+#include <alloca.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <glob.h>      /* XXX rpmio.h */
+#include <dirent.h>    /* XXX rpmio.h */
+#include <locale.h>
+#include <time.h>
+
+#include "Python.h"
+#include "rpmio_internal.h"
+#include "rpmcli.h"    /* XXX for rpmCheckSig */
+#include "depends.h"   /* XXX for ts->rpmdb */
+#include "legacy.h"
+#include "misc.h"
+#include "header_internal.h"
+#include "upgrade.h"
+
+#include "db-py.h"
+#include "header-py.h"
+
+extern int _rpmio_debug;
+
+/* XXX These names/constants have been removed from the rpmlib API. */
+enum {
+   RPMDEP_SENSE_REQUIRES,              /*!< requirement not satisfied. */
+   RPMDEP_SENSE_CONFLICTS              /*!< conflict was found. */
+};
+
+#ifdef __LCLINT__
+#undef PyObject_HEAD
+#define        PyObject_HEAD   int _PyObjectHead
+#endif
+
+void initrpm(void);
+
+/* from lib/misc.c */
+int rpmvercmp(const char * one, const char * two);
+
+/** \ingroup python
+ */
+typedef struct rpmtransObject_s rpmtransObject;
+
+/** \ingroup python
+ * \name Class: rpmtrans
+ * \class rpmtrans
+ * \brief A python rpmtrans object represents an RPM transaction set.
+ * 
+ * The transaction set is the workhorse of RPM.  It performs the
+ * installation and upgrade of packages.  The rpmtrans object is
+ * instantiated by the TransactionSet function in the rpm module.
+ *
+ * The TransactionSet function takes two optional arguments.  The first
+ * argument is the root path, the second is an open database to perform
+ * the transaction set upon.
+ *
+ * A rpmtrans object has the following methods:
+ *
+ * - add(header,data,mode)     Add a binary package to a transaction set.
+ * @param header the header to be added
+ * @param data user data that will be passed to the transaction callback
+ *             during transaction execution
+ * @param mode         optional argument that specifies if this package should
+ *             be installed ('i'), upgraded ('u'), or if it is just
+ *             available to the transaction when computing
+ *             dependencies but no action should be performed with it
+ *             ('a').
+ *
+ * - remove
+ *
+ * - depcheck()        Perform a dependency and conflict check on the
+ *             transaction set. After headers have been added to a
+ *             transaction set, a dependency check can be performed
+ *             to make sure that all package dependencies are
+ *             satisfied.
+ * @return     None If there are no unresolved dependencies
+ *             Otherwise a list of complex tuples is returned, one tuple per
+ *             unresolved dependency, with
+ * The format of the dependency tuple is:
+ *     ((packageName, packageVersion, packageRelease),
+ *      (reqName, reqVersion),
+ *      needsFlags,
+ *      suggestedPackage,
+ *      sense)
+ *     packageName, packageVersion, packageRelease are the name,
+ *     version, and release of the package that has the unresolved
+ *     dependency or conflict.
+ *     The reqName and reqVersion are the name and version of the
+ *     requirement or conflict.
+ *     The needsFlags is a bitfield that describes the versioned
+ *     nature of a requirement or conflict.  The constants
+ *     rpm.RPMSENSE_LESS, rpm.RPMSENSE_GREATER, and
+ *     rpm.RPMSENSE_EQUAL can be logical ANDed with the needsFlags
+ *     to get versioned dependency information.
+ *     suggestedPackage is a tuple if the dependency check was aware
+ *     of a package that solves this dependency problem when the
+ *     dependency check was run.  Packages that are added to the
+ *     transaction set as "available" are examined during the
+ *     dependency check as possible dependency solvers. The tuple
+ *     contains two values, (header, suggestedName).  These are set to
+ *     the header of the suggested package and its name, respectively.
+ *     If there is no known package to solve the dependency problem,
+ *     suggestedPackage is None.
+ *     The constants rpm.RPMDEP_SENSE_CONFLICTS and
+ *     rpm.RPMDEP_SENSE_REQUIRES are set to show a dependency as a
+ *     requirement or a conflict.
+ *
+ * - run(flags,problemSetFilter,callback,data) Attempt to execute a
+ *     transaction set. After the transaction set has been populated
+ *     with install and upgrade actions, it can be executed by invoking
+ *     the run() method.
+ * @param flags - modifies the behavior of the transaction set as it is
+ *             processed.  The following values can be locical ORed
+ *             together:
+ *     - rpm.RPMTRANS_FLAG_TEST - test mode, do not modify the RPM
+ *             database, change any files, or run any package scripts
+ *     - rpm.RPMTRANS_FLAG_BUILD_PROBS - only build a list of
+ *             problems encountered when attempting to run this transaction
+ *             set
+ *     - rpm.RPMTRANS_FLAG_NOSCRIPTS - do not execute package scripts
+ *     - rpm.RPMTRANS_FLAG_JUSTDB - only make changes to the rpm
+ *             database, do not modify files.
+ *     - rpm.RPMTRANS_FLAG_NOTRIGGERS - do not run trigger scripts
+ *     - rpm.RPMTRANS_FLAG_NODOCS - do not install files marked as %doc
+ *     - rpm.RPMTRANS_FLAG_ALLFILES - create all files, even if a
+ *             file is marked %config(missingok) and an upgrade is
+ *             being performed.
+ *     - rpm.RPMTRANS_FLAG_KEEPOBSOLETE - do not remove obsoleted
+ *             packages.
+ * @param problemSetFilter - control bit(s) to ignore classes of problems,
+ *             any of
+ *     - rpm.RPMPROB_FILTER_IGNOREOS - 
+ *     - rpm.RPMPROB_FILTER_IGNOREARCH - 
+ *     - rpm.RPMPROB_FILTER_REPLACEPKG - 
+ *     - rpm.RPMPROB_FILTER_FORCERELOCATE - 
+ *     - rpm.RPMPROB_FILTER_REPLACENEWFILES - 
+ *     - rpm.RPMPROB_FILTER_REPLACEOLDFILES - 
+ *     - rpm.RPMPROB_FILTER_OLDPACKAGE - 
+ *     - rpm.RPMPROB_FILTER_DISKSPACE - 
+ */
+
+/** \ingroup python
+ * \name Class: rpmtrans
+ */
+/*@{*/
+
+/** \ingroup python
+ */
+struct rpmtransObject_s {
+    PyObject_HEAD;
+    rpmdbObject * dbo;
+    rpmTransactionSet ts;
+    PyObject * keyList;                        /* keeps reference counts correct */
+    FD_t scriptFd;
+} ;
+
+/** \ingroup python
+ */
+static PyObject * rpmtransAdd(rpmtransObject * s, PyObject * args) {
+    hdrObject * h;
+    PyObject * key;
+    char * how = NULL;
+    int isUpgrade = 0;
+    PyObject * hObj;
+
+    if (!PyArg_ParseTuple(args, "OO|s", &h, &key, &how)) return NULL;
+
+    hObj = (PyObject *) h;
+    if (hObj->ob_type != &hdrType) {
+       PyErr_SetString(PyExc_TypeError, "bad type for header argument");
+       return NULL;
+    }
+
+    if (how && strcmp(how, "a") && strcmp(how, "u") && strcmp(how, "i")) {
+       PyErr_SetString(PyExc_TypeError, "how argument must be \"u\", \"a\", or \"i\"");
+       return NULL;
+    } else if (how && !strcmp(how, "u"))
+       isUpgrade = 1;
+
+    if (how && !strcmp(how, "a"))
+       rpmtransAvailablePackage(s->ts, hdrGetHeader(h), key);
+    else
+       rpmtransAddPackage(s->ts, hdrGetHeader(h), key, isUpgrade, NULL);
+
+    /* This should increment the usage count for me */
+    if (key) {
+       PyList_Append(s->keyList, key);
+    }
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+/** \ingroup python
+ */
+static PyObject * rpmtransRemove(rpmtransObject * s, PyObject * args) {
+    char * name;
+    int count;
+    rpmdbMatchIterator mi;
+    
+    if (!PyArg_ParseTuple(args, "s", &name))
+        return NULL;
+
+    /* XXX: Copied hack from ../lib/rpminstall.c, rpmErase() */
+    mi = rpmdbInitIterator(dbFromDb(s->dbo), RPMDBI_LABEL, name, 0);
+    count = rpmdbGetIteratorCount(mi);
+    if (count <= 0) {
+        PyErr_SetString(pyrpmError, "package not installed");
+        return NULL;
+    } else { /* XXX: Note that we automatically choose to remove all matches */
+        Header h;
+        while ((h = rpmdbNextIterator(mi)) != NULL) {
+           unsigned int recOffset = rpmdbGetIteratorOffset(mi);
+           if (recOffset) {
+               rpmtransRemovePackage(s->ts, h, recOffset);
+           }
+       }
+    }
+    rpmdbFreeIterator(mi);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+/** \ingroup python
+ */
+static PyObject * rpmtransDepCheck(rpmtransObject * s, PyObject * args) {
+    rpmProblem conflicts, c;
+    int numConflicts;
+    PyObject * list, * cf;
+    int i;
+    int allSuggestions = 0;
+
+    if (!PyArg_ParseTuple(args, "|i", &allSuggestions)) return NULL;
+
+    rpmdepCheck(s->ts, &conflicts, &numConflicts);
+    if (numConflicts) {
+       list = PyList_New(0);
+
+       /* XXX TODO: rpmlib >= 4.0.3 can return multiple suggested keys. */
+       for (i = 0; i < numConflicts; i++) {
+#ifdef DYING
+           cf = Py_BuildValue("((sss)(ss)iOi)", conflicts[i].byName,
+                              conflicts[i].byVersion, conflicts[i].byRelease,
+
+                              conflicts[i].needsName,
+                              conflicts[i].needsVersion,
+
+                              conflicts[i].needsFlags,
+                              conflicts[i].suggestedPkgs ?
+                                  conflicts[i].suggestedPkgs[0] : Py_None,
+                              conflicts[i].sense);
+#else
+           char * byName, * byVersion, * byRelease;
+           char * needsName, * needsOP, * needsVersion;
+           int needsFlags, sense;
+           fnpyKey key;
+           
+           c = conflicts + i;
+
+           byName = c->pkgNEVR;
+           if ((byRelease = strrchr(byName, '-')) != NULL)
+               *byRelease++ = '\0';
+           if ((byVersion = strrchr(byName, '-')) != NULL)
+               *byVersion++ = '\0';
+
+           key = c->key;
+
+           needsName = c->altNEVR;
+           if (needsName[1] == ' ') {
+               sense = (needsName[0] == 'C')
+                       ? RPMDEP_SENSE_CONFLICTS : RPMDEP_SENSE_REQUIRES;
+               needsName += 2;
+           } else
+               sense = RPMDEP_SENSE_REQUIRES;
+           if ((needsVersion = strrchr(needsName, ' ')) != NULL)
+               *needsVersion++ = '\0';
+
+           needsFlags = 0;
+           if ((needsOP = strrchr(needsName, ' ')) != NULL) {
+               for (*needsOP++ = '\0'; *needsOP != '\0'; needsOP++) {
+                   if (*needsOP == '<')        needsFlags |= RPMSENSE_LESS;
+                   else if (*needsOP == '>')   needsFlags |= RPMSENSE_GREATER;
+                   else if (*needsOP == '=')   needsFlags |= RPMSENSE_EQUAL;
+               }
+           }
+           
+           cf = Py_BuildValue("((sss)(ss)iOi)", byName, byVersion, byRelease,
+                              needsName, needsVersion, needsFlags,
+                              (key != NULL ? key : Py_None),
+                              sense);
+#endif
+           PyList_Append(list, (PyObject *) cf);
+           Py_DECREF(cf);
+       }
+
+       conflicts = rpmdepFreeConflicts(conflicts, numConflicts);
+
+       return list;
+    }
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+/** \ingroup python
+ */
+static PyObject * rpmtransOrder(rpmtransObject * s, PyObject * args) {
+    if (!PyArg_ParseTuple(args, "")) return NULL;
+
+    rpmdepOrder(s->ts);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+/** \ingroup python
+ */
+static PyObject * py_rpmtransGetKeys(rpmtransObject * s, PyObject * args) {
+    const void **data = NULL;
+    int num, i;
+    PyObject *tuple;
+
+    rpmtransGetKeys(s->ts, &data, &num);
+    if (data == NULL) {
+       Py_INCREF(Py_None);
+       return Py_None;
+    }
+
+    tuple = PyTuple_New(num);
+
+    for (i = 0; i < num; i++) {
+       PyObject *obj = (PyObject *) data[i];
+       Py_INCREF(obj);
+       PyTuple_SetItem(tuple, i, obj);
+    }
+
+    free (data);
+
+    return tuple;
+}
+
+/** \ingroup python
+ */
+struct tsCallbackType {
+    PyObject * cb;
+    PyObject * data;
+    int pythonError;
+};
+
+/** \ingroup python
+ * @todo Remove, there's no headerLink refcount on the pointer.
+ */
+static Header transactionSetHeader = NULL;
+
+/** \ingroup python
+ */
+static void * tsCallback(const void * hd, const rpmCallbackType what,
+                        const unsigned long amount, const unsigned long total,
+                        const void * pkgKey, rpmCallbackData data) {
+    struct tsCallbackType * cbInfo = data;
+    PyObject * args, * result;
+    int fd;
+    static FD_t fdt;
+    const Header h = (Header) hd;
+
+    if (cbInfo->pythonError) return NULL;
+    if (cbInfo->cb == Py_None) return NULL;
+
+    if (!pkgKey) pkgKey = Py_None;
+    transactionSetHeader = h;    
+
+    args = Py_BuildValue("(illOO)", what, amount, total, pkgKey, cbInfo->data);
+    result = PyEval_CallObject(cbInfo->cb, args);
+    Py_DECREF(args);
+
+    if (!result) {
+       cbInfo->pythonError = 1;
+       return NULL;
+    }
+
+    if (what == RPMCALLBACK_INST_OPEN_FILE) {
+        if (!PyArg_Parse(result, "i", &fd)) {
+           cbInfo->pythonError = 1;
+           return NULL;
+       }
+       fdt = fdDup(fd);
+       
+       Py_DECREF(result);
+       return fdt;
+    }
+
+    if (what == RPMCALLBACK_INST_CLOSE_FILE) {
+       Fclose (fdt);
+    }
+
+    Py_DECREF(result);
+
+    return NULL;
+}
+
+/** \ingroup python
+ */
+static PyObject * rpmtransRun(rpmtransObject * s, PyObject * args) {
+    int flags, ignoreSet;
+    int rc, i;
+    PyObject * list, * prob;
+    rpmProblemSet probs;
+    struct tsCallbackType cbInfo;
+
+    if (!PyArg_ParseTuple(args, "iiOO", &flags, &ignoreSet, &cbInfo.cb,
+                         &cbInfo.data))
+       return NULL;
+
+    cbInfo.pythonError = 0;
+
+    (void) rpmtsSetNotifyCallback(s->ts, tsCallback, (void *) &cbInfo);
+    (void) rpmtsSetFlags(s->ts, flags);
+
+    rc = rpmRunTransactions(s->ts, NULL, &probs, ignoreSet);
+
+    if (cbInfo.pythonError) {
+       if (rc > 0)
+           rpmProblemSetFree(probs);
+       return NULL;
+    }
+
+    if (rc < 0) {
+       list = PyList_New(0);
+       return list;
+    } else if (!rc) {
+       Py_INCREF(Py_None);
+       return Py_None;
+    }
+
+    list = PyList_New(0);
+    for (i = 0; i < probs->numProblems; i++) {
+       rpmProblem myprob = probs->probs + i;
+       prob = Py_BuildValue("s(isN)", rpmProblemString(myprob),
+                            myprob->type,
+                            myprob->str1,
+                            PyLong_FromLongLong(myprob->ulong1));
+       PyList_Append(list, prob);
+       Py_DECREF(prob);
+    }
+
+    rpmProblemSetFree(probs);
+
+    return list;
+}
+
+/** \ingroup python
+ */
+static struct PyMethodDef rpmtransMethods[] = {
+       {"add",         (PyCFunction) rpmtransAdd,      1 },
+       {"remove",      (PyCFunction) rpmtransRemove,   1 },
+       {"depcheck",    (PyCFunction) rpmtransDepCheck, 1 },
+       {"order",       (PyCFunction) rpmtransOrder,    1 },
+       {"getKeys",     (PyCFunction) py_rpmtransGetKeys, 1 },
+       {"run",         (PyCFunction) rpmtransRun, 1 },
+       {NULL,          NULL}           /* sentinel */
+};
+
+/** \ingroup python
+ */
+static PyObject * rpmtransGetAttr(rpmtransObject * o, char * name) {
+    return Py_FindMethod(rpmtransMethods, (PyObject *) o, name);
+}
+
+/** \ingroup python
+ */
+static void rpmtransDealloc(PyObject * o) {
+    rpmtransObject * trans = (void *) o;
+
+    trans->ts->rpmdb = NULL;   /* XXX HACK: avoid rpmdb close/free */
+    rpmtransFree(trans->ts);
+    if (trans->dbo) {
+       Py_DECREF(trans->dbo);
+    }
+    if (trans->scriptFd) Fclose(trans->scriptFd);
+    /* this will free the keyList, and decrement the ref count of all
+       the items on the list as well :-) */
+    Py_DECREF(trans->keyList);
+    PyMem_DEL(o);
+}
+
+/** \ingroup python
+ */
+static int rpmtransSetAttr(rpmtransObject * o, char * name,
+                          PyObject * val) {
+    int i;
+
+    if (!strcmp(name, "scriptFd")) {
+       if (!PyArg_Parse(val, "i", &i)) return 0;
+       if (i < 0) {
+           PyErr_SetString(PyExc_TypeError, "bad file descriptor");
+           return -1;
+       } else {
+           o->scriptFd = fdDup(i);
+           rpmtransSetScriptFd(o->ts, o->scriptFd);
+       }
+    } else {
+       PyErr_SetString(PyExc_AttributeError, name);
+       return -1;
+    }
+
+    return 0;
+}
+
+/** \ingroup python
+ */
+static PyTypeObject rpmtransType = {
+       PyObject_HEAD_INIT(NULL)
+       0,                              /* ob_size */
+       "rpmtrans",                     /* tp_name */
+       sizeof(rpmtransObject),         /* tp_size */
+       0,                              /* tp_itemsize */
+       (destructor) rpmtransDealloc,   /* tp_dealloc */
+       0,                              /* tp_print */
+       (getattrfunc) rpmtransGetAttr,  /* tp_getattr */
+       (setattrfunc) rpmtransSetAttr,  /* tp_setattr */
+       0,                              /* tp_compare */
+       0,                              /* tp_repr */
+       0,                              /* tp_as_number */
+       0,                              /* tp_as_sequence */
+       0,                              /* tp_as_mapping */
+};
+
+/*@}*/
+
+/** \ingroup python
+ * \name Module: rpm
+ */
+/*@{*/
+
+/**
+ */
+static PyObject * rpmtransCreate(PyObject * self, PyObject * args) {
+    rpmtransObject * o;
+    rpmdbObject * db = NULL;
+    char * rootPath = "/";
+
+    if (!PyArg_ParseTuple(args, "|sO", &rootPath, &db)) return NULL;
+    if (db && ((PyObject *) db)->ob_type != &rpmdbType) {
+       PyErr_SetString(PyExc_TypeError, "bad type for database argument");
+       return NULL;
+    }
+
+    o = (void *) PyObject_NEW(rpmtransObject, &rpmtransType);
+
+    Py_XINCREF(db);
+    o->dbo = db;
+    o->scriptFd = NULL;
+    o->ts = rpmtransCreateSet(NULL, rootPath);
+    o->ts->rpmdb = (db ? dbFromDb(db) : NULL);
+    o->keyList = PyList_New(0);
+
+    return (void *) o;
+}
+
+/**
+ */
+static PyObject * doAddMacro(PyObject * self, PyObject * args) {
+    char * name, * val;
+
+    if (!PyArg_ParseTuple(args, "ss", &name, &val))
+       return NULL;
+
+    addMacro(NULL, name, NULL, val, RMIL_DEFAULT);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+/**
+ */
+static PyObject * doDelMacro(PyObject * self, PyObject * args) {
+    char * name;
+
+    if (!PyArg_ParseTuple(args, "s", &name))
+       return NULL;
+
+    delMacro(NULL, name);
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
+/**
+ */
+static PyObject * archScore(PyObject * self, PyObject * args) {
+    char * arch;
+    int score;
+
+    if (!PyArg_ParseTuple(args, "s", &arch))
+       return NULL;
+
+    score = rpmMachineScore(RPM_MACHTABLE_INSTARCH, arch);
+
+    return Py_BuildValue("i", score);
+}
+
+/**
+ */
+static int psGetArchScore(Header h) {
+    void * pkgArch;
+    int type, count;
+
+    if (!headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &pkgArch, &count) ||
+        type == RPM_INT8_TYPE)
+       return 150;
+    else
+        return rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch);
+}
+
+/**
+ */
+static int pkgCompareVer(void * first, void * second) {
+    struct packageInfo ** a = first;
+    struct packageInfo ** b = second;
+    int ret, score1, score2;
+
+    /* put packages w/o names at the end */
+    if (!(*a)->name) return 1;
+    if (!(*b)->name) return -1;
+
+    ret = xstrcasecmp((*a)->name, (*b)->name);
+    if (ret) return ret;
+    score1 = psGetArchScore((*a)->h);
+    if (!score1) return 1;
+    score2 = psGetArchScore((*b)->h);
+    if (!score2) return -1;
+    if (score1 < score2) return -1;
+    if (score1 > score2) return 1;
+    return rpmVersionCompare((*b)->h, (*a)->h);
+}
+
+/**
+ */
+static void pkgSort(struct pkgSet * psp) {
+    int i;
+    char *name;
+
+    if (psp->numPackages <= 0)
+       return;
+
+    qsort(psp->packages, psp->numPackages, sizeof(*psp->packages),
+        (void *) pkgCompareVer);
+
+    name = psp->packages[0]->name;
+    if (!name) {
+       psp->numPackages = 0;
+       return;
+    }
+    for (i = 1; i < psp->numPackages; i++) {
+       if (!psp->packages[i]->name) break;
+       if (!strcmp(psp->packages[i]->name, name))
+          psp->packages[i]->name = NULL;
+       else
+          name = psp->packages[i]->name;
+    }
+
+    qsort(psp->packages, psp->numPackages, sizeof(*psp->packages),
+        (void *) pkgCompareVer);
+
+    for (i = 0; i < psp->numPackages; i++)
+       if (!psp->packages[i]->name) break;
+    psp->numPackages = i;
+}
+
+/**
+ */
+static PyObject * findUpgradeSet(PyObject * self, PyObject * args) {
+    PyObject * hdrList, * result;
+    char * root = "/";
+    int i;
+    struct pkgSet list;
+    hdrObject * hdr;
+
+    if (!PyArg_ParseTuple(args, "O|s", &hdrList, &root)) return NULL;
+
+    if (!PyList_Check(hdrList)) {
+       PyErr_SetString(PyExc_TypeError, "list of headers expected");
+       return NULL;
+    }
+
+    list.numPackages = PyList_Size(hdrList);
+    list.packages = alloca(sizeof(list.packages) * list.numPackages);
+    for (i = 0; i < list.numPackages; i++) {
+       hdr = (hdrObject *) PyList_GetItem(hdrList, i);
+       if (((PyObject *) hdr)->ob_type != &hdrType) {
+           PyErr_SetString(PyExc_TypeError, "list of headers expected");
+           return NULL;
+       }
+       list.packages[i] = alloca(sizeof(struct packageInfo));
+       list.packages[i]->h = hdrGetHeader(hdr);
+       list.packages[i]->selected = 0;
+       list.packages[i]->data = hdr;
+
+       headerGetEntry(list.packages[i]->h, RPMTAG_NAME, NULL,
+                     (void **) &list.packages[i]->name, NULL);
+    }
+
+    pkgSort (&list);
+
+    if (ugFindUpgradePackages(&list, root)) {
+       PyErr_SetString(pyrpmError, "error during upgrade check");
+       return NULL;
+    }
+
+    result = PyList_New(0);
+    for (i = 0; i < list.numPackages; i++) {
+       if (list.packages[i]->selected) {
+           PyList_Append(result, list.packages[i]->data);
+/*         Py_DECREF(list.packages[i]->data); */
+       }
+    }
+
+    return result;
+}
+
+/**
+ */
+static PyObject * rpmInitDB(PyObject * self, PyObject * args) {
+    char *root;
+    int forWrite = 0;
+
+    if (!PyArg_ParseTuple(args, "i|s", &forWrite, &root)) return NULL;
+
+    if (rpmdbInit(root, forWrite ? O_RDWR | O_CREAT: O_RDONLY)) {
+       char * errmsg = "cannot initialize database in %s";
+       char * errstr = NULL;
+       int errsize;
+
+       errsize = strlen(errmsg) + strlen(root);
+       errstr = alloca(errsize);
+       snprintf(errstr, errsize, errmsg, root);
+       PyErr_SetString(pyrpmError, errstr);
+       return NULL;
+    }
+
+    Py_INCREF(Py_None);
+    return(Py_None);
+}
+
+/**
+ */
+static PyObject * errorCB = NULL, * errorData = NULL;
+
+/**
+ */
+static void errorcb (void)
+{
+    PyObject * result, * args = NULL;
+
+    if (errorData)
+       args = Py_BuildValue("(O)", errorData);
+
+    result = PyEval_CallObject(errorCB, args);
+    Py_XDECREF(args);
+
+    if (result == NULL) {
+       PyErr_Print();
+       PyErr_Clear();
+    }
+    Py_DECREF (result);
+}
+
+/**
+ */
+static PyObject * errorSetCallback (PyObject * self, PyObject * args) {
+    PyObject *newCB = NULL, *newData = NULL;
+
+    if (!PyArg_ParseTuple(args, "O|O", &newCB, &newData)) return NULL;
+
+    /* if we're getting a void*, set the error callback to this. */
+    /* also, we can possibly decref any python callbacks we had  */
+    /* and set them to NULL.                                     */
+    if (PyCObject_Check (newCB)) {
+       rpmErrorSetCallback (PyCObject_AsVoidPtr(newCB));
+
+       Py_XDECREF (errorCB);
+       Py_XDECREF (errorData);
+
+       errorCB   = NULL;
+       errorData = NULL;
+       
+       Py_INCREF(Py_None);
+       return Py_None;
+    }
+    
+    if (!PyCallable_Check (newCB)) {
+       PyErr_SetString(PyExc_TypeError, "parameter must be callable");
+       return NULL;
+    }
+
+    Py_XDECREF(errorCB);
+    Py_XDECREF(errorData);
+
+    errorCB = newCB;
+    errorData = newData;
+    
+    Py_INCREF (errorCB);
+    Py_XINCREF (errorData);
+
+    return PyCObject_FromVoidPtr(rpmErrorSetCallback (errorcb), NULL);
+}
+
+/**
+ */
+static PyObject * errorString (PyObject * self, PyObject * args) {
+    return PyString_FromString(rpmErrorString ());
+}
+
+/**
+ */
+static PyObject * checkSig (PyObject * self, PyObject * args) {
+    char * filename;
+    int flags;
+    int rc = 255;
+
+    if (PyArg_ParseTuple(args, "si", &filename, &flags)) {
+       rpmTransactionSet ts;
+       const char * av[2];
+       QVA_t ka = memset(alloca(sizeof(*ka)), 0, sizeof(*ka));
+
+       av[0] = filename;
+       av[1] = NULL;
+       ka->qva_mode = 'K';
+       ka->qva_flags = (VERIFY_DIGEST|VERIFY_SIGNATURE);
+       ka->sign = 0;
+       ka->passPhrase = NULL;
+       ts = rpmtransCreateSet(NULL, NULL);
+       rc = rpmcliSign(ts, ka, av);
+       rpmtransFree(ts);
+    }
+    return Py_BuildValue("i", rc);
+}
+
+/* hack to get the current header that's in the transaction set */
+/**
+ */
+static PyObject * getTsHeader (PyObject * self, PyObject * args) {
+
+    if (!PyArg_ParseTuple(args, ""))
+       return NULL;
+    
+    if (transactionSetHeader) {
+       return (PyObject *) createHeaderObject(transactionSetHeader);
+    }
+    Py_INCREF(Py_None);
+    return (PyObject *) Py_None;
+}
+
+static PyObject * setVerbosity (PyObject * self, PyObject * args) {
+    int level;
+
+    if (!PyArg_ParseTuple(args, "i", &level))
+       return NULL;
+
+    rpmSetVerbosity(level);
+
+    Py_INCREF(Py_None);
+    return (PyObject *) Py_None;
+}
+
+/**
+ */
+typedef struct FDlist_t FDlist;
+
+/**
+ */
+struct FDlist_t {
+    FILE *f;
+    FD_t fd;
+    char *note;
+    FDlist *next;
+} ;
+
+/**
+ */
+static FDlist *fdhead = NULL;
+
+/**
+ */
+static FDlist *fdtail = NULL;
+
+/**
+ */
+static int closeCallback(FILE * f) {
+    FDlist *node, *last;
+
+    printf ("close callback on %p\n", f);
+    
+    node = fdhead;
+    last = NULL;
+    while (node) {
+        if (node->f == f)
+            break;
+        last = node;
+        node = node->next;
+    }
+    if (node) {
+        if (last)
+            last->next = node->next;
+        else
+            fdhead = node->next;
+        printf ("closing %s %p\n", node->note, node->fd);
+       free (node->note);
+        node->fd = fdLink(node->fd, "closeCallback");
+        Fclose (node->fd);
+        while (node->fd)
+            node->fd = fdFree(node->fd, "closeCallback");
+        free (node);
+    }
+    return 0; 
+}
+
+/**
+ */
+static PyObject * doFopen(PyObject * self, PyObject * args) {
+    char * path, * mode;
+    FDlist *node;
+    
+    if (!PyArg_ParseTuple(args, "ss", &path, &mode))
+       return NULL;
+    
+    node = malloc (sizeof(FDlist));
+    
+    node->fd = Fopen(path, mode);
+    node->fd = fdLink(node->fd, "doFopen");
+    node->note = strdup (path);
+
+    if (!node->fd) {
+       PyErr_SetFromErrno(pyrpmError);
+        free (node);
+       return NULL;
+    }
+    
+    if (Ferror(node->fd)) {
+       const char *err = Fstrerror(node->fd);
+        free(node);
+       if (err) {
+           PyErr_SetString(pyrpmError, err);
+           return NULL;
+       }
+    }
+    node->f = fdGetFp(node->fd);
+    printf ("opening %s fd = %p f = %p\n", node->note, node->fd, node->f);
+    if (!node->f) {
+       PyErr_SetString(pyrpmError, "FD_t has no FILE*");
+        free(node);
+       return NULL;
+    }
+
+    node->next = NULL;
+    if (!fdhead) {
+       fdhead = fdtail = node;
+    } else if (fdtail) {
+        fdtail->next = node;
+    } else {
+        fdhead = node;
+    }
+    fdtail = node;
+    
+    return PyFile_FromFile (node->f, path, mode, closeCallback);
+}
+
+/**
+ */
+static PyMethodDef rpmModuleMethods[] = {
+    { "TransactionSet", (PyCFunction) rpmtransCreate, METH_VARARGS, NULL },
+    { "addMacro", (PyCFunction) doAddMacro, METH_VARARGS, NULL },
+    { "delMacro", (PyCFunction) doDelMacro, METH_VARARGS, NULL },
+    { "archscore", (PyCFunction) archScore, METH_VARARGS, NULL },
+    { "findUpgradeSet", (PyCFunction) findUpgradeSet, METH_VARARGS, NULL },
+    { "headerFromPackage", (PyCFunction) rpmHeaderFromPackage, METH_VARARGS, NULL },
+    { "headerLoad", (PyCFunction) hdrLoad, METH_VARARGS, NULL },
+    { "rhnLoad", (PyCFunction) rhnLoad, METH_VARARGS, NULL },
+    { "initdb", (PyCFunction) rpmInitDB, METH_VARARGS, NULL },
+    { "opendb", (PyCFunction) rpmOpenDB, METH_VARARGS, NULL },
+    { "rebuilddb", (PyCFunction) rebuildDB, METH_VARARGS, NULL },
+    { "mergeHeaderListFromFD", (PyCFunction) rpmMergeHeadersFromFD, METH_VARARGS, NULL },
+    { "readHeaderListFromFD", (PyCFunction) rpmHeaderFromFD, METH_VARARGS, NULL },
+    { "readHeaderListFromFile", (PyCFunction) rpmHeaderFromFile, METH_VARARGS, NULL },
+    { "errorSetCallback", (PyCFunction) errorSetCallback, METH_VARARGS, NULL },
+    { "errorString", (PyCFunction) errorString, METH_VARARGS, NULL },
+    { "versionCompare", (PyCFunction) versionCompare, METH_VARARGS, NULL },
+    { "labelCompare", (PyCFunction) labelCompare, METH_VARARGS, NULL },
+    { "checksig", (PyCFunction) checkSig, METH_VARARGS, NULL },
+    { "getTransactionCallbackHeader", (PyCFunction) getTsHeader, METH_VARARGS, NULL },
+    { "Fopen", (PyCFunction) doFopen, METH_VARARGS, NULL },
+    { "setVerbosity", (PyCFunction) setVerbosity, METH_VARARGS, NULL },
+    { NULL }
+} ;
+
+/**
+ */
+void initrpm(void) {
+    PyObject * m, * d, *o, * tag = NULL, * dict;
+    int i;
+    const struct headerSprintfExtension_s * extensions = rpmHeaderFormats;
+    struct headerSprintfExtension_s * ext;
+    m = Py_InitModule("rpm", rpmModuleMethods);
+
+    hdrType.ob_type = &PyType_Type;
+    rpmdbMIType.ob_type = &PyType_Type;
+    rpmdbType.ob_type = &PyType_Type;
+    rpmtransType.ob_type = &PyType_Type;
+
+    if(!m)
+       return;
+
+/*      _rpmio_debug = -1; */
+    rpmReadConfigFiles(NULL, NULL);
+
+    d = PyModule_GetDict(m);
+
+    pyrpmError = PyString_FromString("rpm.error");
+    PyDict_SetItemString(d, "error", pyrpmError);
+    Py_DECREF(pyrpmError);
+
+    dict = PyDict_New();
+
+    for (i = 0; i < rpmTagTableSize; i++) {
+       tag = PyInt_FromLong(rpmTagTable[i].val);
+       PyDict_SetItemString(d, (char *) rpmTagTable[i].name, tag);
+       Py_DECREF(tag);
+        PyDict_SetItem(dict, tag, o=PyString_FromString(rpmTagTable[i].name + 7));
+       Py_DECREF(o);
+    }
+
+    while (extensions->name) {
+       if (extensions->type == HEADER_EXT_TAG) {
+            (const struct headerSprintfExtension *) ext = extensions;
+            PyDict_SetItemString(d, (char *) extensions->name, o=PyCObject_FromVoidPtr(ext, NULL));
+           Py_DECREF(o);
+            PyDict_SetItem(dict, tag, o=PyString_FromString(ext->name + 7));
+           Py_DECREF(o);    
+        }
+        extensions++;
+    }
+
+    PyDict_SetItemString(d, "tagnames", dict);
+    Py_DECREF(dict);
+
+
+#define REGISTER_ENUM(val) \
+    PyDict_SetItemString(d, #val, o=PyInt_FromLong( val )); \
+    Py_DECREF(o);
+    
+    REGISTER_ENUM(RPMFILE_STATE_NORMAL);
+    REGISTER_ENUM(RPMFILE_STATE_REPLACED);
+    REGISTER_ENUM(RPMFILE_STATE_NOTINSTALLED);
+    REGISTER_ENUM(RPMFILE_STATE_NETSHARED);
+
+    REGISTER_ENUM(RPMFILE_CONFIG);
+    REGISTER_ENUM(RPMFILE_DOC);
+    REGISTER_ENUM(RPMFILE_MISSINGOK);
+    REGISTER_ENUM(RPMFILE_NOREPLACE);
+    REGISTER_ENUM(RPMFILE_GHOST);
+    REGISTER_ENUM(RPMFILE_LICENSE);
+    REGISTER_ENUM(RPMFILE_README);
+
+    REGISTER_ENUM(RPMDEP_SENSE_REQUIRES);
+    REGISTER_ENUM(RPMDEP_SENSE_CONFLICTS);
+
+    REGISTER_ENUM(RPMSENSE_SERIAL);
+    REGISTER_ENUM(RPMSENSE_LESS);
+    REGISTER_ENUM(RPMSENSE_GREATER);
+    REGISTER_ENUM(RPMSENSE_EQUAL);
+    REGISTER_ENUM(RPMSENSE_PREREQ);
+    REGISTER_ENUM(RPMSENSE_INTERP);
+    REGISTER_ENUM(RPMSENSE_SCRIPT_PRE);
+    REGISTER_ENUM(RPMSENSE_SCRIPT_POST);
+    REGISTER_ENUM(RPMSENSE_SCRIPT_PREUN);
+    REGISTER_ENUM(RPMSENSE_SCRIPT_POSTUN);
+    REGISTER_ENUM(RPMSENSE_SCRIPT_VERIFY);
+    REGISTER_ENUM(RPMSENSE_FIND_REQUIRES);
+    REGISTER_ENUM(RPMSENSE_FIND_PROVIDES);
+    REGISTER_ENUM(RPMSENSE_TRIGGERIN);
+    REGISTER_ENUM(RPMSENSE_TRIGGERUN);
+    REGISTER_ENUM(RPMSENSE_TRIGGERPOSTUN);
+    REGISTER_ENUM(RPMSENSE_MULTILIB);
+    REGISTER_ENUM(RPMSENSE_SCRIPT_PREP);
+    REGISTER_ENUM(RPMSENSE_SCRIPT_BUILD);
+    REGISTER_ENUM(RPMSENSE_SCRIPT_INSTALL);
+    REGISTER_ENUM(RPMSENSE_SCRIPT_CLEAN);
+    REGISTER_ENUM(RPMSENSE_RPMLIB);
+    REGISTER_ENUM(RPMSENSE_TRIGGERPREIN);
+
+    REGISTER_ENUM(RPMTRANS_FLAG_TEST);
+    REGISTER_ENUM(RPMTRANS_FLAG_BUILD_PROBS);
+    REGISTER_ENUM(RPMTRANS_FLAG_NOSCRIPTS);
+    REGISTER_ENUM(RPMTRANS_FLAG_JUSTDB);
+    REGISTER_ENUM(RPMTRANS_FLAG_NOTRIGGERS);
+    REGISTER_ENUM(RPMTRANS_FLAG_NODOCS);
+    REGISTER_ENUM(RPMTRANS_FLAG_ALLFILES);
+    REGISTER_ENUM(RPMTRANS_FLAG_KEEPOBSOLETE);
+    REGISTER_ENUM(RPMTRANS_FLAG_MULTILIB);
+
+    REGISTER_ENUM(RPMPROB_FILTER_IGNOREOS);
+    REGISTER_ENUM(RPMPROB_FILTER_IGNOREARCH);
+    REGISTER_ENUM(RPMPROB_FILTER_REPLACEPKG);
+    REGISTER_ENUM(RPMPROB_FILTER_FORCERELOCATE);
+    REGISTER_ENUM(RPMPROB_FILTER_REPLACENEWFILES);
+    REGISTER_ENUM(RPMPROB_FILTER_REPLACEOLDFILES);
+    REGISTER_ENUM(RPMPROB_FILTER_OLDPACKAGE);
+    REGISTER_ENUM(RPMPROB_FILTER_DISKSPACE);
+    REGISTER_ENUM(RPMPROB_FILTER_DISKNODES);
+
+    REGISTER_ENUM(RPMCALLBACK_INST_PROGRESS);
+    REGISTER_ENUM(RPMCALLBACK_INST_START);
+    REGISTER_ENUM(RPMCALLBACK_INST_OPEN_FILE);
+    REGISTER_ENUM(RPMCALLBACK_INST_CLOSE_FILE);
+    REGISTER_ENUM(RPMCALLBACK_TRANS_PROGRESS);
+    REGISTER_ENUM(RPMCALLBACK_TRANS_START);
+    REGISTER_ENUM(RPMCALLBACK_TRANS_STOP);
+    REGISTER_ENUM(RPMCALLBACK_UNINST_PROGRESS);
+    REGISTER_ENUM(RPMCALLBACK_UNINST_START);
+    REGISTER_ENUM(RPMCALLBACK_UNINST_STOP);
+    REGISTER_ENUM(RPMCALLBACK_UNPACK_ERROR);
+    REGISTER_ENUM(RPMCALLBACK_CPIO_ERROR);
+
+    REGISTER_ENUM(RPMPROB_BADARCH);
+    REGISTER_ENUM(RPMPROB_BADOS);
+    REGISTER_ENUM(RPMPROB_PKG_INSTALLED);
+    REGISTER_ENUM(RPMPROB_BADRELOCATE);
+    REGISTER_ENUM(RPMPROB_REQUIRES);
+    REGISTER_ENUM(RPMPROB_CONFLICT);
+    REGISTER_ENUM(RPMPROB_NEW_FILE_CONFLICT);
+    REGISTER_ENUM(RPMPROB_FILE_CONFLICT);
+    REGISTER_ENUM(RPMPROB_OLDPACKAGE);
+    REGISTER_ENUM(RPMPROB_DISKSPACE);
+    REGISTER_ENUM(RPMPROB_DISKNODES);
+    REGISTER_ENUM(RPMPROB_BADPRETRANS);
+
+#ifdef DEAD
+    REGISTER_ENUM(CHECKSIG_PGP);       /* XXX use VERIFY_SIGNATURE */
+    REGISTER_ENUM(CHECKSIG_GPG);       /* XXX use VERIFY_SIGNATURE */
+    REGISTER_ENUM(CHECKSIG_MD5);       /* XXX use VERIFY_DIGEST */
+#else
+    REGISTER_ENUM(VERIFY_DIGEST);
+    REGISTER_ENUM(VERIFY_SIGNATURE);
+#endif
+
+    REGISTER_ENUM(RPMLOG_EMERG);
+    REGISTER_ENUM(RPMLOG_ALERT);
+    REGISTER_ENUM(RPMLOG_CRIT);
+    REGISTER_ENUM(RPMLOG_ERR);
+    REGISTER_ENUM(RPMLOG_WARNING);
+    REGISTER_ENUM(RPMLOG_NOTICE);
+    REGISTER_ENUM(RPMLOG_INFO);
+    REGISTER_ENUM(RPMLOG_DEBUG);
+
+    REGISTER_ENUM(RPMMIRE_DEFAULT);
+    REGISTER_ENUM(RPMMIRE_STRCMP);
+    REGISTER_ENUM(RPMMIRE_REGEX);
+    REGISTER_ENUM(RPMMIRE_GLOB);
+
+}
+
+/*@}*/