2002-10-10 Marcus Brinkmann <marcus@g10code.de>
[gpgme.git] / gpgme / trustlist.c
1 /* trustlist.c -  key listing
2  *      Copyright (C) 2000 Werner Koch (dd9jn)
3  *      Copyright (C) 2001, 2002 g10 Code GmbH
4  *
5  * This file is part of GPGME.
6  *
7  * GPGME is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GPGME is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
20  */
21
22 #include <config.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <time.h>
27 #include <assert.h>
28
29 #include "util.h"
30 #include "context.h"
31 #include "ops.h"
32
33 struct gpgme_trust_item_s
34 {
35   int level;
36   char keyid[16+1];
37   int type;   
38   char ot[2];
39   char val[2];
40   char *name;
41 };
42
43
44 static GpgmeTrustItem
45 trust_item_new (void)
46 {
47   GpgmeTrustItem item;
48
49   item = calloc (1, sizeof *item);
50   return item;
51 }
52
53
54 static void
55 trustlist_status_handler (GpgmeCtx ctx, GpgmeStatusCode code, char *args)
56 {
57   if (ctx->error)
58     return;
59
60   switch (code)
61     {
62     case GPGME_STATUS_EOF:
63       break;
64
65     default:
66       break;
67     }
68 }
69
70
71 /* 
72  * This handler is used to parse the output of --list-trust-path:
73  * Format:
74  *   level:keyid:type:recno:ot:val:mc:cc:name:
75  * With TYPE = U for a user ID
76  *             K for a key
77  * The RECNO is either the one of the dir record or the one of the uid record.
78  * OT is the the usual trust letter and only availabel on K lines.
79  * VAL is the calcualted validity
80  * MC is the marginal trust counter and only available on U lines
81  * CC is the same for the complete count
82  * NAME ist the username and only printed on U lines
83  */
84 static void
85 trustlist_colon_handler (GpgmeCtx ctx, char *line)
86 {
87   char *p, *pend;
88   int field = 0;
89   GpgmeTrustItem item = NULL;
90
91   if (ctx->error)
92     return;
93   if (!line)
94     return; /* EOF */
95
96   for (p = line; p; p = pend)
97     {
98       field++;
99       pend = strchr (p, ':');
100       if (pend) 
101         *pend++ = 0;
102
103       switch (field)
104         {
105         case 1: /* level */
106           item = trust_item_new ();
107           if (!item)
108             {
109               ctx->error = mk_error (Out_Of_Core);
110               return;
111             }
112           item->level = atoi (p);
113           break;
114         case 2: /* long keyid */
115           if (strlen (p) == DIM(item->keyid) - 1)
116             strcpy (item->keyid, p);
117           break;
118         case 3: /* type */
119           item->type = *p == 'K'? 1 : *p == 'U'? 2 : 0;
120           break;
121         case 5: /* owner trust */
122           item->ot[0] = *p;
123           item->ot[1] = 0;
124           break;
125         case 6: /* validity */
126           item->val[0] = *p;
127           item->val[1] = 0;
128           break;
129         case 9: /* user ID */
130           item->name = strdup (p);
131           if (!item->name)
132             ctx->error = mk_error (Out_Of_Core);
133           break;
134         }
135     }
136
137   if (item)
138     _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_TRUSTITEM, item);
139 }
140
141
142 void
143 _gpgme_op_trustlist_event_cb (void *data, GpgmeEventIO type, void *type_data)
144 {
145   GpgmeCtx ctx = (GpgmeCtx) data;
146   GpgmeTrustItem item = (GpgmeTrustItem) type_data;
147   struct trust_queue_item_s *q, *q2;
148
149   assert (type == GPGME_EVENT_NEXT_KEY);
150
151   q = malloc (sizeof *q);
152   if (!q)
153     {
154       gpgme_trust_item_release (item);
155       ctx->error = mk_error (Out_Of_Core);
156       return;
157     }
158   q->item = item;
159   q->next = NULL;
160   /* FIXME: lock queue, keep a tail pointer */
161   q2 = ctx->trust_queue;
162   if (!q2)
163     ctx->trust_queue = q;
164   else
165     {
166       while (q2->next)
167         q2 = q2->next;
168       q2->next = q;
169     }
170   /* FIXME: unlock queue */
171   ctx->key_cond = 1;
172 }
173
174
175 GpgmeError
176 gpgme_op_trustlist_start (GpgmeCtx ctx, const char *pattern, int max_level)
177 {
178   GpgmeError err = 0;
179
180   if (!pattern || !*pattern)
181     return mk_error (Invalid_Value);
182
183   err = _gpgme_op_reset (ctx, 2);
184   if (err)
185     goto leave;
186
187   _gpgme_engine_set_status_handler (ctx->engine,
188                                     trustlist_status_handler, ctx);
189   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
190                                               trustlist_colon_handler, ctx);
191   if (err)
192     goto leave;
193
194   err =_gpgme_engine_op_trustlist (ctx->engine, pattern);
195
196   if (!err)     /* And kick off the process.  */
197     err = _gpgme_engine_start (ctx->engine, ctx);
198
199  leave:
200   if (err)
201     {
202       ctx->pending = 0; 
203       _gpgme_engine_release (ctx->engine);
204       ctx->engine = NULL;
205     }
206   return err;
207 }
208
209
210 GpgmeError
211 gpgme_op_trustlist_next (GpgmeCtx ctx, GpgmeTrustItem *r_item)
212 {
213   struct trust_queue_item_s *q;
214
215   if (!r_item)
216     return mk_error (Invalid_Value);
217   *r_item = NULL;
218   if (!ctx)
219     return mk_error (Invalid_Value);
220   if (!ctx->pending)
221     return mk_error (No_Request);
222   if (ctx->error)
223     return ctx->error;
224
225   if (!ctx->trust_queue)
226     {
227       GpgmeError err = _gpgme_wait_on_condition (ctx, &ctx->key_cond);
228       if (err)
229         {
230           ctx->pending = 0;
231           return err;
232         }
233       if (!ctx->pending)
234         {
235           /* The operation finished.  Because not all keys might have
236              been returned to the caller yet, we just reset the
237              pending flag to 1.  This will cause us to call
238              _gpgme_wait_on_condition without any active file
239              descriptors, but that is a no-op, so it is safe.  */
240           ctx->pending = 1;
241         }
242       if (!ctx->key_cond)
243         {
244           ctx->pending = 0;
245           return mk_error (EOF);
246         }
247       ctx->key_cond = 0; 
248       assert (ctx->trust_queue);
249     }
250   q = ctx->trust_queue;
251   ctx->trust_queue = q->next;
252
253   *r_item = q->item;
254   free (q);
255   return 0;
256 }
257
258
259 /**
260  * gpgme_op_trustlist_end:
261  * @c: Context
262  *
263  * Ends the trustlist operation and allows to use the context for some
264  * other operation next.
265  **/
266 GpgmeError
267 gpgme_op_trustlist_end (GpgmeCtx ctx)
268 {
269   if (!ctx)
270     return mk_error (Invalid_Value);
271   if (!ctx->pending)
272     return mk_error (No_Request);
273   if (ctx->error)
274     return ctx->error;
275
276   ctx->pending = 0;
277   return 0;
278 }
279
280
281 void
282 gpgme_trust_item_release (GpgmeTrustItem item)
283 {
284   if (!item)
285     return;
286   free (item->name);
287   free (item);
288 }
289
290
291 const char *
292 gpgme_trust_item_get_string_attr (GpgmeTrustItem item, GpgmeAttr what,
293                                   const void *reserved, int idx)
294 {
295   const char *val = NULL;
296
297   if (!item)
298     return NULL;
299   if (reserved)
300     return NULL;
301   if (idx)
302     return NULL;
303
304   switch (what)
305     {
306     case GPGME_ATTR_KEYID:
307       val = item->keyid;
308       break;
309     case GPGME_ATTR_OTRUST:  
310       val = item->ot;
311       break;
312     case GPGME_ATTR_VALIDITY:
313       val = item->val;
314       break;
315     case GPGME_ATTR_USERID:  
316       val = item->name;
317       break;
318     default:
319       break;
320     }
321   return val;
322 }
323
324
325 int
326 gpgme_trust_item_get_int_attr (GpgmeTrustItem item, GpgmeAttr what,
327                                const void *reserved, int idx)
328 {
329   int val = 0;
330   
331   if (!item)
332     return 0;
333   if (reserved)
334     return 0;
335   if (idx)
336     return 0;
337
338   switch (what)
339     {
340     case GPGME_ATTR_LEVEL:    
341       val = item->level;
342       break;
343     case GPGME_ATTR_TYPE:    
344       val = item->type;
345       break;
346     default:
347       break;
348     }
349   return val;
350 }