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