<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/assets/atom.xsl" type="text/xsl"?><feed
	xmlns="http://www.w3.org/2005/Atom"
	xmlns:thr="http://purl.org/syndication/thread/1.0"
	xml:lang="en-US"
	><title>Sacha Chua - tag - bbdb</title>
	<subtitle>Emacs, sketches, and life</subtitle>
	<link rel="self" type="application/atom+xml" href="https://sachachua.com/blog/tag/bbdb/feed/atom/index.xml" />
  <link rel="alternate" type="text/html" href="https://sachachua.com/blog/tag/bbdb" />
  <id>https://sachachua.com/blog/tag/bbdb/feed/atom/index.xml</id>
  <generator uri="https://11ty.dev">11ty</generator>
	<updated>2008-04-12T22:19:11Z</updated>
<entry>
		<title type="html">Wicked Cool Emacs: BBDB: Import CSV and vCard Files</title>
		<link rel="alternate" type="text/html" href="https://sachachua.com/blog/2008/04/wicked-cool-emacs-bbdb-import-csv-and-vcard-files/"/>
		<author><name><![CDATA[Sacha Chua]]></name></author>
		<updated>2008-04-13T02:19:49Z</updated>
    <published>2008-04-12T22:19:11Z</published>
    <category term="bbdb" />
<category term="emacs" />
<category term="wickedcoolemacs" />
		<id>https://sachachua.com/blog/?p=4834</id>
		<content type="html"><![CDATA[<p>If you have many contacts in another address book program, you can import them into BBDB. Two popular formats are comma-separated value files (CSV) and vCard files (VCF).</p>
<h3>Project XXX: Import a CSV File into BBDB</h3>
<p>To import a CSV file into BBDB, you will need csv.el from http://ulf.epplejasper.de/downloads/csv.el and lookout.el from http://ulf.epplejasper.de/downloads/lookout.el . Save both files to your ~/elisp directory. Make sure that your ~/elisp directory is in your load-path by adding the following line to your ~/.emacs:</p>
<pre>
(add-to-list 'load-path "~/elisp")
</pre>
<p>Export your contacts as an Outlook-style CSV file, then open the file in Emacs. After loading the following code, call M-x wicked/bbdb-import-csv-buffer to merge the CSV data into your address book. Emacs will try to update existing records based on the e-mail address or name provided, creating new records if necessary. After Emacs updates the records, the relevant records are displayed in the *BBDB* buffer. Here is the code to make that work:</p>
<p>ch6-bbdb-import-csv-buffer.el:</p>
<pre>
(require 'lookout)
(defconst wicked/lookout-bbdb-mapping-table-outlook
  '(("name" "Name")
    ("net" "E-mail Address")
    ("notes" "Notes")
    ("phones" "Mobile Phone"
     "Home Phone"
     "Home Phone 2"
     "Home Fax"
     "Business Phone"
     "Business Phone 2"
     "Business Fax"
     "Other Phone"
     "Other Fax")
    ("addr1" "Home Address")
    ("addr2" "Business Address")
    ("addr3" "Other Address")
    ("lastname" "Last Name")
    ("firstname" "First Name")
    ("job" "Job Title")
    ("company" "Company")
    ("otherfields" ""))
  "Field mappings for Outlook-type CSVs exported from Outlook, Gmail, LinkedIn, etc.")

(defun wicked/bbdb-import-csv-line (line)
  "Import LINE as a CSV, trying to merge it with existing records."
  (let* (record
	 (name  (lookout-bbdb-get-value "name" line))
	 (lastname (lookout-bbdb-get-value "lastname" line))
	 (firstname (lookout-bbdb-get-value "firstname" line))
	 (company   (lookout-bbdb-get-value "company" line))
         (job       (lookout-bbdb-get-value "job" line))
	 (net       (lookout-bbdb-get-value "net" line))
	 (addr1     (lookout-bbdb-get-value "addr1" line))
	 (addr2     (lookout-bbdb-get-value "addr2" line))
	 (addr3     (lookout-bbdb-get-value "addr3" line))
	 (phones    (lookout-bbdb-get-value "phones" line t)) ;; !
	 (notes     (lookout-bbdb-get-value "notes" line ))
         (j (concat job ", " company))
	 (otherfields (lookout-bbdb-get-value "otherfields" line t))
	 (addrs nil)
         name-search
	 (message ""))
    (if (string= company "") (setq company nil))
    (if (string= notes "") (setq notes nil))
    (if (string= name "") (setq name nil))
    (setq name-search (concat "^" (or name (concat firstname " " lastname))))
    (setq record (or (bbdb-search (bbdb-records) nil nil net)
		     (bbdb-search (bbdb-records) name-search)))
    (if record
	(progn
	  ;; Matching records found, update first matching record
	  (setq record (car record))
	  (let ((nets (bbdb-record-net record)))
	    (unless (member net nets)
	      ;; New e-mail address noticed, add to front of list
	      (add-to-list 'nets net)
	      (bbdb-record-set-net record nets)
	      (message "%s: New e-mail address noticed: %s"
		       (or name (concat firstname " " lastname)) net)))
	  ;; Check if job title and company have changed
	  (when (or job company)
	    (cond
	     ((string= (or (bbdb-record-company record) "") "")
	      (bbdb-record-set-company record j))
	     ((string= (bbdb-record-company record) j)
	      nil)
	     (t
	      (bbdb-record-set-notes
	       record
	       (concat "Noticed change from job title of "
		       (bbdb-record-company record)
		       "\n"
		       (bbdb-record-notes record)))
	      (message "%s: Noticed change from job title of %s to %s"
		       (or name (concat firstname " " lastname))
		       (bbdb-record-company record) j)
	      (bbdb-record-set-company record j)))))
      ;; No record found, create record
      (if (and addr1 (> (length addr1) 0))
	  (add-to-list 'addrs
		       (vector "Address 1" (list addr1) "" "" "" "")))
      (if (and addr2 (> (length addr2) 0))
	  (add-to-list 'addrs
		       (vector "Address 2" (list addr2) "" "" "" "")))
      (if (and addr3 (> (length addr3) 0))
	  (add-to-list 'addrs
		       (vector "Address 3" (list addr3) "" "" "" "")))
      (setq record (list
		    (wicked/lookout-bbdb-create-entry
		     (or name (concat firstname " " lastname))
		     (concat job ", " company)
		     net
		     addrs
		     phones
		     notes
		     otherfields))))
    record))
  
(defun wicked/lookout-bbdb-create-entry (name company net addrs phones notes
					      &amp;amp;optional otherfields)
  (when (or t (y-or-n-p (format "Add %s to bbdb? " name)))
    ;;(message "Adding record to bbdb: %s" name)
    (let ((record (bbdb-create-internal name company net addrs phones notes)))
      (unless record (error "Error creating bbdb record"))
      (mapcar (lambda (i)
		(let ((field (make-symbol (aref i 0)))
		      (value (aref i 1)))
		  (when (and value (not (string= "" value)))
		    (bbdb-insert-new-field record field value))))
	      otherfields)
      record)))

(defun wicked/bbdb-import-csv-buffer ()
  "Import this buffer."
  (interactive)
  (let ((lookout-bbdb-mapping-table
	 wicked/lookout-bbdb-mapping-table-outlook))
    (bbdb-display-records
     (mapcar
      'wicked/bbdb-import-csv-line
      (csv-parse-buffer t)))))
</pre>
<h3>Project xxx: Import a vCard File into BBDB</h3>
<p>To import a vCard file (VCF) into BBDB, you will need vcard.el from http://www.splode.com/~friedman/software/emacs-lisp/src/vcard.el and bbdb-vcard-import.el from http://www-pu.informatik.uni-tuebingen.de/users/crestani/downloads/bbdb-vcard-import.el . By default, these files allow you to import names and e-mail addresses from vCard files exported from various address book programs. Save vcard.el and bbdb-vcard-import.el to your ~/elisp directory and add the following lines to your ~/.emacs:</p>
<pre>
(add-to-list 'load-path "~/elisp")
(require 'bbdb-vcard-import)
</pre>
<p>Back up your ~/.bbdb file before calling M-x bbdb-vcard-import to import a file or M-x bbdb-vcard-import-buffer to import the current buffer. WARNING: If your vCard file includes fields with multiline values, you may get silent errors. Verify your import by browsing through the displayed entries. If some of them have been misread, revert to your backup ~/.bbdb by closing Emacs and copying your backup over the ~/.bbdb file. To fix the multi-line error, include the following lines in your ~/.emacs:</p>
<pre>
(defun wicked/vcard-parse-region (beg end &amp;amp;optional filter)
  "Parse the raw vcard data in region, and return an alist representing data.
This function is just like `vcard-parse-string' except that it operates on
a region of the current buffer rather than taking a string as an argument.

Note: this function modifies the buffer!"
  (or filter
      (setq filter 'vcard-standard-filter))
  (let ((case-fold-search t)
        (vcard-data nil)
        (pos (make-marker))
        (newpos (make-marker))
        properties value)
    (save-restriction
      (narrow-to-region beg end)
      (save-match-data
        ;; Unfold folded lines and delete naked carriage returns
        (goto-char (point-min))
        (while (re-search-forward "\r$\\|\n[ \t]" nil t)
          (goto-char (match-beginning 0))
          (delete-char 1))
        (goto-char (point-min))
        (re-search-forward "^begin:[ \t]*vcard[ \t]*\n")
        (set-marker pos (point))
        (while (and (not (looking-at "^end[ \t]*:[ \t]*vcard[ \t]*$"))
                    (re-search-forward ":[ \t]*" nil t))
          (set-marker newpos (match-end 0))
          (setq properties
                (vcard-parse-region-properties pos (match-beginning 0)))
          (set-marker pos (marker-position newpos))
          (re-search-forward "\n[-A-Z0-9;=]+:")   ;; change to deal with multiline
          (set-marker newpos (1+ (match-beginning 0))) ;; change to deal with multiline
          (setq value
                (vcard-parse-region-value properties pos (match-beginning 0)))
          (set-marker pos (marker-position newpos))
          (goto-char pos)
          (funcall filter properties value)
          (setq vcard-data (cons (cons properties value) vcard-data)))))
    (nreverse vcard-data)))
;; Replace vcard.el's definition
(fset 'vcard-parse-region 'wicked/vcard-parse-region)
</pre>
<p>Because address book programs don&#8217;t use standard labels for addresses and phone numbers, bbdb-vcard-import.el ignores those fields. For example, Gmail uses the generic field &#8220;Label&#8221; for address information and does not use separate fields for city, state, zip code, and country. While bbdb-snarf.el makes an attempt to extract addresses from plain text, it seems to be less trouble to export to the Outlook CSV format instead, or even to type the address in yourself. If you want to import addresses, see Project XXX: Import a CSV File into BBDB.</p>
<p>Here&#8217;s a partial workaround to enable you to import phone numbers. I tested this code with vCard files from Gmail and LinkedIn. To try it out, add the following modifications to your ~/.emacs:</p>
<pre>
(defun wicked/bbdb-vcard-merge (record)
  "Merge data from vcard interactively into bbdb."
  (let* ((name (bbdb-vcard-values record "fn"))
	 (company (bbdb-vcard-values record "org"))
	 (net (bbdb-vcard-get-emails record))
	 (addrs (bbdb-vcard-get-addresses record))
	 (phones (bbdb-vcard-get-phones record))
	 (categories (bbdb-vcard-values record "categories"))
	 (notes (and (not (string= "" categories))
		     (list (cons 'categories categories))))
	 ;; TODO: addrs are not yet imported.  To do this right,
	 ;; figure out a way to map the several labels to
	 ;; `bbdb-default-label-list'.  Note, some phone number
	 ;; conversion may break the format of numbers.
	 (bbdb-north-american-phone-numbers-p nil)
	 (new-record (bbdb-vcard-merge-interactively name
						     company
						     net
						     nil ;; Skip addresses
						     phones ;; Include phones
						     notes)))
    (setq bbdb-vcard-merged-records (append bbdb-vcard-merged-records 
					    (list new-record)))))
;; Replace bbdb-vcard-import.el's definition
(fset 'bbdb-vcard-merge 'wicked/bbdb-vcard-merge)
</pre>
<p>Evaluate this code or restart Emacs, then call M-x bbdb-import-vcard again, which should merge phone numbers into your BBDB records.</p>
<p>You can <a href="https://sachachua.com/blog/2008/04/wicked-cool-emacs-bbdb-import-csv-and-vcard-files/#comment">view 5 comments</a> or <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2008%2F04%2Fwicked-cool-emacs-bbdb-import-csv-and-vcard-files%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></content>
		</entry><entry>
		<title type="html">Wicked Cool Emacs: BBDB: Work with Records</title>
		<link rel="alternate" type="text/html" href="https://sachachua.com/blog/2008/04/wicked-cool-emacs-bbdb-work-with-records-2/"/>
		<author><name><![CDATA[Sacha Chua]]></name></author>
		<updated>2008-04-12T23:23:10Z</updated>
    <published>2008-04-12T19:21:58Z</published>
    <category term="bbdb" />
<category term="emacs" />
<category term="wickedcoolemacs" />
		<id>https://sachachua.com/blog/?p=4833</id>
		<content type="html"><![CDATA[<h3>Creating Records</h3>
<p>
Creating a record in BBDB is not like creating a record in graphical address book programs. You will be prompted for each field through the minibuffer, one field at a time. Don&#8217;t worry about making mistakes while entering data, as you can always edit the records afterwards.
</p>
<p>
To create a record, use the command M-x bbdb-create. Here are the prompts you&#8217;ll encounter:
</p>
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">
<col align="left">
<col align="left">
<col align="left">
<tbody>
<tr>
<td>Prompt</td>
<td>Notes</td>
<td>Example</td>
</tr>
<tr>
<td>Name</td>
<td>Full name</td>
<td>John Doe</td>
</tr>
<tr>
<td>Company</td>
<td>Company or organization</td>
<td>ACME</td>
</tr>
<tr>
<td>Network Address</td>
<td>E-mail address (comma-separated list)</td>
<td>john@example.com</td>
</tr>
<tr>
<td>Address Description</td>
<td>Short identifier for address (Home, Office, etc.) &#8211; tab completion available. Leave blank if you have no address information, or if you are done.</td>
<td>Home</td>
</tr>
<tr>
<td>Street, line 1</td>
<td>Street address, line 1 (not including city, state, postal code or country)</td>
<td>1 Acme Road</td>
</tr>
<tr>
<td>Street, line &#8230;</td>
<td>Street address, more lines &#8211; press RET to indicate the end of the street address</td>
<td></td>
</tr>
<tr>
<td>City</td>
<td></td>
<td>Acme City</td>
</tr>
<tr>
<td>State</td>
<td>Abbreviations are okay. Consistency helps.</td>
<td>AC</td>
</tr>
<tr>
<td>Country</td>
<td></td>
<td>Acme Country</td>
</tr>
<tr>
<td>Phone Location</td>
<td>Short identifier for phone number (Home, Office, etc.) &#8211; tab completion available. Leave blank if you have no phone information, or if you are done.</td>
<td>Home</td>
</tr>
<tr>
<td>Phone</td>
<td>Phone number. I tend to specify the full number, using spaces to break it into readable chunks.</td>
<td>+1 111 111 1111 x1111</td>
</tr>
<tr>
<td>Additional Comments</td>
<td>Notes about the person, such as interests, how you met, and so on</td>
<td>Likes rockets</td>
</tr>
</tbody>
</table>
<p>
Press RET to skip any fields for which you don&#8217;t have information. To<br>
cancel the entry process, type <kbd>C-g</kbd> (keyboard-quit).
</p>
<p>
After you create the record, Emacs will display the record in another<br>
window. You can then switch to the record and edit it. See Project XXX: Edit a BBDB record.
</p>
<h3>
Searching Records<br>
</h3>
<p>
To search for a specific record, type M-x bbdb, or press <kbd>b</kbd><br>
(bbdb) while in the <b>BBDB</b> buffer. This prompts for a regular<br>
expression and searches the name, company, network address, and notes<br>
fields of all the records for a match against the regular expression<br>
supplied. M-x bbdb-name, M-x bbdb-company, M-x bbdb-net, M-x<br>
bbdb-notes, and M-x bbdb-phones search the corresponding fields only.
</p>
<h3>
Updating Records<br>
</h3>
<p>
After creating or searching for a record, you can switch to the <b>BBDB</b><br>
window to edit it. Press <kbd>C-o</kbd> (bbdb-insert-field) to insert<br>
custom fields. You can use tab completion on existing field names, and<br>
you can also define your own fields by typing any field name. For<br>
example, you may want to store people&#8217;s job titles in a field called<br>
&#8220;job&#8221;.
</p>
<p>
To edit the value of a field, move your cursor to the field and press<br>
<kbd>e</kbd> (bbdb-edit-current-field) to change the value. To delete<br>
a field, move your cursor to the field and press <kbd>C-k</kbd><br>
(bbdb-delete-current-field-or-record).
</p>
<h3>
Deleting Records<br>
</h3>
<p>
To delete an entire record, move the text cursor to the name and press <kbd>C-k</kbd> (bbdb-delete-current-field-or-record).  You will be prompted for confirmation. Be careful! If you mistakenly delete a record, there&#8217;s no easy way to get it back. Fortunately, BBDB stores its data in a plain text file (~/.bbdb). Back up that file regularly and you&#8217;ll be able to recover from mistakes. You can also set up automatic file backups in Emacs (see Project XXX: Make Automatic Backups).
</p>
<p>
Now you know how to work with individual records. How can you import your address book information from other programs?</p>
<p>You can <a href="https://sachachua.com/blog/2008/04/wicked-cool-emacs-bbdb-work-with-records-2/#comment">view 2 comments</a> or <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2008%2F04%2Fwicked-cool-emacs-bbdb-work-with-records-2%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></content>
		</entry><entry>
		<title type="html">Wicked Cool Emacs: BBDB: Set up BBDB</title>
		<link rel="alternate" type="text/html" href="https://sachachua.com/blog/2008/04/wicked-cool-emacs-bbdb-set-up-bbdb/"/>
		<author><name><![CDATA[Sacha Chua]]></name></author>
		<updated>2008-04-12T23:11:20Z</updated>
    <published>2008-04-12T19:10:14Z</published>
    <category term="bbdb" />
<category term="emacs" />
<category term="wickedcoolemacs" />
		<id>https://sachachua.com/blog/?p=4831</id>
		<content type="html"><![CDATA[<p>The main address book and contact management module for Emacs is the Insidious Big Brother Database (BBDB), which can be integrated into several mail clients and other modules within Emacs. If you use BBDB to keep track of contact information, you&#8217;ll be able to look up phone numbers or add notes to people&#8217;s records from your Emacs-based mail. Even if you don&#8217;t do e-mail within Emacs, you&#8217;ll find that BBDB&#8217;s customizability makes it surprisingly powerful.</p>
<p>In this project, you will learn how to set up BBDB as a basic address book.  The BBDB homepage is at <i>http://bbdb.sourceforge.net/</i>.  The development version fixes a number of bugs, so I recommend you try it instead of the stable version. However, if you are on Microsoft Windows or you do not have development tools handy, you might find the stable version easier to install. As of this writing, the stable version (2.35) can be downloaded from http://bbdb.sourceforge.net/bbdb-2.35.tar.gz . Download and unpack it to ~/elisp/bbdb-2.35, and save the pre-built bbdb-autoloads.el from http://bbdb.sourceforge.net/bbdb-autoloads.el into ~/elisp/bbdb-2.35/lisp .</p>
<p>To check out the development version, change to your <i>~/elisp</i> directory and type in the following lines at the command prompt:</p>
<pre>
cvs -d :pserver:anonymous@bbdb.cvs.sourceforge.net:/cvsroot/bbdb login
cvs -d :pserver:anonymous@bbdb.cvs.sourceforge.net:/cvsroot/bbdb checkout bbdb
</pre>
<p>You should now have a directory called <i>~/elisp/bbdb</i>. Change to that directory and run the following commands:</p>
<pre>
autoconf
./configure
make autoloads
make all
</pre>
<p>After installing either the stable or development version of BBDB, include it in your load-path by adding the appropriate line to your <i>~/.emacs</i>:</p>
<pre>
(add-to-list 'load-path "~/elisp/bbdb-2.35/lisp")    ;; (1)
(add-to-list 'load-path "~/elisp/bbdb/lisp")         ;; (2)

(require 'bbdb) ;; (3)
(bbdb-initialize 'gnus 'message)   ;; (4)
(setq bbdb-north-american-phone-numbers-p nil)   ;; (5)
</pre>
<p>Use either <i>~/elisp/bbdb-2.35/lisp</i>(1) or <i>~/elisp/bbdb/lisp</i>(2) depending on the location of the installed BBDB Lisp files. Then load BBDB(3) and configure it for the Gnus mail client and the Message mode used to compose mail(4). It&#8217;s also a good idea to configure BBDB to accept any kind of phone number(5), not just North American numbers with a particular syntax.</p>
<p>After you evaluate this code or restart Emacs, BBDB should be part of your system. Next step: enter your address book!</p>
<p>You can <a href="https://sachachua.com/blog/2008/04/wicked-cool-emacs-bbdb-set-up-bbdb/#comment">view 2 comments</a> or <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2008%2F04%2Fwicked-cool-emacs-bbdb-set-up-bbdb%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></content>
		</entry><entry>
		<title type="html">Wicked Cool Emacs: BBDB: Use nicknames and custom salutations</title>
		<link rel="alternate" type="text/html" href="https://sachachua.com/blog/2008/03/wicked-cool-emacs-bbdb-use-nicknames-and-custom-salutations/"/>
		<author><name><![CDATA[Sacha Chua]]></name></author>
		<updated>2014-05-14T03:06:41Z</updated>
    <published>2008-03-24T08:26:48Z</published>
    <category term="bbdb" />
<category term="emacs" />
<category term="wickedcoolemacs" />
		<id>https://sachachua.com/blog/?p=4808</id>
		<content type="html"><![CDATA[<div class="update">
<p>Update 2014-05-13: The original code is for BBDB version 2. Thomas Morgan sent this update which makes it work with BBDB version 3 &#8211; see below.</p>
</div>
<p>I like starting my e-mail with a short salutation such as “Hello, Mike!”, “Hello, Michael”, or “Hello, Mikong!”, but it can be hard to remember which nicknames people prefer to use, and calling someone by the wrong name is a bit of a faux pas. Sometimes people sign e-mail with their preferred name, but what if you haven&#8217;t sent e-mail to or received e-mail from someone in a while? In this project, you&#8217;ll learn how to set up my BBDB to remember people&#8217;s nicknames for you using a custom “nick” field, and to use those nicknames when replying to messages in Gnus or composing messages from my BBDB.</p>
<p>The nickname code worked so well that I started thinking of what else I could customize. It was easy to go from nicknames to personalized salutations. This hack started because one of my friends is from Romania, so I thought I&#8217;d greet her in Romanian with “Salut, Letitia!” instead of just “Hello, Letitia!”. The code in this project uses a “hello” field to store these salutations in your BBDB.</p>
<p>To set up personalized nicknames and salutations, add the following code to your <code>~/.emacs</code>:</p>
<p>For BBDB v2</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp">(<span class="org-keyword">defvar</span> <span class="org-variable-name">wicked/gnus-nick-threshold</span> 5 <span class="org-doc">"*Number of people to stop greeting individually. Nil means always greet individually."</span>)  <span class="org-comment-delimiter">;; </span><span class="org-comment">(1)</span>
(<span class="org-keyword">defvar</span> <span class="org-variable-name">wicked/bbdb-hello-string</span> <span class="org-string">"Hello, %s!"</span> <span class="org-doc">"Format string for hello. Example: \"Hello, %s!\""</span>)
(<span class="org-keyword">defvar</span> <span class="org-variable-name">wicked/bbdb-hello-all-string</span> <span class="org-string">"Hello, all!"</span> <span class="org-doc">"String for hello when there are many people. Example: \"Hello, all!\""</span>)
(<span class="org-keyword">defvar</span> <span class="org-variable-name">wicked/bbdb-nick-field</span> 'nick <span class="org-doc">"Symbol name for nickname field in BBDB."</span>)
(<span class="org-keyword">defvar</span> <span class="org-variable-name">wicked/bbdb-salutation-field</span> 'hello <span class="org-doc">"Symbol name for salutation field in BBDB."</span>)

(<span class="org-keyword">defun</span> <span class="org-function-name">wicked/gnus-add-nick-to-message</span> ()
  <span class="org-doc">"Inserts \"Hello, NICK!\" in messages based on the recipient's nick field."</span>
  (interactive)
  (<span class="org-keyword">save-excursion</span>
    (<span class="org-keyword">let*</span> ((bbdb-get-addresses-headers <span class="org-comment-delimiter">;; </span><span class="org-comment">(2)</span>
            (list (assoc 'recipients bbdb-get-addresses-headers)))
           (recipients (bbdb-get-addresses
                        nil
                        gnus-ignored-from-addresses
                        'gnus-fetch-field))
           recipient nicks rec net salutations)
      (goto-char (point-min))
      (<span class="org-keyword">when</span> (re-search-forward <span class="org-string">"&#45;&#45;text follows this line&#45;&#45;"</span> nil t)
        (forward-line 1)
        (<span class="org-keyword">if</span> (and wicked/gnus-nick-threshold 
                 (&gt;= (length recipients) wicked/gnus-nick-threshold))
            (insert wicked/bbdb-hello-all-string <span class="org-string">"\n\n"</span>) <span class="org-comment-delimiter">;; </span><span class="org-comment">(3)</span>
          (<span class="org-keyword">while</span> recipients
            (setq recipient (car (cddr (car recipients))))
            (setq net (nth 1 recipient))
            (setq rec (car (bbdb-search (bbdb-records) nil nil net)))
            (<span class="org-keyword">cond</span>
             ((null rec) <span class="org-comment-delimiter">;; </span><span class="org-comment">(4)</span>
              (add-to-list 'nicks (car recipient))) 
             ((bbdb-record-getprop rec wicked/bbdb-salutation-field) <span class="org-comment-delimiter">;; </span><span class="org-comment">(5)</span>
              (add-to-list 'salutations 
                           (bbdb-record-getprop rec wicked/bbdb-salutation-field))) 
             ((bbdb-record-getprop rec wicked/bbdb-nick-field) <span class="org-comment-delimiter">;; </span><span class="org-comment">(6)</span>
              (add-to-list 'nicks 
                           (bbdb-record-getprop rec wicked/bbdb-nick-field)))
             (t (bbdb-record-name rec))) <span class="org-comment-delimiter">;; </span><span class="org-comment">(7) </span>
            (setq recipients (cdr recipients))))
        (<span class="org-keyword">when</span> nicks <span class="org-comment-delimiter">;; </span><span class="org-comment">(8)</span>
          (insert (format wicked/bbdb-hello-string 
                          (mapconcat 'identity (nreverse nicks) <span class="org-string">", "</span>))
                  <span class="org-string">" "</span>))
        (<span class="org-keyword">when</span> salutations <span class="org-comment-delimiter">;; </span><span class="org-comment">(9)</span>
          (insert (mapconcat 'identity salutations <span class="org-string">" "</span>)))
        (<span class="org-keyword">when</span> (or nicks salutations)
          (insert <span class="org-string">"\n\n"</span>)))))
  (goto-char (point-min)))

(<span class="org-keyword">defadvice</span> <span class="org-function-name">gnus-post-news</span> (after wicked/bbdb activate)
  <span class="org-doc">"Insert nicknames or custom salutations."</span>
  (wicked/gnus-add-nick-to-message))

(<span class="org-keyword">defadvice</span> <span class="org-function-name">gnus-msg-mail</span> (after wicked/bbdb activate)
  <span class="org-doc">"Insert nicknames or custom salutations."</span>
  (wicked/gnus-add-nick-to-message))

(<span class="org-keyword">defadvice</span> <span class="org-function-name">gnus-summary-reply</span> (after wicked/bbdb activate)
  <span class="org-doc">"Insert nicknames or custom salutations."</span>
  (wicked/gnus-add-nick-to-message))
</pre>
</div>
<p>For BBDB v3</p>
<div class="org-src-container">
<pre class="src src-emacs-lisp"><span class="org-comment-delimiter">;; </span><span class="org-comment">This version is for BBDBv3 - thanks, Thomas!</span>

(<span class="org-keyword">defvar</span> <span class="org-variable-name">wicked/gnus-nick-threshold</span> 5 <span class="org-doc">"*Number of people to stop greeting individually. Nil means always greet individually."</span>)  <span class="org-comment-delimiter">;; </span><span class="org-comment">(1)</span>
(<span class="org-keyword">defvar</span> <span class="org-variable-name">wicked/bbdb-hello-string</span> <span class="org-string">"Hello, %s!"</span> <span class="org-doc">"Format string for hello. Example: \"Hello, %s!\""</span>)
(<span class="org-keyword">defvar</span> <span class="org-variable-name">wicked/bbdb-hello-all-string</span> <span class="org-string">"Hello, all!"</span> <span class="org-doc">"String for hello when there are many people. Example: \"Hello, all!\""</span>)
(<span class="org-keyword">defvar</span> <span class="org-variable-name">wicked/bbdb-nick-field</span> 'nick <span class="org-doc">"Symbol name for nickname field in BBDB."</span>)
(<span class="org-keyword">defvar</span> <span class="org-variable-name">wicked/bbdb-salutation-field</span> 'hello <span class="org-doc">"Symbol name for salutation field in BBDB."</span>)

(<span class="org-keyword">defun</span> <span class="org-function-name">wicked/gnus-add-nick-to-message</span> ()
  <span class="org-doc">"Inserts \"Hello, NICK!\" in messages based on the recipient's nick field."</span>
  (interactive)
  (<span class="org-keyword">let</span> ((recipients (bbdb-get-address-components))
        recipient nicks rec net salutations)
    (goto-char (point-min))
    (<span class="org-keyword">when</span> (re-search-forward <span class="org-string">"&#45;&#45;text follows this line&#45;&#45;"</span> nil t)
      (forward-line 1)
      (<span class="org-keyword">if</span> (and wicked/gnus-nick-threshold 
               (&gt;= (length recipients) wicked/gnus-nick-threshold))
          (insert wicked/bbdb-hello-all-string <span class="org-string">"\n\n"</span>) <span class="org-comment-delimiter">;; </span><span class="org-comment">(3)</span>
        (<span class="org-keyword">while</span> recipients
          (setq recipient (car recipients))
          (setq net (nth 1 recipient))
          (setq rec (car (bbdb-search (bbdb-records) nil nil net)))
          (<span class="org-keyword">cond</span>
           ((null rec) <span class="org-comment-delimiter">;; </span><span class="org-comment">(4)</span>
            (add-to-list 'nicks (car recipient))) 
           ((bbdb-record-xfield rec wicked/bbdb-salutation-field) <span class="org-comment-delimiter">;; </span><span class="org-comment">(5)</span>
            (add-to-list 'salutations 
                         (bbdb-record-xfield rec wicked/bbdb-salutation-field))) 
           ((bbdb-record-xfield rec wicked/bbdb-nick-field) <span class="org-comment-delimiter">;; </span><span class="org-comment">(6)</span>
            (add-to-list 'nicks 
                         (bbdb-record-xfield rec wicked/bbdb-nick-field)))
           (t
            (add-to-list 'nicks
                         (car (split-string (bbdb-record-name rec)))))) <span class="org-comment-delimiter">;; </span><span class="org-comment">(7) </span>
          (setq recipients (cdr recipients))))
      (<span class="org-keyword">when</span> nicks <span class="org-comment-delimiter">;; </span><span class="org-comment">(8)</span>
        (insert (format wicked/bbdb-hello-string 
                        (mapconcat 'identity (nreverse nicks) <span class="org-string">", "</span>))
                <span class="org-string">" "</span>))
      (<span class="org-keyword">when</span> salutations <span class="org-comment-delimiter">;; </span><span class="org-comment">(9)</span>
        (insert (mapconcat 'identity salutations <span class="org-string">" "</span>)))
      (<span class="org-keyword">when</span> (or nicks salutations)
        (insert <span class="org-string">"\n\n"</span>)))))

(<span class="org-keyword">defadvice</span> <span class="org-function-name">gnus-post-news</span> (after wicked/bbdb activate)
  <span class="org-doc">"Insert nicknames or custom salutations."</span>
  (wicked/gnus-add-nick-to-message))

(<span class="org-keyword">defadvice</span> <span class="org-function-name">gnus-msg-mail</span> (after wicked/bbdb activate)
  <span class="org-doc">"Insert nicknames or custom salutations."</span>
  (wicked/gnus-add-nick-to-message))

(<span class="org-keyword">defadvice</span> <span class="org-function-name">gnus-summary-reply</span> (after wicked/bbdb activate)
  <span class="org-doc">"Insert nicknames or custom salutations."</span>
  (wicked/gnus-add-nick-to-message))
</pre>
</div>
<p>After you add this code, you can store personalized nicknames and salutations in your BBDB. Nicknames and salutations will be looked up using people&#8217;s e-mail addresses. While in the <code>*BBDB*</code> buffer, you can type <code>C-o (bbdb-insert-new-field)</code> to add a field to the current record. Add a <code>nick</code> field with the person&#8217;s nickname, or a <code>hello</code> field with a custom salutation. When you compose a message to or reply to a message from that person, the salutation or nickname will be included. If no nickname can be found, the recipient&#8217;s name will be used instead.</p>
<p>A number of variables can be used to modify the behavior of this code(1). For example, you may or may not want to greet 20 people individually. The default value of <code>wicked/gnus-nick-threshold</code> is to greet up to four people individually, and greet more people collectively. If you always want to greet people individually, add <code>(setq wicked/gnus-nick-threshold nil)</code> to your <code>~/.emacs</code>. If you want to change the strings used to greet people individually or collectively, change <code>wicked/bbdb-hello-string</code> and <code>wicked/bbdb-hello-all-string</code>. If you want to store the data into different fields, change <code>wicked/bbdb-nick-field</code> and <code>wicked/bbdb-salutation-field</code>, but note that old data will not be automatically copied to the new fields.</p>
<p>Here&#8217;s how the code works. First, it retrieves the list of addresses from the header(2). If there are more addresses than <code>wicked/gnus-nick-threshold</code>, then <code>wicked/bbdb-hello-all-string</code> is used to greet everyone. If not, each recipient address is looked up. If the recipient cannot be found in your BBDB, then the recipient&#8217;s name or e-mail address is used(4). If there is a personalized salutation, it is used(5). If there is a nickname, it is used(6). If the person has a record but neither salutation or nickname, then the name of the record is used(7). After all recipients have been processed, the names are added to the message(8), followed by the salutations(9). This function is added to the different Gnus message-posting functions, so it should be called whenever you compose or reply to messages.</p>
<p>You can <a href="https://sachachua.com/blog/2008/03/wicked-cool-emacs-bbdb-use-nicknames-and-custom-salutations/#comment">view 4 comments</a> or <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2008%2F03%2Fwicked-cool-emacs-bbdb-use-nicknames-and-custom-salutations%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></content>
		</entry><entry>
		<title type="html">Wicked Cool Emacs: BBDB: Keeping track of contact dates</title>
		<link rel="alternate" type="text/html" href="https://sachachua.com/blog/2008/03/wicked-cool-emacs-bbdb-keeping-track-of-contact-dates/"/>
		<author><name><![CDATA[Sacha Chua]]></name></author>
		<updated>2009-02-11T19:19:51Z</updated>
    <published>2008-03-01T08:49:00Z</published>
    <category term="emacs" />
<category term="wickedcoolemacs" />
		<id>https://sachachua.com/blog/?p=4792</id>
		<content type="html"><![CDATA[<div>
  <p>I hadn’t realized just how much I missed my Big Brother Database until today. Three networking events packed into one week meant that I hadn’t set aside enough time for follow up, and I felt my memories of the conversations getting a little hazy. Fortunately I’d taken some notes on my Palm, but I knew I had to get it into some kind of contact management system quickly, and Gmail Contacts just wasn’t compelling enough for me. So it’s back to Emacs, plain text files, and a surprisingly sophisticated contact manager.</p>

  <p>I also promised to do some work on the book today, so everything dovetailed nicely.</p>

  <p>The following bit of code helps me filter displayed contacts to show only the people I haven’t contacted since a certain date. This is handy for remembering to keep in touch with old friends, for example. Or at least it would be handy if I used it more often and if I actually sent the letters that pile up in my e-mail drafts and my snail mail outbox… but at least it’s a step in the right direction.</p>

  <p>If you want to know who you have or haven’t talked to in a while, you need to do two things. First, you need to keep track of when you talked to people. Second, you need to generate reports.</p>

  <p>To be able to quickly add contact notes to BBDB records, add the following to your 
    <i>~/.emacs</i>:
  </p>

  <h3>ch6-bbdb-ping.el:</h3>

  <pre>
(define-key bbdb-mode-map 
    <span class="org-string">&quot;z&quot;</span> &apos;wicked/bbdb-ping-bbdb-record)
(
    <span class="org-keyword">defun</span> 
    <span class="org-function-name">wicked/bbdb-ping-bbdb-record</span> (bbdb-record text 
    <span class="org-type">&amp;optional</span> date regrind)
  
    <span class="org-doc">&quot;Adds a note for today to the current BBDB record.
Call with a prefix to specify date.
BBDB-RECORD is the record to modify (default: current).
TEXT is the note to add for DATE.
If REGRIND is non-nil, redisplay the BBDB record.&quot;</span>
  (interactive (list (bbdb-current-record t)
                     (read-string 
    <span class="org-string">&quot;Notes: &quot;</span>)
                     
    <span class="org-comment-delimiter">;; </span>
    <span class="org-comment">Reading date - more powerful with Planner, but we&apos;ll make do if necessary
</span>                     (
    <span class="org-keyword">if</span> (
    <span class="org-keyword">featurep</span> &apos;
    <span class="org-constant">planner</span>)
                         (
    <span class="org-keyword">if</span> current-prefix-arg (planner-read-date) (planner-today))
                       (
    <span class="org-keyword">if</span> current-prefix-arg
                           (read-string 
    <span class="org-string">&quot;Date (YYYY.MM.DD): &quot;</span>)
                         (format-time-string 
    <span class="org-string">&quot;%Y.%m.%d&quot;</span>)))
                     t))
  (bbdb-record-putprop bbdb-record
                       &apos;contact
                       (concat date 
    <span class="org-string">&quot;: &quot;</span> text 
    <span class="org-string">&quot;\n&quot;</span>
                               (or (bbdb-record-getprop bbdb-record &apos;contact))))
  (
    <span class="org-keyword">if</span> regrind
      (
    <span class="org-keyword">save-excursion</span>
        (set-buffer bbdb-buffer-name)
        (bbdb-redisplay-one-record bbdb-record)))
  nil)

  </pre>

  <p>You can then use 
    <bold>z</bold> in BBDB buffers to add a quick note to the “contact” field of the current record. The date is automatically noted. You can create a note for a specific date by calling 
    <kbd>C-u wicked/bbdb-ping-bbdb-record</kbd> with a prefix argument. For convenience, the suggested configuration binds this to “z”, because it was one of the few unbound keys I could find.  Use this after you meet, call, or e-mail people, and write down a short note about the conversation you had. You might find these notes useful later on.
  </p>

  <p>If you met a number of people at an event in the past and you have Planner installed and loaded, you can use 
    <kbd>planner-timewarp</kbd> to set the effective date to another date. To return to today, use 
    <kbd>M-x planner-timewarp nil</kbd>.
  </p>

  <p>To automatically add a datestamped copy of sent e-mail subjects to people’s BBDB records, add the following to your 
    <i>~/.gnus</i>:
  </p>

  <h3>ch6-bbdb-message-add-subject.el:</h3>

  <pre>
(
    <span class="org-keyword">defun</span> 
    <span class="org-function-name">wicked/message-add-subject-to-bbdb-record</span> ()
  
    <span class="org-doc">&quot;Add datestamped subject note for each person this message has been sent to.&quot;</span>
  (
    <span class="org-keyword">let*</span> ((subject (concat (format-time-string 
    <span class="org-string">&quot;%Y.%m.%d&quot;</span>)
                          
    <span class="org-string">&quot;: E-mail: &quot;</span> (message-fetch-field 
    <span class="org-string">&quot;Subject&quot;</span>) 
    <span class="org-string">&quot;\n&quot;</span>))
         (bbdb-get-addresses-headers
          (list (assoc &apos;recipients bbdb-get-addresses-headers)))
         records)
    (setq records
          (bbdb-update-records
           (bbdb-get-addresses nil gnus-ignored-from-addresses &apos;gnus-fetch-field)
           nil nil))
    (mapc (
    <span class="org-keyword">lambda</span> (rec)
            (bbdb-record-putprop rec
                                 &apos;contact
                                 (concat subject
                                         (or
                                          (bbdb-record-getprop rec &apos;contact)
                                          
    <span class="org-string">&quot;&quot;</span>))))
          records)))
(add-hook &apos;message-send-hook &apos;wicked/message-add-subject-to-bbdb-record)

  </pre>

  <p>Now that you have the data, how can you use it to filter? Add the following to your 
    <i>~/.emacs</i>:
  </p>

  <h3>ch6-bbdb-show-only-no-contact-since.el:</h3>

  <pre>
(
    <span class="org-keyword">defun</span> 
    <span class="org-function-name">wicked/bbdb-show-only-no-contact-since</span> (date 
    <span class="org-type">&amp;optional</span> reverse records)
  
    <span class="org-doc">&quot;Show only people who haven&apos;t been pinged since DATE or at all.
If REVERSE is non-nil, show only the people you&apos;ve contacted on or since DATE.
Call with a prefix argument to show only people you&apos;ve contacted on or since DATE.&quot;</span>
  (interactive (list
                (
    <span class="org-keyword">if</span> (
    <span class="org-keyword">featurep</span> &apos;
    <span class="org-constant">planner</span>)
                    (planner-read-date)
                  (read-string 
    <span class="org-string">&quot;Date (YYYY.MM.DD): &quot;</span>))
                current-prefix-arg (or bbdb-records (bbdb-records))))
  (
    <span class="org-keyword">let</span> (new-records
        last-match
        timestamp
        omit
        notes)
    (
    <span class="org-keyword">while</span> records
      
    <span class="org-comment-delimiter">;; </span>
    <span class="org-comment">Find the latest date mentioned in the entry
</span>      (
    <span class="org-keyword">let</span> ((timestamp (wicked/bbdb-last-date
                        (
    <span class="org-keyword">if</span> (vectorp (car records))
                            (car records)
                          (caar records)))))
        (
    <span class="org-keyword">if</span> (
    <span class="org-keyword">if</span> reverse
                
    <span class="org-comment-delimiter">;; </span>
    <span class="org-comment">Keep if contact is &gt;= date
</span>                (null (string&lt; timestamp date))
              
    <span class="org-comment-delimiter">;; </span>
    <span class="org-comment">Keep if date &gt; contact
</span>              (string&gt; date timestamp))
            (add-to-list &apos;new-records (
    <span class="org-keyword">if</span> (vectorp (car records))
                            (car records)
                          (caar records)) t)))
      (setq records (cdr records)))
    (bbdb-display-records new-records)))

(
    <span class="org-keyword">defun</span> 
    <span class="org-function-name">wicked/bbdb-last-date</span> (rec)
  
    <span class="org-doc">&quot;Return the most recent date for REC or nil if none.
Dates should be in the form YYYY.MM.DD.  The first date in the
notes field and the first date in the contact field are used, so
dates should be in reverse chronological order.&quot;</span>
  (
    <span class="org-keyword">let*</span> ((wicked/date-regexp
          
    <span class="org-string">&quot;\\&lt;</span>
    <span class="org-string">
      <span class="regexp-grouping-backslash">\\</span>
    </span>
    <span class="org-string">
      <span class="regexp-grouping-construct">(</span>
    </span>
    <span class="org-string">[1-9][0-9][0-9][0-9]</span>
    <span class="org-string">
      <span class="regexp-grouping-backslash">\\</span>
    </span>
    <span class="org-string">
      <span class="regexp-grouping-construct">)</span>
    </span>
    <span class="org-string">\\.</span>
    <span class="org-string">
      <span class="regexp-grouping-backslash">\\</span>
    </span>
    <span class="org-string">
      <span class="regexp-grouping-construct">(</span>
    </span>
    <span class="org-string">[0-9][0-9]?</span>
    <span class="org-string">
      <span class="regexp-grouping-backslash">\\</span>
    </span>
    <span class="org-string">
      <span class="regexp-grouping-construct">)</span>
    </span>
    <span class="org-string">\\.</span>
    <span class="org-string">
      <span class="regexp-grouping-backslash">\\</span>
    </span>
    <span class="org-string">
      <span class="regexp-grouping-construct">(</span>
    </span>
    <span class="org-string">[0-9][0-9]?</span>
    <span class="org-string">
      <span class="regexp-grouping-backslash">\\</span>
    </span>
    <span class="org-string">
      <span class="regexp-grouping-construct">)</span>
    </span>
    <span class="org-string">\\&gt;&quot;</span>)
         
    <span class="org-comment-delimiter">;; </span>
    <span class="org-comment">Get the first date mentioned in the notes field
</span>         (notes-date
          (or (and (string-match wicked/date-regexp (or (bbdb-record-notes rec) 
    <span class="org-string">&quot;&quot;</span>))
                   (match-string 0 (or (bbdb-record-notes rec) 
    <span class="org-string">&quot;&quot;</span>)))
              
    <span class="org-string">&quot;0000.00.00&quot;</span>))
         
    <span class="org-comment-delimiter">;; </span>
    <span class="org-comment">Get the first date mentioned in the contact field
</span>         (contact-date
          (or (and (string-match wicked/date-regexp (or (bbdb-record-getprop rec &apos;contact) 
    <span class="org-string">&quot;&quot;</span>))
                   (match-string 0 (or (bbdb-record-getprop rec &apos;contact) 
    <span class="org-string">&quot;&quot;</span>)))
              
    <span class="org-string">&quot;0000.00.00&quot;</span>)))
    
    <span class="org-comment-delimiter">;; </span>
    <span class="org-comment">Compare the two dates
</span>    (or (
    <span class="org-keyword">if</span> (string&lt; notes-date contact-date) contact-date notes-date)
        
    <span class="org-string">&quot;0000.00.00&quot;</span>)))

  </pre>

  <p>To generate a report, use 
    <kbd>M-x wicked/bbdb-show-only-no-contact-since</kbd> and specify the date.  These functions are much easier to use with Planner’s date-handling functions. Planner can read dates like “-1” (yesterday), “-7fri” (seven Fridays ago), “2” (the second of this month), “1.2” (January 2 in this year), and “2007.01.02” (January 2, 2007).
  </p>

  <p>You can also flip the filter by using the universal prefix argument (\{\{C-u M-x wicked/bbdb-show-only-no-contact-since\}\}) to show only the people you’ve contacted since a certain date. This is good for knowing the size of your active network. Because the filter works on displayed records, you can combine it to find all the people you talked to last year but not this year. You can also combine it with other filters to find all the people you’ve marked as friends, but who you haven’t talked to in three months. Then you can send a personalized e-mail or make a phone list, and get back in touch. And that’s how you keep track of your contact dates!</p>

</div><p>You can <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2008%2F03%2Fwicked-cool-emacs-bbdb-keeping-track-of-contact-dates%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></content>
		</entry><entry>
		<title type="html">BBDB: Show a phone list</title>
		<link rel="alternate" type="text/html" href="https://sachachua.com/blog/2008/02/bbdb-show-a-phone-list/"/>
		<author><name><![CDATA[Sacha Chua]]></name></author>
		<updated>2008-02-15T08:27:50Z</updated>
    <published>2008-02-15T03:27:50Z</published>
    <category term="bbdb" />
<category term="emacs" />
<category term="wickedcoolemacs" />
		<id>https://sachachua.com/blog/?p=4763</id>
		<content type="html"><![CDATA[<p>When I find myself in an airport, I sometimes take a little time to say hi to a bunch of people who are suddenly just a local call a way. Or sometimes I&#8217;m thinking of going somewhere, and instead of flipping through my phone&#8217;s address book, I&#8217;ll check my computer to see who might be interested.</p>
<p>You can use this function to filter phone numbers in your BBDB based on a regular expression. As usual, leaving the regular expression blank means that all records with phone numbers will be displayed. By default, the function works on the currently displayed records, allowing you to apply multiple filters. You can call it with a universal prefix argument (C-u M-x sacha/bbdb-find-people-with-phones) to match against all contacts in your database.</p>
<p>Here&#8217;s the code:</p>
<pre>
(defun sacha/bbdb-find-people-with-phones (&optional regexp records)
  "Search for phone numbers that match REGEXP in BBDB RECORDS.
Without a prefix argument, filter the list of displayed records.
Call with a prefix argument to search the entire database.  This
works best if you use a consistent format to store your phone
numbers.  The search will strip out non-numeric characters. For
example, +1-888-123-4567 will be treated as +18001234567.

To search for all numbers in Toronto, search for
\"+1\\(416\\|647\\)\". If you search for certain areas
frequently, it might be a good idea to define a function for
them."
  (interactive (list (read-string "Regexp: ")
		     (if current-prefix-arg
			 (bbdb-records)
		       (or bbdb-records (bbdb-records)))))
  (let (filtered next)
    (while records
      (when
          (and (bbdb-record-get-field-internal
		(if (arrayp (car records))
		    (car records)
		  (caar records)) 'phone)
               (or
                (null regexp)
		(string= regexp "")
                (delq nil
                      (mapcar
                       (lambda (phone)
			 (when (string-match regexp (sacha/bbdb-phone-string phone))
			   (concat (bbdb-phone-location phone) ": " (bbdb-phone-string phone))))
                       (bbdb-record-get-field-internal
                        (if (arrayp (car records))
                            (car records)
                          (caar records)) 'phone)))))
        (setq filtered (cons (if (arrayp (car records))
                                 (car records)
                               (caar records)) filtered)))
      (setq records (cdr records)))
    (bbdb-display-records (nreverse filtered))))

(defun sacha/bbdb-phone-string (&optional phone)
  "Strip non-numeric characters from PHONE, except for +."
  (replace-regexp-in-string "[^+1234567890]" "" (bbdb-phone-string phone)))
   
(defun sacha/bbdb-yank-phones ()
  "Copy a phone list into the kill ring."
  (interactive)
  (kill-new
   (mapconcat
    (lambda (record)
      (mapconcat
       (lambda (phone)
	 (concat (bbdb-record-name (car record)) "\t" 
                 (bbdb-phone-location phone) "\t"
		 (bbdb-phone-string phone)))
        (bbdb-record-get-field-internal (car record) 'phone)
        "\n"))
    bbdb-records
    "\n")))
</pre>
<p>You can <a href="https://sachachua.com/blog/2008/02/bbdb-show-a-phone-list/#comment">view 2 comments</a> or <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2008%2F02%2Fbbdb-show-a-phone-list%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></content>
		</entry><entry>
		<title type="html">Chapter 6: Being Big Brother (plan)</title>
		<link rel="alternate" type="text/html" href="https://sachachua.com/blog/2008/02/chapter-6-being-big-brother-plan/"/>
		<author><name><![CDATA[Sacha Chua]]></name></author>
		<updated>2008-02-14T09:32:10Z</updated>
    <published>2008-02-14T02:34:02Z</published>
    <category term="emacs" />
<category term="wickedcoolemacs" />
		<id>https://sachachua.com/blog/?p=4760</id>
		<content type="html"><![CDATA[<p>I haven&#8217;t been writing about Emacs lately. Here&#8217;s my outline so that you can help keep me honest. =) My next chapter is about the Big Brother Database (BBDB) and contact management in Emacs, which is one of the things that made people laugh when I showed my Emacs configuration at DemoCamp in Toronto. Anyway, here&#8217;s what I&#8217;m planning to write about:</p>
<p><strong>Chapter 6: Being Big Brother</strong> (30 pages)</p>
<ul>
<li>Why use Emacs to manage your contacts?<br>
What is BBDB?</li>
<li>Project xxx: Set up BBDB<br>
Project xxx: Import contacts: CSV, card<br>
Project xxx: Create a record<br>
Project xxx: Search records</li>
<li>Mail<br>
Project xxx: Integrate BBDB with Mail<br>
Project xxx: Notice e-mail changes<br>
Project xxx: Filter mail according to record<br>
Project xxx: Categorize contacts with mail aliases<br>
Project xxx: Personalize greetings<br>
Project xxx: Personalize signatures<br>
Project xxx: Mail merge<br>
Project xxx: Track last contact</li>
<li>Filtering records<br>
Project xxx: Show a phone list<br>
Project xxx: Show an address list<br>
Project xxx: Show no contact since<br>
Project xxx: Show tag queries<br>
Project xxx: Remember birthdays</li>
<li>More data<br>
Project xxx: Snarf records<br>
Project xxx: Add pictures<br>
Project xxx: Export contacts<br>
Project xxx: Synchronize contacts<br>
Project xxx: Synchronize with LinkedIn</li>
</ul>
<p>You can <a href="https://sachachua.com/blog/2008/02/chapter-6-being-big-brother-plan/#comment">view 4 comments</a> or <a href="mailto:sacha@sachachua.com?subject=Comment%20on%20https%3A%2F%2Fsachachua.com%2Fblog%2F2008%2F02%2Fchapter-6-being-big-brother-plan%2F&body=Name%20you%20want%20to%20be%20credited%20by%20(if%20any)%3A%20%0AMessage%3A%20%0ACan%20I%20share%20your%20comment%20so%20other%20people%20can%20learn%20from%20it%3F%20Yes%2FNo%0A">e-mail me at sacha@sachachua.com</a>.</p>]]></content>
		</entry>
</feed>