In Python 3, return all our string data as surrogate-escaped utf-8 strings
[platform/upstream/rpm.git] / python / rpmts-py.c
index 85c8cb2..779599a 100644 (file)
@@ -1,8 +1,6 @@
-/** \ingroup py_c
- * \file python/rpmts-py.c
- */
+#include "rpmsystem-py.h"
 
-#include "system.h"
+#include <fcntl.h>
 
 #include <rpm/rpmlib.h>        /* rpmReadPackageFile, headerCheck */
 #include <rpm/rpmtag.h>
 
 #include "header-py.h"
 #include "rpmds-py.h"  /* XXX for rpmdsNew */
+#include "rpmfd-py.h"
+#include "rpmkeyring-py.h"
 #include "rpmfi-py.h"  /* XXX for rpmfiNew */
 #include "rpmmi-py.h"
+#include "rpmii-py.h"
 #include "rpmps-py.h"
 #include "rpmte-py.h"
-#include "spec-py.h"
-
 #include "rpmts-py.h"
 
-#include "debug.h"
-
-extern int _rpmts_debug;
-
-
 /** \ingroup python
  * \name Class: Rpmts
  * \class Rpmts
@@ -57,10 +51,7 @@ extern int _rpmts_debug;
  * @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').
+ *             be installed ('i'), upgraded ('u').
  *
  * - addErase(name) Add an erase element to a transaction set.
  * @param name the package name to be erased
@@ -105,23 +96,26 @@ extern int _rpmts_debug;
  * @return     None
  *
  * - ts.setFlags(transFlags) Set transaction set flags.
- * @param transFlags - bit(s) to controll transaction operations. The
+ * @param transFlags - bit(s) to control transaction operations. The
  *             following values can be logically OR'ed 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_NOSCRIPTS - do not execute package scripts
  *     - rpm.RPMTRANS_FLAG_NOTRIGGERS - do not run trigger scripts
+ *     - rpm.RPMTRANS_FLAG_NO* - disable specific scripts and triggers
  *     - rpm.RPMTRANS_FLAG_NODOCS - do not install files marked as %doc
+ *     - rpm.RPMTRANS_FLAG_NOPLUGINS - do not run plugins
+ *     - rpm.RPMTRANS_FLAG_NOFILEDIGEST - disable checking checksums
  *     - 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.
+ *     - rpm.RPMTRANS_FLAG_NOCONFIGS - skip config files
+ *     - rpm.RPMTRANS_FLAG_DEPLOOPS - enable debugging for dependency loops
  * @return     previous transFlags
  *
  * - ts.setProbFilter(ignoreSet) Set transaction set problem filter.
@@ -143,182 +137,87 @@ extern int _rpmts_debug;
  *     the ts.run() method.
  */
 
-/** \ingroup py_c
- */
+struct rpmtsObject_s {
+    PyObject_HEAD
+    PyObject *md_dict;         /*!< to look like PyModuleObject */
+    rpmfdObject *scriptFd;
+    PyObject *keyList;
+    rpmts      ts;
+    rpmtsi tsi;
+};
+
 struct rpmtsCallbackType_s {
     PyObject * cb;
     PyObject * data;
     rpmtsObject * tso;
-    int pythonError;
     PyThreadState *_save;
 };
 
-/** \ingroup py_c
- */
-static PyObject *
-rpmts_Debug(rpmtsObject * s, PyObject * args, PyObject * kwds)
-{
-    char * kwlist[] = {"debugLevel", NULL};
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Debug", kwlist,
-           &_rpmts_debug))
-       return NULL;
-
-if (_rpmts_debug < 0)
-fprintf(stderr, "*** rpmts_Debug(%p) ts %p\n", s, s->ts);
-
-    Py_INCREF(Py_None);
-    return Py_None;
-}
-
-#if 0
-/** \ingroup py_c
- * Add package to universe of possible packages to install in transaction set.
- * @param ts           transaction set
- * @param h            header
- * @param key          package private data
- */
-static void rpmtsAddAvailableElement(rpmts ts, Header h,
-               fnpyKey key)
+RPM_GNUC_NORETURN
+static void die(PyObject *cb)
 {
-    int scareMem = 0;
-    rpmds provides = rpmdsNew(h, RPMTAG_PROVIDENAME, scareMem);
-    rpmfi fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
-
-    /* XXX FIXME: return code RPMAL_NOMATCH is error */
-    (void) rpmalAdd(&ts->availablePackages, RPMAL_NOMATCH, key,
-               provides, fi, rpmtsColor(ts));
-    fi = rpmfiFree(fi);
-    provides = rpmdsFree(provides);
-
-if (_rpmts_debug < 0)
-fprintf(stderr, "\tAddAvailable(%p) list %p\n", ts, ts->availablePackages);
+    char *pyfn = NULL;
+    PyObject *r;
 
+    if (PyErr_Occurred()) {
+       PyErr_Print();
+    }
+    if ((r = PyObject_Repr(cb)) != NULL) { 
+       pyfn = PyBytes_AsString(r);
+    }
+    fprintf(stderr, "FATAL ERROR: python callback %s failed, aborting!\n", 
+                     pyfn ? pyfn : "???");
+    exit(EXIT_FAILURE);
 }
-#endif
 
-/** \ingroup py_c
- */
 static PyObject *
-rpmts_AddInstall(rpmtsObject * s, PyObject * args, PyObject * kwds)
+rpmts_AddInstall(rpmtsObject * s, PyObject * args)
 {
-    hdrObject * h;
+    Header h = NULL;
     PyObject * key;
-    char * how = "u";  /* XXX default to upgrade element if missing */
-    int isUpgrade = 0;
-    char * kwlist[] = {"header", "key", "how", NULL};
-    int rc = 0;
+    int how = 0;
+    int rc;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O|s:AddInstall", kwlist,
-           &hdr_Type, &h, &key, &how))
+    if (!PyArg_ParseTuple(args, "O&Oi:AddInstall", 
+                         hdrFromPyObject, &h, &key, &how))
        return NULL;
 
-    {  PyObject * hObj = (PyObject *) h;
-       if (hObj->ob_type != &hdr_Type) {
-           PyErr_SetString(PyExc_TypeError, "bad type for header argument");
-           return NULL;
-       }
+    rc = rpmtsAddInstallElement(s->ts, h, key, how, NULL);
+    if (key && rc == 0) {
+       PyList_Append(s->keyList, key);
     }
+    return PyBool_FromLong((rc == 0));
+}
 
-if (_rpmts_debug < 0 || (_rpmts_debug > 0 && *how != 'a'))
-fprintf(stderr, "*** rpmts_AddInstall(%p,%p,%p,%s) ts %p\n", s, h, key, how, s->ts);
+static PyObject *
+rpmts_AddReinstall(rpmtsObject * s, PyObject * args)
+{
+    Header h = NULL;
+    PyObject * key;
+    int rc;
 
-    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;
-
-    /*
-     * XXX resurrect when better available mechanism is, well, available.
-     * OTOH nothing appears to use it these days...
-     * Raise exception to catch out any callers while broken.
-     */
-    if (how && !strcmp(how, "a")) {
-#ifdef DYING
-       rpmtsAddAvailableElement(s->ts, hdrGetHeader(h), key); 
-#else
-       PyErr_SetString(pyrpmError, "available package mechanism currently broken");
+    if (!PyArg_ParseTuple(args, "O&O:AddReinstall", 
+                         hdrFromPyObject, &h, &key))
        return NULL;
-#endif
-    } else
-       rc = rpmtsAddInstallElement(s->ts, hdrGetHeader(h), key, isUpgrade, NULL);
-    if (rc) {
-       PyErr_SetString(pyrpmError, "adding package to transaction failed");
-       return NULL;
-    }
-       
 
-    /* This should increment the usage count for me */
-    if (key)
+    rc = rpmtsAddReinstallElement(s->ts, h, key);
+    if (key && rc == 0) {
        PyList_Append(s->keyList, key);
-
-    Py_INCREF(Py_None);
-    return Py_None;
+    }
+    return PyBool_FromLong((rc == 0));
 }
 
-/** \ingroup py_c
- * @todo Permit finer control (i.e. not just --allmatches) of deleted elments.
- */
 static PyObject *
-rpmts_AddErase(rpmtsObject * s, PyObject * args, PyObject * kwds)
+rpmts_AddErase(rpmtsObject * s, PyObject * args)
 {
-    PyObject * o;
-    int count;
-    rpmdbMatchIterator mi;
-    char * kwlist[] = {"name", NULL};
-
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_AddErase(%p) ts %p\n", s, s->ts);
+    Header h;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:AddErase", kwlist, &o))
+    if (!PyArg_ParseTuple(args, "O&:AddErase", hdrFromPyObject, &h))
         return NULL;
 
-    if (PyString_Check(o)) {
-       char * name = PyString_AsString(o);
-
-       mi = rpmtsInitIterator(s->ts, RPMDBI_LABEL, name, 0);
-       count = rpmdbGetIteratorCount(mi);
-       if (count <= 0) {
-           mi = rpmdbFreeIterator(mi);
-           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)
-                   rpmtsAddEraseElement(s->ts, h, recOffset);
-           }
-       }
-       mi = rpmdbFreeIterator(mi);
-    } else
-    if (PyInt_Check(o)) {
-       uint32_t instance = PyInt_AsLong(o);
-
-       mi = rpmtsInitIterator(s->ts, RPMDBI_PACKAGES, &instance, sizeof(instance));
-       if (instance == 0 || mi == NULL) {
-           mi = rpmdbFreeIterator(mi);
-           PyErr_SetString(pyrpmError, "package not installed");
-           return NULL;
-       } else {
-           Header h;
-           while ((h = rpmdbNextIterator(mi)) != NULL) {
-               uint32_t recOffset = rpmdbGetIteratorOffset(mi);
-               if (recOffset)
-                   rpmtsAddEraseElement(s->ts, h, recOffset);
-               break;
-           }
-       }
-       mi = rpmdbFreeIterator(mi);
-    }
-
-    Py_INCREF(Py_None);
-    return Py_None;
+    return PyBool_FromLong(rpmtsAddEraseElement(s->ts, h, -1) == 0);
 }
 
-/** \ingroup py_c
- */
 static int
 rpmts_SolveCallback(rpmts ts, rpmds ds, const void * data)
 {
@@ -326,22 +225,19 @@ rpmts_SolveCallback(rpmts ts, rpmds ds, const void * data)
     PyObject * args, * result;
     int res = 1;
 
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_SolveCallback(%p,%p,%p) \"%s\"\n", ts, ds, data, rpmdsDNEVR(ds));
-
     if (cbInfo->tso == NULL) return res;
-    if (cbInfo->pythonError) return res;
     if (cbInfo->cb == Py_None) return res;
 
     PyEval_RestoreThread(cbInfo->_save);
 
-    args = Py_BuildValue("(Oissi)", cbInfo->tso,
-               rpmdsTagN(ds), rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds));
+    args = Py_BuildValue("(OiNNi)", cbInfo->tso,
+               rpmdsTagN(ds), utf8FromString(rpmdsN(ds)),
+               utf8FromString(rpmdsEVR(ds)), rpmdsFlags(ds));
     result = PyEval_CallObject(cbInfo->cb, args);
     Py_DECREF(args);
 
     if (!result) {
-       cbInfo->pythonError = 1;
+       die(cbInfo->cb);
     } else {
        if (PyInt_Check(result))
            res = PyInt_AsLong(result);
@@ -353,17 +249,11 @@ fprintf(stderr, "*** rpmts_SolveCallback(%p,%p,%p) \"%s\"\n", ts, ds, data, rpmd
     return res;
 }
 
-/** \ingroup py_c
- */
 static PyObject *
 rpmts_Check(rpmtsObject * s, PyObject * args, PyObject * kwds)
 {
-    rpmps ps;
-    rpmProblem p;
-    PyObject * list, * cf;
     struct rpmtsCallbackType_s cbInfo;
-    int i;
-    int xx;
+    int rc;
     char * kwlist[] = {"callback", NULL};
 
     memset(&cbInfo, 0, sizeof(cbInfo));
@@ -376,101 +266,24 @@ rpmts_Check(rpmtsObject * s, PyObject * args, PyObject * kwds)
            PyErr_SetString(PyExc_TypeError, "expected a callable");
            return NULL;
        }
-       xx = rpmtsSetSolveCallback(s->ts, rpmts_SolveCallback, (void *)&cbInfo);
+       rc = rpmtsSetSolveCallback(s->ts, rpmts_SolveCallback, (void *)&cbInfo);
     }
 
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_Check(%p) ts %p cb %p\n", s, s->ts, cbInfo.cb);
-
     cbInfo.tso = s;
-    cbInfo.pythonError = 0;
     cbInfo._save = PyEval_SaveThread();
 
-#ifdef DYING
-    /* XXX resurrect availablePackages one more time ... */
-    rpmalMakeIndex(s->ts->availablePackages);
-#endif
-
-    xx = rpmtsCheck(s->ts);
-    ps = rpmtsProblems(s->ts);
-
-    if (cbInfo.cb)
-       xx = rpmtsSetSolveCallback(s->ts, rpmtsSolve, NULL);
+    rc = rpmtsCheck(s->ts);
 
     PyEval_RestoreThread(cbInfo._save);
 
-    if (ps != NULL) {
-       list = PyList_New(0);
-       rpmpsi psi = rpmpsInitIterator(ps);
-
-       /* XXX TODO: rpmlib >= 4.0.3 can return multiple suggested keys. */
-       while ((i = rpmpsNextIterator(psi)) >= 0) {
-           const char * needsName;
-           char * byName, * byVersion, * byRelease, *byArch;
-           char * needsOP, * needsVersion;
-           rpmsenseFlags needsFlags, sense;
-           fnpyKey key;
-
-           p = rpmpsGetProblem(psi);
-
-           byName = strdup(rpmProblemGetPkgNEVR(p));
-           if ((byArch= strrchr(byName, '.')) != NULL)
-               *byArch++ = '\0';
-           if ((byRelease = strrchr(byName, '-')) != NULL)
-               *byRelease++ = '\0';
-           if ((byVersion = strrchr(byName, '-')) != NULL)
-               *byVersion++ = '\0';
-
-           key = rpmProblemGetKey(p);
-
-           needsName = rpmProblemGetAltNEVR(p);
-           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);
-           PyList_Append(list, (PyObject *) cf);
-           Py_DECREF(cf);
-           free(byName);
-       }
-
-       psi = rpmpsFreeIterator(psi);
-       ps = rpmpsFree(ps);
-
-       return list;
-    }
-
-    Py_INCREF(Py_None);
-    return Py_None;
+    return PyBool_FromLong((rc == 0));
 }
 
-/** \ingroup py_c
- */
 static PyObject *
 rpmts_Order(rpmtsObject * s)
 {
     int rc;
 
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_Order(%p) ts %p\n", s, s->ts);
-
     Py_BEGIN_ALLOW_THREADS
     rc = rpmtsOrder(s->ts);
     Py_END_ALLOW_THREADS
@@ -478,30 +291,27 @@ fprintf(stderr, "*** rpmts_Order(%p) ts %p\n", s, s->ts);
     return Py_BuildValue("i", rc);
 }
 
-/** \ingroup py_c
- */
 static PyObject *
 rpmts_Clean(rpmtsObject * s)
 {
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_Clean(%p) ts %p\n", s, s->ts);
-
     rpmtsClean(s->ts);
 
-    Py_INCREF(Py_None);
-    return Py_None;
+    Py_RETURN_NONE;
+}
+
+static PyObject *
+rpmts_Clear(rpmtsObject * s)
+{
+    rpmtsEmpty(s->ts);
+
+    Py_RETURN_NONE;
 }
 
-/** \ingroup py_c
- */
 static PyObject *
 rpmts_OpenDB(rpmtsObject * s)
 {
     int dbmode;
 
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_OpenDB(%p) ts %p\n", s, s->ts);
-
     dbmode = rpmtsGetDBMode(s->ts);
     if (dbmode == -1)
        dbmode = O_RDONLY;
@@ -509,32 +319,22 @@ fprintf(stderr, "*** rpmts_OpenDB(%p) ts %p\n", s, s->ts);
     return Py_BuildValue("i", rpmtsOpenDB(s->ts, dbmode));
 }
 
-/** \ingroup py_c
- */
 static PyObject *
 rpmts_CloseDB(rpmtsObject * s)
 {
     int rc;
 
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_CloseDB(%p) ts %p\n", s, s->ts);
-
     rc = rpmtsCloseDB(s->ts);
     rpmtsSetDBMode(s->ts, -1); /* XXX disable lazy opens */
 
     return Py_BuildValue("i", rc);
 }
 
-/** \ingroup py_c
- */
 static PyObject *
 rpmts_InitDB(rpmtsObject * s)
 {
     int rc;
 
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_InitDB(%p) ts %p\n", s, s->ts);
-
     rc = rpmtsInitDB(s->ts, O_RDONLY);
     if (rc == 0)
        rc = rpmtsCloseDB(s->ts);
@@ -542,16 +342,11 @@ fprintf(stderr, "*** rpmts_InitDB(%p) ts %p\n", s, s->ts);
     return Py_BuildValue("i", rc);
 }
 
-/** \ingroup py_c
- */
 static PyObject *
 rpmts_RebuildDB(rpmtsObject * s)
 {
     int rc;
 
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_RebuildDB(%p) ts %p\n", s, s->ts);
-
     Py_BEGIN_ALLOW_THREADS
     rc = rpmtsRebuildDB(s->ts);
     Py_END_ALLOW_THREADS
@@ -559,16 +354,11 @@ fprintf(stderr, "*** rpmts_RebuildDB(%p) ts %p\n", s, s->ts);
     return Py_BuildValue("i", rc);
 }
 
-/** \ingroup py_c
- */
 static PyObject *
 rpmts_VerifyDB(rpmtsObject * s)
 {
     int rc;
 
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_VerifyDB(%p) ts %p\n", s, s->ts);
-
     Py_BEGIN_ALLOW_THREADS
     rc = rpmtsVerifyDB(s->ts);
     Py_END_ALLOW_THREADS
@@ -576,161 +366,53 @@ fprintf(stderr, "*** rpmts_VerifyDB(%p) ts %p\n", s, s->ts);
     return Py_BuildValue("i", rc);
 }
 
-/** \ingroup py_c
- */
 static PyObject *
-rpmts_HdrFromFdno(rpmtsObject * s, PyObject * args, PyObject * kwds)
+rpmts_HdrFromFdno(rpmtsObject * s, PyObject *arg)
 {
-    PyObject * result = NULL;
+    PyObject *ho = NULL;
+    rpmfdObject *fdo = NULL;
     Header h;
-    FD_t fd;
-    int fdno;
     rpmRC rpmrc;
-    char * kwlist[] = {"fd", NULL};
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:HdrFromFdno", kwlist,
-           &fdno))
+    if (!PyArg_Parse(arg, "O&:HdrFromFdno", rpmfdFromPyObject, &fdo))
        return NULL;
 
-    fd = fdDup(fdno);
-    rpmrc = rpmReadPackageFile(s->ts, fd, "rpmts_HdrFromFdno", &h);
-    Fclose(fd);
-
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_HdrFromFdno(%p) ts %p rc %d\n", s, s->ts, rpmrc);
-
-    switch (rpmrc) {
-    case RPMRC_OK:
-       if (h)
-           result = Py_BuildValue("N", hdr_Wrap(h));
-       h = headerFree(h);      /* XXX ref held by result */
-       break;
-
-    case RPMRC_NOKEY:
-       PyErr_SetString(pyrpmError, "public key not available");
-       break;
-
-    case RPMRC_NOTTRUSTED:
-       PyErr_SetString(pyrpmError, "public key not trusted");
-       break;
-
-    case RPMRC_NOTFOUND:
-    case RPMRC_FAIL:
-    default:
-       PyErr_SetString(pyrpmError, "error reading package header");
-       break;
-    }
+    Py_BEGIN_ALLOW_THREADS;
+    rpmrc = rpmReadPackageFile(s->ts, rpmfdGetFd(fdo), NULL, &h);
+    Py_END_ALLOW_THREADS;
+    Py_XDECREF(fdo);
 
-    return result;
+    if (rpmrc == RPMRC_OK) {
+       ho = hdr_Wrap(&hdr_Type, h);
+    } else {
+       Py_INCREF(Py_None);
+       ho = Py_None;
+    }
+    return Py_BuildValue("(iN)", rpmrc, ho);
 }
 
-/** \ingroup py_c
- */
 static PyObject *
-rpmts_HdrCheck(rpmtsObject * s, PyObject * args, PyObject * kwds)
+rpmts_HdrCheck(rpmtsObject * s, PyObject *obj)
 {
     PyObject * blob;
-    PyObject * result = NULL;
     char * msg = NULL;
     const void * uh;
     int uc;
     rpmRC rpmrc;
-    char * kwlist[] = {"headers", NULL};
-
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_HdrCheck(%p) ts %p\n", s, s->ts);
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:HdrCheck", kwlist, &blob))
+    if (!PyArg_Parse(obj, "S:HdrCheck", &blob))
        return NULL;
 
-    if (blob == Py_None) {
-       Py_INCREF(Py_None);
-       return Py_None;
-    }
-    if (!PyString_Check(blob)) {
-       PyErr_SetString(pyrpmError, "hdrCheck takes a string of octets");
-       return result;
-    }
-    uh = PyString_AsString(blob);
-    uc = PyString_Size(blob);
+    uh = PyBytes_AsString(blob);
+    uc = PyBytes_Size(blob);
 
+    Py_BEGIN_ALLOW_THREADS;
     rpmrc = headerCheck(s->ts, uh, uc, &msg);
+    Py_END_ALLOW_THREADS;
 
-    switch (rpmrc) {
-    case RPMRC_OK:
-       Py_INCREF(Py_None);
-       result = Py_None;
-       break;
-
-    case RPMRC_NOKEY:
-       PyErr_SetString(pyrpmError, "public key not availaiable");
-       break;
-
-    case RPMRC_NOTTRUSTED:
-       PyErr_SetString(pyrpmError, "public key not trusted");
-       break;
-
-    case RPMRC_FAIL:
-    default:
-       PyErr_SetString(pyrpmError, msg);
-       break;
-    }
-    msg = _free(msg);
-
-    return result;
-}
-
-/** \ingroup py_c
- */
-static PyObject *
-rpmts_SetVSFlags(rpmtsObject * s, PyObject * args, PyObject * kwds)
-{
-    rpmVSFlags vsflags;
-    char * kwlist[] = {"flags", NULL};
-
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_SetVSFlags(%p) ts %p\n", s, s->ts);
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:SetVSFlags", kwlist,
-           &vsflags))
-       return NULL;
-
-    /* XXX FIXME: value check on vsflags, or build pure python object 
-     * for it, and require an object of that type */
-
-    return Py_BuildValue("i", rpmtsSetVSFlags(s->ts, vsflags));
-}
-
-/** \ingroup py_c
- */
-static PyObject *
-rpmts_GetVSFlags(rpmtsObject * s)
-{
-    return Py_BuildValue("i", rpmtsVSFlags(s->ts));
-}
-
-/** \ingroup py_c
- */
-static PyObject *
-rpmts_SetColor(rpmtsObject * s, PyObject * args, PyObject * kwds)
-{
-    rpm_color_t tscolor;
-    char * kwlist[] = {"color", NULL};
-
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_SetColor(%p) ts %p\n", s, s->ts);
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Color", kwlist, &tscolor))
-       return NULL;
-
-    /* XXX FIXME: value check on tscolor, or build pure python object
-     * for it, and require an object of that type */
-
-    return Py_BuildValue("i", rpmtsSetColor(s->ts, tscolor));
+    return Py_BuildValue("(iN)", rpmrc, utf8FromString(msg));
 }
 
-/** \ingroup py_c
- */
 static PyObject *
 rpmts_PgpPrtPkts(rpmtsObject * s, PyObject * args, PyObject * kwds)
 {
@@ -740,30 +422,17 @@ rpmts_PgpPrtPkts(rpmtsObject * s, PyObject * args, PyObject * kwds)
     int rc;
     char * kwlist[] = {"octets", NULL};
 
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_PgpPrtPkts(%p) ts %p\n", s, s->ts);
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:PgpPrtPkts", kwlist, &blob))
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:PgpPrtPkts", kwlist, &blob))
        return NULL;
 
-    if (blob == Py_None) {
-       Py_INCREF(Py_None);
-       return Py_None;
-    }
-    if (!PyString_Check(blob)) {
-       PyErr_SetString(pyrpmError, "pgpPrtPkts takes a string of octets");
-       return NULL;
-    }
-    pkt = (unsigned char *)PyString_AsString(blob);
-    pktlen = PyString_Size(blob);
+    pkt = (unsigned char *)PyBytes_AsString(blob);
+    pktlen = PyBytes_Size(blob);
 
     rc = pgpPrtPkts(pkt, pktlen, NULL, 1);
 
     return Py_BuildValue("i", rc);
 }
 
-/** \ingroup py_c
- */
 static PyObject *
 rpmts_PgpImportPubkey(rpmtsObject * s, PyObject * args, PyObject * kwds)
 {
@@ -773,67 +442,50 @@ rpmts_PgpImportPubkey(rpmtsObject * s, PyObject * args, PyObject * kwds)
     int rc;
     char * kwlist[] = {"pubkey", NULL};
 
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_PgpImportPubkey(%p) ts %p\n", s, s->ts);
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:PgpImportPubkey",
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "S:PgpImportPubkey",
            kwlist, &blob))
        return NULL;
 
-    if (blob == Py_None) {
-       Py_INCREF(Py_None);
-       return Py_None;
-    }
-    if (!PyString_Check(blob)) {
-       PyErr_SetString(pyrpmError, "PgpImportPubkey takes a string of octets");
-       return NULL;
-    }
-    pkt = (unsigned char *)PyString_AsString(blob);
-    pktlen = PyString_Size(blob);
+    pkt = (unsigned char *)PyBytes_AsString(blob);
+    pktlen = PyBytes_Size(blob);
 
     rc = rpmtsImportPubkey(s->ts, pkt, pktlen);
 
     return Py_BuildValue("i", rc);
 }
 
-/** \ingroup py_c
- */
-static PyObject *
-rpmts_GetKeys(rpmtsObject * s)
+static PyObject *rpmts_setKeyring(rpmtsObject *s, PyObject *arg)
 {
-    const void **data = NULL;
-    int num, i;
-    PyObject *tuple;
-
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_GetKeys(%p) ts %p\n", s, s->ts);
-
-    rpmtsGetKeys(s->ts, &data, &num);
-    if (data == NULL || num <= 0) {
-       data = _free(data);
-       Py_INCREF(Py_None);
-       return Py_None;
+    rpmKeyring keyring = NULL;
+    if (arg == Py_None || rpmKeyringFromPyObject(arg, &keyring)) {
+       return PyBool_FromLong(rpmtsSetKeyring(s->ts, keyring) == 0);
+    } else {
+       PyErr_SetString(PyExc_TypeError, "rpm.keyring or None expected");
+       return NULL;
     }
+}
 
-    tuple = PyTuple_New(num);
-
-    for (i = 0; i < num; i++) {
-       PyObject *obj;
-       obj = (data[i] ? (PyObject *) data[i] : Py_None);
-       Py_INCREF(obj);
-       PyTuple_SetItem(tuple, i, obj);
-    }
+static PyObject *rpmts_getKeyring(rpmtsObject *s, PyObject *args, PyObject *kwds)
+{
+    rpmKeyring keyring = NULL;
+    int autoload = 1;
+    char * kwlist[] = { "autoload", NULL };
 
-    data = _free(data);
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:getKeyring",
+                                    kwlist, &autoload))
+       return NULL;
 
-    return tuple;
+    keyring = rpmtsGetKeyring(s->ts, autoload);
+    if (keyring) {
+       return rpmKeyring_Wrap(&rpmKeyring_Type, keyring);
+    } else {
+       Py_RETURN_NONE;
+    }
 }
 
-/** \ingroup py_c
- */
 static void *
 rpmtsCallback(const void * hd, const rpmCallbackType what,
-                        const rpm_off_t amount, const rpm_off_t total,
+                        const rpm_loff_t amount, const rpm_loff_t total,
                         const void * pkgKey, rpmCallbackData data)
 {
     Header h = (Header) hd;
@@ -842,15 +494,12 @@ rpmtsCallback(const void * hd, const rpmCallbackType what,
     PyObject * args, * result;
     static FD_t fd;
 
-    if (cbInfo->pythonError) return NULL;
     if (cbInfo->cb == Py_None) return NULL;
 
     /* Synthesize a python object for callback (if necessary). */
     if (pkgObj == NULL) {
        if (h) {
-           const char * n = NULL;
-           (void) headerNVR(h, &n, NULL, NULL);
-           pkgObj = Py_BuildValue("s", n);
+           pkgObj = utf8FromString(headerGetString(h, RPMTAG_NAME));
        } else {
            pkgObj = Py_None;
            Py_INCREF(pkgObj);
@@ -860,43 +509,31 @@ rpmtsCallback(const void * hd, const rpmCallbackType what,
 
     PyEval_RestoreThread(cbInfo->_save);
 
-    args = Py_BuildValue("(illOO)", what, amount, total, pkgObj, cbInfo->data);
+    args = Py_BuildValue("(iLLOO)", what, amount, total, pkgObj, cbInfo->data);
     result = PyEval_CallObject(cbInfo->cb, args);
     Py_DECREF(args);
     Py_DECREF(pkgObj);
 
     if (!result) {
-       cbInfo->pythonError = 1;
-       cbInfo->_save = PyEval_SaveThread();
-       return NULL;
+       die(cbInfo->cb);
     }
 
     if (what == RPMCALLBACK_INST_OPEN_FILE) {
        int fdno;
 
         if (!PyArg_Parse(result, "i", &fdno)) {
-           cbInfo->pythonError = 1;
-           cbInfo->_save = PyEval_SaveThread();
-           return NULL;
+           die(cbInfo->cb);
        }
        Py_DECREF(result);
        cbInfo->_save = PyEval_SaveThread();
 
        fd = fdDup(fdno);
-if (_rpmts_debug)
-fprintf(stderr, "\t%p = fdDup(%d)\n", fd, fdno);
-
        fcntl(Fileno(fd), F_SETFD, FD_CLOEXEC);
 
        return fd;
     } else
     if (what == RPMCALLBACK_INST_CLOSE_FILE) {
-if (_rpmts_debug)
-fprintf(stderr, "\tFclose(%p)\n", fd);
        Fclose (fd);
-    } else {
-if (_rpmts_debug)
-fprintf(stderr, "\t%d:%d key %p\n", amount, total, pkgKey);
     }
 
     Py_DECREF(result);
@@ -905,79 +542,28 @@ fprintf(stderr, "\t%d:%d key %p\n", amount, total, pkgKey);
     return NULL;
 }
 
-/** \ingroup py_c
- */
-static PyObject *
-rpmts_SetFlags(rpmtsObject * s, PyObject * args, PyObject * kwds)
-{
-    rpmtransFlags transFlags = 0;
-    char * kwlist[] = {"flags", NULL};
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:SetFlags", kwlist,
-           &transFlags))
-       return NULL;
-
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_SetFlags(%p) ts %p transFlags %x\n", s, s->ts, transFlags);
-
-    /* XXX FIXME: value check on flags, or build pure python object 
-     * for it, and require an object of that type */
-
-    return Py_BuildValue("i", rpmtsSetFlags(s->ts, transFlags));
-}
-
-/** \ingroup py_c
- */
 static PyObject *
-rpmts_SetProbFilter(rpmtsObject * s, PyObject * args, PyObject * kwds)
-{
-    rpmprobFilterFlags ignoreSet = 0;
-    rpmprobFilterFlags oignoreSet;
-    char * kwlist[] = {"ignoreSet", NULL};
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:ProbFilter", kwlist,
-           &ignoreSet))
-       return NULL;
-
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_SetProbFilter(%p) ts %p ignoreSet %x\n", s, s->ts, ignoreSet);
-
-    oignoreSet = s->ignoreSet;
-    s->ignoreSet = ignoreSet;
-
-    return Py_BuildValue("i", oignoreSet);
-}
-
-/** \ingroup py_c
- */
-static rpmpsObject *
 rpmts_Problems(rpmtsObject * s)
 {
-
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_Problems(%p) ts %p\n", s, s->ts);
-
-    return rpmps_Wrap( rpmtsProblems(s->ts) );
+    rpmps ps = rpmtsProblems(s->ts);
+    PyObject *problems = rpmps_AsList(ps);
+    rpmpsFree(ps);
+    return problems;
 }
 
-/** \ingroup py_c
- */
 static PyObject *
 rpmts_Run(rpmtsObject * s, PyObject * args, PyObject * kwds)
 {
     int rc;
-    PyObject * list;
-    rpmps ps;
-    rpmpsi psi;
     struct rpmtsCallbackType_s cbInfo;
-    char * kwlist[] = {"callback", "data", NULL};
+    rpmprobFilterFlags ignoreSet;
+    char * kwlist[] = {"callback", "data", "ignoreSet", NULL};
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO:Run", kwlist,
-           &cbInfo.cb, &cbInfo.data))
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOi:Run", kwlist,
+           &cbInfo.cb, &cbInfo.data, &ignoreSet))
        return NULL;
 
     cbInfo.tso = s;
-    cbInfo.pythonError = 0;
     cbInfo._save = PyEval_SaveThread();
 
     if (cbInfo.cb != NULL) {
@@ -988,180 +574,74 @@ rpmts_Run(rpmtsObject * s, PyObject * args, PyObject * kwds)
        (void) rpmtsSetNotifyCallback(s->ts, rpmtsCallback, (void *) &cbInfo);
     }
 
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_Run(%p) ts %p ignore %x\n", s, s->ts, s->ignoreSet);
-
-    rc = rpmtsRun(s->ts, NULL, s->ignoreSet);
-    ps = rpmtsProblems(s->ts);
+    rc = rpmtsRun(s->ts, NULL, ignoreSet);
 
     if (cbInfo.cb)
        (void) rpmtsSetNotifyCallback(s->ts, NULL, NULL);
 
     PyEval_RestoreThread(cbInfo._save);
 
-    if (cbInfo.pythonError) {
-       ps = rpmpsFree(ps);
-       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);
-    psi = rpmpsInitIterator(ps);
-    while (rpmpsNextIterator(psi) >= 0) {
-       rpmProblem p = rpmpsGetProblem(psi);
-       char * ps = rpmProblemString(p);
-       PyObject * prob = Py_BuildValue("s(isN)", ps,
-                            rpmProblemGetType(p),
-                            rpmProblemGetStr(p),
-                            PyLong_FromLongLong(rpmProblemGetLong(p)));
-       PyList_Append(list, prob);
-       free(ps);
-       Py_DECREF(prob);
-    }
-
-    psi = rpmpsFreeIterator(psi);
-    ps = rpmpsFree(ps);
-
-    return list;
-}
-
-#if Py_TPFLAGS_HAVE_ITER
-static PyObject *
-rpmts_iter(rpmtsObject * s)
-{
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_iter(%p) ts %p\n", s, s->ts);
-
-    Py_INCREF(s);
-    return (PyObject *)s;
+    return Py_BuildValue("i", rc);
 }
-#endif
 
-/**
- * @todo Add TR_ADDED filter to iterator.
- */
 static PyObject *
 rpmts_iternext(rpmtsObject * s)
 {
     PyObject * result = NULL;
     rpmte te;
 
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_iternext(%p) ts %p tsi %p %d\n", s, s->ts, s->tsi, s->tsiFilter);
-
     /* Reset iterator on 1st entry. */
     if (s->tsi == NULL) {
        s->tsi = rpmtsiInit(s->ts);
        if (s->tsi == NULL)
            return NULL;
-       s->tsiFilter = 0;
     }
 
-    te = rpmtsiNext(s->tsi, s->tsiFilter);
+    te = rpmtsiNext(s->tsi, 0);
     if (te != NULL) {
-       result = (PyObject *) rpmte_Wrap(te);
+       result = rpmte_Wrap(&rpmte_Type, te);
     } else {
        s->tsi = rpmtsiFree(s->tsi);
-       s->tsiFilter = 0;
     }
 
     return result;
 }
 
-/**
- * @todo Add TR_ADDED filter to iterator.
- */
 static PyObject *
-rpmts_Next(rpmtsObject * s)
-{
-    PyObject * result;
-
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_Next(%p) ts %p\n", s, s->ts);
-
-    result = rpmts_iternext(s);
-
-    if (result == NULL) {
-       Py_INCREF(Py_None);
-       return Py_None;
-    }
-
-    return result;
-}
-
-/**
- */
-static specObject *
-spec_Parse(rpmtsObject * s, PyObject * args, PyObject * kwds)
-{
-    const char * specfile;
-    rpmSpec spec;
-    char * buildRoot = NULL;
-    int recursing = 0;
-    char * passPhrase = "";
-    char *cookie = NULL;
-    int anyarch = 1;
-    int force = 1;
-    char * kwlist[] = {"specfile", NULL};
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "s:Parse", kwlist, &specfile))
-       return NULL;
-
-    if (parseSpec(s->ts, specfile,"/", buildRoot,recursing, passPhrase,
-             cookie, anyarch, force)!=0) {
-             PyErr_SetString(pyrpmError, "can't parse specfile\n");
-                     return NULL;
-   }
-
-    spec = rpmtsSpec(s->ts);
-    return spec_Wrap(spec);
-}
-
-/**
- */
-static rpmmiObject *
 rpmts_Match(rpmtsObject * s, PyObject * args, PyObject * kwds)
 {
-    PyObject *TagN = NULL;
     PyObject *Key = NULL;
+    PyObject *str = NULL;
+    PyObject *mio = NULL;
     char *key = NULL;
 /* XXX lkey *must* be a 32 bit integer, int "works" on all known platforms. */
     int lkey = 0;
     int len = 0;
-    rpmTag tag = RPMDBI_PACKAGES;
+    rpmDbiTagVal tag = RPMDBI_PACKAGES;
     char * kwlist[] = {"tagNumber", "key", NULL};
 
-if (_rpmts_debug)
-fprintf(stderr, "*** rpmts_Match(%p) ts %p\n", s, s->ts);
-
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:Match", kwlist,
-           &TagN, &Key))
-       return NULL;
-
-    if (TagN && (tag = tagNumFromPyObject (TagN)) == -1) {
-       PyErr_SetString(PyExc_TypeError, "unknown tag type");
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&O:Match", kwlist,
+           tagNumFromPyObject, &tag, &Key))
        return NULL;
-    }
 
     if (Key) {
-       if (PyString_Check(Key) || PyUnicode_Check(Key)) {
-           key = PyString_AsString(Key);
-           len = PyString_Size(Key);
-       } else if (PyInt_Check(Key)) {
+       if (PyInt_Check(Key)) {
            lkey = PyInt_AsLong(Key);
            key = (char *)&lkey;
            len = sizeof(lkey);
+       } else if (PyLong_Check(Key)) {
+           lkey = PyLong_AsLong(Key);
+           key = (char *)&lkey;
+           len = sizeof(lkey);
+       } else if (utf8FromPyObject(Key, &str)) {
+           key = PyBytes_AsString(str);
+           len = PyBytes_Size(str);
        } else {
            PyErr_SetString(PyExc_TypeError, "unknown key type");
            return NULL;
        }
+       /* One of the conversions above failed, exception is set already */
+       if (PyErr_Occurred()) goto exit;
     }
 
     /* XXX If not already opened, open the database O_RDONLY now. */
@@ -1169,36 +649,99 @@ fprintf(stderr, "*** rpmts_Match(%p) ts %p\n", s, s->ts);
     if (rpmtsGetRdb(s->ts) == NULL) {
        int rc = rpmtsOpenDB(s->ts, O_RDONLY);
        if (rc || rpmtsGetRdb(s->ts) == NULL) {
-           PyErr_SetString(PyExc_TypeError, "rpmdb open failed");
-           return NULL;
+           PyErr_SetString(pyrpmError, "rpmdb open failed");
+           goto exit;
        }
     }
 
-    return rpmmi_Wrap( rpmtsInitIterator(s->ts, tag, key, len), (PyObject*)s);
+    mio = rpmmi_Wrap(&rpmmi_Type, rpmtsInitIterator(s->ts, tag, key, len), (PyObject*)s);
+
+exit:
+    Py_XDECREF(str);
+    return mio;
 }
+static PyObject *
+rpmts_index(rpmtsObject * s, PyObject * args, PyObject * kwds)
+{
+    rpmDbiTagVal tag;
+    PyObject *mio = NULL;
+    char * kwlist[] = {"tag", NULL};
 
-/** \ingroup py_c
- */
-static struct PyMethodDef rpmts_methods[] = {
- {"Debug",     (PyCFunction)rpmts_Debug,       METH_VARARGS|METH_KEYWORDS,
-        NULL},
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&:Keys", kwlist,
+              tagNumFromPyObject, &tag))
+       return NULL;
+
+    /* XXX If not already opened, open the database O_RDONLY now. */
+    if (rpmtsGetRdb(s->ts) == NULL) {
+       int rc = rpmtsOpenDB(s->ts, O_RDONLY);
+       if (rc || rpmtsGetRdb(s->ts) == NULL) {
+           PyErr_SetString(pyrpmError, "rpmdb open failed");
+           goto exit;
+       }
+    }
+
+    rpmdbIndexIterator ii = rpmdbIndexIteratorInit(rpmtsGetRdb(s->ts), tag);
+    if (ii == NULL) {
+        PyErr_SetString(PyExc_KeyError, "No index for this tag");
+        return NULL;
+    }
+    mio = rpmii_Wrap(&rpmii_Type, ii, (PyObject*)s);
+
+exit:
+    return mio;
+}
 
- {"addInstall",        (PyCFunction) rpmts_AddInstall, METH_VARARGS|METH_KEYWORDS,
-       NULL },
+static struct PyMethodDef rpmts_methods[] = {
+ {"addInstall",        (PyCFunction) rpmts_AddInstall, METH_VARARGS,
+  "ts.addInstall(hdr, data, mode) --  Add transaction element(s)\n"
+  "representing an installation or update of a package.\n\n"
+  "Args:\n"
+  "  hdr : the header to be added\n"
+  "  data : user data that will be passed to the transaction callback\n\t\tduring transaction execution\n"
+  "  mode : optional argument that specifies if this package should be\n\t\tinstalled ('i'), upgraded ('u')"},
+ {"addReinstall",      (PyCFunction) rpmts_AddReinstall,       METH_VARARGS,
+  "ts.addReinstall(hdr, data) -- Adds transaction elements\nrepresenting a reinstall of an already installed package.\n\nSee addInstall for details."},
  {"addErase",  (PyCFunction) rpmts_AddErase,   METH_VARARGS|METH_KEYWORDS,
-       NULL },
+  "addErase(name) -- Add a transaction element representing an erase\nof an installed package.\n\n"
+  "  name: the package name to be erased"},
  {"check",     (PyCFunction) rpmts_Check,      METH_VARARGS|METH_KEYWORDS,
-       NULL },
+  "ts.check( )-- Perform a dependency check on the transaction set.\n"
+  "            After headers have been added to a transaction set,\n"
+  "            a dependencycheck can be performed to make sure that\n"
+  "            all package dependencies are satisfied.\n"
+  "Return      None If there are no unresolved dependencies\n"
+  "            Otherwise a list of complex tuples is returned,\n"
+  "            one tuple per unresolved dependency, with\n"
+  "The format of the dependency tuple is:\n"
+  "    ((packageName, packageVersion, packageRelease),\n"
+  "     (reqName, reqVersion),\n"
+  "     needsFlags,\n"
+  "     suggestedPackage,\n"
+  "     sense)\n"
+  "  packageName, packageVersion, packageRelease are the name,\n"
+  "    version, and release of the package that has the unresolved\n"
+  "    dependency or conflict.\n"
+  "  The reqName and reqVersion are the name and version of the\n"
+  "    requirement or conflict.\n"
+  "  The needsFlags is a bitfield that describes the versioned\n"
+  "    nature of a requirement or conflict.  The constants\n"
+  "    rpm.RPMSENSE_LESS, rpm.RPMSENSE_GREATER, and\n"
+  "    rpm.RPMSENSE_EQUAL can be logical ANDed with the needsFlags\n"
+  "    to get versioned dependency information.\n"
+  "  suggestedPackage is a tuple if the dependency check was aware\n"
+  "    of a package that solves this dependency problem when the\n"
+  "    dependency check was run.  Packages that are added to the\n"
+  "    transaction set as \"available\" are examined during the\n"
+  "    dependency check as possible dependency solvers. The tuple\n"
+  "    contains two values, (header, suggestedName).  These are set to\n"
+  "    the header of the suggested package and its name, respectively.\n"
+  "    If there is no known package to solve the dependency problem,\n"
+  "    suggestedPackage is None.\n"
+  "  The constants rpm.RPMDEP_SENSE_CONFLICTS and\n"
+  "    rpm.RPMDEP_SENSE_REQUIRES are set to show a dependency as a\n"
+  "    requirement or a conflict.\n"},
  {"order",     (PyCFunction) rpmts_Order,      METH_NOARGS,
-       NULL },
- {"setFlags",  (PyCFunction) rpmts_SetFlags,   METH_VARARGS|METH_KEYWORDS,
-"ts.setFlags(transFlags) -> previous transFlags\n\
-- Set control bit(s) for executing ts.run().\n\
-  Note: This method replaces the 1st argument to the old ts.run()\n" },
- {"setProbFilter",     (PyCFunction) rpmts_SetProbFilter,      METH_VARARGS|METH_KEYWORDS,
-"ts.setProbFilter(ignoreSet) -> previous ignoreSet\n\
-- Set control bit(s) for ignoring problems found by ts.run().\n\
-  Note: This method replaces the 2nd argument to the old ts.run()\n" },
+  "ts.order() Do a topological sort of added element relations." },
  {"problems",  (PyCFunction) rpmts_Problems,   METH_NOARGS,
 "ts.problems() -> ps\n\
 - Return current problem set.\n" },
@@ -1207,15 +750,18 @@ static struct PyMethodDef rpmts_methods[] = {
 - Run a transaction set, returning list of problems found.\n\
   Note: The callback may not be None.\n" },
  {"clean",     (PyCFunction) rpmts_Clean,      METH_NOARGS,
-       NULL },
+  "ts.clean()-- Free memory needed only for dependency checks\nand ordering. Should not be needed in normal operation." },
+ {"clear",     (PyCFunction) rpmts_Clear,      METH_NOARGS,
+"ts.clear() -> None\n\
+Remove all elements from the transaction set\n" },
  {"openDB",    (PyCFunction) rpmts_OpenDB,     METH_NOARGS,
-"ts.openDB() -> None\n\
-- Open the default transaction rpmdb.\n\
-  Note: The transaction rpmdb is lazily opened, so ts.openDB() is seldom needed.\n" },
+"ts.openDB() -> None -- Open the default transaction rpmdb.\n\n\
+  Note: The transaction rpmdb is lazily opened,\n  so ts.openDB() is seldom needed.\n" },
  {"closeDB",   (PyCFunction) rpmts_CloseDB,    METH_NOARGS,
 "ts.closeDB() -> None\n\
 - Close the default transaction rpmdb.\n\
-  Note: ts.closeDB() disables lazy opens, and should hardly ever be used.\n" },
+  Note: ts.closeDB() disables lazy opens,\n\
+  and should hardly ever be used.\n" },
  {"initDB",    (PyCFunction) rpmts_InitDB,     METH_NOARGS,
 "ts.initDB() -> None\n\
 - Initialize the default transaction rpmdb.\n\
@@ -1226,173 +772,203 @@ static struct PyMethodDef rpmts_methods[] = {
  {"verifyDB",  (PyCFunction) rpmts_VerifyDB,   METH_NOARGS,
 "ts.verifyDB() -> None\n\
 - Verify the default transaction rpmdb.\n" },
- {"hdrFromFdno",(PyCFunction) rpmts_HdrFromFdno,METH_VARARGS|METH_KEYWORDS,
+ {"hdrFromFdno",(PyCFunction) rpmts_HdrFromFdno,METH_O,
 "ts.hdrFromFdno(fdno) -> hdr\n\
 - Read a package header from a file descriptor.\n" },
- {"hdrCheck",  (PyCFunction) rpmts_HdrCheck,   METH_VARARGS|METH_KEYWORDS,
-       NULL },
- {"setVSFlags",(PyCFunction) rpmts_SetVSFlags, METH_VARARGS|METH_KEYWORDS,
-"ts.setVSFlags(vsflags) -> ovsflags\n\
-- Set signature verification flags. Values for vsflags are:\n\
-    rpm.RPMVSF_NOHDRCHK      if set, don't check rpmdb headers\n\
-    rpm.RPMVSF_NEEDPAYLOAD   if not set, check header+payload (if possible)\n\
-    rpm.RPMVSF_NOSHA1HEADER  if set, don't check header SHA1 digest\n\
-    rpm.RPMVSF_NODSAHEADER   if set, don't check header DSA signature\n\
-    rpm.RPMVSF_NOMD5         if set, don't check header+payload MD5 digest\n\
-    rpm.RPMVSF_NODSA         if set, don't check header+payload DSA signature\n\
-    rpm.RPMVSF_NORSA         if set, don't check header+payload RSA signature\n\
-    rpm._RPMVSF_NODIGESTS    if set, don't check digest(s)\n\
-    rpm._RPMVSF_NOSIGNATURES if set, don't check signature(s)\n" },
- {"getVSFlags",(PyCFunction) rpmts_GetVSFlags, METH_NOARGS,
-"ts.getVSFlags() -> vsflags\n\
-- Retrieve current signature verification flags from transaction\n" },
- {"setColor",(PyCFunction) rpmts_SetColor,     METH_VARARGS|METH_KEYWORDS,
-       NULL },
+ {"hdrCheck",  (PyCFunction) rpmts_HdrCheck,   METH_O,
+  "ts.hdrCheck(hdrblob) -- Check header consistency,\nperforming headerGetEntry() the hard way.\n\n"
+  "Sanity checks on the header are performed while looking for a\n"
+  "header-only digest or signature to verify the blob. If found,\n"
+  "the digest or signature is verified.\n\n"
+  "\thdrblob : unloaded header blob\n"
+  "Return tuple (int status, message string)"},
  {"pgpPrtPkts",        (PyCFunction) rpmts_PgpPrtPkts, METH_VARARGS|METH_KEYWORDS,
-       NULL },
+  "pgpPrtPkts(octets) -- Print/parse a OpenPGP packet(s).\n\nReturn 0 on success." },
  {"pgpImportPubkey",   (PyCFunction) rpmts_PgpImportPubkey,    METH_VARARGS|METH_KEYWORDS,
-       NULL },
- {"getKeys",   (PyCFunction) rpmts_GetKeys,    METH_NOARGS,
-       NULL },
- {"parseSpec", (PyCFunction) spec_Parse,       METH_VARARGS|METH_KEYWORDS,
-"ts.parseSpec(\"/path/to/foo.spec\") -> spec\n\
-- Parse a spec file.\n" },
+  "pgpImportPubkey(pubkey) -- Import public key packet." },
+ {"getKeyring",        (PyCFunction) rpmts_getKeyring, METH_VARARGS|METH_KEYWORDS, 
+  "ts.getKeyring(autoload=False) -- Return key ring object." },
+ {"setKeyring",        (PyCFunction) rpmts_setKeyring, METH_O, 
+  "ts.setKeyring(keyring) -- Set key ring used for checking signatures\n\n"
+  "Pass None for an empty key ring." },
  {"dbMatch",   (PyCFunction) rpmts_Match,      METH_VARARGS|METH_KEYWORDS,
-"ts.dbMatch([TagN, [key, [len]]]) -> mi\n\
+"ts.dbMatch([TagN, [key]]) -> mi\n\
 - Create a match iterator for the default transaction rpmdb.\n" },
- {"next",              (PyCFunction)rpmts_Next,        METH_NOARGS,
-"ts.next() -> te\n\
-- Retrieve next transaction set element.\n" },
+ {"dbIndex",     (PyCFunction) rpmts_index,    METH_VARARGS|METH_KEYWORDS,
+"ts.dbIndex(TagN) -> ii\n\
+- Create a key iterator for the default transaction rpmdb.\n" },
     {NULL,             NULL}           /* sentinel */
 };
 
-/** \ingroup py_c
- */
 static void rpmts_dealloc(rpmtsObject * s)
 {
 
-if (_rpmts_debug)
-fprintf(stderr, "%p -- ts %p db %p\n", s, s->ts, rpmtsGetRdb(s->ts));
     s->ts = rpmtsFree(s->ts);
-
-    if (s->scriptFd) Fclose(s->scriptFd);
-    /* this will free the keyList, and decrement the ref count of all
-       the items on the list as well :-) */
-    Py_DECREF(s->keyList);
-    PyObject_Del((PyObject *)s);
+    Py_XDECREF(s->scriptFd);
+    Py_XDECREF(s->keyList);
+    Py_TYPE(s)->tp_free((PyObject *)s);
 }
 
-static PyObject * rpmts_getattro(PyObject * o, PyObject * n)
+static PyObject * rpmts_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds)
 {
-    return PyObject_GenericGetAttr(o, n);
+    rpmtsObject * s = (rpmtsObject *)subtype->tp_alloc(subtype, 0);
+    if (s == NULL) return NULL;
+
+    s->ts = rpmtsCreate();
+    s->scriptFd = NULL;
+    s->tsi = NULL;
+    s->keyList = PyList_New(0);
+    return (PyObject *) s;
 }
 
-/** \ingroup py_c
- */
-static int rpmts_setattro(PyObject * o, PyObject * n, PyObject * v)
+static int rpmts_init(rpmtsObject *s, PyObject *args, PyObject *kwds)
 {
-    rpmtsObject *s = (rpmtsObject *)o;
-    char * name = PyString_AsString(n);
-    int fdno;
-
-    if (!strcmp(name, "scriptFd")) {
-       if (!PyArg_Parse(v, "i", &fdno)) return 0;
-       if (fdno < 0) {
-           PyErr_SetString(PyExc_TypeError, "bad file descriptor");
-           return -1;
-       } else {
-           s->scriptFd = fdDup(fdno);
-           rpmtsSetScriptFd(s->ts, s->scriptFd);
-       }
-    } else {
-       PyErr_SetString(PyExc_AttributeError, name);
+    const char * rootDir = "/";
+    rpmVSFlags vsflags = rpmExpandNumeric("%{?__vsflags}");
+    char * kwlist[] = {"rootdir", "vsflags", 0};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|si:rpmts_new", kwlist,
+           &rootDir, &vsflags))
        return -1;
-    }
+
+    (void) rpmtsSetRootDir(s->ts, rootDir);
+    /* XXX: make this use common code with rpmts_SetVSFlags() to check the
+     *      python objects */
+    (void) rpmtsSetVSFlags(s->ts, vsflags);
 
     return 0;
 }
 
-/** \ingroup py_c
- */
-static int rpmts_init(rpmtsObject * s, PyObject *args, PyObject *kwds)
+static PyObject *rpmts_get_tid(rpmtsObject *s, void *closure)
 {
-    /* nothing to do atm... */
-    return 0;
+    return Py_BuildValue("i", rpmtsGetTid(s->ts));
 }
 
-/** \ingroup py_c
- */
-static void rpmts_free(rpmtsObject * s)
+static PyObject *rpmts_get_rootDir(rpmtsObject *s, void *closure)
 {
-if (_rpmts_debug)
-fprintf(stderr, "%p -- ts %p db %p\n", s, s->ts, rpmtsGetRdb(s->ts));
-    s->ts = rpmtsFree(s->ts);
+    return utf8FromString(rpmtsRootDir(s->ts));
+}
 
-    if (s->scriptFd)
-       Fclose(s->scriptFd);
+static int rpmts_set_scriptFd(rpmtsObject *s, PyObject *value, void *closure)
+{
+    rpmfdObject *fdo = NULL;
+    int rc = 0;
+    if (PyArg_Parse(value, "O&", rpmfdFromPyObject, &fdo)) {
+       Py_XDECREF(s->scriptFd);
+       s->scriptFd = fdo;
+       rpmtsSetScriptFd(s->ts, rpmfdGetFd(s->scriptFd));
+    } else if (value == Py_None) {
+       Py_XDECREF(s->scriptFd);
+       s->scriptFd = NULL;
+       rpmtsSetScriptFd(s->ts, NULL);
+    } else {
+       rc = -1;
+    }
+    return rc;
+}
 
-    /* this will free the keyList, and decrement the ref count of all
-       the items on the list as well :-) */
-    Py_DECREF(s->keyList);
+static PyObject *rpmts_get_color(rpmtsObject *s, void *closure)
+{
+    return Py_BuildValue("i", rpmtsColor(s->ts));
+}
 
-    PyObject_Del((PyObject *)s);
+static PyObject *rpmts_get_prefcolor(rpmtsObject *s, void *closure)
+{
+    return Py_BuildValue("i", rpmtsPrefColor(s->ts));
 }
 
-/** \ingroup py_c
- */
-static PyObject * rpmts_alloc(PyTypeObject * subtype, int nitems)
+static int rpmts_set_color(rpmtsObject *s, PyObject *value, void *closure)
 {
-    PyObject * s = PyType_GenericAlloc(subtype, nitems);
+    rpm_color_t color;
+    if (!PyArg_Parse(value, "i", &color)) return -1;
 
-if (_rpmts_debug < 0)
-fprintf(stderr, "*** rpmts_alloc(%p,%d) ret %p\n", subtype, nitems, s);
-    return s;
+    /* TODO: validate the bits */
+    rpmtsSetColor(s->ts, color);
+    return 0;
 }
 
-/** \ingroup py_c
- */
-static PyObject * rpmts_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds)
+static int rpmts_set_prefcolor(rpmtsObject *s, PyObject *value, void *closure)
 {
-    rpmtsObject * s = (void *) PyObject_New(rpmtsObject, subtype);
+    rpm_color_t color;
+    if (!PyArg_Parse(value, "i", &color)) return -1;
 
-    char * rootDir = "/";
-    rpmVSFlags vsflags = rpmExpandNumeric("%{?__vsflags}");
-    char * kwlist[] = {"rootdir", "vsflags", 0};
+    /* TODO: validate the bits */
+    rpmtsSetPrefColor(s->ts, color);
+    return 0;
+}
 
-    if (_rpmts_debug < 0)
-       fprintf(stderr, "*** rpmts_new(%p,%p,%p)\n", s, args, kwds);
+static int rpmts_set_flags(rpmtsObject *s, PyObject *value, void *closure)
+{
+    rpmtransFlags flags;
+    if (!PyArg_Parse(value, "i", &flags)) return -1;
 
-    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|si:rpmts_init", kwlist,
-           &rootDir, &vsflags))
-       return NULL;
+    /* TODO: validate the bits */
+    rpmtsSetFlags(s->ts, flags);
+    return 0;
+}
 
-    s->ts = rpmtsCreate();
-    /* XXX: Why is there no rpmts_SetRootDir() ? */
-    (void) rpmtsSetRootDir(s->ts, rootDir);
-    /* XXX: make this use common code with rpmts_SetVSFlags() to check the
-     *      python objects */
-    (void) rpmtsSetVSFlags(s->ts, vsflags);
-    s->keyList = PyList_New(0);
-    s->scriptFd = NULL;
-    s->tsi = NULL;
-    s->tsiFilter = 0;
+static int rpmts_set_vsflags(rpmtsObject *s, PyObject *value, void *closure)
+{
+    rpmVSFlags flags;
+    if (!PyArg_Parse(value, "i", &flags)) return -1;
 
-    if (_rpmts_debug)
-       fprintf(stderr, "%p ++ ts %p db %p\n", s, s->ts, rpmtsGetRdb(s->ts));
+    /* TODO: validate the bits */
+    rpmtsSetVSFlags(s->ts, flags);
+    return 0;
+}
 
-    return (PyObject *)s;
+static PyObject *rpmts_get_flags(rpmtsObject *s, void *closure)
+{
+    return Py_BuildValue("i", rpmtsFlags(s->ts));
+}
+
+static PyObject *rpmts_get_vsflags(rpmtsObject *s, void *closure)
+{
+    return Py_BuildValue("i", rpmtsVSFlags(s->ts));
 }
 
-/**
- */
 static char rpmts_doc[] =
-"";
+  "A python rpm.ts object represents an RPM transaction set.\n"
+  "\n"
+  "The transaction set is the workhorse of RPM. It performs the\n"
+  "installation and upgrade of packages. The rpm.ts object is\n"
+  "instantiated by the TransactionSet function in the rpm module.\n"
+  "\n"
+  "The TransactionSet function takes two optional arguments. The first\n"
+  "argument is the root path. The second is the verify signature disable\n"
+  "flags, a set of the following bits:\n"
+  "\n"
+  "-    rpm.RPMVSF_NOHDRCHK    if set, don't check rpmdb headers\n"
+  "-    rpm.RPMVSF_NEEDPAYLOAD if not set, check header+payload\n"
+  "                            (if possible)\n"
+  "-    rpm.RPMVSF_NOSHA1HEADER        if set, don't check header SHA1 digest\n"
+  "-    rpm.RPMVSF_NODSAHEADER if set, don't check header DSA signature\n"
+  "-    rpm.RPMVSF_NOMD5       if set, don't check header+payload MD5 digest\n"
+  "-    rpm.RPMVSF_NODSA       if set, don't check header+payload DSA signature\n"
+  "-    rpm.RPMVSF_NORSA       if set, don't check header+payload RSA signature\n"
+  "\n"
+  "For convenience, there are the following masks:\n"
+  "-    rpm._RPMVSF_NODIGESTS  if set, don't check digest(s).\n"
+  "-    rpm._RPMVSF_NOSIGNATURES       if set, don't check signature(s).\n\n"
+  "The transaction set offers an read only iterable interface for the\ntransaction elements added by the .addInstall(), .addErase() and\n.addReinstall() methods.";
+
+static PyGetSetDef rpmts_getseters[] = {
+       /* only provide a setter until we have rpmfd wrappings */
+       {"scriptFd",    NULL,   (setter)rpmts_set_scriptFd,
+        "write only, file descriptor the output of script gets written to." },
+       {"tid",         (getter)rpmts_get_tid, NULL,
+        "read only, current transaction id, i.e. transaction time stamp."},
+       {"rootDir",     (getter)rpmts_get_rootDir, NULL,
+        "read only, directory rpm treats as root of the file system." },
+       {"_color",      (getter)rpmts_get_color, (setter)rpmts_set_color, NULL},
+       {"_prefcolor",  (getter)rpmts_get_prefcolor, (setter)rpmts_set_prefcolor, NULL},
+       {"_flags",      (getter)rpmts_get_flags, (setter)rpmts_set_flags, NULL},
+       {"_vsflags",    (getter)rpmts_get_vsflags, (setter)rpmts_set_vsflags, NULL},
+       { NULL }
+};
 
-/** \ingroup py_c
- */
 PyTypeObject rpmts_Type = {
-       PyObject_HEAD_INIT(&PyType_Type)
-       0,                              /* ob_size */
+       PyVarObject_HEAD_INIT(&PyType_Type, 0)
        "rpm.ts",                       /* tp_name */
        sizeof(rpmtsObject),            /* tp_size */
        0,                              /* tp_itemsize */
@@ -1408,38 +984,28 @@ PyTypeObject rpmts_Type = {
        0,                              /* tp_hash */
        0,                              /* tp_call */
        0,                              /* tp_str */
-       (getattrofunc) rpmts_getattro,  /* tp_getattro */
-       (setattrofunc) rpmts_setattro,  /* tp_setattro */
+       PyObject_GenericGetAttr,        /* tp_getattro */
+       PyObject_GenericSetAttr,        /* tp_setattro */
        0,                              /* tp_as_buffer */
-       Py_TPFLAGS_DEFAULT,             /* tp_flags */
+       Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */
        rpmts_doc,                      /* tp_doc */
-#if Py_TPFLAGS_HAVE_ITER
        0,                              /* tp_traverse */
        0,                              /* tp_clear */
        0,                              /* tp_richcompare */
        0,                              /* tp_weaklistoffset */
-       (getiterfunc) rpmts_iter,       /* tp_iter */
+       PyObject_SelfIter,              /* tp_iter */
        (iternextfunc) rpmts_iternext,  /* tp_iternext */
        rpmts_methods,                  /* tp_methods */
        0,                              /* tp_members */
-       0,                              /* tp_getset */
+       rpmts_getseters,                /* tp_getset */
        0,                              /* tp_base */
        0,                              /* tp_dict */
        0,                              /* tp_descr_get */
        0,                              /* tp_descr_set */
        0,                              /* tp_dictoffset */
        (initproc) rpmts_init,          /* tp_init */
-       (allocfunc) rpmts_alloc,        /* tp_alloc */
+       0,                              /* tp_alloc */
        (newfunc) rpmts_new,            /* tp_new */
-       (freefunc) rpmts_free,          /* tp_free */
+       0,                              /* tp_free */
        0,                              /* tp_is_gc */
-#endif
 };
-
-/**
- */
-PyObject *
-rpmts_Create(PyObject * self, PyObject * args, PyObject * kwds)
-{
-    return PyObject_Call((PyObject *) &rpmts_Type, args, kwds);
-}