~psic4t/qcard

3e0936d60affcb053f3ac0e77cf66f5087019971 — psic4t 4 months ago a443635
add mutt compatibility
6 files changed, 69 insertions(+), 53 deletions(-)

M README.md
M defines.go
M helpers.go
M main.go
M parse.go
M qcard
M README.md => README.md +25 -15
@@ 2,7 2,7 @@

qcard is a CLI addressbook application for CardDAV servers written in Go. In
contrast to other tools it does not cache anything. It can fetch multiple
servers / addressbooks in parallel which makes it quite fast.
servers / addressbooks in parallel what makes it quite fast.

Its main purpose is displaying addressbook data. Nevertheless it supports basic
creation and editing of entries.


@@ 59,22 59,22 @@ This searches for contacts containing "doe" in all addressbooks:
    
    qcard -s doe

The DetailThreshold parameter in the configuration file determines when all contact details are shown for a given numer of search results. For instance, on DetailTreshold = 3 you get all details if 3 or less contacts are found for the searchword "doe".
The DetailThreshold parameter in the configuration file determines when all contact details are shown for a given numer 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
* **n:** Note
* **M:** phoneCell
* **P:** phoneHome
* **p:** phoneWork
* **E:** emailHome
* **e:** emailWork
* **A:** addressHome
* **a:** addressWork
* **O:** Organisation
* **B:** Birthday
* **T:** Title
* **n:** Note

### Add new contact



@@ 89,12 89,22 @@ Just combine the parameters from above like you wish.
This shows searches for "doe" in addressbook 2 and prints the corresponding filenames
("fobarxyz.vcf"):

    qcal -a 2 -s doe -f
    qcard -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:

    qcal -c 2 -edit foobarxyz.vcf
    qcard -c 2 -edit foobarxyz.vcf

## Integrations

### neomutt / other cli mail tools

To use qcard as your addressbook in neomutt, put the following in your neomuttrc:

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


## About

M defines.go => defines.go +2 -1
@@ 16,6 16,7 @@ var timezone, _ = time.Now().Zone()
var xmlContent []byte
var showDetails bool
var showFilename bool
var showEmailOnly *bool
var displayFlag bool
var toFile bool
var filter string


@@ 26,7 27,7 @@ var colorBlock string = "|"
var contactsSlice []contactStruct
var Colors = [10]string{"\033[0;31m", "\033[0;32m", "\033[1;33m", "\033[1;34m", "\033[1;35m", "\033[1;36m", "\033[1;37m", "\033[1;38m", "\033[1;39m", "\033[1;40m"}
var showColor bool = true
var qcardversion string = "0.5.0"
var qcardversion string = "0.6.0"

const (
	ConfigDir  = ".config/qcard"

M helpers.go => helpers.go +35 -35
@@ 117,61 117,64 @@ func splitAfter(s string, re *regexp.Regexp) (r []string) {
}

func (e contactStruct) fancyOutput() {
	if showColor {
		fmt.Print(e.Color + colorBlock + ColDefault + ` `)
	}
	fmt.Println(e.fullName)
	//fmt.Println(e.name)
	//fmt.Printf(`%5s`, ` `)
	//fmt.Println(` M: ` + e.phoneCell)
	if *showEmailOnly {
		showDetails = false

		if e.emailHome != "" {
			fmt.Printf("%s\t%s\tHOME\n", e.emailHome, e.fullName)
		}
		if e.emailWork != "" {
			fmt.Printf("%s\t%s\tWORK\n", e.emailWork, e.fullName)
		}
	} else {
		if showColor {
			fmt.Print(e.Color + colorBlock + ColDefault + ` `)
		}
		fmt.Println(e.fullName)
	}

	if showDetails {
		if e.title != "" {
			fmt.Printf(`%2s`, ` `)
			fmt.Println(`T: ` + e.title)
			fmt.Println(`  T: ` + e.title)
		}
		if e.organisation != "" {
			fmt.Printf(`%2s`, ` `)
			fmt.Println(`O: ` + e.organisation)
			fmt.Println(`  O: ` + e.organisation)
		}
		if e.phoneCell != "" {
			fmt.Printf(`%2s`, ` `)
			fmt.Println(`M: ` + e.phoneCell)
			//fmt.Printf(`%2s`, ` `)
			//fmt.Printf("%2s%s\n", " ", "M: "+e.phoneCell)
			fmt.Println("  M: " + e.phoneCell)
			//fmt.Println(`M: ` + e.phoneCell)
		}
		if e.phoneHome != "" {
			fmt.Printf(`%2s`, ` `)
			fmt.Println(`P: ` + e.phoneHome)
			fmt.Println(`  P: ` + e.phoneHome)
		}
		if e.phoneWork != "" {
			fmt.Println(`  p: ` + e.phoneWork)
		}
		if e.emailHome != "" {
			fmt.Printf(`%2s`, ` `)
			fmt.Println(`E: ` + e.emailHome)
			fmt.Println(`  E: ` + e.emailHome)
		}
		if e.emailWork != "" {
			fmt.Printf(`%2s`, ` `)
			fmt.Println(`e: ` + e.emailWork)
			fmt.Println(`  e: ` + e.emailWork)
		}
		if e.addressHome != "" {
			fmt.Printf(`%2s`, ` `)
			fmt.Println(`A: ` + e.addressHome)
			fmt.Println(`  A: ` + e.addressHome)
		}
		if e.addressWork != "" {
			fmt.Printf(`%2s`, ` `)
			fmt.Println(`a: ` + e.addressWork)
		}
		if e.phoneWork != "" {
			fmt.Printf(`%2s`, ` `)
			fmt.Println(`p: ` + e.phoneWork)
			fmt.Println(`  a: ` + e.addressWork)
		}
		if e.birthday != "" {
			fmt.Printf(`%2s`, ` `)
			fmt.Println(`B: ` + e.birthday)
			fmt.Println(`  B: ` + e.birthday)
		}
		if e.name != "" {
			fmt.Printf(`%2s`, ` `)
			fmt.Println(`N: ` + e.name)
			fmt.Println(`  N: ` + e.name)
		}
		if e.note != "" {
			fmt.Printf(`%2s`, ` `)
			fmt.Println(`n: ` + e.note)
			fmt.Println(`  n: ` + e.note)
		}
	}



@@ 187,11 190,8 @@ func (e contactStruct) vcfOutput() {
	fmt.Println(`Contact
=======`)
	//fmt.Printf(`Summary:%6s`, ` `)
	//fmt.Print(e.Summary)
	fmt.Printf(`Full Name:%2s`+e.fullName, ` `)
	fmt.Println(``)
	fmt.Printf(`Cell:%5s`+e.phoneCell, ` `)
	fmt.Println(``)
	fmt.Printf("Full Name:\t%s\n", e.fullName)
	fmt.Printf("Cell:\t\t%s\n", e.phoneCell)
}

func genUUID() (uuid string) {

M main.go => main.go +5 -0
@@ 91,6 91,10 @@ func showAddresses(abNo int) {
		showDetails = true
	}

	if *showEmailOnly {
		fmt.Println("Searching...")
	}

	for _, e := range contactsSlice {
		e.fancyOutput() // pretty print
	}


@@ 213,6 217,7 @@ func main() {
	contactDump := flag.String("d", "", "Dump raw contact data. Get filename with \"-f\" and use with \"-a\"")
	contactEdit := flag.String("edit", "", "Edit + upload contact data. Get filename with \"-f\" and use with \"-a\"")
	contactNew := flag.String("n", "", "Add a new contact. Check README.md for syntax")
	showEmailOnly = flag.Bool("emailonly", false, "Show only email addresses and names without further formatting (for CLI mail tools like mutt)")
	flag.Parse()
	flagset := make(map[string]bool) // map for flag.Visit. get bools to determine set flags
	flag.Visit(func(f *flag.Flag) { flagset[f.Name] = true })

M parse.go => parse.go +2 -2
@@ 43,9 43,9 @@ func parseContactPhoneWork(contactData *string) string {
}

func parseContactEmailHome(contactData *string) string {
	re, _ := regexp.Compile(`(?i)EMAIL;TYPE=HOME:.*?\n`)
	re, _ := regexp.Compile(`(?i)EMAIL(;TYPE=(HOME|INTERNET))?:.*?\n`)
	result := re.FindString(*contactData)
	return trimField(result, "(?i)EMAIL;TYPE=HOME:")
	return trimField(result, "(?i)EMAIL(;TYPE=(HOME|INTERNET))?:")
}

func parseContactEmailWork(contactData *string) string {

M qcard => qcard +0 -0