Could someone volunteer to roll the updated vCard import/export plug-ins into the appropriate Gramps branch?
The built-in vcard import/export gramplets were forked and enhanced to support version 1, 2, 3, and 4 – because most smart phones import/export version 2.1 and the built-in importer only recognized v3 .vcf files.
This enhancement did not add support for any new chunks. It just expanded the version coverage for more compatibility. The updates were published in March as addons to facilitate testing with the new Sniffer functionality. But I never noticed how to run those tests. (I think that testing opportunity just slipped away.)
I agree that it out to be rolled into the core… but I am very uncomfortable touching core. I can experiment with validating the plugin registration in the addon system. But not the core.
v5.2+ .tgz file available (If you’d rather not use the Addon Manager.)
https://github.com/emyoulation/CuratedGrampsPlugins/tree/main/gramps61/download
Just updated the README.md:
vcardenhanced — Multi-version vCard Import/Export for Gramps
Addon type: Fork-and-Hide workaround (GEPS 048, Workaround A)
vCard versions supported: 1.0, 2.1, 3.0, 4.0
Status: Experimental / proof-of-concept
vCard
.vcf addons
Plug-in Types:Importer /
Export
What this addon does
Replaces the built-in Gramps vCard importer and exporter with dialect-aware versions that handle vCard versions 1.0, 2.1, 3.0, and 4.0. Unhandled vCard properties are preserved (not silently dropped) as Person attributes of type vCard <version> source. A Variant Call Format (VCF) DNA file is detected on the first line and rejected with a clear alert rather than a confusing parse error. ORG vCards without Names are imported as Surnames.
The exporter adds a version selector to the export wizard (default: 3.0).
See vCard on wikipedia
Installation
-
Copy the four files into a single addon directory inside your Gramps user data folder, e.g.:
~/.gramps/gramps60/plugins/vcardenhanced/Files:
vcardenhanced.gpr.pyimportvcard_enh.pyexportvcard_enh.pyREADME.md
-
Restart Gramps.
-
The addon once attempted to automatically hide the built-in vCard plugins on startup so that the addon could supersede. (see Hurdle 4 below). The automatic hide did not work so you have to do this manually:
- Open Help → Plugin Manager Enhanced
- Search
vCard(the built-in import) andvCard(the built-in export) and set them to Hidden - The addon versions are named vCard (Enhanced — v1/2.1/3.0/4.0)
Fork/Hide Workaround — Hurdles Encountered
This addon is a structured experiment in the GEPS 048 “Workaround A:Fork-and-Hide” approach. The following problems were discovered during development and are documented here as input to the full GEPS 048 implementation.
Hurdle 1 — Duplicate plugin IDs cause silent failures
Problem: The built-in vCard plugins use the IDs im_vcard and ex_vcard. Reusing these IDs in an addon causes Gramps to raise a duplicate-plugin registration error. This error is not clearly reported to the user — depending on the Gramps version, the startup log either silently drops one of the registrations or produces a traceback that doesn’t identify which plugin caused it.
Workaround: This addon uses distinct IDs: im_vcard_f (‘f’ for “fork”) and ex_vcard_f. This means both the built-in and the enhanced versions are registered simultaneously, creating a duplicate-entry problem in the import/export dialog (see Hurdle 4).
GEPS 048 implication: The framework needs a first-class “supersedes” or “replaces” registration field so addon authors can explicitly declare that their plugin replaces a built-in, and the framework can handle deduplication automatically.
Hurdle 2 — Built-in .gpr.py is amalgamated; no standalone file to copy
Problem: The built-in importer and exporter plugins are registered in a shared gramps/plugins/lib/...gpr.py file (or similar amalgamated file) alongside many other plugins. There is no standalone vcard.gpr.py to simply copy and modify. An addon author who doesn’t know where to look has no obvious path to find the registration parameters needed to construct a fork.
Additional problem: If fname= in a .gpr.py points to a file that doesn’t exist, Gramps silently skips the plugin at startup with no user-visible error and no log message at the default log level. This makes typos in fname= very hard to diagnose.
Workaround: The addon’s .gpr.py was written from scratch, using the built-in plugin’s parameters as reference. The fname= values were verified by confirming that both .py files exist in the addon directory before testing.
GEPS 048 implication: The framework should emit a warning (at least
at DEBUG level) when a registered fname= cannot be found. Ideally,
the Plugin Manager UI would show “file missing” next to the plugin name.
Hurdle 3 — Import paths differ between core plugins and addons
Problem: Core Gramps plugins import from relative paths or from gramps.plugins.lib directly. Addon plugins live in the user data directory, outside the Gramps package tree, and must use fully qualified gramps.* import paths. Copying a core plugin file and adjusting only the registration is not sufficient — imports also need updating.
Additionally, the built-in importvcard.py uses OpenFileOrStdin without specifying encoding=, which works for core because it falls back to the system default. In the enhanced version, explicit encoding="utf-8", errors="replace" is necessary to handle multi-version input gracefully.
Workaround: This addon is self-contained — no shared modules from core are monkey-patched or subclassed. All imports use fully qualified Gramps package paths.
GEPS 048 implication: The fork-and-hide workaround guide (in GEPS 048’s Workaround A section) should include a checklist of import path differences as a known friction point.
Hurdle 4 — Hiding the built-in has no stable API
Problem: To eliminate the duplicate-entry problem in the import/export dialog (both built-in and enhanced showing up for .vcf files), the built-in plugins must be hidden. The .gpr.py includes a best-effort automatic hide using PluginRegister. However:
- The API for reading and writing the hidden-plugin set (
get_hidden_plugin_ids/save_hidden_plugin_ids) is not part of the documented Gramps plugin API and may not exist in all versions. - The hidden-plugin list is managed by Plugin Manager Enhanced, which stores it in a user config file. The attribute names on
PluginRegisterdiffer between Gramps versions. - If the automatic hide fails, it fails silently — there is no feedback to the user that manual hiding is required.
Workaround: The _auto_hide_upstream() function in .gpr.py tries two known attribute names (get_hidden_plugin_ids and _hidden) and swallows all exceptions. The README instructs users to hide manually if the automatic hide does not work.
GEPS 048 implication: A stable, version-independent API for hiding a plugin by ID is essential for any fork-and-hide approach to be reliable. This should be part of the core plugin registration system, not a side-effect dependency on Plugin Manager Enhanced.
Hurdle 5 — No “toggle active fork” UI in core
Problem: Once both the built-in and the enhanced plugin are registered, and one is hidden, there is no built-in Gramps UI for the user to toggle which one is active. This requires either Plugin Manager Enhanced (a separate addon) or manual config-file editing.
Workaround: The README documents the manual procedure. A future version of the exporter option box could include a “Restore built-in” button that calls the toggle pattern described in GEPS 048.
A vCard (.vcf) file stores contact information like a digital business card. It uses standardized text tags (or fields) to define personal and professional details.
The standard fields used in a .vcf file include:
Required / Core Fields
BEGIN:VCARD / END:VCARD: Every file must start and end with these markers.
VERSION: Specifies the vCard version (e.g., 2.1, 3.0, or 4.0).
N: Structured name (separated by semicolons: Last; First; Middle; Prefix; Suffix).
FN: Formatted Name (the display name, complete with prefixes/suffixes).
Contact Details
TEL: Telephone numbers (e.g., TEL;TYPE=CELL,VOICE).
EMAIL: Email addresses.
ADR: Physical address (Post Office, Extended, Street, City, State, Zip, Country).
Professional & Work Info
ORG: Organization or Company name.
TITLE: Job title or role within the company.
ROLE: The specific function or role of the person.
LOGO: URL or embedded image of the company logo.
Personal & Additional Data
BDAY: Birthday (formatted as YYYY-MM-DD).
URL: Websites or social media links.
PHOTO: Profile photo (can be a URL or a base64-encoded image).
NOTE: Free-form text for any extra details.
NICKNAME: Alternative names or aliases.
IMPP: Instant messaging and presence protocol addresses (e.g., SIP, XMPP).
RELATED: Other people related to this contact (e.g., TYPE=CO-WORKER or TYPE=SPOUSE).
KEY: Public encryption keys.
Additional fields
Geographical & Time Fields
GEO: Latitude and longitude coordinates (e.g., GEO:geo:37.386013,-122.082932).
TZ: The contact’s time zone (expressed as a text string or a UTC offset).
Metadata & System Fields
UID: A globally Unique Identifier for the specific contact.
REV: Revision date and time indicating when the contact card was last updated.
PRODID: The identifier of the software application that generated the vCard file.
KIND: Defines the type of entity the vCard represents (individual, group, org, or location).
CLIENTPIDMAP: Used in vCard 4.0 synchronization to map local IDs to global IDs.
Advanced Identity & Personalization (RFC 6474 / RFC 9554)
BIRTHPLACE: The geographical place or city where the individual was born.
DEATHPLACE: The location where the individual passed away.
DEATHDATE: The exact date of death.
ANNIVERSARY: The wedding or significant anniversary date.
GENDER: Gender identity (M for male, F for female, O for other, N for none, U for unknown).
X-GENDER: Gender identity (M for male, F for female, N/A, None, Unspecified).
GRAMGENDER: Grammatical gender settings for formatting text about the user.
PRONOUNS: Designated personal pronouns (e.g., he/him, they/them).
LANGUAGE: The contact’s preferred spoken/written language.
Media & Security Extensions
AUDIO: An embedded audio file or URI pointing to the correct pronunciation of the contact’s name.
FBURL: Free/Busy URL, pointing to a web page showing the contact’s calendar availability.
CALADRURI: Calendar address URI used to send meeting invitations to the contact.
CALURI: A direct link to the contact’s primary calendar.
SOCIALPROFILE: Officially introduced to formalize web and social media handle URIs.
Custom Fields (X- Prefix)
Applications and phone systems create non-standard, custom fields by prefixing them with X-. These are widely parsed across modern systems:
X-PHONETIC-FIRST-NAME / X-PHONETIC-LAST-NAME: Phonetic spellings for proper text-to-speech rendering.
X-SOCIALPROFILE: The legacy/vendor format for mapping Twitter, Facebook, or LinkedIn links.
X-ABRELATEDNAMES: Used heavily by Apple and Android to list custom relationships.
RELATED (a future enhancement)
In a .vcf (vCard) file, the RELATED property is used to specify a relationship between the contact and another entity.
The formatting rules and valid entries depend on whether you are defining the property value itself or the relationship TYPE parameter.
1. Valid Property Values
The value of the RELATED property is text by default, but it can also be a URI pointing directly to another digital identity or vCard.
- Text (Default): The actual name of the related person or entity.
- Example:
RELATED:Jane Doe
- Example:
- URI: A direct link, such as a
uuid:, amailto:email address, or a web link. You must declareVALUE=uri.- Example:
RELATED;VALUE=uri:urn:uuid:f81d4fae-7dec-11d0-a765-00a0c91e6bf6 - Example:
RELATED;VALUE=uri:mailto:jane.doe@example.com
- Example:
2. Valid TYPE Parameters (Relationship Categories)
To specify how the contact is related to the person or entity, the official vCard 4.0 specification (RFC 6350) and IANA registry allow a standardized list of lowercase values for the TYPE= parameter:
Family & Personal Relationships
child– Offspringparent– Mother, father, or legal guardiansibling– Brother or sisterspouse– Husband, wife, or legal partnerkin– General relative or family membersweetheart/crush/date– Romantic interests
Professional & Organizational Relationships
colleague– Someone in the same field or professioncoworker– Someone working at the same companyagent– Someone who can act on behalf of the contactmanager– A supervisor or boss
Social & Living Arrangements
friend– A personal friendacquaintance– A casual social contactneighbor– A person living nearbycoresident– A roommate or housemate
Other Specialized Standard Types
contact– A general related connectionemergency– A primary contact for health or safety emergenciesme– Points to another vCard or online profile belonging to the exact same person
Code Examples in Action
Example 1: Plain text spouse relationship
RELATED;TYPE=spouse:John Doe
Example 2: Multiple comma-separated relationship types linking to an email
RELATED;TYPE=friend,coworker;VALUE=uri:mailto:alex@work.com
vCard Version Notes
| Version | Standard | Notes |
|---|---|---|
| 1.0 | Versit 1995 | Rarely encountered; tab-folding; QUOTED-PRINTABLE common |
| 2.1 | Versit 1996 | Widely supported; used by Outlook, older phones; QP encoding |
| 3.0 | RFC 2426 (1998) | Gramps default; space-folding; UTF-8 |
| 4.0 | RFC 6350 (2011) | Modern standard; GENDER, ANNIVERSARY, CLIENTPIDMAP |
Properties not handled by the importer are stored as a vCard <n> source Person attribute (where <n> is the detected version), so data is preserved for manual review or future processing.
Variant Call Format (DNA) Detection
.vcf is shared between vCard (contact data) and Variant Call Format (genomic/DNA data). VCF DNA files begin with ##fileformat=VCFv. This addon reads the first 32 bytes of any .vcf file before attempting to parse it as a vCard. If the DNA magic bytes are detected, import is aborted and an alert is shown.
Credits
- Original vCard import/export: Martin Hawlisch, Donald N. Allingham, Brian G. Matherly, Jakim Friant, Michiel D. Nauta (Gramps project)
- Export option box pattern: Kari Kujansuu (isotammiexportxml)
- Enhanced multi-version fork: Claude (Anthropic, claude-sonnet-4-6), GEPS 048 experiment, 2026-03-21
- Human author / tester: Brian McCullough (emyoulation), Gramps project