More changes and and some new functions
[gpgme.git] / gpgme / trustlist.c
1 /* trustlist.c -  key listing
2  *      Copyright (C) 2000 Werner Koch (dd9jn)
3  *
4  * This file is part of GPGME.
5  *
6  * GPGME is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * GPGME is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <time.h>
26 #include <assert.h>
27
28 #include "util.h"
29 #include "context.h"
30 #include "ops.h"
31
32 #define my_isdigit(a) ( (a) >='0' && (a) <= '9' )
33
34 struct gpgme_trust_item_s {
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 = xtrycalloc (1, sizeof *item);
50     return item;
51 }
52
53
54
55 static void
56 trustlist_status_handler ( GpgmeCtx ctx, GpgStatusCode code, char *args )
57 {
58     if ( ctx->out_of_core )
59         return;
60
61     switch (code) {
62       case STATUS_EOF:
63         break;
64
65       default:
66         break;
67     }
68 }
69
70
71
72 /* 
73  * This handler is used to parse the output of --list-trust-path:
74  * Format:
75  *   level:keyid:type:recno:ot:val:mc:cc:name:
76  * With TYPE = U for a user ID
77  *             K for a key
78  * The RECNO is either the one of the dir record or the one of the uid record.
79  * OT is the the usual trust letter and only availabel on K lines.
80  * VAL is the calcualted validity
81  * MC is the marginal trust counter and only available on U lines
82  * CC is the same for the complete count
83  * NAME ist the username and only printed on U lines
84  */
85 static void
86 trustlist_colon_handler ( GpgmeCtx ctx, char *line )
87 {
88     char *p, *pend;
89     int field = 0;
90     GpgmeTrustItem item = NULL;
91     struct trust_queue_item_s *q, *q2;
92
93     if ( ctx->out_of_core )
94         return;
95     if (!line)
96         return; /* EOF */
97
98     for (p = line; p; p = pend) {
99         field++;
100         pend = strchr (p, ':');
101         if (pend) 
102             *pend++ = 0;
103
104         switch (field) {
105           case 1: /* level */
106             q = xtrymalloc ( sizeof *q );
107             if ( !q ) {
108                 ctx->out_of_core = 1;
109                 return;
110             }
111             q->next = NULL;
112             q->item = item = trust_item_new ();
113             if (!q->item) {
114                 xfree (q);
115                 ctx->out_of_core = 1;
116                 return;
117             }
118             /* fixme: lock queue, keep a tail pointer */
119             if ( !(q2 = ctx->trust_queue) )
120                 ctx->trust_queue = q;
121             else {
122                 for ( ; q2->next; q2 = q2->next )
123                     ;
124                 q2->next = q;
125             }
126             /* fixme: unlock queue */
127             item->level = atoi (p);
128             break;
129           case 2: /* long keyid */
130             if ( strlen (p) == DIM(item->keyid)-1 )
131                 strcpy (item->keyid, p);
132             break;
133           case 3: /* type */
134             item->type = *p == 'K'? 1 : *p == 'U'? 2 : 0;
135             break;
136           case 5: /* owner trust */
137             item->ot[0] = *p;
138             item->ot[1] = 0;
139             break;
140           case 6: /* validity */
141             item->val[0] = *p;
142             item->val[1] = 0;
143             break;
144           case 10: /* user ID */
145             item->name = xtrystrdup (p);
146             if (!item->name)
147                 ctx->out_of_core = 1;
148             break;
149         }
150     }
151
152     if (field)
153         ctx->key_cond = 1;
154 }
155
156
157
158 GpgmeError
159 gpgme_op_trustlist_start ( GpgmeCtx c, const char *pattern, int max_level )
160 {
161     GpgmeError rc = 0;
162
163     fail_on_pending_request( c );
164     if ( !pattern || !*pattern ) {
165         return mk_error (Invalid_Value);
166     }
167
168     c->pending = 1;
169
170     _gpgme_release_result (c);
171     c->out_of_core = 0;
172
173     if ( c->gpg ) {
174         _gpgme_gpg_release ( c->gpg ); 
175         c->gpg = NULL;
176     }
177     
178     rc = _gpgme_gpg_new ( &c->gpg );
179     if (rc)
180         goto leave;
181
182     _gpgme_gpg_set_status_handler ( c->gpg, trustlist_status_handler, c );
183     rc = _gpgme_gpg_set_colon_line_handler ( c->gpg,
184                                              trustlist_colon_handler, c );
185     if (rc)
186         goto leave;
187
188     /* build the commandline */
189     _gpgme_gpg_add_arg ( c->gpg, "--with-colons" );
190     _gpgme_gpg_add_arg ( c->gpg, "--list-trust-path" );
191     
192     /* Tell the gpg object about the data */
193     _gpgme_gpg_add_arg ( c->gpg, "--" );
194     _gpgme_gpg_add_arg ( c->gpg, pattern );
195
196     /* and kick off the process */
197     rc = _gpgme_gpg_spawn ( c->gpg, c );
198
199  leave:
200     if (rc) {
201         c->pending = 0; 
202         _gpgme_gpg_release ( c->gpg ); c->gpg = NULL;
203     }
204     return rc;
205 }
206
207
208 GpgmeError
209 gpgme_op_trustlist_next ( GpgmeCtx c, GpgmeTrustItem *r_item )
210 {
211     struct trust_queue_item_s *q;
212
213     if (!r_item)
214         return mk_error (Invalid_Value);
215     *r_item = NULL;
216     if (!c)
217         return mk_error (Invalid_Value);
218     if ( !c->pending )
219         return mk_error (No_Request);
220     if ( c->out_of_core )
221         return mk_error (Out_Of_Core);
222
223     if ( !c->trust_queue ) {
224         _gpgme_wait_on_condition (c, 1, &c->key_cond );
225         if ( c->out_of_core )
226             return mk_error (Out_Of_Core);
227         if ( !c->key_cond )
228             return mk_error (EOF);
229         c->key_cond = 0; 
230         assert ( c->trust_queue );
231     }
232     q = c->trust_queue;
233     c->trust_queue = q->next;
234
235     *r_item = q->item;
236     xfree (q);
237     return 0;
238 }
239
240
241 void
242 gpgme_trust_item_release ( GpgmeTrustItem item )
243 {
244     if (!item)
245         return;
246     xfree (item->name);
247     xfree (item);
248 }
249
250
251 const char *
252 gpgme_trust_item_get_string_attr ( GpgmeTrustItem item, GpgmeAttr what,
253                                    const void *reserved, int idx )
254 {
255     const char *val = NULL;
256
257     if (!item)
258         return NULL;
259     if (reserved)
260         return NULL;
261     if (idx)
262         return NULL;
263
264     switch (what) {
265       case GPGME_ATTR_KEYID:
266         val = item->keyid;
267         break;
268       case GPGME_ATTR_OTRUST:  
269         val = item->ot;
270         break;
271       case GPGME_ATTR_VALIDITY:
272         val = item->val;
273         break;
274       case GPGME_ATTR_USERID:  
275         val = item->name;
276         break;
277       default:
278         break;
279     }
280     return val;
281 }
282
283
284 int
285 gpgme_trust_item_get_int_attr ( GpgmeTrustItem item, GpgmeAttr what,
286                                 const void *reserved, int idx )
287 {
288     int val = 0;
289
290     if (!item)
291         return 0;
292     if (reserved)
293         return 0;
294     if (idx)
295         return 0;
296
297     switch (what) {
298       case GPGME_ATTR_LEVEL:    
299         val = item->level;
300         break;
301       case GPGME_ATTR_TYPE:    
302         val = item->type;
303         break;
304       default:
305         break;
306     }
307     return val;
308 }
309