chiark / gitweb /
key.c: Rename sad-path label to `end'.
[catacomb-python] / key.c
1 /* -*-c-*-
2  *
3  * Key files and data
4  *
5  * (c) 2005 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of the Python interface to Catacomb.
11  *
12  * Catacomb/Python is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * Catacomb/Python is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with Catacomb/Python; if not, write to the Free Software Foundation,
24  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25  */
26
27 /*----- Header files ------------------------------------------------------*/
28
29 #include "catacomb-python.h"
30
31 /*----- Exceptions --------------------------------------------------------*/
32
33 static PyObject *keyexc;
34 static PyObject *keyioexc;
35 static PyObject *keyfilebrokenexc;
36
37 static PyObject *kxmeth___init__(PyObject *me, PyObject *arg)
38 {
39   int err;
40   PyObject *x = 0;
41
42   if (!PyArg_ParseTuple(arg, "Oi:__init__", &me, &err) ||
43       (x = PyInt_FromLong(err)) == 0 ||
44       PyObject_SetAttrString(me, "err", x))
45     goto end;
46   Py_DECREF(x); x = 0;
47   if ((x = PyString_FromString(key_strerror(err))) == 0 ||
48       PyObject_SetAttrString(me, "errstring", x))
49     goto end;
50   Py_DECREF(x); x = 0;
51   if ((x = PySequence_GetSlice(arg, 1, PySequence_Size(arg))) == 0 ||
52       PyObject_SetAttrString(me, "args", x))
53     goto end;
54   Py_DECREF(x); x = 0;
55   RETURN_NONE;
56
57 end:
58   Py_XDECREF(x);
59   return (0);
60 }
61
62 static PyObject *kxmeth___str__(PyObject *me, PyObject *arg)
63 {
64   long err;
65   const char *errstr, *errtag;
66   PyObject *x = 0;
67   PyObject *rc = 0;
68
69   static const char *const tab[] = {
70 #define ENTRY(tag, num, str) "KERR_" #tag,
71     KEY_ERRORS(ENTRY)
72 #undef ENTRY
73   };
74
75   if (!PyArg_ParseTuple(arg, "O:__str__", &me) ||
76       (x = PyObject_GetAttrString(me, "err")) == 0 ||
77       (err = PyInt_AsLong(x), PyErr_Occurred()))
78     goto done;
79   Py_DECREF(x); x = 0;
80   err = -err;
81   if (err >= 0 && err < N(tab)) errtag = tab[err];
82   else errtag = "<unknown>";
83   if ((x = PyObject_GetAttrString(me, "errstring")) == 0 ||
84       (errstr = PyString_AsString(x)) == 0)
85     goto done;
86   rc = PyString_FromFormat("%s (%ld): %s", errtag, -err, errstr);
87
88 done:
89   Py_XDECREF(x);
90   return (rc);
91 }
92
93 static PyMethodDef keyexc_pymethods[] = {
94 #define METHNAME(func) kxmeth_##func
95   METH  (__init__,              "KeyError(CODE)")
96   METH  (__str__,               "E.__str__() -> STRING")
97 #undef METHNAME
98   { 0 }
99 };
100
101 static void keyexc_raise(int err)
102 {
103   PyObject *arg = Py_BuildValue("(i)", err);
104   if (arg) PyErr_SetObject(keyexc, arg);
105   Py_XDECREF(arg);
106 }
107 #define KEYERR(err) do { keyexc_raise(err); goto end; } while (0)
108 #define KEYIOERR(name) do {                                             \
109   PyErr_SetFromErrnoWithFilename(keyioexc, name);                       \
110   goto end;                                                             \
111 } while (0)
112 #define KEYFILEBROKEN(name) do {                                        \
113   PyErr_SetFromErrnoWithFilename(keyfilebrokenexc, name);               \
114   goto end;                                                             \
115 } while (0)
116
117 /*----- Data structures ---------------------------------------------------*/
118
119 typedef struct keydata_pyobj {
120   PyObject_HEAD
121   key_data *kd;
122 } keydata_pyobj;
123
124 static PyTypeObject *keydata_pytype;
125 static PyTypeObject *keydatabin_pytype;
126 static PyTypeObject *keydataenc_pytype;
127 static PyTypeObject *keydatamp_pytype;
128 static PyTypeObject *keydatastruct_pytype;
129 static PyTypeObject *keydatastr_pytype;
130 static PyTypeObject *keydataec_pytype;
131 #define KEYDATA_PYCHECK(o) PyObject_TypeCheck(o, keydata_pytype)
132 #define KEYDATA_KD(o) (((keydata_pyobj *)(o))->kd)
133
134 typedef struct subkeyiter_pyobj {
135   PyObject_HEAD
136   key_subkeyiter i;
137   PyObject *kdobj;
138 } subkeyiter_pyobj;
139
140 static PyTypeObject *subkeyiter_pytype;
141 #define SUBKEYITER_PYCHECK(o) PyObject_TypeCheck(o, subkeyiter_pytype);
142 #define SUBKEYITER_I(o) (&((subkeyiter_pyobj *)(o))->i)
143 #define SUBKEYITER_KDOBJ(o) (((subkeyiter_pyobj *)(o))->kdobj)
144
145 typedef struct keyfile_pyobj {
146   PyObject_HEAD
147   key_file kf;
148 } keyfile_pyobj;
149
150 static PyTypeObject *keyfile_pytype;
151 #define KEYFILE_PYCHECK(o) PyObject_TypeCheck(o, keyfile_pytype)
152 #define KEYFILE_KF(o) (&((keyfile_pyobj *)(o))->kf)
153
154 typedef struct key_pyobj {
155   PyObject_HEAD
156   key *k;
157   PyObject *kfobj;
158 } key_pyobj;
159
160 static PyTypeObject *key_pytype;
161 #define KEY_PYCHECK(o) PyObject_TypeCheck(o, key_pytype)
162 #define KEY_K(o) (((key_pyobj *)(o))->k)
163 #define KEY_KFOBJ(o) (((key_pyobj *)(o))->kfobj)
164 #define KEY_KF(o) KEYFILE_KF(KEY_KFOBJ(o))
165
166 typedef struct keyiter_pyobj {
167   PyObject_HEAD
168   key_iter i;
169   PyObject *kfobj;
170 } keyiter_pyobj;
171
172 static PyTypeObject *keyiter_pytype;
173 #define KEYITER_PYCHECK(o) PyObject_TypeCheck(o, keyiter_pytype)
174 #define KEYITER_I(o) (&((keyiter_pyobj *)(o))->i)
175 #define KEYITER_KFOBJ(o) (((keyiter_pyobj *)(o))->kfobj)
176 #define KEYITER_KF(o) KEYFILE_KF(KEYITER_KFOBJ(o))
177
178 typedef struct keyattrs_pyobj {
179   PyObject_HEAD
180   PyObject *kobj;
181 } keyattrs_pyobj;
182
183 static PyTypeObject *keyattrs_pytype;
184 #define KEYATTRS_PYCHECK(o) PyObject_TypeCheck(o, keyattrs_pytype)
185 #define KEYATTRS_KOBJ(o) (((keyattrs_pyobj *)(o))->kobj)
186 #define KEYATTRS_KF(o) KEY_KF(KEYATTRS_KOBJ(o))
187 #define KEYATTRS_K(o) KEY_K(KEYATTRS_KOBJ(o))
188
189 typedef struct keyattriter_pyobj {
190   PyObject_HEAD
191   key_attriter i;
192   PyObject *kobj;
193 } keyattriter_pyobj;
194
195 static PyTypeObject *keyattriter_pytype;
196 #define KEYATTRITER_PYCHECK(o) PyObject_TypeCheck(o, keyattriter_pytype)
197 #define KEYATTRITER_I(o) (&((keyattriter_pyobj *)(o))->i)
198 #define KEYATTRITER_KOBJ(o) (((keyattriter_pyobj *)(o))->kobj)
199 #define KEYATTRITER_K(o) KEY_K(KEYATTRITER_KOBJ(o))
200 #define KEYATTRITER_KFOBJ(o) KEY_KFOBJ(KEYATTRITER_KOBJ(o))
201 #define KEYATTRITER_KF(o) KEY_KF(KEYATTRITER_KOBJ(o))
202
203 /*----- Filters -----------------------------------------------------------*/
204
205 static int convfilter(PyObject *x, void *p)
206 {
207   key_filter *f = p;
208   const char *fs;
209   char *end;
210   int n;
211   PyObject *a = 0, *b = 0;
212   int err;
213   int rc = 0;
214
215   if ((fs = PyString_AsString(x)) != 0) {
216     if ((err = key_readflags(fs, &end, &f->f, &f->m)) != 0)
217       KEYERR(err);
218     if (*end)
219       KEYERR(KERR_BADFLAGS);
220   } else {
221     PyErr_Clear();
222     if (!PySequence_Check(x))
223       goto tyerr;
224     else if ((n = PySequence_Size(x)) < 0)
225       goto end;
226     else if (n != 2)
227       goto tyerr;
228     else if ((a = PySequence_GetItem(x, 0)) == 0 || !convuint(a, &f->f) ||
229              (b = PySequence_GetItem(x, 1)) == 0 || !convuint(b, &f->m))
230       goto end;
231   }
232   rc = 1;
233   goto end;
234 tyerr:
235   TYERR("expected flag string or flag/mask pair");
236 end:
237   Py_XDECREF(a);
238   Py_XDECREF(b);
239   return (rc);
240 }
241
242 static int convflags(PyObject *x, void *p)
243 {
244   unsigned *f = p;
245   const char *fs;
246   char *end;
247   int err;
248   int rc = 0;
249
250   if (convuint(x, p))
251     return (1);
252   else {
253     PyErr_Clear();
254     if ((fs = PyString_AsString(x)) != 0) {
255       if ((err = key_readflags(fs, &end, f, 0)) != 0)
256         KEYERR(err);
257       if (*end)
258         KEYERR(KERR_BADFLAGS);
259     } else {
260       PyErr_Clear();
261       goto tyerr;
262     }
263   }
264   rc = 1;
265   goto end;
266 tyerr:
267   TYERR("expected flag string or integer bitfield");
268 end:
269   return (rc);
270 }
271
272 static PyObject *meth__KeyData_readflags(PyObject *me, PyObject *arg)
273 {
274   const char *p;
275   char *end;
276   unsigned f, m;
277   PyObject *rc = 0;
278   int err;
279
280   if (!PyArg_ParseTuple(arg, "Os:key_readflags", &me, &p))
281     goto end;
282   if ((err = key_readflags(p, &end, &f, &m)) != 0)
283     KEYERR(err);
284   rc = Py_BuildValue("(NNs)", getulong(f), getulong(m), end);
285 end:
286   return (rc);
287 }
288
289 static PyObject *meth__KeyData_writeflags(PyObject *me, PyObject *arg)
290 {
291   dstr d = DSTR_INIT;
292   PyObject *rc;
293   unsigned f;
294
295   if (!PyArg_ParseTuple(arg, "OO&:key_writeflags", &me, convuint, &f))
296     return (0);
297   key_writeflags(f, &d);
298   rc = PyString_FromStringAndSize(d.buf, d.len);
299   dstr_destroy(&d);
300   return (rc);
301 }
302
303 /*----- Key data ----------------------------------------------------------*/
304
305 static PyObject *keydata_pywrap(key_data *kd)
306 {
307   PyTypeObject *ty;
308   keydata_pyobj *kdobj;
309
310   switch (kd->e & KF_ENCMASK) {
311     case KENC_BINARY: ty = keydatabin_pytype; break;
312     case KENC_ENCRYPT: ty = keydataenc_pytype; break;
313     case KENC_MP: ty = keydatamp_pytype; break;
314     case KENC_STRUCT: ty = keydatastruct_pytype; break;
315     case KENC_STRING: ty = keydatastr_pytype; break;
316     case KENC_EC: ty = keydataec_pytype; break;
317     default: abort();
318   }
319   kdobj = PyObject_NEW(keydata_pyobj, ty);
320   kdobj->kd = kd;
321   return ((PyObject *)kdobj);
322 }
323
324 static void keydata_pydealloc(PyObject *me)
325 {
326   key_drop(KEYDATA_KD(me));
327   FREEOBJ(me);
328 }
329
330 static PyObject *kdmeth_matchp(PyObject *me, PyObject *arg)
331 {
332   key_filter f;
333
334   if (!PyArg_ParseTuple(arg, "O&:matchp", convfilter, &f))
335     return (0);
336   return (getbool(KEY_MATCH(KEYDATA_KD(me), &f)));
337 }
338
339 static PyObject *kdmeth_split(PyObject *me, PyObject *arg)
340 {
341   if (!PyArg_ParseTuple(arg, ":split"))
342     return (0);
343   key_split(&KEYDATA_KD(me));
344   RETURN_ME;
345 }
346
347 static PyObject *kdmeth_copy(PyObject *me, PyObject *arg, PyObject *kw)
348 {
349   key_filter f = { 0, 0 };
350   static char *kwlist[] = { "filter", 0 };
351   key_data *kd;
352
353   if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:copy", kwlist,
354                                    convfilter, &f))
355     return (0);
356   if ((kd = key_copydata(KEYDATA_KD(me), &f)) == 0)
357     RETURN_NONE;
358   else
359     return (keydata_pywrap(kd));
360 }
361
362 static PyObject *kdmeth_write(PyObject *me, PyObject *arg, PyObject *kw)
363 {
364   key_filter f = { 0, 0 };
365   dstr d = DSTR_INIT;
366   PyObject *rc = 0;
367   static char *kwlist[] = { "filter", 0 };
368
369   if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:write", kwlist,
370                                    convfilter, &f))
371     return (0);
372   key_write(KEYDATA_KD(me), &d, &f);
373   rc = PyString_FromStringAndSize(d.buf, d.len);
374   dstr_destroy(&d);
375   return (rc);
376 }
377
378 static PyObject *kdmeth_encode(PyObject *me, PyObject *arg, PyObject *kw)
379 {
380   key_filter f = { 0, 0 };
381   dstr d = DSTR_INIT;
382   PyObject *rc = 0;
383   static char *kwlist[] = { "filter", 0 };
384
385   if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O&:encode", kwlist,
386                                    convfilter, &f))
387     return (0);
388   key_encode(KEYDATA_KD(me), &d, &f);
389   rc = bytestring_pywrap(d.buf, d.len);
390   dstr_destroy(&d);
391   return (rc);
392 }
393
394 static PyObject *kdmeth_plock(PyObject *me, PyObject *arg)
395 {
396   char *tag;
397   int err;
398   PyObject *rc = 0;
399   key_data *kd;
400
401   if (!PyArg_ParseTuple(arg, "s:plock", &tag))
402     goto end;
403   if ((err = key_plock(&kd, KEYDATA_KD(me), tag)) != 0)
404     KEYERR(err);
405   rc = keydata_pywrap(kd);
406 end:
407   return (rc);
408 }
409
410 static PyObject *kdmeth_lock(PyObject *me, PyObject *arg)
411 {
412   char *p;
413   Py_ssize_t n;
414   PyObject *rc = 0;
415   key_data *kd;
416
417   if (!PyArg_ParseTuple(arg, "s#:lock", &p, &n))
418     goto end;
419   key_lock(&kd, KEYDATA_KD(me), p, n);
420   rc = keydata_pywrap(kd);
421 end:
422   return (rc);
423 }
424
425 static PyObject *meth__KeyData_read(PyObject *me, PyObject *arg)
426 {
427   const char *p;
428   char *end;
429   key_data *kd;
430   PyObject *rc = 0;
431
432   if (!PyArg_ParseTuple(arg, "Os:read", &me, &p))
433     goto end;
434   if ((kd = key_read(p, &end)) == 0)
435     KEYERR(KERR_MALFORMED);
436   rc = Py_BuildValue("(Ns)", keydata_pywrap(kd), end);
437 end:
438   return (rc);
439 }
440
441 static PyObject *meth__KeyData_decode(PyObject *me, PyObject *arg)
442 {
443   const char *p;
444   Py_ssize_t n;
445   key_data *kd;
446   PyObject *rc = 0;
447
448   if (!PyArg_ParseTuple(arg, "Os#:decode", &me, &p, &n))
449     goto end;
450   if ((kd = key_decode(p, n)) == 0)
451     KEYERR(KERR_MALFORMED);
452   rc =  keydata_pywrap(kd);
453 end:
454   return (rc);
455 }
456
457 static PyObject *kdget_flags(PyObject *me, void *hunoz)
458   { return (getulong(KEYDATA_KD(me)->e)); }
459
460 static PyMethodDef keydata_pymethods[] = {
461 #define METHNAME(func) kdmeth_##func
462   METH  (matchp,                "KD.matchp(FILTER) -> BOOL")
463   METH  (split,                 "KD.split()")
464   KWMETH(write,                 "KD.write([filter = <any>]) -> STRING")
465   KWMETH(encode,                "KD.encode([filter = <any>]) -> BYTES")
466   KWMETH(copy,                  "KD.copy([filter = <any>]) -> KD")
467   METH  (plock,                 "KD.plock(TAG) -> ENCRYPTED-KD")
468   METH  (lock,                  "KD.lock(KEY) -> ENCRYPTED-KD")
469 #undef METHNAME
470   { 0 }
471 };
472
473 static PyGetSetDef keydata_pygetset[] = {
474 #define GETSETNAME(op, name) kd##op##_##name
475   GET   (flags,                 "KD.flags -> FLAGS")
476 #undef GETSETNAME
477   { 0 }
478 };
479
480 static PyTypeObject keydata_pytype_skel = {
481   PyObject_HEAD_INIT(0) 0,              /* Header */
482   "KeyData",                            /* @tp_name@ */
483   sizeof(keydata_pyobj),                /* @tp_basicsize@ */
484   0,                                    /* @tp_itemsize@ */
485
486   keydata_pydealloc,                    /* @tp_dealloc@ */
487   0,                                    /* @tp_print@ */
488   0,                                    /* @tp_getattr@ */
489   0,                                    /* @tp_setattr@ */
490   0,                                    /* @tp_compare@ */
491   0,                                    /* @tp_repr@ */
492   0,                                    /* @tp_as_number@ */
493   0,                                    /* @tp_as_sequence@ */
494   0,                                    /* @tp_as_mapping@ */
495   0,                                    /* @tp_hash@ */
496   0,                                    /* @tp_call@ */
497   0,                                    /* @tp_str@ */
498   0,                                    /* @tp_getattro@ */
499   0,                                    /* @tp_setattro@ */
500   0,                                    /* @tp_as_buffer@ */
501   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
502     Py_TPFLAGS_BASETYPE,
503
504   /* @tp_doc@ */
505 "Key data base class.",
506
507   0,                                    /* @tp_traverse@ */
508   0,                                    /* @tp_clear@ */
509   0,                                    /* @tp_richcompare@ */
510   0,                                    /* @tp_weaklistoffset@ */
511   0,                                    /* @tp_iter@ */
512   0,                                    /* @tp_iternext@ */
513   keydata_pymethods,                    /* @tp_methods@ */
514   0,                                    /* @tp_members@ */
515   keydata_pygetset,                     /* @tp_getset@ */
516   0,                                    /* @tp_base@ */
517   0,                                    /* @tp_dict@ */
518   0,                                    /* @tp_descr_get@ */
519   0,                                    /* @tp_descr_set@ */
520   0,                                    /* @tp_dictoffset@ */
521   0,                                    /* @tp_init@ */
522   PyType_GenericAlloc,                  /* @tp_alloc@ */
523   abstract_pynew,                       /* @tp_new@ */
524   0,                                    /* @tp_free@ */
525   0                                     /* @tp_is_gc@ */
526 };
527
528 static PyObject *keydatabin_pynew(PyTypeObject *ty,
529                                   PyObject *arg, PyObject *kw)
530 {
531   char *p;
532   Py_ssize_t n;
533   unsigned f = 0;
534   keydata_pyobj *me = 0;
535   static char *kwlist[] = { "key", "flags", 0 };
536
537   if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|O&:new", kwlist,
538                                    &p, &n, convflags, &f))
539     goto end;
540   me = (keydata_pyobj *)ty->tp_alloc(ty, 0);
541   me->kd = key_newbinary(f & ~KF_ENCMASK, p, n);
542 end:
543   return ((PyObject *)me);
544 }
545
546 static PyObject *kdbget_bin(PyObject *me, void *hunoz)
547   { return (bytestring_pywrap(KEYDATA_KD(me)->u.k.k,
548                               KEYDATA_KD(me)->u.k.sz)); }
549
550 static PyGetSetDef keydatabin_pygetset[] = {
551 #define GETSETNAME(op, name) kdb##op##_##name
552   GET   (bin,                   "KD.bin -> BYTES")
553 #undef GETSETNAME
554   { 0 }
555 };
556
557 static PyTypeObject keydatabin_pytype_skel = {
558   PyObject_HEAD_INIT(0) 0,              /* Header */
559   "KeyDataBinary",                      /* @tp_name@ */
560   sizeof(keydata_pyobj),                /* @tp_basicsize@ */
561   0,                                    /* @tp_itemsize@ */
562
563   0,                                    /* @tp_dealloc@ */
564   0,                                    /* @tp_print@ */
565   0,                                    /* @tp_getattr@ */
566   0,                                    /* @tp_setattr@ */
567   0,                                    /* @tp_compare@ */
568   0,                                    /* @tp_repr@ */
569   0,                                    /* @tp_as_number@ */
570   0,                                    /* @tp_as_sequence@ */
571   0,                                    /* @tp_as_mapping@ */
572   0,                                    /* @tp_hash@ */
573   0,                                    /* @tp_call@ */
574   0,                                    /* @tp_str@ */
575   0,                                    /* @tp_getattro@ */
576   0,                                    /* @tp_setattro@ */
577   0,                                    /* @tp_as_buffer@ */
578   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
579     Py_TPFLAGS_BASETYPE,
580
581   /* @tp_doc@ */
582 "Key data for binary keys.",
583
584   0,                                    /* @tp_traverse@ */
585   0,                                    /* @tp_clear@ */
586   0,                                    /* @tp_richcompare@ */
587   0,                                    /* @tp_weaklistoffset@ */
588   0,                                    /* @tp_iter@ */
589   0,                                    /* @tp_iternext@ */
590   0,                                    /* @tp_methods@ */
591   0,                                    /* @tp_members@ */
592   keydatabin_pygetset,                  /* @tp_getset@ */
593   0,                                    /* @tp_base@ */
594   0,                                    /* @tp_dict@ */
595   0,                                    /* @tp_descr_get@ */
596   0,                                    /* @tp_descr_set@ */
597   0,                                    /* @tp_dictoffset@ */
598   0,                                    /* @tp_init@ */
599   PyType_GenericAlloc,                  /* @tp_alloc@ */
600   keydatabin_pynew,                     /* @tp_new@ */
601   0,                                    /* @tp_free@ */
602   0                                     /* @tp_is_gc@ */
603 };
604
605 static PyObject *keydataenc_pynew(PyTypeObject *ty,
606                                   PyObject *arg, PyObject *kw)
607 {
608   char *p;
609   Py_ssize_t n;
610   unsigned f = 0;
611   keydata_pyobj *me = 0;
612   static char *kwlist[] = { "key", "flags", 0 };
613
614   if (!PyArg_ParseTupleAndKeywords(arg, kw, "s#|O&:new", kwlist,
615                                    &p, &n, convflags, &f))
616     goto end;
617   me = (keydata_pyobj *)ty->tp_alloc(ty, 0);
618   me->kd = key_newencrypted(f & ~KF_ENCMASK, p, n);
619 end:
620   return ((PyObject *)me);
621 }
622
623 static PyObject *kdemeth_plock(PyObject *me, PyObject *arg)
624 {
625   char *hunoz;
626   if (!PyArg_ParseTuple(arg, "s:plock", &hunoz)) goto end;
627   KEYERR(KERR_WRONGTYPE);
628 end:
629   return (0);
630 }
631
632 static PyObject *kdemeth_lock(PyObject *me, PyObject *arg)
633 {
634   char *hunoz;
635   Py_ssize_t hukairz;
636   if (!PyArg_ParseTuple(arg, "s#:lock", &hunoz, &hukairz)) goto end;
637   KEYERR(KERR_WRONGTYPE);
638 end:
639   return (0);
640 }
641
642 static PyObject *kdemeth_punlock(PyObject *me, PyObject *arg)
643 {
644   char *tag;
645   int err;
646   PyObject *rc = 0;
647   key_data *kd;
648
649   if (!PyArg_ParseTuple(arg, "s:punlock", &tag))
650     goto end;
651   if ((err = key_punlock(&kd, KEYDATA_KD(me), tag)) != 0)
652     KEYERR(err);
653   rc = keydata_pywrap(kd);
654 end:
655   return (rc);
656 }
657
658 static PyObject *kdemeth_unlock(PyObject *me, PyObject *arg)
659 {
660   char *p;
661   Py_ssize_t n;
662   int err;
663   PyObject *rc = 0;
664   key_data *kd;
665
666   if (!PyArg_ParseTuple(arg, "s#:unlock", &p, &n))
667     goto end;
668   if ((err = key_unlock(&kd, KEYDATA_KD(me), p, n)) != 0)
669     KEYERR(err);
670   rc = keydata_pywrap(kd);
671 end:
672   return (rc);
673 }
674
675 #define kdeget_ct kdbget_bin
676
677 static PyMethodDef keydataenc_pymethods[] = {
678 #define METHNAME(func) kdemeth_##func
679   METH  (plock,                 "KD.plock(TAG) -> ENCRYPTED-KD")
680   METH  (lock,                  "KD.lock(KEY) -> ENCRYPTED-KD")
681   METH  (punlock,               "KD.punlock(TAG) -> KD")
682   METH  (unlock,                "KD.unlock(KEY) -> KD")
683 #undef METHNAME
684   { 0 }
685 };
686
687 static PyGetSetDef keydataenc_pygetset[] = {
688 #define GETSETNAME(op, name) kde##op##_##name
689   GET   (ct,                    "KD.ct -> BYTES")
690 #undef GETSETNAME
691   { 0 }
692 };
693
694 static PyTypeObject keydataenc_pytype_skel = {
695   PyObject_HEAD_INIT(0) 0,              /* Header */
696   "KeyDataEncrypted",                   /* @tp_name@ */
697   sizeof(keydata_pyobj),                /* @tp_basicsize@ */
698   0,                                    /* @tp_itemsize@ */
699
700   0,                                    /* @tp_dealloc@ */
701   0,                                    /* @tp_print@ */
702   0,                                    /* @tp_getattr@ */
703   0,                                    /* @tp_setattr@ */
704   0,                                    /* @tp_compare@ */
705   0,                                    /* @tp_repr@ */
706   0,                                    /* @tp_as_number@ */
707   0,                                    /* @tp_as_sequence@ */
708   0,                                    /* @tp_as_mapping@ */
709   0,                                    /* @tp_hash@ */
710   0,                                    /* @tp_call@ */
711   0,                                    /* @tp_str@ */
712   0,                                    /* @tp_getattro@ */
713   0,                                    /* @tp_setattro@ */
714   0,                                    /* @tp_as_buffer@ */
715   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
716     Py_TPFLAGS_BASETYPE,
717
718   /* @tp_doc@ */
719 "Key data for encrypted keys.",
720
721   0,                                    /* @tp_traverse@ */
722   0,                                    /* @tp_clear@ */
723   0,                                    /* @tp_richcompare@ */
724   0,                                    /* @tp_weaklistoffset@ */
725   0,                                    /* @tp_iter@ */
726   0,                                    /* @tp_iternext@ */
727   keydataenc_pymethods,                 /* @tp_methods@ */
728   0,                                    /* @tp_members@ */
729   keydataenc_pygetset,                  /* @tp_getset@ */
730   0,                                    /* @tp_base@ */
731   0,                                    /* @tp_dict@ */
732   0,                                    /* @tp_descr_get@ */
733   0,                                    /* @tp_descr_set@ */
734   0,                                    /* @tp_dictoffset@ */
735   0,                                    /* @tp_init@ */
736   PyType_GenericAlloc,                  /* @tp_alloc@ */
737   keydataenc_pynew,                     /* @tp_new@ */
738   0,                                    /* @tp_free@ */
739   0                                     /* @tp_is_gc@ */
740 };
741
742 static PyObject *keydatamp_pynew(PyTypeObject *ty,
743                                  PyObject *arg, PyObject *kw)
744 {
745   mp *x = 0;
746   unsigned f = 0;
747   keydata_pyobj *me = 0;
748   static char *kwlist[] = { "key", "flags", 0 };
749
750   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:new", kwlist,
751                                    convmp, &x, convflags, &f))
752     goto end;
753   me = (keydata_pyobj *)ty->tp_alloc(ty, 0);
754   me->kd = key_newmp(f & ~KF_ENCMASK, x);
755 end:
756   mp_drop(x);
757   return ((PyObject *)me);
758 }
759
760 static PyObject *kdmget_mp(PyObject *me, void *hunoz)
761   { return (mp_pywrap(MP_COPY(KEYDATA_KD(me)->u.m))); }
762
763 static PyGetSetDef keydatamp_pygetset[] = {
764 #define GETSETNAME(op, name) kdm##op##_##name
765   GET   (mp,                    "KD.mp -> X")
766 #undef GETSETNAME
767   { 0 }
768 };
769
770 static PyTypeObject keydatamp_pytype_skel = {
771   PyObject_HEAD_INIT(0) 0,              /* Header */
772   "KeyDataMP",                          /* @tp_name@ */
773   sizeof(keydata_pyobj),                /* @tp_basicsize@ */
774   0,                                    /* @tp_itemsize@ */
775
776   0,                                    /* @tp_dealloc@ */
777   0,                                    /* @tp_print@ */
778   0,                                    /* @tp_getattr@ */
779   0,                                    /* @tp_setattr@ */
780   0,                                    /* @tp_compare@ */
781   0,                                    /* @tp_repr@ */
782   0,                                    /* @tp_as_number@ */
783   0,                                    /* @tp_as_sequence@ */
784   0,                                    /* @tp_as_mapping@ */
785   0,                                    /* @tp_hash@ */
786   0,                                    /* @tp_call@ */
787   0,                                    /* @tp_str@ */
788   0,                                    /* @tp_getattro@ */
789   0,                                    /* @tp_setattro@ */
790   0,                                    /* @tp_as_buffer@ */
791   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
792     Py_TPFLAGS_BASETYPE,
793
794   /* @tp_doc@ */
795 "Key data for large-integer keys.",
796
797   0,                                    /* @tp_traverse@ */
798   0,                                    /* @tp_clear@ */
799   0,                                    /* @tp_richcompare@ */
800   0,                                    /* @tp_weaklistoffset@ */
801   0,                                    /* @tp_iter@ */
802   0,                                    /* @tp_iternext@ */
803   0,                                    /* @tp_methods@ */
804   0,                                    /* @tp_members@ */
805   keydatamp_pygetset,                   /* @tp_getset@ */
806   0,                                    /* @tp_base@ */
807   0,                                    /* @tp_dict@ */
808   0,                                    /* @tp_descr_get@ */
809   0,                                    /* @tp_descr_set@ */
810   0,                                    /* @tp_dictoffset@ */
811   0,                                    /* @tp_init@ */
812   PyType_GenericAlloc,                  /* @tp_alloc@ */
813   keydatamp_pynew,                      /* @tp_new@ */
814   0,                                    /* @tp_free@ */
815   0                                     /* @tp_is_gc@ */
816 };
817
818 static PyObject *keydatastr_pynew(PyTypeObject *ty,
819                                   PyObject *arg, PyObject *kw)
820 {
821   char *p;
822   unsigned f = 0;
823   keydata_pyobj *me = 0;
824   static char *kwlist[] = { "key", "flags", 0 };
825
826   if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|O&:new", kwlist,
827                                    &p, convflags, &f))
828     goto end;
829   me = (keydata_pyobj *)ty->tp_alloc(ty, 0);
830   me->kd = key_newstring(f & ~KF_ENCMASK, p);
831 end:
832   return ((PyObject *)me);
833 }
834
835 static PyObject *kdsget_str(PyObject *me, void *hunoz)
836   { return (PyString_FromString(KEYDATA_KD(me)->u.p)); }
837
838 static PyGetSetDef keydatastr_pygetset[] = {
839 #define GETSETNAME(op, name) kds##op##_##name
840   GET   (str,                   "KD.str -> STRING")
841 #undef GETSETNAME
842   { 0 }
843 };
844
845 static PyTypeObject keydatastr_pytype_skel = {
846   PyObject_HEAD_INIT(0) 0,              /* Header */
847   "KeyDataString",                      /* @tp_name@ */
848   sizeof(keydata_pyobj),                /* @tp_basicsize@ */
849   0,                                    /* @tp_itemsize@ */
850
851   0,                                    /* @tp_dealloc@ */
852   0,                                    /* @tp_print@ */
853   0,                                    /* @tp_getattr@ */
854   0,                                    /* @tp_setattr@ */
855   0,                                    /* @tp_compare@ */
856   0,                                    /* @tp_repr@ */
857   0,                                    /* @tp_as_number@ */
858   0,                                    /* @tp_as_sequence@ */
859   0,                                    /* @tp_as_mapping@ */
860   0,                                    /* @tp_hash@ */
861   0,                                    /* @tp_call@ */
862   0,                                    /* @tp_str@ */
863   0,                                    /* @tp_getattro@ */
864   0,                                    /* @tp_setattro@ */
865   0,                                    /* @tp_as_buffer@ */
866   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
867     Py_TPFLAGS_BASETYPE,
868
869   /* @tp_doc@ */
870 "Key data for string keys.",
871
872   0,                                    /* @tp_traverse@ */
873   0,                                    /* @tp_clear@ */
874   0,                                    /* @tp_richcompare@ */
875   0,                                    /* @tp_weaklistoffset@ */
876   0,                                    /* @tp_iter@ */
877   0,                                    /* @tp_iternext@ */
878   0,                                    /* @tp_methods@ */
879   0,                                    /* @tp_members@ */
880   keydatastr_pygetset,                  /* @tp_getset@ */
881   0,                                    /* @tp_base@ */
882   0,                                    /* @tp_dict@ */
883   0,                                    /* @tp_descr_get@ */
884   0,                                    /* @tp_descr_set@ */
885   0,                                    /* @tp_dictoffset@ */
886   0,                                    /* @tp_init@ */
887   PyType_GenericAlloc,                  /* @tp_alloc@ */
888   keydatastr_pynew,                     /* @tp_new@ */
889   0,                                    /* @tp_free@ */
890   0                                     /* @tp_is_gc@ */
891 };
892
893 static PyObject *keydataec_pynew(PyTypeObject *ty,
894                                  PyObject *arg, PyObject *kw)
895 {
896   ec x = EC_INIT;
897   unsigned f = 0;
898   keydata_pyobj *me = 0;
899   static char *kwlist[] = { "key", "flags", 0 };
900
901   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:new", kwlist,
902                                    convecpt, &x, convflags, &f))
903     goto end;
904   me = (keydata_pyobj *)ty->tp_alloc(ty, 0);
905   me->kd = key_newec(f & ~KF_ENCMASK, &x);
906 end:
907   EC_DESTROY(&x);
908   return ((PyObject *)me);
909 }
910
911 static PyObject *kdeget_ecpt(PyObject *me, void *hunoz)
912 {
913   ec pt = EC_INIT;
914   EC_COPY(&pt, &KEYDATA_KD(me)->u.e);
915   return (ecpt_pywrapout(ecpt_pytype, &pt));
916 }
917
918 static PyGetSetDef keydataec_pygetset[] = {
919 #define GETSETNAME(op, name) kde##op##_##name
920   GET   (ecpt,                  "KD.ecpt -> ECPT")
921 #undef GETSETNAME
922   { 0 }
923 };
924
925 static PyTypeObject keydataec_pytype_skel = {
926   PyObject_HEAD_INIT(0) 0,              /* Header */
927   "KeyDataECPt",                        /* @tp_name@ */
928   sizeof(keydata_pyobj),                /* @tp_basicsize@ */
929   0,                                    /* @tp_itemsize@ */
930
931   0,                                    /* @tp_dealloc@ */
932   0,                                    /* @tp_print@ */
933   0,                                    /* @tp_getattr@ */
934   0,                                    /* @tp_setattr@ */
935   0,                                    /* @tp_compare@ */
936   0,                                    /* @tp_repr@ */
937   0,                                    /* @tp_as_number@ */
938   0,                                    /* @tp_as_sequence@ */
939   0,                                    /* @tp_as_mapping@ */
940   0,                                    /* @tp_hash@ */
941   0,                                    /* @tp_call@ */
942   0,                                    /* @tp_str@ */
943   0,                                    /* @tp_getattro@ */
944   0,                                    /* @tp_setattro@ */
945   0,                                    /* @tp_as_buffer@ */
946   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
947     Py_TPFLAGS_BASETYPE,
948
949   /* @tp_doc@ */
950 "Key data for elliptic-curve keys.",
951
952   0,                                    /* @tp_traverse@ */
953   0,                                    /* @tp_clear@ */
954   0,                                    /* @tp_richcompare@ */
955   0,                                    /* @tp_weaklistoffset@ */
956   0,                                    /* @tp_iter@ */
957   0,                                    /* @tp_iternext@ */
958   0,                                    /* @tp_methods@ */
959   0,                                    /* @tp_members@ */
960   keydataec_pygetset,                   /* @tp_getset@ */
961   0,                                    /* @tp_base@ */
962   0,                                    /* @tp_dict@ */
963   0,                                    /* @tp_descr_get@ */
964   0,                                    /* @tp_descr_set@ */
965   0,                                    /* @tp_dictoffset@ */
966   0,                                    /* @tp_init@ */
967   PyType_GenericAlloc,                  /* @tp_alloc@ */
968   keydataec_pynew,                      /* @tp_new@ */
969   0,                                    /* @tp_free@ */
970   0                                     /* @tp_is_gc@ */
971 };
972
973 static PyObject *subkeyiter_make(PyObject *kdobj)
974 {
975   subkeyiter_pyobj *me = PyObject_NEW(subkeyiter_pyobj, subkeyiter_pytype);
976   me->kdobj = kdobj;
977   Py_INCREF(kdobj);
978   key_mksubkeyiter(&me->i, KEYDATA_KD(kdobj));
979   return ((PyObject *)me);
980 }
981
982 static PyObject *subkeyiter_pynext(PyObject *me)
983 {
984   const char *tag;
985   if (!key_nextsubkey(SUBKEYITER_I(me), &tag, 0))
986     return (0);
987   return (PyString_FromString(tag));
988 }
989
990 static void subkeyiter_pydealloc(PyObject *me)
991 {
992   Py_DECREF(SUBKEYITER_KDOBJ(me));
993   FREEOBJ(me);
994 }
995
996 static PyTypeObject subkeyiter_pytype_skel = {
997   PyObject_HEAD_INIT(0) 0,              /* Header */
998   "SubKeyIter",                         /* @tp_name@ */
999   sizeof(subkeyiter_pyobj),             /* @tp_basicsize@ */
1000   0,                                    /* @tp_itemsize@ */
1001
1002   subkeyiter_pydealloc,                 /* @tp_dealloc@ */
1003   0,                                    /* @tp_print@ */
1004   0,                                    /* @tp_getattr@ */
1005   0,                                    /* @tp_setattr@ */
1006   0,                                    /* @tp_compare@ */
1007   0,                                    /* @tp_repr@ */
1008   0,                                    /* @tp_as_number@ */
1009   0,                                    /* @tp_as_sequence@ */
1010   0,                                    /* @tp_as_mapping@ */
1011   0,                                    /* @tp_hash@ */
1012   0,                                    /* @tp_call@ */
1013   0,                                    /* @tp_str@ */
1014   0,                                    /* @tp_getattro@ */
1015   0,                                    /* @tp_setattro@ */
1016   0,                                    /* @tp_as_buffer@ */
1017   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1018     Py_TPFLAGS_BASETYPE,
1019
1020   /* @tp_doc@ */
1021 "Iterator for structured keys.",
1022
1023   0,                                    /* @tp_traverse@ */
1024   0,                                    /* @tp_clear@ */
1025   0,                                    /* @tp_richcompare@ */
1026   0,                                    /* @tp_weaklistoffset@ */
1027   PyObject_SelfIter,                    /* @tp_iter@ */
1028   subkeyiter_pynext,                    /* @tp_iternext@ */
1029   0,                                    /* @tp_methods@ */
1030   0,                                    /* @tp_members@ */
1031   0,                                    /* @tp_getset@ */
1032   0,                                    /* @tp_base@ */
1033   0,                                    /* @tp_dict@ */
1034   0,                                    /* @tp_descr_get@ */
1035   0,                                    /* @tp_descr_set@ */
1036   0,                                    /* @tp_dictoffset@ */
1037   0,                                    /* @tp_init@ */
1038   PyType_GenericAlloc,                  /* @tp_alloc@ */
1039   abstract_pynew,                       /* @tp_new@ */
1040   0,                                    /* @tp_free@ */
1041   0                                     /* @tp_is_gc@ */
1042 };
1043
1044 static PyObject *keydatastruct_pynew(PyTypeObject *ty,
1045                                      PyObject *arg, PyObject *kw)
1046 {
1047   PyObject *sub = 0;
1048   PyObject *it = 0, *name = 0, *val = 0;
1049   char *p;
1050   keydata_pyobj *me = 0;
1051   key_data *kd = 0;
1052   static char *kwlist[] = { "subkeys", 0 };
1053
1054   Py_XINCREF(arg); Py_XINCREF(kw);
1055   if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:new", kwlist, &sub))
1056     goto end;
1057   kd = key_newstruct();
1058   if (sub) {
1059     if (!PyMapping_Check(sub))
1060       TYERR("subkeys must be an iterable mapping");
1061     if ((it = PyObject_GetIter(sub)) == 0)
1062       goto end;
1063     while ((name = PyIter_Next(it)) != 0) {
1064       if ((p = PyString_AsString(name)) == 0 ||
1065           (val = PyObject_GetItem(sub, name)) == 0)
1066         goto end;
1067       if (!KEYDATA_PYCHECK(val))
1068         TYERR("subkey objects must be subclasses of KeyData");
1069       key_structset(kd, p, KEYDATA_KD(val));
1070       Py_DECREF(name); name = 0;
1071       Py_DECREF(val); val = 0;
1072     }
1073     if (PyErr_Occurred())
1074       goto end;
1075     Py_DECREF(it); it = 0;
1076   }
1077   me = (keydata_pyobj *)ty->tp_alloc(ty, 0);
1078   me->kd = kd;
1079 end:
1080   if (kd && !me) key_drop(kd);
1081   Py_XDECREF(name); Py_XDECREF(val); Py_XDECREF(it);
1082   Py_XDECREF(arg); Py_XDECREF(kw);
1083   return ((PyObject *)me);
1084 }
1085
1086 static PyObject *keydatastruct_pylookup(PyObject *me, PyObject *key)
1087 {
1088   const char *tag;
1089   key_data *kd;
1090   PyObject *rc = 0;
1091
1092   if ((tag = PyString_AsString(key)) == 0)
1093     goto end;
1094   if ((kd = key_structfind(KEYDATA_KD(me), tag)) == 0)
1095     INDEXERR(key);
1096   key_incref(kd);
1097   rc = keydata_pywrap(kd);
1098 end:
1099   return (rc);
1100 }
1101
1102 static int keydatastruct_pystore(PyObject *me,
1103                                  PyObject *key, PyObject *value)
1104 {
1105   const char *tag;
1106   int rc = -1;
1107
1108   if ((tag = PyString_AsString(key)) == 0)
1109     goto end;
1110   key_split(&KEYDATA_KD(me));
1111   if (value) {
1112     if (!KEYDATA_PYCHECK(value))
1113       TYERR("expected KeyData value");
1114     key_structset(KEYDATA_KD(me), tag, KEYDATA_KD(value));
1115   } else {
1116     if (!key_structfind(KEYDATA_KD(me), tag))
1117       INDEXERR(key);
1118     key_structset(KEYDATA_KD(me), tag, 0);
1119   }
1120   rc = 0;
1121 end:
1122   return (rc);
1123 }
1124
1125 static PyMappingMethods keydatastruct_pymapping = {
1126   gmap_pysize,                          /* @mp_length@ */
1127   keydatastruct_pylookup,               /* @mp_subscript@ */
1128   keydatastruct_pystore                 /* @mp_ass_subscript@ */
1129 };
1130
1131 static PyTypeObject keydatastruct_pytype_skel = {
1132   PyObject_HEAD_INIT(0) 0,              /* Header */
1133   "KeyDataStructured",                  /* @tp_name@ */
1134   sizeof(keydata_pyobj),                /* @tp_basicsize@ */
1135   0,                                    /* @tp_itemsize@ */
1136
1137   0,                                    /* @tp_dealloc@ */
1138   0,                                    /* @tp_print@ */
1139   0,                                    /* @tp_getattr@ */
1140   0,                                    /* @tp_setattr@ */
1141   0,                                    /* @tp_compare@ */
1142   0,                                    /* @tp_repr@ */
1143   0,                                    /* @tp_as_number@ */
1144   0,                                    /* @tp_as_sequence@ */
1145   &keydatastruct_pymapping,             /* @tp_as_mapping@ */
1146   0,                                    /* @tp_hash@ */
1147   0,                                    /* @tp_call@ */
1148   0,                                    /* @tp_str@ */
1149   0,                                    /* @tp_getattro@ */
1150   0,                                    /* @tp_setattro@ */
1151   0,                                    /* @tp_as_buffer@ */
1152   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1153     Py_TPFLAGS_BASETYPE,
1154
1155   /* @tp_doc@ */
1156 "Key data for structured keys.",
1157
1158   0,                                    /* @tp_traverse@ */
1159   0,                                    /* @tp_clear@ */
1160   0,                                    /* @tp_richcompare@ */
1161   0,                                    /* @tp_weaklistoffset@ */
1162   subkeyiter_make,                      /* @tp_iter@ */
1163   0,                                    /* @tp_iternext@ */
1164   gmap_pymethods,                       /* @tp_methods@ */
1165   0,                                    /* @tp_members@ */
1166   0,                                    /* @tp_getset@ */
1167   0,                                    /* @tp_base@ */
1168   0,                                    /* @tp_dict@ */
1169   0,                                    /* @tp_descr_get@ */
1170   0,                                    /* @tp_descr_set@ */
1171   0,                                    /* @tp_dictoffset@ */
1172   0,                                    /* @tp_init@ */
1173   PyType_GenericAlloc,                  /* @tp_alloc@ */
1174   keydatastruct_pynew,                  /* @tp_new@ */
1175   0,                                    /* @tp_free@ */
1176   0                                     /* @tp_is_gc@ */
1177 };
1178
1179 /*----- Key attributes ----------------------------------------------------*/
1180
1181 static PyObject *keyattriter_make(PyObject *kaobj)
1182 {
1183   PyObject *kobj = KEYATTRS_KOBJ(kaobj);
1184   keyattriter_pyobj *me = PyObject_NEW(keyattriter_pyobj,
1185                                        keyattriter_pytype);
1186   me->kobj = kobj;
1187   Py_INCREF(kobj);
1188   key_mkattriter(&me->i, KEY_K(kobj));
1189   return ((PyObject *)me);
1190 }
1191
1192 static PyObject *keyattriter_pynext(PyObject *me)
1193 {
1194   const char *name;
1195
1196   if (!key_nextattr(KEYATTRITER_I(me), &name, 0))
1197     return (0);
1198   return (PyString_FromString(name));
1199 }
1200
1201 static void keyattriter_pydealloc(PyObject *me)
1202 {
1203   Py_DECREF(KEYATTRITER_KOBJ(me));
1204   FREEOBJ(me);
1205 }
1206
1207 static PyTypeObject keyattriter_pytype_skel = {
1208   PyObject_HEAD_INIT(0) 0,              /* Header */
1209   "KeyAttributeIter",                   /* @tp_name@ */
1210   sizeof(keyattriter_pyobj),            /* @tp_basicsize@ */
1211   0,                                    /* @tp_itemsize@ */
1212
1213   keyattriter_pydealloc,                /* @tp_dealloc@ */
1214   0,                                    /* @tp_print@ */
1215   0,                                    /* @tp_getattr@ */
1216   0,                                    /* @tp_setattr@ */
1217   0,                                    /* @tp_compare@ */
1218   0,                                    /* @tp_repr@ */
1219   0,                                    /* @tp_as_number@ */
1220   0,                                    /* @tp_as_sequence@ */
1221   0,                                    /* @tp_as_mapping@ */
1222   0,                                    /* @tp_hash@ */
1223   0,                                    /* @tp_call@ */
1224   0,                                    /* @tp_str@ */
1225   0,                                    /* @tp_getattro@ */
1226   0,                                    /* @tp_setattro@ */
1227   0,                                    /* @tp_as_buffer@ */
1228   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1229     Py_TPFLAGS_BASETYPE,
1230
1231   /* @tp_doc@ */
1232 "Iterator for key attributes.",
1233
1234   0,                                    /* @tp_traverse@ */
1235   0,                                    /* @tp_clear@ */
1236   0,                                    /* @tp_richcompare@ */
1237   0,                                    /* @tp_weaklistoffset@ */
1238   PyObject_SelfIter,                    /* @tp_iter@ */
1239   keyattriter_pynext,                   /* @tp_iternext@ */
1240   0,                                    /* @tp_methods@ */
1241   0,                                    /* @tp_members@ */
1242   0,                                    /* @tp_getset@ */
1243   0,                                    /* @tp_base@ */
1244   0,                                    /* @tp_dict@ */
1245   0,                                    /* @tp_descr_get@ */
1246   0,                                    /* @tp_descr_set@ */
1247   0,                                    /* @tp_dictoffset@ */
1248   0,                                    /* @tp_init@ */
1249   PyType_GenericAlloc,                  /* @tp_alloc@ */
1250   abstract_pynew,                       /* @tp_new@ */
1251   0,                                    /* @tp_free@ */
1252   0                                     /* @tp_is_gc@ */
1253 };
1254
1255 static PyObject *keyattrs_pylookup(PyObject *me, PyObject *key)
1256 {
1257   const char *attr;
1258   const char *value;
1259   PyObject *rc = 0;
1260
1261   if ((attr = PyString_AsString(key)) == 0)
1262     goto end;
1263   if ((value = key_getattr(KEYATTRS_KF(me), KEYATTRS_K(me), attr)) == 0)
1264     INDEXERR(key);
1265   rc = PyString_FromString(value);
1266 end:
1267   return (rc);
1268 }
1269
1270 static int keyattrs_pystore(PyObject *me,
1271                             PyObject *key, PyObject *value)
1272 {
1273   const char *attr;
1274   const char *val;
1275   int err;
1276   int rc = -1;
1277
1278   if ((attr = PyString_AsString(key)) == 0)
1279     goto end;
1280   if (value) {
1281     if ((val = PyString_AsString(value)) == 0)
1282       goto end;
1283     if ((err = key_putattr(KEYATTRS_KF(me), KEYATTRS_K(me),
1284                            attr, val)) != 0)
1285       KEYERR(err);
1286   } else {
1287     if (!key_getattr(KEYATTRS_KF(me), KEYATTRS_K(me), attr))
1288       INDEXERR(key);
1289     if ((err = key_putattr(KEYATTRS_KF(me), KEYATTRS_K(me), attr, 0)) != 0)
1290       KEYERR(err);
1291   }
1292   rc = 0;
1293 end:
1294   return (rc);
1295 }
1296
1297 static PyObject *keyattrs_make(PyObject *kobj)
1298 {
1299   keyattrs_pyobj *me = PyObject_NEW(keyattrs_pyobj, keyattrs_pytype);
1300   me->kobj = kobj;
1301   Py_INCREF(kobj);
1302   return ((PyObject *)me);
1303 }
1304
1305 static void keyattrs_pydealloc(PyObject *me)
1306 {
1307   Py_DECREF(KEYATTRS_KOBJ(me));
1308   FREEOBJ(me);
1309 }
1310
1311 static PyMappingMethods keyattrs_pymapping = {
1312   gmap_pysize,                          /* @mp_length@ */
1313   keyattrs_pylookup,                    /* @mp_subscript@ */
1314   keyattrs_pystore                      /* @mp_ass_subscript@ */
1315 };
1316
1317 static PyTypeObject keyattrs_pytype_skel = {
1318   PyObject_HEAD_INIT(0) 0,              /* Header */
1319   "KeyAttributes",                      /* @tp_name@ */
1320   sizeof(keyattrs_pyobj),               /* @tp_basicsize@ */
1321   0,                                    /* @tp_itemsize@ */
1322
1323   keyattrs_pydealloc,                   /* @tp_dealloc@ */
1324   0,                                    /* @tp_print@ */
1325   0,                                    /* @tp_getattr@ */
1326   0,                                    /* @tp_setattr@ */
1327   0,                                    /* @tp_compare@ */
1328   0,                                    /* @tp_repr@ */
1329   0,                                    /* @tp_as_number@ */
1330   &gmap_pysequence,                     /* @tp_as_sequence@ */
1331   &keyattrs_pymapping,                  /* @tp_as_mapping@ */
1332   0,                                    /* @tp_hash@ */
1333   0,                                    /* @tp_call@ */
1334   0,                                    /* @tp_str@ */
1335   0,                                    /* @tp_getattro@ */
1336   0,                                    /* @tp_setattro@ */
1337   0,                                    /* @tp_as_buffer@ */
1338   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1339     Py_TPFLAGS_BASETYPE,
1340
1341   /* @tp_doc@ */
1342 "Proxy thing for talking about key attributes.",
1343
1344   0,                                    /* @tp_traverse@ */
1345   0,                                    /* @tp_clear@ */
1346   0,                                    /* @tp_richcompare@ */
1347   0,                                    /* @tp_weaklistoffset@ */
1348   keyattriter_make,                     /* @tp_iter@ */
1349   0,                                    /* @tp_iternext@ */
1350   gmap_pymethods,                       /* @tp_methods@ */
1351   0,                                    /* @tp_members@ */
1352   0,                                    /* @tp_getset@ */
1353   0,                                    /* @tp_base@ */
1354   0,                                    /* @tp_dict@ */
1355   0,                                    /* @tp_descr_get@ */
1356   0,                                    /* @tp_descr_set@ */
1357   0,                                    /* @tp_dictoffset@ */
1358   0,                                    /* @tp_init@ */
1359   PyType_GenericAlloc,                  /* @tp_alloc@ */
1360   abstract_pynew,                       /* @tp_new@ */
1361   0,                                    /* @tp_free@ */
1362   0                                     /* @tp_is_gc@ */
1363 };
1364
1365 /*----- Key objects -------------------------------------------------------*/
1366
1367 static PyObject *key_dowrap(PyTypeObject *ty, PyObject *kfobj, key *k)
1368 {
1369   key_pyobj *kobj = (key_pyobj *)ty->tp_alloc(ty, 0);
1370   kobj->kfobj = kfobj;
1371   Py_INCREF(kfobj);
1372   kobj->k = k;
1373   return ((PyObject *)kobj);
1374 }
1375
1376 static PyObject *key_pywrap(PyObject *kfobj, key *k)
1377   { return (key_dowrap(key_pytype, kfobj, k)); }
1378
1379 static PyObject *key_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
1380 {
1381   PyObject *kfobj;
1382   uint32 id;
1383   char *type;
1384   unsigned long exptime = KEXP_FOREVER;
1385   static char *kwlist[] = { "keyfile", "id", "type", "exptime", 0 };
1386   key *k;
1387   int err;
1388
1389   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O&s|O&:new", kwlist,
1390                                    keyfile_pytype, &kfobj, convu32, &id,
1391                                    &type, convulong, &exptime))
1392     goto end;
1393   if ((err = key_new(KEYFILE_KF(kfobj), id, type, exptime, &k)) != 0)
1394     KEYERR(err);
1395   return (key_dowrap(ty, kfobj, k));
1396 end:
1397   return (0);
1398 }
1399
1400 static void key_pydealloc(PyObject *me)
1401 {
1402   Py_DECREF(KEY_KFOBJ(me));
1403   FREEOBJ(me);
1404 }
1405
1406 static PyObject *kmeth_delete(PyObject *me, PyObject *arg)
1407 {
1408   int err;
1409
1410   if (!PyArg_ParseTuple(arg, ":delete")) goto end;
1411   if ((err = key_delete(KEY_KF(me), KEY_K(me))) != 0) KEYERR(err);
1412   RETURN_ME;
1413 end:
1414   return (0);
1415 }
1416
1417 static PyObject *kmeth_expire(PyObject *me, PyObject *arg)
1418 {
1419   int err;
1420
1421   if (!PyArg_ParseTuple(arg, ":expire")) goto end;
1422   if ((err = key_expire(KEY_KF(me), KEY_K(me))) != 0) KEYERR(err);
1423   RETURN_ME;
1424 end:
1425   return (0);
1426 }
1427
1428 static PyObject *kmeth_used(PyObject *me, PyObject *arg)
1429 {
1430   long t;
1431   int err;
1432
1433   if (!PyArg_ParseTuple(arg, "l:used", &t)) goto end;
1434   if ((err = key_used(KEY_KF(me), KEY_K(me), t)) != 0) KEYERR(err);
1435   RETURN_ME;
1436 end:
1437   return (0);
1438 }
1439
1440 static PyObject *kmeth_extract(PyObject *me, PyObject *arg, PyObject *kw)
1441 {
1442   key_filter f = { 0, 0 };
1443   PyObject *file;
1444   PyObject *nameobj;
1445   char *name;
1446   FILE *fp;
1447   static char *kwlist[] = { "file", "filter", 0 };
1448
1449   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!|O&:extract", kwlist,
1450                                    &PyFile_Type, &file,
1451                                    convfilter, &f) ||
1452       (fp = PyFile_AsFile(file)) == 0 ||
1453       (nameobj = PyFile_Name(file)) == 0 ||
1454       (name = PyString_AsString(nameobj)) == 0)
1455     goto end;
1456   if (key_extract(KEY_KF(me), KEY_K(me), fp, &f))
1457     OSERR(name);
1458   RETURN_ME;
1459 end:
1460   return (0);
1461 }
1462
1463 static PyObject *kmeth_fingerprint(PyObject *me,
1464                                    PyObject *arg, PyObject *kw)
1465 {
1466   ghash *h;
1467   key_filter f = { KF_NONSECRET, KF_NONSECRET };
1468   static char *kwlist[] = { "hash", "filter", 0 };
1469
1470   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:fingerprint", kwlist,
1471                                    convghash, &h, convfilter, &f))
1472     return (0);
1473   return (getbool(key_fingerprint(KEY_K(me), h, &f)));
1474 }
1475
1476 static PyObject *kget_id(PyObject *me, void *hunoz)
1477   { return (getulong(KEY_K(me)->id)); }
1478 static PyObject *kget_file(PyObject *me, void *hunoz)
1479   { RETURN_OBJ(KEY_KFOBJ(me)); }
1480 static PyObject *kget_type(PyObject *me, void *hunoz)
1481   { return (PyString_FromString(KEY_K(me)->type)); }
1482 static PyObject *kget_exptime(PyObject *me, void *hunoz)
1483   { return (getulong(KEY_K(me)->exp)); }
1484 static PyObject *kget_deltime(PyObject *me, void *hunoz)
1485   { return (getulong(KEY_K(me)->del)); }
1486 static PyObject *kget_expiredp(PyObject *me, void *hunoz)
1487   { return (getbool(key_expired(KEY_K(me)))); }
1488 static PyObject *kget_attr(PyObject *me, void *hunoz)
1489   { return (keyattrs_make(me)); }
1490
1491 static int kset_exptime(PyObject *me, PyObject *x, void *hunoz)
1492 {
1493   key *k = KEY_K(me);
1494   unsigned long et;
1495
1496   if (!x) NIERR("__del__");
1497   if (!convulong(x, &et))
1498     goto end;
1499   if (!(KEY_KF(me)->f & KF_WRITE))
1500     KEYERR(KERR_READONLY);
1501   k->exp = et;
1502   KEY_KF(me)->f |= KF_MODIFIED;
1503   return (0);
1504 end:
1505   return (-1);
1506 }
1507
1508 static int kset_deltime(PyObject *me, PyObject *x, void *hunoz)
1509 {
1510   key *k = KEY_K(me);
1511   unsigned long dt;
1512
1513   if (!x) NIERR("__del__");
1514   if (!convulong(x, &dt))
1515     goto end;
1516   if (dt == KEXP_FOREVER && k->exp != KEXP_FOREVER)
1517     VALERR("key will eventually expire");
1518   if (!(KEY_KF(me)->f & KF_WRITE))
1519     KEYERR(KERR_READONLY);
1520   k->del = dt;
1521   KEY_KF(me)->f |= KF_MODIFIED;
1522   return (0);
1523 end:
1524   return (-1);
1525 }
1526
1527 static PyObject *kget_data(PyObject *me, void *hunoz)
1528 {
1529   key_data *kd = KEY_K(me)->k;
1530   key_incref(kd);
1531   return (keydata_pywrap(kd));
1532 }
1533 static int kset_data(PyObject *me, PyObject *x, void *hunoz)
1534 {
1535   int err;
1536
1537   if (!x) NIERR("__del__");
1538   if (!KEYDATA_PYCHECK(x)) TYERR("expected KeyData object");
1539   if ((err = key_setkeydata(KEY_KF(me), KEY_K(me), KEYDATA_KD(x))) != 0)
1540     KEYERR(err);
1541   return (0);
1542 end:
1543   return (-1);
1544 }
1545
1546 static PyObject *kget_fulltag(PyObject *me, void *hunoz)
1547 {
1548   dstr d = DSTR_INIT;
1549   PyObject *rc;
1550
1551   key_fulltag(KEY_K(me), &d);
1552   rc = PyString_FromStringAndSize(d.buf, d.len);
1553   dstr_destroy(&d);
1554   return (rc);
1555 }
1556
1557 static PyObject *kget_tag(PyObject *me, void *hunoz)
1558 {
1559   if (!KEY_K(me)->tag) RETURN_NONE;
1560   return (PyString_FromString(KEY_K(me)->tag));
1561 }
1562 static int kset_tag(PyObject *me, PyObject *x, void *hunoz)
1563 {
1564   int err;
1565   char *tag;
1566
1567   if (!x || x == Py_None) tag = 0;
1568   else if ((tag = PyString_AsString(x)) == 0) goto end;
1569   if ((err = key_settag(KEY_KF(me), KEY_K(me), tag)) != 0) KEYERR(err);
1570   return (0);
1571 end:
1572   return (-1);
1573 }
1574
1575 static PyObject *kget_comment(PyObject *me, void *hunoz)
1576 {
1577   if (!KEY_K(me)->c) RETURN_NONE;
1578   return (PyString_FromString(KEY_K(me)->c));
1579 }
1580 static int kset_comment(PyObject *me, PyObject *x, void *hunoz)
1581 {
1582   int err;
1583   char *c;
1584
1585   if (!x || x == Py_None) c = 0;
1586   else if ((c = PyString_AsString(x)) == 0) goto end;
1587   if ((err = key_setcomment(KEY_KF(me), KEY_K(me), c)) != 0) KEYERR(err);
1588   return (0);
1589 end:
1590   return (-1);
1591 }
1592
1593 static PyMethodDef key_pymethods[] = {
1594 #define METHNAME(func) kmeth_##func
1595   METH  (delete,        "KEY.delete()")
1596   METH  (expire,        "KEY.expire()")
1597   METH  (used,          "KEY.used(TIME)")
1598   KWMETH(extract,       "KEY.extract(FILE, [filter = <any>])")
1599   KWMETH(fingerprint,   "KEY.fingerprint(HASH, [filter = '-secret'])")
1600 #undef METHNAME
1601   { 0 }
1602 };
1603
1604 static PyGetSetDef key_pygetset[] = {
1605 #define GETSETNAME(op, name) k##op##_##name
1606   GET   (file,          "KEY.file -> KF")
1607   GET   (id,            "KEY.id -> ID")
1608   GETSET(tag,           "KEY.tag -> TAG")
1609   GET   (type,          "KEY.type -> TYPE")
1610   GETSET(exptime,       "KEY.exptime -> TIME")
1611   GETSET(deltime,       "KEY.deltime -> TIME")
1612   GET   (expiredp,      "KEY.expiredp -> BOOL")
1613   GET   (attr,          "KEY.attr -> ATTRIBUTES")
1614   GETSET(data,          "KEY.data -> KD")
1615   GETSET(comment,       "KEY.comment -> COMMENT")
1616   GET   (fulltag,       "KEY.fulltag -> FULLTAG")
1617 #undef GETSETNAME
1618   { 0 }
1619 };
1620
1621 static PyTypeObject key_pytype_skel = {
1622   PyObject_HEAD_INIT(0) 0,              /* Header */
1623   "Key",                                /* @tp_name@ */
1624   sizeof(key_pyobj),                    /* @tp_basicsize@ */
1625   0,                                    /* @tp_itemsize@ */
1626
1627   key_pydealloc,                        /* @tp_dealloc@ */
1628   0,                                    /* @tp_print@ */
1629   0,                                    /* @tp_getattr@ */
1630   0,                                    /* @tp_setattr@ */
1631   0,                                    /* @tp_compare@ */
1632   0,                                    /* @tp_repr@ */
1633   0,                                    /* @tp_as_number@ */
1634   0,                                    /* @tp_as_sequence@ */
1635   0,                                    /* @tp_as_mapping@ */
1636   0,                                    /* @tp_hash@ */
1637   0,                                    /* @tp_call@ */
1638   0,                                    /* @tp_str@ */
1639   0,                                    /* @tp_getattro@ */
1640   0,                                    /* @tp_setattro@ */
1641   0,                                    /* @tp_as_buffer@ */
1642   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1643     Py_TPFLAGS_BASETYPE,
1644
1645   /* @tp_doc@ */
1646 "Key object.",
1647
1648   0,                                    /* @tp_traverse@ */
1649   0,                                    /* @tp_clear@ */
1650   0,                                    /* @tp_richcompare@ */
1651   0,                                    /* @tp_weaklistoffset@ */
1652   0,                                    /* @tp_iter@ */
1653   0,                                    /* @tp_iternext@ */
1654   key_pymethods,                        /* @tp_methods@ */
1655   0,                                    /* @tp_members@ */
1656   key_pygetset,                         /* @tp_getset@ */
1657   0,                                    /* @tp_base@ */
1658   0,                                    /* @tp_dict@ */
1659   0,                                    /* @tp_descr_get@ */
1660   0,                                    /* @tp_descr_set@ */
1661   0,                                    /* @tp_dictoffset@ */
1662   0,                                    /* @tp_init@ */
1663   PyType_GenericAlloc,                  /* @tp_alloc@ */
1664   key_pynew,                            /* @tp_new@ */
1665   0,                                    /* @tp_free@ */
1666   0                                     /* @tp_is_gc@ */
1667 };
1668
1669 /*----- Key iteration -----------------------------------------------------*/
1670
1671 static PyObject *keyiter_new(PyObject *kfobj)
1672 {
1673   keyiter_pyobj *me = PyObject_NEW(keyiter_pyobj, keyiter_pytype);
1674   key_mkiter(&me->i, KEYFILE_KF(kfobj));
1675   me->kfobj = kfobj;
1676   Py_INCREF(kfobj);
1677   return ((PyObject *)me);
1678 }
1679
1680 static PyObject *keyiter_pynext(PyObject *me)
1681 {
1682   key *k;
1683
1684   if ((k = key_next(KEYITER_I(me))) == 0)
1685     return (0);
1686   return (getulong(k->id));
1687 }
1688
1689 static void keyiter_pydealloc(PyObject *me)
1690 {
1691   Py_DECREF(KEYITER_KFOBJ(me));
1692   FREEOBJ(me);
1693 }
1694
1695 static PyTypeObject keyiter_pytype_skel = {
1696   PyObject_HEAD_INIT(0) 0,              /* Header */
1697   "KeyFileIter",                        /* @tp_name@ */
1698   sizeof(keyiter_pyobj),                /* @tp_basicsize@ */
1699   0,                                    /* @tp_itemsize@ */
1700
1701   keyiter_pydealloc,                    /* @tp_dealloc@ */
1702   0,                                    /* @tp_print@ */
1703   0,                                    /* @tp_getattr@ */
1704   0,                                    /* @tp_setattr@ */
1705   0,                                    /* @tp_compare@ */
1706   0,                                    /* @tp_repr@ */
1707   0,                                    /* @tp_as_number@ */
1708   0,                                    /* @tp_as_sequence@ */
1709   0,                                    /* @tp_as_mapping@ */
1710   0,                                    /* @tp_hash@ */
1711   0,                                    /* @tp_call@ */
1712   0,                                    /* @tp_str@ */
1713   0,                                    /* @tp_getattro@ */
1714   0,                                    /* @tp_setattro@ */
1715   0,                                    /* @tp_as_buffer@ */
1716   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1717     Py_TPFLAGS_BASETYPE,
1718
1719   /* @tp_doc@ */
1720 "Keyring iterator.",
1721
1722   0,                                    /* @tp_traverse@ */
1723   0,                                    /* @tp_clear@ */
1724   0,                                    /* @tp_richcompare@ */
1725   0,                                    /* @tp_weaklistoffset@ */
1726   PyObject_SelfIter,                    /* @tp_iter@ */
1727   keyiter_pynext,                       /* @tp_iternext@ */
1728   0,                                    /* @tp_methods@ */
1729   0,                                    /* @tp_members@ */
1730   0,                                    /* @tp_getset@ */
1731   0,                                    /* @tp_base@ */
1732   0,                                    /* @tp_dict@ */
1733   0,                                    /* @tp_descr_get@ */
1734   0,                                    /* @tp_descr_set@ */
1735   0,                                    /* @tp_dictoffset@ */
1736   0,                                    /* @tp_init@ */
1737   PyType_GenericAlloc,                  /* @tp_alloc@ */
1738   abstract_pynew,                       /* @tp_new@ */
1739   0,                                    /* @tp_free@ */
1740   0                                     /* @tp_is_gc@ */
1741 };
1742
1743 /*----- Key files ---------------------------------------------------------*/
1744
1745 struct reportinfo {
1746   PyObject *func;
1747   int stop;
1748 };
1749
1750 static void pythonreporter(const char *file, int line,
1751                            const char *msg, void *p)
1752 {
1753   struct reportinfo *ri = p;
1754   PyObject *res = 0;
1755
1756   if (ri->stop)
1757     return;
1758   if (!ri->func)
1759     key_moan(file, line, msg, 0);
1760   else if ((res = PyObject_CallFunction(ri->func, "sis",
1761                                         file, line, msg)) == 0)
1762     ri->stop = 1;
1763   else
1764     Py_DECREF(res);
1765 }
1766
1767 static PyObject *keyfile_pynew(PyTypeObject *ty,
1768                                PyObject *arg, PyObject *kw)
1769 {
1770   struct reportinfo ri = { 0, 0 };
1771   char *file = 0;
1772   unsigned how = KOPEN_READ;
1773   keyfile_pyobj *rc = 0;
1774   static char *kwlist[] = { "file", "how", "report", 0 };
1775
1776   Py_XINCREF(arg); Py_XINCREF(kw);
1777   if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|iO:new", kwlist,
1778                                    &file, &how, &ri.func))
1779     goto end;
1780   if (ri.func && !PyCallable_Check(ri.func))
1781     TYERR("reporter function not callable");
1782   if ((rc = (keyfile_pyobj *)ty->tp_alloc(ty, 0)) == 0)
1783     goto end;
1784   if (key_open(&rc->kf, file, how, pythonreporter, &ri))
1785     OSERR(file);
1786   if (ri.stop) {
1787     key_discard(&rc->kf);
1788     goto end;
1789   }
1790   goto done;
1791
1792 end:
1793   if (rc) {
1794     FREEOBJ(rc);
1795     rc = 0;
1796   }
1797 done:
1798   Py_XDECREF(arg); Py_XDECREF(kw);
1799   return ((PyObject *)rc);
1800 }
1801
1802 static void keyfile_pydealloc(PyObject *me)
1803 {
1804   key_discard(KEYFILE_KF(me));
1805   FREEOBJ(me);
1806 }
1807
1808 static PyObject *kfmeth_save(PyObject *me, PyObject *arg)
1809 {
1810   if (!PyArg_ParseTuple(arg, ":save"))
1811     goto end;
1812   switch (key_save(KEYFILE_KF(me))) {
1813     case KWRITE_OK:
1814       RETURN_ME;
1815     case KWRITE_FAIL:
1816       KEYIOERR(KEYFILE_KF(me)->name);
1817     case KWRITE_BROKEN:
1818       KEYFILEBROKEN(KEYFILE_KF(me)->name);
1819     default:
1820       abort();
1821   }
1822 end:
1823   return (0);
1824 }
1825
1826 static PyObject *kfmeth_merge(PyObject *me, PyObject *arg, PyObject *kw)
1827 {
1828   struct reportinfo ri = { 0, 0 };
1829   char *name;
1830   PyObject *x = 0;
1831   FILE *fp = 0;
1832   int rc;
1833   static char *kwlist[] = { "file", "report", 0 };
1834
1835   Py_XINCREF(arg); Py_XINCREF(kw);
1836   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!|O:merge", kwlist,
1837                                    &PyFile_Type, &x, &ri.func))
1838     goto end;
1839   if (ri.func && !PyCallable_Check(ri.func))
1840     TYERR("reporter function not callable");
1841   if ((fp = PyFile_AsFile(x)) == 0)
1842     goto end;
1843   x = PyFile_Name(x);
1844   if ((name = PyString_AsString(x)) == 0)
1845     goto end;
1846   rc = key_merge(KEYFILE_KF(me), name, fp, pythonreporter, &ri);
1847   if (ri.stop)
1848     goto end;
1849   if (rc != 0)
1850     KEYERR(rc);
1851   Py_XDECREF(arg); Py_XDECREF(kw);
1852   RETURN_ME;
1853
1854 end:
1855   Py_XDECREF(arg); Py_XDECREF(kw);
1856   return (0);
1857 }
1858
1859 static PyObject *kfmeth_byid(PyObject *me, PyObject *arg)
1860 {
1861   uint32 id;
1862   key *k;
1863   PyObject *rc = 0;
1864
1865   if (!PyArg_ParseTuple(arg, "O&:byid", convu32, &id)) goto end;
1866   if ((k = key_byid(KEYFILE_KF(me), id)) == 0) KEYERR(KERR_NOTFOUND);
1867   rc = key_pywrap(me, k);
1868 end:
1869   return (rc);
1870 }
1871
1872 static PyObject *kfmeth_bytype(PyObject *me, PyObject *arg)
1873 {
1874   char *type;
1875   key *k;
1876   PyObject *rc = 0;
1877
1878   if (!PyArg_ParseTuple(arg, "s:bytype", &type)) goto end;
1879   if ((k = key_bytype(KEYFILE_KF(me), type)) == 0) RETURN_NONE;
1880   rc = key_pywrap(me, k);
1881 end:
1882   return (rc);
1883 }
1884
1885 static PyObject *bytag(PyObject *me, PyObject *tagobj)
1886 {
1887   uint32 id;
1888   char *tag;
1889   key *k;
1890   PyObject *rc = 0;
1891
1892   if (convu32(tagobj, &id))
1893     k = key_byid(KEYFILE_KF(me), id);
1894   else {
1895     PyErr_Clear();
1896     if ((tag = PyString_AsString(tagobj)) == 0)
1897       goto end;
1898     k = key_bytag(KEYFILE_KF(me), tag);
1899   }
1900   if (!k) RETURN_NONE;
1901   rc = key_pywrap(me, k);
1902 end:
1903   return (rc);
1904 }
1905
1906 static PyObject *kfmeth_bytag(PyObject *me, PyObject *arg)
1907 {
1908   PyObject *tagobj;
1909
1910   if (!PyArg_ParseTuple(arg, "O:bytag", &tagobj)) return (0);
1911   return (bytag(me, tagobj));
1912 }
1913
1914 static PyObject *keyfile_pylookup(PyObject *me, PyObject *key)
1915 {
1916   PyObject *rc = bytag(me, key);
1917   if (!rc) goto end;
1918   if (rc == Py_None) {
1919     Py_DECREF(rc);
1920     rc = 0;
1921     INDEXERR(key);
1922   }
1923 end:
1924   return (rc);
1925 }
1926
1927 static PyObject *kfmeth_newkey(PyObject *me, PyObject *arg, PyObject *kw)
1928 {
1929   uint32 id;
1930   char *type;
1931   long exptime = KEXP_FOREVER;
1932   static char *kwlist[] = { "id", "type", "exptime", 0 };
1933   key *k;
1934   int err;
1935
1936   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&s|l:newkey", kwlist,
1937                                    convu32, &id, &type, &exptime))
1938     goto end;
1939   if ((err = key_new(KEYFILE_KF(me), id, type, exptime, &k)) != 0)
1940     KEYERR(err);
1941   return (key_pywrap(me, k));
1942 end:
1943   return (0);
1944 }
1945
1946 static PyObject *kfmeth_qtag(PyObject *me, PyObject *arg, PyObject *kw)
1947 {
1948   key *k;
1949   key_data **kd, *okd;
1950   PyObject *newkdobj = 0;
1951   char *tag;
1952   dstr d = DSTR_INIT;
1953   PyObject *rc = 0;
1954   static char *kwlist[] = { "tag", "new", 0 };
1955
1956   if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|O!:qtag", kwlist,
1957                                    &tag, keydata_pytype, &newkdobj))
1958     goto end;
1959   if (key_qtag(KEYFILE_KF(me), tag, &d, &k, &kd))
1960     KEYERR(KERR_NOTFOUND);
1961   okd = *kd;
1962   if (newkdobj) {
1963     if (!(KEYFILE_KF(me)->f & KF_WRITE))
1964       KEYERR(KERR_READONLY);
1965     KEYFILE_KF(me)->f |= KF_MODIFIED;
1966     *kd = KEYDATA_KD(newkdobj);
1967   }
1968   key_incref(*kd);
1969   rc = Py_BuildValue("(s#NN)",
1970                      d.buf, (Py_ssize_t)d.len,
1971                      key_pywrap(me, k),
1972                      keydata_pywrap(okd));
1973 end:
1974   return (rc);
1975 }
1976
1977 static PyObject *kfget_name(PyObject *me, void *hunoz)
1978   { return (PyString_FromString(KEYFILE_KF(me)->name)); }
1979 static PyObject *kfget_modifiedp(PyObject *me, void *hunoz)
1980   { return (getbool(KEYFILE_KF(me)->f & KF_MODIFIED)); }
1981 static PyObject *kfget_writep(PyObject *me, void *hunoz)
1982   { return (getbool(KEYFILE_KF(me)->f & KF_WRITE)); }
1983 static PyObject *kfget_filep(PyObject *me, void *hunoz)
1984   { return (getbool(!!KEYFILE_KF(me)->fp)); }
1985
1986 static PyMethodDef keyfile_pymethods[] = {
1987 #define METHNAME(func) kfmeth_##func
1988   METH  (save,          "KF.save()")
1989   KWMETH(merge,         "KF.merge(FILE, [report = <built-in-reporter>])")
1990   KWMETH(newkey,        "KF.newkey(ID, TYPE, "
1991                                 "[exptime = KEXP_FOREVER]) -> KEY")
1992   METH  (byid,          "KF.byid(KEYID) -> KEY|None")
1993   METH  (bytype,        "KF.bytype(TYPE) -> KEY|None")
1994   METH  (bytag,         "KF.bytag(TAG) -> KEY|None")
1995   KWMETH(qtag,          "KF.qtag(TAG, [new = KD]) -> FULLTAG, KEY, OLDKD")
1996   GMAP_ROMETHODS
1997 #undef METHNAME
1998   { 0 }
1999 };
2000
2001 static PyGetSetDef keyfile_pygetset[] = {
2002 #define GETSETNAME(op, name) kf##op##_##name
2003   GET   (name,          "KF.name -> file name")
2004   GET   (modifiedp,     "KF.modifiedp -> has keyring been modified?")
2005   GET   (writep,        "KF.writep -> is keyring modifiable?")
2006   GET   (filep,         "KF.filep -> does keyring have a backing file?")
2007 #undef GETSETNAME
2008   { 0 }
2009 };
2010
2011 static PyMappingMethods keyfile_pymapping = {
2012   gmap_pysize,
2013   keyfile_pylookup,
2014   0
2015 };
2016
2017 static PyTypeObject keyfile_pytype_skel = {
2018   PyObject_HEAD_INIT(0) 0,              /* Header */
2019   "KeyFile",                            /* @tp_name@ */
2020   sizeof(keyfile_pyobj),                /* @tp_basicsize@ */
2021   0,                                    /* @tp_itemsize@ */
2022
2023   keyfile_pydealloc,                    /* @tp_dealloc@ */
2024   0,                                    /* @tp_print@ */
2025   0,                                    /* @tp_getattr@ */
2026   0,                                    /* @tp_setattr@ */
2027   0,                                    /* @tp_compare@ */
2028   0,                                    /* @tp_repr@ */
2029   0,                                    /* @tp_as_number@ */
2030   &gmap_pysequence,                     /* @tp_as_sequence@ */
2031   &keyfile_pymapping,                   /* @tp_as_mapping@ */
2032   0,                                    /* @tp_hash@ */
2033   0,                                    /* @tp_call@ */
2034   0,                                    /* @tp_str@ */
2035   0,                                    /* @tp_getattro@ */
2036   0,                                    /* @tp_setattro@ */
2037   0,                                    /* @tp_as_buffer@ */
2038   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
2039     Py_TPFLAGS_BASETYPE,
2040
2041   /* @tp_doc@ */
2042 "Keyring file.",
2043
2044   0,                                    /* @tp_traverse@ */
2045   0,                                    /* @tp_clear@ */
2046   0,                                    /* @tp_richcompare@ */
2047   0,                                    /* @tp_weaklistoffset@ */
2048   keyiter_new,                          /* @tp_iter@ */
2049   0,                                    /* @tp_iternext@ */
2050   keyfile_pymethods,                    /* @tp_methods@ */
2051   0,                                    /* @tp_members@ */
2052   keyfile_pygetset,                     /* @tp_getset@ */
2053   0,                                    /* @tp_base@ */
2054   0,                                    /* @tp_dict@ */
2055   0,                                    /* @tp_descr_get@ */
2056   0,                                    /* @tp_descr_set@ */
2057   0,                                    /* @tp_dictoffset@ */
2058   0,                                    /* @tp_init@ */
2059   PyType_GenericAlloc,                  /* @tp_alloc@ */
2060   keyfile_pynew,                        /* @tp_new@ */
2061   0,                                    /* @tp_free@ */
2062   0                                     /* @tp_is_gc@ */
2063 };
2064
2065 /*----- Global stuff ------------------------------------------------------*/
2066
2067 static PyObject *meth_barf(PyObject *me, PyObject *arg)
2068 {
2069   int err;
2070
2071   if (PyArg_ParseTuple(arg, "i:barf", &err))
2072     KEYERR(err);
2073 end:
2074   return (0);
2075 }
2076
2077 static PyMethodDef methods[] = {
2078 #define METHNAME(func) meth_##func
2079   METH  (_KeyData_readflags,
2080            "KeyData.readflags(STRING) -> (FLAGS, MASK, REST)")
2081   METH  (_KeyData_writeflags,   "KeyData.writeflags(FLAGS) -> STRING")
2082   METH  (_KeyData_read,         "KeyData.read(STRING) -> (KD, REST)")
2083   METH  (_KeyData_decode,       "KeyData.decode(BYTES) -> KD")
2084   METH  (barf,                  "barf(ERR)")
2085 #undef METHNAME
2086   { 0 }
2087 };
2088
2089 /*----- Initialization ----------------------------------------------------*/
2090
2091 void key_pyinit(void)
2092 {
2093   INITTYPE(keyfile, root);
2094   INITTYPE(key, root);
2095   INITTYPE(keyiter, root);
2096   INITTYPE(keydata, root);
2097   INITTYPE(keydatabin, keydata);
2098   INITTYPE(keydataenc, keydata);
2099   INITTYPE(keydatastr, keydata);
2100   INITTYPE(keydatamp, keydata);
2101   INITTYPE(keydataec, keydata);
2102   INITTYPE(keydatastruct, keydata);
2103   INITTYPE(subkeyiter, root);
2104   INITTYPE(keyattrs, root);
2105   INITTYPE(keyattriter, root);
2106   addmethods(methods);
2107 }
2108
2109 void key_pyinsert(PyObject *mod)
2110 {
2111   INSEXC("KeyError", keyexc, PyExc_Exception, keyexc_pymethods);
2112   INSEXC("KeyFileIOError", keyioexc, PyExc_OSError, 0);
2113   INSEXC("KeyFileBroken", keyfilebrokenexc, keyioexc, 0);
2114   INSERT("KeyFile", keyfile_pytype);
2115   INSERT("KeyFileIter", keyiter_pytype);
2116   INSERT("Key", key_pytype);
2117   INSERT("KeyAttributes", keyattrs_pytype);
2118   INSERT("KeyAttributeIter", keyattriter_pytype);
2119   INSERT("KeyData", keydata_pytype);
2120   INSERT("KeyDataBinary", keydatabin_pytype);
2121   INSERT("KeyDataEncrypted", keydataenc_pytype);
2122   INSERT("KeyDataMP", keydatamp_pytype);
2123   INSERT("KeyDataECPt", keydataec_pytype);
2124   INSERT("KeyDataString", keydatastr_pytype);
2125   INSERT("KeyDataStructured", keydatastruct_pytype);
2126   INSERT("SubKeyIter", subkeyiter_pytype);
2127 }
2128
2129 /*----- That's all, folks -------------------------------------------------*/