Use gpg_error_from_syserror instead of directly accessing errno.
[gpgme.git] / src / trustlist.c
1 /* trustlist.c - Trust item listing.
2    Copyright (C) 2000 Werner Koch (dd9jn)
3    Copyright (C) 2001, 2002, 2003, 2004 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 Lesser General Public License as
9    published by the Free Software Foundation; either version 2.1 of
10    the License, or (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    Lesser General Public License for more details.
16
17    You should have received a copy of the GNU Lesser General Public
18    License along with this program; if not, write to the Free Software
19    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20    02111-1307, USA.  */
21
22 #if HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include <errno.h>
29
30 #include "gpgme.h"
31 #include "debug.h"
32 #include "util.h"
33 #include "context.h"
34 #include "ops.h"
35
36 \f
37 struct trust_queue_item_s
38 {
39   struct trust_queue_item_s *next;
40   gpgme_trust_item_t item;
41 };
42
43 typedef struct
44 {
45   /* Something new is available.  */
46   int trust_cond;
47   struct trust_queue_item_s *trust_queue;
48 } *op_data_t;
49
50
51 \f
52 static gpgme_error_t
53 trustlist_status_handler (void *priv, gpgme_status_code_t code, char *args)
54 {
55   return 0;
56 }
57
58
59 /* This handler is used to parse the output of --list-trust-path:
60    Format:
61    level:keyid:type:recno:ot:val:mc:cc:name:
62    With TYPE = U for a user ID
63                K for a key
64    The RECNO is either the one of the dir record or the one of the uid
65    record.  OT is the the usual trust letter and only availabel on K
66    lines.  VAL is the calcualted validity MC is the marginal trust
67    counter and only available on U lines CC is the same for the
68    complete count NAME ist the username and only printed on U
69    lines.  */
70 static gpgme_error_t
71 trustlist_colon_handler (void *priv, char *line)
72 {
73   gpgme_ctx_t ctx = (gpgme_ctx_t) priv;
74   gpgme_error_t err;
75   char *p, *pend;
76   int field = 0;
77   gpgme_trust_item_t item = NULL;
78
79   if (!line)
80     return 0; /* EOF */
81
82   for (p = line; p; p = pend)
83     {
84       field++;
85       pend = strchr (p, ':');
86       if (pend)
87         *pend++ = 0;
88
89       switch (field)
90         {
91         case 1: /* level */
92           err = _gpgme_trust_item_new (&item);
93           if (err)
94             return err;
95           item->level = atoi (p);
96           break;
97         case 2: /* long keyid */
98           if (strlen (p) == DIM(item->keyid) - 1)
99             strcpy (item->keyid, p);
100           break;
101         case 3: /* type */
102           item->type = *p == 'K'? 1 : *p == 'U'? 2 : 0;
103           break;
104         case 5: /* owner trust */
105           item->_owner_trust[0] = *p;
106           break;
107         case 6: /* validity */
108           item->_validity[0] = *p;
109           break;
110         case 9: /* user ID */
111           item->name = strdup (p);
112           if (!item->name)
113             {
114               int saved_err = gpg_error_from_syserror ();
115               gpgme_trust_item_unref (item);
116               return saved_err;
117             }
118           break;
119         }
120     }
121
122   if (item)
123     _gpgme_engine_io_event (ctx->engine, GPGME_EVENT_NEXT_TRUSTITEM, item);
124   return 0;
125 }
126
127
128 void
129 _gpgme_op_trustlist_event_cb (void *data, gpgme_event_io_t type,
130                               void *type_data)
131 {
132   gpgme_ctx_t ctx = (gpgme_ctx_t) data;
133   gpgme_error_t err;
134   void *hook;
135   op_data_t opd;
136   gpgme_trust_item_t item = (gpgme_trust_item_t) type_data;
137   struct trust_queue_item_s *q, *q2;
138
139   assert (type == GPGME_EVENT_NEXT_TRUSTITEM);
140
141   err = _gpgme_op_data_lookup (ctx, OPDATA_TRUSTLIST, &hook, -1, NULL);
142   opd = hook;
143   if (err)
144     return;
145
146   q = malloc (sizeof *q);
147   if (!q)
148     {
149       gpgme_trust_item_unref (item);
150       /* FIXME: GPGME_Out_Of_Core; */
151       return;
152     }
153   q->item = item;
154   q->next = NULL;
155   /* FIXME: Use a tail pointer */
156   q2 = opd->trust_queue;
157   if (!q2)
158     opd->trust_queue = q;
159   else
160     {
161       while (q2->next)
162         q2 = q2->next;
163       q2->next = q;
164     }
165   /* FIXME: unlock queue */
166   opd->trust_cond = 1;
167 }
168
169
170 gpgme_error_t
171 gpgme_op_trustlist_start (gpgme_ctx_t ctx, const char *pattern, int max_level)
172 {
173   gpgme_error_t err = 0;
174   void *hook;
175   op_data_t opd;
176
177   TRACE_BEG2 (DEBUG_CTX, "gpgme_op_trustlist_start", ctx,
178               "pattern=%s, max_level=%i", pattern, max_level);
179
180   if (!ctx || !pattern || !*pattern)
181     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
182
183   err = _gpgme_op_reset (ctx, 2);
184   if (err)
185     return TRACE_ERR (err);
186
187   err = _gpgme_op_data_lookup (ctx, OPDATA_TRUSTLIST, &hook,
188                                sizeof (*opd), NULL);
189   opd = hook;
190   if (err)
191     return TRACE_ERR (err);
192
193   _gpgme_engine_set_status_handler (ctx->engine,
194                                     trustlist_status_handler, ctx);
195   err = _gpgme_engine_set_colon_line_handler (ctx->engine,
196                                               trustlist_colon_handler, ctx);
197   if (err)
198     return TRACE_ERR (err);
199
200   err = _gpgme_engine_op_trustlist (ctx->engine, pattern);
201   return TRACE_ERR (err);
202 }
203
204
205 gpgme_error_t
206 gpgme_op_trustlist_next (gpgme_ctx_t ctx, gpgme_trust_item_t *r_item)
207 {
208   gpgme_error_t err;
209   void *hook;
210   op_data_t opd;
211   struct trust_queue_item_s *q;
212
213   TRACE_BEG (DEBUG_CTX, "gpgme_op_trustlist_next", ctx);
214
215   if (!ctx || !r_item)
216     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
217   *r_item = NULL;
218   if (!ctx)
219     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
220
221   err = _gpgme_op_data_lookup (ctx, OPDATA_TRUSTLIST, &hook, -1, NULL);
222   opd = hook;
223   if (err)
224     return TRACE_ERR (err);
225   if (opd == NULL)
226     return TRACE_ERR (gpg_error (GPG_ERR_INV_VALUE));
227
228   if (!opd->trust_queue)
229     {
230       err = _gpgme_wait_on_condition (ctx, &opd->trust_cond, NULL);
231       if (err)
232         return TRACE_ERR (err);
233       if (!opd->trust_cond)
234         return TRACE_ERR (gpg_error (GPG_ERR_EOF));
235       opd->trust_cond = 0;
236       assert (opd->trust_queue);
237     }
238   q = opd->trust_queue;
239   opd->trust_queue = q->next;
240
241   *r_item = q->item;
242   free (q);
243   if ((*r_item)->type == 1)
244     {
245       TRACE_SUC5 ("trust_item=%p: %s: owner trust %s with level %i "
246                   "and validity 0x%x", *r_item, (*r_item)->keyid,
247                   (*r_item)->owner_trust, (*r_item)->level,
248                   (*r_item)->validity);
249     }
250   else if ((*r_item)->type == 2)
251     {
252       TRACE_SUC5 ("trust_item=%p: %s: UID %s with level %i "
253                   "and validity 0x%x", *r_item, (*r_item)->keyid,
254                   (*r_item)->name, (*r_item)->level, (*r_item)->validity);
255     }
256   else
257     {
258       TRACE_SUC5 ("trust_item=%p: %s: unknown type %i with level %i "
259                   "and validity 0x%x", *r_item, (*r_item)->keyid,
260                   (*r_item)->type, (*r_item)->level, (*r_item)->validity);
261     }
262   return 0;
263 }
264
265
266 /* Terminate a pending trustlist operation within CTX.  */
267 gpgme_error_t
268 gpgme_op_trustlist_end (gpgme_ctx_t ctx)
269 {
270   TRACE (DEBUG_CTX, "gpgme_op_trustlist_end", ctx);
271
272   if (!ctx)
273     return gpg_error (GPG_ERR_INV_VALUE);
274
275   return 0;
276 }