2001-11-21 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 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 #define my_isdigit(a) ( (a) >='0' && (a) <= '9' )
34
35 struct gpgme_trust_item_s {
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 = xtrycalloc (1, sizeof *item);
51     return item;
52 }
53
54
55
56 static void
57 trustlist_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
58 {
59     if ( ctx->out_of_core )
60         return;
61
62     switch (code) {
63       case STATUS_EOF:
64         break;
65
66       default:
67         break;
68     }
69 }
70
71
72
73 /* 
74  * This handler is used to parse the output of --list-trust-path:
75  * Format:
76  *   level:keyid:type:recno:ot:val:mc:cc:name:
77  * With TYPE = U for a user ID
78  *             K for a key
79  * The RECNO is either the one of the dir record or the one of the uid record.
80  * OT is the the usual trust letter and only availabel on K lines.
81  * VAL is the calcualted validity
82  * MC is the marginal trust counter and only available on U lines
83  * CC is the same for the complete count
84  * NAME ist the username and only printed on U lines
85  */
86 static void
87 trustlist_colon_handler ( GpgmeCtx ctx, char *line )
88 {
89     char *p, *pend;
90     int field = 0;
91     GpgmeTrustItem item = NULL;
92     struct trust_queue_item_s *q, *q2;
93
94     if ( ctx->out_of_core )
95         return;
96     if (!line)
97         return; /* EOF */
98
99     for (p = line; p; p = pend) {
100         field++;
101         pend = strchr (p, ':');
102         if (pend) 
103             *pend++ = 0;
104
105         switch (field) {
106           case 1: /* level */
107             q = xtrymalloc ( sizeof *q );
108             if ( !q ) {
109                 ctx->out_of_core = 1;
110                 return;
111             }
112             q->next = NULL;
113             q->item = item = trust_item_new ();
114             if (!q->item) {
115                 xfree (q);
116                 ctx->out_of_core = 1;
117                 return;
118             }
119             /* fixme: lock queue, keep a tail pointer */
120             if ( !(q2 = ctx->trust_queue) )
121                 ctx->trust_queue = q;
122             else {
123                 for ( ; q2->next; q2 = q2->next )
124                     ;
125                 q2->next = q;
126             }
127             /* fixme: unlock queue */
128             item->level = atoi (p);
129             break;
130           case 2: /* long keyid */
131             if ( strlen (p) == DIM(item->keyid)-1 )
132                 strcpy (item->keyid, p);
133             break;
134           case 3: /* type */
135             item->type = *p == 'K'? 1 : *p == 'U'? 2 : 0;
136             break;
137           case 5: /* owner trust */
138             item->ot[0] = *p;
139             item->ot[1] = 0;
140             break;
141           case 6: /* validity */
142             item->val[0] = *p;
143             item->val[1] = 0;
144             break;
145           case 9: /* user ID */
146             item->name = xtrystrdup (p);
147             if (!item->name)
148                 ctx->out_of_core = 1;
149             break;
150         }
151     }
152
153     if (field)
154         ctx->key_cond = 1;
155 }
156
157 GpgmeError
158 gpgme_op_trustlist_start (GpgmeCtx ctx, const char *pattern, int max_level)
159 {
160   GpgmeError err = 0;
161
162   fail_on_pending_request (ctx);
163   if (!pattern || !*pattern)
164     return mk_error (Invalid_Value);
165
166   ctx->pending = 1;
167
168   _gpgme_release_result (ctx);
169   ctx->out_of_core = 0;
170
171   if (ctx->engine)
172     {
173       _gpgme_engine_release (ctx->engine); 
174       ctx->engine = NULL;
175     }
176     
177   err = _gpgme_engine_new (ctx->use_cms ? GPGME_PROTOCOL_CMS
178                            : GPGME_PROTOCOL_OpenPGP, &ctx->engine);
179   if (err)
180     goto leave;
181
182   _gpgme_engine_set_status_handler (ctx->engine, 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   if (!err)     /* And kick off the process.  */
191     err = _gpgme_engine_start (ctx->engine, ctx);
192
193  leave:
194   if (err) {
195     ctx->pending = 0; 
196     _gpgme_engine_release (ctx->engine);
197     ctx->engine = NULL;
198   }
199   return err;
200 }
201
202
203 GpgmeError
204 gpgme_op_trustlist_next ( GpgmeCtx c, GpgmeTrustItem *r_item )
205 {
206     struct trust_queue_item_s *q;
207
208     if (!r_item)
209         return mk_error (Invalid_Value);
210     *r_item = NULL;
211     if (!c)
212         return mk_error (Invalid_Value);
213     if ( !c->pending )
214         return mk_error (No_Request);
215     if ( c->out_of_core )
216         return mk_error (Out_Of_Core);
217
218     if ( !c->trust_queue ) {
219         _gpgme_wait_on_condition (c, 1, &c->key_cond );
220         if ( c->out_of_core )
221             return mk_error (Out_Of_Core);
222         if ( !c->key_cond )
223             return mk_error (EOF);
224         c->key_cond = 0; 
225         assert ( c->trust_queue );
226     }
227     q = c->trust_queue;
228     c->trust_queue = q->next;
229
230     *r_item = q->item;
231     xfree (q);
232     return 0;
233 }
234
235
236 void
237 gpgme_trust_item_release ( GpgmeTrustItem item )
238 {
239     if (!item)
240         return;
241     xfree (item->name);
242     xfree (item);
243 }
244
245
246 const char *
247 gpgme_trust_item_get_string_attr ( GpgmeTrustItem item, GpgmeAttr what,
248                                    const void *reserved, int idx )
249 {
250     const char *val = NULL;
251
252     if (!item)
253         return NULL;
254     if (reserved)
255         return NULL;
256     if (idx)
257         return NULL;
258
259     switch (what) {
260       case GPGME_ATTR_KEYID:
261         val = item->keyid;
262         break;
263       case GPGME_ATTR_OTRUST:  
264         val = item->ot;
265         break;
266       case GPGME_ATTR_VALIDITY:
267         val = item->val;
268         break;
269       case GPGME_ATTR_USERID:  
270         val = item->name;
271         break;
272       default:
273         break;
274     }
275     return val;
276 }
277
278
279 int
280 gpgme_trust_item_get_int_attr ( GpgmeTrustItem item, GpgmeAttr what,
281                                 const void *reserved, int idx )
282 {
283     int val = 0;
284
285     if (!item)
286         return 0;
287     if (reserved)
288         return 0;
289     if (idx)
290         return 0;
291
292     switch (what) {
293       case GPGME_ATTR_LEVEL:    
294         val = item->level;
295         break;
296       case GPGME_ATTR_TYPE:    
297         val = item->type;
298         break;
299       default:
300         break;
301     }
302     return val;
303 }
304