emacs-orgmode@gnu.org archives
 help / color / mirror / code / Atom feed
From: Jean Louis <bugs@gnu.support>
To: dalanicolai <dalanicolai@gmail.com>
Cc: emacs-orgmode@gnu.org
Subject: Re: contact management in emacs
Date: Mon, 8 Mar 2021 01:51:32 +0300	[thread overview]
Message-ID: <YEVY9GVCoHcxF9K5@protected.rcdrun.com> (raw)
In-Reply-To: <CACJP=3kbUAEUnKiRJ1Xa3p1ic0ad0n0JQYPh9WGD_hTYd78hLw@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 2684 bytes --]

* dalanicolai <dalanicolai@gmail.com> [2021-02-27 23:53]:
> I think all packages fulfill your requirements. So I would say it depends
> on how many contacts you are managing. I have some experience with
> org-contacts, and I find it very convenient and straightforward. It is also
> very convenient to just use org-mode, i.e. a plain text file, for your
> contacts.

That may be convenient for friends or family, but is not a good idea
if such a contact database is to enlarge due to marketing actions.

People who collect leads and manage relations with many other people
must have straight way to manage contacts, and similar to well known
CRM systems such as SugarCRM or others. In fact contact management
could be managed by external program and database accessed through
Emacs. Though I do both with Emacs. And I like to access database from
shell as I do not use only Emacs as editor. As the database is
liberated from editor it allows access through any software or
programming language.

> Every contact is a headline and you can add any kind of property
> or tag etc. you want. Also anniversaries get added to the Agenda. You can
> very easily jump to the right contact, using imenu or swoop/swiper (I use
> `SPC j i ` in Spacemacs. So if you have less than say 300 contacts (I have
> really no clue about the number of contacts that will still work smoothly),
> then depending on how die-hard you are, I would recommend to start with
> org-contacs.

More important is how fast are contacts coming into the database. If
there are just 100 per year, then that will work well.

But marketing action of 23 hours have provided me like 1700 contacts,
so there would be no way that I ever keep up with text or hand
work. That requires automated insertion of contacts into the database,
and I use local database. Online lead capture is sent PGP encrypted by
email and emails are automatically processed and leads entered into
the local database. Placing contacts online is insecure IMHO, no
matter what is advertised about it.

> You can use org-vcard to import contacts, and org-vcard claims to
> support exports too but I did not test that yet.  Anyway, I think
> you won't loose much time with setting up org-contacts and from then
> you can slowly check out and study the other options.

I am attaching `rcd-vcard.el` that uses PostgreSQL database and my
schemas to export vCards that work nicely with
Android/LineageOS/Replicant devices. Package alone will not
work. Functions may be useful for some people to modify them as they
wish. If somebody wish to really install my system, I will be helpful
in private chat or email and guide person until it becomes functional.


[-- Attachment #2: rcd-vcard.el --]
[-- Type: text/plain, Size: 9384 bytes --]

;;; rcd-vcard.el --- RCD vCard functions  -*- lexical-binding: t; -*-

;; Copyright (C) 2016-2021 by Jean Louis

;; Author: Jean Louis <bugs@gnu.support>
;; Version: 0.1
;; Package-Requires: (rcd-utilities rcd-db-init rcd-db rcd-cf)
;; Keywords: 
;; URL: https://gnu.support/gnu-emacs/packages/rcd-vcard.html

;; This file is not part of GNU Emacs.

;; This program is free software: you can redistribute it and/or
;; modify it under the terms of the GNU General Public License as
;; published by the Free Software Foundation, either version 3 of the
;; License, or (at your option) any later version.
;; This program is distributed in the hope that it will be useful, but
;; WITHOUT ANY WARRANTY; without even the implied warranty of
;; General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.

;;; Commentary:

;; These are the RCD vCard functions
;; RCD is acronym for Reach, Connect, Deliver, my personal
;; principle and formula for Wealth.

;;; Change Log:

;;; Code:

(require 'rcd-utilities)
(require 'rcd-db-init)
(require 'rcd-db)
(require 'rcd-cf)

(defvar *rcd-vcard-version* "2.1")
(defvar *rcd-vcard-output* "~/tmp/rcd-vcards/")

(defun rcd-vcard-jabber (xmpp)
  (if (rcd-string-not-empty-p xmpp)
      (format "X-JABBER:%s\nX-JABBER;WORK:%s\n" xmpp xmpp)

(defun rcd-vcard-tel (tel &optional type)
  (if (rcd-string-not-empty-p tel)
      (let* ((type (or type "CELL"))
	     (type (upcase type)))
	(format "TEL;%s:%s\n" type tel))

(defun rcd-vcard-address (address1 city1 zip1 state1 country1 address2 city2 zip2 state2 country2)
    (princ "ADR;DOM;HOME;:")
    (princ city1)
    (princ ";")
    (princ country1)
    (princ "\n"))) ;; TODO

(defun rcd-vcard-phones (office mobile home other fax &optional other-2 other-3 other-4)
    (when office
      (princ (rcd-vcard-tel office "WORK")))
    (when mobile
      (princ (rcd-vcard-tel mobile "CELL")))
    (when home
      (princ (rcd-vcard-tel home "HOME")))
    (when other
      (princ (rcd-vcard-tel other "OTHER")))
    (when fax
      (princ (rcd-vcard-tel fax "FAX")))
    (when other-2
      (princ (rcd-vcard-tel other-2 "OTHER")))
    (when other-3
      (princ (rcd-vcard-tel other-3 "OTHER")))
    (when other-3
      (princ (rcd-vcard-tel other-3 "OTHER")))))

(defun rcd-vcard-title (title)
  (if (rcd-string-not-empty-p title)
      (format "TITLE:%s\n" title)

(defun rcd-vcard-organization (org &optional unit)
  (if (rcd-string-not-empty-p org)
      (let ((unit (or unit "")))
	(format "ORG:%s;%s\n" org unit))

;; (defun rcd-vcard-note (note)
;;   (if (rcd-string-not-empty-p note)
;;       (format "NOTE:ENCODING=BASE64;:%s\n" (base64-encode-string note))
;;     ""))

(defun rcd-vcard-note (id note)
    ;;     (princ (format "NOTE;ENCODING=BIT8;:Contact ID %s; " id))
    (princ (format "NOTE:Contact ID %s" id))
    (if (rcd-string-not-empty-p note)
	(princ (format "%s\n" "")) ;; place note instead of ""

(defun rcd-vcard-begin ()
  (format "BEGIN:VCARD\nVERSION:%s\n" *rcd-vcard-version*))

(defun rcd-vcard-end ()
  (format "END:VCARD\n"))

(defun rcd-vcard-email (email &optional type)
  (if (rcd-string-not-empty-p email)
      (let* ((type (or type "HOME"))
	     (type (upcase type)))
	(format "EMAIL;%s:%s\n" type email))

(defun rcd-vcard-url (url)
  (if (rcd-string-not-empty-p url)
      (format "URL:%s\n" url)

(defun rcd-vcard-birthday (bday)
  (if (rcd-string-not-empty-p bday)
      (format "BDAY:%s\n" bday)

(defun rcd-vcard-formatted-name (fn)
  (if (rcd-string-not-empty-p fn)
      (format "FN:%s\n" fn)

(defun rcd-vcard-name (last &optional first middle prefix suffix)
  (if (rcd-string-not-empty-p last)
      (let ((first (or first ""))
	    (middle (or middle ""))
	    (prefix (or prefix ""))
	    (suffix (or suffix "")))
	(format "N;CHARSET=UTF-8:%s;%s;%s;%s;%s;\n" last first middle prefix suffix))

(defun cf-contact-geo-location (id)
  (let* ((sql (format "SELECT locations_latitude, locations_longitude FROM locations WHERE locations_contacts = %s" id))
	 (geo (car (rcd-sql-list sql *cf*)))
	 (latitude (car geo))
	 (longitude (cadr geo)))
    (if geo
	(format "geo:%s,%s" latitude longitude)

(defun rcd-cf-contact-vcard-list (id)
  (let* ((hash (rcd-db-table-id-hash-values "people" id *cf*))
	 (prefix (gethash 'people_prefix hash))
	 (first (gethash 'people_firstname hash))
	 (middle (gethash 'people_middlenames hash))
	 (last (gethash 'people_lastname hash))
	 (suffix (gethash 'people_suffix hash))
	 (account (gethash 'people_account1 hash))
	 (company (gethash 'people_account2 hash))
	 (member (gethash 'people_account3 hash))
	 (title (gethash 'people_title hash))
	 (department (gethash 'people_department hash))
	 (birthday (gethash 'people_birthdate hash))
	 (office (gethash 'people_officephone hash))
	 (mobile (gethash 'people_mobilephone hash))
	 (home (gethash 'people_homephone hash))
	 (other (gethash 'people_otherphone hash))
	 (fax (gethash 'people_fax hash))
	 (email1 (gethash 'people_email1 hash))
	 (email2 (gethash 'people_email2 hash))
	 (email3 (gethash 'people_email3 hash))
	 (website (gethash 'people_website1 hash))
	 (blog (gethash 'people_website2 hash))
	 (address1 (gethash 'people_address1 hash))
	 (city1 (gethash 'people_city1 hash))
	 (zip1 (gethash 'people_zip1 hash))
	 (state1 (gethash 'people_state1 hash))
	 (country1 (gethash 'people_country1 hash))
	 (address2 (gethash 'people_address2 hash))
	 (city2 (gethash 'people_city2 hash))
	 (zip2 (gethash 'people_zip2 hash))
	 (state2 (gethash 'people_state2 hash))
	 (country2 (gethash 'people_country2 hash))
	 (note (gethash 'people_description hash))
	 (geo (cf-contact-geo-location id))
	 (geo (if geo (upcase geo) ""))
	 (contact (list prefix first middle last suffix account company member title department birthday office mobile home other fax email1 email2 email3 website blog address1 city1 zip1 state1 country1 address2 city2 zip2 state2 country2 note geo)))
    (mapcar 'string-blank-nil contact)))

(defun rcd-cf-contact-vcard (id)
  (let* ((contact (rcd-cf-contact-vcard-list id))
	 (full-name (cf-get-full-name id))
	 (vcard (rcd-vcard-begin))
	 (prefix (elt contact 0))
	 (first (elt contact 1))
	 (middle (elt contact 2))
	 (last (elt contact 3))
	 (suffix (elt contact 4))
	 (n (rcd-vcard-name last first middle prefix suffix))
	 (vcard (concat vcard n))
	 (fn (concat prefix " " first " " middle " " last " " suffix))
	 (fn (replace-regexp-in-string " +" " " fn))
	 (fn (rcd-vcard-formatted-name fn))
	 (vcard (concat vcard fn))
	 (account (elt contact 5))
	 (company (elt contact 6))
	 (member (elt contact 7))
	 (title (elt contact 8))
	 (department (elt contact 9))
	 (org (rcd-vcard-organization company department))
	 (vcard (concat vcard org))
	 (account-org (rcd-vcard-organization account "Account"))
	 (vcard (concat vcard account-org))
	 (member-org (rcd-vcard-organization member "Member"))
	 (vcard (concat vcard member-org))
	 (vcard (concat vcard (rcd-vcard-title title)))
	 (birthday (elt contact 10))
	 (vcard (concat vcard (rcd-vcard-birthday birthday)))
	 (office (elt contact 11))
	 (mobile (elt contact 12))
	 (home (elt contact 13))
	 (other (elt contact 14))
	 (fax (elt contact 15))
	 (phones (rcd-vcard-phones office mobile home other fax))
	 (vcard (concat vcard phones))
	 (email1 (elt contact 16))
	 (email2 (elt contact 17))
	 (email3 (elt contact 18))
	 (vcard (concat vcard (rcd-vcard-email email1)))
	 (vcard (concat vcard (rcd-vcard-email email2)))
	 (vcard (concat vcard (rcd-vcard-email email3)))
	 (website (elt contact 19))
	 (vcard (concat vcard (rcd-vcard-url website)))
	 (blog (elt contact 20))
	 (vcard (concat vcard (rcd-vcard-url blog)))
	 (address1 (elt contact 21))
	 (city1 (elt contact 22))
	 (zip1 (elt contact 23))
	 (state1 (elt contact 24))
	 (country1 (elt contact 25))
	 (address2 (elt contact 26))
	 (city2 (elt contact 27))
	 (zip2 (elt contact 28))
	 (state2 (elt contact 29))
	 (country2 (elt contact 30))
	 (address (rcd-vcard-address address1 city1 zip1 state1 country1 address2 city2 zip2 state2 country2))
	 (vcard (concat vcard address))
	 (note (elt contact 31))
	 (note (rcd-vcard-note id note))
	 (vcard (concat vcard note))
	 (geo (elt contact 32))
	 (geo (if geo (concat geo "\n") ""))
	 (vcard (concat vcard geo))
	 ;;(vcard (concat vcard note))
	 (vcard (concat vcard (rcd-vcard-end))))

(defun rcd-vcard-mobile-1 ()
  "Exports all vCards for mobile phone #1"
  (make-directory *rcd-vcard-output* t)
  (let* ((ids (rcd-sql "SELECT addressbookentries_people FROM addressbookentries" *cf*)))
       (dolist (id ids)
	 (princ (rcd-cf-contact-vcard id))))
     (concat *rcd-vcard-output* "rcd-people.vcf"))))

(defun cf-contact-vcard-export (id)
  "Export vCard for contact ID"
  (let ((vcard (rcd-cf-contact-vcard id))
	(file (format "%s%08d.vcf" *rcd-vcard-output* id)))
    (string-to-file-force vcard file)
    (message (concat "vCard exported to: " file))))

(provide 'rcd-vcard)
;;; rcd-vcard.el ends here

  reply	other threads:[~2021-03-07 22:54 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <mailman.47.1614445226.20994.emacs-orgmode@gnu.org>
2021-02-27 18:57 ` content management in emacs Ian Garmaise
2021-02-27 19:16   ` Martin Steffen
2021-02-27 20:11     ` Juan Manuel Macías
2021-03-01  5:17     ` Bob Newell
2021-02-28 10:39   ` Eric S Fraga
2021-03-07 22:31   ` Jean Louis
2021-03-07 22:38   ` Jean Louis
2021-02-27 20:52 ` contact " dalanicolai
2021-03-07 22:51   ` Jean Louis [this message]
2021-02-27 11:08 Alan Schmitt
2021-02-27 11:31 ` Martin Steffen
2021-02-27 13:20   ` andrés ramírez
2021-02-27 14:40     ` Eric S Fraga
2021-02-27 15:12       ` andrés ramírez
2021-02-28 10:21         ` Eric S Fraga
2021-02-27 15:14       ` Martin Steffen
2021-02-27 17:00   ` Dr. Arne Babenhauserheide
2021-02-27 16:53 ` Bob Newell
2021-02-28  9:06 ` Russell Adams
2021-02-28 11:09   ` Alan Schmitt
2021-03-03 14:40   ` TRS-80
2021-03-07 22:57   ` Jean Louis
2021-03-08 20:06     ` John Kitchin
2021-03-10  8:32       ` Jean Louis
2021-03-07 22:13 ` Jean Louis
2021-03-08  7:49   ` Alan Schmitt
2021-03-08  8:12     ` Jose E. Marchesi
2021-03-10  8:32       ` Jean Louis
2022-09-09 16:11 ` Sébastien Rey-Coyrehourcq
2022-09-10  5:46   ` Ihor Radchenko

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:

  List information: https://www.orgmode.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=YEVY9GVCoHcxF9K5@protected.rcdrun.com \
    --to=bugs@gnu.support \
    --cc=dalanicolai@gmail.com \
    --cc=emacs-orgmode@gnu.org \


* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).