Lose unnecessary next() methods
[platform/upstream/rpm.git] / python / rpmts-py.c
1 /** \ingroup py_c
2  * \file python/rpmts-py.c
3  */
4
5 #include "system.h"
6
7 #include <rpm/rpmlib.h> /* rpmReadPackageFile, headerCheck */
8 #include <rpm/rpmtag.h>
9 #include <rpm/rpmpgp.h>
10 #include <rpm/rpmdb.h>
11 #include <rpm/rpmbuild.h>
12
13 #include "header-py.h"
14 #include "rpmds-py.h"   /* XXX for rpmdsNew */
15 #include "rpmfi-py.h"   /* XXX for rpmfiNew */
16 #include "rpmmi-py.h"
17 #include "rpmps-py.h"
18 #include "rpmte-py.h"
19 #include "spec-py.h"
20
21 #include "rpmts-py.h"
22
23 #include "debug.h"
24
25 extern int _rpmts_debug;
26
27
28 /** \ingroup python
29  * \name Class: Rpmts
30  * \class Rpmts
31  * \brief A python rpm.ts object represents an RPM transaction set.
32  *
33  * The transaction set is the workhorse of RPM.  It performs the
34  * installation and upgrade of packages.  The rpm.ts object is
35  * instantiated by the TransactionSet function in the rpm module.
36  *
37  * The TransactionSet function takes two optional arguments. The first
38  * argument is the root path. The second is the verify signature disable flags,
39  * a set of the following bits:
40  *
41  * -    rpm.RPMVSF_NOHDRCHK     if set, don't check rpmdb headers
42  * -    rpm.RPMVSF_NEEDPAYLOAD  if not set, check header+payload (if possible)
43  * -    rpm.RPMVSF_NOSHA1HEADER if set, don't check header SHA1 digest
44  * -    rpm.RPMVSF_NODSAHEADER  if set, don't check header DSA signature
45  * -    rpm.RPMVSF_NOMD5        if set, don't check header+payload MD5 digest
46  * -    rpm.RPMVSF_NODSA        if set, don't check header+payload DSA signature
47  * -    rpm.RPMVSF_NORSA        if set, don't check header+payload RSA signature
48  *
49  * For convenience, there are the following masks:
50  * -    rpm._RPMVSF_NODIGESTS           if set, don't check digest(s).
51  * -    rpm._RPMVSF_NOSIGNATURES        if set, don't check signature(s).
52  *
53  * A rpm.ts object has the following methods:
54  *
55  * - addInstall(hdr,data,mode)  Add an install element to a transaction set.
56  * @param hdr   the header to be added
57  * @param data  user data that will be passed to the transaction callback
58  *              during transaction execution
59  * @param mode  optional argument that specifies if this package should
60  *              be installed ('i'), upgraded ('u').
61  *
62  * - addErase(name) Add an erase element to a transaction set.
63  * @param name  the package name to be erased
64  *
65  * - check()    Perform a dependency check on the transaction set. After
66  *              headers have been added to a transaction set, a dependency
67  *              check can be performed to make sure that all package
68  *              dependencies are satisfied.
69  * @return      None If there are no unresolved dependencies
70  *              Otherwise a list of complex tuples is returned, one tuple per
71  *              unresolved dependency, with
72  * The format of the dependency tuple is:
73  *     ((packageName, packageVersion, packageRelease),
74  *      (reqName, reqVersion),
75  *      needsFlags,
76  *      suggestedPackage,
77  *      sense)
78  *     packageName, packageVersion, packageRelease are the name,
79  *     version, and release of the package that has the unresolved
80  *     dependency or conflict.
81  *     The reqName and reqVersion are the name and version of the
82  *     requirement or conflict.
83  *     The needsFlags is a bitfield that describes the versioned
84  *     nature of a requirement or conflict.  The constants
85  *     rpm.RPMSENSE_LESS, rpm.RPMSENSE_GREATER, and
86  *     rpm.RPMSENSE_EQUAL can be logical ANDed with the needsFlags
87  *     to get versioned dependency information.
88  *     suggestedPackage is a tuple if the dependency check was aware
89  *     of a package that solves this dependency problem when the
90  *     dependency check was run.  Packages that are added to the
91  *     transaction set as "available" are examined during the
92  *     dependency check as possible dependency solvers. The tuple
93  *     contains two values, (header, suggestedName).  These are set to
94  *     the header of the suggested package and its name, respectively.
95  *     If there is no known package to solve the dependency problem,
96  *     suggestedPackage is None.
97  *     The constants rpm.RPMDEP_SENSE_CONFLICTS and
98  *     rpm.RPMDEP_SENSE_REQUIRES are set to show a dependency as a
99  *     requirement or a conflict.
100  *
101  * - ts.order() Do a topological sort of added element relations.
102  * @return      None
103  *
104  * - ts.setFlags(transFlags) Set transaction set flags.
105  * @param transFlags - bit(s) to controll transaction operations. The
106  *              following values can be logically OR'ed together:
107  *      - rpm.RPMTRANS_FLAG_TEST - test mode, do not modify the RPM
108  *              database, change any files, or run any package scripts
109  *      - rpm.RPMTRANS_FLAG_BUILD_PROBS - only build a list of
110  *              problems encountered when attempting to run this transaction
111  *              set
112  *      - rpm.RPMTRANS_FLAG_NOSCRIPTS - do not execute package scripts
113  *      - rpm.RPMTRANS_FLAG_JUSTDB - only make changes to the rpm
114  *              database, do not modify files.
115  *      - rpm.RPMTRANS_FLAG_NOTRIGGERS - do not run trigger scripts
116  *      - rpm.RPMTRANS_FLAG_NODOCS - do not install files marked as %doc
117  *      - rpm.RPMTRANS_FLAG_ALLFILES - create all files, even if a
118  *              file is marked %config(missingok) and an upgrade is
119  *              being performed.
120  *      - rpm.RPMTRANS_FLAG_KEEPOBSOLETE - do not remove obsoleted
121  *              packages.
122  * @return      previous transFlags
123  *
124  * - ts.setProbFilter(ignoreSet) Set transaction set problem filter.
125  * @param problemSetFilter - control bit(s) to ignore classes of problems,
126  *              a logical or of one or more of the following bit(s):
127  *      - rpm.RPMPROB_FILTER_IGNOREOS -
128  *      - rpm.RPMPROB_FILTER_IGNOREARCH -
129  *      - rpm.RPMPROB_FILTER_REPLACEPKG -
130  *      - rpm.RPMPROB_FILTER_FORCERELOCATE -
131  *      - rpm.RPMPROB_FILTER_REPLACENEWFILES -
132  *      - rpm.RPMPROB_FILTER_REPLACEOLDFILES -
133  *      - rpm.RPMPROB_FILTER_OLDPACKAGE -
134  *      - rpm.RPMPROB_FILTER_DISKSPACE -
135  * @return      previous ignoreSet
136  *
137  * - ts.run(callback,data) Attempt to execute a transaction set.
138  *      After the transaction set has been populated with install/upgrade or
139  *      erase actions, the transaction set can be executed by invoking
140  *      the ts.run() method.
141  */
142
143 struct rpmtsObject_s {
144     PyObject_HEAD
145     PyObject *md_dict;          /*!< to look like PyModuleObject */
146     rpmts       ts;
147     PyObject * keyList;         /* keeps reference counts correct */
148     FD_t scriptFd;
149     rpmtsi tsi;
150     rpmElementType tsiFilter;
151     rpmprobFilterFlags ignoreSet;
152 };
153
154 /** \ingroup py_c
155  */
156 struct rpmtsCallbackType_s {
157     PyObject * cb;
158     PyObject * data;
159     rpmtsObject * tso;
160     PyThreadState *_save;
161 };
162
163 /** \ingroup py_c
164  */
165 static PyObject *
166 rpmts_Debug(rpmtsObject * s, PyObject * args, PyObject * kwds)
167 {
168     char * kwlist[] = {"debugLevel", NULL};
169
170     if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Debug", kwlist,
171             &_rpmts_debug))
172         return NULL;
173
174 if (_rpmts_debug < 0)
175 fprintf(stderr, "*** rpmts_Debug(%p) ts %p\n", s, s->ts);
176
177     Py_RETURN_NONE;
178 }
179
180 RPM_GNUC_NORETURN
181 static void die(PyObject *cb)
182 {
183     char *pyfn = NULL;
184     PyObject *r;
185
186     if (PyErr_Occurred()) {
187         PyErr_Print();
188     }
189     if ((r = PyObject_Repr(cb)) != NULL) { 
190         pyfn = PyString_AsString(r);
191     }
192     fprintf(stderr, _("error: python callback %s failed, aborting!\n"), 
193                       pyfn ? pyfn : "???");
194     rpmdbCheckTerminate(1);
195     exit(EXIT_FAILURE);
196 }
197
198 /** \ingroup py_c
199  */
200 static PyObject *
201 rpmts_AddInstall(rpmtsObject * s, PyObject * args, PyObject * kwds)
202 {
203     hdrObject * h;
204     PyObject * key;
205     char * how = "u";   /* XXX default to upgrade element if missing */
206     int isUpgrade = 0;
207     char * kwlist[] = {"header", "key", "how", NULL};
208     int rc = 0;
209
210     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O|s:AddInstall", kwlist,
211             &hdr_Type, &h, &key, &how))
212         return NULL;
213
214     {   PyObject * hObj = (PyObject *) h;
215         if (hObj->ob_type != &hdr_Type) {
216             PyErr_SetString(PyExc_TypeError, "bad type for header argument");
217             return NULL;
218         }
219     }
220
221 if (_rpmts_debug < 0 || (_rpmts_debug > 0))
222 fprintf(stderr, "*** rpmts_AddInstall(%p,%p,%p,%s) ts %p\n", s, h, key, how, s->ts);
223
224     if (how && !rstreq(how, "u") && !rstreq(how, "i")) {
225         PyErr_SetString(PyExc_TypeError, "how argument must be \"u\" or \"i\"");
226         return NULL;
227     } else if (how && rstreq(how, "u"))
228         isUpgrade = 1;
229
230     rc = rpmtsAddInstallElement(s->ts, hdrGetHeader(h), key, isUpgrade, NULL);
231     if (rc) {
232         PyErr_SetString(pyrpmError, "adding package to transaction failed");
233         return NULL;
234     }
235         
236
237     /* This should increment the usage count for me */
238     if (key)
239         PyList_Append(s->keyList, key);
240
241     Py_RETURN_NONE;
242 }
243
244 /** \ingroup py_c
245  * @todo Permit finer control (i.e. not just --allmatches) of deleted elments.
246  */
247 static PyObject *
248 rpmts_AddErase(rpmtsObject * s, PyObject * args, PyObject * kwds)
249 {
250     PyObject * o;
251     int installed = 0;
252     rpmdbMatchIterator mi = NULL;
253     Header h;
254     char * kwlist[] = {"name", NULL};
255
256 if (_rpmts_debug)
257 fprintf(stderr, "*** rpmts_AddErase(%p) ts %p\n", s, s->ts);
258
259     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:AddErase", kwlist, &o))
260         return NULL;
261
262     if (PyString_Check(o)) {
263         char * name = PyString_AsString(o);
264         mi = rpmtsInitIterator(s->ts, RPMDBI_LABEL, name, 0);
265     } else if (PyInt_Check(o)) {
266         uint32_t recno = PyInt_AsLong(o);
267         mi = rpmtsInitIterator(s->ts, RPMDBI_PACKAGES, &recno, sizeof(recno));
268     } else {
269         PyErr_SetString(PyExc_TypeError, "string or integer expected");
270         return NULL;
271     }
272
273     while ((h = rpmdbNextIterator(mi)) != NULL) {
274         installed++;
275         rpmtsAddEraseElement(s->ts, h, -1);
276     }
277     rpmdbFreeIterator(mi);
278     
279     if (installed) {
280         Py_RETURN_NONE;
281     } else {
282         PyErr_SetString(pyrpmError, "package not installed");
283         return NULL;
284     }
285 }
286
287 /** \ingroup py_c
288  */
289 static int
290 rpmts_SolveCallback(rpmts ts, rpmds ds, const void * data)
291 {
292     struct rpmtsCallbackType_s * cbInfo = (struct rpmtsCallbackType_s *) data;
293     PyObject * args, * result;
294     int res = 1;
295
296 if (_rpmts_debug)
297 fprintf(stderr, "*** rpmts_SolveCallback(%p,%p,%p) \"%s\"\n", ts, ds, data, rpmdsDNEVR(ds));
298
299     if (cbInfo->tso == NULL) return res;
300     if (cbInfo->cb == Py_None) return res;
301
302     PyEval_RestoreThread(cbInfo->_save);
303
304     args = Py_BuildValue("(Oissi)", cbInfo->tso,
305                 rpmdsTagN(ds), rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds));
306     result = PyEval_CallObject(cbInfo->cb, args);
307     Py_DECREF(args);
308
309     if (!result) {
310         die(cbInfo->cb);
311     } else {
312         if (PyInt_Check(result))
313             res = PyInt_AsLong(result);
314         Py_DECREF(result);
315     }
316
317     cbInfo->_save = PyEval_SaveThread();
318
319     return res;
320 }
321
322 /** \ingroup py_c
323  */
324 static PyObject *
325 rpmts_Check(rpmtsObject * s, PyObject * args, PyObject * kwds)
326 {
327     rpmps ps;
328     rpmProblem p;
329     PyObject * list, * cf;
330     struct rpmtsCallbackType_s cbInfo;
331     int xx;
332     char * kwlist[] = {"callback", NULL};
333
334     memset(&cbInfo, 0, sizeof(cbInfo));
335     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:Check", kwlist,
336             &cbInfo.cb))
337         return NULL;
338
339     if (cbInfo.cb != NULL) {
340         if (!PyCallable_Check(cbInfo.cb)) {
341             PyErr_SetString(PyExc_TypeError, "expected a callable");
342             return NULL;
343         }
344         xx = rpmtsSetSolveCallback(s->ts, rpmts_SolveCallback, (void *)&cbInfo);
345     }
346
347 if (_rpmts_debug)
348 fprintf(stderr, "*** rpmts_Check(%p) ts %p cb %p\n", s, s->ts, cbInfo.cb);
349
350     cbInfo.tso = s;
351     cbInfo._save = PyEval_SaveThread();
352
353     xx = rpmtsCheck(s->ts);
354     ps = rpmtsProblems(s->ts);
355
356     PyEval_RestoreThread(cbInfo._save);
357
358     if (ps != NULL) {
359         list = PyList_New(0);
360         rpmpsi psi = rpmpsInitIterator(ps);
361
362         /* XXX TODO: rpmlib >= 4.0.3 can return multiple suggested keys. */
363         while (rpmpsNextIterator(psi) >= 0) {
364             char * altNEVR, * needsName;
365             char * byName, * byVersion, * byRelease, *byArch;
366             char * needsOP, * needsVersion;
367             rpmsenseFlags needsFlags, sense;
368             fnpyKey key;
369
370             p = rpmpsGetProblem(psi);
371
372             byName = xstrdup(rpmProblemGetPkgNEVR(p));
373             if ((byArch= strrchr(byName, '.')) != NULL)
374                 *byArch++ = '\0';
375             if ((byRelease = strrchr(byName, '-')) != NULL)
376                 *byRelease++ = '\0';
377             if ((byVersion = strrchr(byName, '-')) != NULL)
378                 *byVersion++ = '\0';
379
380             key = rpmProblemGetKey(p);
381
382             altNEVR = needsName = xstrdup(rpmProblemGetAltNEVR(p));
383             if (needsName[1] == ' ') {
384                 sense = (needsName[0] == 'C')
385                         ? RPMDEP_SENSE_CONFLICTS : RPMDEP_SENSE_REQUIRES;
386                 needsName += 2;
387             } else
388                 sense = RPMDEP_SENSE_REQUIRES;
389             if ((needsVersion = strrchr(needsName, ' ')) != NULL)
390                 *needsVersion++ = '\0';
391
392             needsFlags = 0;
393             if ((needsOP = strrchr(needsName, ' ')) != NULL) {
394                 for (*needsOP++ = '\0'; *needsOP != '\0'; needsOP++) {
395                     if (*needsOP == '<')        needsFlags |= RPMSENSE_LESS;
396                     else if (*needsOP == '>')   needsFlags |= RPMSENSE_GREATER;
397                     else if (*needsOP == '=')   needsFlags |= RPMSENSE_EQUAL;
398                 }
399             }
400
401             cf = Py_BuildValue("((sss)(ss)iOi)", byName, byVersion, byRelease,
402                                needsName, needsVersion, needsFlags,
403                                (key != NULL ? key : Py_None),
404                                sense);
405             PyList_Append(list, (PyObject *) cf);
406             Py_DECREF(cf);
407             free(byName);
408             free(altNEVR);
409         }
410
411         psi = rpmpsFreeIterator(psi);
412         ps = rpmpsFree(ps);
413
414         return list;
415     }
416
417     Py_RETURN_NONE;
418 }
419
420 /** \ingroup py_c
421  */
422 static PyObject *
423 rpmts_Order(rpmtsObject * s)
424 {
425     int rc;
426
427 if (_rpmts_debug)
428 fprintf(stderr, "*** rpmts_Order(%p) ts %p\n", s, s->ts);
429
430     Py_BEGIN_ALLOW_THREADS
431     rc = rpmtsOrder(s->ts);
432     Py_END_ALLOW_THREADS
433
434     return Py_BuildValue("i", rc);
435 }
436
437 /** \ingroup py_c
438  */
439 static PyObject *
440 rpmts_Clean(rpmtsObject * s)
441 {
442 if (_rpmts_debug)
443 fprintf(stderr, "*** rpmts_Clean(%p) ts %p\n", s, s->ts);
444
445     rpmtsClean(s->ts);
446
447     Py_RETURN_NONE;
448 }
449
450 /** \ingroup py_c
451  */
452 static PyObject *
453 rpmts_OpenDB(rpmtsObject * s)
454 {
455     int dbmode;
456
457 if (_rpmts_debug)
458 fprintf(stderr, "*** rpmts_OpenDB(%p) ts %p\n", s, s->ts);
459
460     dbmode = rpmtsGetDBMode(s->ts);
461     if (dbmode == -1)
462         dbmode = O_RDONLY;
463
464     return Py_BuildValue("i", rpmtsOpenDB(s->ts, dbmode));
465 }
466
467 /** \ingroup py_c
468  */
469 static PyObject *
470 rpmts_CloseDB(rpmtsObject * s)
471 {
472     int rc;
473
474 if (_rpmts_debug)
475 fprintf(stderr, "*** rpmts_CloseDB(%p) ts %p\n", s, s->ts);
476
477     rc = rpmtsCloseDB(s->ts);
478     rpmtsSetDBMode(s->ts, -1);  /* XXX disable lazy opens */
479
480     return Py_BuildValue("i", rc);
481 }
482
483 /** \ingroup py_c
484  */
485 static PyObject *
486 rpmts_InitDB(rpmtsObject * s)
487 {
488     int rc;
489
490 if (_rpmts_debug)
491 fprintf(stderr, "*** rpmts_InitDB(%p) ts %p\n", s, s->ts);
492
493     rc = rpmtsInitDB(s->ts, O_RDONLY);
494     if (rc == 0)
495         rc = rpmtsCloseDB(s->ts);
496
497     return Py_BuildValue("i", rc);
498 }
499
500 /** \ingroup py_c
501  */
502 static PyObject *
503 rpmts_RebuildDB(rpmtsObject * s)
504 {
505     int rc;
506
507 if (_rpmts_debug)
508 fprintf(stderr, "*** rpmts_RebuildDB(%p) ts %p\n", s, s->ts);
509
510     Py_BEGIN_ALLOW_THREADS
511     rc = rpmtsRebuildDB(s->ts);
512     Py_END_ALLOW_THREADS
513
514     return Py_BuildValue("i", rc);
515 }
516
517 /** \ingroup py_c
518  */
519 static PyObject *
520 rpmts_VerifyDB(rpmtsObject * s)
521 {
522     int rc;
523
524 if (_rpmts_debug)
525 fprintf(stderr, "*** rpmts_VerifyDB(%p) ts %p\n", s, s->ts);
526
527     Py_BEGIN_ALLOW_THREADS
528     rc = rpmtsVerifyDB(s->ts);
529     Py_END_ALLOW_THREADS
530
531     return Py_BuildValue("i", rc);
532 }
533
534 /** \ingroup py_c
535  */
536 static PyObject *
537 rpmts_HdrFromFdno(rpmtsObject * s, PyObject * args, PyObject * kwds)
538 {
539     PyObject * result = NULL;
540     Header h;
541     FD_t fd;
542     int fdno;
543     rpmRC rpmrc;
544     char * kwlist[] = {"fd", NULL};
545
546     if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:HdrFromFdno", kwlist,
547             &fdno))
548         return NULL;
549
550     fd = fdDup(fdno);
551     rpmrc = rpmReadPackageFile(s->ts, fd, "rpmts_HdrFromFdno", &h);
552     Fclose(fd);
553
554 if (_rpmts_debug)
555 fprintf(stderr, "*** rpmts_HdrFromFdno(%p) ts %p rc %d\n", s, s->ts, rpmrc);
556
557     switch (rpmrc) {
558     case RPMRC_OK:
559         if (h)
560             result = Py_BuildValue("N", hdr_Wrap(h));
561         h = headerFree(h);      /* XXX ref held by result */
562         break;
563
564     case RPMRC_NOKEY:
565         PyErr_SetString(pyrpmError, "public key not available");
566         break;
567
568     case RPMRC_NOTTRUSTED:
569         PyErr_SetString(pyrpmError, "public key not trusted");
570         break;
571
572     case RPMRC_NOTFOUND:
573     case RPMRC_FAIL:
574     default:
575         PyErr_SetString(pyrpmError, "error reading package header");
576         break;
577     }
578
579     return result;
580 }
581
582 /** \ingroup py_c
583  */
584 static PyObject *
585 rpmts_HdrCheck(rpmtsObject * s, PyObject * args, PyObject * kwds)
586 {
587     PyObject * blob;
588     PyObject * result = NULL;
589     char * msg = NULL;
590     const void * uh;
591     int uc;
592     rpmRC rpmrc;
593     char * kwlist[] = {"headers", NULL};
594
595 if (_rpmts_debug)
596 fprintf(stderr, "*** rpmts_HdrCheck(%p) ts %p\n", s, s->ts);
597
598     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:HdrCheck", kwlist, &blob))
599         return NULL;
600
601     if (blob == Py_None) {
602         Py_RETURN_NONE;
603     }
604     if (!PyString_Check(blob)) {
605         PyErr_SetString(pyrpmError, "hdrCheck takes a string of octets");
606         return result;
607     }
608     uh = PyString_AsString(blob);
609     uc = PyString_Size(blob);
610
611     rpmrc = headerCheck(s->ts, uh, uc, &msg);
612
613     switch (rpmrc) {
614     case RPMRC_OK:
615         Py_INCREF(Py_None);
616         result = Py_None;
617         break;
618
619     case RPMRC_NOKEY:
620         PyErr_SetString(pyrpmError, "public key not availaiable");
621         break;
622
623     case RPMRC_NOTTRUSTED:
624         PyErr_SetString(pyrpmError, "public key not trusted");
625         break;
626
627     case RPMRC_FAIL:
628     default:
629         PyErr_SetString(pyrpmError, msg);
630         break;
631     }
632     msg = _free(msg);
633
634     return result;
635 }
636
637 /** \ingroup py_c
638  */
639 static PyObject *
640 rpmts_SetVSFlags(rpmtsObject * s, PyObject * args, PyObject * kwds)
641 {
642     rpmVSFlags vsflags;
643     char * kwlist[] = {"flags", NULL};
644
645 if (_rpmts_debug)
646 fprintf(stderr, "*** rpmts_SetVSFlags(%p) ts %p\n", s, s->ts);
647
648     if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:SetVSFlags", kwlist,
649             &vsflags))
650         return NULL;
651
652     /* XXX FIXME: value check on vsflags, or build pure python object 
653      * for it, and require an object of that type */
654
655     return Py_BuildValue("i", rpmtsSetVSFlags(s->ts, vsflags));
656 }
657
658 /** \ingroup py_c
659  */
660 static PyObject *
661 rpmts_GetVSFlags(rpmtsObject * s)
662 {
663     return Py_BuildValue("i", rpmtsVSFlags(s->ts));
664 }
665
666 /** \ingroup py_c
667  */
668 static PyObject *
669 rpmts_SetColor(rpmtsObject * s, PyObject * args, PyObject * kwds)
670 {
671     rpm_color_t tscolor;
672     char * kwlist[] = {"color", NULL};
673
674 if (_rpmts_debug)
675 fprintf(stderr, "*** rpmts_SetColor(%p) ts %p\n", s, s->ts);
676
677     if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:Color", kwlist, &tscolor))
678         return NULL;
679
680     /* XXX FIXME: value check on tscolor, or build pure python object
681      * for it, and require an object of that type */
682
683     return Py_BuildValue("i", rpmtsSetColor(s->ts, tscolor));
684 }
685
686 /** \ingroup py_c
687  */
688 static PyObject *
689 rpmts_PgpPrtPkts(rpmtsObject * s, PyObject * args, PyObject * kwds)
690 {
691     PyObject * blob;
692     unsigned char * pkt;
693     unsigned int pktlen;
694     int rc;
695     char * kwlist[] = {"octets", NULL};
696
697 if (_rpmts_debug)
698 fprintf(stderr, "*** rpmts_PgpPrtPkts(%p) ts %p\n", s, s->ts);
699
700     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:PgpPrtPkts", kwlist, &blob))
701         return NULL;
702
703     if (blob == Py_None) {
704         Py_RETURN_NONE;
705     }
706     if (!PyString_Check(blob)) {
707         PyErr_SetString(pyrpmError, "pgpPrtPkts takes a string of octets");
708         return NULL;
709     }
710     pkt = (unsigned char *)PyString_AsString(blob);
711     pktlen = PyString_Size(blob);
712
713     rc = pgpPrtPkts(pkt, pktlen, NULL, 1);
714
715     return Py_BuildValue("i", rc);
716 }
717
718 /** \ingroup py_c
719  */
720 static PyObject *
721 rpmts_PgpImportPubkey(rpmtsObject * s, PyObject * args, PyObject * kwds)
722 {
723     PyObject * blob;
724     unsigned char * pkt;
725     unsigned int pktlen;
726     int rc;
727     char * kwlist[] = {"pubkey", NULL};
728
729 if (_rpmts_debug)
730 fprintf(stderr, "*** rpmts_PgpImportPubkey(%p) ts %p\n", s, s->ts);
731
732     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:PgpImportPubkey",
733             kwlist, &blob))
734         return NULL;
735
736     if (blob == Py_None) {
737         Py_RETURN_NONE;
738     }
739     if (!PyString_Check(blob)) {
740         PyErr_SetString(pyrpmError, "PgpImportPubkey takes a string of octets");
741         return NULL;
742     }
743     pkt = (unsigned char *)PyString_AsString(blob);
744     pktlen = PyString_Size(blob);
745
746     rc = rpmtsImportPubkey(s->ts, pkt, pktlen);
747
748     return Py_BuildValue("i", rc);
749 }
750
751 /** \ingroup py_c
752  */
753 static PyObject *
754 rpmts_GetKeys(rpmtsObject * s)
755 {
756     const void **data = NULL;
757     int num, i;
758     PyObject *tuple;
759
760 if (_rpmts_debug)
761 fprintf(stderr, "*** rpmts_GetKeys(%p) ts %p\n", s, s->ts);
762
763     rpmtsGetKeys(s->ts, &data, &num);
764     if (data == NULL || num <= 0) {
765         data = _free(data);
766         Py_RETURN_NONE;
767     }
768
769     tuple = PyTuple_New(num);
770
771     for (i = 0; i < num; i++) {
772         PyObject *obj;
773         obj = (data[i] ? (PyObject *) data[i] : Py_None);
774         Py_INCREF(obj);
775         PyTuple_SetItem(tuple, i, obj);
776     }
777
778     data = _free(data);
779
780     return tuple;
781 }
782
783 /** \ingroup py_c
784  */
785 static void *
786 rpmtsCallback(const void * hd, const rpmCallbackType what,
787                          const rpm_loff_t amount, const rpm_loff_t total,
788                          const void * pkgKey, rpmCallbackData data)
789 {
790     Header h = (Header) hd;
791     struct rpmtsCallbackType_s * cbInfo = data;
792     PyObject * pkgObj = (PyObject *) pkgKey;
793     PyObject * args, * result;
794     static FD_t fd;
795
796     if (cbInfo->cb == Py_None) return NULL;
797
798     /* Synthesize a python object for callback (if necessary). */
799     if (pkgObj == NULL) {
800         if (h) {
801             pkgObj = Py_BuildValue("s", headerGetString(h, RPMTAG_NAME));
802         } else {
803             pkgObj = Py_None;
804             Py_INCREF(pkgObj);
805         }
806     } else
807         Py_INCREF(pkgObj);
808
809     PyEval_RestoreThread(cbInfo->_save);
810
811     args = Py_BuildValue("(iLLOO)", what, amount, total, pkgObj, cbInfo->data);
812     result = PyEval_CallObject(cbInfo->cb, args);
813     Py_DECREF(args);
814     Py_DECREF(pkgObj);
815
816     if (!result) {
817         die(cbInfo->cb);
818     }
819
820     if (what == RPMCALLBACK_INST_OPEN_FILE) {
821         int fdno;
822
823         if (!PyArg_Parse(result, "i", &fdno)) {
824             die(cbInfo->cb);
825         }
826         Py_DECREF(result);
827         cbInfo->_save = PyEval_SaveThread();
828
829         fd = fdDup(fdno);
830 if (_rpmts_debug)
831 fprintf(stderr, "\t%p = fdDup(%d)\n", fd, fdno);
832
833         fcntl(Fileno(fd), F_SETFD, FD_CLOEXEC);
834
835         return fd;
836     } else
837     if (what == RPMCALLBACK_INST_CLOSE_FILE) {
838 if (_rpmts_debug)
839 fprintf(stderr, "\tFclose(%p)\n", fd);
840         Fclose (fd);
841     } else {
842 if (_rpmts_debug)
843 fprintf(stderr, "\t%llu:%llu key %p\n", (long long) amount, (long long) total, pkgKey);
844     }
845
846     Py_DECREF(result);
847     cbInfo->_save = PyEval_SaveThread();
848
849     return NULL;
850 }
851
852 /** \ingroup py_c
853  */
854 static PyObject *
855 rpmts_SetFlags(rpmtsObject * s, PyObject * args, PyObject * kwds)
856 {
857     rpmtransFlags transFlags = 0;
858     char * kwlist[] = {"flags", NULL};
859
860     if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:SetFlags", kwlist,
861             &transFlags))
862         return NULL;
863
864 if (_rpmts_debug)
865 fprintf(stderr, "*** rpmts_SetFlags(%p) ts %p transFlags %x\n", s, s->ts, transFlags);
866
867     /* XXX FIXME: value check on flags, or build pure python object 
868      * for it, and require an object of that type */
869
870     return Py_BuildValue("i", rpmtsSetFlags(s->ts, transFlags));
871 }
872
873 /** \ingroup py_c
874  */
875 static PyObject *
876 rpmts_SetProbFilter(rpmtsObject * s, PyObject * args, PyObject * kwds)
877 {
878     rpmprobFilterFlags ignoreSet = 0;
879     rpmprobFilterFlags oignoreSet;
880     char * kwlist[] = {"ignoreSet", NULL};
881
882     if (!PyArg_ParseTupleAndKeywords(args, kwds, "i:ProbFilter", kwlist,
883             &ignoreSet))
884         return NULL;
885
886 if (_rpmts_debug)
887 fprintf(stderr, "*** rpmts_SetProbFilter(%p) ts %p ignoreSet %x\n", s, s->ts, ignoreSet);
888
889     oignoreSet = s->ignoreSet;
890     s->ignoreSet = ignoreSet;
891
892     return Py_BuildValue("i", oignoreSet);
893 }
894
895 /** \ingroup py_c
896  */
897 static rpmpsObject *
898 rpmts_Problems(rpmtsObject * s)
899 {
900
901 if (_rpmts_debug)
902 fprintf(stderr, "*** rpmts_Problems(%p) ts %p\n", s, s->ts);
903
904     return rpmps_Wrap( rpmtsProblems(s->ts) );
905 }
906
907 /** \ingroup py_c
908  */
909 static PyObject *
910 rpmts_Run(rpmtsObject * s, PyObject * args, PyObject * kwds)
911 {
912     int rc;
913     PyObject * list;
914     rpmps ps;
915     rpmpsi psi;
916     struct rpmtsCallbackType_s cbInfo;
917     char * kwlist[] = {"callback", "data", NULL};
918
919     if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO:Run", kwlist,
920             &cbInfo.cb, &cbInfo.data))
921         return NULL;
922
923     cbInfo.tso = s;
924     cbInfo._save = PyEval_SaveThread();
925
926     if (cbInfo.cb != NULL) {
927         if (!PyCallable_Check(cbInfo.cb)) {
928             PyErr_SetString(PyExc_TypeError, "expected a callable");
929             return NULL;
930         }
931         (void) rpmtsSetNotifyCallback(s->ts, rpmtsCallback, (void *) &cbInfo);
932     }
933
934 if (_rpmts_debug)
935 fprintf(stderr, "*** rpmts_Run(%p) ts %p ignore %x\n", s, s->ts, s->ignoreSet);
936
937     rc = rpmtsRun(s->ts, NULL, s->ignoreSet);
938     ps = rpmtsProblems(s->ts);
939
940     if (cbInfo.cb)
941         (void) rpmtsSetNotifyCallback(s->ts, NULL, NULL);
942
943     PyEval_RestoreThread(cbInfo._save);
944
945     if (rc < 0) {
946         list = PyList_New(0);
947         return list;
948     } else if (!rc) {
949         Py_RETURN_NONE;
950     }
951
952     list = PyList_New(0);
953     psi = rpmpsInitIterator(ps);
954     while (rpmpsNextIterator(psi) >= 0) {
955         rpmProblem p = rpmpsGetProblem(psi);
956         char * ps = rpmProblemString(p);
957         PyObject * prob = Py_BuildValue("s(isN)", ps,
958                              rpmProblemGetType(p),
959                              rpmProblemGetStr(p),
960                              PyLong_FromLongLong(rpmProblemGetDiskNeed(p)));
961         PyList_Append(list, prob);
962         free(ps);
963         Py_DECREF(prob);
964     }
965
966     psi = rpmpsFreeIterator(psi);
967     ps = rpmpsFree(ps);
968
969     return list;
970 }
971
972 /**
973  * @todo Add TR_ADDED filter to iterator.
974  */
975 static PyObject *
976 rpmts_iternext(rpmtsObject * s)
977 {
978     PyObject * result = NULL;
979     rpmte te;
980
981 if (_rpmts_debug)
982 fprintf(stderr, "*** rpmts_iternext(%p) ts %p tsi %p %d\n", s, s->ts, s->tsi, s->tsiFilter);
983
984     /* Reset iterator on 1st entry. */
985     if (s->tsi == NULL) {
986         s->tsi = rpmtsiInit(s->ts);
987         if (s->tsi == NULL)
988             return NULL;
989         s->tsiFilter = 0;
990     }
991
992     te = rpmtsiNext(s->tsi, s->tsiFilter);
993     if (te != NULL) {
994         result = (PyObject *) rpmte_Wrap(te);
995     } else {
996         s->tsi = rpmtsiFree(s->tsi);
997         s->tsiFilter = 0;
998     }
999
1000     return result;
1001 }
1002
1003 /**
1004  */
1005 static specObject *
1006 spec_Parse(rpmtsObject * s, PyObject * args, PyObject * kwds)
1007 {
1008     const char * specfile;
1009     rpmSpec spec;
1010     char * buildRoot = NULL;
1011     int recursing = 0;
1012     char * passPhrase = "";
1013     char *cookie = NULL;
1014     int anyarch = 1;
1015     int force = 1;
1016     char * kwlist[] = {"specfile", NULL};
1017
1018     if (!PyArg_ParseTupleAndKeywords(args, kwds, "s:Parse", kwlist, &specfile))
1019         return NULL;
1020
1021     if (parseSpec(s->ts, specfile,"/", buildRoot,recursing, passPhrase,
1022              cookie, anyarch, force)!=0) {
1023              PyErr_SetString(pyrpmError, "can't parse specfile\n");
1024                      return NULL;
1025    }
1026
1027     spec = rpmtsSpec(s->ts);
1028     return spec_Wrap(spec);
1029 }
1030
1031 /**
1032  */
1033 static rpmmiObject *
1034 rpmts_Match(rpmtsObject * s, PyObject * args, PyObject * kwds)
1035 {
1036     PyObject *TagN = NULL;
1037     PyObject *Key = NULL;
1038     char *key = NULL;
1039 /* XXX lkey *must* be a 32 bit integer, int "works" on all known platforms. */
1040     int lkey = 0;
1041     int len = 0;
1042     rpmTag tag = RPMDBI_PACKAGES;
1043     char * kwlist[] = {"tagNumber", "key", NULL};
1044
1045 if (_rpmts_debug)
1046 fprintf(stderr, "*** rpmts_Match(%p) ts %p\n", s, s->ts);
1047
1048     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO:Match", kwlist,
1049             &TagN, &Key))
1050         return NULL;
1051
1052     if (TagN && (tag = tagNumFromPyObject (TagN)) == RPMTAG_NOT_FOUND) {
1053         return NULL;
1054     }
1055
1056     if (Key) {
1057         if (PyString_Check(Key)) {
1058             key = PyString_AsString(Key);
1059             len = PyString_Size(Key);
1060         } else if (PyInt_Check(Key)) {
1061             lkey = PyInt_AsLong(Key);
1062             key = (char *)&lkey;
1063             len = sizeof(lkey);
1064         } else {
1065             PyErr_SetString(PyExc_TypeError, "unknown key type");
1066             return NULL;
1067         }
1068         /* One of the conversions above failed, exception is set already */
1069         if (PyErr_Occurred()) {
1070             return NULL;
1071         }
1072     }
1073
1074     /* XXX If not already opened, open the database O_RDONLY now. */
1075     /* XXX FIXME: lazy default rdonly open also done by rpmtsInitIterator(). */
1076     if (rpmtsGetRdb(s->ts) == NULL) {
1077         int rc = rpmtsOpenDB(s->ts, O_RDONLY);
1078         if (rc || rpmtsGetRdb(s->ts) == NULL) {
1079             PyErr_SetString(PyExc_TypeError, "rpmdb open failed");
1080             return NULL;
1081         }
1082     }
1083
1084     return rpmmi_Wrap( rpmtsInitIterator(s->ts, tag, key, len), (PyObject*)s);
1085 }
1086
1087 /** \ingroup py_c
1088  */
1089 static struct PyMethodDef rpmts_methods[] = {
1090  {"Debug",      (PyCFunction)rpmts_Debug,       METH_VARARGS|METH_KEYWORDS,
1091         NULL},
1092
1093  {"addInstall", (PyCFunction) rpmts_AddInstall, METH_VARARGS|METH_KEYWORDS,
1094         NULL },
1095  {"addErase",   (PyCFunction) rpmts_AddErase,   METH_VARARGS|METH_KEYWORDS,
1096         NULL },
1097  {"check",      (PyCFunction) rpmts_Check,      METH_VARARGS|METH_KEYWORDS,
1098         NULL },
1099  {"order",      (PyCFunction) rpmts_Order,      METH_NOARGS,
1100         NULL },
1101  {"setFlags",   (PyCFunction) rpmts_SetFlags,   METH_VARARGS|METH_KEYWORDS,
1102 "ts.setFlags(transFlags) -> previous transFlags\n\
1103 - Set control bit(s) for executing ts.run().\n\
1104   Note: This method replaces the 1st argument to the old ts.run()\n" },
1105  {"setProbFilter",      (PyCFunction) rpmts_SetProbFilter,      METH_VARARGS|METH_KEYWORDS,
1106 "ts.setProbFilter(ignoreSet) -> previous ignoreSet\n\
1107 - Set control bit(s) for ignoring problems found by ts.run().\n\
1108   Note: This method replaces the 2nd argument to the old ts.run()\n" },
1109  {"problems",   (PyCFunction) rpmts_Problems,   METH_NOARGS,
1110 "ts.problems() -> ps\n\
1111 - Return current problem set.\n" },
1112  {"run",        (PyCFunction) rpmts_Run,        METH_VARARGS|METH_KEYWORDS,
1113 "ts.run(callback, data) -> (problems)\n\
1114 - Run a transaction set, returning list of problems found.\n\
1115   Note: The callback may not be None.\n" },
1116  {"clean",      (PyCFunction) rpmts_Clean,      METH_NOARGS,
1117         NULL },
1118  {"openDB",     (PyCFunction) rpmts_OpenDB,     METH_NOARGS,
1119 "ts.openDB() -> None\n\
1120 - Open the default transaction rpmdb.\n\
1121   Note: The transaction rpmdb is lazily opened, so ts.openDB() is seldom needed.\n" },
1122  {"closeDB",    (PyCFunction) rpmts_CloseDB,    METH_NOARGS,
1123 "ts.closeDB() -> None\n\
1124 - Close the default transaction rpmdb.\n\
1125   Note: ts.closeDB() disables lazy opens, and should hardly ever be used.\n" },
1126  {"initDB",     (PyCFunction) rpmts_InitDB,     METH_NOARGS,
1127 "ts.initDB() -> None\n\
1128 - Initialize the default transaction rpmdb.\n\
1129  Note: ts.initDB() is seldom needed anymore.\n" },
1130  {"rebuildDB",  (PyCFunction) rpmts_RebuildDB,  METH_NOARGS,
1131 "ts.rebuildDB() -> None\n\
1132 - Rebuild the default transaction rpmdb.\n" },
1133  {"verifyDB",   (PyCFunction) rpmts_VerifyDB,   METH_NOARGS,
1134 "ts.verifyDB() -> None\n\
1135 - Verify the default transaction rpmdb.\n" },
1136  {"hdrFromFdno",(PyCFunction) rpmts_HdrFromFdno,METH_VARARGS|METH_KEYWORDS,
1137 "ts.hdrFromFdno(fdno) -> hdr\n\
1138 - Read a package header from a file descriptor.\n" },
1139  {"hdrCheck",   (PyCFunction) rpmts_HdrCheck,   METH_VARARGS|METH_KEYWORDS,
1140         NULL },
1141  {"setVSFlags",(PyCFunction) rpmts_SetVSFlags,  METH_VARARGS|METH_KEYWORDS,
1142 "ts.setVSFlags(vsflags) -> ovsflags\n\
1143 - Set signature verification flags. Values for vsflags are:\n\
1144     rpm.RPMVSF_NOHDRCHK      if set, don't check rpmdb headers\n\
1145     rpm.RPMVSF_NEEDPAYLOAD   if not set, check header+payload (if possible)\n\
1146     rpm.RPMVSF_NOSHA1HEADER  if set, don't check header SHA1 digest\n\
1147     rpm.RPMVSF_NODSAHEADER   if set, don't check header DSA signature\n\
1148     rpm.RPMVSF_NOMD5         if set, don't check header+payload MD5 digest\n\
1149     rpm.RPMVSF_NODSA         if set, don't check header+payload DSA signature\n\
1150     rpm.RPMVSF_NORSA         if set, don't check header+payload RSA signature\n\
1151     rpm._RPMVSF_NODIGESTS    if set, don't check digest(s)\n\
1152     rpm._RPMVSF_NOSIGNATURES if set, don't check signature(s)\n" },
1153  {"getVSFlags",(PyCFunction) rpmts_GetVSFlags,  METH_NOARGS,
1154 "ts.getVSFlags() -> vsflags\n\
1155 - Retrieve current signature verification flags from transaction\n" },
1156  {"setColor",(PyCFunction) rpmts_SetColor,      METH_VARARGS|METH_KEYWORDS,
1157         NULL },
1158  {"pgpPrtPkts", (PyCFunction) rpmts_PgpPrtPkts, METH_VARARGS|METH_KEYWORDS,
1159         NULL },
1160  {"pgpImportPubkey",    (PyCFunction) rpmts_PgpImportPubkey,    METH_VARARGS|METH_KEYWORDS,
1161         NULL },
1162  {"getKeys",    (PyCFunction) rpmts_GetKeys,    METH_NOARGS,
1163         NULL },
1164  {"parseSpec",  (PyCFunction) spec_Parse,       METH_VARARGS|METH_KEYWORDS,
1165 "ts.parseSpec(\"/path/to/foo.spec\") -> spec\n\
1166 - Parse a spec file.\n" },
1167  {"dbMatch",    (PyCFunction) rpmts_Match,      METH_VARARGS|METH_KEYWORDS,
1168 "ts.dbMatch([TagN, [key, [len]]]) -> mi\n\
1169 - Create a match iterator for the default transaction rpmdb.\n" },
1170     {NULL,              NULL}           /* sentinel */
1171 };
1172
1173 /** \ingroup py_c
1174  */
1175 static void rpmts_dealloc(rpmtsObject * s)
1176 {
1177
1178 if (_rpmts_debug)
1179 fprintf(stderr, "%p -- ts %p db %p\n", s, s->ts, rpmtsGetRdb(s->ts));
1180     s->ts = rpmtsFree(s->ts);
1181
1182     if (s->scriptFd) Fclose(s->scriptFd);
1183     /* this will free the keyList, and decrement the ref count of all
1184        the items on the list as well :-) */
1185     Py_DECREF(s->keyList);
1186     PyObject_Del((PyObject *)s);
1187 }
1188
1189 static PyObject * rpmts_getattro(PyObject * o, PyObject * n)
1190 {
1191     return PyObject_GenericGetAttr(o, n);
1192 }
1193
1194 /** \ingroup py_c
1195  */
1196 static int rpmts_setattro(PyObject * o, PyObject * n, PyObject * v)
1197 {
1198     rpmtsObject *s = (rpmtsObject *)o;
1199     char * name = PyString_AsString(n);
1200     int fdno;
1201
1202     if (rstreq(name, "scriptFd")) {
1203         if (!PyArg_Parse(v, "i", &fdno)) return 0;
1204         if (fdno < 0) {
1205             PyErr_SetString(PyExc_TypeError, "bad file descriptor");
1206             return -1;
1207         } else {
1208             s->scriptFd = fdDup(fdno);
1209             rpmtsSetScriptFd(s->ts, s->scriptFd);
1210         }
1211     } else {
1212         PyErr_SetString(PyExc_AttributeError, name);
1213         return -1;
1214     }
1215
1216     return 0;
1217 }
1218
1219 /** \ingroup py_c
1220  */
1221 static void rpmts_free(rpmtsObject * s)
1222 {
1223 if (_rpmts_debug)
1224 fprintf(stderr, "%p -- ts %p db %p\n", s, s->ts, rpmtsGetRdb(s->ts));
1225     s->ts = rpmtsFree(s->ts);
1226
1227     if (s->scriptFd)
1228         Fclose(s->scriptFd);
1229
1230     /* this will free the keyList, and decrement the ref count of all
1231        the items on the list as well :-) */
1232     Py_DECREF(s->keyList);
1233
1234     PyObject_Del((PyObject *)s);
1235 }
1236
1237 /** \ingroup py_c
1238  */
1239 static PyObject * rpmts_new(PyTypeObject * subtype, PyObject *args, PyObject *kwds)
1240 {
1241     rpmtsObject * s = (void *) PyObject_New(rpmtsObject, subtype);
1242
1243     char * rootDir = "/";
1244     rpmVSFlags vsflags = rpmExpandNumeric("%{?__vsflags}");
1245     char * kwlist[] = {"rootdir", "vsflags", 0};
1246
1247     if (_rpmts_debug < 0)
1248         fprintf(stderr, "*** rpmts_new(%p,%p,%p)\n", s, args, kwds);
1249
1250     if (!PyArg_ParseTupleAndKeywords(args, kwds, "|si:rpmts_new", kwlist,
1251             &rootDir, &vsflags))
1252         return NULL;
1253
1254     s->ts = rpmtsCreate();
1255     /* XXX: Why is there no rpmts_SetRootDir() ? */
1256     (void) rpmtsSetRootDir(s->ts, rootDir);
1257     /* XXX: make this use common code with rpmts_SetVSFlags() to check the
1258      *      python objects */
1259     (void) rpmtsSetVSFlags(s->ts, vsflags);
1260     s->keyList = PyList_New(0);
1261     s->scriptFd = NULL;
1262     s->tsi = NULL;
1263     s->tsiFilter = 0;
1264
1265     if (_rpmts_debug)
1266         fprintf(stderr, "%p ++ ts %p db %p\n", s, s->ts, rpmtsGetRdb(s->ts));
1267
1268     return (PyObject *)s;
1269 }
1270
1271 /**
1272  */
1273 static char rpmts_doc[] =
1274 "";
1275
1276 /** \ingroup py_c
1277  */
1278 PyTypeObject rpmts_Type = {
1279         PyObject_HEAD_INIT(&PyType_Type)
1280         0,                              /* ob_size */
1281         "rpm.ts",                       /* tp_name */
1282         sizeof(rpmtsObject),            /* tp_size */
1283         0,                              /* tp_itemsize */
1284         (destructor) rpmts_dealloc,     /* tp_dealloc */
1285         0,                              /* tp_print */
1286         (getattrfunc)0,                 /* tp_getattr */
1287         (setattrfunc)0,                 /* tp_setattr */
1288         0,                              /* tp_compare */
1289         0,                              /* tp_repr */
1290         0,                              /* tp_as_number */
1291         0,                              /* tp_as_sequence */
1292         0,                              /* tp_as_mapping */
1293         0,                              /* tp_hash */
1294         0,                              /* tp_call */
1295         0,                              /* tp_str */
1296         (getattrofunc) rpmts_getattro,  /* tp_getattro */
1297         (setattrofunc) rpmts_setattro,  /* tp_setattro */
1298         0,                              /* tp_as_buffer */
1299         Py_TPFLAGS_DEFAULT,             /* tp_flags */
1300         rpmts_doc,                      /* tp_doc */
1301         0,                              /* tp_traverse */
1302         0,                              /* tp_clear */
1303         0,                              /* tp_richcompare */
1304         0,                              /* tp_weaklistoffset */
1305         PyObject_SelfIter,              /* tp_iter */
1306         (iternextfunc) rpmts_iternext,  /* tp_iternext */
1307         rpmts_methods,                  /* tp_methods */
1308         0,                              /* tp_members */
1309         0,                              /* tp_getset */
1310         0,                              /* tp_base */
1311         0,                              /* tp_dict */
1312         0,                              /* tp_descr_get */
1313         0,                              /* tp_descr_set */
1314         0,                              /* tp_dictoffset */
1315         0,                              /* tp_init */
1316         0,                              /* tp_alloc */
1317         (newfunc) rpmts_new,            /* tp_new */
1318         (freefunc) rpmts_free,          /* tp_free */
1319         0,                              /* tp_is_gc */
1320 };
1321
1322 /**
1323  */
1324 PyObject *
1325 rpmts_Create(PyObject * self, PyObject * args, PyObject * kwds)
1326 {
1327     return PyObject_Call((PyObject *) &rpmts_Type, args, kwds);
1328 }