| | 1841 | static int pgp_gpgme_extract_keys (gpgme_data_t keydata, FILE** fp) |
| | 1842 | { |
| | 1843 | /* there's no side-effect free way to view key data in GPGME, |
| | 1844 | * so we import the key into a temporary keyring */ |
| | 1845 | char tmpdir[_POSIX_PATH_MAX]; |
| | 1846 | char tmpfile[_POSIX_PATH_MAX]; |
| | 1847 | gpgme_ctx_t tmpctx; |
| | 1848 | gpgme_error_t err; |
| | 1849 | gpgme_engine_info_t engineinfo; |
| | 1850 | gpgme_key_t key; |
| | 1851 | gpgme_user_id_t uid; |
| | 1852 | gpgme_subkey_t subkey; |
| | 1853 | const char* shortid; |
| | 1854 | int len; |
| | 1855 | char date[STRING]; |
| | 1856 | int more; |
| | 1857 | int rc = -1; |
| | 1858 | |
| | 1859 | snprintf (tmpdir, sizeof(tmpdir), "%s/mutt-gpgme-XXXXXX", Tempdir); |
| | 1860 | if (!mkdtemp (tmpdir)) |
| | 1861 | { |
| | 1862 | dprint (1, (debugfile, "Error creating temporary GPGME home\n")); |
| | 1863 | return rc; |
| | 1864 | } |
| | 1865 | |
| | 1866 | if ((err = gpgme_new (&tmpctx)) != GPG_ERR_NO_ERROR) |
| | 1867 | { |
| | 1868 | dprint (1, (debugfile, "Error creating GPGME context\n")); |
| | 1869 | goto err_tmpdir; |
| | 1870 | } |
| | 1871 | |
| | 1872 | engineinfo = gpgme_ctx_get_engine_info (tmpctx); |
| | 1873 | while (engineinfo && engineinfo->protocol != GPGME_PROTOCOL_OpenPGP) |
| | 1874 | engineinfo = engineinfo->next; |
| | 1875 | if (!engineinfo) |
| | 1876 | { |
| | 1877 | dprint (1, (debugfile, "Error finding GPGME PGP engine\n")); |
| | 1878 | goto err_ctx; |
| | 1879 | } |
| | 1880 | |
| | 1881 | err = gpgme_ctx_set_engine_info (tmpctx, GPGME_PROTOCOL_OpenPGP, |
| | 1882 | engineinfo->file_name, tmpdir); |
| | 1883 | if (err != GPG_ERR_NO_ERROR) |
| | 1884 | { |
| | 1885 | dprint (1, (debugfile, "Error setting GPGME context home\n")); |
| | 1886 | goto err_ctx; |
| | 1887 | } |
| | 1888 | |
| | 1889 | if ((err = gpgme_op_import (tmpctx, keydata)) != GPG_ERR_NO_ERROR) |
| | 1890 | { |
| | 1891 | dprint (1, (debugfile, "Error importing key\n")); |
| | 1892 | goto err_ctx; |
| | 1893 | } |
| | 1894 | |
| | 1895 | mutt_mktemp (tmpfile); |
| | 1896 | *fp = safe_fopen (tmpfile, "w+"); |
| | 1897 | if (!*fp) |
| | 1898 | { |
| | 1899 | mutt_perror (tmpfile); |
| | 1900 | goto err_ctx; |
| | 1901 | } |
| | 1902 | unlink (tmpfile); |
| | 1903 | |
| | 1904 | err = gpgme_op_keylist_start (tmpctx, NULL, 0); |
| | 1905 | while (!err) |
| | 1906 | { |
| | 1907 | if ((err = gpgme_op_keylist_next (tmpctx, &key))) |
| | 1908 | break; |
| | 1909 | uid = key->uids; |
| | 1910 | subkey = key->subkeys; |
| | 1911 | more = 0; |
| | 1912 | while (subkey) |
| | 1913 | { |
| | 1914 | shortid = subkey->keyid; |
| | 1915 | len = mutt_strlen (subkey->keyid); |
| | 1916 | if (len > 8) |
| | 1917 | shortid += len - 8; |
| | 1918 | strftime (date, sizeof (date), "%Y-%m-%d", localtime (&subkey->timestamp)); |
| | 1919 | |
| | 1920 | if (!more) |
| | 1921 | fprintf (*fp, "%s %5.5s %d/%8s %s %s\n", more ? "sub" : "pub", |
| | 1922 | gpgme_pubkey_algo_name (subkey->pubkey_algo), subkey->length, |
| | 1923 | shortid, date, uid->uid); |
| | 1924 | else |
| | 1925 | fprintf (*fp, "%s %5.5s %d/%8s %s\n", more ? "sub" : "pub", |
| | 1926 | gpgme_pubkey_algo_name (subkey->pubkey_algo), subkey->length, |
| | 1927 | shortid, date); |
| | 1928 | subkey = subkey->next; |
| | 1929 | more = 1; |
| | 1930 | } |
| | 1931 | gpgme_key_release (key); |
| | 1932 | } |
| | 1933 | if (gpg_err_code (err) != GPG_ERR_EOF) |
| | 1934 | { |
| | 1935 | dprint (1, (debugfile, "Error listing keys\n")); |
| | 1936 | goto err_fp; |
| | 1937 | } |
| | 1938 | |
| | 1939 | rc = 0; |
| | 1940 | |
| | 1941 | err_fp: |
| | 1942 | if (rc) |
| | 1943 | { |
| | 1944 | fclose (*fp); |
| | 1945 | *fp = NULL; |
| | 1946 | } |
| | 1947 | err_ctx: |
| | 1948 | gpgme_release (tmpctx); |
| | 1949 | err_tmpdir: |
| | 1950 | mutt_rmtree (tmpdir); |
| | 1951 | |
| | 1952 | return rc; |
| | 1953 | } |