feat(catalog): scan Thunderbird address books and Gloda contacts

Add oo catalog scan-thunderbird for *.mab and global-messages-db.sqlite,
with noise filters and work-domain heuristics (e.g. wheregroup.com).
This commit is contained in:
2026-07-26 11:27:57 +01:00
parent c32e4dd611
commit 502b373e37
7 changed files with 448 additions and 16 deletions
+37 -7
View File
@@ -18,20 +18,21 @@ trees, match against live OnlyOffice CRM, then create/update only rows with
approve: true.
Typical flow:
oo catalog scan-contacts --root PATH -o /tmp/contacts.yaml
oo catalog scan-projects --root ~/projects -o /tmp/projects.yaml
oo catalog merge -i /tmp/contacts.yaml -i /tmp/projects.yaml -o docs/catalog/clients-contacts.yaml
oo catalog match -i docs/catalog/clients-contacts.yaml -o docs/catalog/clients-contacts.yaml
oo catalog scan-contacts --root PATH -O /tmp/contacts.yaml
oo catalog scan-projects --root ~/projects -O /tmp/projects.yaml
oo catalog scan-thunderbird --root PATH -O /tmp/thunderbird.yaml
oo catalog merge -i /tmp/contacts.yaml -i /tmp/projects.yaml -i /tmp/thunderbird.yaml -O docs/catalog/clients-contacts.yaml
oo catalog match -i docs/catalog/clients-contacts.yaml
# edit approve: true on pilot rows
oo catalog apply --dry-run -i docs/catalog/clients-contacts.yaml
oo catalog apply --apply -i docs/catalog/clients-contacts.yaml -o docs/catalog/clients-contacts.yaml
`,
}
oo catalog apply --apply -i docs/catalog/clients-contacts.yaml
`}
func init() {
rootCmd.AddCommand(catalogCmd)
catalogCmd.AddCommand(catalogScanContactsCmd())
catalogCmd.AddCommand(catalogScanProjectsCmd())
catalogCmd.AddCommand(catalogScanThunderbirdCmd())
catalogCmd.AddCommand(catalogMergeCmd())
catalogCmd.AddCommand(catalogMatchCmd())
catalogCmd.AddCommand(catalogApplyCmd())
@@ -85,6 +86,35 @@ func catalogScanProjectsCmd() *cobra.Command {
return cmd
}
func catalogScanThunderbirdCmd() *cobra.Command {
var outPath string
cmd := &cobra.Command{
Use: "scan-thunderbird",
Short: "Thunderbird profiles: abook/history.mab + Gloda SQLite contacts",
Long: `Walk a directory tree for Thunderbird profiles and extract person rows from:
- *.mab address books (email regex)
- global-messages-db.sqlite Gloda contacts/identities
Noisy senders (noreply, Amazon marketplace, GitHub reply, …) are skipped.
Default zone is private; known work domains (e.g. wheregroup.com) get zone=warm role=work.`,
RunE: func(cmd *cobra.Command, args []string) error {
root, _ := cmd.Flags().GetString("root")
if root == "" {
return fmt.Errorf("--root is required")
}
doc, err := catalog.ScanThunderbirdRoot(root)
if err != nil {
return err
}
return writeCatalog(cmd, doc, outPath)
},
}
cmd.Flags().String("root", "", "Thunderbird profile or parent directory (local path)")
cmd.Flags().StringVarP(&outPath, "out", "O", "", "write YAML to this path")
_ = cmd.MarkFlagRequired("root")
return cmd
}
func catalogMergeCmd() *cobra.Command {
var inputs []string
var outPath string
+1 -1
View File
@@ -15,7 +15,7 @@
// oo crm cleanup
// oo mails accounts | folders | list | get | delete
// oo applications sync
// oo catalog scan-contacts | scan-projects | merge | match | apply
// oo catalog scan-contacts | scan-projects | scan-thunderbird | merge | match | apply
//
// Every list supports `--output/-o json|table` (table is the default).
//