build: Update standard build-aux files.
[gnupg.git] / g10 / kbnode.c
1 /* kbnode.c -  keyblock node utility functions
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002,
3  *               2005, 2010 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
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 3 of the License, or
10  * (at your option) any later version.
11  *
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.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, see <http://www.gnu.org/licenses/>.
19  */
20
21 #include <config.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26
27 #include "gpg.h"
28 #include "util.h"
29 #include "../common/init.h"
30 #include "packet.h"
31 #include "keydb.h"
32
33 #define USE_UNUSED_NODES 1
34
35 static int cleanup_registered;
36 static KBNODE unused_nodes;
37
38 #if USE_UNUSED_NODES
39 static void
40 release_unused_nodes (void)
41 {
42   while (unused_nodes)
43     {
44       kbnode_t next = unused_nodes->next;
45       xfree (unused_nodes);
46       unused_nodes = next;
47     }
48 }
49 #endif /*USE_UNUSED_NODES*/
50
51
52 static kbnode_t
53 alloc_node (void)
54 {
55   kbnode_t n;
56
57   n = unused_nodes;
58   if (n)
59     unused_nodes = n->next;
60   else
61     {
62       if (!cleanup_registered)
63         {
64           cleanup_registered = 1;
65           register_mem_cleanup_func (release_unused_nodes);
66         }
67       n = xmalloc (sizeof *n);
68     }
69   n->next = NULL;
70   n->pkt = NULL;
71   n->flag = 0;
72   n->private_flag=0;
73   n->recno = 0;
74   return n;
75 }
76
77 static void
78 free_node( KBNODE n )
79 {
80   if (n)
81     {
82 #if USE_UNUSED_NODES
83       n->next = unused_nodes;
84       unused_nodes = n;
85 #else
86       xfree (n);
87 #endif
88     }
89 }
90
91
92
93 KBNODE
94 new_kbnode( PACKET *pkt )
95 {
96     KBNODE n = alloc_node();
97     n->pkt = pkt;
98     return n;
99 }
100
101
102 KBNODE
103 clone_kbnode( KBNODE node )
104 {
105     KBNODE n = alloc_node();
106
107     n->pkt = node->pkt;
108     n->private_flag = node->private_flag | 2; /* mark cloned */
109     return n;
110 }
111
112
113 void
114 release_kbnode( KBNODE n )
115 {
116     KBNODE n2;
117
118     while( n ) {
119         n2 = n->next;
120         if( !is_cloned_kbnode(n) ) {
121             free_packet( n->pkt );
122             xfree( n->pkt );
123         }
124         free_node( n );
125         n = n2;
126     }
127 }
128
129
130 /****************
131  * Delete NODE.
132  * Note: This only works with walk_kbnode!!
133  */
134 void
135 delete_kbnode( KBNODE node )
136 {
137     node->private_flag |= 1;
138 }
139
140 /****************
141  * Append NODE to ROOT.  ROOT must exist!
142  */
143 void
144 add_kbnode( KBNODE root, KBNODE node )
145 {
146     KBNODE n1;
147
148     for(n1=root; n1->next; n1 = n1->next)
149         ;
150     n1->next = node;
151 }
152
153 /****************
154  * Insert NODE into the list after root but before a packet which is not of
155  * type PKTTYPE
156  * (only if PKTTYPE != 0)
157  */
158 void
159 insert_kbnode( KBNODE root, KBNODE node, int pkttype )
160 {
161     if( !pkttype ) {
162         node->next = root->next;
163         root->next = node;
164     }
165     else {
166         KBNODE n1;
167
168         for(n1=root; n1->next;  n1 = n1->next)
169             if( pkttype != n1->next->pkt->pkttype ) {
170                 node->next = n1->next;
171                 n1->next = node;
172                 return;
173             }
174         /* no such packet, append */
175         node->next = NULL;
176         n1->next = node;
177     }
178 }
179
180
181 /****************
182  * Find the previous node (if PKTTYPE = 0) or the previous node
183  * with pkttype PKTTYPE in the list starting with ROOT of NODE.
184  */
185 KBNODE
186 find_prev_kbnode( KBNODE root, KBNODE node, int pkttype )
187 {
188     KBNODE n1;
189
190     for (n1=NULL; root && root != node; root = root->next ) {
191         if (!pkttype ||root->pkt->pkttype == pkttype)
192             n1 = root;
193     }
194     return n1;
195 }
196
197 /****************
198  * Ditto, but find the next packet.  The behaviour is trivial if
199  * PKTTYPE is 0 but if it is specified, the next node with a packet
200  * of this type is returned.  The function has some knowledge about
201  * the valid ordering of packets: e.g. if the next signature packet
202  * is requested, the function will not return one if it encounters
203  * a user-id.
204  */
205 KBNODE
206 find_next_kbnode( KBNODE node, int pkttype )
207 {
208     for( node=node->next ; node; node = node->next ) {
209         if( !pkttype )
210             return node;
211         else if( pkttype == PKT_USER_ID
212                  && (   node->pkt->pkttype == PKT_PUBLIC_KEY
213                      || node->pkt->pkttype == PKT_SECRET_KEY ) )
214             return NULL;
215         else if( pkttype == PKT_SIGNATURE
216                  && (   node->pkt->pkttype == PKT_USER_ID
217                      || node->pkt->pkttype == PKT_PUBLIC_KEY
218                      || node->pkt->pkttype == PKT_SECRET_KEY ) )
219             return NULL;
220         else if( node->pkt->pkttype == pkttype )
221             return node;
222     }
223     return NULL;
224 }
225
226
227 KBNODE
228 find_kbnode( KBNODE node, int pkttype )
229 {
230     for( ; node; node = node->next ) {
231         if( node->pkt->pkttype == pkttype )
232             return node;
233     }
234     return NULL;
235 }
236
237
238
239 /****************
240  * Walk through a list of kbnodes. This function returns
241  * the next kbnode for each call; before using the function the first
242  * time, the caller must set CONTEXT to NULL (This has simply the effect
243  * to start with ROOT).
244  */
245 KBNODE
246 walk_kbnode( KBNODE root, KBNODE *context, int all )
247 {
248     KBNODE n;
249
250     do {
251         if( !*context ) {
252             *context = root;
253             n = root;
254         }
255         else {
256             n = (*context)->next;
257             *context = n;
258         }
259     } while( !all && n && is_deleted_kbnode(n) );
260
261     return n;
262 }
263
264 void
265 clear_kbnode_flags( KBNODE n )
266 {
267     for( ; n; n = n->next ) {
268         n->flag = 0;
269     }
270 }
271
272
273 /****************
274  * Commit changes made to the kblist at ROOT. Note that ROOT my change,
275  * and it is therefore passed by reference.
276  * The function has the effect of removing all nodes marked as deleted.
277  * returns true if any node has been changed
278  */
279 int
280 commit_kbnode( KBNODE *root )
281 {
282     KBNODE n, nl;
283     int changed = 0;
284
285     for( n = *root, nl=NULL; n; n = nl->next ) {
286         if( is_deleted_kbnode(n) ) {
287             if( n == *root )
288                 *root = nl = n->next;
289             else
290                 nl->next = n->next;
291             if( !is_cloned_kbnode(n) ) {
292                 free_packet( n->pkt );
293                 xfree( n->pkt );
294             }
295             free_node( n );
296             changed = 1;
297         }
298         else
299             nl = n;
300     }
301     return changed;
302 }
303
304 void
305 remove_kbnode( KBNODE *root, KBNODE node )
306 {
307     KBNODE n, nl;
308
309     for( n = *root, nl=NULL; n; n = nl->next ) {
310         if( n == node ) {
311             if( n == *root )
312                 *root = nl = n->next;
313             else
314                 nl->next = n->next;
315             if( !is_cloned_kbnode(n) ) {
316                 free_packet( n->pkt );
317                 xfree( n->pkt );
318             }
319             free_node( n );
320         }
321         else
322             nl = n;
323     }
324 }
325
326
327 /****************
328  * Move NODE behind right after WHERE or to the beginning if WHERE is NULL.
329  */
330 void
331 move_kbnode( KBNODE *root, KBNODE node, KBNODE where )
332 {
333     KBNODE tmp, prev;
334
335     if( !root || !*root || !node )
336         return;  /* sanity check */
337     for( prev = *root; prev && prev->next != node; prev = prev->next )
338         ;
339     if( !prev )
340         return; /* node is not in the list */
341
342     if( !where ) {  /* move node before root */
343         if( node == *root ) /* move to itself */
344             return;
345         prev->next = node->next;
346         node->next = *root;
347         *root = node;
348         return;
349     }
350     /* move it after where */
351     if( node == where )
352         return;
353     tmp = node->next;
354     node->next = where->next;
355     where->next = node;
356     prev->next = tmp;
357 }
358
359
360
361
362 void
363 dump_kbnode (KBNODE node)
364 {
365   for (; node; node = node->next )
366     {
367       const char *s;
368       switch (node->pkt->pkttype)
369         {
370         case 0:         s="empty"; break;
371         case PKT_PUBLIC_KEY:    s="public-key"; break;
372         case PKT_SECRET_KEY:    s="secret-key"; break;
373         case PKT_SECRET_SUBKEY: s= "secret-subkey"; break;
374         case PKT_PUBKEY_ENC:    s="public-enc"; break;
375         case PKT_SIGNATURE:     s="signature"; break;
376         case PKT_ONEPASS_SIG: s="onepass-sig"; break;
377         case PKT_USER_ID:       s="user-id"; break;
378         case PKT_PUBLIC_SUBKEY: s="public-subkey"; break;
379         case PKT_COMMENT:       s="comment"; break;
380         case PKT_RING_TRUST:    s="trust"; break;
381         case PKT_PLAINTEXT:     s="plaintext"; break;
382         case PKT_COMPRESSED:    s="compressed"; break;
383         case PKT_ENCRYPTED:     s="encrypted"; break;
384         case PKT_GPG_CONTROL: s="gpg-control"; break;
385         default:                s="unknown"; break;
386         }
387       log_debug ("node %p %02x/%02x type=%s",
388                  node, node->flag, node->private_flag, s);
389       if (node->pkt->pkttype == PKT_USER_ID)
390         {
391           PKT_user_id *uid = node->pkt->pkt.user_id;
392           log_printf ("  \"");
393           es_write_sanitized (log_get_stream (), uid->name, uid->len,
394                               NULL, NULL);
395           log_printf ("\" %c%c%c%c\n",
396                       uid->is_expired? 'e':'.',
397                       uid->is_revoked? 'r':'.',
398                       uid->created?    'v':'.',
399                       uid->is_primary? 'p':'.' );
400         }
401       else if (node->pkt->pkttype == PKT_SIGNATURE)
402         {
403           log_printf ("  class=%02x keyid=%08lX ts=%lu\n",
404                       node->pkt->pkt.signature->sig_class,
405                       (ulong)node->pkt->pkt.signature->keyid[1],
406                       (ulong)node->pkt->pkt.signature->timestamp);
407         }
408       else if (node->pkt->pkttype == PKT_GPG_CONTROL)
409         {
410           log_printf (" ctrl=%d len=%u\n",
411                       node->pkt->pkt.gpg_control->control,
412                       (unsigned int)node->pkt->pkt.gpg_control->datalen);
413         }
414       else if (node->pkt->pkttype == PKT_PUBLIC_KEY
415                || node->pkt->pkttype == PKT_PUBLIC_SUBKEY)
416         {
417           PKT_public_key *pk = node->pkt->pkt.public_key;
418
419           log_printf ("  keyid=%08lX a=%d u=%d %c%c%c%c\n",
420                       (ulong)keyid_from_pk( pk, NULL ),
421                       pk->pubkey_algo, pk->pubkey_usage,
422                       pk->has_expired? 'e':'.',
423                       pk->flags.revoked? 'r':'.',
424                       pk->flags.valid?    'v':'.',
425                       pk->flags.mdc?   'm':'.');
426         }
427       else
428         log_printf ("\n");
429
430       log_flush ();
431     }
432 }