+ struct onak_db4_dbctx *privctx = (struct onak_db4_dbctx *) dbctx->priv;
+ struct openpgp_packet_list *packets = NULL;
+ struct openpgp_packet_list *list_end = NULL;
+ struct openpgp_publickey *next = NULL;
+ int ret = 0;
+ int i = 0;
+ struct buffer_ctx storebuf;
+ DBT key;
+ DBT data;
+ uint64_t keyid = 0;
+ uint32_t shortkeyid = 0;
+ struct openpgp_fingerprint *subkeyids = NULL;
+ char **uids = NULL;
+ char *primary = NULL;
+ struct ll *wordlist = NULL;
+ struct ll *curword = NULL;
+ bool deadlock = false;
+ struct skshash hash;
+ struct openpgp_fingerprint fingerprint;
+
+ if (get_keyid(publickey, &keyid) != ONAK_E_OK) {
+ logthing(LOGTHING_ERROR, "Couldn't find key ID for key.");
+ return 0;
+ }
+
+ if (get_fingerprint(publickey->publickey, &fingerprint) != ONAK_E_OK) {
+ logthing(LOGTHING_ERROR, "Couldn't find fingerprint for key.");
+ return 0;
+ }
+
+ if (!intrans) {
+ db4_starttrans(dbctx);
+ }
+
+ /*
+ * Delete the key if we already have it.
+ *
+ * TODO: Can we optimize this perhaps? Possibly when other data is
+ * involved as well? I suspect this is easiest and doesn't make a lot
+ * of difference though - the largest chunk of data is the keydata and
+ * it definitely needs updated.
+ */
+ if (update) {
+ deadlock = (db4_delete_key(dbctx, &fingerprint, true) == -1);
+ }
+
+ /*
+ * Convert the key to a flat set of binary data.
+ */
+ if (!deadlock) {
+ next = publickey->next;
+ publickey->next = NULL;
+ flatten_publickey(publickey, &packets, &list_end);
+ publickey->next = next;
+
+ storebuf.offset = 0;
+ storebuf.size = 8192;
+ storebuf.buffer = malloc(8192);
+
+ write_openpgp_stream(buffer_putchar, &storebuf, packets);
+
+ /*
+ * Now we have the key data store it in the DB; the fingerprint
+ * is the key.
+ */
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ key.data = fingerprint.fp;
+ key.size = fingerprint.length;
+ data.size = storebuf.offset;
+ data.data = storebuf.buffer;
+
+ ret = keydb_fp(privctx, &fingerprint)->put(
+ keydb_fp(privctx, &fingerprint),
+ privctx->txn,
+ &key,
+ &data,
+ 0); /* flags*/
+ if (ret != 0) {
+ logthing(LOGTHING_ERROR,
+ "Problem storing key: %s",
+ db_strerror(ret));
+ if (ret == DB_LOCK_DEADLOCK) {
+ deadlock = true;
+ }
+ }
+
+ free(storebuf.buffer);
+ storebuf.buffer = NULL;
+ storebuf.size = 0;
+ storebuf.offset = 0;
+
+ free_packet_list(packets);
+ packets = NULL;
+ }
+
+ /*
+ * Walk through our uids storing the words into the db with the
+ * fingerprint.
+ */
+ if (!deadlock) {
+ uids = keyuids(publickey, &primary);
+ }
+ if (uids != NULL) {
+ for (i = 0; ret == 0 && uids[i] != NULL; i++) {
+ wordlist = makewordlist(wordlist, uids[i]);
+ }
+
+ for (curword = wordlist; curword != NULL && !deadlock;
+ curword = curword->next) {
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ key.data = curword->object;
+ key.size = strlen(key.data);
+ data.data = fingerprint.fp;
+ data.size = fingerprint.length;
+
+ ret = privctx->worddb->put(privctx->worddb,
+ privctx->txn,
+ &key,
+ &data,
+ 0);
+ if (ret != 0) {
+ logthing(LOGTHING_ERROR,
+ "Problem storing word: %s",
+ db_strerror(ret));
+ if (ret == DB_LOCK_DEADLOCK) {
+ deadlock = true;
+ }
+ }
+ }
+
+ /*
+ * Free our UID and word lists.
+ */
+ llfree(wordlist, NULL);
+ for (i = 0; uids[i] != NULL; i++) {
+ free(uids[i]);
+ uids[i] = NULL;
+ }
+ free(uids);
+ uids = NULL;
+ }
+
+ /*
+ * Write the truncated 32 bit keyid so we can lookup the fingerprint
+ * for queries.
+ */
+ if (!deadlock) {
+ shortkeyid = keyid & 0xFFFFFFFF;
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ key.data = &shortkeyid;
+ key.size = sizeof(shortkeyid);
+ data.data = fingerprint.fp;
+ data.size = fingerprint.length;
+
+ ret = privctx->id32db->put(privctx->id32db,
+ privctx->txn,
+ &key,
+ &data,
+ 0);
+ if (ret != 0) {
+ logthing(LOGTHING_ERROR,
+ "Problem storing short keyid: %s",
+ db_strerror(ret));
+ if (ret == DB_LOCK_DEADLOCK) {
+ deadlock = true;
+ }
+ }
+ }
+
+ /*
+ * Write the 64 bit keyid so we can lookup the fingerprint for
+ * queries.
+ */
+ if (!deadlock) {
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ key.data = &keyid;
+ key.size = sizeof(keyid);
+ data.data = fingerprint.fp;
+ data.size = fingerprint.length;
+
+ ret = privctx->id64db->put(privctx->id64db,
+ privctx->txn,
+ &key,
+ &data,
+ 0);
+ if (ret != 0) {
+ logthing(LOGTHING_ERROR,
+ "Problem storing keyid: %s",
+ db_strerror(ret));
+ if (ret == DB_LOCK_DEADLOCK) {
+ deadlock = true;
+ }
+ }
+ }
+
+ if (!deadlock) {
+ subkeyids = keysubkeys(publickey);
+ i = 0;
+ while (subkeyids != NULL && subkeyids[i].length != 0) {
+ /* Store the subkey ID -> main key fp mapping */
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ key.data = subkeyids[i].fp;
+ key.size = subkeyids[i].length;
+ data.data = fingerprint.fp;
+ data.size = fingerprint.length;
+
+ ret = privctx->subkeydb->put(privctx->subkeydb,
+ privctx->txn,
+ &key,
+ &data,
+ 0);
+ if (ret != 0) {
+ logthing(LOGTHING_ERROR,
+ "Problem storing subkey keyid: %s",
+ db_strerror(ret));
+ if (ret == DB_LOCK_DEADLOCK) {
+ deadlock = true;
+ }
+ }
+
+ /* Store the 64 bit subkey ID -> main key fp mapping */
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+
+ keyid = fingerprint2keyid(&subkeyids[i]);
+ key.data = &keyid;
+ key.size = sizeof(keyid);
+ data.data = fingerprint.fp;
+ data.size = fingerprint.length;
+
+ ret = privctx->id64db->put(privctx->id64db,
+ privctx->txn,
+ &key,
+ &data,
+ 0);
+ if (ret != 0) {
+ logthing(LOGTHING_ERROR,
+ "Problem storing keyid: %s",
+ db_strerror(ret));
+ if (ret == DB_LOCK_DEADLOCK) {
+ deadlock = true;
+ }
+ }
+
+ /* Store the short subkey ID -> main key fp mapping */
+ shortkeyid = keyid & 0xFFFFFFFF;
+
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ key.data = &shortkeyid;
+ key.size = sizeof(shortkeyid);
+ data.data = fingerprint.fp;
+ data.size = fingerprint.length;
+
+ ret = privctx->id32db->put(privctx->id32db,
+ privctx->txn,
+ &key,
+ &data,
+ 0);
+ if (ret != 0) {
+ logthing(LOGTHING_ERROR,
+ "Problem storing short keyid: %s",
+ db_strerror(ret));
+ if (ret == DB_LOCK_DEADLOCK) {
+ deadlock = true;
+ }
+ }
+ i++;
+ }
+ if (subkeyids != NULL) {
+ free(subkeyids);
+ subkeyids = NULL;
+ }
+ }
+
+ if (!deadlock) {
+ get_skshash(publickey, &hash);
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ key.data = hash.hash;
+ key.size = sizeof(hash.hash);
+ data.data = fingerprint.fp;
+ data.size = fingerprint.length;