Move mailsync functionality to the database backends.
[onak.git] / keydb.c
1 /*
2  * keydb.c - Routines for DB access that just use store/fetch.
3  *
4  * Jonathan McDowell <noodles@earth.li>
5  *
6  * Copyright 2002-2004 Project Purple
7  */
8
9 /**
10  *      The routines in this file are meant to be used as an initial step when
11  *      adding a new db access module. They provide various functions required
12  *      of the db access module using only the store and fetch functions. As
13  *      they need to parse the actual OpenPGP data to work they are a lot
14  *      slower than custom functions however.
15  */
16
17 #include <stdio.h>
18
19 #include "decodekey.h"
20 #include "hash.h"
21 #include "keydb.h"
22 #include "keyid.h"
23 #include "keystructs.h"
24 #include "mem.h"
25 #include "merge.h"
26 #include "parsekey.h"
27
28 #ifdef NEED_KEYID2UID
29 /**
30  *      keyid2uid - Takes a keyid and returns the primary UID for it.
31  *      @keyid: The keyid to lookup.
32  */
33 char *keyid2uid(uint64_t keyid)
34 {
35         struct openpgp_publickey *publickey = NULL;
36         struct openpgp_signedpacket_list *curuid = NULL;
37         char buf[1024];
38
39         buf[0]=0;
40         if (fetch_key(keyid, &publickey, false) && publickey != NULL) {
41                 curuid = publickey->uids;
42                 while (curuid != NULL && buf[0] == 0) {
43                         if (curuid->packet->tag == 13) {
44                                 snprintf(buf, 1023, "%.*s",
45                                                 (int) curuid->packet->length,
46                                                 curuid->packet->data);
47                         }
48                         curuid = curuid -> next;
49                 }
50                 free_publickey(publickey);
51         }
52
53         if (buf[0] == 0) {
54                 return NULL;
55         } else {
56                 return strdup(buf);
57         }
58 }
59 #endif
60
61 #ifdef NEED_GETKEYSIGS
62 /**
63  *      getkeysigs - Gets a linked list of the signatures on a key.
64  *      @keyid: The keyid to get the sigs for.
65  *      @revoked: Is the key revoked?
66  *
67  *      This function gets the list of signatures on a key. Used for key 
68  *      indexing and doing stats bits. If revoked is non-NULL then if the key
69  *      is revoked it's set to true.
70  */
71 struct ll *getkeysigs(uint64_t keyid, bool *revoked)
72 {
73         struct ll *sigs = NULL;
74         struct openpgp_signedpacket_list *uids = NULL;
75         struct openpgp_publickey *publickey = NULL;
76
77         fetch_key(keyid, &publickey, false);
78         
79         if (publickey != NULL) {
80                 for (uids = publickey->uids; uids != NULL; uids = uids->next) {
81                         sigs = keysigs(sigs, uids->sigs);
82                 }
83                 if (revoked != NULL) {
84                         *revoked = (publickey->revocations != NULL);
85                 }
86                 free_publickey(publickey);
87         }
88
89         return sigs;
90 }
91 #endif
92
93 /**
94  *      cached_getkeysigs - Gets the signatures on a key.
95  *      @keyid: The key we want the signatures for.
96  *      
97  *      This function gets the signatures on a key. It's the same as the
98  *      getkeysigs function above except we use the hash module to cache the
99  *      data so if we need it again it's already loaded.
100  */
101 struct ll *cached_getkeysigs(uint64_t keyid)
102 {
103         struct stats_key *key = NULL;
104         struct stats_key *signedkey = NULL;
105         struct ll        *cursig = NULL;
106         bool              revoked = false;
107
108         if (keyid == 0)  {
109                 return NULL;
110         }
111
112         key = createandaddtohash(keyid);
113
114         if (key->gotsigs == false) {
115                 key->sigs = getkeysigs(key->keyid, &revoked);
116                 key->revoked = revoked;
117                 for (cursig = key->sigs; cursig != NULL;
118                                 cursig = cursig->next) {
119                         signedkey = (struct stats_key *) cursig->object;
120                         signedkey->signs = lladd(signedkey->signs, key);
121                 }
122                 key->gotsigs = true;
123         }
124
125         return key->sigs;
126 }
127
128 #ifdef NEED_GETFULLKEYID
129 /**
130  *      getfullkeyid - Maps a 32bit key id to a 64bit one.
131  *      @keyid: The 32bit keyid.
132  *
133  *      This function maps a 32bit key id to the full 64bit one. It returns the
134  *      full keyid. If the key isn't found a keyid of 0 is returned.
135  */
136 uint64_t getfullkeyid(uint64_t keyid)
137 {
138         struct openpgp_publickey *publickey = NULL;
139
140         if (keyid < 0x100000000LL) {
141                 fetch_key(keyid, &publickey, false);
142                 if (publickey != NULL) {
143                         keyid = get_keyid(publickey);
144                         free_publickey(publickey);
145                         publickey = NULL;
146                 } else {
147                         keyid = 0;
148                 }
149         }
150         
151         return keyid;
152 }
153 #endif
154
155 #ifdef NEED_UPDATEKEYS
156 /**
157  *      update_keys - Takes a list of public keys and updates them in the DB.
158  *      @keys: The keys to update in the DB.
159  *      @sendsync: Should we send a sync mail to our peers.
160  *
161  *      Takes a list of keys and adds them to the database, merging them with
162  *      the key in the database if it's already present there. The key list is
163  *      update to contain the minimum set of updates required to get from what
164  *      we had before to what we have now (ie the set of data that was added to
165  *      the DB). Returns the number of entirely new keys added.
166  */
167 int update_keys(struct openpgp_publickey **keys, bool sendsync)
168 {
169         struct openpgp_publickey *curkey = NULL;
170         struct openpgp_publickey *oldkey = NULL;
171         struct openpgp_publickey *prev = NULL;
172         int newkeys = 0;
173         bool intrans;
174
175         for (curkey = *keys; curkey != NULL; curkey = curkey->next) {
176                 intrans = starttrans();
177                 logthing(LOGTHING_INFO,
178                         "Fetching key 0x%llX, result: %d",
179                         get_keyid(curkey),
180                         fetch_key(get_keyid(curkey), &oldkey, intrans));
181
182                 /*
183                  * If we already have the key stored in the DB then merge it
184                  * with the new one that's been supplied. Otherwise the key
185                  * we've just got is the one that goes in the DB and also the
186                  * one that we send out.
187                  */
188                 if (oldkey != NULL) {
189                         merge_keys(oldkey, curkey);
190                         if (curkey->revocations == NULL &&
191                                         curkey->uids == NULL &&
192                                         curkey->subkeys == NULL) {
193                                 if (prev == NULL) {
194                                         *keys = curkey->next;
195                                 } else {
196                                         prev->next = curkey->next;
197                                         curkey->next = NULL;
198                                         free_publickey(curkey);
199                                         curkey = prev;
200                                 }
201                         } else {
202                                 prev = curkey;
203                                 logthing(LOGTHING_INFO,
204                                         "Merged key; storing updated key.");
205                                 store_key(oldkey, intrans, true);
206                         }
207                         free_publickey(oldkey);
208                         oldkey = NULL;
209                 } else {
210                         logthing(LOGTHING_INFO,
211                                 "Storing completely new key.");
212                         store_key(curkey, intrans, false);
213                         newkeys++;
214                 }
215                 endtrans();
216                 intrans = false;
217         }
218
219         if (sendsync && keys != NULL) {
220                 sendkeysync(keys);
221         }
222
223         return newkeys;
224 }
225 #endif /* NEED_UPDATEKEYS */