* keyserver.c (path_makes_direct): New. (keyserver_spawn): Used here
[gnupg.git] / g10 / kbnode.c
blob9038f5b44c151d5a41fb7de0ca7aa8da75beef8b
1 /* kbnode.c - keyblock node utility functions
2 * Copyright (C) 1998, 1999, 2000, 2001, 2002,
3 * 2005 Free Software Foundation, Inc.
5 * This file is part of GnuPG.
7 * GnuPG 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.
12 * GnuPG 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.
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20 * USA.
23 #include <config.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28 #include "util.h"
29 #include "memory.h"
30 #include "packet.h"
31 #include "keydb.h"
33 #define USE_UNUSED_NODES 1
35 static KBNODE unused_nodes;
37 static KBNODE
38 alloc_node(void)
40 KBNODE n;
42 n = unused_nodes;
43 if( n )
44 unused_nodes = n->next;
45 else
46 n = xmalloc( sizeof *n );
47 n->next = NULL;
48 n->pkt = NULL;
49 n->flag = 0;
50 n->private_flag=0;
51 n->recno = 0;
52 return n;
55 static void
56 free_node( KBNODE n )
58 if( n ) {
59 #if USE_UNUSED_NODES
60 n->next = unused_nodes;
61 unused_nodes = n;
62 #else
63 xfree( n );
64 #endif
70 KBNODE
71 new_kbnode( PACKET *pkt )
73 KBNODE n = alloc_node();
74 n->pkt = pkt;
75 return n;
79 KBNODE
80 clone_kbnode( KBNODE node )
82 KBNODE n = alloc_node();
84 n->pkt = node->pkt;
85 n->private_flag = node->private_flag | 2; /* mark cloned */
86 return n;
90 void
91 release_kbnode( KBNODE n )
93 KBNODE n2;
95 while( n ) {
96 n2 = n->next;
97 if( !is_cloned_kbnode(n) ) {
98 free_packet( n->pkt );
99 xfree( n->pkt );
101 free_node( n );
102 n = n2;
107 /****************
108 * Delete NODE.
109 * Note: This only works with walk_kbnode!!
111 void
112 delete_kbnode( KBNODE node )
114 node->private_flag |= 1;
117 /****************
118 * Append NODE to ROOT. ROOT must exist!
120 void
121 add_kbnode( KBNODE root, KBNODE node )
123 KBNODE n1;
125 for(n1=root; n1->next; n1 = n1->next)
127 n1->next = node;
130 /****************
131 * Insert NODE into the list after root but before a packet which is not of
132 * type PKTTYPE
133 * (only if PKTTYPE != 0)
135 void
136 insert_kbnode( KBNODE root, KBNODE node, int pkttype )
138 if( !pkttype ) {
139 node->next = root->next;
140 root->next = node;
142 else {
143 KBNODE n1;
145 for(n1=root; n1->next; n1 = n1->next)
146 if( pkttype != n1->next->pkt->pkttype ) {
147 node->next = n1->next;
148 n1->next = node;
149 return;
151 /* no such packet, append */
152 node->next = NULL;
153 n1->next = node;
158 /****************
159 * Find the previous node (if PKTTYPE = 0) or the previous node
160 * with pkttype PKTTYPE in the list starting with ROOT of NODE.
162 KBNODE
163 find_prev_kbnode( KBNODE root, KBNODE node, int pkttype )
165 KBNODE n1;
167 for (n1=NULL; root && root != node; root = root->next ) {
168 if (!pkttype ||root->pkt->pkttype == pkttype)
169 n1 = root;
171 return n1;
174 /****************
175 * Ditto, but find the next packet. The behaviour is trivial if
176 * PKTTYPE is 0 but if it is specified, the next node with a packet
177 * of this type is returned. The function has some knowledge about
178 * the valid ordering of packets: e.g. if the next signature packet
179 * is requested, the function will not return one if it encounters
180 * a user-id.
182 KBNODE
183 find_next_kbnode( KBNODE node, int pkttype )
185 for( node=node->next ; node; node = node->next ) {
186 if( !pkttype )
187 return node;
188 else if( pkttype == PKT_USER_ID
189 && ( node->pkt->pkttype == PKT_PUBLIC_KEY
190 || node->pkt->pkttype == PKT_SECRET_KEY ) )
191 return NULL;
192 else if( pkttype == PKT_SIGNATURE
193 && ( node->pkt->pkttype == PKT_USER_ID
194 || node->pkt->pkttype == PKT_PUBLIC_KEY
195 || node->pkt->pkttype == PKT_SECRET_KEY ) )
196 return NULL;
197 else if( node->pkt->pkttype == pkttype )
198 return node;
200 return NULL;
204 KBNODE
205 find_kbnode( KBNODE node, int pkttype )
207 for( ; node; node = node->next ) {
208 if( node->pkt->pkttype == pkttype )
209 return node;
211 return NULL;
216 /****************
217 * Walk through a list of kbnodes. This function returns
218 * the next kbnode for each call; before using the function the first
219 * time, the caller must set CONTEXT to NULL (This has simply the effect
220 * to start with ROOT).
222 KBNODE
223 walk_kbnode( KBNODE root, KBNODE *context, int all )
225 KBNODE n;
227 do {
228 if( !*context ) {
229 *context = root;
230 n = root;
232 else {
233 n = (*context)->next;
234 *context = n;
236 } while( !all && n && is_deleted_kbnode(n) );
238 return n;
241 void
242 clear_kbnode_flags( KBNODE n )
244 for( ; n; n = n->next ) {
245 n->flag = 0;
250 /****************
251 * Commit changes made to the kblist at ROOT. Note that ROOT my change,
252 * and it is therefore passed by reference.
253 * The function has the effect of removing all nodes marked as deleted.
254 * returns true if any node has been changed
257 commit_kbnode( KBNODE *root )
259 KBNODE n, nl;
260 int changed = 0;
262 for( n = *root, nl=NULL; n; n = nl->next ) {
263 if( is_deleted_kbnode(n) ) {
264 if( n == *root )
265 *root = nl = n->next;
266 else
267 nl->next = n->next;
268 if( !is_cloned_kbnode(n) ) {
269 free_packet( n->pkt );
270 xfree( n->pkt );
272 free_node( n );
273 changed = 1;
275 else
276 nl = n;
278 return changed;
281 void
282 remove_kbnode( KBNODE *root, KBNODE node )
284 KBNODE n, nl;
286 for( n = *root, nl=NULL; n; n = nl->next ) {
287 if( n == node ) {
288 if( n == *root )
289 *root = nl = n->next;
290 else
291 nl->next = n->next;
292 if( !is_cloned_kbnode(n) ) {
293 free_packet( n->pkt );
294 xfree( n->pkt );
296 free_node( n );
298 else
299 nl = n;
304 /****************
305 * Move NODE behind right after WHERE or to the beginning if WHERE is NULL.
307 void
308 move_kbnode( KBNODE *root, KBNODE node, KBNODE where )
310 KBNODE tmp, prev;
312 if( !root || !*root || !node )
313 return; /* sanity check */
314 for( prev = *root; prev && prev->next != node; prev = prev->next )
316 if( !prev )
317 return; /* node is not in the list */
319 if( !where ) { /* move node before root */
320 if( node == *root ) /* move to itself */
321 return;
322 prev->next = node->next;
323 node->next = *root;
324 *root = node;
325 return;
327 /* move it after where */
328 if( node == where )
329 return;
330 tmp = node->next;
331 node->next = where->next;
332 where->next = node;
333 prev->next = tmp;
339 void
340 dump_kbnode( KBNODE node )
342 for(; node; node = node->next ) {
343 const char *s;
344 switch( node->pkt->pkttype ) {
345 case 0: s="empty"; break;
346 case PKT_PUBLIC_KEY: s="public-key"; break;
347 case PKT_SECRET_KEY: s="secret-key"; break;
348 case PKT_SECRET_SUBKEY: s= "secret-subkey"; break;
349 case PKT_PUBKEY_ENC: s="public-enc"; break;
350 case PKT_SIGNATURE: s="signature"; break;
351 case PKT_ONEPASS_SIG: s="onepass-sig"; break;
352 case PKT_USER_ID: s="user-id"; break;
353 case PKT_PUBLIC_SUBKEY: s="public-subkey"; break;
354 case PKT_COMMENT: s="comment"; break;
355 case PKT_RING_TRUST: s="trust"; break;
356 case PKT_PLAINTEXT: s="plaintext"; break;
357 case PKT_COMPRESSED: s="compressed"; break;
358 case PKT_ENCRYPTED: s="encrypted"; break;
359 case PKT_GPG_CONTROL: s="gpg-control"; break;
360 default: s="unknown"; break;
362 fprintf(stderr, "node %p %02x/%02x type=%s",
363 node, node->flag, node->private_flag, s);
364 if( node->pkt->pkttype == PKT_USER_ID ) {
365 PKT_user_id *uid = node->pkt->pkt.user_id;
366 fputs(" \"", stderr);
367 print_string( stderr, uid->name, uid->len, 0 );
368 fprintf (stderr, "\" %c%c%c%c\n",
369 uid->is_expired? 'e':'.',
370 uid->is_revoked? 'r':'.',
371 uid->created? 'v':'.',
372 uid->is_primary? 'p':'.' );
374 else if( node->pkt->pkttype == PKT_SIGNATURE ) {
375 fprintf(stderr, " class=%02x keyid=%08lX ts=%lu\n",
376 node->pkt->pkt.signature->sig_class,
377 (ulong)node->pkt->pkt.signature->keyid[1],
378 (ulong)node->pkt->pkt.signature->timestamp);
380 else if( node->pkt->pkttype == PKT_GPG_CONTROL ) {
381 fprintf(stderr, " ctrl=%d len=%u\n",
382 node->pkt->pkt.gpg_control->control,
383 (unsigned int)node->pkt->pkt.gpg_control->datalen);
385 else if( node->pkt->pkttype == PKT_PUBLIC_KEY
386 || node->pkt->pkttype == PKT_PUBLIC_SUBKEY ) {
387 PKT_public_key *pk = node->pkt->pkt.public_key;
388 fprintf(stderr, " keyid=%08lX a=%d u=%d %c%c%c%c\n",
389 (ulong)keyid_from_pk( pk, NULL ),
390 pk->pubkey_algo, pk->pubkey_usage,
391 pk->has_expired? 'e':'.',
392 pk->is_revoked? 'r':'.',
393 pk->is_valid? 'v':'.',
394 pk->mdc_feature? 'm':'.');
396 else
397 fputs("\n", stderr);