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