chiark / gitweb /
catacomb/pwsafe.py: Use `binascii' for Base64 conversion.
[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 PyObject *keydatastruct_pynew(PyTypeObject *ty,
1019                                      PyObject *arg, PyObject *kw)
1020 {
1021   PyObject *sub = 0;
1022   PyObject *it = 0, *name = 0, *val = 0;
1023   char *p;
1024   keydata_pyobj *me = 0;
1025   key_data *kd = 0;
1026   static const char *const kwlist[] = { "subkeys", 0 };
1027
1028   Py_XINCREF(arg); Py_XINCREF(kw);
1029   if (!PyArg_ParseTupleAndKeywords(arg, kw, "|O:new", KWLIST, &sub))
1030     goto end;
1031   kd = key_newstruct();
1032   if (sub) {
1033     if (!PyMapping_Check(sub))
1034       TYERR("subkeys must be an iterable mapping");
1035     if ((it = PyObject_GetIter(sub)) == 0)
1036       goto end;
1037     while ((name = PyIter_Next(it)) != 0) {
1038       if ((p = TEXT_STR(name)) == 0 ||
1039           (val = PyObject_GetItem(sub, name)) == 0)
1040         goto end;
1041       if (!KEYDATA_PYCHECK(val))
1042         TYERR("subkey objects must be subclasses of KeyData");
1043       key_structset(kd, p, KEYDATA_KD(val));
1044       Py_DECREF(name); name = 0;
1045       Py_DECREF(val); val = 0;
1046     }
1047     if (PyErr_Occurred())
1048       goto end;
1049     Py_DECREF(it); it = 0;
1050   }
1051   me = (keydata_pyobj *)ty->tp_alloc(ty, 0);
1052   me->gmops = &keydatastruct_gmops;
1053   me->kd = kd;
1054 end:
1055   if (kd && !me) key_drop(kd);
1056   Py_XDECREF(name); Py_XDECREF(val); Py_XDECREF(it);
1057   Py_XDECREF(arg); Py_XDECREF(kw);
1058   return ((PyObject *)me);
1059 }
1060
1061 static Py_ssize_t keydatastruct_pysize(PyObject *me)
1062   { return gmap_pysize_from_sym(&KEYDATA_KD(me)->u.s); }
1063
1064 static const PyMappingMethods keydatastruct_pymapping = {
1065   keydatastruct_pysize,
1066   gmap_pylookup,
1067   gmap_pystore
1068 };
1069
1070 static const PyTypeObject keydatastruct_pytype_skel = {
1071   PyVarObject_HEAD_INIT(0, 0)           /* Header */
1072   "KeyDataStructured",                  /* @tp_name@ */
1073   sizeof(keydata_pyobj),                /* @tp_basicsize@ */
1074   0,                                    /* @tp_itemsize@ */
1075
1076   0,                                    /* @tp_dealloc@ */
1077   0,                                    /* @tp_print@ */
1078   0,                                    /* @tp_getattr@ */
1079   0,                                    /* @tp_setattr@ */
1080   0,                                    /* @tp_compare@ */
1081   0,                                    /* @tp_repr@ */
1082   0,                                    /* @tp_as_number@ */
1083   PYSEQUENCE(gmap),                     /* @tp_as_sequence@ */
1084   PYMAPPING(keydatastruct),             /* @tp_as_mapping@ */
1085   0,                                    /* @tp_hash@ */
1086   0,                                    /* @tp_call@ */
1087   0,                                    /* @tp_str@ */
1088   0,                                    /* @tp_getattro@ */
1089   0,                                    /* @tp_setattro@ */
1090   0,                                    /* @tp_as_buffer@ */
1091   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1092     Py_TPFLAGS_BASETYPE,
1093
1094   /* @tp_doc@ */
1095   "KeyDataStructured([subkeys = []]): key data for structured keys.",
1096
1097   0,                                    /* @tp_traverse@ */
1098   0,                                    /* @tp_clear@ */
1099   0,                                    /* @tp_richcompare@ */
1100   0,                                    /* @tp_weaklistoffset@ */
1101   gmap_pyiter,                          /* @tp_iter@ */
1102   0,                                    /* @tp_iternext@ */
1103   PYMETHODS(gmap),                      /* @tp_methods@ */
1104   0,                                    /* @tp_members@ */
1105   0,                                    /* @tp_getset@ */
1106   0,                                    /* @tp_base@ */
1107   0,                                    /* @tp_dict@ */
1108   0,                                    /* @tp_descr_get@ */
1109   0,                                    /* @tp_descr_set@ */
1110   0,                                    /* @tp_dictoffset@ */
1111   0,                                    /* @tp_init@ */
1112   PyType_GenericAlloc,                  /* @tp_alloc@ */
1113   keydatastruct_pynew,                  /* @tp_new@ */
1114   0,                                    /* @tp_free@ */
1115   0                                     /* @tp_is_gc@ */
1116 };
1117
1118 /*----- Key attributes ----------------------------------------------------*/
1119
1120 static void *keyattrs_gmlookup(PyObject *me, PyObject *k, unsigned *f)
1121 {
1122   char *name = TEXT_STR(k);
1123   key_attr *a = 0;
1124
1125   if (!name) goto end;
1126   if (f && !(KEYATTRS_KF(me)->f&KF_WRITE)) KEYERR(KERR_READONLY);
1127   a = sym_find(&KEYATTRS_K(me)->a, name, -1, f ? sizeof(key_attr) : 0, f);
1128   if (f && !*f) a->p = 0;
1129 end:
1130   return (a);
1131 }
1132
1133 static void keyattrs_gmiterinit(PyObject *me, void *i)
1134   { sym_mkiter(i, &KEYATTRS_K(me)->a); }
1135
1136 static void *keyattrs_gmiternext(PyObject *me, void *i)
1137   { return (sym_next(i)); }
1138
1139 static PyObject *keyattrs_gmentrykey(PyObject *me, void *e)
1140   { return (TEXT_FROMSTR(SYM_NAME(e))); }
1141
1142 static PyObject *keyattrs_gmentryvalue(PyObject *me, void *e)
1143   { return (TEXT_FROMSTR(((key_attr *)e)->p)); }
1144
1145 static int keyattrs_gmsetentry(PyObject *me, void *e, PyObject *val)
1146 {
1147   key_attr *a = e;
1148   const char *p;
1149   Py_ssize_t n;
1150   int rc = -1;
1151
1152   if (!TEXT_CHECK(val)) TYERR("expected string");
1153   TEXT_PTRLEN(val, p, n);
1154   if (n > 255) VALERR("attribute too long");
1155   if (memchr(p, 0, n)) VALERR("attribute must not contain nul");
1156   if (a->p) xfree(a->p);
1157   a->p = xmalloc(n + 1); memcpy(a->p, p, n + 1);
1158   KEYATTRS_KF(me)->f |= KF_MODIFIED;
1159   rc = 0;
1160 end:
1161   return (rc);
1162 }
1163
1164 static int keyattrs_gmdelentry(PyObject *me, void *e)
1165 {
1166   key_attr *a = e;
1167   int rc = -1;
1168
1169   if (!(KEYATTRS_KF(me)->f&KF_WRITE)) KEYERR(KERR_READONLY);
1170   if (a->p) { KEYATTRS_KF(me)->f |= KF_MODIFIED; xfree(a->p); }
1171   sym_remove(&KEYATTRS_K(me)->a, a);
1172   rc = 0;
1173 end:
1174   return (rc);
1175 }
1176
1177 static const gmap_ops keyattrs_gmops = {
1178   sizeof(sym_iter),
1179   keyattrs_gmlookup,
1180   keyattrs_gmiterinit,
1181   keyattrs_gmiternext,
1182   keyattrs_gmentrykey,
1183   keyattrs_gmentryvalue,
1184   keyattrs_gmsetentry,
1185   keyattrs_gmdelentry
1186 };
1187
1188 static PyObject *keyattrs_make(PyObject *kobj)
1189 {
1190   keyattrs_pyobj *me = PyObject_NEW(keyattrs_pyobj, keyattrs_pytype);
1191   me->gmops = &keyattrs_gmops;
1192   me->kobj = kobj;
1193   Py_INCREF(kobj);
1194   return ((PyObject *)me);
1195 }
1196
1197 static void keyattrs_pydealloc(PyObject *me)
1198 {
1199   Py_DECREF(KEYATTRS_KOBJ(me));
1200   FREEOBJ(me);
1201 }
1202
1203 static Py_ssize_t keyattrs_pysize(PyObject *me)
1204   { return gmap_pysize_from_sym(&KEYATTRS_K(me)->a); }
1205
1206 static const PyMappingMethods keyattrs_pymapping = {
1207   keyattrs_pysize,
1208   gmap_pylookup,
1209   gmap_pystore
1210 };
1211
1212 static const PyTypeObject keyattrs_pytype_skel = {
1213   PyVarObject_HEAD_INIT(0, 0)           /* Header */
1214   "KeyAttributes",                      /* @tp_name@ */
1215   sizeof(keyattrs_pyobj),               /* @tp_basicsize@ */
1216   0,                                    /* @tp_itemsize@ */
1217
1218   keyattrs_pydealloc,                   /* @tp_dealloc@ */
1219   0,                                    /* @tp_print@ */
1220   0,                                    /* @tp_getattr@ */
1221   0,                                    /* @tp_setattr@ */
1222   0,                                    /* @tp_compare@ */
1223   0,                                    /* @tp_repr@ */
1224   0,                                    /* @tp_as_number@ */
1225   PYSEQUENCE(gmap),                     /* @tp_as_sequence@ */
1226   PYMAPPING(keyattrs),                  /* @tp_as_mapping@ */
1227   0,                                    /* @tp_hash@ */
1228   0,                                    /* @tp_call@ */
1229   0,                                    /* @tp_str@ */
1230   0,                                    /* @tp_getattro@ */
1231   0,                                    /* @tp_setattro@ */
1232   0,                                    /* @tp_as_buffer@ */
1233   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1234     Py_TPFLAGS_BASETYPE,
1235
1236   /* @tp_doc@ */
1237   "Proxy thing for talking about key attributes.",
1238
1239   0,                                    /* @tp_traverse@ */
1240   0,                                    /* @tp_clear@ */
1241   0,                                    /* @tp_richcompare@ */
1242   0,                                    /* @tp_weaklistoffset@ */
1243   gmap_pyiter,                          /* @tp_iter@ */
1244   0,                                    /* @tp_iternext@ */
1245   PYMETHODS(gmap),                      /* @tp_methods@ */
1246   0,                                    /* @tp_members@ */
1247   0,                                    /* @tp_getset@ */
1248   0,                                    /* @tp_base@ */
1249   0,                                    /* @tp_dict@ */
1250   0,                                    /* @tp_descr_get@ */
1251   0,                                    /* @tp_descr_set@ */
1252   0,                                    /* @tp_dictoffset@ */
1253   0,                                    /* @tp_init@ */
1254   PyType_GenericAlloc,                  /* @tp_alloc@ */
1255   abstract_pynew,                       /* @tp_new@ */
1256   0,                                    /* @tp_free@ */
1257   0                                     /* @tp_is_gc@ */
1258 };
1259
1260 /*----- Key objects -------------------------------------------------------*/
1261
1262 static PyObject *key_dowrap(PyTypeObject *ty, PyObject *kfobj, key *k)
1263 {
1264   key_pyobj *kobj = (key_pyobj *)ty->tp_alloc(ty, 0);
1265   kobj->kfobj = kfobj;
1266   Py_INCREF(kfobj);
1267   kobj->k = k;
1268   return ((PyObject *)kobj);
1269 }
1270
1271 static PyObject *key_pywrap(PyObject *kfobj, key *k)
1272   { return (key_dowrap(key_pytype, kfobj, k)); }
1273
1274 static PyObject *key_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
1275 {
1276   PyObject *kfobj;
1277   uint32 id;
1278   char *type;
1279   unsigned long exptime = KEXP_FOREVER;
1280   static const char *const kwlist[] =
1281     { "keyfile", "id", "type", "exptime", 0 };
1282   key *k;
1283   int err;
1284
1285   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!O&s|O&:new", KWLIST,
1286                                    keyfile_pytype, &kfobj, convu32, &id,
1287                                    &type, convulong, &exptime))
1288     goto end;
1289   if ((err = key_new(KEYFILE_KF(kfobj), id, type, exptime, &k)) != 0)
1290     KEYERR(err);
1291   return (key_dowrap(ty, kfobj, k));
1292 end:
1293   return (0);
1294 }
1295
1296 static void key_pydealloc(PyObject *me)
1297 {
1298   Py_DECREF(KEY_KFOBJ(me));
1299   FREEOBJ(me);
1300 }
1301
1302 static PyObject *kmeth_delete(PyObject *me)
1303 {
1304   int err;
1305
1306   if ((err = key_delete(KEY_KF(me), KEY_K(me))) != 0) KEYERR(err);
1307   RETURN_ME;
1308 end:
1309   return (0);
1310 }
1311
1312 static PyObject *kmeth_expire(PyObject *me)
1313 {
1314   int err;
1315
1316   if ((err = key_expire(KEY_KF(me), KEY_K(me))) != 0) KEYERR(err);
1317   RETURN_ME;
1318 end:
1319   return (0);
1320 }
1321
1322 static PyObject *kmeth_used(PyObject *me, PyObject *arg)
1323 {
1324   long t;
1325   int err;
1326
1327   if (!PyArg_ParseTuple(arg, "l:used", &t)) goto end;
1328   if ((err = key_used(KEY_KF(me), KEY_K(me), t)) != 0) KEYERR(err);
1329   RETURN_ME;
1330 end:
1331   return (0);
1332 }
1333
1334 static PyObject *kmeth_extract(PyObject *me, PyObject *arg, PyObject *kw)
1335 {
1336   key_filter f = { 0, 0 };
1337   PyObject *file;
1338   PyObject *nameobj;
1339   char *name;
1340   FILE *fp;
1341   static const char *const kwlist[] = { "file", "filter", 0 };
1342
1343   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!|O&:extract", KWLIST,
1344                                    &PyFile_Type, &file,
1345                                    convfilter, &f) ||
1346       (fp = PyFile_AsFile(file)) == 0 ||
1347       (nameobj = PyFile_Name(file)) == 0 ||
1348       (name = TEXT_STR(nameobj)) == 0)
1349     goto end;
1350   if (key_extract(KEY_KF(me), KEY_K(me), fp, &f))
1351     OSERR(name);
1352   RETURN_ME;
1353 end:
1354   return (0);
1355 }
1356
1357 static PyObject *kmeth_fingerprint(PyObject *me,
1358                                    PyObject *arg, PyObject *kw)
1359 {
1360   ghash *h;
1361   key_filter f = { KF_NONSECRET, KF_NONSECRET };
1362   static const char *const kwlist[] = { "hash", "filter", 0 };
1363
1364   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|O&:fingerprint", KWLIST,
1365                                    convghash, &h, convfilter, &f))
1366     return (0);
1367   return (getbool(key_fingerprint(KEY_K(me), h, &f)));
1368 }
1369
1370 static PyObject *kget_id(PyObject *me, void *hunoz)
1371   { return (getulong(KEY_K(me)->id)); }
1372 static PyObject *kget_file(PyObject *me, void *hunoz)
1373   { RETURN_OBJ(KEY_KFOBJ(me)); }
1374 static PyObject *kget_type(PyObject *me, void *hunoz)
1375   { return (TEXT_FROMSTR(KEY_K(me)->type)); }
1376 static PyObject *kget_exptime(PyObject *me, void *hunoz)
1377   { return (getulong(KEY_K(me)->exp)); }
1378 static PyObject *kget_deltime(PyObject *me, void *hunoz)
1379   { return (getulong(KEY_K(me)->del)); }
1380 static PyObject *kget_expiredp(PyObject *me, void *hunoz)
1381   { return (getbool(key_expired(KEY_K(me)))); }
1382 static PyObject *kget_attr(PyObject *me, void *hunoz)
1383   { return (keyattrs_make(me)); }
1384
1385 static int kset_exptime(PyObject *me, PyObject *x, void *hunoz)
1386 {
1387   key *k = KEY_K(me);
1388   unsigned long et;
1389
1390   if (!x) NIERR("__del__");
1391   if (!convulong(x, &et))
1392     goto end;
1393   if (!(KEY_KF(me)->f & KF_WRITE))
1394     KEYERR(KERR_READONLY);
1395   k->exp = et;
1396   KEY_KF(me)->f |= KF_MODIFIED;
1397   return (0);
1398 end:
1399   return (-1);
1400 }
1401
1402 static int kset_deltime(PyObject *me, PyObject *x, void *hunoz)
1403 {
1404   key *k = KEY_K(me);
1405   unsigned long dt;
1406
1407   if (!x) NIERR("__del__");
1408   if (!convulong(x, &dt))
1409     goto end;
1410   if (dt == KEXP_FOREVER && k->exp != KEXP_FOREVER)
1411     VALERR("key will eventually expire");
1412   if (!(KEY_KF(me)->f & KF_WRITE))
1413     KEYERR(KERR_READONLY);
1414   k->del = dt;
1415   KEY_KF(me)->f |= KF_MODIFIED;
1416   return (0);
1417 end:
1418   return (-1);
1419 }
1420
1421 static PyObject *kget_data(PyObject *me, void *hunoz)
1422 {
1423   key_data *kd = KEY_K(me)->k;
1424   key_incref(kd);
1425   return (keydata_pywrap(kd));
1426 }
1427 static int kset_data(PyObject *me, PyObject *x, void *hunoz)
1428 {
1429   int err;
1430
1431   if (!x) NIERR("__del__");
1432   if (!KEYDATA_PYCHECK(x)) TYERR("expected KeyData object");
1433   if ((err = key_setkeydata(KEY_KF(me), KEY_K(me), KEYDATA_KD(x))) != 0)
1434     KEYERR(err);
1435   return (0);
1436 end:
1437   return (-1);
1438 }
1439
1440 static PyObject *kget_fulltag(PyObject *me, void *hunoz)
1441 {
1442   dstr d = DSTR_INIT;
1443   PyObject *rc;
1444
1445   key_fulltag(KEY_K(me), &d);
1446   rc = TEXT_FROMSTRLEN(d.buf, d.len);
1447   dstr_destroy(&d);
1448   return (rc);
1449 }
1450
1451 static PyObject *kget_tag(PyObject *me, void *hunoz)
1452 {
1453   if (!KEY_K(me)->tag) RETURN_NONE;
1454   return (TEXT_FROMSTR(KEY_K(me)->tag));
1455 }
1456 static int kset_tag(PyObject *me, PyObject *x, void *hunoz)
1457 {
1458   int err;
1459   char *tag;
1460
1461   if (!x || x == Py_None) tag = 0;
1462   else if ((tag = TEXT_STR(x)) == 0) goto end;
1463   if ((err = key_settag(KEY_KF(me), KEY_K(me), tag)) != 0) KEYERR(err);
1464   return (0);
1465 end:
1466   return (-1);
1467 }
1468
1469 static PyObject *kget_comment(PyObject *me, void *hunoz)
1470 {
1471   if (!KEY_K(me)->c) RETURN_NONE;
1472   return (TEXT_FROMSTR(KEY_K(me)->c));
1473 }
1474 static int kset_comment(PyObject *me, PyObject *x, void *hunoz)
1475 {
1476   int err;
1477   char *c;
1478
1479   if (!x || x == Py_None) c = 0;
1480   else if ((c = TEXT_STR(x)) == 0) goto end;
1481   if ((err = key_setcomment(KEY_KF(me), KEY_K(me), c)) != 0) KEYERR(err);
1482   return (0);
1483 end:
1484   return (-1);
1485 }
1486
1487 static const PyMethodDef key_pymethods[] = {
1488 #define METHNAME(func) kmeth_##func
1489   NAMETH(delete,        "KEY.delete()")
1490   NAMETH(expire,        "KEY.expire()")
1491   METH  (used,          "KEY.used(TIME)")
1492   KWMETH(extract,       "KEY.extract(FILE, [filter = <any>])")
1493   KWMETH(fingerprint,   "KEY.fingerprint(HASH, [filter = '-secret'])")
1494 #undef METHNAME
1495   { 0 }
1496 };
1497
1498 static const PyGetSetDef key_pygetset[] = {
1499 #define GETSETNAME(op, name) k##op##_##name
1500   GET   (file,          "KEY.file -> KF")
1501   GET   (id,            "KEY.id -> ID")
1502   GETSET(tag,           "KEY.tag -> TAG")
1503   GET   (type,          "KEY.type -> TYPE")
1504   GETSET(exptime,       "KEY.exptime -> TIME")
1505   GETSET(deltime,       "KEY.deltime -> TIME")
1506   GET   (expiredp,      "KEY.expiredp -> BOOL")
1507   GET   (attr,          "KEY.attr -> ATTRIBUTES")
1508   GETSET(data,          "KEY.data -> KD")
1509   GETSET(comment,       "KEY.comment -> COMMENT")
1510   GET   (fulltag,       "KEY.fulltag -> FULLTAG")
1511 #undef GETSETNAME
1512   { 0 }
1513 };
1514
1515 static const PyTypeObject key_pytype_skel = {
1516   PyVarObject_HEAD_INIT(0, 0)           /* Header */
1517   "Key",                                /* @tp_name@ */
1518   sizeof(key_pyobj),                    /* @tp_basicsize@ */
1519   0,                                    /* @tp_itemsize@ */
1520
1521   key_pydealloc,                        /* @tp_dealloc@ */
1522   0,                                    /* @tp_print@ */
1523   0,                                    /* @tp_getattr@ */
1524   0,                                    /* @tp_setattr@ */
1525   0,                                    /* @tp_compare@ */
1526   0,                                    /* @tp_repr@ */
1527   0,                                    /* @tp_as_number@ */
1528   0,                                    /* @tp_as_sequence@ */
1529   0,                                    /* @tp_as_mapping@ */
1530   0,                                    /* @tp_hash@ */
1531   0,                                    /* @tp_call@ */
1532   0,                                    /* @tp_str@ */
1533   0,                                    /* @tp_getattro@ */
1534   0,                                    /* @tp_setattro@ */
1535   0,                                    /* @tp_as_buffer@ */
1536   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1537     Py_TPFLAGS_BASETYPE,
1538
1539   /* @tp_doc@ */
1540   "Key(KF, ID, TYPE, [exptime = KEXP_FOREVER]): key object.",
1541
1542   0,                                    /* @tp_traverse@ */
1543   0,                                    /* @tp_clear@ */
1544   0,                                    /* @tp_richcompare@ */
1545   0,                                    /* @tp_weaklistoffset@ */
1546   0,                                    /* @tp_iter@ */
1547   0,                                    /* @tp_iternext@ */
1548   PYMETHODS(key),                       /* @tp_methods@ */
1549   0,                                    /* @tp_members@ */
1550   PYGETSET(key),                        /* @tp_getset@ */
1551   0,                                    /* @tp_base@ */
1552   0,                                    /* @tp_dict@ */
1553   0,                                    /* @tp_descr_get@ */
1554   0,                                    /* @tp_descr_set@ */
1555   0,                                    /* @tp_dictoffset@ */
1556   0,                                    /* @tp_init@ */
1557   PyType_GenericAlloc,                  /* @tp_alloc@ */
1558   key_pynew,                            /* @tp_new@ */
1559   0,                                    /* @tp_free@ */
1560   0                                     /* @tp_is_gc@ */
1561 };
1562
1563 /*----- Key files ---------------------------------------------------------*/
1564
1565 static key *bytag(PyObject *me, PyObject *tagobj)
1566 {
1567   uint32 id;
1568   char *tag;
1569   key *k = 0;
1570
1571   if (convu32(tagobj, &id))
1572     k = key_byid(KEYFILE_KF(me), id);
1573   else {
1574     PyErr_Clear();
1575     if ((tag = TEXT_STR(tagobj)) == 0)
1576       goto end;
1577     k = key_bytag(KEYFILE_KF(me), tag);
1578   }
1579 end:
1580   return (k);
1581 }
1582
1583 static void *keyfile_gmlookup(PyObject *me, PyObject *k, unsigned *f)
1584   { key *kk = bytag(me, k); if (f) *f = !!kk; return (kk); }
1585
1586 static void keyfile_gmiterinit(PyObject *me, void *i)
1587   { key_mkiter(i, KEYFILE_KF(me)); }
1588
1589 static void *keyfile_gmiternext(PyObject *me, void *i)
1590   { return (key_next(i)); }
1591
1592 static PyObject *keyfile_gmentrykey(PyObject *me, void *e)
1593   { key *k = e; return (getulong(k->id)); }
1594
1595 static PyObject *keyfile_gmentryvalue(PyObject *me, void *e)
1596   { return (key_pywrap(me, e)); }
1597
1598 static const gmap_ops keyfile_gmops = {
1599   sizeof(key_iter),
1600   keyfile_gmlookup,
1601   keyfile_gmiterinit,
1602   keyfile_gmiternext,
1603   keyfile_gmentrykey,
1604   keyfile_gmentryvalue,
1605   0,
1606   0
1607 };
1608
1609 struct reportinfo {
1610   PyObject *func;
1611   int stop;
1612 };
1613
1614 static void pythonreporter(const char *file, int line,
1615                            const char *msg, void *p)
1616 {
1617   struct reportinfo *ri = p;
1618   PyObject *res = 0;
1619
1620   if (ri->stop)
1621     return;
1622   if (!ri->func)
1623     key_moan(file, line, msg, 0);
1624   else if ((res = PyObject_CallFunction(ri->func, "sis",
1625                                         file, line, msg)) == 0)
1626     ri->stop = 1;
1627   else
1628     Py_DECREF(res);
1629 }
1630
1631 static PyObject *keyfile_pynew(PyTypeObject *ty,
1632                                PyObject *arg, PyObject *kw)
1633 {
1634   struct reportinfo ri = { 0, 0 };
1635   char *file = 0;
1636   unsigned how = KOPEN_READ;
1637   keyfile_pyobj *rc = 0;
1638   static const char *const kwlist[] = { "file", "how", "report", 0 };
1639
1640   Py_XINCREF(arg); Py_XINCREF(kw);
1641   if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|iO:new", KWLIST,
1642                                    &file, &how, &ri.func))
1643     goto end;
1644   if (ri.func && !PyCallable_Check(ri.func))
1645     TYERR("reporter function not callable");
1646   if ((rc = (keyfile_pyobj *)ty->tp_alloc(ty, 0)) == 0)
1647     goto end;
1648   rc->gmops = &keyfile_gmops;
1649   if (key_open(&rc->kf, file, how, pythonreporter, &ri))
1650     OSERR(file);
1651   if (ri.stop) {
1652     key_discard(&rc->kf);
1653     goto end;
1654   }
1655   goto done;
1656
1657 end:
1658   if (rc) {
1659     FREEOBJ(rc);
1660     rc = 0;
1661   }
1662 done:
1663   Py_XDECREF(arg); Py_XDECREF(kw);
1664   return ((PyObject *)rc);
1665 }
1666
1667 static void keyfile_pydealloc(PyObject *me)
1668 {
1669   key_discard(KEYFILE_KF(me));
1670   FREEOBJ(me);
1671 }
1672
1673 static PyObject *kfmeth_save(PyObject *me)
1674 {
1675   switch (key_save(KEYFILE_KF(me))) {
1676     case KWRITE_OK:
1677       RETURN_ME;
1678     case KWRITE_FAIL:
1679       KEYIOERR(KEYFILE_KF(me)->name);
1680     case KWRITE_BROKEN:
1681       KEYFILEBROKEN(KEYFILE_KF(me)->name);
1682     default:
1683       abort();
1684   }
1685 end:
1686   return (0);
1687 }
1688
1689 static PyObject *kfmeth_merge(PyObject *me, PyObject *arg, PyObject *kw)
1690 {
1691   struct reportinfo ri = { 0, 0 };
1692   char *name;
1693   PyObject *x = 0;
1694   FILE *fp = 0;
1695   int rc;
1696   static const char *const kwlist[] = { "file", "report", 0 };
1697
1698   Py_XINCREF(arg); Py_XINCREF(kw);
1699   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O!|O:merge", KWLIST,
1700                                    &PyFile_Type, &x, &ri.func))
1701     goto end;
1702   if (ri.func && !PyCallable_Check(ri.func))
1703     TYERR("reporter function not callable");
1704   if ((fp = PyFile_AsFile(x)) == 0)
1705     goto end;
1706   x = PyFile_Name(x);
1707   if ((name = TEXT_STR(x)) == 0)
1708     goto end;
1709   rc = key_merge(KEYFILE_KF(me), name, fp, pythonreporter, &ri);
1710   if (ri.stop)
1711     goto end;
1712   if (rc != 0)
1713     KEYERR(rc);
1714   Py_XDECREF(arg); Py_XDECREF(kw);
1715   RETURN_ME;
1716
1717 end:
1718   Py_XDECREF(arg); Py_XDECREF(kw);
1719   return (0);
1720 }
1721
1722 static PyObject *kfmeth_byid(PyObject *me, PyObject *arg)
1723 {
1724   uint32 id;
1725   key *k;
1726   PyObject *rc = 0;
1727
1728   if (!PyArg_ParseTuple(arg, "O&:byid", convu32, &id)) goto end;
1729   if ((k = key_byid(KEYFILE_KF(me), id)) == 0) KEYERR(KERR_NOTFOUND);
1730   rc = key_pywrap(me, k);
1731 end:
1732   return (rc);
1733 }
1734
1735 static PyObject *kfmeth_bytype(PyObject *me, PyObject *arg)
1736 {
1737   char *type;
1738   key *k;
1739   PyObject *rc = 0;
1740
1741   if (!PyArg_ParseTuple(arg, "s:bytype", &type)) goto end;
1742   if ((k = key_bytype(KEYFILE_KF(me), type)) == 0) RETURN_NONE;
1743   rc = key_pywrap(me, k);
1744 end:
1745   return (rc);
1746 }
1747
1748 static PyObject *kfmeth_bytag(PyObject *me, PyObject *arg)
1749 {
1750   PyObject *tagobj;
1751   key *k;
1752
1753   if (!PyArg_ParseTuple(arg, "O:bytag", &tagobj)) return (0);
1754   if ((k = bytag(me, tagobj)) == 0) RETURN_NONE;
1755   else return (key_pywrap(me, k));
1756 }
1757
1758 static PyObject *kfmeth_newkey(PyObject *me, PyObject *arg, PyObject *kw)
1759 {
1760   uint32 id;
1761   char *type;
1762   long exptime = KEXP_FOREVER;
1763   static const char *const kwlist[] = { "id", "type", "exptime", 0 };
1764   key *k;
1765   int err;
1766
1767   if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&s|l:newkey", KWLIST,
1768                                    convu32, &id, &type, &exptime))
1769     goto end;
1770   if ((err = key_new(KEYFILE_KF(me), id, type, exptime, &k)) != 0)
1771     KEYERR(err);
1772   return (key_pywrap(me, k));
1773 end:
1774   return (0);
1775 }
1776
1777 static PyObject *kfmeth_qtag(PyObject *me, PyObject *arg, PyObject *kw)
1778 {
1779   key *k;
1780   key_data **kd, *okd;
1781   PyObject *newkdobj = 0;
1782   char *tag;
1783   dstr d = DSTR_INIT;
1784   PyObject *rc = 0;
1785   static const char *const kwlist[] = { "tag", "new", 0 };
1786
1787   if (!PyArg_ParseTupleAndKeywords(arg, kw, "s|O!:qtag", KWLIST,
1788                                    &tag, keydata_pytype, &newkdobj))
1789     goto end;
1790   if (key_qtag(KEYFILE_KF(me), tag, &d, &k, &kd))
1791     KEYERR(KERR_NOTFOUND);
1792   okd = *kd;
1793   if (newkdobj) {
1794     if (!(KEYFILE_KF(me)->f & KF_WRITE))
1795       KEYERR(KERR_READONLY);
1796     KEYFILE_KF(me)->f |= KF_MODIFIED;
1797     *kd = KEYDATA_KD(newkdobj);
1798   }
1799   key_incref(*kd);
1800   rc = Py_BuildValue("(s#NN)",
1801                      d.buf, (Py_ssize_t)d.len,
1802                      key_pywrap(me, k),
1803                      keydata_pywrap(okd));
1804 end:
1805   return (rc);
1806 }
1807
1808 static PyObject *kfget_name(PyObject *me, void *hunoz)
1809   { return (TEXT_FROMSTR(KEYFILE_KF(me)->name)); }
1810 static PyObject *kfget_modifiedp(PyObject *me, void *hunoz)
1811   { return (getbool(KEYFILE_KF(me)->f & KF_MODIFIED)); }
1812 static PyObject *kfget_writep(PyObject *me, void *hunoz)
1813   { return (getbool(KEYFILE_KF(me)->f & KF_WRITE)); }
1814 static PyObject *kfget_filep(PyObject *me, void *hunoz)
1815   { return (getbool(!!KEYFILE_KF(me)->fp)); }
1816
1817 static const PyMethodDef keyfile_pymethods[] = {
1818 #define METHNAME(func) kfmeth_##func
1819   NAMETH(save,          "KF.save()")
1820   KWMETH(merge,         "KF.merge(FILE, [report = <built-in-reporter>])")
1821   KWMETH(newkey,        "KF.newkey(ID, TYPE, [exptime = KEXP_FOREVER]) "
1822                                                                     "-> KEY")
1823   METH  (byid,          "KF.byid(KEYID) -> KEY|None")
1824   METH  (bytype,        "KF.bytype(TYPE) -> KEY|None")
1825   METH  (bytag,         "KF.bytag(TAG) -> KEY|None")
1826   KWMETH(qtag,          "KF.qtag(TAG, [new = KD]) -> FULLTAG, KEY, OLDKD")
1827   GMAP_ROMETHODS
1828 #undef METHNAME
1829   { 0 }
1830 };
1831
1832 static const PyGetSetDef keyfile_pygetset[] = {
1833 #define GETSETNAME(op, name) kf##op##_##name
1834   GET   (name,          "KF.name -> file name")
1835   GET   (modifiedp,     "KF.modifiedp -> has keyring been modified?")
1836   GET   (writep,        "KF.writep -> is keyring modifiable?")
1837   GET   (filep,         "KF.filep -> does keyring have a backing file?")
1838 #undef GETSETNAME
1839   { 0 }
1840 };
1841
1842 static const PyMappingMethods keyfile_pymapping = {
1843   gmap_pysize,
1844   gmap_pylookup,
1845   0
1846 };
1847
1848 static const PyTypeObject keyfile_pytype_skel = {
1849   PyVarObject_HEAD_INIT(0, 0)           /* Header */
1850   "KeyFile",                            /* @tp_name@ */
1851   sizeof(keyfile_pyobj),                /* @tp_basicsize@ */
1852   0,                                    /* @tp_itemsize@ */
1853
1854   keyfile_pydealloc,                    /* @tp_dealloc@ */
1855   0,                                    /* @tp_print@ */
1856   0,                                    /* @tp_getattr@ */
1857   0,                                    /* @tp_setattr@ */
1858   0,                                    /* @tp_compare@ */
1859   0,                                    /* @tp_repr@ */
1860   0,                                    /* @tp_as_number@ */
1861   PYSEQUENCE(gmap),                     /* @tp_as_sequence@ */
1862   PYMAPPING(keyfile),                   /* @tp_as_mapping@ */
1863   0,                                    /* @tp_hash@ */
1864   0,                                    /* @tp_call@ */
1865   0,                                    /* @tp_str@ */
1866   0,                                    /* @tp_getattro@ */
1867   0,                                    /* @tp_setattro@ */
1868   0,                                    /* @tp_as_buffer@ */
1869   Py_TPFLAGS_DEFAULT |                  /* @tp_flags@ */
1870     Py_TPFLAGS_BASETYPE,
1871
1872   /* @tp_doc@ */
1873   "KeyFile(FILE, [how = KOPEN_READ], [report = ?]): Keyring file.\n"
1874   "   calls REPORT(FILE, LINE, MSG) on problems",
1875
1876   0,                                    /* @tp_traverse@ */
1877   0,                                    /* @tp_clear@ */
1878   0,                                    /* @tp_richcompare@ */
1879   0,                                    /* @tp_weaklistoffset@ */
1880   gmap_pyiter,                          /* @tp_iter@ */
1881   0,                                    /* @tp_iternext@ */
1882   PYMETHODS(keyfile),                   /* @tp_methods@ */
1883   0,                                    /* @tp_members@ */
1884   PYGETSET(keyfile),                    /* @tp_getset@ */
1885   0,                                    /* @tp_base@ */
1886   0,                                    /* @tp_dict@ */
1887   0,                                    /* @tp_descr_get@ */
1888   0,                                    /* @tp_descr_set@ */
1889   0,                                    /* @tp_dictoffset@ */
1890   0,                                    /* @tp_init@ */
1891   PyType_GenericAlloc,                  /* @tp_alloc@ */
1892   keyfile_pynew,                        /* @tp_new@ */
1893   0,                                    /* @tp_free@ */
1894   0                                     /* @tp_is_gc@ */
1895 };
1896
1897 /*----- Initialization ----------------------------------------------------*/
1898
1899 static const struct nameval consts[] = {
1900   CONST(KOPEN_READ), CONST(KOPEN_WRITE), CONST(KOPEN_NOFILE),
1901   CONST(KEXP_FOREVER), CONST(KEXP_EXPIRE),
1902   CONST(KF_ENCMASK), CONST(KENC_BINARY), CONST(KENC_MP), CONST(KENC_STRUCT),
1903     CONST(KENC_ENCRYPT), CONST(KENC_STRING), CONST(KENC_EC),
1904   CONST(KF_CATMASK), CONST(KCAT_SYMM), CONST(KCAT_PRIV), CONST(KCAT_PUB),
1905     CONST(KCAT_SHARE),
1906   CONST(KF_NONSECRET),
1907   CONST(KF_BURN), CONST(KF_OPT),
1908 #define ENTRY(tag, val, str) CONSTFLAG(CF_SIGNED, KERR_##tag),
1909   KEY_ERRORS(ENTRY)
1910 #undef ENTRY
1911   { 0 }
1912 };
1913
1914 void key_pyinit(void)
1915 {
1916   INITTYPE(keyfile, root);
1917   INITTYPE(key, root);
1918   INITTYPE(keydata, root);
1919   INITTYPE(keydatabin, keydata);
1920   INITTYPE(keydataenc, keydata);
1921   INITTYPE(keydatastr, keydata);
1922   INITTYPE(keydatamp, keydata);
1923   INITTYPE(keydataec, keydata);
1924   INITTYPE(keydatastruct, keydata);
1925   INITTYPE(keyattrs, root);
1926 }
1927
1928 void key_pyinsert(PyObject *mod)
1929 {
1930   INSEXC("KeyError", keyexc, PyExc_Exception, keyexc_pymethods);
1931   INSEXC("KeyFileIOError", keyioexc, PyExc_OSError, 0);
1932   INSEXC("KeyFileBroken", keyfilebrokenexc, keyioexc, 0);
1933   INSERT("KeyFile", keyfile_pytype);
1934   INSERT("Key", key_pytype);
1935   INSERT("KeyAttributes", keyattrs_pytype);
1936   INSERT("KeyData", keydata_pytype);
1937   INSERT("KeyDataBinary", keydatabin_pytype);
1938   INSERT("KeyDataEncrypted", keydataenc_pytype);
1939   INSERT("KeyDataMP", keydatamp_pytype);
1940   INSERT("KeyDataECPt", keydataec_pytype);
1941   INSERT("KeyDataString", keydatastr_pytype);
1942   INSERT("KeyDataStructured", keydatastruct_pytype);
1943   setconstants(mod, consts);
1944 }
1945
1946 /*----- That's all, folks -------------------------------------------------*/