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