+/* --- @key_fingerprint@ --- *
+ *
+ * Arguments: @key *k@ = the key to fingerprint
+ * @ghash *h@ = the hash to use
+ * @const key_filter *kf@ = filter to apply
+ *
+ * Returns: Nonzero if the key slightly matched the filter.
+ *
+ * Use: Updates the hash context with the key contents.
+ */
+
+static int abyname(const void *a, const void *b) {
+ key_attr *const *x = a, *const *y = b;
+ return (strcmp(SYM_NAME(*x), SYM_NAME(*y)));
+}
+
+int key_fingerprint(key *k, ghash *h, const key_filter *kf)
+{
+ dstr d = DSTR_INIT;
+ int rc = 0;
+ key_attr *a, **v;
+ size_t n, i, len;
+ octet b[2];
+ sym_iter ai;
+
+ if (!key_encode(&k->k, &d, kf))
+ goto done;
+ rc = 1;
+ GH_HASH(h, d.buf, d.len);
+ for (n = 0, sym_mkiter(&ai, &k->a); (a = sym_next(&ai)) != 0; n++);
+ if (n) {
+ v = xmalloc(n * sizeof(*v));
+ for (i = 0, sym_mkiter(&ai, &k->a); (a = sym_next(&ai)) != 0; i++)
+ v[i] = a;
+ qsort(v, n, sizeof(*v), abyname);
+ len = strlen(k->type); STORE8(b, len);
+ GH_HASH(h, b, 1); GH_HASH(h, k->type, len);
+ for (i = 0; i < n; i++) {
+ a = v[i];
+ len = strlen(SYM_NAME(a)); STORE8(b, len);
+ GH_HASH(h, b, 1); GH_HASH(h, SYM_NAME(a), len);
+ len = strlen(a->p); STORE16(b, len);
+ GH_HASH(h, b, 2); GH_HASH(h, a->p, len);
+ }
+ xfree(v);
+ }
+done:
+ dstr_destroy(&d);
+ return (rc);
+}
+