# lbb

![logo](https://git.sr.ht/~ser/lbb/blob/master/quillbook.svg)

[![Build status](https://builds.sr.ht/~ser/lbb/.svg)](https://builds.sr.ht/~ser/lbb/)
★ ![Version](https://downloads.ser1.net/software/lbb/badges/latest_release.svg)
★ [Releases](https://downloads.ser1.net/software/lbb/)
★ [![AUR version](https://img.shields.io/aur/version/lbb)](https://aur.archlinux.org/packages/lbb)  
[![License](https://img.shields.io/aur/license/lbb)](https://git.sr.ht/~ser/lbb/tree/master/item/LICENSE)
★ [Changelog](https://git.sr.ht/~ser/lbb/tree/master/item/CHANGELOG.md)
★ [Issues](https://todo.sr.ht/~ser/lbb)
★ [Mailing list](https://lists.sr.ht/~ser/lbb)  
[![Go Report Card](https://goreportcard.com/badge/ser1.net/lbb)](https://goreportcard.com/report/ser1.net/lbb)
★ ![Code linting](https://downloads.ser1.net/software/lbb/badges/linting.svg)
★ ![Markdown linting](https://downloads.ser1.net/software/lbb/badges/doc_linting.svg)  
![Code complexity](https://downloads.ser1.net/software/lbb/badges/complexity.svg)
★ ![ABC metrics](https://downloads.ser1.net/software/lbb/badges/abc_score.svg)
★ ![Lines of code](https://downloads.ser1.net/software/lbb/badges/loc.svg)

lbb is a CLI address book application for CardDAV servers and vcard directries.
In contrast to other tools it does not cache anything. It can process multiple
remote servers & address books in parallel. It provides modes to allow
integration with email clients for providing address auto-complete.

Its main purpose is displaying address book data. It also supports
basic creation and editing of entries.

lbb was forked from [qcard](https://git.sr.ht/~psic4t/qcard), and diverges
significantly.

**Note** Version 0.10 changed the flags parsing library; now it's more conformant
to standard GNU flags, using double-dash `--` instead of Go flags' single dash.
Check `lbb help` for updated flags. You will have to update any scripts using lbb.

**Please do not submit vibe-coded patches.** I'll feel bad about you wasting time submitting
a patch, but I'll reject it. Thanks.

## Features

- Easy search for contacts.
- Concurrent fetching of multiple address books.
- Easy to use filters.
- Create, modify and delete contacts.
- Import VCF files.
- Display VCF files.
- Easy setup.
- Supports arbitrary number of remote and local accounts.

## Divergence from qcard

- Supports ICS directories, as made by vdirsyncer as well as caldav servers
- The original code contains bespoke vcf parsing based on regular expressions.
  There are performance and parsing issues, but the main issue is that many
  valid vcf files would not parse. This fork introduces a carefully considered
  vcf depedency which provides more correct parsing.
- Has a `-mailclient` argument which formats output in the format aerc expects, which avoids the necessity of reformatting the `-emailonly` output with awk.

This fork is 12x faster than the regexp version, and also 12x faster than khard.
Using hyperfine on a local directory containing 955 contact vcfs:

| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|:---|---:|---:|---:|---:|
| `khard email --parsable --remove-first-line` | 511.7 ± 6.3 | 504.5 | 520.9 | 23.22 ± 0.88 |
| `qcard -emailonly` | 520.9 ± 4.6 | 515.3 | 528.7 | 23.64 ± 0.87 |
| `lbb -emailonly` | 22.0 ± 0.8 | 20.3 | 24.3 | 1.00 |

## Installation

### From binaries

**Note:** binaries are currently broken, because I made the poor decision to try to use git on this one project (which started as a git fork), and doing even simple stuff like getting version numbers from the CI source is not simple with git. Until I figure this out, no binaries. Sorry.

Check the [Releases](https://downloads.ser1.net/software/lbb/) page for a
package for your OS/Architecture. If you don't find one, you can [send an email](~ser/lbb@todo.sr.ht) to the [mailing list](https://lists.sr.ht/~ser/lbb) and I'll add it.

### Using your Linux package manager

Binaries are provided (check the top of this document for the link) for a couple
of OS/architectures. I will add more upon request. There is no reason why lbb
should not compile for any target Go supports -- BSD, Darwin, Windows, ARM,
RISCV64, whatever. Ask, and ye shall receive.

- AUR (Arch): `yay -S lbb`
- Alpine (you'll need to have enabled the `testing` repository): `apk add lbb`
- RPM: download the relevant `rpm` binary from the
  [Releases](https://downloads.ser1.net/software/lbb/) page.
- Debian/Ubuntu derivatives: download the relevant `dpkg` binary from the
  [Releases](https://downloads.ser1.net/software/lbb/) page.
- Void: in progress

### Compiling from repository

No special tools are needed beyond Go >= 1.17. The project builds with a simple
`go build .`, and can be installed (into your `go env GOPATH` bin directory)
with `go install .`.

lbb compiles, but does not run, with tinygo 0.37.0. tinygo does not implement
`SliceOf()`, but while you'll get a lovely binary with no dependencies and 1/8th
the size of the Go build, it'll panic and core dump if you run it.

### Installing the Go Way

`go install -ldflags="-s -w" ser1.net/lbb@latest`

The ldflags merely strip down the binary so it's smaller; it's not necessary.

## Configuration

Run `lbb -init` to create a stub configuration, then edit the file and customize
it for your use case.

For additional address books just add a comma and new address book credentials
in curly brackets. The sample configuration contains both a CalDAV server
address book, and a local vcard directory book.

In the sample configuration are:

- An example for a CardDAV calendar with embedded username and password
- An example for a CardDAV calendar with embedded username and external command
  (secret service) to provide the password
- An example of a local directory full of `.vcf` contacts, as created by
  e.g. vdirsyncer. 

### External password command

Instead of putting your password in the config file you can specify an
external command to resolve your password. Put a line like this in your
addressbook config and leave the "Password" field empty:

```
"PasswordCmd":"rook show -np my-caldav-account"
```

## Usage

Common options:

```
lbb -h
```

### Displaying address books

This simply displays all contacts from all address books:

```
lbb
```

This only shows contacts from address book 0:

```
lbb -a 0
```

This displays all available address books with their numbers and colors:

```
lbb -l
```

This searches for contacts containing "doe" in all address books:

```
lbb -s doe
```

The `DetailThreshold` parameter in the configuration file determines when all
contact details are shown for a given number of search results. For instance, on
DetailThreshold = 3 you get all details if 3 or less contacts are found for the
searchword "doe".

Here's a list of all attributes:

- **M:** phoneCell
- **P:** phoneHome
- **p:** phoneWork
- **E:** emailHome
- **e:** emailWork
- **A:** addressHome
- **a:** addressWork
- **O:** organisation
- **B:** birthday
- **T:** title
- **R:** role
- **I:** nickname
- **n:** note

### Add new contact

This creates a contact for John Doe with a private mobile phone number and an email address in address book 1:

```
lbb -a 1 -n "John Doe M:+49 172 123123 E:jdoe@data.haus"
```

Just combine the parameters from above like you wish.

### Edit a contact

This shows searches for "doe" in address book 2 and prints the corresponding filenames
("fobarxyz.vcf"):

```
lbb -a 2 -s doe -f
```

This edits the selected vCard object in your $EDITOR (i.e. vim). When you
save-quit the modified object is automatically uploaded:

```
lbb -c 2 -edit foobarxyz.vcf
```

## Integrations

### neomutt

To use lbb as your address book in neomutt, put the following in your neomuttrc:

```
set query_command= "lbb -s '%s' -emailonly"
bind editor <Tab> complete-query
bind editor ^T complete
```

### aerc

Add or change `~/.config/aerc/aerc.conf`:

```
[compose]
address-book-cmd=lbb -mailclient -s "%s"
```

## Errata

### Why "lbb"

It stands for "Little Black Book," and was chosen mainly because it didn't have
"card" or "address" or "rolo" in the name, of which there are already a
plethora. It abbreviates to a nice, easily typed, 3-letter command, and wasn't
already taken[^1].

I'm not very creative with names, but I do require at least some tenuous link to
the actual purpose of the program. While "little black book" has connotations of
amorous intent, in _this_ case, it's just an address book.

### Why the hard fork?

~psic4t and I have different priorities. There's no acrimony; we simply agreed
to disagree on some key, irreconcilable points.

- ~psic4t -- quite reasonable -- prioritizes minimizing external dependencies.
  This meant that they did not want to use an external vcard library, which
  means maintaining a bespoke RFC6350 parser.
- Speed and correctness trumps other concerns for me. The bespoke parser in
  qcard did not meet my needs.

That's mainly it. There are other differences of opinion, and those could be
reconciled, but the decision to import a dependency or keep `go.mod` empty was
not.

### Why emersion/go-vcard?

I evaluated both [emersion/go-vcard](https://github.com/emersion/go-vcard) and
[wehmoen/vcard-go](https://github.com/wehmoen/vcard-go), looking both at
completeness and performance. The benchmark and tests parsed a directory of 955
vcf files.

|Benchmark           |Runs|Timing        |
|:-------------------|:---|:-------------|
|BenchmarkWehmoen-16 |28  |40392531 ns/op|
|BenchmarkEmersion-16|38  |30069657 ns/op|

In that set of files, 7 vcf files generated parse errors by Wehmoen, whereas
Emersion parsed all files.

Neither package had any significant external dependencies; Emersion has
literally none, and Wehmoen imports only `testify`, which is irrelevant in the
final linking.

## About

Questions? Ideas? File bugs and requests through the [issue
tracker](https://todo.sr.ht/~ser/lbb), or [email](mailto:~ser/lbb@todo.sr.ht)
questions and patches to the [mailing list](https://lists.sr.ht/~ser/lbb).

If you have cloned the repository, I use [legume](https://hg.sr.ht/~ser/legume)
for development issue tracking, as I do with all of my projects. To see behind
the curtain, in the repository run `legume` to see the tickets hidden in the
sourcecode.

## Credits

- The logo came from [publicdomainvectors.org](https://publicdomainvectors.org/en/free-clipart/Quill-and-a-book/70507.html) under CC0; unfortunately, there was no artist attribution, even in the source SVG metadata. To whomever created this: my thanks.
- ~psic4t on Sourcehut, for the original qcard code.
- The developers of [Jujutsu](https://jj-vcs.github.io/jj/latest/), without whom I'd have had to have far more contact with git than otherwise. They're doing good work trying to make git not a horrible, awful tool.
- @emersion on github, for go-vcard, which is solely responsible for the massive performance improvement, and the smaller but still significant correctness in vcard handling.

[^1] No guarantees; in fact, statistically, it's almost certain there's _some_ project out there called "lbb", but there was non in Arch's AUR, and that's good enough for me.
